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_peer_values.h
|
||||||
data/data_photo.cpp
|
data/data_photo.cpp
|
||||||
data/data_photo.h
|
data/data_photo.h
|
||||||
|
data/data_photo_media.cpp
|
||||||
|
data/data_photo_media.h
|
||||||
data/data_poll.cpp
|
data/data_poll.cpp
|
||||||
data/data_poll.h
|
data/data_poll.h
|
||||||
data/data_pts_waiter.cpp
|
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_user.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
|
@ -894,12 +895,12 @@ ConfirmInviteBox::ConfirmInviteBox(
|
||||||
|
|
||||||
const auto photo = _session->data().processPhoto(data.vphoto());
|
const auto photo = _session->data().processPhoto(data.vphoto());
|
||||||
if (!photo->isNull()) {
|
if (!photo->isNull()) {
|
||||||
_photo = photo->thumbnail();
|
_photo = photo->createMediaView();
|
||||||
if (!_photo->loaded()) {
|
_photo->wanted(Data::PhotoSize::Small, Data::FileOrigin());
|
||||||
|
if (!_photo->image(Data::PhotoSize::Small)) {
|
||||||
subscribe(_session->downloaderTaskFinished(), [=] {
|
subscribe(_session->downloaderTaskFinished(), [=] {
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
_photo->load(Data::FileOrigin());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_photoEmpty = std::make_unique<Ui::EmptyUserpic>(
|
_photoEmpty = std::make_unique<Ui::EmptyUserpic>(
|
||||||
|
@ -972,14 +973,16 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
if (_photo) {
|
if (_photo) {
|
||||||
p.drawPixmap(
|
if (const auto image = _photo->image(Data::PhotoSize::Small)) {
|
||||||
(width() - st::confirmInvitePhotoSize) / 2,
|
p.drawPixmap(
|
||||||
st::confirmInvitePhotoTop,
|
(width() - st::confirmInvitePhotoSize) / 2,
|
||||||
_photo->pixCircled(
|
st::confirmInvitePhotoTop,
|
||||||
Data::FileOrigin(),
|
image->pixCircled(
|
||||||
st::confirmInvitePhotoSize,
|
Data::FileOrigin(),
|
||||||
st::confirmInvitePhotoSize));
|
st::confirmInvitePhotoSize,
|
||||||
} else {
|
st::confirmInvitePhotoSize));
|
||||||
|
}
|
||||||
|
} else if (_photoEmpty) {
|
||||||
_photoEmpty->paint(
|
_photoEmpty->paint(
|
||||||
p,
|
p,
|
||||||
(width() - st::confirmInvitePhotoSize) / 2,
|
(width() - st::confirmInvitePhotoSize) / 2,
|
||||||
|
|
|
@ -10,6 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/abstract_box.h"
|
#include "boxes/abstract_box.h"
|
||||||
#include "mtproto/mtproto_rpc_sender.h"
|
#include "mtproto/mtproto_rpc_sender.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class PhotoMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
@ -230,7 +234,7 @@ private:
|
||||||
Fn<void()> _submit;
|
Fn<void()> _submit;
|
||||||
object_ptr<Ui::FlatLabel> _title;
|
object_ptr<Ui::FlatLabel> _title;
|
||||||
object_ptr<Ui::FlatLabel> _status;
|
object_ptr<Ui::FlatLabel> _status;
|
||||||
Image *_photo = nullptr;
|
std::shared_ptr<Data::PhotoMedia> _photo;
|
||||||
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
|
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
|
||||||
std::vector<not_null<UserData*>> _participants;
|
std::vector<not_null<UserData*>> _participants;
|
||||||
bool _isChannel = false;
|
bool _isChannel = false;
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_streaming.h"
|
#include "data/data_streaming.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
@ -55,6 +56,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using namespace ::Media::Streaming;
|
using namespace ::Media::Streaming;
|
||||||
|
using Data::PhotoSize;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -75,9 +77,10 @@ EditCaptionBox::EditCaptionBox(
|
||||||
|
|
||||||
const auto media = item->media();
|
const auto media = item->media();
|
||||||
if (const auto photo = media->photo()) {
|
if (const auto photo = media->photo()) {
|
||||||
_photo = true;
|
_photoMedia = photo->createMediaView();
|
||||||
dimensions = QSize(photo->width(), photo->height());
|
_photoMedia->wanted(PhotoSize::Large, _msgId);
|
||||||
image = photo->large();
|
image = _photoMedia->image(PhotoSize::Large);
|
||||||
|
dimensions = _photoMedia->size(PhotoSize::Large);
|
||||||
} else if (const auto document = media->document()) {
|
} else if (const auto document = media->document()) {
|
||||||
_documentMedia = document->createMediaView();
|
_documentMedia = document->createMediaView();
|
||||||
_documentMedia->thumbnailWanted(_msgId);
|
_documentMedia->thumbnailWanted(_msgId);
|
||||||
|
@ -97,7 +100,10 @@ EditCaptionBox::EditCaptionBox(
|
||||||
}
|
}
|
||||||
const auto editData = PrepareEditText(item);
|
const auto editData = PrepareEditText(item);
|
||||||
|
|
||||||
if (!_animated && (dimensions.isEmpty() || _documentMedia || !image)) {
|
if (!_animated
|
||||||
|
&& (dimensions.isEmpty()
|
||||||
|
|| _documentMedia
|
||||||
|
|| (!_photoMedia && !image))) {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
_thumbw = 0;
|
_thumbw = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,7 +145,7 @@ EditCaptionBox::EditCaptionBox(
|
||||||
_refreshThumbnail();
|
_refreshThumbnail();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!image) {
|
if (!image && !_photoMedia) {
|
||||||
image = Image::BlankMedia();
|
image = Image::BlankMedia();
|
||||||
}
|
}
|
||||||
auto maxW = 0, maxH = 0;
|
auto maxW = 0, maxH = 0;
|
||||||
|
@ -177,7 +183,10 @@ EditCaptionBox::EditCaptionBox(
|
||||||
maxH = dimensions.height();
|
maxH = dimensions.height();
|
||||||
_thumbnailImage = image;
|
_thumbnailImage = image;
|
||||||
_refreshThumbnail = [=] {
|
_refreshThumbnail = [=] {
|
||||||
_thumb = image->pixNoCache(
|
if (!_thumbnailImage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_thumb = _thumbnailImage->pixNoCache(
|
||||||
_msgId,
|
_msgId,
|
||||||
maxW * cIntRetinaFactor(),
|
maxW * cIntRetinaFactor(),
|
||||||
maxH * cIntRetinaFactor(),
|
maxH * cIntRetinaFactor(),
|
||||||
|
@ -253,6 +262,8 @@ EditCaptionBox::EditCaptionBox(
|
||||||
|
|
||||||
_thumbnailImageLoaded = _thumbnailImage
|
_thumbnailImageLoaded = _thumbnailImage
|
||||||
? _thumbnailImage->loaded()
|
? _thumbnailImage->loaded()
|
||||||
|
: _photoMedia
|
||||||
|
? false
|
||||||
: _documentMedia
|
: _documentMedia
|
||||||
? !_documentMedia->owner()->hasThumbnail()
|
? !_documentMedia->owner()->hasThumbnail()
|
||||||
: true;
|
: true;
|
||||||
|
@ -260,6 +271,8 @@ EditCaptionBox::EditCaptionBox(
|
||||||
subscribe(_controller->session().downloaderTaskFinished(), [=] {
|
subscribe(_controller->session().downloaderTaskFinished(), [=] {
|
||||||
if (_thumbnailImageLoaded) {
|
if (_thumbnailImageLoaded) {
|
||||||
return;
|
return;
|
||||||
|
} else if (!_thumbnailImage && _photoMedia) {
|
||||||
|
_thumbnailImage = _photoMedia->image(PhotoSize::Large);
|
||||||
} else if (!_thumbnailImage
|
} else if (!_thumbnailImage
|
||||||
&& _documentMedia
|
&& _documentMedia
|
||||||
&& _documentMedia->owner()->hasThumbnail()) {
|
&& _documentMedia->owner()->hasThumbnail()) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ class SessionController;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Media;
|
class Media;
|
||||||
|
class PhotoMedia;
|
||||||
class DocumentMedia;
|
class DocumentMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
@ -103,6 +104,7 @@ private:
|
||||||
|
|
||||||
not_null<Window::SessionController*> _controller;
|
not_null<Window::SessionController*> _controller;
|
||||||
FullMsgId _msgId;
|
FullMsgId _msgId;
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
||||||
Image *_thumbnailImage = nullptr;
|
Image *_thumbnailImage = nullptr;
|
||||||
bool _thumbnailImageLoaded = false;
|
bool _thumbnailImageLoaded = false;
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "calls/calls_emoji_fingerprint.h"
|
#include "calls/calls_emoji_fingerprint.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
|
@ -299,7 +300,7 @@ QImage Panel::Button::prepareRippleMask() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Panel::Panel(not_null<Call*> call)
|
Panel::Panel(not_null<Call*> call)
|
||||||
:RpWidget(App::wnd())
|
: RpWidget(App::wnd())
|
||||||
, _call(call)
|
, _call(call)
|
||||||
, _user(call->user())
|
, _user(call->user())
|
||||||
, _answerHangupRedial(this, st::callAnswer, &st::callHangup)
|
, _answerHangupRedial(this, st::callAnswer, &st::callHangup)
|
||||||
|
@ -319,6 +320,8 @@ Panel::Panel(not_null<Call*> call)
|
||||||
showAndActivate();
|
showAndActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Panel::~Panel() = default;
|
||||||
|
|
||||||
void Panel::showAndActivate() {
|
void Panel::showAndActivate() {
|
||||||
toggleOpacityAnimation(true);
|
toggleOpacityAnimation(true);
|
||||||
raise();
|
raise();
|
||||||
|
@ -515,26 +518,28 @@ void Panel::processUserPhoto() {
|
||||||
? _user->owner().photo(_user->userpicPhotoId()).get()
|
? _user->owner().photo(_user->userpicPhotoId()).get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (isGoodUserPhoto(photo)) {
|
if (isGoodUserPhoto(photo)) {
|
||||||
photo->large()->load(_user->userpicPhotoOrigin());
|
_photo = photo->createMediaView();
|
||||||
} else if (_user->userpicPhotoUnknown() || (photo && !photo->date)) {
|
_photo->wanted(Data::PhotoSize::Large, _user->userpicPhotoOrigin());
|
||||||
_user->session().api().requestFullPeer(_user);
|
} else {
|
||||||
|
_photo = nullptr;
|
||||||
|
if (_user->userpicPhotoUnknown() || (photo && !photo->date)) {
|
||||||
|
_user->session().api().requestFullPeer(_user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
refreshUserPhoto();
|
refreshUserPhoto();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::refreshUserPhoto() {
|
void Panel::refreshUserPhoto() {
|
||||||
const auto photo = _user->userpicPhotoId()
|
const auto isNewBigPhoto = [&] {
|
||||||
? _user->owner().photo(_user->userpicPhotoId()).get()
|
return _photo
|
||||||
: nullptr;
|
&& _photo->loaded()
|
||||||
const auto isNewPhoto = [&](not_null<PhotoData*> photo) {
|
&& (_photo->owner()->id != _userPhotoId || !_userPhotoFull);
|
||||||
return photo->large()->loaded()
|
}();
|
||||||
&& (photo->id != _userPhotoId || !_userPhotoFull);
|
if (isNewBigPhoto) {
|
||||||
};
|
_userPhotoId = _photo->owner()->id;
|
||||||
if (isGoodUserPhoto(photo) && isNewPhoto(photo)) {
|
|
||||||
_userPhotoId = photo->id;
|
|
||||||
_userPhotoFull = true;
|
_userPhotoFull = true;
|
||||||
createUserpicCache(
|
createUserpicCache(
|
||||||
photo->isNull() ? nullptr : photo->large().get(),
|
_photo->image(Data::PhotoSize::Large),
|
||||||
_user->userpicPhotoOrigin());
|
_user->userpicPhotoOrigin());
|
||||||
} else if (_userPhoto.isNull()) {
|
} else if (_userPhoto.isNull()) {
|
||||||
const auto userpic = _user->currentUserpic();
|
const auto userpic = _user->currentUserpic();
|
||||||
|
|
|
@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class PhotoMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class IconButton;
|
class IconButton;
|
||||||
class FlatLabel;
|
class FlatLabel;
|
||||||
|
@ -56,6 +60,7 @@ class Panel
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Panel(not_null<Call*> call);
|
Panel(not_null<Call*> call);
|
||||||
|
~Panel();
|
||||||
|
|
||||||
void showAndActivate();
|
void showAndActivate();
|
||||||
void replaceCall(not_null<Call*> call);
|
void replaceCall(not_null<Call*> call);
|
||||||
|
@ -111,6 +116,7 @@ private:
|
||||||
|
|
||||||
Call *_call = nullptr;
|
Call *_call = nullptr;
|
||||||
not_null<UserData*> _user;
|
not_null<UserData*> _user;
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _photo;
|
||||||
|
|
||||||
bool _useTransparency = true;
|
bool _useTransparency = true;
|
||||||
style::margins _padding;
|
style::margins _padding;
|
||||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
@ -370,18 +371,23 @@ void GifsListWidget::selectInlineResult(int row, int column) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto ctrl = (QGuiApplication::keyboardModifiers()
|
||||||
|
== Qt::ControlModifier);
|
||||||
auto item = _rows[row].items[column];
|
auto item = _rows[row].items[column];
|
||||||
if (const auto photo = item->getPhoto()) {
|
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);
|
_photoChosen.fire_copy(photo);
|
||||||
} else if (!photo->thumbnail()->loading()) {
|
} else if (!photo->loading(PhotoSize::Thumbnail)) {
|
||||||
photo->thumbnail()->loadEvenCancelled(Data::FileOrigin());
|
photo->load(PhotoSize::Thumbnail, Data::FileOrigin());
|
||||||
}
|
}
|
||||||
} else if (const auto document = item->getDocument()) {
|
} else if (const auto document = item->getDocument()) {
|
||||||
const auto media = document->activeMediaView();
|
const auto media = document->activeMediaView();
|
||||||
const auto preview = Data::VideoPreviewState(media.get());
|
const auto preview = Data::VideoPreviewState(media.get());
|
||||||
if ((media && preview.loaded())
|
if (ctrl || (media && preview.loaded())) {
|
||||||
|| QGuiApplication::keyboardModifiers() == Qt::ControlModifier) {
|
|
||||||
_fileChosen.fire_copy(document);
|
_fileChosen.fire_copy(document);
|
||||||
} else if (!preview.usingThumbnail()) {
|
} else if (!preview.usingThumbnail()) {
|
||||||
if (preview.loading()) {
|
if (preview.loading()) {
|
||||||
|
@ -551,11 +557,13 @@ void GifsListWidget::clearInlineRows(bool resultsDeleted) {
|
||||||
_rows.clear();
|
_rows.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(DocumentData *doc, int32 position) {
|
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(
|
||||||
auto it = _gifLayouts.find(doc);
|
not_null<DocumentData*> document,
|
||||||
|
int32 position) {
|
||||||
|
auto it = _gifLayouts.find(document);
|
||||||
if (it == _gifLayouts.cend()) {
|
if (it == _gifLayouts.cend()) {
|
||||||
if (auto layout = LayoutItem::createLayoutGif(this, doc)) {
|
if (auto layout = LayoutItem::createLayoutGif(this, document)) {
|
||||||
it = _gifLayouts.emplace(doc, std::move(layout)).first;
|
it = _gifLayouts.emplace(document, std::move(layout)).first;
|
||||||
it->second->initDimensions();
|
it->second->initDimensions();
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -567,7 +575,9 @@ GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(DocumentData *
|
||||||
return it->second.get();
|
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);
|
auto it = _inlineLayouts.find(result);
|
||||||
if (it == _inlineLayouts.cend()) {
|
if (it == _inlineLayouts.cend()) {
|
||||||
if (auto layout = LayoutItem::createLayout(this, result, _inlineWithThumb)) {
|
if (auto layout = LayoutItem::createLayout(this, result, _inlineWithThumb)) {
|
||||||
|
|
|
@ -134,11 +134,19 @@ private:
|
||||||
QVector<Row> _rows;
|
QVector<Row> _rows;
|
||||||
void clearInlineRows(bool resultsDeleted);
|
void clearInlineRows(bool resultsDeleted);
|
||||||
|
|
||||||
std::map<DocumentData*, std::unique_ptr<LayoutItem>> _gifLayouts;
|
std::map<
|
||||||
LayoutItem *layoutPrepareSavedGif(DocumentData *doc, int32 position);
|
not_null<DocumentData*>,
|
||||||
|
std::unique_ptr<LayoutItem>> _gifLayouts;
|
||||||
|
LayoutItem *layoutPrepareSavedGif(
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
int32 position);
|
||||||
|
|
||||||
std::map<InlineResult*, std::unique_ptr<LayoutItem>> _inlineLayouts;
|
std::map<
|
||||||
LayoutItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
|
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 inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, Row &row, int32 &sumWidth);
|
||||||
bool inlineRowFinalize(Row &row, int32 &sumWidth, bool force = false);
|
bool inlineRowFinalize(Row &row, int32 &sumWidth, bool force = false);
|
||||||
|
|
|
@ -128,11 +128,6 @@ public:
|
||||||
QImage takeLoaded() override;
|
QImage takeLoaded() override;
|
||||||
void unload() override;
|
void unload() override;
|
||||||
|
|
||||||
void automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) override;
|
|
||||||
void automaticLoadSettingsChanged() override;
|
|
||||||
|
|
||||||
bool loading() override;
|
bool loading() override;
|
||||||
bool displayLoading() override;
|
bool displayLoading() override;
|
||||||
void cancel() override;
|
void cancel() override;
|
||||||
|
@ -222,14 +217,6 @@ void ImageSource::unload() {
|
||||||
_data = QImage();
|
_data = QImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageSource::automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageSource::automaticLoadSettingsChanged() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImageSource::loading() {
|
bool ImageSource::loading() {
|
||||||
return _data.isNull() && _bytes.isEmpty();
|
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_peer.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "ui/image/image_source.h"
|
|
||||||
#include "ui/image/image.h"
|
|
||||||
|
|
||||||
#include <QtCore/QBuffer>
|
#include <QtCore/QBuffer>
|
||||||
|
|
||||||
|
@ -294,11 +292,11 @@ bool Should(
|
||||||
bool Should(
|
bool Should(
|
||||||
const Full &data,
|
const Full &data,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
not_null<Images::Source*> image) {
|
not_null<PhotoData*> photo) {
|
||||||
return data.shouldDownload(
|
return data.shouldDownload(
|
||||||
SourceFromPeer(peer),
|
SourceFromPeer(peer),
|
||||||
Type::Photo,
|
Type::Photo,
|
||||||
image->bytesSize());
|
photo->imageByteSize(PhotoSize::Large));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldAutoPlay(
|
bool ShouldAutoPlay(
|
||||||
|
|
|
@ -9,10 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace Images {
|
|
||||||
class Source;
|
|
||||||
} // namespace Images
|
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
namespace AutoDownload {
|
namespace AutoDownload {
|
||||||
|
|
||||||
|
@ -118,7 +114,7 @@ private:
|
||||||
[[nodiscard]] bool Should(
|
[[nodiscard]] bool Should(
|
||||||
const Full &data,
|
const Full &data,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
not_null<Images::Source*> image);
|
not_null<PhotoData*> photo);
|
||||||
|
|
||||||
[[nodiscard]] bool ShouldAutoPlay(
|
[[nodiscard]] bool ShouldAutoPlay(
|
||||||
const Full &data,
|
const Full &data,
|
||||||
|
|
|
@ -700,10 +700,10 @@ void DocumentData::loadThumbnail(Data::FileOrigin origin) {
|
||||||
_flags |= Flag::ThumbnailFailed;
|
_flags |= Flag::ThumbnailFailed;
|
||||||
}, [=] {
|
}, [=] {
|
||||||
if (_thumbnailLoader && !_thumbnailLoader->cancelled()) {
|
if (_thumbnailLoader && !_thumbnailLoader->cancelled()) {
|
||||||
if (auto image = _thumbnailLoader->imageData(); image.isNull()) {
|
if (auto read = _thumbnailLoader->imageData(); read.isNull()) {
|
||||||
_flags |= Flag::ThumbnailFailed;
|
_flags |= Flag::ThumbnailFailed;
|
||||||
} else if (const auto active = activeMediaView()) {
|
} else if (const auto active = activeMediaView()) {
|
||||||
active->setThumbnail(std::move(image));
|
active->setThumbnail(std::move(read));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_thumbnailLoader = nullptr;
|
_thumbnailLoader = nullptr;
|
||||||
|
|
|
@ -159,8 +159,8 @@ public:
|
||||||
[[nodiscard]] bool thumbnailLoading() const;
|
[[nodiscard]] bool thumbnailLoading() const;
|
||||||
[[nodiscard]] bool thumbnailFailed() const;
|
[[nodiscard]] bool thumbnailFailed() const;
|
||||||
void loadThumbnail(Data::FileOrigin origin);
|
void loadThumbnail(Data::FileOrigin origin);
|
||||||
const ImageLocation &thumbnailLocation() const;
|
[[nodiscard]] const ImageLocation &thumbnailLocation() const;
|
||||||
int thumbnailByteSize() const;
|
[[nodiscard]] int thumbnailByteSize() const;
|
||||||
|
|
||||||
[[nodiscard]] bool hasVideoThumbnail() const;
|
[[nodiscard]] bool hasVideoThumbnail() const;
|
||||||
[[nodiscard]] bool videoThumbnailLoading() const;
|
[[nodiscard]] bool videoThumbnailLoading() const;
|
||||||
|
|
|
@ -381,98 +381,98 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
||||||
}
|
}
|
||||||
parent()->history()->owner().photoConvert(_photo, *content);
|
parent()->history()->owner().photoConvert(_photo, *content);
|
||||||
|
|
||||||
if (content->type() != mtpc_photo) {
|
//if (content->type() != mtpc_photo) { // #TODO optimize
|
||||||
return false;
|
// return false;
|
||||||
}
|
//}
|
||||||
const auto &photo = content->c_photo();
|
//const auto &photo = content->c_photo();
|
||||||
|
|
||||||
struct SizeData {
|
//struct SizeData {
|
||||||
MTPstring type = MTP_string();
|
// MTPstring type = MTP_string();
|
||||||
int width = 0;
|
// int width = 0;
|
||||||
int height = 0;
|
// int height = 0;
|
||||||
QByteArray bytes;
|
// QByteArray bytes;
|
||||||
};
|
//};
|
||||||
const auto saveImageToCache = [&](
|
//const auto saveImageToCache = [&](
|
||||||
not_null<Image*> image,
|
// not_null<Image*> image,
|
||||||
SizeData size) {
|
// SizeData size) {
|
||||||
Expects(!size.type.v.isEmpty());
|
// Expects(!size.type.v.isEmpty());
|
||||||
|
|
||||||
const auto key = StorageImageLocation(
|
// const auto key = StorageImageLocation(
|
||||||
StorageFileLocation(
|
// StorageFileLocation(
|
||||||
photo.vdc_id().v,
|
// photo.vdc_id().v,
|
||||||
_photo->session().userId(),
|
// _photo->session().userId(),
|
||||||
MTP_inputPhotoFileLocation(
|
// MTP_inputPhotoFileLocation(
|
||||||
photo.vid(),
|
// photo.vid(),
|
||||||
photo.vaccess_hash(),
|
// photo.vaccess_hash(),
|
||||||
photo.vfile_reference(),
|
// photo.vfile_reference(),
|
||||||
size.type)),
|
// size.type)),
|
||||||
size.width,
|
// size.width,
|
||||||
size.height);
|
// size.height);
|
||||||
if (!key.valid() || image->isNull() || !image->loaded()) {
|
// if (!key.valid() || image->isNull() || !image->loaded()) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
if (size.bytes.isEmpty()) {
|
// if (size.bytes.isEmpty()) {
|
||||||
size.bytes = image->bytesForCache();
|
// size.bytes = image->bytesForCache();
|
||||||
}
|
// }
|
||||||
const auto length = size.bytes.size();
|
// const auto length = size.bytes.size();
|
||||||
if (!length || length > Storage::kMaxFileInMemory) {
|
// if (!length || length > Storage::kMaxFileInMemory) {
|
||||||
LOG(("App Error: Bad photo data for saving to cache."));
|
// LOG(("App Error: Bad photo data for saving to cache."));
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
parent()->history()->owner().cache().putIfEmpty(
|
// parent()->history()->owner().cache().putIfEmpty(
|
||||||
key.file().cacheKey(),
|
// key.file().cacheKey(),
|
||||||
Storage::Cache::Database::TaggedValue(
|
// Storage::Cache::Database::TaggedValue(
|
||||||
std::move(size.bytes),
|
// std::move(size.bytes),
|
||||||
Data::kImageCacheTag));
|
// Data::kImageCacheTag));
|
||||||
image->replaceSource(
|
// image->replaceSource(
|
||||||
std::make_unique<Images::StorageSource>(key, length));
|
// std::make_unique<Images::StorageSource>(key, length));
|
||||||
};
|
//};
|
||||||
auto &sizes = photo.vsizes().v;
|
//auto &sizes = photo.vsizes().v;
|
||||||
auto max = 0;
|
//auto max = 0;
|
||||||
auto maxSize = SizeData();
|
//auto maxSize = SizeData();
|
||||||
for (const auto &data : sizes) {
|
//for (const auto &data : sizes) {
|
||||||
const auto size = data.match([](const MTPDphotoSize &data) {
|
// const auto size = data.match([](const MTPDphotoSize &data) {
|
||||||
return SizeData{
|
// return SizeData{
|
||||||
data.vtype(),
|
// data.vtype(),
|
||||||
data.vw().v,
|
// data.vw().v,
|
||||||
data.vh().v,
|
// data.vh().v,
|
||||||
QByteArray()
|
// QByteArray()
|
||||||
};
|
// };
|
||||||
}, [](const MTPDphotoCachedSize &data) {
|
// }, [](const MTPDphotoCachedSize &data) {
|
||||||
return SizeData{
|
// return SizeData{
|
||||||
data.vtype(),
|
// data.vtype(),
|
||||||
data.vw().v,
|
// data.vw().v,
|
||||||
data.vh().v,
|
// data.vh().v,
|
||||||
qba(data.vbytes())
|
// qba(data.vbytes())
|
||||||
};
|
// };
|
||||||
}, [](const MTPDphotoSizeEmpty &) {
|
// }, [](const MTPDphotoSizeEmpty &) {
|
||||||
return SizeData();
|
// return SizeData();
|
||||||
}, [](const MTPDphotoStrippedSize &data) {
|
// }, [](const MTPDphotoStrippedSize &data) {
|
||||||
// No need to save stripped images to local cache.
|
// // No need to save stripped images to local cache.
|
||||||
return SizeData();
|
// return SizeData();
|
||||||
});
|
// });
|
||||||
const auto letter = size.type.v.isEmpty() ? char(0) : size.type.v[0];
|
// const auto letter = size.type.v.isEmpty() ? char(0) : size.type.v[0];
|
||||||
if (!letter) {
|
// if (!letter) {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
if (letter == 's') {
|
// if (letter == 's') {
|
||||||
saveImageToCache(_photo->thumbnailSmall(), size);
|
// saveImageToCache(_photo->thumbnailSmall(), size);
|
||||||
} else if (letter == 'm') {
|
// } else if (letter == 'm') {
|
||||||
saveImageToCache(_photo->thumbnail(), size);
|
// saveImageToCache(_photo->thumbnail(), size);
|
||||||
} else if (letter == 'x' && max < 1) {
|
// } else if (letter == 'x' && max < 1) {
|
||||||
max = 1;
|
// max = 1;
|
||||||
maxSize = size;
|
// maxSize = size;
|
||||||
} else if (letter == 'y' && max < 2) {
|
// } else if (letter == 'y' && max < 2) {
|
||||||
max = 2;
|
// max = 2;
|
||||||
maxSize = size;
|
// maxSize = size;
|
||||||
//} else if (letter == 'w' && max < 3) {
|
// //} else if (letter == 'w' && max < 3) {
|
||||||
// max = 3;
|
// // max = 3;
|
||||||
// maxSize = size;
|
// // maxSize = size;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
if (!maxSize.type.v.isEmpty()) {
|
//if (!maxSize.type.v.isEmpty()) {
|
||||||
saveImageToCache(_photo->large(), maxSize);
|
// saveImageToCache(_photo->large(), maxSize);
|
||||||
}
|
//}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_reply_preview.h"
|
#include "data/data_reply_preview.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/image/image_source.h"
|
#include "ui/image/image_source.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
#include "storage/file_download.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "facades.h"
|
#include "facades.h"
|
||||||
#include "app.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)
|
PhotoData::PhotoData(not_null<Data::Session*> owner, PhotoId id)
|
||||||
: id(id)
|
: id(id)
|
||||||
, _owner(owner) {
|
, _owner(owner) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PhotoData::~PhotoData() = default;
|
PhotoData::~PhotoData() {
|
||||||
|
for (auto &image : _images) {
|
||||||
|
base::take(image.loader).reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Data::Session &PhotoData::owner() const {
|
Data::Session &PhotoData::owner() const {
|
||||||
return *_owner;
|
return *_owner;
|
||||||
|
@ -33,55 +48,77 @@ Main::Session &PhotoData::session() const {
|
||||||
return _owner->session();
|
return _owner->session();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) {
|
|
||||||
_large->automaticLoad(origin, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhotoData::automaticLoadSettingsChanged() {
|
void PhotoData::automaticLoadSettingsChanged() {
|
||||||
_large->automaticLoadSettingsChanged();
|
const auto index = PhotoSizeIndex(PhotoSize::Large);
|
||||||
}
|
if (!(_images[index].flags & ImageFlag::Cancelled)) {
|
||||||
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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 {
|
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 {
|
bool PhotoData::displayLoading() const {
|
||||||
return _large->loading()
|
const auto index = PhotoSizeIndex(PhotoSize::Large);
|
||||||
? _large->displayLoading()
|
return _images[index].loader
|
||||||
|
? (!_images[index].loader->loadingLocal()
|
||||||
|
|| !_images[index].loader->autoLoading())
|
||||||
: (uploading() && !waitingForAlbum());
|
: (uploading() && !waitingForAlbum());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::cancel() {
|
void PhotoData::cancel() {
|
||||||
_large->cancel();
|
if (!loading()) {
|
||||||
_owner->notifyPhotoLayoutChanged(this);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto index = PhotoSizeIndex(PhotoSize::Large);
|
||||||
|
_images[index].flags |= ImageFlag::Cancelled;
|
||||||
|
destroyLoader(PhotoSize::Large);
|
||||||
|
_owner->photoLoadDone(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
float64 PhotoData::progress() const {
|
float64 PhotoData::progress() const {
|
||||||
if (uploading()) {
|
if (uploading()) {
|
||||||
if (uploadingData->size > 0) {
|
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() {
|
void PhotoData::setWaitingForAlbum() {
|
||||||
|
@ -95,7 +132,8 @@ bool PhotoData::waitingForAlbum() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 PhotoData::loadOffset() 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 {
|
bool PhotoData::uploading() const {
|
||||||
|
@ -103,11 +141,6 @@ bool PhotoData::uploading() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::unload() {
|
void PhotoData::unload() {
|
||||||
// Forget thumbnail only when image cache limit exceeds.
|
|
||||||
//_thumbnailInline->unload();
|
|
||||||
_thumbnailSmall->unload();
|
|
||||||
_thumbnail->unload();
|
|
||||||
_large->unload();
|
|
||||||
_replyPreview = nullptr;
|
_replyPreview = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,9 +175,9 @@ QByteArray PhotoData::fileReference() const {
|
||||||
|
|
||||||
void PhotoData::refreshFileReference(const QByteArray &value) {
|
void PhotoData::refreshFileReference(const QByteArray &value) {
|
||||||
_fileReference = value;
|
_fileReference = value;
|
||||||
_thumbnailSmall->refreshFileReference(value);
|
for (auto &image : _images) {
|
||||||
_thumbnail->refreshFileReference(value);
|
image.location.refreshFileReference(value);
|
||||||
_large->refreshFileReference(value);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::collectLocalData(not_null<PhotoData*> local) {
|
void PhotoData::collectLocalData(not_null<PhotoData*> local) {
|
||||||
|
@ -152,83 +185,185 @@ void PhotoData::collectLocalData(not_null<PhotoData*> local) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto copyImage = [&](const ImagePtr &src, const ImagePtr &dst) {
|
for (auto i = 0; i != kPhotoSizeCount; ++i) {
|
||||||
if (const auto from = src->cacheKey()) {
|
if (const auto from = local->_images[i].location.file().cacheKey()) {
|
||||||
if (const auto to = dst->cacheKey()) {
|
if (const auto to = _images[i].location.file().cacheKey()) {
|
||||||
_owner->cache().copyIfEmpty(from, to);
|
_owner->cache().copyIfEmpty(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
copyImage(local->_thumbnailSmall, _thumbnailSmall);
|
if (const auto localMedia = local->activeMediaView()) {
|
||||||
copyImage(local->_thumbnail, _thumbnail);
|
const auto media = createMediaView();
|
||||||
copyImage(local->_large, _large);
|
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 {
|
bool PhotoData::isNull() const {
|
||||||
return _large->isNull();
|
return !_images[PhotoSizeIndex(PhotoSize::Large)].location.valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::loadThumbnail(Data::FileOrigin origin) {
|
void PhotoData::load(
|
||||||
_thumbnail->load(origin);
|
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) {
|
void PhotoData::finishLoad(PhotoSize size) {
|
||||||
_thumbnailSmall->load(origin);
|
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 {
|
void PhotoData::destroyLoader(PhotoSize size) {
|
||||||
return _thumbnailInline ? _thumbnailInline.get() : nullptr;
|
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 {
|
std::shared_ptr<PhotoMedia> PhotoData::createMediaView() {
|
||||||
return _thumbnailSmall.get();
|
if (auto result = activeMediaView()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
auto result = std::make_shared<PhotoMedia>(this);
|
||||||
|
_media = result;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Image*> PhotoData::thumbnail() const {
|
std::shared_ptr<PhotoMedia> PhotoData::activeMediaView() const {
|
||||||
return _thumbnail.get();
|
return _media.lock();
|
||||||
}
|
|
||||||
|
|
||||||
void PhotoData::load(Data::FileOrigin origin) {
|
|
||||||
_large->load(origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
not_null<Image*> PhotoData::large() const {
|
|
||||||
return _large.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::updateImages(
|
void PhotoData::updateImages(
|
||||||
ImagePtr thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
ImagePtr thumbnailSmall,
|
const ImageWithLocation &small,
|
||||||
ImagePtr thumbnail,
|
const ImageWithLocation &thumbnail,
|
||||||
ImagePtr large) {
|
const ImageWithLocation &large) {
|
||||||
if (!thumbnailSmall || !thumbnail || !large) {
|
if (!inlineThumbnailBytes.isEmpty()
|
||||||
return;
|
&& _inlineThumbnailBytes.isEmpty()) {
|
||||||
|
_inlineThumbnailBytes = inlineThumbnailBytes;
|
||||||
}
|
}
|
||||||
if (thumbnailInline && !_thumbnailInline) {
|
const auto update = [&](PhotoSize size, const ImageWithLocation &data) {
|
||||||
_thumbnailInline = thumbnailInline;
|
auto &image = _images[PhotoSizeIndex(size)];
|
||||||
}
|
if (data.location.valid()
|
||||||
const auto update = [](ImagePtr &was, ImagePtr now) {
|
&& (!image.location.valid()
|
||||||
if (!was) {
|
|| image.location.width() != data.location.width()
|
||||||
was = now;
|
|| image.location.height() != data.location.height())) {
|
||||||
} else if (was->isDelayedStorageImage()) {
|
image.location = data.location;
|
||||||
if (const auto location = now->location(); location.valid()) {
|
image.byteSize = data.bytesCount;
|
||||||
was->setDelayedStorageLocation(
|
if (!data.preloaded.isNull()) {
|
||||||
Data::FileOrigin(),
|
image.loader = nullptr;
|
||||||
location);
|
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(PhotoSize::Small, small);
|
||||||
update(_thumbnail, thumbnail);
|
update(PhotoSize::Thumbnail, thumbnail);
|
||||||
update(_large, large);
|
update(PhotoSize::Large, large);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PhotoData::width() const {
|
int PhotoData::width() const {
|
||||||
return _large->width();
|
return _images[PhotoSizeIndex(PhotoSize::Large)].location.width();
|
||||||
}
|
}
|
||||||
|
|
||||||
int PhotoData::height() const {
|
int PhotoData::height() const {
|
||||||
return _large->height();
|
return _images[PhotoSizeIndex(PhotoSize::Large)].location.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
PhotoClickHandler::PhotoClickHandler(
|
PhotoClickHandler::PhotoClickHandler(
|
||||||
|
@ -255,7 +390,7 @@ void PhotoSaveClickHandler::onClickImpl() const {
|
||||||
if (!data->date) {
|
if (!data->date) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
data->download(context());
|
data->load(context());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,26 @@ class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
class ReplyPreview;
|
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
|
} // namespace Data
|
||||||
|
|
||||||
class PhotoData final {
|
class PhotoData final {
|
||||||
|
@ -25,20 +43,17 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Data::Session &owner() const;
|
[[nodiscard]] Data::Session &owner() const;
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
[[nodiscard]] bool isNull() const;
|
||||||
|
|
||||||
void automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item);
|
|
||||||
void automaticLoadSettingsChanged();
|
void automaticLoadSettingsChanged();
|
||||||
|
|
||||||
void download(Data::FileOrigin origin);
|
|
||||||
[[nodiscard]] bool loaded() const;
|
|
||||||
[[nodiscard]] bool loading() const;
|
[[nodiscard]] bool loading() const;
|
||||||
[[nodiscard]] bool displayLoading() const;
|
[[nodiscard]] bool displayLoading() const;
|
||||||
void cancel();
|
void cancel();
|
||||||
[[nodiscard]] float64 progress() const;
|
[[nodiscard]] float64 progress() const;
|
||||||
[[nodiscard]] int32 loadOffset() const;
|
[[nodiscard]] int32 loadOffset() const;
|
||||||
[[nodiscard]] bool uploading() const;
|
[[nodiscard]] bool uploading() const;
|
||||||
|
[[nodiscard]] bool cancelled() const;
|
||||||
|
|
||||||
void setWaitingForAlbum();
|
void setWaitingForAlbum();
|
||||||
[[nodiscard]] bool waitingForAlbum() const;
|
[[nodiscard]] bool waitingForAlbum() const;
|
||||||
|
@ -60,27 +75,39 @@ public:
|
||||||
// to (this) received from the server "same" photo.
|
// to (this) received from the server "same" photo.
|
||||||
void collectLocalData(not_null<PhotoData*> local);
|
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 updateImages(
|
||||||
void loadThumbnailSmall(Data::FileOrigin origin);
|
const QByteArray &inlineThumbnailBytes,
|
||||||
Image *thumbnailInline() const;
|
const ImageWithLocation &small,
|
||||||
not_null<Image*> thumbnailSmall() const;
|
const ImageWithLocation &thumbnail,
|
||||||
not_null<Image*> thumbnail() const;
|
const ImageWithLocation &large);
|
||||||
|
|
||||||
void load(Data::FileOrigin origin);
|
[[nodiscard]] QByteArray inlineThumbnailBytes() const {
|
||||||
not_null<Image*> large() 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.
|
// For now they return size of the 'large' image.
|
||||||
int width() const;
|
int width() const;
|
||||||
int height() const;
|
int height() const;
|
||||||
|
|
||||||
void updateImages(
|
|
||||||
ImagePtr thumbnailInline,
|
|
||||||
ImagePtr thumbnailSmall,
|
|
||||||
ImagePtr thumbnail,
|
|
||||||
ImagePtr large);
|
|
||||||
|
|
||||||
PhotoId id = 0;
|
PhotoId id = 0;
|
||||||
TimeId date = 0;
|
TimeId date = 0;
|
||||||
bool hasSticker = false;
|
bool hasSticker = false;
|
||||||
|
@ -91,15 +118,30 @@ public:
|
||||||
std::unique_ptr<Data::UploadState> uploadingData;
|
std::unique_ptr<Data::UploadState> uploadingData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ImagePtr _thumbnailInline;
|
enum class ImageFlag : uchar {
|
||||||
ImagePtr _thumbnailSmall;
|
Cancelled = 0x01,
|
||||||
ImagePtr _thumbnail;
|
Failed = 0x02,
|
||||||
ImagePtr _large;
|
};
|
||||||
|
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;
|
int32 _dc = 0;
|
||||||
uint64 _access = 0;
|
uint64 _access = 0;
|
||||||
QByteArray _fileReference;
|
QByteArray _fileReference;
|
||||||
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
||||||
|
std::weak_ptr<Data::PhotoMedia> _media;
|
||||||
|
|
||||||
not_null<Data::Session*> _owner;
|
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.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/image/image_source.h"
|
#include "ui/image/image_source.h"
|
||||||
|
|
||||||
|
@ -62,18 +63,18 @@ Image *ReplyPreview::image(Data::FileOrigin origin) {
|
||||||
return _image.get();
|
return _image.get();
|
||||||
}
|
}
|
||||||
if (_document) {
|
if (_document) {
|
||||||
if (!_documentMedia) {
|
if (!_image || (!_good && _document->hasThumbnail())) {
|
||||||
_documentMedia = _document->createMediaView();
|
if (!_documentMedia) {
|
||||||
}
|
_documentMedia = _document->createMediaView();
|
||||||
const auto thumbnail = _documentMedia->thumbnail();
|
_documentMedia->thumbnailWanted(origin);
|
||||||
if (!_image || (!_good && thumbnail)) {
|
}
|
||||||
|
const auto thumbnail = _documentMedia->thumbnail();
|
||||||
const auto option = _document->isVideoMessage()
|
const auto option = _document->isVideoMessage()
|
||||||
? Images::Option::Circled
|
? Images::Option::Circled
|
||||||
: Images::Option::None;
|
: Images::Option::None;
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
prepare(thumbnail, option);
|
prepare(thumbnail, option);
|
||||||
} else {
|
} else {
|
||||||
_documentMedia->thumbnailWanted(origin);
|
|
||||||
if (const auto image = _documentMedia->thumbnailInline()) {
|
if (const auto image = _documentMedia->thumbnailInline()) {
|
||||||
prepare(image, option | Images::Option::Blurred);
|
prepare(image, option | Images::Option::Blurred);
|
||||||
}
|
}
|
||||||
|
@ -85,22 +86,33 @@ Image *ReplyPreview::image(Data::FileOrigin origin) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Assert(_photo != nullptr);
|
Assert(_photo != nullptr);
|
||||||
const auto small = _photo->thumbnailSmall();
|
if (!_image || !_good) {
|
||||||
const auto large = _photo->large();
|
if (!_photoMedia) {
|
||||||
if (!_image || (!_good && (small->loaded() || large->loaded()))) {
|
_photoMedia = _photo->createMediaView();
|
||||||
if (small->isDelayedStorageImage()
|
_photoMedia->wanted(PhotoSize::Small, origin);
|
||||||
&& !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 (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();
|
return _image.get();
|
||||||
|
|
|
@ -12,6 +12,7 @@ class PhotoData;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
|
class PhotoMedia;
|
||||||
class DocumentMedia;
|
class DocumentMedia;
|
||||||
struct FileOrigin;
|
struct FileOrigin;
|
||||||
|
|
||||||
|
@ -26,11 +27,12 @@ private:
|
||||||
void prepare(not_null<Image*> image, Images::Options options);
|
void prepare(not_null<Image*> image, Images::Options options);
|
||||||
|
|
||||||
std::unique_ptr<Image> _image;
|
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 _good = false;
|
||||||
bool _checked = 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
|
// b: crop 320x320
|
||||||
// c: crop 640x640
|
// c: crop 640x640
|
||||||
// d: crop 1280x1280
|
// d: crop 1280x1280
|
||||||
const auto InlineLevels = QByteArray::fromRawData("i", 1);
|
const auto InlineLevels = "i"_q;
|
||||||
const auto SmallLevels = QByteArray::fromRawData("sambcxydwi", 10);
|
const auto SmallLevels = "sambcxydwi"_q;
|
||||||
const auto ThumbnailLevels = QByteArray::fromRawData("mbcxasydwi", 10);
|
const auto ThumbnailLevels = "mbcxasydwi"_q;
|
||||||
const auto LargeLevels = QByteArray::fromRawData("yxwmsdcbai", 10);
|
const auto LargeLevels = "yxwmsdcbai"_q;
|
||||||
|
|
||||||
void CheckForSwitchInlineButton(not_null<HistoryItem*> item) {
|
void CheckForSwitchInlineButton(not_null<HistoryItem*> item) {
|
||||||
if (item->out() || !item->hasSwitchInlineButton()) {
|
if (item->out() || !item->hasSwitchInlineButton()) {
|
||||||
|
@ -127,23 +127,22 @@ std::vector<UnavailableReason> ExtractUnavailableReasons(
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FindDocumentInlineThumbnail(const MTPDdocument &data) {
|
[[nodiscard]] QByteArray FindInlineThumbnail(
|
||||||
const auto thumbs = data.vthumbs();
|
const QVector<MTPPhotoSize> &sizes) {
|
||||||
if (!thumbs) {
|
|
||||||
return QByteArray();
|
|
||||||
}
|
|
||||||
const auto &list = thumbs->v;
|
|
||||||
const auto i = ranges::find(
|
const auto i = ranges::find(
|
||||||
list,
|
sizes,
|
||||||
mtpc_photoStrippedSize,
|
mtpc_photoStrippedSize,
|
||||||
&MTPPhotoSize::type);
|
&MTPPhotoSize::type);
|
||||||
if (i == list.end()) {
|
return (i != sizes.end())
|
||||||
return QByteArray();
|
? i->c_photoStrippedSize().vbytes().v
|
||||||
}
|
: QByteArray();
|
||||||
return i->c_photoStrippedSize().vbytes().v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
const auto area = [](const MTPPhotoSize &size) {
|
||||||
static constexpr auto kInvalid = 0;
|
static constexpr auto kInvalid = 0;
|
||||||
return size.match([](const MTPDphotoSizeEmpty &) {
|
return size.match([](const MTPDphotoSizeEmpty &) {
|
||||||
|
@ -165,7 +164,7 @@ MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
|
||||||
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
|
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
|
[[nodiscard]] std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
|
||||||
const MTPDdocument &data) {
|
const MTPDdocument &data) {
|
||||||
const auto area = [](const MTPVideoSize &size) {
|
const auto area = [](const MTPVideoSize &size) {
|
||||||
static constexpr auto kInvalid = 0;
|
static constexpr auto kInvalid = 0;
|
||||||
|
@ -184,7 +183,11 @@ std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
|
||||||
: std::nullopt;
|
: 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) {
|
not_null<Main::Session*> session) {
|
||||||
return rpl::single(
|
return rpl::single(
|
||||||
rpl::empty_value()
|
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(
|
void Session::notifyDocumentLayoutChanged(
|
||||||
not_null<const DocumentData*> document) {
|
not_null<const DocumentData*> document) {
|
||||||
const auto i = _documentItems.find(document);
|
const auto i = _documentItems.find(document);
|
||||||
|
@ -1153,6 +1165,20 @@ void Session::documentLoadFail(
|
||||||
notifyDocumentLayoutChanged(document);
|
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) {
|
void Session::markMediaRead(not_null<const DocumentData*> document) {
|
||||||
const auto i = _documentItems.find(document);
|
const auto i = _documentItems.find(document);
|
||||||
if (i != end(_documentItems)) {
|
if (i != end(_documentItems)) {
|
||||||
|
@ -2174,11 +2200,10 @@ not_null<PhotoData*> Session::processPhoto(
|
||||||
const auto image = [&](const QByteArray &levels) {
|
const auto image = [&](const QByteArray &levels) {
|
||||||
const auto i = find(levels);
|
const auto i = find(levels);
|
||||||
return (i == thumbs.end())
|
return (i == thumbs.end())
|
||||||
? ImagePtr()
|
? ImageWithLocation()
|
||||||
: Images::Create(base::duplicate(i->second), "JPG");
|
: Images::FromImageInMemory(i->second, "JPG");
|
||||||
};
|
};
|
||||||
const auto thumbnailInline = image(InlineLevels);
|
const auto small = image(SmallLevels);
|
||||||
const auto thumbnailSmall = image(SmallLevels);
|
|
||||||
const auto thumbnail = image(ThumbnailLevels);
|
const auto thumbnail = image(ThumbnailLevels);
|
||||||
const auto large = image(LargeLevels);
|
const auto large = image(LargeLevels);
|
||||||
return data.match([&](const MTPDphoto &data) {
|
return data.match([&](const MTPDphoto &data) {
|
||||||
|
@ -2189,8 +2214,8 @@ not_null<PhotoData*> Session::processPhoto(
|
||||||
data.vdate().v,
|
data.vdate().v,
|
||||||
data.vdc_id().v,
|
data.vdc_id().v,
|
||||||
data.is_has_stickers(),
|
data.is_has_stickers(),
|
||||||
thumbnailInline,
|
QByteArray(),
|
||||||
thumbnailSmall,
|
small,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
large);
|
large);
|
||||||
}, [&](const MTPDphotoEmpty &data) {
|
}, [&](const MTPDphotoEmpty &data) {
|
||||||
|
@ -2205,10 +2230,10 @@ not_null<PhotoData*> Session::photo(
|
||||||
TimeId date,
|
TimeId date,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
bool hasSticker,
|
bool hasSticker,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnailSmall,
|
const ImageWithLocation &small,
|
||||||
const ImagePtr &thumbnail,
|
const ImageWithLocation &thumbnail,
|
||||||
const ImagePtr &large) {
|
const ImageWithLocation &large) {
|
||||||
const auto result = photo(id);
|
const auto result = photo(id);
|
||||||
photoApplyFields(
|
photoApplyFields(
|
||||||
result,
|
result,
|
||||||
|
@ -2217,8 +2242,8 @@ not_null<PhotoData*> Session::photo(
|
||||||
date,
|
date,
|
||||||
dc,
|
dc,
|
||||||
hasSticker,
|
hasSticker,
|
||||||
thumbnailInline,
|
inlineThumbnailBytes,
|
||||||
thumbnailSmall,
|
small,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
large);
|
large);
|
||||||
return result;
|
return result;
|
||||||
|
@ -2252,26 +2277,28 @@ void Session::photoConvert(
|
||||||
|
|
||||||
PhotoData *Session::photoFromWeb(
|
PhotoData *Session::photoFromWeb(
|
||||||
const MTPWebDocument &data,
|
const MTPWebDocument &data,
|
||||||
ImagePtr thumbnail,
|
const ImageLocation &thumbnailLocation,
|
||||||
bool willBecomeNormal) {
|
bool willBecomeNormal) {
|
||||||
const auto large = Images::Create(data);
|
const auto large = Images::FromWebDocument(data);
|
||||||
const auto thumbnailInline = ImagePtr();
|
const auto thumbnailInline = ImagePtr();
|
||||||
if (large->isNull()) {
|
if (!large.valid()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto thumbnailSmall = large;
|
auto small = large;
|
||||||
|
auto thumbnail = thumbnailLocation;
|
||||||
if (willBecomeNormal) {
|
if (willBecomeNormal) {
|
||||||
const auto width = large->width();
|
const auto width = large.width();
|
||||||
const auto height = large->height();
|
const auto height = large.height();
|
||||||
|
|
||||||
auto thumbsize = shrinkToKeepAspect(width, height, 100, 100);
|
// #TODO optimize
|
||||||
thumbnailSmall = Images::Create(thumbsize.width(), thumbsize.height());
|
//auto thumbsize = shrinkToKeepAspect(width, height, 100, 100);
|
||||||
|
//small = Images::Create(thumbsize.width(), thumbsize.height());
|
||||||
|
|
||||||
if (thumbnail->isNull()) {
|
//if (!thumbnail.valid()) {
|
||||||
auto mediumsize = shrinkToKeepAspect(width, height, 320, 320);
|
// auto mediumsize = shrinkToKeepAspect(width, height, 320, 320);
|
||||||
thumbnail = Images::Create(mediumsize.width(), mediumsize.height());
|
// thumbnail = Images::Create(mediumsize.width(), mediumsize.height());
|
||||||
}
|
//}
|
||||||
} else if (thumbnail->isNull()) {
|
} else if (!thumbnail.valid()) {
|
||||||
thumbnail = large;
|
thumbnail = large;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2282,10 +2309,10 @@ PhotoData *Session::photoFromWeb(
|
||||||
base::unixtime::now(),
|
base::unixtime::now(),
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
thumbnailInline,
|
QByteArray(),
|
||||||
thumbnailSmall,
|
ImageWithLocation{ .location = small },
|
||||||
thumbnail,
|
ImageWithLocation{ .location = thumbnail },
|
||||||
large);
|
ImageWithLocation{ .location = large });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::photoApplyFields(
|
void Session::photoApplyFields(
|
||||||
|
@ -2319,13 +2346,12 @@ void Session::photoApplyFields(
|
||||||
};
|
};
|
||||||
const auto image = [&](const QByteArray &levels) {
|
const auto image = [&](const QByteArray &levels) {
|
||||||
const auto i = find(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);
|
const auto large = image(LargeLevels);
|
||||||
if (thumbnailSmall && thumbnail && large) {
|
if (large.location.valid()) {
|
||||||
photoApplyFields(
|
photoApplyFields(
|
||||||
photo,
|
photo,
|
||||||
data.vaccess_hash().v,
|
data.vaccess_hash().v,
|
||||||
|
@ -2333,9 +2359,9 @@ void Session::photoApplyFields(
|
||||||
data.vdate().v,
|
data.vdate().v,
|
||||||
data.vdc_id().v,
|
data.vdc_id().v,
|
||||||
data.is_has_stickers(),
|
data.is_has_stickers(),
|
||||||
thumbnailInline,
|
FindPhotoInlineThumbnail(data),
|
||||||
thumbnailSmall,
|
image(SmallLevels),
|
||||||
thumbnail,
|
image(ThumbnailLevels),
|
||||||
large);
|
large);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2347,10 +2373,10 @@ void Session::photoApplyFields(
|
||||||
TimeId date,
|
TimeId date,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
bool hasSticker,
|
bool hasSticker,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnailSmall,
|
const ImageWithLocation &small,
|
||||||
const ImagePtr &thumbnail,
|
const ImageWithLocation &thumbnail,
|
||||||
const ImagePtr &large) {
|
const ImageWithLocation &large) {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2358,8 +2384,8 @@ void Session::photoApplyFields(
|
||||||
photo->date = date;
|
photo->date = date;
|
||||||
photo->hasSticker = hasSticker;
|
photo->hasSticker = hasSticker;
|
||||||
photo->updateImages(
|
photo->updateImages(
|
||||||
thumbnailInline,
|
inlineThumbnailBytes,
|
||||||
thumbnailSmall,
|
small,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
large);
|
large);
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,12 +427,17 @@ public:
|
||||||
void documentLoadSettingsChanged();
|
void documentLoadSettingsChanged();
|
||||||
|
|
||||||
void notifyPhotoLayoutChanged(not_null<const PhotoData*> photo);
|
void notifyPhotoLayoutChanged(not_null<const PhotoData*> photo);
|
||||||
|
void requestPhotoViewRepaint(not_null<const PhotoData*> photo);
|
||||||
void notifyDocumentLayoutChanged(
|
void notifyDocumentLayoutChanged(
|
||||||
not_null<const DocumentData*> document);
|
not_null<const DocumentData*> document);
|
||||||
void requestDocumentViewRepaint(not_null<const DocumentData*> document);
|
void requestDocumentViewRepaint(not_null<const DocumentData*> document);
|
||||||
void markMediaRead(not_null<const DocumentData*> document);
|
void markMediaRead(not_null<const DocumentData*> document);
|
||||||
void requestPollViewRepaint(not_null<const PollData*> poll);
|
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 documentLoadProgress(not_null<DocumentData*> document);
|
||||||
void documentLoadDone(not_null<DocumentData*> document);
|
void documentLoadDone(not_null<DocumentData*> document);
|
||||||
void documentLoadFail(not_null<DocumentData*> document, bool started);
|
void documentLoadFail(not_null<DocumentData*> document, bool started);
|
||||||
|
@ -473,16 +478,16 @@ public:
|
||||||
TimeId date,
|
TimeId date,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
bool hasSticker,
|
bool hasSticker,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnailSmall,
|
const ImageWithLocation &small,
|
||||||
const ImagePtr &thumbnail,
|
const ImageWithLocation &thumbnail,
|
||||||
const ImagePtr &large);
|
const ImageWithLocation &large);
|
||||||
void photoConvert(
|
void photoConvert(
|
||||||
not_null<PhotoData*> original,
|
not_null<PhotoData*> original,
|
||||||
const MTPPhoto &data);
|
const MTPPhoto &data);
|
||||||
[[nodiscard]] PhotoData *photoFromWeb(
|
[[nodiscard]] PhotoData *photoFromWeb(
|
||||||
const MTPWebDocument &data,
|
const MTPWebDocument &data,
|
||||||
ImagePtr thumbnail = ImagePtr(),
|
const ImageLocation &thumbnailLocation = ImageLocation(),
|
||||||
bool willBecomeNormal = false);
|
bool willBecomeNormal = false);
|
||||||
|
|
||||||
[[nodiscard]] not_null<DocumentData*> document(DocumentId id);
|
[[nodiscard]] not_null<DocumentData*> document(DocumentId id);
|
||||||
|
@ -736,10 +741,10 @@ private:
|
||||||
TimeId date,
|
TimeId date,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
bool hasSticker,
|
bool hasSticker,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnailSmall,
|
const ImageWithLocation &small,
|
||||||
const ImagePtr &thumbnail,
|
const ImageWithLocation &thumbnail,
|
||||||
const ImagePtr &large);
|
const ImageWithLocation &large);
|
||||||
|
|
||||||
void documentApplyFields(
|
void documentApplyFields(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
|
|
|
@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/peers/edit_participants_box.h"
|
#include "boxes/peers/edit_participants_box.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
@ -1137,11 +1138,13 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::savePhotoToFile(PhotoData *photo) {
|
void InnerWidget::savePhotoToFile(not_null<PhotoData*> photo) {
|
||||||
if (!photo || photo->isNull() || !photo->loaded()) {
|
const auto media = photo->activeMediaView();
|
||||||
|
if (photo->isNull() || !media || !media->loaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto image = media->image(Data::PhotoSize::Large)->original();
|
||||||
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
|
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
|
||||||
FileDialog::GetWritePath(
|
FileDialog::GetWritePath(
|
||||||
this,
|
this,
|
||||||
|
@ -1150,22 +1153,26 @@ void InnerWidget::savePhotoToFile(PhotoData *photo) {
|
||||||
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
|
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
|
||||||
crl::guard(this, [=](const QString &result) {
|
crl::guard(this, [=](const QString &result) {
|
||||||
if (!result.isEmpty()) {
|
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(
|
DocumentSaveClickHandler::Save(
|
||||||
Data::FileOrigin(),
|
Data::FileOrigin(),
|
||||||
document,
|
document,
|
||||||
DocumentSaveClickHandler::Mode::ToNewFile);
|
DocumentSaveClickHandler::Mode::ToNewFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::copyContextImage(PhotoData *photo) {
|
void InnerWidget::copyContextImage(not_null<PhotoData*> photo) {
|
||||||
if (!photo || 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 InnerWidget::copySelectedText() {
|
void InnerWidget::copySelectedText() {
|
||||||
|
|
|
@ -162,9 +162,9 @@ private:
|
||||||
QPoint mapPointToItem(QPoint point, const Element *view) const;
|
QPoint mapPointToItem(QPoint point, const Element *view) const;
|
||||||
|
|
||||||
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
|
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
|
||||||
void savePhotoToFile(PhotoData *photo);
|
void savePhotoToFile(not_null<PhotoData*> photo);
|
||||||
void saveDocumentToFile(DocumentData *document);
|
void saveDocumentToFile(not_null<DocumentData*> document);
|
||||||
void copyContextImage(PhotoData *photo);
|
void copyContextImage(not_null<PhotoData*> photo);
|
||||||
void showStickerPackInfo(not_null<DocumentData*> document);
|
void showStickerPackInfo(not_null<DocumentData*> document);
|
||||||
void cancelContextDownload(not_null<DocumentData*> document);
|
void cancelContextDownload(not_null<DocumentData*> document);
|
||||||
void showContextInFolder(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_document.h"
|
||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
|
@ -1853,8 +1854,12 @@ void HistoryInner::copySelectedText() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
|
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();
|
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
|
||||||
FileDialog::GetWritePath(
|
FileDialog::GetWritePath(
|
||||||
this,
|
this,
|
||||||
|
@ -1865,15 +1870,19 @@ void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
|
||||||
qsl(".jpg")),
|
qsl(".jpg")),
|
||||||
crl::guard(this, [=](const QString &result) {
|
crl::guard(this, [=](const QString &result) {
|
||||||
if (!result.isEmpty()) {
|
if (!result.isEmpty()) {
|
||||||
photo->large()->original().save(result, "JPG");
|
image.save(result, "JPG");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInner::copyContextImage(not_null<PhotoData*> photo) {
|
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) {
|
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/confirm_box.h"
|
||||||
#include "boxes/sticker_set_box.h"
|
#include "boxes/sticker_set_box.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -72,10 +73,12 @@ MsgId ItemIdAcrossData(not_null<HistoryItem*> item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SavePhotoToFile(not_null<PhotoData*> photo) {
|
void SavePhotoToFile(not_null<PhotoData*> photo) {
|
||||||
if (photo->isNull() || !photo->loaded()) {
|
const auto media = photo->activeMediaView();
|
||||||
|
if (photo->isNull() || !media || !media->loaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto image = media->image(Data::PhotoSize::Large)->original();
|
||||||
FileDialog::GetWritePath(
|
FileDialog::GetWritePath(
|
||||||
Core::App().getFileDialogParent(),
|
Core::App().getFileDialogParent(),
|
||||||
tr::lng_save_photo(tr::now),
|
tr::lng_save_photo(tr::now),
|
||||||
|
@ -83,17 +86,19 @@ void SavePhotoToFile(not_null<PhotoData*> photo) {
|
||||||
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
|
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
|
||||||
crl::guard(&photo->session(), [=](const QString &result) {
|
crl::guard(&photo->session(), [=](const QString &result) {
|
||||||
if (!result.isEmpty()) {
|
if (!result.isEmpty()) {
|
||||||
photo->large()->original().save(result, "JPG");
|
image.save(result, "JPG");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyImage(not_null<PhotoData*> photo) {
|
void CopyImage(not_null<PhotoData*> photo) {
|
||||||
if (photo->isNull() || !photo->loaded()) {
|
const auto media = photo->activeMediaView();
|
||||||
|
if (photo->isNull() || !media || !media->loaded()) {
|
||||||
return;
|
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) {
|
void ShowStickerPackInfo(not_null<DocumentData*> document) {
|
||||||
|
|
|
@ -18,11 +18,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/grouped_layout.h"
|
#include "ui/grouped_layout.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Data::PhotoSize;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Photo::Photo(
|
Photo::Photo(
|
||||||
not_null<Element*> parent,
|
not_null<Element*> parent,
|
||||||
|
@ -46,18 +52,48 @@ Photo::Photo(
|
||||||
create(parent->data()->fullId(), chat);
|
create(parent->data()->fullId(), chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Photo::~Photo() = default;
|
||||||
|
|
||||||
void Photo::create(FullMsgId contextId, PeerData *chat) {
|
void Photo::create(FullMsgId contextId, PeerData *chat) {
|
||||||
setLinks(
|
setLinks(
|
||||||
std::make_shared<PhotoOpenClickHandler>(_data, contextId, chat),
|
std::make_shared<PhotoOpenClickHandler>(_data, contextId, chat),
|
||||||
std::make_shared<PhotoSaveClickHandler>(_data, contextId, chat),
|
std::make_shared<PhotoSaveClickHandler>(_data, contextId, chat),
|
||||||
std::make_shared<PhotoCancelClickHandler>(_data, contextId, chat));
|
std::make_shared<PhotoCancelClickHandler>(_data, contextId, chat));
|
||||||
if (!_data->thumbnailInline()
|
if ((_dataMedia = _data->activeMediaView())) {
|
||||||
&& !_data->loaded()
|
dataMediaCreated();
|
||||||
&& !_data->thumbnail()->loaded()) {
|
} else if (_data->inlineThumbnailBytes().isEmpty()) {
|
||||||
_data->thumbnailSmall()->load(contextId);
|
_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() {
|
QSize Photo::countOptimalSize() {
|
||||||
if (_parent->media() != this) {
|
if (_parent->media() != this) {
|
||||||
_caption = Ui::Text::String();
|
_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 {
|
void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
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 selected = (selection == FullSelection);
|
||||||
auto loaded = _data->loaded();
|
auto loaded = _dataMedia->loaded();
|
||||||
auto displayLoading = _data->displayLoading();
|
auto displayLoading = _data->displayLoading();
|
||||||
|
|
||||||
auto inWebPage = (_parent->media() != this);
|
auto inWebPage = (_parent->media() != this);
|
||||||
|
@ -159,7 +196,7 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
|
||||||
if (displayLoading) {
|
if (displayLoading) {
|
||||||
ensureAnimation();
|
ensureAnimation();
|
||||||
if (!_animation->radial.animating()) {
|
if (!_animation->radial.animating()) {
|
||||||
_animation->radial.start(_data->progress());
|
_animation->radial.start(_dataMedia->progress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto radial = isRadialAnimation();
|
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());
|
auto rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
||||||
if (_serviceWidth > 0) {
|
if (_serviceWidth > 0) {
|
||||||
const auto pix = [&] {
|
const auto pix = [&] {
|
||||||
if (loaded) {
|
if (const auto large = _dataMedia->image(PhotoSize::Large)) {
|
||||||
return _data->large()->pixCircled(_realParent->fullId(), _pixw, _pixh);
|
return large->pixCircled(_realParent->fullId(), _pixw, _pixh);
|
||||||
} else if (_data->thumbnail()->loaded()) {
|
} else if (const auto thumbnail = _dataMedia->image(
|
||||||
return _data->thumbnail()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
PhotoSize::Thumbnail)) {
|
||||||
} else if (_data->thumbnailSmall()->loaded()) {
|
return thumbnail->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
||||||
return _data->thumbnailSmall()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
} else if (const auto small = _dataMedia->image(
|
||||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
PhotoSize::Small)) {
|
||||||
|
return small->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
||||||
|
} else if (const auto blurred = _dataMedia->thumbnailInline()) {
|
||||||
return blurred->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
return blurred->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
||||||
} else {
|
} else {
|
||||||
return QPixmap();
|
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)
|
auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
|
||||||
| ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
|
| ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
|
||||||
const auto pix = [&] {
|
const auto pix = [&] {
|
||||||
if (loaded) {
|
if (const auto large = _dataMedia->image(PhotoSize::Large)) {
|
||||||
return _data->large()->pixSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
return large->pixSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||||
} else if (_data->thumbnail()->loaded()) {
|
} else if (const auto thumbnail = _dataMedia->image(
|
||||||
return _data->thumbnail()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
PhotoSize::Thumbnail)) {
|
||||||
} else if (_data->thumbnailSmall()->loaded()) {
|
return thumbnail->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||||
return _data->thumbnailSmall()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
} else if (const auto small = _dataMedia->image(
|
||||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
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);
|
return blurred->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||||
} else {
|
} else {
|
||||||
return QPixmap();
|
return QPixmap();
|
||||||
|
@ -241,7 +282,7 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
|
||||||
auto icon = [&]() -> const style::icon* {
|
auto icon = [&]() -> const style::icon* {
|
||||||
if (radial || _data->loading()) {
|
if (radial || _data->loading()) {
|
||||||
if (_data->uploading()
|
if (_data->uploading()
|
||||||
|| _data->large()->location().valid()) {
|
|| _data->location(PhotoSize::Large).valid()) {
|
||||||
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
|
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -304,12 +345,13 @@ TextState Photo::textState(QPoint point, StateRequest request) const {
|
||||||
painth -= st::mediaCaptionSkip;
|
painth -= st::mediaCaptionSkip;
|
||||||
}
|
}
|
||||||
if (QRect(paintx, painty, paintw, painth).contains(point)) {
|
if (QRect(paintx, painty, paintw, painth).contains(point)) {
|
||||||
|
ensureDataMediaCreated();
|
||||||
if (_data->uploading()) {
|
if (_data->uploading()) {
|
||||||
result.link = _cancell;
|
result.link = _cancell;
|
||||||
} else if (_data->loaded()) {
|
} else if (_dataMedia->loaded()) {
|
||||||
result.link = _openl;
|
result.link = _openl;
|
||||||
} else if (_data->loading()) {
|
} else if (_data->loading()) {
|
||||||
if (_data->large()->location().valid()) {
|
if (_data->location(PhotoSize::Large).valid()) {
|
||||||
result.link = _cancell;
|
result.link = _cancell;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -349,19 +391,20 @@ void Photo::drawGrouped(
|
||||||
RectParts corners,
|
RectParts corners,
|
||||||
not_null<uint64*> cacheKey,
|
not_null<uint64*> cacheKey,
|
||||||
not_null<QPixmap*> cache) const {
|
not_null<QPixmap*> cache) const {
|
||||||
_data->automaticLoad(_realParent->fullId(), _parent->data());
|
ensureDataMediaCreated();
|
||||||
|
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
|
||||||
|
|
||||||
validateGroupedCache(geometry, corners, cacheKey, cache);
|
validateGroupedCache(geometry, corners, cacheKey, cache);
|
||||||
|
|
||||||
const auto selected = (selection == FullSelection);
|
const auto selected = (selection == FullSelection);
|
||||||
const auto loaded = _data->loaded();
|
const auto loaded = _dataMedia->loaded();
|
||||||
const auto displayLoading = _data->displayLoading();
|
const auto displayLoading = _data->displayLoading();
|
||||||
const auto bubble = _parent->hasBubble();
|
const auto bubble = _parent->hasBubble();
|
||||||
|
|
||||||
if (displayLoading) {
|
if (displayLoading) {
|
||||||
ensureAnimation();
|
ensureAnimation();
|
||||||
if (!_animation->radial.animating()) {
|
if (!_animation->radial.animating()) {
|
||||||
_animation->radial.start(_data->progress());
|
_animation->radial.start(_dataMedia->progress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto radial = isRadialAnimation();
|
const auto radial = isRadialAnimation();
|
||||||
|
@ -414,7 +457,7 @@ void Photo::drawGrouped(
|
||||||
return &(selected ? st::historyFileThumbWaitingSelected : st::historyFileThumbWaiting);
|
return &(selected ? st::historyFileThumbWaitingSelected : st::historyFileThumbWaiting);
|
||||||
} else if (radial || _data->loading()) {
|
} else if (radial || _data->loading()) {
|
||||||
if (_data->uploading()
|
if (_data->uploading()
|
||||||
|| _data->large()->location().valid()) {
|
|| _data->location(PhotoSize::Large).valid()) {
|
||||||
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
|
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -455,19 +498,21 @@ TextState Photo::getStateGrouped(
|
||||||
if (!geometry.contains(point)) {
|
if (!geometry.contains(point)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
ensureDataMediaCreated();
|
||||||
return TextState(_parent, _data->uploading()
|
return TextState(_parent, _data->uploading()
|
||||||
? _cancell
|
? _cancell
|
||||||
: _data->loaded()
|
: _dataMedia->loaded()
|
||||||
? _openl
|
? _openl
|
||||||
: _data->loading()
|
: _data->loading()
|
||||||
? (_data->large()->location().valid()
|
? (_data->location(PhotoSize::Large).valid()
|
||||||
? _cancell
|
? _cancell
|
||||||
: nullptr)
|
: nullptr)
|
||||||
: _savel);
|
: _savel);
|
||||||
}
|
}
|
||||||
|
|
||||||
float64 Photo::dataProgress() const {
|
float64 Photo::dataProgress() const {
|
||||||
return _data->progress();
|
ensureDataMediaCreated();
|
||||||
|
return _dataMedia->progress();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Photo::dataFinished() const {
|
bool Photo::dataFinished() const {
|
||||||
|
@ -476,7 +521,8 @@ bool Photo::dataFinished() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Photo::dataLoaded() const {
|
bool Photo::dataLoaded() const {
|
||||||
return _data->loaded();
|
ensureDataMediaCreated();
|
||||||
|
return _dataMedia->loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Photo::needInfoDisplay() const {
|
bool Photo::needInfoDisplay() const {
|
||||||
|
@ -491,12 +537,15 @@ void Photo::validateGroupedCache(
|
||||||
not_null<uint64*> cacheKey,
|
not_null<uint64*> cacheKey,
|
||||||
not_null<QPixmap*> cache) const {
|
not_null<QPixmap*> cache) const {
|
||||||
using Option = Images::Option;
|
using Option = Images::Option;
|
||||||
const auto loaded = _data->loaded();
|
|
||||||
|
ensureDataMediaCreated();
|
||||||
|
|
||||||
|
const auto loaded = _dataMedia->loaded();
|
||||||
const auto loadLevel = loaded
|
const auto loadLevel = loaded
|
||||||
? 2
|
? 2
|
||||||
: (_data->thumbnailInline()
|
: (_dataMedia->thumbnailInline()
|
||||||
|| _data->thumbnail()->loaded()
|
|| _dataMedia->image(PhotoSize::Small)
|
||||||
|| _data->thumbnailSmall()->loaded())
|
|| _dataMedia->image(PhotoSize::Thumbnail))
|
||||||
? 1
|
? 1
|
||||||
: 0;
|
: 0;
|
||||||
const auto width = geometry.width();
|
const auto width = geometry.width();
|
||||||
|
@ -523,14 +572,14 @@ void Photo::validateGroupedCache(
|
||||||
{ width, height });
|
{ width, height });
|
||||||
const auto pixWidth = pixSize.width() * cIntRetinaFactor();
|
const auto pixWidth = pixSize.width() * cIntRetinaFactor();
|
||||||
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
|
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
|
||||||
const auto image = loaded
|
const auto image = _dataMedia->image(PhotoSize::Large)
|
||||||
? _data->large().get()
|
? _dataMedia->image(PhotoSize::Large)
|
||||||
: _data->thumbnail()->loaded()
|
: _dataMedia->image(PhotoSize::Thumbnail)
|
||||||
? _data->thumbnail().get()
|
? _dataMedia->image(PhotoSize::Thumbnail)
|
||||||
: _data->thumbnailSmall()->loaded()
|
: _dataMedia->image(PhotoSize::Small)
|
||||||
? _data->thumbnailSmall().get()
|
? _dataMedia->image(PhotoSize::Small)
|
||||||
: _data->thumbnailInline()
|
: _dataMedia->thumbnailInline()
|
||||||
? _data->thumbnailInline()
|
? _dataMedia->thumbnailInline()
|
||||||
: Image::BlankMedia().get();
|
: Image::BlankMedia().get();
|
||||||
|
|
||||||
*cacheKey = key;
|
*cacheKey = key;
|
||||||
|
@ -556,7 +605,8 @@ bool Photo::needsBubble() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Photo::isReadyForOpen() const {
|
bool Photo::isReadyForOpen() const {
|
||||||
return _data->loaded();
|
ensureDataMediaCreated();
|
||||||
|
return _dataMedia->loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Photo::parentTextUpdated() {
|
void Photo::parentTextUpdated() {
|
||||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "history/view/media/history_view_file.h"
|
#include "history/view/media/history_view_file.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class PhotoMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
class Photo : public File {
|
class Photo : public File {
|
||||||
|
@ -22,6 +26,7 @@ public:
|
||||||
not_null<PeerData*> chat,
|
not_null<PeerData*> chat,
|
||||||
not_null<PhotoData*> photo,
|
not_null<PhotoData*> photo,
|
||||||
int width);
|
int width);
|
||||||
|
~Photo();
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &clip, TextSelection selection, crl::time ms) const override;
|
void draw(Painter &p, const QRect &clip, TextSelection selection, crl::time ms) const override;
|
||||||
TextState textState(QPoint point, StateRequest request) const override;
|
TextState textState(QPoint point, StateRequest request) const override;
|
||||||
|
@ -75,6 +80,9 @@ public:
|
||||||
|
|
||||||
void parentTextUpdated() override;
|
void parentTextUpdated() override;
|
||||||
|
|
||||||
|
void checkHeavyPart() override;
|
||||||
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float64 dataProgress() const override;
|
float64 dataProgress() const override;
|
||||||
bool dataFinished() const override;
|
bool dataFinished() const override;
|
||||||
|
@ -83,6 +91,9 @@ protected:
|
||||||
private:
|
private:
|
||||||
void create(FullMsgId contextId, PeerData *chat = nullptr);
|
void create(FullMsgId contextId, PeerData *chat = nullptr);
|
||||||
|
|
||||||
|
void ensureDataMediaCreated() const;
|
||||||
|
void dataMediaCreated() const;
|
||||||
|
|
||||||
QSize countOptimalSize() override;
|
QSize countOptimalSize() override;
|
||||||
QSize countCurrentSize(int newWidth) override;
|
QSize countCurrentSize(int newWidth) override;
|
||||||
|
|
||||||
|
@ -98,6 +109,7 @@ private:
|
||||||
int _pixw = 1;
|
int _pixw = 1;
|
||||||
int _pixh = 1;
|
int _pixh = 1;
|
||||||
Ui::Text::String _caption;
|
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_media_types.h"
|
||||||
#include "data/data_web_page.h"
|
#include "data/data_web_page.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
@ -32,15 +33,17 @@ namespace {
|
||||||
constexpr auto kMaxOriginalEntryLines = 8192;
|
constexpr auto kMaxOriginalEntryLines = 8192;
|
||||||
|
|
||||||
int articleThumbWidth(not_null<PhotoData*> thumb, int height) {
|
int articleThumbWidth(not_null<PhotoData*> thumb, int height) {
|
||||||
auto w = thumb->thumbnail()->width();
|
const auto size = thumb->location(Data::PhotoSize::Thumbnail);
|
||||||
auto h = thumb->thumbnail()->height();
|
return size.height()
|
||||||
return qMax(qMin(height * w / h, height), 1);
|
? qMax(qMin(height * size.width() / size.height(), height), 1)
|
||||||
|
: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int articleThumbHeight(not_null<PhotoData*> thumb, int width) {
|
int articleThumbHeight(not_null<Data::PhotoMedia*> thumb, int width) {
|
||||||
return qMax(
|
const auto size = thumb->size(Data::PhotoSize::Thumbnail);
|
||||||
thumb->thumbnail()->height() * width / thumb->thumbnail()->width(),
|
return size.width()
|
||||||
1);
|
? std::max(size.height() * width / size.width(), 1)
|
||||||
|
: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Data::Media>> PrepareCollageMedia(
|
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 {
|
void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
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();
|
auto lineHeight = unitedLineHeight();
|
||||||
if (asArticle()) {
|
if (asArticle()) {
|
||||||
|
ensurePhotoMediaCreated();
|
||||||
|
|
||||||
const auto contextId = _parent->data()->fullId();
|
const auto contextId = _parent->data()->fullId();
|
||||||
_data->photo->loadThumbnail(contextId);
|
|
||||||
bool full = _data->photo->thumbnail()->loaded();
|
|
||||||
QPixmap pix;
|
QPixmap pix;
|
||||||
auto pw = qMax(_pixw, lineHeight);
|
auto pw = qMax(_pixw, lineHeight);
|
||||||
auto ph = _pixh;
|
auto ph = _pixh;
|
||||||
auto pixw = _pixw, pixh = articleThumbHeight(_data->photo, _pixw);
|
auto pixw = _pixw, pixh = articleThumbHeight(_photoMedia.get(), _pixw);
|
||||||
const auto maxw = style::ConvertScale(_data->photo->thumbnail()->width());
|
const auto maxsize = _photoMedia->size(Data::PhotoSize::Thumbnail);
|
||||||
const auto maxh = style::ConvertScale(_data->photo->thumbnail()->height());
|
const auto maxw = style::ConvertScale(maxsize.width());
|
||||||
|
const auto maxh = style::ConvertScale(maxsize.height());
|
||||||
if (pixw * ph != pixh * pw) {
|
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));
|
float64 coef = (pixw * ph > pixh * pw) ? qMin(ph / float64(pixh), maxh / float64(pixh)) : qMin(pw / float64(pixw), maxw / float64(pixw));
|
||||||
pixh = qRound(pixh * coef);
|
pixh = qRound(pixh * coef);
|
||||||
pixw = qRound(pixw * coef);
|
pixw = qRound(pixw * coef);
|
||||||
}
|
}
|
||||||
if (full) {
|
if (const auto thumbnail = _photoMedia->image(
|
||||||
pix = _data->photo->thumbnail()->pixSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
Data::PhotoSize::Thumbnail)) {
|
||||||
} else if (_data->photo->thumbnailSmall()->loaded()) {
|
pix = thumbnail->pixSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
||||||
pix = _data->photo->thumbnailSmall()->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
} else if (const auto small = _photoMedia->image(
|
||||||
} else if (const auto blurred = _data->photo->thumbnailInline()) {
|
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);
|
pix = blurred->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
||||||
}
|
}
|
||||||
p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix);
|
p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix);
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Media;
|
class Media;
|
||||||
|
class PhotoMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
@ -85,16 +86,8 @@ public:
|
||||||
return _attach.get();
|
return _attach.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkHeavyPart() override {
|
void checkHeavyPart() override;
|
||||||
if (_attach) {
|
void unloadHeavyPart() override;
|
||||||
_attach->checkHeavyPart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void unloadHeavyPart() override {
|
|
||||||
if (_attach) {
|
|
||||||
_attach->unloadHeavyPart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~WebPage();
|
~WebPage();
|
||||||
|
|
||||||
|
@ -103,6 +96,8 @@ private:
|
||||||
QSize countOptimalSize() override;
|
QSize countOptimalSize() override;
|
||||||
QSize countCurrentSize(int newWidth) override;
|
QSize countCurrentSize(int newWidth) override;
|
||||||
|
|
||||||
|
void ensurePhotoMediaCreated() const;
|
||||||
|
|
||||||
TextSelection toTitleSelection(TextSelection selection) const;
|
TextSelection toTitleSelection(TextSelection selection) const;
|
||||||
TextSelection fromTitleSelection(TextSelection selection) const;
|
TextSelection fromTitleSelection(TextSelection selection) const;
|
||||||
TextSelection toDescriptionSelection(TextSelection selection) const;
|
TextSelection toDescriptionSelection(TextSelection selection) const;
|
||||||
|
@ -119,6 +114,7 @@ private:
|
||||||
std::vector<std::unique_ptr<Data::Media>> _collage;
|
std::vector<std::unique_ptr<Data::Media>> _collage;
|
||||||
ClickHandlerPtr _openl;
|
ClickHandlerPtr _openl;
|
||||||
std::unique_ptr<Media> _attach;
|
std::unique_ptr<Media> _attach;
|
||||||
|
mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
|
|
||||||
bool _asArticle = false;
|
bool _asArticle = false;
|
||||||
int _dataVersion = -1;
|
int _dataVersion = -1;
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "styles/style_overview.h"
|
#include "styles/style_overview.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
@ -47,7 +48,9 @@ FileBase::FileBase(not_null<Context*> context, not_null<Result*> result)
|
||||||
: ItemBase(context, 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) {
|
: ItemBase(context, document) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,10 +90,16 @@ int FileBase::content_duration() const {
|
||||||
return getResultDuration();
|
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) {
|
if (hasDeleteButton) {
|
||||||
_delete = std::make_shared<DeleteSavedGifClickHandler>(document);
|
_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) {
|
: FileBase(context, result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,6 +464,12 @@ void Sticker::ensureDataMediaCreated(not_null<DocumentData*> document) const {
|
||||||
_dataMedia = document->createMediaView();
|
_dataMedia = document->createMediaView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sticker::unloadHeavyPart() {
|
||||||
|
_dataMedia = nullptr;
|
||||||
|
_lifetime.destroy();
|
||||||
|
_lottie = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||||
ensureDataMediaCreated(getShownDocument());
|
ensureDataMediaCreated(getShownDocument());
|
||||||
bool loaded = _dataMedia->loaded();
|
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) {
|
: ItemBase(context, result) {
|
||||||
|
Expects(getShownPhoto() != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Photo::initDimensions() {
|
void Photo::initDimensions() {
|
||||||
|
@ -611,15 +627,20 @@ TextState Photo::getState(
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Photo::unloadHeavyPart() {
|
||||||
|
getShownPhoto()->unload();
|
||||||
|
_photoMedia = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
PhotoData *Photo::getShownPhoto() const {
|
PhotoData *Photo::getShownPhoto() const {
|
||||||
if (PhotoData *result = getPhoto()) {
|
if (const auto result = getPhoto()) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return getResultPhoto();
|
return getResultPhoto();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Photo::countFrameSize() const {
|
QSize Photo::countFrameSize() const {
|
||||||
PhotoData *photo = getShownPhoto();
|
const auto photo = getShownPhoto();
|
||||||
int32 framew = photo->width(), frameh = photo->height(), height = st::inlineMediaHeight;
|
int32 framew = photo->width(), frameh = photo->height(), height = st::inlineMediaHeight;
|
||||||
if (framew * height > frameh * _width) {
|
if (framew * height > frameh * _width) {
|
||||||
if (framew < st::maxStickerSize || frameh > height) {
|
if (framew < st::maxStickerSize || frameh > height) {
|
||||||
|
@ -672,15 +693,20 @@ void Photo::validateThumbnail(
|
||||||
|
|
||||||
void Photo::prepareThumbnail(QSize size, QSize frame) const {
|
void Photo::prepareThumbnail(QSize size, QSize frame) const {
|
||||||
if (const auto photo = getShownPhoto()) {
|
if (const auto photo = getShownPhoto()) {
|
||||||
validateThumbnail(photo->thumbnail(), size, frame, true);
|
using PhotoSize = Data::PhotoSize;
|
||||||
validateThumbnail(photo->thumbnailSmall(), size, frame, false);
|
if (!_photoMedia) {
|
||||||
validateThumbnail(photo->thumbnailInline(), size, frame, false);
|
_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()) {
|
} else if (const auto thumbnail = getResultThumb()) {
|
||||||
validateThumbnail(thumbnail, size, frame, true);
|
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)
|
: FileBase(context, result)
|
||||||
, _link(getResultPreviewHandler())
|
, _link(getResultPreviewHandler())
|
||||||
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
|
, _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(
|
TextState Video::getState(
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const {
|
StateRequest request) const {
|
||||||
|
@ -951,6 +981,10 @@ void File::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void File::unloadHeavyPart() {
|
||||||
|
_documentMedia = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
File::~File() {
|
File::~File() {
|
||||||
unregDocumentItem(_document, this);
|
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)
|
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
|
||||||
, _description(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 {
|
void Contact::prepareThumbnail(int width, int height) const {
|
||||||
const auto thumb = getResultThumb();
|
const auto thumb = getResultThumb(); // #TODO optimize
|
||||||
if (!thumb) {
|
if (!thumb) {
|
||||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||||
_thumb = getResultContactAvatar(width, height);
|
_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())
|
, _url(getResultUrlHandler())
|
||||||
, _link(getResultPreviewHandler())
|
, _link(getResultPreviewHandler())
|
||||||
, _withThumb(withThumb)
|
, _withThumb(withThumb)
|
||||||
|
@ -1196,7 +1235,7 @@ void Article::paint(Painter &p, const QRect &clip, const PaintContext *context)
|
||||||
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
|
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
|
||||||
QRect rthumb(style::rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width));
|
QRect rthumb(style::rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width));
|
||||||
if (_thumb.isNull()) {
|
if (_thumb.isNull()) {
|
||||||
const auto thumb = getResultThumb();
|
const auto thumb = getResultThumb(); // #TODO optimize
|
||||||
if (!thumb && !_thumbLetter.isEmpty()) {
|
if (!thumb && !_thumbLetter.isEmpty()) {
|
||||||
int32 index = (_thumbLetter.at(0).unicode() % 4);
|
int32 index = (_thumbLetter.at(0).unicode() % 4);
|
||||||
style::color colors[] = {
|
style::color colors[] = {
|
||||||
|
@ -1261,7 +1300,7 @@ TextState Article::getState(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Article::prepareThumbnail(int width, int height) const {
|
void Article::prepareThumbnail(int width, int height) const {
|
||||||
const auto thumb = getResultThumb();
|
const auto thumb = getResultThumb(); // #TODO optimize
|
||||||
if (!thumb) {
|
if (!thumb) {
|
||||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||||
_thumb = getResultContactAvatar(width, height);
|
_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)
|
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
|
||||||
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
|
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
|
||||||
countFrameSize();
|
countFrameSize();
|
||||||
|
@ -1359,18 +1399,21 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
|
||||||
|
|
||||||
// Gif thumb
|
// Gif thumb
|
||||||
auto thumbDisplayed = false, radial = false;
|
auto thumbDisplayed = false, radial = false;
|
||||||
|
const auto photo = getResultPhoto();
|
||||||
const auto document = getResultDocument();
|
const auto document = getResultDocument();
|
||||||
if (document) {
|
if (document) {
|
||||||
ensureDataMediaCreated(document);
|
ensureDataMediaCreated(document);
|
||||||
|
} else if (photo) {
|
||||||
|
ensureDataMediaCreated(photo);
|
||||||
}
|
}
|
||||||
auto animatedThumb = document && document->isAnimation();
|
auto animatedThumb = document && document->isAnimation();
|
||||||
if (animatedThumb) {
|
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()) {
|
if (loaded && !_gif && !_gif.isBad()) {
|
||||||
auto that = const_cast<Game*>(this);
|
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);
|
that->clipCallback(notification);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1383,7 +1426,7 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!_radial->animating()) {
|
if (!_radial->animating()) {
|
||||||
_radial->start(_dataMedia->progress());
|
_radial->start(_documentMedia->progress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
radial = isRadialAnimation();
|
radial = isRadialAnimation();
|
||||||
|
@ -1445,22 +1488,33 @@ TextState Game::getState(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::prepareThumbnail(QSize size) const {
|
void Game::prepareThumbnail(QSize size) const {
|
||||||
if (const auto photo = getResultPhoto()) {
|
if (const auto document = getResultDocument()) {
|
||||||
validateThumbnail(photo->thumbnail(), size, true);
|
Assert(_documentMedia != nullptr);
|
||||||
validateThumbnail(photo->thumbnailInline(), size, false);
|
validateThumbnail(_documentMedia->thumbnail(), size, true);
|
||||||
} else if (const auto document = getResultDocument()) {
|
validateThumbnail(_documentMedia->thumbnailInline(), size, false);
|
||||||
Assert(_dataMedia != nullptr);
|
} else if (const auto photo = getResultPhoto()) {
|
||||||
validateThumbnail(_dataMedia->thumbnail(), size, true);
|
using Data::PhotoSize;
|
||||||
validateThumbnail(_dataMedia->thumbnailInline(), size, false);
|
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 {
|
void Game::ensureDataMediaCreated(not_null<DocumentData*> document) const {
|
||||||
if (_dataMedia) {
|
if (_documentMedia) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_dataMedia = document->createMediaView();
|
_documentMedia = document->createMediaView();
|
||||||
_dataMedia->thumbnailWanted(fileOrigin());
|
_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 {
|
void Game::validateThumbnail(Image *image, QSize size, bool good) const {
|
||||||
|
@ -1507,7 +1561,7 @@ bool Game::isRadialAnimation() const {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
ensureDataMediaCreated(getResultDocument());
|
ensureDataMediaCreated(getResultDocument());
|
||||||
if (_dataMedia->loaded()) {
|
if (_documentMedia->loaded()) {
|
||||||
_radial = nullptr;
|
_radial = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1520,22 +1574,28 @@ void Game::radialAnimationCallback(crl::time now) const {
|
||||||
ensureDataMediaCreated(document);
|
ensureDataMediaCreated(document);
|
||||||
const auto updated = [&] {
|
const auto updated = [&] {
|
||||||
return _radial->update(
|
return _radial->update(
|
||||||
_dataMedia->progress(),
|
_documentMedia->progress(),
|
||||||
!document->loading() || _dataMedia->loaded(),
|
!document->loading() || _documentMedia->loaded(),
|
||||||
now);
|
now);
|
||||||
}();
|
}();
|
||||||
if (!anim::Disabled() || updated) {
|
if (!anim::Disabled() || updated) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
if (!_radial->animating() && _dataMedia->loaded()) {
|
if (!_radial->animating() && _documentMedia->loaded()) {
|
||||||
_radial = nullptr;
|
_radial = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::unloadHeavyPart() {
|
void Game::unloadHeavyPart() {
|
||||||
_gif.reset();
|
_gif.reset();
|
||||||
getResultDocument()->unload();
|
if (const auto document = getResultDocument()) {
|
||||||
_dataMedia = nullptr;
|
document->unload();
|
||||||
|
_documentMedia = nullptr;
|
||||||
|
}
|
||||||
|
if (const auto photo = getResultPhoto()) {
|
||||||
|
photo->unload();
|
||||||
|
_photoMedia = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::clipCallback(Media::Clip::Notification notification) {
|
void Game::clipCallback(Media::Clip::Notification notification) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ class SinglePlayer;
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
class PhotoMedia;
|
||||||
class DocumentMedia;
|
class DocumentMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
@ -29,8 +30,9 @@ namespace internal {
|
||||||
class FileBase : public ItemBase {
|
class FileBase : public ItemBase {
|
||||||
public:
|
public:
|
||||||
FileBase(not_null<Context*> context, not_null<Result*> result);
|
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:
|
protected:
|
||||||
DocumentData *getShownDocument() const;
|
DocumentData *getShownDocument() const;
|
||||||
|
@ -54,10 +56,13 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Gif : public FileBase {
|
class Gif final : public FileBase {
|
||||||
public:
|
public:
|
||||||
Gif(not_null<Context*> context, Result *result);
|
Gif(not_null<Context*> context, not_null<Result*> result);
|
||||||
Gif(not_null<Context*> context, DocumentData *doc, bool hasDeleteButton);
|
Gif(
|
||||||
|
not_null<Context*> context,
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
bool hasDeleteButton);
|
||||||
|
|
||||||
void setPosition(int32 position) override;
|
void setPosition(int32 position) override;
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
@ -131,9 +136,9 @@ private:
|
||||||
|
|
||||||
class Photo : public ItemBase {
|
class Photo : public ItemBase {
|
||||||
public:
|
public:
|
||||||
Photo(not_null<Context*> context, Result *result);
|
Photo(not_null<Context*> context, not_null<Result*> result);
|
||||||
// Not used anywhere currently.
|
// Not used anywhere currently.
|
||||||
//Photo(not_null<Context*> context, PhotoData *photo);
|
//Photo(not_null<Context*> context, not_null<PhotoData*> photo);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
|
||||||
|
@ -149,6 +154,8 @@ public:
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const override;
|
StateRequest request) const override;
|
||||||
|
|
||||||
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PhotoData *getShownPhoto() const;
|
PhotoData *getShownPhoto() const;
|
||||||
|
|
||||||
|
@ -163,14 +170,16 @@ private:
|
||||||
QSize frame,
|
QSize frame,
|
||||||
bool good) const;
|
bool good) const;
|
||||||
|
|
||||||
|
mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sticker : public FileBase {
|
class Sticker : public FileBase {
|
||||||
public:
|
public:
|
||||||
Sticker(not_null<Context*> context, Result *result);
|
Sticker(not_null<Context*> context, not_null<Result*> result);
|
||||||
~Sticker();
|
~Sticker();
|
||||||
// Not used anywhere currently.
|
// Not used anywhere currently.
|
||||||
//Sticker(not_null<Context*> context, DocumentData *document);
|
//Sticker(not_null<Context*> context, not_null<DocumentData*> document);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
|
||||||
|
@ -190,6 +199,8 @@ public:
|
||||||
// ClickHandlerHost interface
|
// ClickHandlerHost interface
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
|
||||||
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
|
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
|
||||||
void setupLottie() const;
|
void setupLottie() const;
|
||||||
|
@ -210,7 +221,7 @@ private:
|
||||||
|
|
||||||
class Video : public FileBase {
|
class Video : public FileBase {
|
||||||
public:
|
public:
|
||||||
Video(not_null<Context*> context, Result *result);
|
Video(not_null<Context*> context, not_null<Result*> result);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
|
||||||
|
@ -219,6 +230,8 @@ public:
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const override;
|
StateRequest request) const override;
|
||||||
|
|
||||||
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClickHandlerPtr _link;
|
ClickHandlerPtr _link;
|
||||||
|
|
||||||
|
@ -262,6 +275,7 @@ private:
|
||||||
class File : public FileBase {
|
class File : public FileBase {
|
||||||
public:
|
public:
|
||||||
File(not_null<Context*> context, not_null<Result*> result);
|
File(not_null<Context*> context, not_null<Result*> result);
|
||||||
|
~File();
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
|
||||||
|
@ -273,7 +287,7 @@ public:
|
||||||
// ClickHandlerHost interface
|
// ClickHandlerHost interface
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
|
||||||
~File();
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void thumbAnimationCallback();
|
void thumbAnimationCallback();
|
||||||
|
@ -334,7 +348,7 @@ private:
|
||||||
|
|
||||||
class Contact : public ItemBase {
|
class Contact : public ItemBase {
|
||||||
public:
|
public:
|
||||||
Contact(not_null<Context*> context, Result *result);
|
Contact(not_null<Context*> context, not_null<Result*> result);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
|
||||||
|
@ -353,7 +367,7 @@ private:
|
||||||
|
|
||||||
class Article : public ItemBase {
|
class Article : public ItemBase {
|
||||||
public:
|
public:
|
||||||
Article(not_null<Context*> context, Result *result, bool withThumb);
|
Article(not_null<Context*> context, not_null<Result*> result, bool withThumb);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
int resizeGetHeight(int width) override;
|
int resizeGetHeight(int width) override;
|
||||||
|
@ -378,7 +392,7 @@ private:
|
||||||
|
|
||||||
class Game : public ItemBase {
|
class Game : public ItemBase {
|
||||||
public:
|
public:
|
||||||
Game(not_null<Context*> context, Result *result);
|
Game(not_null<Context*> context, not_null<Result*> result);
|
||||||
|
|
||||||
void setPosition(int32 position) override;
|
void setPosition(int32 position) override;
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
@ -391,6 +405,7 @@ public:
|
||||||
void unloadHeavyPart() override;
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ensureDataMediaCreated(not_null<PhotoData*> photo) const;
|
||||||
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
|
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
|
||||||
void countFrameSize();
|
void countFrameSize();
|
||||||
|
|
||||||
|
@ -403,7 +418,8 @@ private:
|
||||||
void clipCallback(Media::Clip::Notification notification);
|
void clipCallback(Media::Clip::Notification notification);
|
||||||
|
|
||||||
Media::Clip::ReaderPointer _gif;
|
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 QPixmap _thumb;
|
||||||
mutable bool _thumbGood = false;
|
mutable bool _thumbGood = false;
|
||||||
mutable std::unique_ptr<Ui::RadialAnimation> _radial;
|
mutable std::unique_ptr<Ui::RadialAnimation> _radial;
|
||||||
|
|
|
@ -41,7 +41,7 @@ Result *ItemBase::getResult() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentData *ItemBase::getDocument() const {
|
DocumentData *ItemBase::getDocument() const {
|
||||||
return _doc;
|
return _document;
|
||||||
}
|
}
|
||||||
|
|
||||||
PhotoData *ItemBase::getPhoto() const {
|
PhotoData *ItemBase::getPhoto() const {
|
||||||
|
@ -49,8 +49,8 @@ PhotoData *ItemBase::getPhoto() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentData *ItemBase::getPreviewDocument() const {
|
DocumentData *ItemBase::getPreviewDocument() const {
|
||||||
if (_doc) {
|
if (_document) {
|
||||||
return _doc;
|
return _document;
|
||||||
} else if (_result) {
|
} else if (_result) {
|
||||||
return _result->_document;
|
return _result->_document;
|
||||||
}
|
}
|
||||||
|
@ -60,8 +60,7 @@ DocumentData *ItemBase::getPreviewDocument() const {
|
||||||
PhotoData *ItemBase::getPreviewPhoto() const {
|
PhotoData *ItemBase::getPreviewPhoto() const {
|
||||||
if (_photo) {
|
if (_photo) {
|
||||||
return _photo;
|
return _photo;
|
||||||
}
|
} else if (_result) {
|
||||||
if (_result) {
|
|
||||||
return _result->_photo;
|
return _result->_photo;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -71,16 +70,16 @@ void ItemBase::preload() const {
|
||||||
const auto origin = fileOrigin();
|
const auto origin = fileOrigin();
|
||||||
if (_result) {
|
if (_result) {
|
||||||
if (_result->_photo) {
|
if (_result->_photo) {
|
||||||
_result->_photo->loadThumbnail(origin);
|
_result->_photo->load(Data::PhotoSize::Thumbnail, origin);
|
||||||
} else if (_result->_document) {
|
} else if (_result->_document) {
|
||||||
_result->_document->loadThumbnail(origin);
|
_result->_document->loadThumbnail(origin);
|
||||||
} else if (!_result->_thumb->isNull()) {
|
} else if (!_result->_thumb->isNull()) {
|
||||||
_result->_thumb->load(origin);
|
_result->_thumb->load(origin);
|
||||||
}
|
}
|
||||||
} else if (_doc) {
|
} else if (_document) {
|
||||||
_doc->loadThumbnail(origin);
|
_document->loadThumbnail(origin);
|
||||||
} else if (_photo) {
|
} 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;
|
using Type = Result::Type;
|
||||||
|
|
||||||
switch (result->_type) {
|
switch (result->_type) {
|
||||||
|
@ -126,7 +128,9 @@ std::unique_ptr<ItemBase> ItemBase::createLayout(not_null<Context*> context, Res
|
||||||
return nullptr;
|
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);
|
return std::make_unique<internal::Gif>(context, document, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,9 +144,7 @@ PhotoData *ItemBase::getResultPhoto() const {
|
||||||
|
|
||||||
Image *ItemBase::getResultThumb() const {
|
Image *ItemBase::getResultThumb() const {
|
||||||
if (_result) {
|
if (_result) {
|
||||||
if (_result->_photo) {
|
if (!_result->_thumb->isNull()) {
|
||||||
return _result->_photo->thumbnail();
|
|
||||||
} else if (!_result->_thumb->isNull()) {
|
|
||||||
return _result->_thumb.get();
|
return _result->_thumb.get();
|
||||||
} else if (!_result->_locationThumb->isNull()) {
|
} else if (!_result->_locationThumb->isNull()) {
|
||||||
return _result->_locationThumb.get();
|
return _result->_locationThumb.get();
|
||||||
|
|
|
@ -50,8 +50,8 @@ public:
|
||||||
: _result(result)
|
: _result(result)
|
||||||
, _context(context) {
|
, _context(context) {
|
||||||
}
|
}
|
||||||
ItemBase(not_null<Context*> context, DocumentData *doc)
|
ItemBase(not_null<Context*> context, not_null<DocumentData*> document)
|
||||||
: _doc(doc)
|
: _document(document)
|
||||||
, _context(context) {
|
, _context(context) {
|
||||||
}
|
}
|
||||||
// Not used anywhere currently.
|
// Not used anywhere currently.
|
||||||
|
@ -94,8 +94,13 @@ public:
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<ItemBase> createLayout(not_null<Context*> context, Result *result, bool forceThumb);
|
static std::unique_ptr<ItemBase> createLayout(
|
||||||
static std::unique_ptr<ItemBase> createLayoutGif(not_null<Context*> context, DocumentData *document);
|
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:
|
protected:
|
||||||
DocumentData *getResultDocument() const;
|
DocumentData *getResultDocument() const;
|
||||||
|
@ -114,7 +119,7 @@ protected:
|
||||||
Data::FileOrigin fileOrigin() const;
|
Data::FileOrigin fileOrigin() const;
|
||||||
|
|
||||||
Result *_result = nullptr;
|
Result *_result = nullptr;
|
||||||
DocumentData *_doc = nullptr;
|
DocumentData *_document = nullptr;
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
|
|
||||||
ClickHandlerPtr _send = ClickHandlerPtr{ new SendClickHandler() };
|
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_document.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
#include "inline_bots/inline_bot_send_data.h"
|
#include "inline_bots/inline_bot_send_data.h"
|
||||||
|
@ -105,7 +106,9 @@ std::unique_ptr<Result> Result::create(
|
||||||
if (result->_type == Type::Photo) {
|
if (result->_type == Type::Photo) {
|
||||||
result->_photo = Auth().data().photoFromWeb(
|
result->_photo = Auth().data().photoFromWeb(
|
||||||
*content,
|
*content,
|
||||||
result->_thumb,
|
(imageThumb
|
||||||
|
? Images::FromWebDocument(*r.vthumb())
|
||||||
|
: ImageLocation()),
|
||||||
true);
|
true);
|
||||||
} else {
|
} else {
|
||||||
result->_document = Auth().data().documentFromWeb(
|
result->_document = Auth().data().documentFromWeb(
|
||||||
|
@ -276,10 +279,13 @@ std::unique_ptr<Result> Result::create(
|
||||||
|
|
||||||
bool Result::onChoose(Layout::ItemBase *layout) {
|
bool Result::onChoose(Layout::ItemBase *layout) {
|
||||||
if (_photo && _type == Type::Photo) {
|
if (_photo && _type == Type::Photo) {
|
||||||
if (_photo->thumbnail()->loaded()) {
|
const auto media = _photo->activeMediaView();
|
||||||
|
if (!media || media->image(Data::PhotoSize::Thumbnail)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (!_photo->thumbnail()->loading()) {
|
} else if (!_photo->loading(Data::PhotoSize::Thumbnail)) {
|
||||||
_photo->thumbnail()->loadEvenCancelled(Data::FileOrigin());
|
_photo->load(
|
||||||
|
Data::PhotoSize::Thumbnail,
|
||||||
|
Data::FileOrigin());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_shared_media.h"
|
#include "data/data_shared_media.h"
|
||||||
#include "data/data_user_photos.h"
|
#include "data/data_user_photos.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
|
@ -129,9 +130,10 @@ public:
|
||||||
Dying,
|
Dying,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Thumb(Key key, Fn<void()> handler);
|
||||||
Thumb(
|
Thumb(
|
||||||
Key key,
|
Key key,
|
||||||
Image *image,
|
not_null<PhotoData*> photo,
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
Fn<void()> handler);
|
Fn<void()> handler);
|
||||||
Thumb(
|
Thumb(
|
||||||
|
@ -165,6 +167,7 @@ private:
|
||||||
ClickHandlerPtr _link;
|
ClickHandlerPtr _link;
|
||||||
const Key _key;
|
const Key _key;
|
||||||
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
Image *_image = nullptr;
|
Image *_image = nullptr;
|
||||||
Data::FileOrigin _origin;
|
Data::FileOrigin _origin;
|
||||||
State _state = State::Alive;
|
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(
|
GroupThumbs::Thumb::Thumb(
|
||||||
Key key,
|
Key key,
|
||||||
Image *image,
|
not_null<PhotoData*> photo,
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
Fn<void()> handler)
|
Fn<void()> handler)
|
||||||
: _key(key)
|
: _key(key)
|
||||||
, _image(image)
|
, _photoMedia(photo->createMediaView())
|
||||||
, _origin(origin) {
|
, _origin(origin) {
|
||||||
_link = std::make_shared<LambdaClickHandler>(std::move(handler));
|
_link = std::make_shared<LambdaClickHandler>(std::move(handler));
|
||||||
_fullWidth = std::min(
|
_fullWidth = std::min(
|
||||||
wantedPixSize().width(),
|
wantedPixSize().width(),
|
||||||
st::mediaviewGroupWidthMax);
|
st::mediaviewGroupWidthMax);
|
||||||
|
_photoMedia->wanted(Data::PhotoSize::Thumbnail, origin);
|
||||||
validateImage();
|
validateImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,8 +231,12 @@ QSize GroupThumbs::Thumb::wantedPixSize() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupThumbs::Thumb::validateImage() {
|
void GroupThumbs::Thumb::validateImage() {
|
||||||
if (!_image && _documentMedia) {
|
if (!_image) {
|
||||||
_image = _documentMedia->thumbnail();
|
if (_photoMedia) {
|
||||||
|
_image = _photoMedia->image(Data::PhotoSize::Thumbnail);
|
||||||
|
} else if (_documentMedia) {
|
||||||
|
_image = _documentMedia->thumbnail();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!_full.isNull() || !_image) {
|
if (!_full.isNull() || !_image) {
|
||||||
return;
|
return;
|
||||||
|
@ -543,12 +560,12 @@ auto GroupThumbs::createThumb(Key key)
|
||||||
-> std::unique_ptr<Thumb> {
|
-> std::unique_ptr<Thumb> {
|
||||||
if (const auto photoId = base::get_if<PhotoId>(&key)) {
|
if (const auto photoId = base::get_if<PhotoId>(&key)) {
|
||||||
const auto photo = Auth().data().photo(*photoId);
|
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)) {
|
} else if (const auto msgId = base::get_if<FullMsgId>(&key)) {
|
||||||
if (const auto item = Auth().data().message(*msgId)) {
|
if (const auto item = Auth().data().message(*msgId)) {
|
||||||
if (const auto media = item->media()) {
|
if (const auto media = item->media()) {
|
||||||
if (const auto photo = media->photo()) {
|
if (const auto photo = media->photo()) {
|
||||||
return createThumb(key, photo->thumbnail());
|
return createThumb(key, photo);
|
||||||
} else if (const auto document = media->document()) {
|
} else if (const auto document = media->document()) {
|
||||||
return createThumb(key, document);
|
return createThumb(key, document);
|
||||||
}
|
}
|
||||||
|
@ -583,18 +600,29 @@ auto GroupThumbs::createThumb(
|
||||||
}
|
}
|
||||||
const auto &item = collage.items[index];
|
const auto &item = collage.items[index];
|
||||||
if (const auto photo = base::get_if<PhotoData*>(&item)) {
|
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)) {
|
} else if (const auto document = base::get_if<DocumentData*>(&item)) {
|
||||||
return createThumb(key, (*document));
|
return createThumb(key, (*document));
|
||||||
}
|
}
|
||||||
return createThumb(key, nullptr);
|
return createThumb(key, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GroupThumbs::createThumb(Key key, Image *image)
|
auto GroupThumbs::createThumb(Key key, std::nullptr_t)
|
||||||
-> std::unique_ptr<Thumb> {
|
-> std::unique_ptr<Thumb> {
|
||||||
const auto weak = base::make_weak(this);
|
const auto weak = base::make_weak(this);
|
||||||
const auto origin = ComputeFileOrigin(key, _context);
|
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()) {
|
if (const auto strong = weak.get()) {
|
||||||
strong->_activateStream.fire_copy(key);
|
strong->_activateStream.fire_copy(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,10 +100,11 @@ private:
|
||||||
Key key,
|
Key key,
|
||||||
const WebPageCollage &collage,
|
const WebPageCollage &collage,
|
||||||
int index);
|
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(
|
std::unique_ptr<Thumb> createThumb(
|
||||||
Key key,
|
Key key,
|
||||||
not_null<DocumentData*> document);
|
not_null<DocumentData*> document);
|
||||||
|
std::unique_ptr<Thumb> createThumb(Key key, std::nullptr_t);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void countUpdatedRect();
|
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 "data/data_cloud_themes.h" // Data::CloudTheme.
|
||||||
#include "media/view/media_view_playback_controls.h"
|
#include "media/view/media_view_playback_controls.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class PhotoMedia;
|
||||||
|
class DocumentMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
class LinkButton;
|
class LinkButton;
|
||||||
|
@ -189,6 +194,9 @@ private:
|
||||||
void playbackPauseMusic();
|
void playbackPauseMusic();
|
||||||
void switchToPip();
|
void switchToPip();
|
||||||
|
|
||||||
|
void assignMediaPointer(DocumentData *document);
|
||||||
|
void assignMediaPointer(not_null<PhotoData*> photo);
|
||||||
|
|
||||||
void updateOver(QPoint mpos);
|
void updateOver(QPoint mpos);
|
||||||
void moveToScreen(bool force = false);
|
void moveToScreen(bool force = false);
|
||||||
bool moveToNext(int delta);
|
bool moveToNext(int delta);
|
||||||
|
@ -347,9 +355,11 @@ private:
|
||||||
QBrush _transparentBrush;
|
QBrush _transparentBrush;
|
||||||
|
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
DocumentData *_doc = nullptr;
|
DocumentData *_document = nullptr;
|
||||||
std::shared_ptr<Data::DocumentMedia> _docMedia;
|
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
base::flat_set<std::shared_ptr<Data::DocumentMedia>> _preloadMedias;
|
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;
|
int _rotation = 0;
|
||||||
std::unique_ptr<SharedMedia> _sharedMedia;
|
std::unique_ptr<SharedMedia> _sharedMedia;
|
||||||
std::optional<SharedMediaWithLastSlice> _sharedMediaData;
|
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_media_types.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "styles/style_overview.h"
|
#include "styles/style_overview.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
@ -297,8 +298,8 @@ Photo::Photo(
|
||||||
: ItemBase(delegate, parent)
|
: ItemBase(delegate, parent)
|
||||||
, _data(photo)
|
, _data(photo)
|
||||||
, _link(std::make_shared<PhotoOpenClickHandler>(photo, parent->fullId())) {
|
, _link(std::make_shared<PhotoOpenClickHandler>(photo, parent->fullId())) {
|
||||||
if (!_data->thumbnailInline()) {
|
if (_data->inlineThumbnailBytes().isEmpty()) {
|
||||||
_data->loadThumbnailSmall(parent->fullId());
|
_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) {
|
void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
|
||||||
bool good = _data->loaded(), selected = (selection == FullSelection);
|
const auto selected = (selection == FullSelection);
|
||||||
if (!good) {
|
const auto widthChanged = _pix.width() != _width * cIntRetinaFactor();
|
||||||
_data->thumbnail()->automaticLoad(parent()->fullId(), parent());
|
if (!_goodLoaded || widthChanged) {
|
||||||
good = _data->thumbnail()->loaded();
|
ensureDataMediaCreated();
|
||||||
}
|
const auto good = _dataMedia->loaded()
|
||||||
if ((good && !_goodLoaded) || _pix.width() != _width * cIntRetinaFactor()) {
|
|| (_dataMedia->image(Data::PhotoSize::Thumbnail) != nullptr);
|
||||||
_goodLoaded = good;
|
if ((good && !_goodLoaded) || widthChanged) {
|
||||||
_pix = QPixmap();
|
_goodLoaded = good;
|
||||||
if (_goodLoaded) {
|
_pix = QPixmap();
|
||||||
setPixFrom(_data->loaded()
|
if (_goodLoaded) {
|
||||||
? _data->large()
|
setPixFrom(_dataMedia->image(Data::PhotoSize::Large)
|
||||||
: _data->thumbnail());
|
? _dataMedia->image(Data::PhotoSize::Large)
|
||||||
} else if (_data->thumbnailSmall()->loaded()) {
|
: _dataMedia->image(Data::PhotoSize::Thumbnail));
|
||||||
setPixFrom(_data->thumbnailSmall());
|
} else if (const auto small = _dataMedia->image(
|
||||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
Data::PhotoSize::Small)) {
|
||||||
blurred->load({});
|
setPixFrom(small);
|
||||||
if (blurred->loaded()) {
|
} else if (const auto blurred = _dataMedia->thumbnailInline()) {
|
||||||
setPixFrom(blurred);
|
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
|
// 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.
|
// won't get a blank image in the media viewer when the photo is opened.
|
||||||
if (_data->thumbnailInline() != nullptr) {
|
if (!_data->inlineThumbnailBytes().isEmpty()) {
|
||||||
_data->unload();
|
_dataMedia = nullptr;
|
||||||
|
delegate()->unregisterHeavyItem(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_pix = App::pixmapFromImageInPlace(std::move(img));
|
_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(
|
TextState Photo::getState(
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const {
|
StateRequest request) const {
|
||||||
|
@ -1460,12 +1476,7 @@ Link::Link(
|
||||||
}
|
}
|
||||||
int32 tw = 0, th = 0;
|
int32 tw = 0, th = 0;
|
||||||
if (_page && _page->photo) {
|
if (_page && _page->photo) {
|
||||||
if (!_page->photo->loaded()
|
_page->photo->load(Data::PhotoSize::Small, parent->fullId());
|
||||||
&& !_page->photo->thumbnail()->loaded()
|
|
||||||
&& !_page->photo->thumbnailSmall()->loaded()) {
|
|
||||||
_page->photo->loadThumbnailSmall(parent->fullId());
|
|
||||||
}
|
|
||||||
|
|
||||||
tw = style::ConvertScale(_page->photo->width());
|
tw = style::ConvertScale(_page->photo->width());
|
||||||
th = style::ConvertScale(_page->photo->height());
|
th = style::ConvertScale(_page->photo->height());
|
||||||
} else if (_page && _page->document && _page->document->hasThumbnail()) {
|
} else if (_page && _page->document && _page->document->hasThumbnail()) {
|
||||||
|
@ -1609,17 +1620,21 @@ void Link::validateThumbnail() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_page && _page->photo) {
|
if (_page && _page->photo) {
|
||||||
if (_page->photo->thumbnail()->loaded()) {
|
using Data::PhotoSize;
|
||||||
_thumbnail = _page->photo->thumbnail()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
ensurePhotoMediaCreated();
|
||||||
} else if (_page->photo->loaded()) {
|
if (const auto thumbnail = _photoMedia->image(PhotoSize::Thumbnail)) {
|
||||||
_thumbnail = _page->photo->large()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
_thumbnail = thumbnail->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||||
} else if (_page->photo->thumbnailSmall()->loaded()) {
|
} else if (const auto large = _photoMedia->image(PhotoSize::Large)) {
|
||||||
_thumbnail = _page->photo->thumbnailSmall()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
_thumbnail = large->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||||
} else if (const auto blurred = _page->photo->thumbnailInline()) {
|
} 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);
|
_thumbnail = blurred->pixBlurredSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_photoMedia = nullptr;
|
||||||
|
delegate()->unregisterHeavyItem(this);
|
||||||
} else if (_page && _page->document && _page->document->hasThumbnail()) {
|
} else if (_page && _page->document && _page->document->hasThumbnail()) {
|
||||||
ensureDocumentMediaCreated();
|
ensureDocumentMediaCreated();
|
||||||
if (const auto thumbnail = _documentMedia->thumbnail()) {
|
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() {
|
void Link::ensureDocumentMediaCreated() {
|
||||||
if (_documentMedia) {
|
if (_documentMedia) {
|
||||||
return;
|
return;
|
||||||
|
@ -1674,6 +1698,7 @@ void Link::ensureDocumentMediaCreated() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Link::clearHeavyPart() {
|
void Link::clearHeavyPart() {
|
||||||
|
_photoMedia = nullptr;
|
||||||
_documentMedia = nullptr;
|
_documentMedia = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct RoundCheckbox;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Media;
|
class Media;
|
||||||
|
class PhotoMedia;
|
||||||
class DocumentMedia;
|
class DocumentMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
@ -184,10 +185,14 @@ public:
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const override;
|
StateRequest request) const override;
|
||||||
|
|
||||||
|
void clearHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ensureDataMediaCreated() const;
|
||||||
void setPixFrom(not_null<Image*> image);
|
void setPixFrom(not_null<Image*> image);
|
||||||
|
|
||||||
not_null<PhotoData*> _data;
|
const not_null<PhotoData*> _data;
|
||||||
|
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
|
||||||
ClickHandlerPtr _link;
|
ClickHandlerPtr _link;
|
||||||
|
|
||||||
QPixmap _pix;
|
QPixmap _pix;
|
||||||
|
@ -222,7 +227,7 @@ private:
|
||||||
void ensureDataMediaCreated() const;
|
void ensureDataMediaCreated() const;
|
||||||
void updateStatusText();
|
void updateStatusText();
|
||||||
|
|
||||||
not_null<DocumentData*> _data;
|
const not_null<DocumentData*> _data;
|
||||||
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||||
StatusText _status;
|
StatusText _status;
|
||||||
|
|
||||||
|
@ -346,6 +351,7 @@ protected:
|
||||||
const style::RoundCheckbox &checkboxStyle() const override;
|
const style::RoundCheckbox &checkboxStyle() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ensurePhotoMediaCreated();
|
||||||
void ensureDocumentMediaCreated();
|
void ensureDocumentMediaCreated();
|
||||||
void validateThumbnail();
|
void validateThumbnail();
|
||||||
|
|
||||||
|
@ -354,6 +360,7 @@ private:
|
||||||
QString _title, _letter;
|
QString _title, _letter;
|
||||||
int _titlew = 0;
|
int _titlew = 0;
|
||||||
WebPageData *_page = nullptr;
|
WebPageData *_page = nullptr;
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
||||||
int _pixw = 0;
|
int _pixw = 0;
|
||||||
int _pixh = 0;
|
int _pixh = 0;
|
||||||
|
|
|
@ -66,29 +66,30 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
|
||||||
bool finished() const {
|
[[nodiscard]] bool finished() const {
|
||||||
return _finished;
|
return _finished;
|
||||||
}
|
}
|
||||||
void finishWithBytes(const QByteArray &data);
|
void finishWithBytes(const QByteArray &data);
|
||||||
bool cancelled() const {
|
[[nodiscard]] bool cancelled() const {
|
||||||
return _cancelled;
|
return _cancelled;
|
||||||
}
|
}
|
||||||
const QByteArray &bytes() const {
|
[[nodiscard]] const QByteArray &bytes() const {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
virtual uint64 objId() const {
|
[[nodiscard]] virtual uint64 objId() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
QByteArray imageFormat(const QSize &shrinkBox = QSize()) const;
|
[[nodiscard]] QByteArray imageFormat(
|
||||||
QImage imageData(const QSize &shrinkBox = QSize()) const;
|
const QSize &shrinkBox = QSize()) const;
|
||||||
QString fileName() const {
|
[[nodiscard]] QImage imageData(const QSize &shrinkBox = QSize()) const;
|
||||||
|
[[nodiscard]] QString fileName() const {
|
||||||
return _filename;
|
return _filename;
|
||||||
}
|
}
|
||||||
// Used in MainWidget::documentLoadFailed.
|
// Used in MainWidget::documentLoadFailed.
|
||||||
[[nodiscard]] virtual Data::FileOrigin fileOrigin() const;
|
[[nodiscard]] virtual Data::FileOrigin fileOrigin() const;
|
||||||
float64 currentProgress() const;
|
[[nodiscard]] float64 currentProgress() const;
|
||||||
virtual int currentOffset() const;
|
[[nodiscard]] virtual int currentOffset() const;
|
||||||
int fullSize() const;
|
[[nodiscard]] int fullSize() const;
|
||||||
|
|
||||||
bool setFileName(const QString &filename); // set filename for loaders to cache
|
bool setFileName(const QString &filename); // set filename for loaders to cache
|
||||||
void permitLoadFromCloud();
|
void permitLoadFromCloud();
|
||||||
|
@ -96,10 +97,10 @@ public:
|
||||||
void start();
|
void start();
|
||||||
void cancel();
|
void cancel();
|
||||||
|
|
||||||
bool loadingLocal() const {
|
[[nodiscard]] bool loadingLocal() const {
|
||||||
return (_localStatus == LocalStatus::Loading);
|
return (_localStatus == LocalStatus::Loading);
|
||||||
}
|
}
|
||||||
bool autoLoading() const {
|
[[nodiscard]] bool autoLoading() const {
|
||||||
return _autoLoading;
|
return _autoLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +113,7 @@ public:
|
||||||
return _updates.events();
|
return _updates.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::lifetime &lifetime() {
|
[[nodiscard]] rpl::lifetime &lifetime() {
|
||||||
return _lifetime;
|
return _lifetime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -946,14 +946,6 @@ QImage Image::original() const {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) {
|
|
||||||
if (!loaded()) {
|
|
||||||
_source->automaticLoad(origin, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Image::load(Data::FileOrigin origin) {
|
void Image::load(Data::FileOrigin origin) {
|
||||||
if (!loaded()) {
|
if (!loaded()) {
|
||||||
_source->load(origin);
|
_source->load(origin);
|
||||||
|
|
|
@ -67,11 +67,6 @@ public:
|
||||||
virtual QImage takeLoaded() = 0;
|
virtual QImage takeLoaded() = 0;
|
||||||
virtual void unload() = 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 loading() = 0;
|
||||||
virtual bool displayLoading() = 0;
|
virtual bool displayLoading() = 0;
|
||||||
virtual void cancel() = 0;
|
virtual void cancel() = 0;
|
||||||
|
@ -178,10 +173,6 @@ public:
|
||||||
int32 w,
|
int32 w,
|
||||||
int32 h = 0) const;
|
int32 h = 0) const;
|
||||||
|
|
||||||
void automaticLoad(Data::FileOrigin origin, const HistoryItem *item);
|
|
||||||
void automaticLoadSettingsChanged() {
|
|
||||||
_source->automaticLoadSettingsChanged();
|
|
||||||
}
|
|
||||||
bool loading() const {
|
bool loading() const {
|
||||||
return _source->loading();
|
return _source->loading();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,65 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Images {
|
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(
|
ImageWithLocation FromPhotoSize(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPDdocument &document,
|
const MTPDdocument &document,
|
||||||
|
|
|
@ -15,6 +15,10 @@ class Session;
|
||||||
|
|
||||||
namespace Images {
|
namespace Images {
|
||||||
|
|
||||||
|
[[nodiscard]] ImageWithLocation FromPhotoSize(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const MTPDphoto &photo,
|
||||||
|
const MTPPhotoSize &size);
|
||||||
[[nodiscard]] ImageWithLocation FromPhotoSize(
|
[[nodiscard]] ImageWithLocation FromPhotoSize(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPDdocument &document,
|
const MTPDdocument &document,
|
||||||
|
|
|
@ -57,14 +57,6 @@ void ImageSource::unload() {
|
||||||
_data = QImage();
|
_data = QImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageSource::automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageSource::automaticLoadSettingsChanged() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImageSource::loading() {
|
bool ImageSource::loading() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -186,14 +178,6 @@ void LocalFileSource::unload() {
|
||||||
_data = QImage();
|
_data = QImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalFileSource::automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void LocalFileSource::automaticLoadSettingsChanged() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalFileSource::loading() {
|
bool LocalFileSource::loading() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -344,36 +328,6 @@ bool RemoteSource::loading() {
|
||||||
return (_loader != nullptr);
|
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) {
|
void RemoteSource::load(Data::FileOrigin origin) {
|
||||||
if (!_loader) {
|
if (!_loader) {
|
||||||
_loader = createLoader(origin, LoadFromCloudOrLocal, false);
|
_loader = createLoader(origin, LoadFromCloudOrLocal, false);
|
||||||
|
@ -645,33 +599,33 @@ void DelayedStorageSource::performDelayedLoad(Data::FileOrigin origin) {
|
||||||
loadLocal();
|
loadLocal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
void DelayedStorageSource::automaticLoad(
|
//void DelayedStorageSource::automaticLoad(
|
||||||
Data::FileOrigin origin,
|
// Data::FileOrigin origin,
|
||||||
const HistoryItem *item) {
|
// const HistoryItem *item) {
|
||||||
if (_location.valid()) {
|
// if (_location.valid()) {
|
||||||
StorageSource::automaticLoad(origin, item);
|
// StorageSource::automaticLoad(origin, item);
|
||||||
return;
|
// return;
|
||||||
} else if (_loadCancelled || !item) {
|
// } else if (_loadCancelled || !item) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
const auto loadFromCloud = Data::AutoDownload::Should(
|
// const auto loadFromCloud = Data::AutoDownload::Should(
|
||||||
Auth().settings().autoDownload(),
|
// Auth().settings().autoDownload(),
|
||||||
item->history()->peer,
|
// item->history()->peer,
|
||||||
this);
|
// this);
|
||||||
|
//
|
||||||
if (_loadRequested) {
|
// if (_loadRequested) {
|
||||||
if (loadFromCloud) _loadFromCloud = loadFromCloud;
|
// if (loadFromCloud) _loadFromCloud = loadFromCloud;
|
||||||
} else {
|
// } else {
|
||||||
_loadFromCloud = loadFromCloud;
|
// _loadFromCloud = loadFromCloud;
|
||||||
_loadRequested = true;
|
// _loadRequested = true;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
void DelayedStorageSource::automaticLoadSettingsChanged() {
|
//void DelayedStorageSource::automaticLoadSettingsChanged() {
|
||||||
if (_loadCancelled) _loadCancelled = false;
|
// if (_loadCancelled) _loadCancelled = false;
|
||||||
StorageSource::automaticLoadSettingsChanged();
|
// StorageSource::automaticLoadSettingsChanged();
|
||||||
}
|
//}
|
||||||
|
|
||||||
void DelayedStorageSource::load(Data::FileOrigin origin) {
|
void DelayedStorageSource::load(Data::FileOrigin origin) {
|
||||||
if (_location.valid()) {
|
if (_location.valid()) {
|
||||||
|
|
|
@ -20,11 +20,6 @@ public:
|
||||||
QImage takeLoaded() override;
|
QImage takeLoaded() override;
|
||||||
void unload() override;
|
void unload() override;
|
||||||
|
|
||||||
void automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) override;
|
|
||||||
void automaticLoadSettingsChanged() override;
|
|
||||||
|
|
||||||
bool loading() override;
|
bool loading() override;
|
||||||
bool displayLoading() override;
|
bool displayLoading() override;
|
||||||
void cancel() override;
|
void cancel() override;
|
||||||
|
@ -69,11 +64,6 @@ public:
|
||||||
QImage takeLoaded() override;
|
QImage takeLoaded() override;
|
||||||
void unload() override;
|
void unload() override;
|
||||||
|
|
||||||
void automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) override;
|
|
||||||
void automaticLoadSettingsChanged() override;
|
|
||||||
|
|
||||||
bool loading() override;
|
bool loading() override;
|
||||||
bool displayLoading() override;
|
bool displayLoading() override;
|
||||||
void cancel() override;
|
void cancel() override;
|
||||||
|
@ -115,11 +105,6 @@ public:
|
||||||
QImage takeLoaded() override;
|
QImage takeLoaded() override;
|
||||||
void unload() override;
|
void unload() override;
|
||||||
|
|
||||||
void automaticLoad(
|
|
||||||
Data::FileOrigin origin,
|
|
||||||
const HistoryItem *item) override;
|
|
||||||
void automaticLoadSettingsChanged() override;
|
|
||||||
|
|
||||||
bool loading() override;
|
bool loading() override;
|
||||||
bool displayLoading() override;
|
bool displayLoading() override;
|
||||||
void cancel() override;
|
void cancel() override;
|
||||||
|
@ -256,11 +241,6 @@ public:
|
||||||
bool isDelayedStorageImage() const override;
|
bool isDelayedStorageImage() const override;
|
||||||
void performDelayedLoad(Data::FileOrigin origin) 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 {
|
bool loading() override {
|
||||||
return _location.valid()
|
return _location.valid()
|
||||||
? StorageSource::loading()
|
? StorageSource::loading()
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "window/window_media_preview.h"
|
#include "window/window_media_preview.h"
|
||||||
|
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
|
@ -114,6 +115,7 @@ void MediaPreviewWidget::showPreview(
|
||||||
startShow();
|
startShow();
|
||||||
_origin = origin;
|
_origin = origin;
|
||||||
_photo = nullptr;
|
_photo = nullptr;
|
||||||
|
_photoMedia = nullptr;
|
||||||
_document = document;
|
_document = document;
|
||||||
_documentMedia = _document->createMediaView();
|
_documentMedia = _document->createMediaView();
|
||||||
_documentMedia->thumbnailWanted(_origin);
|
_documentMedia->thumbnailWanted(_origin);
|
||||||
|
@ -128,9 +130,10 @@ void MediaPreviewWidget::showPreview(
|
||||||
not_null<PhotoData*> photo) {
|
not_null<PhotoData*> photo) {
|
||||||
startShow();
|
startShow();
|
||||||
_origin = origin;
|
_origin = origin;
|
||||||
_photo = photo;
|
|
||||||
_document = nullptr;
|
_document = nullptr;
|
||||||
_documentMedia = nullptr;
|
_documentMedia = nullptr;
|
||||||
|
_photo = photo;
|
||||||
|
_photoMedia = _photo->createMediaView();
|
||||||
fillEmojiString();
|
fillEmojiString();
|
||||||
resetGifAndCache();
|
resetGifAndCache();
|
||||||
}
|
}
|
||||||
|
@ -159,6 +162,7 @@ void MediaPreviewWidget::hidePreview() {
|
||||||
_hiding = true;
|
_hiding = true;
|
||||||
_a_shown.start([=] { update(); }, 1., 0., st::stickerPreviewDuration);
|
_a_shown.start([=] { update(); }, 1., 0., st::stickerPreviewDuration);
|
||||||
_photo = nullptr;
|
_photo = nullptr;
|
||||||
|
_photoMedia = nullptr;
|
||||||
_document = nullptr;
|
_document = nullptr;
|
||||||
_documentMedia = nullptr;
|
_documentMedia = nullptr;
|
||||||
resetGifAndCache();
|
resetGifAndCache();
|
||||||
|
@ -296,30 +300,31 @@ QPixmap MediaPreviewWidget::currentImage() const {
|
||||||
}
|
}
|
||||||
} else if (_photo) {
|
} else if (_photo) {
|
||||||
if (_cacheStatus != CacheLoaded) {
|
if (_cacheStatus != CacheLoaded) {
|
||||||
if (_photo->loaded()) {
|
if (_photoMedia->loaded()) {
|
||||||
QSize s = currentDimensions();
|
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;
|
_cacheStatus = CacheLoaded;
|
||||||
} else {
|
} else {
|
||||||
_photo->load(_origin);
|
_photo->load(_origin);
|
||||||
if (_cacheStatus != CacheThumbLoaded) {
|
if (_cacheStatus != CacheThumbLoaded) {
|
||||||
QSize s = currentDimensions();
|
QSize s = currentDimensions();
|
||||||
if (_photo->thumbnail()->loaded()) {
|
if (const auto thumbnail = _photoMedia->image(
|
||||||
_cache = _photo->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
Data::PhotoSize::Thumbnail)) {
|
||||||
|
_cache = thumbnail->pixBlurred(_origin, s.width(), s.height());
|
||||||
_cacheStatus = CacheThumbLoaded;
|
_cacheStatus = CacheThumbLoaded;
|
||||||
} else if (_photo->thumbnailSmall()->loaded()) {
|
} else if (const auto small = _photoMedia->image(
|
||||||
_cache = _photo->thumbnailSmall()->pixBlurred(_origin, s.width(), s.height());
|
Data::PhotoSize::Small)) {
|
||||||
|
_cache = small->pixBlurred(_origin, s.width(), s.height());
|
||||||
_cacheStatus = CacheThumbLoaded;
|
_cacheStatus = CacheThumbLoaded;
|
||||||
} else if (const auto blurred = _photo->thumbnailInline()) {
|
} else if (const auto blurred = _photoMedia->thumbnailInline()) {
|
||||||
_cache = blurred->pixBlurred(_origin, s.width(), s.height());
|
_cache = blurred->pixBlurred(_origin, s.width(), s.height());
|
||||||
_cacheStatus = CacheThumbLoaded;
|
_cacheStatus = CacheThumbLoaded;
|
||||||
} else {
|
} else {
|
||||||
_photo->thumbnailSmall()->load(_origin);
|
_photoMedia->wanted(Data::PhotoSize::Small, _origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return _cache;
|
return _cache;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
class PhotoMedia;
|
||||||
class DocumentMedia;
|
class DocumentMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
@ -60,9 +61,10 @@ private:
|
||||||
Ui::Animations::Simple _a_shown;
|
Ui::Animations::Simple _a_shown;
|
||||||
bool _hiding = false;
|
bool _hiding = false;
|
||||||
Data::FileOrigin _origin;
|
Data::FileOrigin _origin;
|
||||||
DocumentData *_document = nullptr;
|
|
||||||
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
|
DocumentData *_document = nullptr;
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||||
|
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
||||||
Media::Clip::ReaderPointer _gif, _gifThumbnail;
|
Media::Clip::ReaderPointer _gif, _gifThumbnail;
|
||||||
crl::time _gifLastPosition = 0;
|
crl::time _gifLastPosition = 0;
|
||||||
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
||||||
|
|
Loading…
Reference in New Issue