Move photo data to Data::PhotoMedia.

This commit is contained in:
John Preston 2020-05-25 18:16:04 +04:00
parent 24fed8105c
commit e27d2bc2d5
51 changed files with 1628 additions and 922 deletions

View File

@ -393,6 +393,8 @@ PRIVATE
data/data_peer_values.h
data/data_photo.cpp
data/data_photo.h
data/data_photo_media.cpp
data/data_photo_media.h
data/data_poll.cpp
data/data_poll.h
data/data_pts_waiter.cpp

View File

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
#include "data/data_photo_media.h"
#include "base/unixtime.h"
#include "main/main_session.h"
#include "observer_peer.h"
@ -894,12 +895,12 @@ ConfirmInviteBox::ConfirmInviteBox(
const auto photo = _session->data().processPhoto(data.vphoto());
if (!photo->isNull()) {
_photo = photo->thumbnail();
if (!_photo->loaded()) {
_photo = photo->createMediaView();
_photo->wanted(Data::PhotoSize::Small, Data::FileOrigin());
if (!_photo->image(Data::PhotoSize::Small)) {
subscribe(_session->downloaderTaskFinished(), [=] {
update();
});
_photo->load(Data::FileOrigin());
}
} else {
_photoEmpty = std::make_unique<Ui::EmptyUserpic>(
@ -972,14 +973,16 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (_photo) {
p.drawPixmap(
(width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop,
_photo->pixCircled(
Data::FileOrigin(),
st::confirmInvitePhotoSize,
st::confirmInvitePhotoSize));
} else {
if (const auto image = _photo->image(Data::PhotoSize::Small)) {
p.drawPixmap(
(width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop,
image->pixCircled(
Data::FileOrigin(),
st::confirmInvitePhotoSize,
st::confirmInvitePhotoSize));
}
} else if (_photoEmpty) {
_photoEmpty->paint(
p,
(width() - st::confirmInvitePhotoSize) / 2,

View File

@ -10,6 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
#include "mtproto/mtproto_rpc_sender.h"
namespace Data {
class PhotoMedia;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
@ -230,7 +234,7 @@ private:
Fn<void()> _submit;
object_ptr<Ui::FlatLabel> _title;
object_ptr<Ui::FlatLabel> _status;
Image *_photo = nullptr;
std::shared_ptr<Data::PhotoMedia> _photo;
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
std::vector<not_null<UserData*>> _participants;
bool _isChannel = false;

View File

@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_streaming.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "data/data_document_media.h"
#include "history/history.h"
#include "history/history_item.h"
@ -55,6 +56,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
using namespace ::Media::Streaming;
using Data::PhotoSize;
} // namespace
@ -75,9 +77,10 @@ EditCaptionBox::EditCaptionBox(
const auto media = item->media();
if (const auto photo = media->photo()) {
_photo = true;
dimensions = QSize(photo->width(), photo->height());
image = photo->large();
_photoMedia = photo->createMediaView();
_photoMedia->wanted(PhotoSize::Large, _msgId);
image = _photoMedia->image(PhotoSize::Large);
dimensions = _photoMedia->size(PhotoSize::Large);
} else if (const auto document = media->document()) {
_documentMedia = document->createMediaView();
_documentMedia->thumbnailWanted(_msgId);
@ -97,7 +100,10 @@ EditCaptionBox::EditCaptionBox(
}
const auto editData = PrepareEditText(item);
if (!_animated && (dimensions.isEmpty() || _documentMedia || !image)) {
if (!_animated
&& (dimensions.isEmpty()
|| _documentMedia
|| (!_photoMedia && !image))) {
if (!image) {
_thumbw = 0;
} else {
@ -139,7 +145,7 @@ EditCaptionBox::EditCaptionBox(
_refreshThumbnail();
}
} else {
if (!image) {
if (!image && !_photoMedia) {
image = Image::BlankMedia();
}
auto maxW = 0, maxH = 0;
@ -177,7 +183,10 @@ EditCaptionBox::EditCaptionBox(
maxH = dimensions.height();
_thumbnailImage = image;
_refreshThumbnail = [=] {
_thumb = image->pixNoCache(
if (!_thumbnailImage) {
return;
}
_thumb = _thumbnailImage->pixNoCache(
_msgId,
maxW * cIntRetinaFactor(),
maxH * cIntRetinaFactor(),
@ -253,6 +262,8 @@ EditCaptionBox::EditCaptionBox(
_thumbnailImageLoaded = _thumbnailImage
? _thumbnailImage->loaded()
: _photoMedia
? false
: _documentMedia
? !_documentMedia->owner()->hasThumbnail()
: true;
@ -260,6 +271,8 @@ EditCaptionBox::EditCaptionBox(
subscribe(_controller->session().downloaderTaskFinished(), [=] {
if (_thumbnailImageLoaded) {
return;
} else if (!_thumbnailImage && _photoMedia) {
_thumbnailImage = _photoMedia->image(PhotoSize::Large);
} else if (!_thumbnailImage
&& _documentMedia
&& _documentMedia->owner()->hasThumbnail()) {

View File

@ -22,6 +22,7 @@ class SessionController;
namespace Data {
class Media;
class PhotoMedia;
class DocumentMedia;
} // namespace Data
@ -103,6 +104,7 @@ private:
not_null<Window::SessionController*> _controller;
FullMsgId _msgId;
std::shared_ptr<Data::PhotoMedia> _photoMedia;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
Image *_thumbnailImage = nullptr;
bool _thumbnailImageLoaded = false;

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "calls/calls_emoji_fingerprint.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
@ -299,7 +300,7 @@ QImage Panel::Button::prepareRippleMask() const {
}
Panel::Panel(not_null<Call*> call)
:RpWidget(App::wnd())
: RpWidget(App::wnd())
, _call(call)
, _user(call->user())
, _answerHangupRedial(this, st::callAnswer, &st::callHangup)
@ -319,6 +320,8 @@ Panel::Panel(not_null<Call*> call)
showAndActivate();
}
Panel::~Panel() = default;
void Panel::showAndActivate() {
toggleOpacityAnimation(true);
raise();
@ -515,26 +518,28 @@ void Panel::processUserPhoto() {
? _user->owner().photo(_user->userpicPhotoId()).get()
: nullptr;
if (isGoodUserPhoto(photo)) {
photo->large()->load(_user->userpicPhotoOrigin());
} else if (_user->userpicPhotoUnknown() || (photo && !photo->date)) {
_user->session().api().requestFullPeer(_user);
_photo = photo->createMediaView();
_photo->wanted(Data::PhotoSize::Large, _user->userpicPhotoOrigin());
} else {
_photo = nullptr;
if (_user->userpicPhotoUnknown() || (photo && !photo->date)) {
_user->session().api().requestFullPeer(_user);
}
}
refreshUserPhoto();
}
void Panel::refreshUserPhoto() {
const auto photo = _user->userpicPhotoId()
? _user->owner().photo(_user->userpicPhotoId()).get()
: nullptr;
const auto isNewPhoto = [&](not_null<PhotoData*> photo) {
return photo->large()->loaded()
&& (photo->id != _userPhotoId || !_userPhotoFull);
};
if (isGoodUserPhoto(photo) && isNewPhoto(photo)) {
_userPhotoId = photo->id;
const auto isNewBigPhoto = [&] {
return _photo
&& _photo->loaded()
&& (_photo->owner()->id != _userPhotoId || !_userPhotoFull);
}();
if (isNewBigPhoto) {
_userPhotoId = _photo->owner()->id;
_userPhotoFull = true;
createUserpicCache(
photo->isNull() ? nullptr : photo->large().get(),
_photo->image(Data::PhotoSize::Large),
_user->userpicPhotoOrigin());
} else if (_userPhoto.isNull()) {
const auto userpic = _user->currentUserpic();

View File

@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h"
#include "ui/rp_widget.h"
namespace Data {
class PhotoMedia;
} // namespace Data
namespace Ui {
class IconButton;
class FlatLabel;
@ -56,6 +60,7 @@ class Panel
public:
Panel(not_null<Call*> call);
~Panel();
void showAndActivate();
void replaceCall(not_null<Call*> call);
@ -111,6 +116,7 @@ private:
Call *_call = nullptr;
not_null<UserData*> _user;
std::shared_ptr<Data::PhotoMedia> _photo;
bool _useTransparency = true;
style::margins _padding;

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "data/data_document_media.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
@ -370,18 +371,23 @@ void GifsListWidget::selectInlineResult(int row, int column) {
return;
}
const auto ctrl = (QGuiApplication::keyboardModifiers()
== Qt::ControlModifier);
auto item = _rows[row].items[column];
if (const auto photo = item->getPhoto()) {
if (photo->thumbnail()->loaded()) {
using Data::PhotoSize;
const auto media = photo->activeMediaView();
if (ctrl
|| (media && media->image(PhotoSize::Thumbnail))
|| (media && media->image(PhotoSize::Large))) {
_photoChosen.fire_copy(photo);
} else if (!photo->thumbnail()->loading()) {
photo->thumbnail()->loadEvenCancelled(Data::FileOrigin());
} else if (!photo->loading(PhotoSize::Thumbnail)) {
photo->load(PhotoSize::Thumbnail, Data::FileOrigin());
}
} else if (const auto document = item->getDocument()) {
const auto media = document->activeMediaView();
const auto preview = Data::VideoPreviewState(media.get());
if ((media && preview.loaded())
|| QGuiApplication::keyboardModifiers() == Qt::ControlModifier) {
if (ctrl || (media && preview.loaded())) {
_fileChosen.fire_copy(document);
} else if (!preview.usingThumbnail()) {
if (preview.loading()) {
@ -551,11 +557,13 @@ void GifsListWidget::clearInlineRows(bool resultsDeleted) {
_rows.clear();
}
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(DocumentData *doc, int32 position) {
auto it = _gifLayouts.find(doc);
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(
not_null<DocumentData*> document,
int32 position) {
auto it = _gifLayouts.find(document);
if (it == _gifLayouts.cend()) {
if (auto layout = LayoutItem::createLayoutGif(this, doc)) {
it = _gifLayouts.emplace(doc, std::move(layout)).first;
if (auto layout = LayoutItem::createLayoutGif(this, document)) {
it = _gifLayouts.emplace(document, std::move(layout)).first;
it->second->initDimensions();
} else {
return nullptr;
@ -567,7 +575,9 @@ GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(DocumentData *
return it->second.get();
}
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareInlineResult(InlineResult *result, int32 position) {
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareInlineResult(
not_null<InlineResult*> result,
int32 position) {
auto it = _inlineLayouts.find(result);
if (it == _inlineLayouts.cend()) {
if (auto layout = LayoutItem::createLayout(this, result, _inlineWithThumb)) {

View File

@ -134,11 +134,19 @@ private:
QVector<Row> _rows;
void clearInlineRows(bool resultsDeleted);
std::map<DocumentData*, std::unique_ptr<LayoutItem>> _gifLayouts;
LayoutItem *layoutPrepareSavedGif(DocumentData *doc, int32 position);
std::map<
not_null<DocumentData*>,
std::unique_ptr<LayoutItem>> _gifLayouts;
LayoutItem *layoutPrepareSavedGif(
not_null<DocumentData*> document,
int32 position);
std::map<InlineResult*, std::unique_ptr<LayoutItem>> _inlineLayouts;
LayoutItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
std::map<
not_null<InlineResult*>,
std::unique_ptr<LayoutItem>> _inlineLayouts;
LayoutItem *layoutPrepareInlineResult(
not_null<InlineResult*> result,
int32 position);
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, Row &row, int32 &sumWidth);
bool inlineRowFinalize(Row &row, int32 &sumWidth, bool force = false);

View File

@ -128,11 +128,6 @@ public:
QImage takeLoaded() override;
void unload() override;
void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) override;
void automaticLoadSettingsChanged() override;
bool loading() override;
bool displayLoading() override;
void cancel() override;
@ -222,14 +217,6 @@ void ImageSource::unload() {
_data = QImage();
}
void ImageSource::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
}
void ImageSource::automaticLoadSettingsChanged() {
}
bool ImageSource::loading() {
return _data.isNull() && _bytes.isEmpty();
}

View File

@ -10,8 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "ui/image/image_source.h"
#include "ui/image/image.h"
#include <QtCore/QBuffer>
@ -294,11 +292,11 @@ bool Should(
bool Should(
const Full &data,
not_null<PeerData*> peer,
not_null<Images::Source*> image) {
not_null<PhotoData*> photo) {
return data.shouldDownload(
SourceFromPeer(peer),
Type::Photo,
image->bytesSize());
photo->imageByteSize(PhotoSize::Large));
}
bool ShouldAutoPlay(

View File

@ -9,10 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <array>
namespace Images {
class Source;
} // namespace Images
namespace Data {
namespace AutoDownload {
@ -118,7 +114,7 @@ private:
[[nodiscard]] bool Should(
const Full &data,
not_null<PeerData*> peer,
not_null<Images::Source*> image);
not_null<PhotoData*> photo);
[[nodiscard]] bool ShouldAutoPlay(
const Full &data,

View File

@ -700,10 +700,10 @@ void DocumentData::loadThumbnail(Data::FileOrigin origin) {
_flags |= Flag::ThumbnailFailed;
}, [=] {
if (_thumbnailLoader && !_thumbnailLoader->cancelled()) {
if (auto image = _thumbnailLoader->imageData(); image.isNull()) {
if (auto read = _thumbnailLoader->imageData(); read.isNull()) {
_flags |= Flag::ThumbnailFailed;
} else if (const auto active = activeMediaView()) {
active->setThumbnail(std::move(image));
active->setThumbnail(std::move(read));
}
}
_thumbnailLoader = nullptr;

View File

@ -159,8 +159,8 @@ public:
[[nodiscard]] bool thumbnailLoading() const;
[[nodiscard]] bool thumbnailFailed() const;
void loadThumbnail(Data::FileOrigin origin);
const ImageLocation &thumbnailLocation() const;
int thumbnailByteSize() const;
[[nodiscard]] const ImageLocation &thumbnailLocation() const;
[[nodiscard]] int thumbnailByteSize() const;
[[nodiscard]] bool hasVideoThumbnail() const;
[[nodiscard]] bool videoThumbnailLoading() const;

View File

@ -381,98 +381,98 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
}
parent()->history()->owner().photoConvert(_photo, *content);
if (content->type() != mtpc_photo) {
return false;
}
const auto &photo = content->c_photo();
//if (content->type() != mtpc_photo) { // #TODO optimize
// return false;
//}
//const auto &photo = content->c_photo();
struct SizeData {
MTPstring type = MTP_string();
int width = 0;
int height = 0;
QByteArray bytes;
};
const auto saveImageToCache = [&](
not_null<Image*> image,
SizeData size) {
Expects(!size.type.v.isEmpty());
//struct SizeData {
// MTPstring type = MTP_string();
// int width = 0;
// int height = 0;
// QByteArray bytes;
//};
//const auto saveImageToCache = [&](
// not_null<Image*> image,
// SizeData size) {
// Expects(!size.type.v.isEmpty());
const auto key = StorageImageLocation(
StorageFileLocation(
photo.vdc_id().v,
_photo->session().userId(),
MTP_inputPhotoFileLocation(
photo.vid(),
photo.vaccess_hash(),
photo.vfile_reference(),
size.type)),
size.width,
size.height);
if (!key.valid() || image->isNull() || !image->loaded()) {
return;
}
if (size.bytes.isEmpty()) {
size.bytes = image->bytesForCache();
}
const auto length = size.bytes.size();
if (!length || length > Storage::kMaxFileInMemory) {
LOG(("App Error: Bad photo data for saving to cache."));
return;
}
parent()->history()->owner().cache().putIfEmpty(
key.file().cacheKey(),
Storage::Cache::Database::TaggedValue(
std::move(size.bytes),
Data::kImageCacheTag));
image->replaceSource(
std::make_unique<Images::StorageSource>(key, length));
};
auto &sizes = photo.vsizes().v;
auto max = 0;
auto maxSize = SizeData();
for (const auto &data : sizes) {
const auto size = data.match([](const MTPDphotoSize &data) {
return SizeData{
data.vtype(),
data.vw().v,
data.vh().v,
QByteArray()
};
}, [](const MTPDphotoCachedSize &data) {
return SizeData{
data.vtype(),
data.vw().v,
data.vh().v,
qba(data.vbytes())
};
}, [](const MTPDphotoSizeEmpty &) {
return SizeData();
}, [](const MTPDphotoStrippedSize &data) {
// No need to save stripped images to local cache.
return SizeData();
});
const auto letter = size.type.v.isEmpty() ? char(0) : size.type.v[0];
if (!letter) {
continue;
}
if (letter == 's') {
saveImageToCache(_photo->thumbnailSmall(), size);
} else if (letter == 'm') {
saveImageToCache(_photo->thumbnail(), size);
} else if (letter == 'x' && max < 1) {
max = 1;
maxSize = size;
} else if (letter == 'y' && max < 2) {
max = 2;
maxSize = size;
//} else if (letter == 'w' && max < 3) {
// max = 3;
// maxSize = size;
}
}
if (!maxSize.type.v.isEmpty()) {
saveImageToCache(_photo->large(), maxSize);
}
// const auto key = StorageImageLocation(
// StorageFileLocation(
// photo.vdc_id().v,
// _photo->session().userId(),
// MTP_inputPhotoFileLocation(
// photo.vid(),
// photo.vaccess_hash(),
// photo.vfile_reference(),
// size.type)),
// size.width,
// size.height);
// if (!key.valid() || image->isNull() || !image->loaded()) {
// return;
// }
// if (size.bytes.isEmpty()) {
// size.bytes = image->bytesForCache();
// }
// const auto length = size.bytes.size();
// if (!length || length > Storage::kMaxFileInMemory) {
// LOG(("App Error: Bad photo data for saving to cache."));
// return;
// }
// parent()->history()->owner().cache().putIfEmpty(
// key.file().cacheKey(),
// Storage::Cache::Database::TaggedValue(
// std::move(size.bytes),
// Data::kImageCacheTag));
// image->replaceSource(
// std::make_unique<Images::StorageSource>(key, length));
//};
//auto &sizes = photo.vsizes().v;
//auto max = 0;
//auto maxSize = SizeData();
//for (const auto &data : sizes) {
// const auto size = data.match([](const MTPDphotoSize &data) {
// return SizeData{
// data.vtype(),
// data.vw().v,
// data.vh().v,
// QByteArray()
// };
// }, [](const MTPDphotoCachedSize &data) {
// return SizeData{
// data.vtype(),
// data.vw().v,
// data.vh().v,
// qba(data.vbytes())
// };
// }, [](const MTPDphotoSizeEmpty &) {
// return SizeData();
// }, [](const MTPDphotoStrippedSize &data) {
// // No need to save stripped images to local cache.
// return SizeData();
// });
// const auto letter = size.type.v.isEmpty() ? char(0) : size.type.v[0];
// if (!letter) {
// continue;
// }
// if (letter == 's') {
// saveImageToCache(_photo->thumbnailSmall(), size);
// } else if (letter == 'm') {
// saveImageToCache(_photo->thumbnail(), size);
// } else if (letter == 'x' && max < 1) {
// max = 1;
// maxSize = size;
// } else if (letter == 'y' && max < 2) {
// max = 2;
// maxSize = size;
// //} else if (letter == 'w' && max < 3) {
// // max = 3;
// // maxSize = size;
// }
//}
//if (!maxSize.type.v.isEmpty()) {
// saveImageToCache(_photo->large(), maxSize);
//}
return true;
}

View File

@ -10,20 +10,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_reply_preview.h"
#include "data/data_photo_media.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
#include "main/main_session.h"
#include "mainwidget.h"
#include "storage/file_download.h"
#include "core/application.h"
#include "facades.h"
#include "app.h"
namespace {
using Data::PhotoMedia;
using Data::PhotoSize;
using Data::PhotoSizeIndex;
using Data::kPhotoSizeCount;
} // namespace
PhotoData::PhotoData(not_null<Data::Session*> owner, PhotoId id)
: id(id)
, _owner(owner) {
}
PhotoData::~PhotoData() = default;
PhotoData::~PhotoData() {
for (auto &image : _images) {
base::take(image.loader).reset();
}
}
Data::Session &PhotoData::owner() const {
return *_owner;
@ -33,55 +48,77 @@ Main::Session &PhotoData::session() const {
return _owner->session();
}
void PhotoData::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
_large->automaticLoad(origin, item);
}
void PhotoData::automaticLoadSettingsChanged() {
_large->automaticLoadSettingsChanged();
}
void PhotoData::download(Data::FileOrigin origin) {
_large->loadEvenCancelled(origin);
_owner->notifyPhotoLayoutChanged(this);
}
bool PhotoData::loaded() const {
bool wasLoading = loading();
if (_large->loaded()) {
if (wasLoading) {
_owner->notifyPhotoLayoutChanged(this);
}
return true;
const auto index = PhotoSizeIndex(PhotoSize::Large);
if (!(_images[index].flags & ImageFlag::Cancelled)) {
return;
}
return false;
_images[index].loader = nullptr;
_images[index].flags &= ~ImageFlag::Cancelled;
}
void PhotoData::load(
Data::FileOrigin origin,
LoadFromCloudSetting fromCloud,
bool autoLoading) {
load(PhotoSize::Large, origin, fromCloud, autoLoading);
}
bool PhotoData::loading() const {
return _large->loading();
return loading(PhotoSize::Large);
}
bool PhotoData::loading(PhotoSize size) const {
return (_images[PhotoSizeIndex(size)].loader != nullptr);
}
bool PhotoData::failed(PhotoSize size) const {
return (_images[PhotoSizeIndex(size)].flags & ImageFlag::Failed);
}
const ImageLocation &PhotoData::location(PhotoSize size) const {
return _images[PhotoSizeIndex(size)].location;
}
int PhotoData::imageByteSize(PhotoSize size) const {
return _images[PhotoSizeIndex(size)].byteSize;
}
bool PhotoData::displayLoading() const {
return _large->loading()
? _large->displayLoading()
const auto index = PhotoSizeIndex(PhotoSize::Large);
return _images[index].loader
? (!_images[index].loader->loadingLocal()
|| !_images[index].loader->autoLoading())
: (uploading() && !waitingForAlbum());
}
void PhotoData::cancel() {
_large->cancel();
_owner->notifyPhotoLayoutChanged(this);
if (!loading()) {
return;
}
const auto index = PhotoSizeIndex(PhotoSize::Large);
_images[index].flags |= ImageFlag::Cancelled;
destroyLoader(PhotoSize::Large);
_owner->photoLoadDone(this);
}
float64 PhotoData::progress() const {
if (uploading()) {
if (uploadingData->size > 0) {
return float64(uploadingData->offset) / uploadingData->size;
const auto result = float64(uploadingData->offset)
/ uploadingData->size;
return snap(result, 0., 1.);
}
return 0;
return 0.;
}
return _large->progress();
const auto index = PhotoSizeIndex(PhotoSize::Large);
return loading() ? _images[index].loader->currentProgress() : 0.;
}
bool PhotoData::cancelled() const {
const auto index = PhotoSizeIndex(PhotoSize::Large);
return (_images[index].flags & ImageFlag::Cancelled);
}
void PhotoData::setWaitingForAlbum() {
@ -95,7 +132,8 @@ bool PhotoData::waitingForAlbum() const {
}
int32 PhotoData::loadOffset() const {
return _large->loadOffset();
const auto index = PhotoSizeIndex(PhotoSize::Large);
return loading() ? _images[index].loader->currentOffset() : 0;
}
bool PhotoData::uploading() const {
@ -103,11 +141,6 @@ bool PhotoData::uploading() const {
}
void PhotoData::unload() {
// Forget thumbnail only when image cache limit exceeds.
//_thumbnailInline->unload();
_thumbnailSmall->unload();
_thumbnail->unload();
_large->unload();
_replyPreview = nullptr;
}
@ -142,9 +175,9 @@ QByteArray PhotoData::fileReference() const {
void PhotoData::refreshFileReference(const QByteArray &value) {
_fileReference = value;
_thumbnailSmall->refreshFileReference(value);
_thumbnail->refreshFileReference(value);
_large->refreshFileReference(value);
for (auto &image : _images) {
image.location.refreshFileReference(value);
}
}
void PhotoData::collectLocalData(not_null<PhotoData*> local) {
@ -152,83 +185,185 @@ void PhotoData::collectLocalData(not_null<PhotoData*> local) {
return;
}
const auto copyImage = [&](const ImagePtr &src, const ImagePtr &dst) {
if (const auto from = src->cacheKey()) {
if (const auto to = dst->cacheKey()) {
for (auto i = 0; i != kPhotoSizeCount; ++i) {
if (const auto from = local->_images[i].location.file().cacheKey()) {
if (const auto to = _images[i].location.file().cacheKey()) {
_owner->cache().copyIfEmpty(from, to);
}
}
};
copyImage(local->_thumbnailSmall, _thumbnailSmall);
copyImage(local->_thumbnail, _thumbnail);
copyImage(local->_large, _large);
}
if (const auto localMedia = local->activeMediaView()) {
const auto media = createMediaView();
media->collectLocalData(localMedia.get());
// Keep DocumentMedia alive for some more time.
// NB! This allows DocumentMedia to outlive Main::Session!
// In case this is a problem this code should be rewritten.
crl::on_main(&session(), [media] {});
}
}
bool PhotoData::isNull() const {
return _large->isNull();
return !_images[PhotoSizeIndex(PhotoSize::Large)].location.valid();
}
void PhotoData::loadThumbnail(Data::FileOrigin origin) {
_thumbnail->load(origin);
void PhotoData::load(
PhotoSize size,
Data::FileOrigin origin,
LoadFromCloudSetting fromCloud,
bool autoLoading) {
const auto index = PhotoSizeIndex(size);
auto &image = _images[index];
if (image.loader) {
if (fromCloud == LoadFromCloudOrLocal) {
image.loader->permitLoadFromCloud();
}
return;
} else if ((image.flags & ImageFlag::Failed)
|| !image.location.valid()) {
return;
} else if (const auto active = activeMediaView()) {
if (active->image(size)) {
return;
}
}
image.flags &= ~ImageFlag::Cancelled;
image.loader = CreateFileLoader(
image.location.file(),
origin,
QString(),
image.byteSize,
UnknownFileLocation,
LoadToCacheAsWell,
fromCloud,
autoLoading,
Data::kImageCacheTag);
image.loader->updates(
) | rpl::start_with_next_error_done([=] {
if (size == PhotoSize::Large) {
_owner->photoLoadProgress(this);
}
}, [=, &image](bool started) {
finishLoad(size);
image.flags |= ImageFlag::Failed;
if (size == PhotoSize::Large) {
_owner->photoLoadFail(this, started);
}
}, [=, &image] {
finishLoad(size);
if (size == PhotoSize::Large) {
_owner->photoLoadDone(this);
}
}, image.loader->lifetime());
image.loader->start();
if (size == PhotoSize::Large) {
_owner->notifyPhotoLayoutChanged(this);
}
}
void PhotoData::loadThumbnailSmall(Data::FileOrigin origin) {
_thumbnailSmall->load(origin);
void PhotoData::finishLoad(PhotoSize size) {
const auto index = PhotoSizeIndex(size);
auto &image = _images[index];
// NB! image.loader may be in ~FileLoader() already.
const auto guard = gsl::finally([&] {
destroyLoader(size);
});
if (!image.loader || image.loader->cancelled()) {
image.flags |= ImageFlag::Cancelled;
return;
} else if (auto read = image.loader->imageData(); read.isNull()) {
image.flags |= ImageFlag::Failed;
} else if (const auto active = activeMediaView()) {
active->set(size, std::move(read));
}
}
Image *PhotoData::thumbnailInline() const {
return _thumbnailInline ? _thumbnailInline.get() : nullptr;
void PhotoData::destroyLoader(PhotoSize size) {
const auto index = PhotoSizeIndex(size);
auto &image = _images[index];
// NB! image.loader may be in ~FileLoader() already.
if (!image.loader) {
return;
}
const auto loader = base::take(image.loader);
if (image.flags & ImageFlag::Cancelled) {
loader->cancel();
}
}
not_null<Image*> PhotoData::thumbnailSmall() const {
return _thumbnailSmall.get();
std::shared_ptr<PhotoMedia> PhotoData::createMediaView() {
if (auto result = activeMediaView()) {
return result;
}
auto result = std::make_shared<PhotoMedia>(this);
_media = result;
return result;
}
not_null<Image*> PhotoData::thumbnail() const {
return _thumbnail.get();
}
void PhotoData::load(Data::FileOrigin origin) {
_large->load(origin);
}
not_null<Image*> PhotoData::large() const {
return _large.get();
std::shared_ptr<PhotoMedia> PhotoData::activeMediaView() const {
return _media.lock();
}
void PhotoData::updateImages(
ImagePtr thumbnailInline,
ImagePtr thumbnailSmall,
ImagePtr thumbnail,
ImagePtr large) {
if (!thumbnailSmall || !thumbnail || !large) {
return;
const QByteArray &inlineThumbnailBytes,
const ImageWithLocation &small,
const ImageWithLocation &thumbnail,
const ImageWithLocation &large) {
if (!inlineThumbnailBytes.isEmpty()
&& _inlineThumbnailBytes.isEmpty()) {
_inlineThumbnailBytes = inlineThumbnailBytes;
}
if (thumbnailInline && !_thumbnailInline) {
_thumbnailInline = thumbnailInline;
}
const auto update = [](ImagePtr &was, ImagePtr now) {
if (!was) {
was = now;
} else if (was->isDelayedStorageImage()) {
if (const auto location = now->location(); location.valid()) {
was->setDelayedStorageLocation(
Data::FileOrigin(),
location);
const auto update = [&](PhotoSize size, const ImageWithLocation &data) {
auto &image = _images[PhotoSizeIndex(size)];
if (data.location.valid()
&& (!image.location.valid()
|| image.location.width() != data.location.width()
|| image.location.height() != data.location.height())) {
image.location = data.location;
image.byteSize = data.bytesCount;
if (!data.preloaded.isNull()) {
image.loader = nullptr;
if (const auto media = activeMediaView()) {
media->set(size, data.preloaded);
}
} else if (image.loader) {
const auto origin = base::take(image.loader)->fileOrigin();
load(size, origin);
}
if (!data.bytes.isEmpty()) {
if (const auto cacheKey = image.location.file().cacheKey()) {
owner().cache().putIfEmpty(
cacheKey,
Storage::Cache::Database::TaggedValue(
base::duplicate(data.bytes),
Data::kImageCacheTag));
}
}
}
//if (was->isDelayedStorageImage()) { // #TODO optimize
// if (const auto location = now->location(); location.valid()) {
// was->setDelayedStorageLocation(
// Data::FileOrigin(),
// location);
// }
//}
};
update(_thumbnailSmall, thumbnailSmall);
update(_thumbnail, thumbnail);
update(_large, large);
update(PhotoSize::Small, small);
update(PhotoSize::Thumbnail, thumbnail);
update(PhotoSize::Large, large);
}
int PhotoData::width() const {
return _large->width();
return _images[PhotoSizeIndex(PhotoSize::Large)].location.width();
}
int PhotoData::height() const {
return _large->height();
return _images[PhotoSizeIndex(PhotoSize::Large)].location.height();
}
PhotoClickHandler::PhotoClickHandler(
@ -255,7 +390,7 @@ void PhotoSaveClickHandler::onClickImpl() const {
if (!data->date) {
return;
} else {
data->download(context());
data->load(context());
}
}

View File

@ -14,8 +14,26 @@ class Session;
} // namespace Main
namespace Data {
class Session;
class ReplyPreview;
class PhotoMedia;
inline constexpr auto kPhotoSizeCount = 3;
enum class PhotoSize : uchar {
Small,
Thumbnail,
Large,
};
[[nodiscard]] inline int PhotoSizeIndex(PhotoSize size) {
Expects(static_cast<int>(size) >= 0
&& static_cast<int>(size) < kPhotoSizeCount);
return static_cast<int>(size);
}
} // namespace Data
class PhotoData final {
@ -25,20 +43,17 @@ public:
[[nodiscard]] Data::Session &owner() const;
[[nodiscard]] Main::Session &session() const;
[[nodiscard]] bool isNull() const;
void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item);
void automaticLoadSettingsChanged();
void download(Data::FileOrigin origin);
[[nodiscard]] bool loaded() const;
[[nodiscard]] bool loading() const;
[[nodiscard]] bool displayLoading() const;
void cancel();
[[nodiscard]] float64 progress() const;
[[nodiscard]] int32 loadOffset() const;
[[nodiscard]] bool uploading() const;
[[nodiscard]] bool cancelled() const;
void setWaitingForAlbum();
[[nodiscard]] bool waitingForAlbum() const;
@ -60,27 +75,39 @@ public:
// to (this) received from the server "same" photo.
void collectLocalData(not_null<PhotoData*> local);
bool isNull() const;
[[nodiscard]] std::shared_ptr<Data::PhotoMedia> createMediaView();
[[nodiscard]] auto activeMediaView() const
-> std::shared_ptr<Data::PhotoMedia>;
void loadThumbnail(Data::FileOrigin origin);
void loadThumbnailSmall(Data::FileOrigin origin);
Image *thumbnailInline() const;
not_null<Image*> thumbnailSmall() const;
not_null<Image*> thumbnail() const;
void updateImages(
const QByteArray &inlineThumbnailBytes,
const ImageWithLocation &small,
const ImageWithLocation &thumbnail,
const ImageWithLocation &large);
void load(Data::FileOrigin origin);
not_null<Image*> large() const;
[[nodiscard]] QByteArray inlineThumbnailBytes() const {
return _inlineThumbnailBytes;
}
void load(
Data::FileOrigin origin,
LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal,
bool autoLoading = false);
[[nodiscard]] bool loading(Data::PhotoSize size) const;
[[nodiscard]] bool failed(Data::PhotoSize size) const;
void load(
Data::PhotoSize size,
Data::FileOrigin origin,
LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal,
bool autoLoading = false);
[[nodiscard]] const ImageLocation &location(Data::PhotoSize size) const;
[[nodiscard]] int imageByteSize(Data::PhotoSize size) const;
// For now they return size of the 'large' image.
int width() const;
int height() const;
void updateImages(
ImagePtr thumbnailInline,
ImagePtr thumbnailSmall,
ImagePtr thumbnail,
ImagePtr large);
PhotoId id = 0;
TimeId date = 0;
bool hasSticker = false;
@ -91,15 +118,30 @@ public:
std::unique_ptr<Data::UploadState> uploadingData;
private:
ImagePtr _thumbnailInline;
ImagePtr _thumbnailSmall;
ImagePtr _thumbnail;
ImagePtr _large;
enum class ImageFlag : uchar {
Cancelled = 0x01,
Failed = 0x02,
};
friend inline constexpr bool is_flag_type(ImageFlag) { return true; };
struct Image final {
ImageLocation location;
std::unique_ptr<FileLoader> loader;
int byteSize = 0;
base::flags<ImageFlag> flags;
};
void finishLoad(Data::PhotoSize size);
void destroyLoader(Data::PhotoSize size);
QByteArray _inlineThumbnailBytes;
std::array<Image, Data::kPhotoSizeCount> _images;
int32 _dc = 0;
uint64 _access = 0;
QByteArray _fileReference;
std::unique_ptr<Data::ReplyPreview> _replyPreview;
std::weak_ptr<Data::PhotoMedia> _media;
not_null<Data::Session*> _owner;

View File

@ -0,0 +1,119 @@
/*
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_photo_media.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_auto_download.h"
#include "main/main_session.h"
#include "history/history_item.h"
#include "history/history.h"
#include "storage/file_download.h"
#include "ui/image/image.h"
//#include "facades.h"
//#include "app.h"
namespace Data {
PhotoMedia::PhotoMedia(not_null<PhotoData*> owner)
: _owner(owner) {
}
// NB! Right now DocumentMedia can outlive Main::Session!
// In DocumentData::collectLocalData a shared_ptr is sent on_main.
// In case this is a problem the ~Gif code should be rewritten.
PhotoMedia::~PhotoMedia() = default;
not_null<PhotoData*> PhotoMedia::owner() const {
return _owner;
}
Image *PhotoMedia::thumbnailInline() const {
if (!_inlineThumbnail) {
auto image = Images::FromInlineBytes(_owner->inlineThumbnailBytes());
if (!image.isNull()) {
_inlineThumbnail = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(
std::move(image),
"PNG"));
}
}
return _inlineThumbnail.get();
}
Image *PhotoMedia::image(PhotoSize size) const {
return _images[PhotoSizeIndex(size)].get();
}
void PhotoMedia::wanted(PhotoSize size, Data::FileOrigin origin) {
const auto index = PhotoSizeIndex(size);
if (!_images[index]) {
_owner->load(size, origin);
}
}
QSize PhotoMedia::size(PhotoSize size) const {
const auto index = PhotoSizeIndex(size);
if (const auto image = _images[index].get()) {
return image->size();
}
const auto &location = _owner->location(size);
return { location.width(), location.height() };
}
void PhotoMedia::set(PhotoSize size, QImage image) {
_images[PhotoSizeIndex(size)] = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(std::move(image), "PNG"));
_owner->session().downloaderTaskFinished().notify();
}
bool PhotoMedia::loaded() const {
const auto index = PhotoSizeIndex(PhotoSize::Large);
return (_images[index] != nullptr);
}
float64 PhotoMedia::progress() const {
return (_owner->uploading() || _owner->loading())
? _owner->progress()
: (loaded() ? 1. : 0.);
}
void PhotoMedia::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
const auto index = PhotoSizeIndex(PhotoSize::Large);
if (!item || loaded() || _owner->cancelled()) {
return;
}
const auto loadFromCloud = Data::AutoDownload::Should(
_owner->session().settings().autoDownload(),
item->history()->peer,
_owner);
_owner->load(
origin,
loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly,
true);
}
void PhotoMedia::collectLocalData(not_null<PhotoMedia*> local) {
if (const auto image = local->_inlineThumbnail.get()) {
_inlineThumbnail = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(image->original(), "PNG"));
}
for (auto i = 0; i != kPhotoSizeCount; ++i) {
if (const auto image = local->_images[i].get()) {
_images[i] = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(
image->original(),
"PNG"));
}
}
}
} // namespace Data

View File

@ -0,0 +1,48 @@
/*
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"
#include "data/data_photo.h"
class FileLoader;
namespace Data {
class PhotoMedia final {
public:
explicit PhotoMedia(not_null<PhotoData*> owner);
~PhotoMedia();
[[nodiscard]] not_null<PhotoData*> owner() const;
[[nodiscard]] Image *thumbnailInline() const;
[[nodiscard]] Image *image(PhotoSize size) const;
[[nodiscard]] QSize size(PhotoSize size) const;
void wanted(PhotoSize size, Data::FileOrigin origin);
void set(PhotoSize size, QImage image);
[[nodiscard]] bool loaded() const;
[[nodiscard]] float64 progress() const;
void automaticLoad(Data::FileOrigin origin, const HistoryItem *item);
void collectLocalData(not_null<PhotoMedia*> local);
private:
// NB! Right now DocumentMedia can outlive Main::Session!
// In DocumentData::collectLocalData a shared_ptr is sent on_main.
// In case this is a problem the ~Gif code should be rewritten.
const not_null<PhotoData*> _owner;
mutable std::unique_ptr<Image> _inlineThumbnail;
std::array<std::unique_ptr<Image>, kPhotoSizeCount> _images;
};
} // namespace Data

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
@ -62,18 +63,18 @@ Image *ReplyPreview::image(Data::FileOrigin origin) {
return _image.get();
}
if (_document) {
if (!_documentMedia) {
_documentMedia = _document->createMediaView();
}
const auto thumbnail = _documentMedia->thumbnail();
if (!_image || (!_good && thumbnail)) {
if (!_image || (!_good && _document->hasThumbnail())) {
if (!_documentMedia) {
_documentMedia = _document->createMediaView();
_documentMedia->thumbnailWanted(origin);
}
const auto thumbnail = _documentMedia->thumbnail();
const auto option = _document->isVideoMessage()
? Images::Option::Circled
: Images::Option::None;
if (thumbnail) {
prepare(thumbnail, option);
} else {
_documentMedia->thumbnailWanted(origin);
if (const auto image = _documentMedia->thumbnailInline()) {
prepare(image, option | Images::Option::Blurred);
}
@ -85,22 +86,33 @@ Image *ReplyPreview::image(Data::FileOrigin origin) {
}
} else {
Assert(_photo != nullptr);
const auto small = _photo->thumbnailSmall();
const auto large = _photo->large();
if (!_image || (!_good && (small->loaded() || large->loaded()))) {
if (small->isDelayedStorageImage()
&& !large->isNull()
&& !large->isDelayedStorageImage()
&& large->loaded()) {
prepare(large, Images::Option(0));
} else if (small->loaded()) {
prepare(small, Images::Option(0));
} else {
small->load(origin);
if (const auto blurred = _photo->thumbnailInline()) {
prepare(blurred, Images::Option::Blurred);
}
if (!_image || !_good) {
if (!_photoMedia) {
_photoMedia = _photo->createMediaView();
_photoMedia->wanted(PhotoSize::Small, origin);
}
if (const auto small = _photoMedia->image(PhotoSize::Small)) {
prepare(small, Images::Option(0));
} else if (const auto large = _photoMedia->image(
PhotoSize::Large)) {
prepare(large, Images::Option(0));
} else if (const auto blurred = _photoMedia->thumbnailInline()) {
prepare(blurred, Images::Option::Blurred);
}
//if (small->isDelayedStorageImage() // #TODO optimize
// && !large->isNull()
// && !large->isDelayedStorageImage()
// && large->loaded()) {
// prepare(large, Images::Option(0));
//} else if (small->loaded()) {
// prepare(small, Images::Option(0));
//} else {
// small->load(origin);
// if (const auto blurred = _photo->thumbnailInline()) {
// prepare(blurred, Images::Option::Blurred);
// }
//}
}
}
return _image.get();

View File

@ -12,6 +12,7 @@ class PhotoData;
namespace Data {
class PhotoMedia;
class DocumentMedia;
struct FileOrigin;
@ -26,11 +27,12 @@ private:
void prepare(not_null<Image*> image, Images::Options options);
std::unique_ptr<Image> _image;
PhotoData *_photo = nullptr;
DocumentData *_document = nullptr;
std::shared_ptr<PhotoMedia> _photoMedia;
std::shared_ptr<DocumentMedia> _documentMedia;
bool _good = false;
bool _checked = false;
DocumentData *_document = nullptr;
PhotoData *_photo = nullptr;
std::shared_ptr<DocumentMedia> _documentMedia;
};

View File

@ -75,10 +75,10 @@ using ViewElement = HistoryView::Element;
// b: crop 320x320
// c: crop 640x640
// d: crop 1280x1280
const auto InlineLevels = QByteArray::fromRawData("i", 1);
const auto SmallLevels = QByteArray::fromRawData("sambcxydwi", 10);
const auto ThumbnailLevels = QByteArray::fromRawData("mbcxasydwi", 10);
const auto LargeLevels = QByteArray::fromRawData("yxwmsdcbai", 10);
const auto InlineLevels = "i"_q;
const auto SmallLevels = "sambcxydwi"_q;
const auto ThumbnailLevels = "mbcxasydwi"_q;
const auto LargeLevels = "yxwmsdcbai"_q;
void CheckForSwitchInlineButton(not_null<HistoryItem*> item) {
if (item->out() || !item->hasSwitchInlineButton()) {
@ -127,23 +127,22 @@ std::vector<UnavailableReason> ExtractUnavailableReasons(
}) | ranges::to_vector;
}
QByteArray FindDocumentInlineThumbnail(const MTPDdocument &data) {
const auto thumbs = data.vthumbs();
if (!thumbs) {
return QByteArray();
}
const auto &list = thumbs->v;
[[nodiscard]] QByteArray FindInlineThumbnail(
const QVector<MTPPhotoSize> &sizes) {
const auto i = ranges::find(
list,
sizes,
mtpc_photoStrippedSize,
&MTPPhotoSize::type);
if (i == list.end()) {
return QByteArray();
}
return i->c_photoStrippedSize().vbytes().v;
return (i != sizes.end())
? i->c_photoStrippedSize().vbytes().v
: QByteArray();
}
MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
[[nodiscard]] QByteArray FindDocumentInlineThumbnail(const MTPDdocument &data) {
return FindInlineThumbnail(data.vthumbs().value_or_empty());
}
[[nodiscard]] MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
const auto area = [](const MTPPhotoSize &size) {
static constexpr auto kInvalid = 0;
return size.match([](const MTPDphotoSizeEmpty &) {
@ -165,7 +164,7 @@ MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
}
std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
[[nodiscard]] std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
const MTPDdocument &data) {
const auto area = [](const MTPVideoSize &size) {
static constexpr auto kInvalid = 0;
@ -184,7 +183,11 @@ std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
: std::nullopt;
}
rpl::producer<int> PinnedDialogsCountMaxValue(
[[nodiscard]] QByteArray FindPhotoInlineThumbnail(const MTPDphoto &data) {
return FindInlineThumbnail(data.vsizes().v);
}
[[nodiscard]] rpl::producer<int> PinnedDialogsCountMaxValue(
not_null<Main::Session*> session) {
return rpl::single(
rpl::empty_value()
@ -1099,6 +1102,15 @@ void Session::notifyPhotoLayoutChanged(not_null<const PhotoData*> photo) {
}
}
void Session::requestPhotoViewRepaint(not_null<const PhotoData*> photo) {
const auto i = _photoItems.find(photo);
if (i != end(_photoItems)) {
for (const auto item : i->second) {
requestItemRepaint(item);
}
}
}
void Session::notifyDocumentLayoutChanged(
not_null<const DocumentData*> document) {
const auto i = _documentItems.find(document);
@ -1153,6 +1165,20 @@ void Session::documentLoadFail(
notifyDocumentLayoutChanged(document);
}
void Session::photoLoadProgress(not_null<PhotoData*> photo) {
requestPhotoViewRepaint(photo);
}
void Session::photoLoadDone(not_null<PhotoData*> photo) {
notifyPhotoLayoutChanged(photo);
}
void Session::photoLoadFail(
not_null<PhotoData*> photo,
bool started) {
notifyPhotoLayoutChanged(photo);
}
void Session::markMediaRead(not_null<const DocumentData*> document) {
const auto i = _documentItems.find(document);
if (i != end(_documentItems)) {
@ -2174,11 +2200,10 @@ not_null<PhotoData*> Session::processPhoto(
const auto image = [&](const QByteArray &levels) {
const auto i = find(levels);
return (i == thumbs.end())
? ImagePtr()
: Images::Create(base::duplicate(i->second), "JPG");
? ImageWithLocation()
: Images::FromImageInMemory(i->second, "JPG");
};
const auto thumbnailInline = image(InlineLevels);
const auto thumbnailSmall = image(SmallLevels);
const auto small = image(SmallLevels);
const auto thumbnail = image(ThumbnailLevels);
const auto large = image(LargeLevels);
return data.match([&](const MTPDphoto &data) {
@ -2189,8 +2214,8 @@ not_null<PhotoData*> Session::processPhoto(
data.vdate().v,
data.vdc_id().v,
data.is_has_stickers(),
thumbnailInline,
thumbnailSmall,
QByteArray(),
small,
thumbnail,
large);
}, [&](const MTPDphotoEmpty &data) {
@ -2205,10 +2230,10 @@ not_null<PhotoData*> Session::photo(
TimeId date,
int32 dc,
bool hasSticker,
const ImagePtr &thumbnailInline,
const ImagePtr &thumbnailSmall,
const ImagePtr &thumbnail,
const ImagePtr &large) {
const QByteArray &inlineThumbnailBytes,
const ImageWithLocation &small,
const ImageWithLocation &thumbnail,
const ImageWithLocation &large) {
const auto result = photo(id);
photoApplyFields(
result,
@ -2217,8 +2242,8 @@ not_null<PhotoData*> Session::photo(
date,
dc,
hasSticker,
thumbnailInline,
thumbnailSmall,
inlineThumbnailBytes,
small,
thumbnail,
large);
return result;
@ -2252,26 +2277,28 @@ void Session::photoConvert(
PhotoData *Session::photoFromWeb(
const MTPWebDocument &data,
ImagePtr thumbnail,
const ImageLocation &thumbnailLocation,
bool willBecomeNormal) {
const auto large = Images::Create(data);
const auto large = Images::FromWebDocument(data);
const auto thumbnailInline = ImagePtr();
if (large->isNull()) {
if (!large.valid()) {
return nullptr;
}
auto thumbnailSmall = large;
auto small = large;
auto thumbnail = thumbnailLocation;
if (willBecomeNormal) {
const auto width = large->width();
const auto height = large->height();
const auto width = large.width();
const auto height = large.height();
auto thumbsize = shrinkToKeepAspect(width, height, 100, 100);
thumbnailSmall = Images::Create(thumbsize.width(), thumbsize.height());
// #TODO optimize
//auto thumbsize = shrinkToKeepAspect(width, height, 100, 100);
//small = Images::Create(thumbsize.width(), thumbsize.height());
if (thumbnail->isNull()) {
auto mediumsize = shrinkToKeepAspect(width, height, 320, 320);
thumbnail = Images::Create(mediumsize.width(), mediumsize.height());
}
} else if (thumbnail->isNull()) {
//if (!thumbnail.valid()) {
// auto mediumsize = shrinkToKeepAspect(width, height, 320, 320);
// thumbnail = Images::Create(mediumsize.width(), mediumsize.height());
//}
} else if (!thumbnail.valid()) {
thumbnail = large;
}
@ -2282,10 +2309,10 @@ PhotoData *Session::photoFromWeb(
base::unixtime::now(),
0,
false,
thumbnailInline,
thumbnailSmall,
thumbnail,
large);
QByteArray(),
ImageWithLocation{ .location = small },
ImageWithLocation{ .location = thumbnail },
ImageWithLocation{ .location = large });
}
void Session::photoApplyFields(
@ -2319,13 +2346,12 @@ void Session::photoApplyFields(
};
const auto image = [&](const QByteArray &levels) {
const auto i = find(levels);
return (i == sizes.end()) ? ImagePtr() : Images::Create(data, *i);
return (i == sizes.end())
? ImageWithLocation()
: Images::FromPhotoSize(_session, data, *i);
};
const auto thumbnailInline = image(InlineLevels);
const auto thumbnailSmall = image(SmallLevels);
const auto thumbnail = image(ThumbnailLevels);
const auto large = image(LargeLevels);
if (thumbnailSmall && thumbnail && large) {
if (large.location.valid()) {
photoApplyFields(
photo,
data.vaccess_hash().v,
@ -2333,9 +2359,9 @@ void Session::photoApplyFields(
data.vdate().v,
data.vdc_id().v,
data.is_has_stickers(),
thumbnailInline,
thumbnailSmall,
thumbnail,
FindPhotoInlineThumbnail(data),
image(SmallLevels),
image(ThumbnailLevels),
large);
}
}
@ -2347,10 +2373,10 @@ void Session::photoApplyFields(
TimeId date,
int32 dc,
bool hasSticker,
const ImagePtr &thumbnailInline,
const ImagePtr &thumbnailSmall,
const ImagePtr &thumbnail,
const ImagePtr &large) {
const QByteArray &inlineThumbnailBytes,
const ImageWithLocation &small,
const ImageWithLocation &thumbnail,
const ImageWithLocation &large) {
if (!date) {
return;
}
@ -2358,8 +2384,8 @@ void Session::photoApplyFields(
photo->date = date;
photo->hasSticker = hasSticker;
photo->updateImages(
thumbnailInline,
thumbnailSmall,
inlineThumbnailBytes,
small,
thumbnail,
large);
}

View File

@ -427,12 +427,17 @@ public:
void documentLoadSettingsChanged();
void notifyPhotoLayoutChanged(not_null<const PhotoData*> photo);
void requestPhotoViewRepaint(not_null<const PhotoData*> photo);
void notifyDocumentLayoutChanged(
not_null<const DocumentData*> document);
void requestDocumentViewRepaint(not_null<const DocumentData*> document);
void markMediaRead(not_null<const DocumentData*> document);
void requestPollViewRepaint(not_null<const PollData*> poll);
void photoLoadProgress(not_null<PhotoData*> photo);
void photoLoadDone(not_null<PhotoData*> photo);
void photoLoadFail(not_null<PhotoData*> photo, bool started);
void documentLoadProgress(not_null<DocumentData*> document);
void documentLoadDone(not_null<DocumentData*> document);
void documentLoadFail(not_null<DocumentData*> document, bool started);
@ -473,16 +478,16 @@ public:
TimeId date,
int32 dc,
bool hasSticker,
const ImagePtr &thumbnailInline,
const ImagePtr &thumbnailSmall,
const ImagePtr &thumbnail,
const ImagePtr &large);
const QByteArray &inlineThumbnailBytes,
const ImageWithLocation &small,
const ImageWithLocation &thumbnail,
const ImageWithLocation &large);
void photoConvert(
not_null<PhotoData*> original,
const MTPPhoto &data);
[[nodiscard]] PhotoData *photoFromWeb(
const MTPWebDocument &data,
ImagePtr thumbnail = ImagePtr(),
const ImageLocation &thumbnailLocation = ImageLocation(),
bool willBecomeNormal = false);
[[nodiscard]] not_null<DocumentData*> document(DocumentId id);
@ -736,10 +741,10 @@ private:
TimeId date,
int32 dc,
bool hasSticker,
const ImagePtr &thumbnailInline,
const ImagePtr &thumbnailSmall,
const ImagePtr &thumbnail,
const ImagePtr &large);
const QByteArray &inlineThumbnailBytes,
const ImageWithLocation &small,
const ImageWithLocation &thumbnail,
const ImageWithLocation &large);
void documentApplyFields(
not_null<DocumentData*> document,

View File

@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_participants_box.h"
#include "data/data_session.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_document.h"
#include "data/data_media_types.h"
#include "data/data_file_origin.h"
@ -1137,11 +1138,13 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
}
void InnerWidget::savePhotoToFile(PhotoData *photo) {
if (!photo || photo->isNull() || !photo->loaded()) {
void InnerWidget::savePhotoToFile(not_null<PhotoData*> photo) {
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
}
const auto image = media->image(Data::PhotoSize::Large)->original();
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
FileDialog::GetWritePath(
this,
@ -1150,22 +1153,26 @@ void InnerWidget::savePhotoToFile(PhotoData *photo) {
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
crl::guard(this, [=](const QString &result) {
if (!result.isEmpty()) {
photo->large()->original().save(result, "JPG");
image.save(result, "JPG");
}
}));
}
void InnerWidget::saveDocumentToFile(DocumentData *document) {
void InnerWidget::saveDocumentToFile(not_null<DocumentData*> document) {
DocumentSaveClickHandler::Save(
Data::FileOrigin(),
document,
DocumentSaveClickHandler::Mode::ToNewFile);
}
void InnerWidget::copyContextImage(PhotoData *photo) {
if (!photo || photo->isNull() || !photo->loaded()) return;
void InnerWidget::copyContextImage(not_null<PhotoData*> photo) {
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
}
QGuiApplication::clipboard()->setImage(photo->large()->original());
const auto image = media->image(Data::PhotoSize::Large)->original();
QGuiApplication::clipboard()->setImage(image);
}
void InnerWidget::copySelectedText() {

View File

@ -162,9 +162,9 @@ private:
QPoint mapPointToItem(QPoint point, const Element *view) const;
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
void savePhotoToFile(PhotoData *photo);
void saveDocumentToFile(DocumentData *document);
void copyContextImage(PhotoData *photo);
void savePhotoToFile(not_null<PhotoData*> photo);
void saveDocumentToFile(not_null<DocumentData*> document);
void copyContextImage(not_null<PhotoData*> photo);
void showStickerPackInfo(not_null<DocumentData*> document);
void cancelContextDownload(not_null<DocumentData*> document);
void showContextInFolder(not_null<DocumentData*> document);

View File

@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_poll.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
@ -1853,8 +1854,12 @@ void HistoryInner::copySelectedText() {
}
void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
if (photo->isNull() || !photo->loaded()) return;
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
}
const auto image = media->image(Data::PhotoSize::Large)->original();
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
FileDialog::GetWritePath(
this,
@ -1865,15 +1870,19 @@ void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
qsl(".jpg")),
crl::guard(this, [=](const QString &result) {
if (!result.isEmpty()) {
photo->large()->original().save(result, "JPG");
image.save(result, "JPG");
}
}));
}
void HistoryInner::copyContextImage(not_null<PhotoData*> photo) {
if (photo->isNull() || !photo->loaded()) return;
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
}
QGuiApplication::clipboard()->setImage(photo->large()->original());
const auto image = media->image(Data::PhotoSize::Large)->original();
QGuiApplication::clipboard()->setImage(image);
}
void HistoryInner::showStickerPackInfo(not_null<DocumentData*> document) {

View File

@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/confirm_box.h"
#include "boxes/sticker_set_box.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_document.h"
#include "data/data_media_types.h"
#include "data/data_session.h"
@ -72,10 +73,12 @@ MsgId ItemIdAcrossData(not_null<HistoryItem*> item) {
}
void SavePhotoToFile(not_null<PhotoData*> photo) {
if (photo->isNull() || !photo->loaded()) {
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
}
const auto image = media->image(Data::PhotoSize::Large)->original();
FileDialog::GetWritePath(
Core::App().getFileDialogParent(),
tr::lng_save_photo(tr::now),
@ -83,17 +86,19 @@ void SavePhotoToFile(not_null<PhotoData*> photo) {
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
crl::guard(&photo->session(), [=](const QString &result) {
if (!result.isEmpty()) {
photo->large()->original().save(result, "JPG");
image.save(result, "JPG");
}
}));
}
void CopyImage(not_null<PhotoData*> photo) {
if (photo->isNull() || !photo->loaded()) {
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
}
QGuiApplication::clipboard()->setImage(photo->large()->original());
const auto image = media->image(Data::PhotoSize::Large)->original();
QGuiApplication::clipboard()->setImage(image);
}
void ShowStickerPackInfo(not_null<DocumentData*> document) {

View File

@ -18,11 +18,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/grouped_layout.h"
#include "data/data_session.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_file_origin.h"
#include "app.h"
#include "styles/style_history.h"
namespace HistoryView {
namespace {
using Data::PhotoSize;
} // namespace
Photo::Photo(
not_null<Element*> parent,
@ -46,18 +52,48 @@ Photo::Photo(
create(parent->data()->fullId(), chat);
}
Photo::~Photo() = default;
void Photo::create(FullMsgId contextId, PeerData *chat) {
setLinks(
std::make_shared<PhotoOpenClickHandler>(_data, contextId, chat),
std::make_shared<PhotoSaveClickHandler>(_data, contextId, chat),
std::make_shared<PhotoCancelClickHandler>(_data, contextId, chat));
if (!_data->thumbnailInline()
&& !_data->loaded()
&& !_data->thumbnail()->loaded()) {
_data->thumbnailSmall()->load(contextId);
if ((_dataMedia = _data->activeMediaView())) {
dataMediaCreated();
} else if (_data->inlineThumbnailBytes().isEmpty()) {
_data->load(PhotoSize::Small, contextId);
}
}
void Photo::ensureDataMediaCreated() const {
if (_dataMedia) {
return;
}
_dataMedia = _data->createMediaView();
dataMediaCreated();
}
void Photo::dataMediaCreated() const {
Expects(_dataMedia != nullptr);
if (!_dataMedia->image(PhotoSize::Large)
&& !_dataMedia->image(PhotoSize::Thumbnail)) {
_dataMedia->wanted(PhotoSize::Small, _realParent->fullId());
}
history()->owner().registerHeavyViewPart(_parent);
}
void Photo::checkHeavyPart() {
if (!_dataMedia) {
history()->owner().unregisterHeavyViewPart(_parent);
}
}
void Photo::unloadHeavyPart() {
_dataMedia = nullptr;
}
QSize Photo::countOptimalSize() {
if (_parent->media() != this) {
_caption = Ui::Text::String();
@ -145,9 +181,10 @@ QSize Photo::countCurrentSize(int newWidth) {
void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
_data->automaticLoad(_realParent->fullId(), _parent->data());
ensureDataMediaCreated();
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
auto selected = (selection == FullSelection);
auto loaded = _data->loaded();
auto loaded = _dataMedia->loaded();
auto displayLoading = _data->displayLoading();
auto inWebPage = (_parent->media() != this);
@ -159,7 +196,7 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
if (displayLoading) {
ensureAnimation();
if (!_animation->radial.animating()) {
_animation->radial.start(_data->progress());
_animation->radial.start(_dataMedia->progress());
}
}
const auto radial = isRadialAnimation();
@ -167,13 +204,15 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
auto rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
if (_serviceWidth > 0) {
const auto pix = [&] {
if (loaded) {
return _data->large()->pixCircled(_realParent->fullId(), _pixw, _pixh);
} else if (_data->thumbnail()->loaded()) {
return _data->thumbnail()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
} else if (_data->thumbnailSmall()->loaded()) {
return _data->thumbnailSmall()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
} else if (const auto blurred = _data->thumbnailInline()) {
if (const auto large = _dataMedia->image(PhotoSize::Large)) {
return large->pixCircled(_realParent->fullId(), _pixw, _pixh);
} else if (const auto thumbnail = _dataMedia->image(
PhotoSize::Thumbnail)) {
return thumbnail->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
} else if (const auto small = _dataMedia->image(
PhotoSize::Small)) {
return small->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
} else if (const auto blurred = _dataMedia->thumbnailInline()) {
return blurred->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
} else {
return QPixmap();
@ -197,13 +236,15 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
| ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
const auto pix = [&] {
if (loaded) {
return _data->large()->pixSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
} else if (_data->thumbnail()->loaded()) {
return _data->thumbnail()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
} else if (_data->thumbnailSmall()->loaded()) {
return _data->thumbnailSmall()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
} else if (const auto blurred = _data->thumbnailInline()) {
if (const auto large = _dataMedia->image(PhotoSize::Large)) {
return large->pixSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
} else if (const auto thumbnail = _dataMedia->image(
PhotoSize::Thumbnail)) {
return thumbnail->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
} else if (const auto small = _dataMedia->image(
PhotoSize::Small)) {
return small->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
} else if (const auto blurred = _dataMedia->thumbnailInline()) {
return blurred->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
} else {
return QPixmap();
@ -241,7 +282,7 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
auto icon = [&]() -> const style::icon* {
if (radial || _data->loading()) {
if (_data->uploading()
|| _data->large()->location().valid()) {
|| _data->location(PhotoSize::Large).valid()) {
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
}
return nullptr;
@ -304,12 +345,13 @@ TextState Photo::textState(QPoint point, StateRequest request) const {
painth -= st::mediaCaptionSkip;
}
if (QRect(paintx, painty, paintw, painth).contains(point)) {
ensureDataMediaCreated();
if (_data->uploading()) {
result.link = _cancell;
} else if (_data->loaded()) {
} else if (_dataMedia->loaded()) {
result.link = _openl;
} else if (_data->loading()) {
if (_data->large()->location().valid()) {
if (_data->location(PhotoSize::Large).valid()) {
result.link = _cancell;
}
} else {
@ -349,19 +391,20 @@ void Photo::drawGrouped(
RectParts corners,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {
_data->automaticLoad(_realParent->fullId(), _parent->data());
ensureDataMediaCreated();
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
validateGroupedCache(geometry, corners, cacheKey, cache);
const auto selected = (selection == FullSelection);
const auto loaded = _data->loaded();
const auto loaded = _dataMedia->loaded();
const auto displayLoading = _data->displayLoading();
const auto bubble = _parent->hasBubble();
if (displayLoading) {
ensureAnimation();
if (!_animation->radial.animating()) {
_animation->radial.start(_data->progress());
_animation->radial.start(_dataMedia->progress());
}
}
const auto radial = isRadialAnimation();
@ -414,7 +457,7 @@ void Photo::drawGrouped(
return &(selected ? st::historyFileThumbWaitingSelected : st::historyFileThumbWaiting);
} else if (radial || _data->loading()) {
if (_data->uploading()
|| _data->large()->location().valid()) {
|| _data->location(PhotoSize::Large).valid()) {
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
}
return nullptr;
@ -455,19 +498,21 @@ TextState Photo::getStateGrouped(
if (!geometry.contains(point)) {
return {};
}
ensureDataMediaCreated();
return TextState(_parent, _data->uploading()
? _cancell
: _data->loaded()
: _dataMedia->loaded()
? _openl
: _data->loading()
? (_data->large()->location().valid()
? (_data->location(PhotoSize::Large).valid()
? _cancell
: nullptr)
: _savel);
}
float64 Photo::dataProgress() const {
return _data->progress();
ensureDataMediaCreated();
return _dataMedia->progress();
}
bool Photo::dataFinished() const {
@ -476,7 +521,8 @@ bool Photo::dataFinished() const {
}
bool Photo::dataLoaded() const {
return _data->loaded();
ensureDataMediaCreated();
return _dataMedia->loaded();
}
bool Photo::needInfoDisplay() const {
@ -491,12 +537,15 @@ void Photo::validateGroupedCache(
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {
using Option = Images::Option;
const auto loaded = _data->loaded();
ensureDataMediaCreated();
const auto loaded = _dataMedia->loaded();
const auto loadLevel = loaded
? 2
: (_data->thumbnailInline()
|| _data->thumbnail()->loaded()
|| _data->thumbnailSmall()->loaded())
: (_dataMedia->thumbnailInline()
|| _dataMedia->image(PhotoSize::Small)
|| _dataMedia->image(PhotoSize::Thumbnail))
? 1
: 0;
const auto width = geometry.width();
@ -523,14 +572,14 @@ void Photo::validateGroupedCache(
{ width, height });
const auto pixWidth = pixSize.width() * cIntRetinaFactor();
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
const auto image = loaded
? _data->large().get()
: _data->thumbnail()->loaded()
? _data->thumbnail().get()
: _data->thumbnailSmall()->loaded()
? _data->thumbnailSmall().get()
: _data->thumbnailInline()
? _data->thumbnailInline()
const auto image = _dataMedia->image(PhotoSize::Large)
? _dataMedia->image(PhotoSize::Large)
: _dataMedia->image(PhotoSize::Thumbnail)
? _dataMedia->image(PhotoSize::Thumbnail)
: _dataMedia->image(PhotoSize::Small)
? _dataMedia->image(PhotoSize::Small)
: _dataMedia->thumbnailInline()
? _dataMedia->thumbnailInline()
: Image::BlankMedia().get();
*cacheKey = key;
@ -556,7 +605,8 @@ bool Photo::needsBubble() const {
}
bool Photo::isReadyForOpen() const {
return _data->loaded();
ensureDataMediaCreated();
return _dataMedia->loaded();
}
void Photo::parentTextUpdated() {

View File

@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_file.h"
namespace Data {
class PhotoMedia;
} // namespace Data
namespace HistoryView {
class Photo : public File {
@ -22,6 +26,7 @@ public:
not_null<PeerData*> chat,
not_null<PhotoData*> photo,
int width);
~Photo();
void draw(Painter &p, const QRect &clip, TextSelection selection, crl::time ms) const override;
TextState textState(QPoint point, StateRequest request) const override;
@ -75,6 +80,9 @@ public:
void parentTextUpdated() override;
void checkHeavyPart() override;
void unloadHeavyPart() override;
protected:
float64 dataProgress() const override;
bool dataFinished() const override;
@ -83,6 +91,9 @@ protected:
private:
void create(FullMsgId contextId, PeerData *chat = nullptr);
void ensureDataMediaCreated() const;
void dataMediaCreated() const;
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;
@ -98,6 +109,7 @@ private:
int _pixw = 1;
int _pixh = 1;
Ui::Text::String _caption;
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
};

View File

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_media_types.h"
#include "data/data_web_page.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_file_origin.h"
#include "app.h"
#include "styles/style_history.h"
@ -32,15 +33,17 @@ namespace {
constexpr auto kMaxOriginalEntryLines = 8192;
int articleThumbWidth(not_null<PhotoData*> thumb, int height) {
auto w = thumb->thumbnail()->width();
auto h = thumb->thumbnail()->height();
return qMax(qMin(height * w / h, height), 1);
const auto size = thumb->location(Data::PhotoSize::Thumbnail);
return size.height()
? qMax(qMin(height * size.width() / size.height(), height), 1)
: 1;
}
int articleThumbHeight(not_null<PhotoData*> thumb, int width) {
return qMax(
thumb->thumbnail()->height() * width / thumb->thumbnail()->width(),
1);
int articleThumbHeight(not_null<Data::PhotoMedia*> thumb, int width) {
const auto size = thumb->size(Data::PhotoSize::Thumbnail);
return size.width()
? std::max(size.height() * width / size.width(), 1)
: 1;
}
std::vector<std::unique_ptr<Data::Media>> PrepareCollageMedia(
@ -410,6 +413,31 @@ void WebPage::refreshParentId(not_null<HistoryItem*> realParent) {
}
}
void WebPage::ensurePhotoMediaCreated() const {
Expects(_data->photo != nullptr);
if (_photoMedia) {
return;
}
_photoMedia = _data->photo->createMediaView();
const auto contextId = _parent->data()->fullId();
_photoMedia->wanted(Data::PhotoSize::Thumbnail, contextId);
history()->owner().registerHeavyViewPart(_parent);
}
void WebPage::checkHeavyPart() {
if (_attach) {
_attach->checkHeavyPart();
}
}
void WebPage::unloadHeavyPart() {
if (_attach) {
_attach->unloadHeavyPart();
}
_photoMedia = nullptr;
}
void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
auto paintx = 0, painty = 0, paintw = width(), painth = height();
@ -440,25 +468,28 @@ void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::tim
auto lineHeight = unitedLineHeight();
if (asArticle()) {
ensurePhotoMediaCreated();
const auto contextId = _parent->data()->fullId();
_data->photo->loadThumbnail(contextId);
bool full = _data->photo->thumbnail()->loaded();
QPixmap pix;
auto pw = qMax(_pixw, lineHeight);
auto ph = _pixh;
auto pixw = _pixw, pixh = articleThumbHeight(_data->photo, _pixw);
const auto maxw = style::ConvertScale(_data->photo->thumbnail()->width());
const auto maxh = style::ConvertScale(_data->photo->thumbnail()->height());
auto pixw = _pixw, pixh = articleThumbHeight(_photoMedia.get(), _pixw);
const auto maxsize = _photoMedia->size(Data::PhotoSize::Thumbnail);
const auto maxw = style::ConvertScale(maxsize.width());
const auto maxh = style::ConvertScale(maxsize.height());
if (pixw * ph != pixh * pw) {
float64 coef = (pixw * ph > pixh * pw) ? qMin(ph / float64(pixh), maxh / float64(pixh)) : qMin(pw / float64(pixw), maxw / float64(pixw));
pixh = qRound(pixh * coef);
pixw = qRound(pixw * coef);
}
if (full) {
pix = _data->photo->thumbnail()->pixSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
} else if (_data->photo->thumbnailSmall()->loaded()) {
pix = _data->photo->thumbnailSmall()->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
} else if (const auto blurred = _data->photo->thumbnailInline()) {
if (const auto thumbnail = _photoMedia->image(
Data::PhotoSize::Thumbnail)) {
pix = thumbnail->pixSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
} else if (const auto small = _photoMedia->image(
Data::PhotoSize::Small)) {
pix = small->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
} else if (const auto blurred = _photoMedia->thumbnailInline()) {
pix = blurred->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
}
p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix);

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Data {
class Media;
class PhotoMedia;
} // namespace Data
namespace HistoryView {
@ -85,16 +86,8 @@ public:
return _attach.get();
}
void checkHeavyPart() override {
if (_attach) {
_attach->checkHeavyPart();
}
}
void unloadHeavyPart() override {
if (_attach) {
_attach->unloadHeavyPart();
}
}
void checkHeavyPart() override;
void unloadHeavyPart() override;
~WebPage();
@ -103,6 +96,8 @@ private:
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;
void ensurePhotoMediaCreated() const;
TextSelection toTitleSelection(TextSelection selection) const;
TextSelection fromTitleSelection(TextSelection selection) const;
TextSelection toDescriptionSelection(TextSelection selection) const;
@ -119,6 +114,7 @@ private:
std::vector<std::unique_ptr<Data::Media>> _collage;
ClickHandlerPtr _openl;
std::unique_ptr<Media> _attach;
mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
bool _asArticle = false;
int _dataVersion = -1;

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "data/data_document_media.h"
#include "styles/style_overview.h"
#include "styles/style_history.h"
@ -47,7 +48,9 @@ FileBase::FileBase(not_null<Context*> context, not_null<Result*> result)
: ItemBase(context, result) {
}
FileBase::FileBase(not_null<Context*> context, DocumentData *document)
FileBase::FileBase(
not_null<Context*> context,
not_null<DocumentData*> document)
: ItemBase(context, document) {
}
@ -87,10 +90,16 @@ int FileBase::content_duration() const {
return getResultDuration();
}
Gif::Gif(not_null<Context*> context, Result *result) : FileBase(context, result) {
Gif::Gif(not_null<Context*> context, not_null<Result*> result)
: FileBase(context, result) {
Expects(getResultDocument() != nullptr);
}
Gif::Gif(not_null<Context*> context, DocumentData *document, bool hasDeleteButton) : FileBase(context, document) {
Gif::Gif(
not_null<Context*> context,
not_null<DocumentData*> document,
bool hasDeleteButton)
: FileBase(context, document) {
if (hasDeleteButton) {
_delete = std::make_shared<DeleteSavedGifClickHandler>(document);
}
@ -428,7 +437,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
}
}
Sticker::Sticker(not_null<Context*> context, Result *result)
Sticker::Sticker(not_null<Context*> context, not_null<Result*> result)
: FileBase(context, result) {
}
@ -455,6 +464,12 @@ void Sticker::ensureDataMediaCreated(not_null<DocumentData*> document) const {
_dataMedia = document->createMediaView();
}
void Sticker::unloadHeavyPart() {
_dataMedia = nullptr;
_lifetime.destroy();
_lottie = nullptr;
}
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
ensureDataMediaCreated(getShownDocument());
bool loaded = _dataMedia->loaded();
@ -572,8 +587,9 @@ void Sticker::prepareThumbnail() const {
}
}
Photo::Photo(not_null<Context*> context, Result *result)
Photo::Photo(not_null<Context*> context, not_null<Result*> result)
: ItemBase(context, result) {
Expects(getShownPhoto() != nullptr);
}
void Photo::initDimensions() {
@ -611,15 +627,20 @@ TextState Photo::getState(
return {};
}
void Photo::unloadHeavyPart() {
getShownPhoto()->unload();
_photoMedia = nullptr;
}
PhotoData *Photo::getShownPhoto() const {
if (PhotoData *result = getPhoto()) {
if (const auto result = getPhoto()) {
return result;
}
return getResultPhoto();
}
QSize Photo::countFrameSize() const {
PhotoData *photo = getShownPhoto();
const auto photo = getShownPhoto();
int32 framew = photo->width(), frameh = photo->height(), height = st::inlineMediaHeight;
if (framew * height > frameh * _width) {
if (framew < st::maxStickerSize || frameh > height) {
@ -672,15 +693,20 @@ void Photo::validateThumbnail(
void Photo::prepareThumbnail(QSize size, QSize frame) const {
if (const auto photo = getShownPhoto()) {
validateThumbnail(photo->thumbnail(), size, frame, true);
validateThumbnail(photo->thumbnailSmall(), size, frame, false);
validateThumbnail(photo->thumbnailInline(), size, frame, false);
using PhotoSize = Data::PhotoSize;
if (!_photoMedia) {
_photoMedia = photo->createMediaView();
_photoMedia->wanted(PhotoSize::Thumbnail, fileOrigin());
}
validateThumbnail(_photoMedia->image(PhotoSize::Thumbnail), size, frame, true);
validateThumbnail(_photoMedia->image(PhotoSize::Small), size, frame, false);
validateThumbnail(_photoMedia->thumbnailInline(), size, frame, false);
} else if (const auto thumbnail = getResultThumb()) {
validateThumbnail(thumbnail, size, frame, true);
}
}
Video::Video(not_null<Context*> context, Result *result)
Video::Video(not_null<Context*> context, not_null<Result*> result)
: FileBase(context, result)
, _link(getResultPreviewHandler())
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
@ -765,6 +791,10 @@ void Video::paint(Painter &p, const QRect &clip, const PaintContext *context) co
}
}
void Video::unloadHeavyPart() {
_documentMedia = nullptr;
}
TextState Video::getState(
QPoint point,
StateRequest request) const {
@ -951,6 +981,10 @@ void File::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
}
}
void File::unloadHeavyPart() {
_documentMedia = nullptr;
}
File::~File() {
unregDocumentItem(_document, this);
}
@ -1056,7 +1090,8 @@ void File::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 r
}
}
Contact::Contact(not_null<Context*> context, Result *result) : ItemBase(context, result)
Contact::Contact(not_null<Context*> context, not_null<Result*> result)
: ItemBase(context, result)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
}
@ -1111,7 +1146,7 @@ TextState Contact::getState(
}
void Contact::prepareThumbnail(int width, int height) const {
const auto thumb = getResultThumb();
const auto thumb = getResultThumb(); // #TODO optimize
if (!thumb) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = getResultContactAvatar(width, height);
@ -1142,7 +1177,11 @@ void Contact::prepareThumbnail(int width, int height) const {
}
}
Article::Article(not_null<Context*> context, Result *result, bool withThumb) : ItemBase(context, result)
Article::Article(
not_null<Context*> context,
not_null<Result*> result,
bool withThumb)
: ItemBase(context, result)
, _url(getResultUrlHandler())
, _link(getResultPreviewHandler())
, _withThumb(withThumb)
@ -1196,7 +1235,7 @@ void Article::paint(Painter &p, const QRect &clip, const PaintContext *context)
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
QRect rthumb(style::rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width));
if (_thumb.isNull()) {
const auto thumb = getResultThumb();
const auto thumb = getResultThumb(); // #TODO optimize
if (!thumb && !_thumbLetter.isEmpty()) {
int32 index = (_thumbLetter.at(0).unicode() % 4);
style::color colors[] = {
@ -1261,7 +1300,7 @@ TextState Article::getState(
}
void Article::prepareThumbnail(int width, int height) const {
const auto thumb = getResultThumb();
const auto thumb = getResultThumb(); // #TODO optimize
if (!thumb) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = getResultContactAvatar(width, height);
@ -1292,7 +1331,8 @@ void Article::prepareThumbnail(int width, int height) const {
}
}
Game::Game(not_null<Context*> context, Result *result) : ItemBase(context, result)
Game::Game(not_null<Context*> context, not_null<Result*> result)
: ItemBase(context, result)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
countFrameSize();
@ -1359,18 +1399,21 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
// Gif thumb
auto thumbDisplayed = false, radial = false;
const auto photo = getResultPhoto();
const auto document = getResultDocument();
if (document) {
ensureDataMediaCreated(document);
} else if (photo) {
ensureDataMediaCreated(photo);
}
auto animatedThumb = document && document->isAnimation();
if (animatedThumb) {
_dataMedia->automaticLoad(fileOrigin(), nullptr);
_documentMedia->automaticLoad(fileOrigin(), nullptr);
bool loaded = _dataMedia->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
bool loaded = _documentMedia->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !_gif && !_gif.isBad()) {
auto that = const_cast<Game*>(this);
that->_gif = Media::Clip::MakeReader(_dataMedia.get(), FullMsgId(), [that](Media::Clip::Notification notification) {
that->_gif = Media::Clip::MakeReader(_documentMedia.get(), FullMsgId(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
}
@ -1383,7 +1426,7 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
});
}
if (!_radial->animating()) {
_radial->start(_dataMedia->progress());
_radial->start(_documentMedia->progress());
}
}
radial = isRadialAnimation();
@ -1445,22 +1488,33 @@ TextState Game::getState(
}
void Game::prepareThumbnail(QSize size) const {
if (const auto photo = getResultPhoto()) {
validateThumbnail(photo->thumbnail(), size, true);
validateThumbnail(photo->thumbnailInline(), size, false);
} else if (const auto document = getResultDocument()) {
Assert(_dataMedia != nullptr);
validateThumbnail(_dataMedia->thumbnail(), size, true);
validateThumbnail(_dataMedia->thumbnailInline(), size, false);
if (const auto document = getResultDocument()) {
Assert(_documentMedia != nullptr);
validateThumbnail(_documentMedia->thumbnail(), size, true);
validateThumbnail(_documentMedia->thumbnailInline(), size, false);
} else if (const auto photo = getResultPhoto()) {
using Data::PhotoSize;
Assert(_photoMedia != nullptr);
validateThumbnail(_photoMedia->image(PhotoSize::Thumbnail), size, true);
validateThumbnail(_photoMedia->image(PhotoSize::Small), size, false);
validateThumbnail(_photoMedia->thumbnailInline(), size, false);
}
}
void Game::ensureDataMediaCreated(not_null<DocumentData*> document) const {
if (_dataMedia) {
if (_documentMedia) {
return;
}
_dataMedia = document->createMediaView();
_dataMedia->thumbnailWanted(fileOrigin());
_documentMedia = document->createMediaView();
_documentMedia->thumbnailWanted(fileOrigin());
}
void Game::ensureDataMediaCreated(not_null<PhotoData*> photo) const {
if (_photoMedia) {
return;
}
_photoMedia = photo->createMediaView();
_photoMedia->wanted(Data::PhotoSize::Thumbnail, fileOrigin());
}
void Game::validateThumbnail(Image *image, QSize size, bool good) const {
@ -1507,7 +1561,7 @@ bool Game::isRadialAnimation() const {
return true;
} else {
ensureDataMediaCreated(getResultDocument());
if (_dataMedia->loaded()) {
if (_documentMedia->loaded()) {
_radial = nullptr;
}
}
@ -1520,22 +1574,28 @@ void Game::radialAnimationCallback(crl::time now) const {
ensureDataMediaCreated(document);
const auto updated = [&] {
return _radial->update(
_dataMedia->progress(),
!document->loading() || _dataMedia->loaded(),
_documentMedia->progress(),
!document->loading() || _documentMedia->loaded(),
now);
}();
if (!anim::Disabled() || updated) {
update();
}
if (!_radial->animating() && _dataMedia->loaded()) {
if (!_radial->animating() && _documentMedia->loaded()) {
_radial = nullptr;
}
}
void Game::unloadHeavyPart() {
_gif.reset();
getResultDocument()->unload();
_dataMedia = nullptr;
if (const auto document = getResultDocument()) {
document->unload();
_documentMedia = nullptr;
}
if (const auto photo = getResultPhoto()) {
photo->unload();
_photoMedia = nullptr;
}
}
void Game::clipCallback(Media::Clip::Notification notification) {

View File

@ -19,6 +19,7 @@ class SinglePlayer;
} // namespace Lottie
namespace Data {
class PhotoMedia;
class DocumentMedia;
} // namespace Data
@ -29,8 +30,9 @@ namespace internal {
class FileBase : public ItemBase {
public:
FileBase(not_null<Context*> context, not_null<Result*> result);
// for saved gif layouts
FileBase(not_null<Context*> context, DocumentData *doc);
// For saved gif layouts.
FileBase(not_null<Context*> context, not_null<DocumentData*> document);
protected:
DocumentData *getShownDocument() const;
@ -54,10 +56,13 @@ private:
};
class Gif : public FileBase {
class Gif final : public FileBase {
public:
Gif(not_null<Context*> context, Result *result);
Gif(not_null<Context*> context, DocumentData *doc, bool hasDeleteButton);
Gif(not_null<Context*> context, not_null<Result*> result);
Gif(
not_null<Context*> context,
not_null<DocumentData*> document,
bool hasDeleteButton);
void setPosition(int32 position) override;
void initDimensions() override;
@ -131,9 +136,9 @@ private:
class Photo : public ItemBase {
public:
Photo(not_null<Context*> context, Result *result);
Photo(not_null<Context*> context, not_null<Result*> result);
// Not used anywhere currently.
//Photo(not_null<Context*> context, PhotoData *photo);
//Photo(not_null<Context*> context, not_null<PhotoData*> photo);
void initDimensions() override;
@ -149,6 +154,8 @@ public:
QPoint point,
StateRequest request) const override;
void unloadHeavyPart() override;
private:
PhotoData *getShownPhoto() const;
@ -163,14 +170,16 @@ private:
QSize frame,
bool good) const;
mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
};
class Sticker : public FileBase {
public:
Sticker(not_null<Context*> context, Result *result);
Sticker(not_null<Context*> context, not_null<Result*> result);
~Sticker();
// Not used anywhere currently.
//Sticker(not_null<Context*> context, DocumentData *document);
//Sticker(not_null<Context*> context, not_null<DocumentData*> document);
void initDimensions() override;
@ -190,6 +199,8 @@ public:
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void unloadHeavyPart() override;
private:
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
void setupLottie() const;
@ -210,7 +221,7 @@ private:
class Video : public FileBase {
public:
Video(not_null<Context*> context, Result *result);
Video(not_null<Context*> context, not_null<Result*> result);
void initDimensions() override;
@ -219,6 +230,8 @@ public:
QPoint point,
StateRequest request) const override;
void unloadHeavyPart() override;
private:
ClickHandlerPtr _link;
@ -262,6 +275,7 @@ private:
class File : public FileBase {
public:
File(not_null<Context*> context, not_null<Result*> result);
~File();
void initDimensions() override;
@ -273,7 +287,7 @@ public:
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
~File();
void unloadHeavyPart() override;
private:
void thumbAnimationCallback();
@ -334,7 +348,7 @@ private:
class Contact : public ItemBase {
public:
Contact(not_null<Context*> context, Result *result);
Contact(not_null<Context*> context, not_null<Result*> result);
void initDimensions() override;
@ -353,7 +367,7 @@ private:
class Article : public ItemBase {
public:
Article(not_null<Context*> context, Result *result, bool withThumb);
Article(not_null<Context*> context, not_null<Result*> result, bool withThumb);
void initDimensions() override;
int resizeGetHeight(int width) override;
@ -378,7 +392,7 @@ private:
class Game : public ItemBase {
public:
Game(not_null<Context*> context, Result *result);
Game(not_null<Context*> context, not_null<Result*> result);
void setPosition(int32 position) override;
void initDimensions() override;
@ -391,6 +405,7 @@ public:
void unloadHeavyPart() override;
private:
void ensureDataMediaCreated(not_null<PhotoData*> photo) const;
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
void countFrameSize();
@ -403,7 +418,8 @@ private:
void clipCallback(Media::Clip::Notification notification);
Media::Clip::ReaderPointer _gif;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
mutable std::shared_ptr<Data::DocumentMedia> _documentMedia;
mutable QPixmap _thumb;
mutable bool _thumbGood = false;
mutable std::unique_ptr<Ui::RadialAnimation> _radial;

View File

@ -41,7 +41,7 @@ Result *ItemBase::getResult() const {
}
DocumentData *ItemBase::getDocument() const {
return _doc;
return _document;
}
PhotoData *ItemBase::getPhoto() const {
@ -49,8 +49,8 @@ PhotoData *ItemBase::getPhoto() const {
}
DocumentData *ItemBase::getPreviewDocument() const {
if (_doc) {
return _doc;
if (_document) {
return _document;
} else if (_result) {
return _result->_document;
}
@ -60,8 +60,7 @@ DocumentData *ItemBase::getPreviewDocument() const {
PhotoData *ItemBase::getPreviewPhoto() const {
if (_photo) {
return _photo;
}
if (_result) {
} else if (_result) {
return _result->_photo;
}
return nullptr;
@ -71,16 +70,16 @@ void ItemBase::preload() const {
const auto origin = fileOrigin();
if (_result) {
if (_result->_photo) {
_result->_photo->loadThumbnail(origin);
_result->_photo->load(Data::PhotoSize::Thumbnail, origin);
} else if (_result->_document) {
_result->_document->loadThumbnail(origin);
} else if (!_result->_thumb->isNull()) {
_result->_thumb->load(origin);
}
} else if (_doc) {
_doc->loadThumbnail(origin);
} else if (_document) {
_document->loadThumbnail(origin);
} else if (_photo) {
_photo->loadThumbnail(origin);
_photo->load(Data::PhotoSize::Thumbnail, origin);
}
}
@ -96,7 +95,10 @@ void ItemBase::layoutChanged() {
}
}
std::unique_ptr<ItemBase> ItemBase::createLayout(not_null<Context*> context, Result *result, bool forceThumb) {
std::unique_ptr<ItemBase> ItemBase::createLayout(
not_null<Context*> context,
not_null<Result*> result,
bool forceThumb) {
using Type = Result::Type;
switch (result->_type) {
@ -126,7 +128,9 @@ std::unique_ptr<ItemBase> ItemBase::createLayout(not_null<Context*> context, Res
return nullptr;
}
std::unique_ptr<ItemBase> ItemBase::createLayoutGif(not_null<Context*> context, DocumentData *document) {
std::unique_ptr<ItemBase> ItemBase::createLayoutGif(
not_null<Context*> context,
not_null<DocumentData*> document) {
return std::make_unique<internal::Gif>(context, document, true);
}
@ -140,9 +144,7 @@ PhotoData *ItemBase::getResultPhoto() const {
Image *ItemBase::getResultThumb() const {
if (_result) {
if (_result->_photo) {
return _result->_photo->thumbnail();
} else if (!_result->_thumb->isNull()) {
if (!_result->_thumb->isNull()) {
return _result->_thumb.get();
} else if (!_result->_locationThumb->isNull()) {
return _result->_locationThumb.get();

View File

@ -50,8 +50,8 @@ public:
: _result(result)
, _context(context) {
}
ItemBase(not_null<Context*> context, DocumentData *doc)
: _doc(doc)
ItemBase(not_null<Context*> context, not_null<DocumentData*> document)
: _document(document)
, _context(context) {
}
// Not used anywhere currently.
@ -94,8 +94,13 @@ public:
update();
}
static std::unique_ptr<ItemBase> createLayout(not_null<Context*> context, Result *result, bool forceThumb);
static std::unique_ptr<ItemBase> createLayoutGif(not_null<Context*> context, DocumentData *document);
static std::unique_ptr<ItemBase> createLayout(
not_null<Context*> context,
not_null<Result*> result,
bool forceThumb);
static std::unique_ptr<ItemBase> createLayoutGif(
not_null<Context*> context,
not_null<DocumentData*> document);
protected:
DocumentData *getResultDocument() const;
@ -114,7 +119,7 @@ protected:
Data::FileOrigin fileOrigin() const;
Result *_result = nullptr;
DocumentData *_doc = nullptr;
DocumentData *_document = nullptr;
PhotoData *_photo = nullptr;
ClickHandlerPtr _send = ClickHandlerPtr{ new SendClickHandler() };

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "data/data_document_media.h"
#include "inline_bots/inline_bot_layout_item.h"
#include "inline_bots/inline_bot_send_data.h"
@ -105,7 +106,9 @@ std::unique_ptr<Result> Result::create(
if (result->_type == Type::Photo) {
result->_photo = Auth().data().photoFromWeb(
*content,
result->_thumb,
(imageThumb
? Images::FromWebDocument(*r.vthumb())
: ImageLocation()),
true);
} else {
result->_document = Auth().data().documentFromWeb(
@ -276,10 +279,13 @@ std::unique_ptr<Result> Result::create(
bool Result::onChoose(Layout::ItemBase *layout) {
if (_photo && _type == Type::Photo) {
if (_photo->thumbnail()->loaded()) {
const auto media = _photo->activeMediaView();
if (!media || media->image(Data::PhotoSize::Thumbnail)) {
return true;
} else if (!_photo->thumbnail()->loading()) {
_photo->thumbnail()->loadEvenCancelled(Data::FileOrigin());
} else if (!_photo->loading(Data::PhotoSize::Thumbnail)) {
_photo->load(
Data::PhotoSize::Thumbnail,
Data::FileOrigin());
}
return false;
}

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_shared_media.h"
#include "data/data_user_photos.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_media_types.h"
@ -129,9 +130,10 @@ public:
Dying,
};
Thumb(Key key, Fn<void()> handler);
Thumb(
Key key,
Image *image,
not_null<PhotoData*> photo,
Data::FileOrigin origin,
Fn<void()> handler);
Thumb(
@ -165,6 +167,7 @@ private:
ClickHandlerPtr _link;
const Key _key;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
std::shared_ptr<Data::PhotoMedia> _photoMedia;
Image *_image = nullptr;
Data::FileOrigin _origin;
State _state = State::Alive;
@ -178,18 +181,28 @@ private:
};
GroupThumbs::Thumb::Thumb(Key key, Fn<void()> handler)
: _key(key) {
_link = std::make_shared<LambdaClickHandler>(std::move(handler));
_fullWidth = std::min(
wantedPixSize().width(),
st::mediaviewGroupWidthMax);
validateImage();
}
GroupThumbs::Thumb::Thumb(
Key key,
Image *image,
not_null<PhotoData*> photo,
Data::FileOrigin origin,
Fn<void()> handler)
: _key(key)
, _image(image)
, _photoMedia(photo->createMediaView())
, _origin(origin) {
_link = std::make_shared<LambdaClickHandler>(std::move(handler));
_fullWidth = std::min(
wantedPixSize().width(),
st::mediaviewGroupWidthMax);
_photoMedia->wanted(Data::PhotoSize::Thumbnail, origin);
validateImage();
}
@ -218,8 +231,12 @@ QSize GroupThumbs::Thumb::wantedPixSize() const {
}
void GroupThumbs::Thumb::validateImage() {
if (!_image && _documentMedia) {
_image = _documentMedia->thumbnail();
if (!_image) {
if (_photoMedia) {
_image = _photoMedia->image(Data::PhotoSize::Thumbnail);
} else if (_documentMedia) {
_image = _documentMedia->thumbnail();
}
}
if (!_full.isNull() || !_image) {
return;
@ -543,12 +560,12 @@ auto GroupThumbs::createThumb(Key key)
-> std::unique_ptr<Thumb> {
if (const auto photoId = base::get_if<PhotoId>(&key)) {
const auto photo = Auth().data().photo(*photoId);
return createThumb(key, photo->thumbnail());
return createThumb(key, photo);
} else if (const auto msgId = base::get_if<FullMsgId>(&key)) {
if (const auto item = Auth().data().message(*msgId)) {
if (const auto media = item->media()) {
if (const auto photo = media->photo()) {
return createThumb(key, photo->thumbnail());
return createThumb(key, photo);
} else if (const auto document = media->document()) {
return createThumb(key, document);
}
@ -583,18 +600,29 @@ auto GroupThumbs::createThumb(
}
const auto &item = collage.items[index];
if (const auto photo = base::get_if<PhotoData*>(&item)) {
return createThumb(key, (*photo)->thumbnail());
return createThumb(key, (*photo));
} else if (const auto document = base::get_if<DocumentData*>(&item)) {
return createThumb(key, (*document));
}
return createThumb(key, nullptr);
}
auto GroupThumbs::createThumb(Key key, Image *image)
auto GroupThumbs::createThumb(Key key, std::nullptr_t)
-> std::unique_ptr<Thumb> {
const auto weak = base::make_weak(this);
const auto origin = ComputeFileOrigin(key, _context);
return std::make_unique<Thumb>(key, image, origin, [=] {
return std::make_unique<Thumb>(key, [=] {
if (const auto strong = weak.get()) {
strong->_activateStream.fire_copy(key);
}
});
}
auto GroupThumbs::createThumb(Key key, not_null<PhotoData*> photo)
-> std::unique_ptr<Thumb> {
const auto weak = base::make_weak(this);
const auto origin = ComputeFileOrigin(key, _context);
return std::make_unique<Thumb>(key, photo, origin, [=] {
if (const auto strong = weak.get()) {
strong->_activateStream.fire_copy(key);
}

View File

@ -100,10 +100,11 @@ private:
Key key,
const WebPageCollage &collage,
int index);
std::unique_ptr<Thumb> createThumb(Key key, Image *image);
std::unique_ptr<Thumb> createThumb(Key key, not_null<PhotoData*> photo);
std::unique_ptr<Thumb> createThumb(
Key key,
not_null<DocumentData*> document);
std::unique_ptr<Thumb> createThumb(Key key, std::nullptr_t);
void update();
void countUpdatedRect();

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_cloud_themes.h" // Data::CloudTheme.
#include "media/view/media_view_playback_controls.h"
namespace Data {
class PhotoMedia;
class DocumentMedia;
} // namespace Data
namespace Ui {
class PopupMenu;
class LinkButton;
@ -189,6 +194,9 @@ private:
void playbackPauseMusic();
void switchToPip();
void assignMediaPointer(DocumentData *document);
void assignMediaPointer(not_null<PhotoData*> photo);
void updateOver(QPoint mpos);
void moveToScreen(bool force = false);
bool moveToNext(int delta);
@ -347,9 +355,11 @@ private:
QBrush _transparentBrush;
PhotoData *_photo = nullptr;
DocumentData *_doc = nullptr;
std::shared_ptr<Data::DocumentMedia> _docMedia;
base::flat_set<std::shared_ptr<Data::DocumentMedia>> _preloadMedias;
DocumentData *_document = nullptr;
std::shared_ptr<Data::PhotoMedia> _photoMedia;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
base::flat_set<std::shared_ptr<Data::PhotoMedia>> _preloadPhotos;
base::flat_set<std::shared_ptr<Data::DocumentMedia>> _preloadDocuments;
int _rotation = 0;
std::unique_ptr<SharedMedia> _sharedMedia;
std::optional<SharedMediaWithLastSlice> _sharedMediaData;

View File

@ -14,6 +14,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_photo_media.h"
#include "data/data_document_media.h"
#include "styles/style_overview.h"
#include "styles/style_history.h"
@ -297,8 +298,8 @@ Photo::Photo(
: ItemBase(delegate, parent)
, _data(photo)
, _link(std::make_shared<PhotoOpenClickHandler>(photo, parent->fullId())) {
if (!_data->thumbnailInline()) {
_data->loadThumbnailSmall(parent->fullId());
if (_data->inlineThumbnailBytes().isEmpty()) {
_data->load(Data::PhotoSize::Small, parent->fullId());
}
}
@ -317,27 +318,25 @@ int32 Photo::resizeGetHeight(int32 width) {
}
void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
bool good = _data->loaded(), selected = (selection == FullSelection);
if (!good) {
_data->thumbnail()->automaticLoad(parent()->fullId(), parent());
good = _data->thumbnail()->loaded();
}
if ((good && !_goodLoaded) || _pix.width() != _width * cIntRetinaFactor()) {
_goodLoaded = good;
_pix = QPixmap();
if (_goodLoaded) {
setPixFrom(_data->loaded()
? _data->large()
: _data->thumbnail());
} else if (_data->thumbnailSmall()->loaded()) {
setPixFrom(_data->thumbnailSmall());
} else if (const auto blurred = _data->thumbnailInline()) {
blurred->load({});
if (blurred->loaded()) {
const auto selected = (selection == FullSelection);
const auto widthChanged = _pix.width() != _width * cIntRetinaFactor();
if (!_goodLoaded || widthChanged) {
ensureDataMediaCreated();
const auto good = _dataMedia->loaded()
|| (_dataMedia->image(Data::PhotoSize::Thumbnail) != nullptr);
if ((good && !_goodLoaded) || widthChanged) {
_goodLoaded = good;
_pix = QPixmap();
if (_goodLoaded) {
setPixFrom(_dataMedia->image(Data::PhotoSize::Large)
? _dataMedia->image(Data::PhotoSize::Large)
: _dataMedia->image(Data::PhotoSize::Thumbnail));
} else if (const auto small = _dataMedia->image(
Data::PhotoSize::Small)) {
setPixFrom(small);
} else if (const auto blurred = _dataMedia->thumbnailInline()) {
setPixFrom(blurred);
}
} else {
_data->loadThumbnailSmall(parent()->fullId());
}
}
@ -377,13 +376,30 @@ void Photo::setPixFrom(not_null<Image*> image) {
// In case we have inline thumbnail we can unload all images and we still
// won't get a blank image in the media viewer when the photo is opened.
if (_data->thumbnailInline() != nullptr) {
_data->unload();
if (!_data->inlineThumbnailBytes().isEmpty()) {
_dataMedia = nullptr;
delegate()->unregisterHeavyItem(this);
}
_pix = App::pixmapFromImageInPlace(std::move(img));
}
void Photo::ensureDataMediaCreated() const {
if (_dataMedia) {
return;
}
_dataMedia = _data->createMediaView();
if (_data->inlineThumbnailBytes().isEmpty()) {
_dataMedia->wanted(Data::PhotoSize::Small, parent()->fullId());
}
_dataMedia->wanted(Data::PhotoSize::Thumbnail, parent()->fullId());
delegate()->registerHeavyItem(this);
}
void Photo::clearHeavyPart() {
_dataMedia = nullptr;
}
TextState Photo::getState(
QPoint point,
StateRequest request) const {
@ -1460,12 +1476,7 @@ Link::Link(
}
int32 tw = 0, th = 0;
if (_page && _page->photo) {
if (!_page->photo->loaded()
&& !_page->photo->thumbnail()->loaded()
&& !_page->photo->thumbnailSmall()->loaded()) {
_page->photo->loadThumbnailSmall(parent->fullId());
}
_page->photo->load(Data::PhotoSize::Small, parent->fullId());
tw = style::ConvertScale(_page->photo->width());
th = style::ConvertScale(_page->photo->height());
} else if (_page && _page->document && _page->document->hasThumbnail()) {
@ -1609,17 +1620,21 @@ void Link::validateThumbnail() {
return;
}
if (_page && _page->photo) {
if (_page->photo->thumbnail()->loaded()) {
_thumbnail = _page->photo->thumbnail()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else if (_page->photo->loaded()) {
_thumbnail = _page->photo->large()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else if (_page->photo->thumbnailSmall()->loaded()) {
_thumbnail = _page->photo->thumbnailSmall()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else if (const auto blurred = _page->photo->thumbnailInline()) {
using Data::PhotoSize;
ensurePhotoMediaCreated();
if (const auto thumbnail = _photoMedia->image(PhotoSize::Thumbnail)) {
_thumbnail = thumbnail->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else if (const auto large = _photoMedia->image(PhotoSize::Large)) {
_thumbnail = large->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else if (const auto small = _photoMedia->image(PhotoSize::Small)) {
_thumbnail = small->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else if (const auto blurred = _photoMedia->thumbnailInline()) {
_thumbnail = blurred->pixBlurredSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else {
return;
}
_photoMedia = nullptr;
delegate()->unregisterHeavyItem(this);
} else if (_page && _page->document && _page->document->hasThumbnail()) {
ensureDocumentMediaCreated();
if (const auto thumbnail = _documentMedia->thumbnail()) {
@ -1664,6 +1679,15 @@ void Link::validateThumbnail() {
}
}
void Link::ensurePhotoMediaCreated() {
if (_photoMedia) {
return;
}
_photoMedia = _page->photo->createMediaView();
_photoMedia->wanted(Data::PhotoSize::Small, parent()->fullId());
delegate()->registerHeavyItem(this);
}
void Link::ensureDocumentMediaCreated() {
if (_documentMedia) {
return;
@ -1674,6 +1698,7 @@ void Link::ensureDocumentMediaCreated() {
}
void Link::clearHeavyPart() {
_photoMedia = nullptr;
_documentMedia = nullptr;
}

View File

@ -19,6 +19,7 @@ struct RoundCheckbox;
namespace Data {
class Media;
class PhotoMedia;
class DocumentMedia;
} // namespace Data
@ -184,10 +185,14 @@ public:
QPoint point,
StateRequest request) const override;
void clearHeavyPart() override;
private:
void ensureDataMediaCreated() const;
void setPixFrom(not_null<Image*> image);
not_null<PhotoData*> _data;
const not_null<PhotoData*> _data;
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
ClickHandlerPtr _link;
QPixmap _pix;
@ -222,7 +227,7 @@ private:
void ensureDataMediaCreated() const;
void updateStatusText();
not_null<DocumentData*> _data;
const not_null<DocumentData*> _data;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
StatusText _status;
@ -346,6 +351,7 @@ protected:
const style::RoundCheckbox &checkboxStyle() const override;
private:
void ensurePhotoMediaCreated();
void ensureDocumentMediaCreated();
void validateThumbnail();
@ -354,6 +360,7 @@ private:
QString _title, _letter;
int _titlew = 0;
WebPageData *_page = nullptr;
std::shared_ptr<Data::PhotoMedia> _photoMedia;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
int _pixw = 0;
int _pixh = 0;

View File

@ -66,29 +66,30 @@ public:
[[nodiscard]] Main::Session &session() const;
bool finished() const {
[[nodiscard]] bool finished() const {
return _finished;
}
void finishWithBytes(const QByteArray &data);
bool cancelled() const {
[[nodiscard]] bool cancelled() const {
return _cancelled;
}
const QByteArray &bytes() const {
[[nodiscard]] const QByteArray &bytes() const {
return _data;
}
virtual uint64 objId() const {
[[nodiscard]] virtual uint64 objId() const {
return 0;
}
QByteArray imageFormat(const QSize &shrinkBox = QSize()) const;
QImage imageData(const QSize &shrinkBox = QSize()) const;
QString fileName() const {
[[nodiscard]] QByteArray imageFormat(
const QSize &shrinkBox = QSize()) const;
[[nodiscard]] QImage imageData(const QSize &shrinkBox = QSize()) const;
[[nodiscard]] QString fileName() const {
return _filename;
}
// Used in MainWidget::documentLoadFailed.
[[nodiscard]] virtual Data::FileOrigin fileOrigin() const;
float64 currentProgress() const;
virtual int currentOffset() const;
int fullSize() const;
[[nodiscard]] float64 currentProgress() const;
[[nodiscard]] virtual int currentOffset() const;
[[nodiscard]] int fullSize() const;
bool setFileName(const QString &filename); // set filename for loaders to cache
void permitLoadFromCloud();
@ -96,10 +97,10 @@ public:
void start();
void cancel();
bool loadingLocal() const {
[[nodiscard]] bool loadingLocal() const {
return (_localStatus == LocalStatus::Loading);
}
bool autoLoading() const {
[[nodiscard]] bool autoLoading() const {
return _autoLoading;
}
@ -112,7 +113,7 @@ public:
return _updates.events();
}
rpl::lifetime &lifetime() {
[[nodiscard]] rpl::lifetime &lifetime() {
return _lifetime;
}

View File

@ -946,14 +946,6 @@ QImage Image::original() const {
return _data;
}
void Image::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
if (!loaded()) {
_source->automaticLoad(origin, item);
}
}
void Image::load(Data::FileOrigin origin) {
if (!loaded()) {
_source->load(origin);

View File

@ -67,11 +67,6 @@ public:
virtual QImage takeLoaded() = 0;
virtual void unload() = 0;
virtual void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) = 0;
virtual void automaticLoadSettingsChanged() = 0;
virtual bool loading() = 0;
virtual bool displayLoading() = 0;
virtual void cancel() = 0;
@ -178,10 +173,6 @@ public:
int32 w,
int32 h = 0) const;
void automaticLoad(Data::FileOrigin origin, const HistoryItem *item);
void automaticLoadSettingsChanged() {
_source->automaticLoadSettingsChanged();
}
bool loading() const {
return _source->loading();
}

View File

@ -14,6 +14,65 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Images {
ImageWithLocation FromPhotoSize(
not_null<Main::Session*> session,
const MTPDphoto &photo,
const MTPPhotoSize &size) {
return size.match([&](const MTPDphotoSize &data) {
return ImageWithLocation{
.location = ImageLocation(
DownloadLocation{ StorageFileLocation(
photo.vdc_id().v,
session->userId(),
MTP_inputPhotoFileLocation(
photo.vid(),
photo.vaccess_hash(),
photo.vfile_reference(),
data.vtype())) },
data.vw().v,
data.vh().v),
.bytesCount = data.vsize().v
};
}, [&](const MTPDphotoCachedSize &data) {
const auto bytes = qba(data.vbytes());
return ImageWithLocation{
.location = ImageLocation(
DownloadLocation{ StorageFileLocation(
photo.vdc_id().v,
session->userId(),
MTP_inputPhotoFileLocation(
photo.vid(),
photo.vaccess_hash(),
photo.vfile_reference(),
data.vtype())) },
data.vw().v,
data.vh().v),
.bytesCount = bytes.size(),
.bytes = bytes
};
}, [&](const MTPDphotoStrippedSize &data) {
return ImageWithLocation();
//const auto bytes = ExpandInlineBytes(qba(data.vbytes()));
//return ImageWithLocation{
// .location = ImageLocation(
// DownloadLocation{ StorageFileLocation(
// photo.vdc_id().v,
// session->userId(),
// MTP_inputPhotoFileLocation(
// photo.vid(),
// photo.vaccess_hash(),
// photo.vfile_reference(),
// data.vtype())) },
// width, // ???
// height), // ???
// .bytesCount = bytes.size(),
// .bytes = bytes
//};
}, [&](const MTPDphotoSizeEmpty &) {
return ImageWithLocation();
});
}
ImageWithLocation FromPhotoSize(
not_null<Main::Session*> session,
const MTPDdocument &document,

View File

@ -15,6 +15,10 @@ class Session;
namespace Images {
[[nodiscard]] ImageWithLocation FromPhotoSize(
not_null<Main::Session*> session,
const MTPDphoto &photo,
const MTPPhotoSize &size);
[[nodiscard]] ImageWithLocation FromPhotoSize(
not_null<Main::Session*> session,
const MTPDdocument &document,

View File

@ -57,14 +57,6 @@ void ImageSource::unload() {
_data = QImage();
}
void ImageSource::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
}
void ImageSource::automaticLoadSettingsChanged() {
}
bool ImageSource::loading() {
return false;
}
@ -186,14 +178,6 @@ void LocalFileSource::unload() {
_data = QImage();
}
void LocalFileSource::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
}
void LocalFileSource::automaticLoadSettingsChanged() {
}
bool LocalFileSource::loading() {
return false;
}
@ -344,36 +328,6 @@ bool RemoteSource::loading() {
return (_loader != nullptr);
}
void RemoteSource::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
if (!item || cancelled()) {
return;
}
const auto loadFromCloud = Data::AutoDownload::Should(
Auth().settings().autoDownload(),
item->history()->peer,
this);
if (_loader) {
if (loadFromCloud) {
_loader->permitLoadFromCloud();
}
} else {
_loader = createLoader(
origin,
loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly,
true);
}
if (_loader) {
_loader->start();
}
}
void RemoteSource::automaticLoadSettingsChanged() {
_cancelled = false;
}
void RemoteSource::load(Data::FileOrigin origin) {
if (!_loader) {
_loader = createLoader(origin, LoadFromCloudOrLocal, false);
@ -645,33 +599,33 @@ void DelayedStorageSource::performDelayedLoad(Data::FileOrigin origin) {
loadLocal();
}
}
void DelayedStorageSource::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
if (_location.valid()) {
StorageSource::automaticLoad(origin, item);
return;
} else if (_loadCancelled || !item) {
return;
}
const auto loadFromCloud = Data::AutoDownload::Should(
Auth().settings().autoDownload(),
item->history()->peer,
this);
if (_loadRequested) {
if (loadFromCloud) _loadFromCloud = loadFromCloud;
} else {
_loadFromCloud = loadFromCloud;
_loadRequested = true;
}
}
void DelayedStorageSource::automaticLoadSettingsChanged() {
if (_loadCancelled) _loadCancelled = false;
StorageSource::automaticLoadSettingsChanged();
}
//
//void DelayedStorageSource::automaticLoad(
// Data::FileOrigin origin,
// const HistoryItem *item) {
// if (_location.valid()) {
// StorageSource::automaticLoad(origin, item);
// return;
// } else if (_loadCancelled || !item) {
// return;
// }
// const auto loadFromCloud = Data::AutoDownload::Should(
// Auth().settings().autoDownload(),
// item->history()->peer,
// this);
//
// if (_loadRequested) {
// if (loadFromCloud) _loadFromCloud = loadFromCloud;
// } else {
// _loadFromCloud = loadFromCloud;
// _loadRequested = true;
// }
//}
//
//void DelayedStorageSource::automaticLoadSettingsChanged() {
// if (_loadCancelled) _loadCancelled = false;
// StorageSource::automaticLoadSettingsChanged();
//}
void DelayedStorageSource::load(Data::FileOrigin origin) {
if (_location.valid()) {

View File

@ -20,11 +20,6 @@ public:
QImage takeLoaded() override;
void unload() override;
void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) override;
void automaticLoadSettingsChanged() override;
bool loading() override;
bool displayLoading() override;
void cancel() override;
@ -69,11 +64,6 @@ public:
QImage takeLoaded() override;
void unload() override;
void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) override;
void automaticLoadSettingsChanged() override;
bool loading() override;
bool displayLoading() override;
void cancel() override;
@ -115,11 +105,6 @@ public:
QImage takeLoaded() override;
void unload() override;
void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) override;
void automaticLoadSettingsChanged() override;
bool loading() override;
bool displayLoading() override;
void cancel() override;
@ -256,11 +241,6 @@ public:
bool isDelayedStorageImage() const override;
void performDelayedLoad(Data::FileOrigin origin) override;
void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) override; // auto load photo
void automaticLoadSettingsChanged() override;
bool loading() override {
return _location.valid()
? StorageSource::loading()

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_media_preview.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "ui/image/image.h"
@ -114,6 +115,7 @@ void MediaPreviewWidget::showPreview(
startShow();
_origin = origin;
_photo = nullptr;
_photoMedia = nullptr;
_document = document;
_documentMedia = _document->createMediaView();
_documentMedia->thumbnailWanted(_origin);
@ -128,9 +130,10 @@ void MediaPreviewWidget::showPreview(
not_null<PhotoData*> photo) {
startShow();
_origin = origin;
_photo = photo;
_document = nullptr;
_documentMedia = nullptr;
_photo = photo;
_photoMedia = _photo->createMediaView();
fillEmojiString();
resetGifAndCache();
}
@ -159,6 +162,7 @@ void MediaPreviewWidget::hidePreview() {
_hiding = true;
_a_shown.start([=] { update(); }, 1., 0., st::stickerPreviewDuration);
_photo = nullptr;
_photoMedia = nullptr;
_document = nullptr;
_documentMedia = nullptr;
resetGifAndCache();
@ -296,30 +300,31 @@ QPixmap MediaPreviewWidget::currentImage() const {
}
} else if (_photo) {
if (_cacheStatus != CacheLoaded) {
if (_photo->loaded()) {
if (_photoMedia->loaded()) {
QSize s = currentDimensions();
_cache = _photo->large()->pix(_origin, s.width(), s.height());
_cache = _photoMedia->image(Data::PhotoSize::Large)->pix(_origin, s.width(), s.height());
_cacheStatus = CacheLoaded;
} else {
_photo->load(_origin);
if (_cacheStatus != CacheThumbLoaded) {
QSize s = currentDimensions();
if (_photo->thumbnail()->loaded()) {
_cache = _photo->thumbnail()->pixBlurred(_origin, s.width(), s.height());
if (const auto thumbnail = _photoMedia->image(
Data::PhotoSize::Thumbnail)) {
_cache = thumbnail->pixBlurred(_origin, s.width(), s.height());
_cacheStatus = CacheThumbLoaded;
} else if (_photo->thumbnailSmall()->loaded()) {
_cache = _photo->thumbnailSmall()->pixBlurred(_origin, s.width(), s.height());
} else if (const auto small = _photoMedia->image(
Data::PhotoSize::Small)) {
_cache = small->pixBlurred(_origin, s.width(), s.height());
_cacheStatus = CacheThumbLoaded;
} else if (const auto blurred = _photo->thumbnailInline()) {
} else if (const auto blurred = _photoMedia->thumbnailInline()) {
_cache = blurred->pixBlurred(_origin, s.width(), s.height());
_cacheStatus = CacheThumbLoaded;
} else {
_photo->thumbnailSmall()->load(_origin);
_photoMedia->wanted(Data::PhotoSize::Small, _origin);
}
}
}
}
}
return _cache;
}

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h"
namespace Data {
class PhotoMedia;
class DocumentMedia;
} // namespace Data
@ -60,9 +61,10 @@ private:
Ui::Animations::Simple _a_shown;
bool _hiding = false;
Data::FileOrigin _origin;
DocumentData *_document = nullptr;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
PhotoData *_photo = nullptr;
DocumentData *_document = nullptr;
std::shared_ptr<Data::PhotoMedia> _photoMedia;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
Media::Clip::ReaderPointer _gif, _gifThumbnail;
crl::time _gifLastPosition = 0;
std::unique_ptr<Lottie::SinglePlayer> _lottie;