mirror of https://github.com/procxx/kepka.git
Move photo data to Data::PhotoMedia.
This commit is contained in:
parent
24fed8105c
commit
e27d2bc2d5
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue