mirror of https://github.com/procxx/kepka.git
parent
a70e72f75d
commit
a1baa23a52
|
@ -894,7 +894,7 @@ void ApiWrap::requestWallPaper(
|
|||
data.vaccess_hash.v,
|
||||
data.vflags.v,
|
||||
qs(data.vslug),
|
||||
document->thumb,
|
||||
document->thumbnail(),
|
||||
document
|
||||
});
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ QImage PrepareScaledFromFull(
|
|||
size);
|
||||
}
|
||||
|
||||
QPixmap PrepareScaledFromThumb(ImagePtr thumb) {
|
||||
QPixmap PrepareScaledFromThumb(not_null<Image*> thumb) {
|
||||
return thumb->loaded()
|
||||
? App::pixmapFromImageInPlace(PrepareScaledFromFull(
|
||||
thumb->original(),
|
||||
|
@ -315,7 +315,7 @@ void BackgroundPreviewBox::prepare() {
|
|||
_scaled = PrepareScaledFromThumb(_paper.thumb);
|
||||
checkLoadedDocument();
|
||||
|
||||
if (_paper.thumb && !_paper.thumb->loaded()) {
|
||||
if (!_paper.thumb->loaded()) {
|
||||
_paper.thumb->loadEvenCancelled(Data::FileOriginWallpaper(
|
||||
_paper.id,
|
||||
_paper.accessHash));
|
||||
|
|
|
@ -42,17 +42,17 @@ EditCaptionBox::EditCaptionBox(
|
|||
Expects(item->media()->allowsEditCaption());
|
||||
|
||||
QSize dimensions;
|
||||
ImagePtr image;
|
||||
auto image = (Image*)nullptr;
|
||||
DocumentData *doc = nullptr;
|
||||
|
||||
const auto media = item->media();
|
||||
if (const auto photo = media->photo()) {
|
||||
_photo = true;
|
||||
dimensions = QSize(photo->full->width(), photo->full->height());
|
||||
image = photo->full;
|
||||
dimensions = QSize(photo->width(), photo->height());
|
||||
image = photo->large();
|
||||
} else if (const auto document = media->document()) {
|
||||
dimensions = document->dimensions;
|
||||
image = document->thumb;
|
||||
image = document->thumbnail();
|
||||
if (document->isAnimation()) {
|
||||
_animated = true;
|
||||
} else if (document->isVideoFile()) {
|
||||
|
@ -68,8 +68,8 @@ EditCaptionBox::EditCaptionBox(
|
|||
ConvertEntitiesToTextTags(original.entities)
|
||||
};
|
||||
|
||||
if (!_animated && (dimensions.isEmpty() || doc || image->isNull())) {
|
||||
if (image->isNull()) {
|
||||
if (!_animated && (dimensions.isEmpty() || doc || !image)) {
|
||||
if (!image) {
|
||||
_thumbw = 0;
|
||||
} else {
|
||||
int32 tw = image->width(), th = image->height();
|
||||
|
|
|
@ -63,7 +63,7 @@ private:
|
|||
|
||||
not_null<Window::Controller*> _controller;
|
||||
FullMsgId _msgId;
|
||||
ImagePtr _thumbnailImage;
|
||||
Image *_thumbnailImage = nullptr;
|
||||
bool _thumbnailImageLoaded = false;
|
||||
Fn<void()> _refreshThumbnail;
|
||||
bool _animated = false;
|
||||
|
|
|
@ -472,7 +472,7 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
|
|||
p.setOpacity(1);
|
||||
|
||||
}
|
||||
doc->checkStickerThumb();
|
||||
doc->checkStickerSmall();
|
||||
|
||||
float64 coef = qMin((st::stickersSize.width() - st::buttonRadius * 2) / float64(doc->dimensions.width()), (st::stickersSize.height() - st::buttonRadius * 2) / float64(doc->dimensions.height()));
|
||||
if (coef > 1) coef = 1;
|
||||
|
@ -480,7 +480,7 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
|
|||
if (w < 1) w = 1;
|
||||
if (h < 1) h = 1;
|
||||
QPoint ppos = pos + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2);
|
||||
if (const auto image = doc->getStickerThumb()) {
|
||||
if (const auto image = doc->getStickerSmall()) {
|
||||
p.drawPixmapLeft(
|
||||
ppos,
|
||||
width(),
|
||||
|
|
|
@ -804,9 +804,11 @@ void StickersBox::Inner::paintRow(Painter &p, Row *set, int index, TimeMs ms) {
|
|||
const auto origin = Data::FileOriginStickerSet(
|
||||
set->id,
|
||||
set->accessHash);
|
||||
set->sticker->thumb->load(origin);
|
||||
auto pix = set->sticker->thumb->pix(origin, set->pixw, set->pixh);
|
||||
p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix);
|
||||
if (const auto thumb = set->sticker->thumbnail()) {
|
||||
thumb->load(origin);
|
||||
auto pix = thumb->pix(origin, set->pixw, set->pixh);
|
||||
p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix);
|
||||
}
|
||||
}
|
||||
|
||||
int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left();
|
||||
|
@ -1575,8 +1577,11 @@ void StickersBox::Inner::fillSetCover(const Stickers::Set &set, DocumentData **o
|
|||
}
|
||||
auto sticker = *outSticker = set.stickers.front();
|
||||
|
||||
auto pixw = sticker->thumb->width();
|
||||
auto pixh = sticker->thumb->height();
|
||||
const auto size = sticker->thumbnail()
|
||||
? sticker->thumbnail()->size()
|
||||
: QSize(1, 1);
|
||||
auto pixw = size.width();
|
||||
auto pixh = size.height();
|
||||
if (pixw > st::contactsPhotoSize) {
|
||||
if (pixw > pixh) {
|
||||
pixh = (pixh * st::contactsPhotoSize) / pixw;
|
||||
|
@ -1734,7 +1739,10 @@ void StickersBox::Inner::readVisibleSets() {
|
|||
if (i * _rowHeight < itemsVisibleTop || (i + 1) * _rowHeight > itemsVisibleBottom) {
|
||||
continue;
|
||||
}
|
||||
if (!_rows[i]->sticker || _rows[i]->sticker->thumb->loaded() || _rows[i]->sticker->loaded()) {
|
||||
if (!_rows[i]->sticker
|
||||
|| !_rows[i]->sticker->hasThumbnail()
|
||||
|| _rows[i]->sticker->thumbnail()->loaded()
|
||||
|| _rows[i]->sticker->loaded()) {
|
||||
Auth().api().readFeaturedSetDelayed(_rows[i]->id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -503,34 +503,39 @@ void Panel::processUserPhoto() {
|
|||
_user->loadUserpic(true);
|
||||
}
|
||||
const auto photo = _user->userpicPhotoId()
|
||||
? Auth().data().photo(_user->userpicPhotoId()).get()
|
||||
? _user->owner().photo(_user->userpicPhotoId()).get()
|
||||
: nullptr;
|
||||
if (isGoodUserPhoto(photo)) {
|
||||
photo->full->load(_user->userpicPhotoOrigin(), true);
|
||||
photo->large()->load(_user->userpicPhotoOrigin(), true);
|
||||
} else if (_user->userpicPhotoUnknown() || (photo && !photo->date)) {
|
||||
Auth().api().requestFullPeer(_user);
|
||||
_user->session().api().requestFullPeer(_user);
|
||||
}
|
||||
refreshUserPhoto();
|
||||
}
|
||||
|
||||
void Panel::refreshUserPhoto() {
|
||||
const auto photo = _user->userpicPhotoId()
|
||||
? Auth().data().photo(_user->userpicPhotoId()).get()
|
||||
? _user->owner().photo(_user->userpicPhotoId()).get()
|
||||
: nullptr;
|
||||
const auto isNewPhoto = [&](not_null<PhotoData*> photo) {
|
||||
return photo->full->loaded()
|
||||
return photo->large()->loaded()
|
||||
&& (photo->id != _userPhotoId || !_userPhotoFull);
|
||||
};
|
||||
if (isGoodUserPhoto(photo) && isNewPhoto(photo)) {
|
||||
_userPhotoId = photo->id;
|
||||
_userPhotoFull = true;
|
||||
createUserpicCache(photo->full, _user->userpicPhotoOrigin());
|
||||
createUserpicCache(
|
||||
photo->isNull() ? nullptr : photo->large().get(),
|
||||
_user->userpicPhotoOrigin());
|
||||
} else if (_userPhoto.isNull()) {
|
||||
createUserpicCache(_user->currentUserpic(), _user->userpicOrigin());
|
||||
const auto userpic = _user->currentUserpic();
|
||||
createUserpicCache(
|
||||
userpic ? userpic.get() : nullptr,
|
||||
_user->userpicOrigin());
|
||||
}
|
||||
}
|
||||
|
||||
void Panel::createUserpicCache(ImagePtr image, Data::FileOrigin origin) {
|
||||
void Panel::createUserpicCache(Image *image, Data::FileOrigin origin) {
|
||||
auto size = st::callWidth * cIntRetinaFactor();
|
||||
auto options = _useTransparency ? (Images::Option::RoundedLarge | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::Smooth) : Images::Option::None;
|
||||
if (image) {
|
||||
|
@ -570,14 +575,14 @@ void Panel::createUserpicCache(ImagePtr image, Data::FileOrigin origin) {
|
|||
}
|
||||
|
||||
bool Panel::isGoodUserPhoto(PhotoData *photo) {
|
||||
if (!photo || !photo->date) {
|
||||
if (!photo || photo->isNull()) {
|
||||
return false;
|
||||
}
|
||||
auto badAspect = [](int a, int b) {
|
||||
const auto badAspect = [](int a, int b) {
|
||||
return a > 10 * b;
|
||||
};
|
||||
auto width = photo->full->width();
|
||||
auto height = photo->full->height();
|
||||
const auto width = photo->width();
|
||||
const auto height = photo->height();
|
||||
return !badAspect(width, height) && !badAspect(height, width);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ private:
|
|||
void processUserPhoto();
|
||||
void refreshUserPhoto();
|
||||
bool isGoodUserPhoto(PhotoData *photo);
|
||||
void createUserpicCache(ImagePtr image, Data::FileOrigin origin);
|
||||
void createUserpicCache(Image *image, Data::FileOrigin origin);
|
||||
QRect signalBarsRect() const;
|
||||
void paintSignalBarsBg(Painter &p);
|
||||
|
||||
|
|
|
@ -561,7 +561,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
|||
App::roundRect(p, QRect(tl, st::stickerPanSize), st::emojiPanHover, StickerHoverCorners);
|
||||
}
|
||||
|
||||
document->checkStickerThumb();
|
||||
document->checkStickerSmall();
|
||||
|
||||
float64 coef = qMin((st::stickerPanSize.width() - st::buttonRadius * 2) / float64(document->dimensions.width()), (st::stickerPanSize.height() - st::buttonRadius * 2) / float64(document->dimensions.height()));
|
||||
if (coef > 1) coef = 1;
|
||||
|
@ -569,7 +569,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
|||
if (w < 1) w = 1;
|
||||
if (h < 1) h = 1;
|
||||
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
|
||||
if (const auto image = document->getStickerThumb()) {
|
||||
if (const auto image = document->getStickerSmall()) {
|
||||
p.drawPixmapLeft(ppos, width(), image->pix(document->stickerSetOrigin(), w, h));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -352,11 +352,10 @@ void GifsListWidget::selectInlineResult(int row, int column) {
|
|||
|
||||
auto item = _rows[row].items[column];
|
||||
if (const auto photo = item->getPhoto()) {
|
||||
if (photo->medium->loaded() || photo->thumb->loaded()) {
|
||||
if (photo->thumbnail()->loaded()) {
|
||||
_photoChosen.fire_copy(photo);
|
||||
} else if (!photo->medium->loading()) {
|
||||
photo->thumb->loadEvenCancelled(Data::FileOrigin());
|
||||
photo->medium->loadEvenCancelled(Data::FileOrigin());
|
||||
} else if (!photo->thumbnail()->loading()) {
|
||||
photo->thumbnail()->loadEvenCancelled(Data::FileOrigin());
|
||||
}
|
||||
} else if (const auto document = item->getDocument()) {
|
||||
if (document->loaded()) {
|
||||
|
|
|
@ -259,8 +259,8 @@ void StickersListWidget::Footer::enumerateVisibleIcons(Callback callback) {
|
|||
|
||||
void StickersListWidget::Footer::preloadImages() {
|
||||
enumerateVisibleIcons([](const StickerIcon &icon, int x) {
|
||||
if (auto sticker = icon.sticker) {
|
||||
sticker->thumb->load(sticker->stickerSetOrigin());
|
||||
if (const auto sticker = icon.sticker) {
|
||||
sticker->loadThumbnail(sticker->stickerSetOrigin());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -631,10 +631,12 @@ void StickersListWidget::Footer::paintSetIcon(
|
|||
int x) const {
|
||||
if (icon.sticker) {
|
||||
const auto origin = icon.sticker->stickerSetOrigin();
|
||||
icon.sticker->thumb->load(origin);
|
||||
auto pix = icon.sticker->thumb->pix(origin, icon.pixw, icon.pixh);
|
||||
if (const auto thumb = icon.sticker->thumbnail()) {
|
||||
thumb->load(origin);
|
||||
auto pix = thumb->pix(origin, icon.pixw, icon.pixh);
|
||||
|
||||
p.drawPixmapLeft(x + (st::stickerIconWidth - icon.pixw) / 2, _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2, width(), pix);
|
||||
p.drawPixmapLeft(x + (st::stickerIconWidth - icon.pixw) / 2, _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2, width(), pix);
|
||||
}
|
||||
} else if (icon.megagroup) {
|
||||
icon.megagroup->paintUserpicLeft(p, x + (st::stickerIconWidth - st::stickerGroupCategorySize) / 2, _iconsTop + (st::emojiFooterHeight - st::stickerGroupCategorySize) / 2, width(), st::stickerGroupCategorySize);
|
||||
} else {
|
||||
|
@ -753,7 +755,9 @@ void StickersListWidget::readVisibleSets() {
|
|||
int count = qMin(set.pack.size(), _columnCount);
|
||||
int loaded = 0;
|
||||
for (int j = 0; j < count; ++j) {
|
||||
if (set.pack[j]->thumb->loaded() || set.pack[j]->loaded()) {
|
||||
if (!set.pack[j]->hasThumbnail()
|
||||
|| set.pack[j]->thumbnail()->loaded()
|
||||
|| set.pack[j]->loaded()) {
|
||||
++loaded;
|
||||
}
|
||||
}
|
||||
|
@ -1339,14 +1343,14 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int index, bo
|
|||
App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners);
|
||||
}
|
||||
|
||||
document->checkStickerThumb();
|
||||
document->checkStickerSmall();
|
||||
|
||||
auto coef = qMin((_singleSize.width() - st::buttonRadius * 2) / float64(document->dimensions.width()), (_singleSize.height() - st::buttonRadius * 2) / float64(document->dimensions.height()));
|
||||
if (coef > 1) coef = 1;
|
||||
auto w = qMax(qRound(coef * document->dimensions.width()), 1);
|
||||
auto h = qMax(qRound(coef * document->dimensions.height()), 1);
|
||||
auto ppos = pos + QPoint((_singleSize.width() - w) / 2, (_singleSize.height() - h) / 2);
|
||||
if (const auto image = document->getStickerThumb()) {
|
||||
if (const auto image = document->getStickerSmall()) {
|
||||
if (image->loaded()) {
|
||||
p.drawPixmapLeft(
|
||||
ppos,
|
||||
|
@ -1786,7 +1790,7 @@ void StickersListWidget::preloadImages() {
|
|||
const auto document = sets[i].pack[j];
|
||||
if (!document || !document->sticker()) continue;
|
||||
|
||||
document->checkStickerThumb();
|
||||
document->checkStickerSmall();
|
||||
}
|
||||
if (k > _columnCount * (_columnCount + 1)) break;
|
||||
}
|
||||
|
@ -2047,7 +2051,10 @@ void StickersListWidget::fillIcons(QList<StickerIcon> &icons) {
|
|||
}
|
||||
auto s = _mySets[i].pack[0];
|
||||
auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding, availh = st::emojiFooterHeight - 2 * st::stickerIconPadding;
|
||||
auto thumbw = s->thumb->width(), thumbh = s->thumb->height(), pixw = 1, pixh = 1;
|
||||
const auto size = s->hasThumbnail()
|
||||
? s->thumbnail()->size()
|
||||
: QSize();
|
||||
auto thumbw = size.width(), thumbh = size.height(), pixw = 1, pixh = 1;
|
||||
if (availw * thumbh > availh * thumbw) {
|
||||
pixh = availh;
|
||||
pixw = (pixh * thumbw) / thumbh;
|
||||
|
|
|
@ -25,7 +25,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/confirm_box.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/image/image_source.h"
|
||||
#include "auth_session.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/application.h"
|
||||
|
||||
|
@ -318,7 +317,7 @@ void DocumentOpenClickHandler::Open(
|
|||
auto audio = AudioMsgId(data, msgId);
|
||||
Media::Player::mixer()->play(audio);
|
||||
Media::Player::Updated().notify(audio);
|
||||
data->session()->data().markMediaRead(data);
|
||||
data->owner().markMediaRead(data);
|
||||
}
|
||||
} else if (playMusic) {
|
||||
auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Song);
|
||||
|
@ -345,24 +344,24 @@ void DocumentOpenClickHandler::Open(
|
|||
File::Launch(filepath);
|
||||
}
|
||||
}
|
||||
data->session()->data().markMediaRead(data);
|
||||
data->owner().markMediaRead(data);
|
||||
} else if (data->isVoiceMessage() || data->isAudioFile() || data->isVideoFile()) {
|
||||
const auto filepath = location.name();
|
||||
if (Data::IsValidMediaFile(filepath)) {
|
||||
File::Launch(filepath);
|
||||
}
|
||||
data->session()->data().markMediaRead(data);
|
||||
data->owner().markMediaRead(data);
|
||||
} else if (data->size < App::kImageSizeLimit) {
|
||||
if (!data->data().isEmpty() && playAnimation) {
|
||||
if (action == ActionOnLoadPlayInline && context) {
|
||||
data->session()->data().requestAnimationPlayInline(context);
|
||||
data->owner().requestAnimationPlayInline(context);
|
||||
} else {
|
||||
Core::App().showDocument(data, context);
|
||||
}
|
||||
} else if (location.accessEnable()) {
|
||||
if (playAnimation || QImageReader(location.name()).canRead()) {
|
||||
if (playAnimation && action == ActionOnLoadPlayInline && context) {
|
||||
data->session()->data().requestAnimationPlayInline(context);
|
||||
data->owner().requestAnimationPlayInline(context);
|
||||
} else {
|
||||
Core::App().showDocument(data, context);
|
||||
}
|
||||
|
@ -462,13 +461,17 @@ VoiceData::~VoiceData() {
|
|||
}
|
||||
}
|
||||
|
||||
DocumentData::DocumentData(DocumentId id, not_null<AuthSession*> session)
|
||||
DocumentData::DocumentData(not_null<Data::Session*> owner, DocumentId id)
|
||||
: id(id)
|
||||
, _session(session) {
|
||||
, _owner(owner) {
|
||||
}
|
||||
|
||||
not_null<AuthSession*> DocumentData::session() const {
|
||||
return _session;
|
||||
Data::Session &DocumentData::owner() const {
|
||||
return *_owner;
|
||||
}
|
||||
|
||||
AuthSession &DocumentData::session() const {
|
||||
return _owner->session();
|
||||
}
|
||||
|
||||
void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) {
|
||||
|
@ -581,7 +584,7 @@ bool DocumentData::checkWallPaperProperties() {
|
|||
return true;
|
||||
}
|
||||
if (type != FileDocument
|
||||
|| !thumb
|
||||
|| !_thumbnail
|
||||
|| !dimensions.width()
|
||||
|| !dimensions.height()
|
||||
|| dimensions.width() > Storage::kMaxWallPaperDimension
|
||||
|
@ -593,10 +596,43 @@ bool DocumentData::checkWallPaperProperties() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void DocumentData::updateThumbnails(
|
||||
ImagePtr thumbnailInline,
|
||||
ImagePtr thumbnail) {
|
||||
if (thumbnailInline && !_thumbnailInline) {
|
||||
_thumbnailInline = thumbnailInline;
|
||||
}
|
||||
if (thumbnail
|
||||
&& (!_thumbnail
|
||||
|| (sticker()
|
||||
&& (_thumbnail->width() < thumbnail->width()
|
||||
|| _thumbnail->height() < thumbnail->height())))) {
|
||||
_thumbnail = thumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
bool DocumentData::isWallPaper() const {
|
||||
return (type == WallPaperDocument);
|
||||
}
|
||||
|
||||
bool DocumentData::hasThumbnail() const {
|
||||
return !_thumbnail->isNull();
|
||||
}
|
||||
|
||||
Image *DocumentData::thumbnailInline() const {
|
||||
return _thumbnailInline ? _thumbnailInline.get() : nullptr;
|
||||
}
|
||||
|
||||
Image *DocumentData::thumbnail() const {
|
||||
return _thumbnail ? _thumbnail.get() : nullptr;
|
||||
}
|
||||
|
||||
void DocumentData::loadThumbnail(Data::FileOrigin origin) {
|
||||
if (_thumbnail && !_thumbnail->loaded()) {
|
||||
_thumbnail->load(origin);
|
||||
}
|
||||
}
|
||||
|
||||
Storage::Cache::Key DocumentData::goodThumbnailCacheKey() const {
|
||||
return Data::DocumentThumbCacheKey(_dc, id);
|
||||
}
|
||||
|
@ -645,14 +681,19 @@ bool DocumentData::saveToCache() const {
|
|||
|
||||
void DocumentData::unload() {
|
||||
// Forget thumb only when image cache limit exceeds.
|
||||
//thumb->unload();
|
||||
//
|
||||
// Also, you can't unload() images that you don't own
|
||||
// from the destructor, because they're already destroyed.
|
||||
//
|
||||
//_thumbnailInline->unload();
|
||||
//_thumbnail->unload();
|
||||
if (sticker()) {
|
||||
if (sticker()->image) {
|
||||
ActiveCache().decrement(ComputeUsage(sticker()));
|
||||
sticker()->image = nullptr;
|
||||
}
|
||||
}
|
||||
_replyPreview = nullptr;
|
||||
_replyPreview.clear();
|
||||
if (!_data.isEmpty()) {
|
||||
ActiveCache().decrement(_data.size());
|
||||
_data.clear();
|
||||
|
@ -737,7 +778,7 @@ void DocumentData::performActionOnLoad() {
|
|||
}
|
||||
} else if (Media::Player::IsStopped(state.state)) {
|
||||
Media::Player::mixer()->play(AudioMsgId(this, _actionOnLoadMsgId));
|
||||
_session->data().markMediaRead(this);
|
||||
_owner->markMediaRead(this);
|
||||
}
|
||||
}
|
||||
} else if (playMusic) {
|
||||
|
@ -758,7 +799,7 @@ void DocumentData::performActionOnLoad() {
|
|||
} else if (playAnimation) {
|
||||
if (loaded()) {
|
||||
if (_actionOnLoad == ActionOnLoadPlayInline && item) {
|
||||
_session->data().requestAnimationPlayInline(item);
|
||||
_owner->requestAnimationPlayInline(item);
|
||||
} else {
|
||||
Core::App().showDocument(this, item);
|
||||
}
|
||||
|
@ -773,7 +814,7 @@ void DocumentData::performActionOnLoad() {
|
|||
if (Data::IsValidMediaFile(already)) {
|
||||
File::Launch(already);
|
||||
}
|
||||
_session->data().markMediaRead(this);
|
||||
_owner->markMediaRead(this);
|
||||
} else if (loc.accessEnable()) {
|
||||
if (showImage && QImageReader(loc.name()).canRead()) {
|
||||
Core::App().showDocument(this, item);
|
||||
|
@ -810,14 +851,14 @@ bool DocumentData::loaded(FilePathResolveType type) const {
|
|||
_loader->imageData()));
|
||||
ActiveCache().increment(ComputeUsage(that->sticker()));
|
||||
}
|
||||
if (!that->_data.isEmpty() || that->getStickerImage()) {
|
||||
if (!that->_data.isEmpty() || that->getStickerLarge()) {
|
||||
ActiveCache().up(that);
|
||||
}
|
||||
|
||||
that->refreshGoodThumbnail();
|
||||
destroyLoader();
|
||||
}
|
||||
_session->data().notifyDocumentLayoutChanged(this);
|
||||
_owner->notifyDocumentLayoutChanged(this);
|
||||
}
|
||||
return !data().isEmpty() || !filepath(type).isEmpty();
|
||||
}
|
||||
|
@ -962,7 +1003,7 @@ void DocumentData::save(
|
|||
if (loading()) {
|
||||
_loader->start();
|
||||
}
|
||||
_session->data().notifyDocumentLayoutChanged(this);
|
||||
_owner->notifyDocumentLayoutChanged(this);
|
||||
}
|
||||
|
||||
void DocumentData::cancel() {
|
||||
|
@ -971,7 +1012,7 @@ void DocumentData::cancel() {
|
|||
}
|
||||
|
||||
destroyLoader(CancelledMtpFileLoader);
|
||||
_session->data().notifyDocumentLayoutChanged(this);
|
||||
_owner->notifyDocumentLayoutChanged(this);
|
||||
App::main()->documentLoadProgress(this);
|
||||
|
||||
_actionOnLoad = ActionOnLoadNone;
|
||||
|
@ -1085,7 +1126,7 @@ bool DocumentData::isStickerSetInstalled() const {
|
|||
Expects(sticker() != nullptr);
|
||||
|
||||
const auto &set = sticker()->set;
|
||||
const auto &sets = _session->data().stickerSets();
|
||||
const auto &sets = _owner->stickerSets();
|
||||
switch (set.type()) {
|
||||
case mtpc_inputStickerSetID: {
|
||||
auto it = sets.constFind(set.c_inputStickerSetID().vid.v);
|
||||
|
@ -1107,25 +1148,30 @@ bool DocumentData::isStickerSetInstalled() const {
|
|||
}
|
||||
|
||||
Image *DocumentData::getReplyPreview(Data::FileOrigin origin) {
|
||||
if (!_replyPreview->isNull() && !thumb->isNull()) {
|
||||
if (thumb->loaded()) {
|
||||
int w = thumb->width(), h = thumb->height();
|
||||
if (w <= 0) w = 1;
|
||||
if (h <= 0) h = 1;
|
||||
auto thumbSize = (w > h) ? QSize(w * st::msgReplyBarSize.height() / h, st::msgReplyBarSize.height()) : QSize(st::msgReplyBarSize.height(), h * st::msgReplyBarSize.height() / w);
|
||||
thumbSize *= cIntRetinaFactor();
|
||||
auto options = Images::Option::Smooth | (isVideoMessage() ? Images::Option::Circled : Images::Option::None) | Images::Option::TransparentBackground;
|
||||
auto outerSize = st::msgReplyBarSize.height();
|
||||
auto image = thumb->pixNoCache(origin, thumbSize.width(), thumbSize.height(), options, outerSize, outerSize);
|
||||
_replyPreview = std::make_unique<Image>(
|
||||
std::make_unique<Images::ImageSource>(
|
||||
image.toImage(),
|
||||
"PNG"));
|
||||
} else {
|
||||
thumb->load(origin);
|
||||
if (!_thumbnail) {
|
||||
return nullptr;
|
||||
} else if (_replyPreview
|
||||
&& (_replyPreview.good() || !_thumbnail->loaded())) {
|
||||
return _replyPreview.image();
|
||||
}
|
||||
const auto option = isVideoMessage()
|
||||
? Images::Option::Circled
|
||||
: Images::Option::None;
|
||||
if (_thumbnail->loaded()) {
|
||||
_replyPreview.prepare(
|
||||
_thumbnail.get(),
|
||||
origin,
|
||||
option);
|
||||
} else {
|
||||
_thumbnail->load(origin);
|
||||
if (_thumbnailInline) {
|
||||
_replyPreview.prepare(
|
||||
_thumbnailInline.get(),
|
||||
origin,
|
||||
option | Images::Option::Blurred);
|
||||
}
|
||||
}
|
||||
return _replyPreview.get();
|
||||
return _replyPreview.image();
|
||||
}
|
||||
|
||||
StickerData *DocumentData::sticker() const {
|
||||
|
@ -1134,7 +1180,7 @@ StickerData *DocumentData::sticker() const {
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
void DocumentData::checkSticker() {
|
||||
void DocumentData::checkStickerLarge() {
|
||||
const auto data = sticker();
|
||||
if (!data) return;
|
||||
|
||||
|
@ -1164,25 +1210,25 @@ void DocumentData::checkSticker() {
|
|||
}
|
||||
}
|
||||
|
||||
void DocumentData::checkStickerThumb() {
|
||||
if (hasGoodStickerThumb()) {
|
||||
thumb->load(stickerSetOrigin());
|
||||
void DocumentData::checkStickerSmall() {
|
||||
if (thumbnailEnoughForSticker()) {
|
||||
_thumbnail->load(stickerSetOrigin());
|
||||
} else {
|
||||
checkSticker();
|
||||
checkStickerLarge();
|
||||
}
|
||||
}
|
||||
|
||||
Image *DocumentData::getStickerImage() {
|
||||
checkSticker();
|
||||
Image *DocumentData::getStickerLarge() {
|
||||
checkStickerLarge();
|
||||
if (const auto data = sticker()) {
|
||||
return data->image.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Image *DocumentData::getStickerThumb() {
|
||||
if (hasGoodStickerThumb()) {
|
||||
return thumb->isNull() ? nullptr : thumb.get();
|
||||
Image *DocumentData::getStickerSmall() {
|
||||
if (thumbnailEnoughForSticker()) {
|
||||
return _thumbnail->isNull() ? nullptr : _thumbnail.get();
|
||||
} else if (const auto data = sticker()) {
|
||||
return data->image.get();
|
||||
}
|
||||
|
@ -1236,8 +1282,8 @@ bool DocumentData::hasWebLocation() const {
|
|||
return _urlLocation.dc() != 0 && _urlLocation.accessHash() != 0;
|
||||
}
|
||||
|
||||
bool DocumentData::isValid() const {
|
||||
return hasRemoteLocation() || hasWebLocation() || !_url.isEmpty();
|
||||
bool DocumentData::isNull() const {
|
||||
return !hasRemoteLocation() && !hasWebLocation() && _url.isEmpty();
|
||||
}
|
||||
|
||||
MTPInputDocument DocumentData::mtpInput() const {
|
||||
|
@ -1260,9 +1306,9 @@ void DocumentData::refreshFileReference(const QByteArray &value) {
|
|||
|
||||
void DocumentData::refreshStickerThumbFileReference() {
|
||||
if (const auto data = sticker()) {
|
||||
if (thumb->loading()) {
|
||||
if (_thumbnail->loading()) {
|
||||
data->loc.refreshFileReference(
|
||||
thumb->location().fileReference());
|
||||
_thumbnail->location().fileReference());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1407,9 +1453,9 @@ void DocumentData::recountIsImage() {
|
|||
&& fileIsImage(filename(), mimeString());
|
||||
}
|
||||
|
||||
bool DocumentData::hasGoodStickerThumb() const {
|
||||
return !thumb->isNull()
|
||||
&& ((thumb->width() >= 128) || (thumb->height() >= 128));
|
||||
bool DocumentData::thumbnailEnoughForSticker() const {
|
||||
return !_thumbnail->isNull()
|
||||
&& ((_thumbnail->width() >= 128) || (_thumbnail->height() >= 128));
|
||||
}
|
||||
|
||||
void DocumentData::setRemoteLocation(
|
||||
|
@ -1420,7 +1466,7 @@ void DocumentData::setRemoteLocation(
|
|||
if (_dc != dc || _access != access) {
|
||||
_dc = dc;
|
||||
_access = access;
|
||||
if (isValid()) {
|
||||
if (!isNull()) {
|
||||
if (_location.check()) {
|
||||
Local::writeFileLocation(mediaKey(), _location);
|
||||
} else {
|
||||
|
@ -1439,10 +1485,12 @@ void DocumentData::setWebLocation(const WebFileLocation &location) {
|
|||
_urlLocation = location;
|
||||
}
|
||||
|
||||
void DocumentData::collectLocalData(DocumentData *local) {
|
||||
if (local == this) return;
|
||||
void DocumentData::collectLocalData(not_null<DocumentData*> local) {
|
||||
if (local == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
_session->data().cache().copyIfEmpty(local->cacheKey(), cacheKey());
|
||||
_owner->cache().copyIfEmpty(local->cacheKey(), cacheKey());
|
||||
if (!local->_data.isEmpty()) {
|
||||
ActiveCache().decrement(_data.size());
|
||||
_data = local->_data;
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "data/data_types.h"
|
||||
#include "ui/image/image.h"
|
||||
|
||||
namespace Images {
|
||||
class Source;
|
||||
|
@ -19,6 +20,10 @@ struct Key;
|
|||
} // namespace Cache
|
||||
} // namespace Storage
|
||||
|
||||
namespace Data {
|
||||
class Session;
|
||||
} // namespace Data
|
||||
|
||||
class AuthSession;
|
||||
class mtpFileLoader;
|
||||
|
||||
|
@ -75,9 +80,10 @@ class Document;
|
|||
|
||||
class DocumentData {
|
||||
public:
|
||||
DocumentData(DocumentId id, not_null<AuthSession*> session);
|
||||
DocumentData(not_null<Data::Session*> owner, DocumentId id);
|
||||
|
||||
not_null<AuthSession*> session() const;
|
||||
[[nodiscard]] Data::Session &owner() const;
|
||||
[[nodiscard]] AuthSession &session() const;
|
||||
|
||||
void setattributes(
|
||||
const QVector<MTPDocumentAttribute> &attributes);
|
||||
|
@ -93,11 +99,11 @@ public:
|
|||
FilePathResolveSaveFromData,
|
||||
FilePathResolveSaveFromDataSilent,
|
||||
};
|
||||
bool loaded(
|
||||
[[nodiscard]] bool loaded(
|
||||
FilePathResolveType type = FilePathResolveCached) const;
|
||||
bool loading() const;
|
||||
QString loadingFilePath() const;
|
||||
bool displayLoading() const;
|
||||
[[nodiscard]] bool loading() const;
|
||||
[[nodiscard]] QString loadingFilePath() const;
|
||||
[[nodiscard]] bool displayLoading() const;
|
||||
void save(
|
||||
Data::FileOrigin origin,
|
||||
const QString &toFile,
|
||||
|
@ -106,19 +112,19 @@ public:
|
|||
LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal,
|
||||
bool autoLoading = false);
|
||||
void cancel();
|
||||
bool cancelled() const;
|
||||
float64 progress() const;
|
||||
int32 loadOffset() const;
|
||||
bool uploading() const;
|
||||
[[nodiscard]] bool cancelled() const;
|
||||
[[nodiscard]] float64 progress() const;
|
||||
[[nodiscard]] int32 loadOffset() const;
|
||||
[[nodiscard]] bool uploading() const;
|
||||
|
||||
void setWaitingForAlbum();
|
||||
bool waitingForAlbum() const;
|
||||
[[nodiscard]] bool waitingForAlbum() const;
|
||||
|
||||
QByteArray data() const;
|
||||
const FileLocation &location(bool check = false) const;
|
||||
[[nodiscard]] QByteArray data() const;
|
||||
[[nodiscard]] const FileLocation &location(bool check = false) const;
|
||||
void setLocation(const FileLocation &loc);
|
||||
|
||||
QString filepath(
|
||||
[[nodiscard]] QString filepath(
|
||||
FilePathResolveType type = FilePathResolveCached,
|
||||
bool forceSavingAs = false) const;
|
||||
|
||||
|
@ -127,44 +133,50 @@ public:
|
|||
void performActionOnLoad();
|
||||
|
||||
void unload();
|
||||
Image *getReplyPreview(Data::FileOrigin origin);
|
||||
[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
|
||||
|
||||
StickerData *sticker() const;
|
||||
void checkSticker();
|
||||
void checkStickerThumb();
|
||||
Image *getStickerThumb();
|
||||
Image *getStickerImage();
|
||||
Data::FileOrigin stickerSetOrigin() const;
|
||||
Data::FileOrigin stickerOrGifOrigin() const;
|
||||
bool isStickerSetInstalled() const;
|
||||
SongData *song();
|
||||
const SongData *song() const;
|
||||
VoiceData *voice();
|
||||
const VoiceData *voice() const;
|
||||
[[nodiscard]] StickerData *sticker() const;
|
||||
void checkStickerLarge();
|
||||
void checkStickerSmall();
|
||||
[[nodiscard]] Image *getStickerSmall();
|
||||
[[nodiscard]] Image *getStickerLarge();
|
||||
[[nodiscard]] Data::FileOrigin stickerSetOrigin() const;
|
||||
[[nodiscard]] Data::FileOrigin stickerOrGifOrigin() const;
|
||||
[[nodiscard]] bool isStickerSetInstalled() const;
|
||||
[[nodiscard]] SongData *song();
|
||||
[[nodiscard]] const SongData *song() const;
|
||||
[[nodiscard]] VoiceData *voice();
|
||||
[[nodiscard]] const VoiceData *voice() const;
|
||||
|
||||
bool isVoiceMessage() const;
|
||||
bool isVideoMessage() const;
|
||||
bool isSong() const;
|
||||
bool isAudioFile() const;
|
||||
bool isVideoFile() const;
|
||||
bool isAnimation() const;
|
||||
bool isGifv() const;
|
||||
bool isTheme() const;
|
||||
bool isSharedMediaMusic() const;
|
||||
int32 duration() const;
|
||||
bool isImage() const;
|
||||
[[nodiscard]] bool isVoiceMessage() const;
|
||||
[[nodiscard]] bool isVideoMessage() const;
|
||||
[[nodiscard]] bool isSong() const;
|
||||
[[nodiscard]] bool isAudioFile() const;
|
||||
[[nodiscard]] bool isVideoFile() const;
|
||||
[[nodiscard]] bool isAnimation() const;
|
||||
[[nodiscard]] bool isGifv() const;
|
||||
[[nodiscard]] bool isTheme() const;
|
||||
[[nodiscard]] bool isSharedMediaMusic() const;
|
||||
[[nodiscard]] int32 duration() const;
|
||||
[[nodiscard]] bool isImage() const;
|
||||
void recountIsImage();
|
||||
bool supportsStreaming() const;
|
||||
[[nodiscard]] bool supportsStreaming() const;
|
||||
void setData(const QByteArray &data) {
|
||||
_data = data;
|
||||
}
|
||||
bool checkWallPaperProperties();
|
||||
bool isWallPaper() const;
|
||||
[[nodiscard]] bool isWallPaper() const;
|
||||
|
||||
bool hasGoodStickerThumb() const;
|
||||
[[nodiscard]] bool hasThumbnail() const;
|
||||
void loadThumbnail(Data::FileOrigin origin);
|
||||
[[nodiscard]] Image *thumbnailInline() const;
|
||||
[[nodiscard]] Image *thumbnail() const;
|
||||
void updateThumbnails(
|
||||
ImagePtr thumbnailInline,
|
||||
ImagePtr thumbnail);
|
||||
|
||||
Image *goodThumbnail() const;
|
||||
Storage::Cache::Key goodThumbnailCacheKey() const;
|
||||
[[nodiscard]] Image *goodThumbnail() const;
|
||||
[[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const;
|
||||
void setGoodThumbnail(QImage &&image, QByteArray &&bytes);
|
||||
void refreshGoodThumbnail();
|
||||
void replaceGoodThumbnail(std::unique_ptr<Images::Source> &&source);
|
||||
|
@ -175,11 +187,11 @@ public:
|
|||
const QByteArray &fileReference);
|
||||
void setContentUrl(const QString &url);
|
||||
void setWebLocation(const WebFileLocation &location);
|
||||
bool hasRemoteLocation() const;
|
||||
bool hasWebLocation() const;
|
||||
bool isValid() const;
|
||||
MTPInputDocument mtpInput() const;
|
||||
QByteArray fileReference() const;
|
||||
[[nodiscard]] bool hasRemoteLocation() const;
|
||||
[[nodiscard]] bool hasWebLocation() const;
|
||||
[[nodiscard]] bool isNull() const;
|
||||
[[nodiscard]] MTPInputDocument mtpInput() const;
|
||||
[[nodiscard]] QByteArray fileReference() const;
|
||||
void refreshFileReference(const QByteArray &value);
|
||||
void refreshStickerThumbFileReference();
|
||||
|
||||
|
@ -187,22 +199,22 @@ public:
|
|||
// (for example for displaying an external inline bot result)
|
||||
// and it has downloaded data, we can collect that data from it
|
||||
// to (this) received from the server "same" document.
|
||||
void collectLocalData(DocumentData *local);
|
||||
void collectLocalData(not_null<DocumentData*> local);
|
||||
|
||||
QString filename() const;
|
||||
QString mimeString() const;
|
||||
bool hasMimeType(QLatin1String mime) const;
|
||||
[[nodiscard]] QString filename() const;
|
||||
[[nodiscard]] QString mimeString() const;
|
||||
[[nodiscard]] bool hasMimeType(QLatin1String mime) const;
|
||||
void setMimeString(const QString &mime);
|
||||
|
||||
MediaKey mediaKey() const;
|
||||
Storage::Cache::Key cacheKey() const;
|
||||
uint8 cacheTag() const;
|
||||
[[nodiscard]] MediaKey mediaKey() const;
|
||||
[[nodiscard]] Storage::Cache::Key cacheKey() const;
|
||||
[[nodiscard]] uint8 cacheTag() const;
|
||||
|
||||
static QString ComposeNameString(
|
||||
[[nodiscard]] static QString ComposeNameString(
|
||||
const QString &filename,
|
||||
const QString &songTitle,
|
||||
const QString &songPerformer);
|
||||
QString composeNameString() const;
|
||||
[[nodiscard]] QString composeNameString() const;
|
||||
|
||||
~DocumentData();
|
||||
|
||||
|
@ -210,7 +222,6 @@ public:
|
|||
DocumentType type = FileDocument;
|
||||
QSize dimensions;
|
||||
int32 date = 0;
|
||||
ImagePtr thumb;
|
||||
int32 size = 0;
|
||||
|
||||
FileStatus status = FileReady;
|
||||
|
@ -225,6 +236,8 @@ private:
|
|||
|
||||
void destroyLoader(mtpFileLoader *newValue = nullptr) const;
|
||||
|
||||
[[nodiscard]] bool thumbnailEnoughForSticker() const;
|
||||
|
||||
// Two types of location: from MTProto by dc+access or from web by url
|
||||
int32 _dc = 0;
|
||||
uint64 _access = 0;
|
||||
|
@ -234,10 +247,12 @@ private:
|
|||
QString _mimeString;
|
||||
WebFileLocation _urlLocation;
|
||||
|
||||
ImagePtr _thumbnailInline;
|
||||
ImagePtr _thumbnail;
|
||||
std::unique_ptr<Image> _goodThumbnail;
|
||||
std::unique_ptr<Image> _replyPreview;
|
||||
Data::ReplyPreview _replyPreview;
|
||||
|
||||
not_null<AuthSession*> _session;
|
||||
not_null<Data::Session*> _owner;
|
||||
|
||||
FileLocation _location;
|
||||
QByteArray _data;
|
||||
|
|
|
@ -290,7 +290,7 @@ bool MediaPhoto::canBeGrouped() const {
|
|||
}
|
||||
|
||||
bool MediaPhoto::hasReplyPreview() const {
|
||||
return !_photo->thumb->isNull();
|
||||
return !_photo->isNull();
|
||||
}
|
||||
|
||||
Image *MediaPhoto::replyPreview() const {
|
||||
|
@ -378,7 +378,7 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
|||
QByteArray bytes;
|
||||
};
|
||||
const auto saveImageToCache = [&](
|
||||
const ImagePtr &image,
|
||||
not_null<Image*> image,
|
||||
SizeData size) {
|
||||
Expects(size.location != nullptr);
|
||||
|
||||
|
@ -435,9 +435,9 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
|||
continue;
|
||||
}
|
||||
if (size.letter == 's') {
|
||||
saveImageToCache(_photo->thumb, size);
|
||||
saveImageToCache(_photo->thumbnailSmall(), size);
|
||||
} else if (size.letter == 'm') {
|
||||
saveImageToCache(_photo->medium, size);
|
||||
saveImageToCache(_photo->thumbnail(), size);
|
||||
} else if (size.letter == 'x' && max < 1) {
|
||||
max = 1;
|
||||
maxSize = size;
|
||||
|
@ -450,7 +450,7 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
|||
}
|
||||
}
|
||||
if (maxSize.location) {
|
||||
saveImageToCache(_photo->full, maxSize);
|
||||
saveImageToCache(_photo->large(), maxSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -533,7 +533,7 @@ bool MediaFile::canBeGrouped() const {
|
|||
}
|
||||
|
||||
bool MediaFile::hasReplyPreview() const {
|
||||
return !_document->thumb->isNull();
|
||||
return _document->hasThumbnail();
|
||||
}
|
||||
|
||||
Image *MediaFile::replyPreview() const {
|
||||
|
@ -1017,9 +1017,9 @@ WebPageData *MediaWebPage::webpage() const {
|
|||
|
||||
bool MediaWebPage::hasReplyPreview() const {
|
||||
if (const auto document = MediaWebPage::document()) {
|
||||
return !document->thumb->isNull();
|
||||
return document->hasThumbnail();
|
||||
} else if (const auto photo = MediaWebPage::photo()) {
|
||||
return !photo->thumb->isNull();
|
||||
return !photo->isNull();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1080,9 +1080,9 @@ std::unique_ptr<Media> MediaGame::clone(not_null<HistoryItem*> parent) {
|
|||
|
||||
bool MediaGame::hasReplyPreview() const {
|
||||
if (const auto document = _game->document) {
|
||||
return !document->thumb->isNull();
|
||||
return document->hasThumbnail();
|
||||
} else if (const auto photo = _game->photo) {
|
||||
return !photo->thumb->isNull();
|
||||
return !photo->isNull();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1182,7 +1182,7 @@ const Invoice *MediaInvoice::invoice() const {
|
|||
|
||||
bool MediaInvoice::hasReplyPreview() const {
|
||||
if (const auto photo = _invoice.photo) {
|
||||
return !photo->thumb->isNull();
|
||||
return !photo->isNull();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -12,49 +12,41 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/image/image.h"
|
||||
#include "ui/image/image_source.h"
|
||||
#include "mainwidget.h"
|
||||
#include "auth_session.h"
|
||||
#include "core/application.h"
|
||||
|
||||
PhotoData::PhotoData(const PhotoId &id)
|
||||
: id(id) {
|
||||
PhotoData::PhotoData(not_null<Data::Session*> owner, PhotoId id)
|
||||
: id(id)
|
||||
, _owner(owner) {
|
||||
}
|
||||
|
||||
PhotoData::PhotoData(
|
||||
const PhotoId &id,
|
||||
const uint64 &access,
|
||||
const QByteArray &fileReference,
|
||||
TimeId date,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &medium,
|
||||
const ImagePtr &full)
|
||||
: id(id)
|
||||
, access(access)
|
||||
, date(date)
|
||||
, thumb(thumb)
|
||||
, medium(medium)
|
||||
, full(full) {
|
||||
Data::Session &PhotoData::owner() const {
|
||||
return *_owner;
|
||||
}
|
||||
|
||||
AuthSession &PhotoData::session() const {
|
||||
return _owner->session();
|
||||
}
|
||||
|
||||
void PhotoData::automaticLoad(
|
||||
Data::FileOrigin origin,
|
||||
const HistoryItem *item) {
|
||||
full->automaticLoad(origin, item);
|
||||
_large->automaticLoad(origin, item);
|
||||
}
|
||||
|
||||
void PhotoData::automaticLoadSettingsChanged() {
|
||||
full->automaticLoadSettingsChanged();
|
||||
_large->automaticLoadSettingsChanged();
|
||||
}
|
||||
|
||||
void PhotoData::download(Data::FileOrigin origin) {
|
||||
full->loadEvenCancelled(origin);
|
||||
Auth().data().notifyPhotoLayoutChanged(this);
|
||||
_large->loadEvenCancelled(origin);
|
||||
_owner->notifyPhotoLayoutChanged(this);
|
||||
}
|
||||
|
||||
bool PhotoData::loaded() const {
|
||||
bool wasLoading = loading();
|
||||
if (full->loaded()) {
|
||||
if (_large->loaded()) {
|
||||
if (wasLoading) {
|
||||
Auth().data().notifyPhotoLayoutChanged(this);
|
||||
_owner->notifyPhotoLayoutChanged(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -62,18 +54,18 @@ bool PhotoData::loaded() const {
|
|||
}
|
||||
|
||||
bool PhotoData::loading() const {
|
||||
return full->loading();
|
||||
return _large->loading();
|
||||
}
|
||||
|
||||
bool PhotoData::displayLoading() const {
|
||||
return full->loading()
|
||||
? full->displayLoading()
|
||||
return _large->loading()
|
||||
? _large->displayLoading()
|
||||
: (uploading() && !waitingForAlbum());
|
||||
}
|
||||
|
||||
void PhotoData::cancel() {
|
||||
full->cancel();
|
||||
Auth().data().notifyPhotoLayoutChanged(this);
|
||||
_large->cancel();
|
||||
_owner->notifyPhotoLayoutChanged(this);
|
||||
}
|
||||
|
||||
float64 PhotoData::progress() const {
|
||||
|
@ -83,7 +75,7 @@ float64 PhotoData::progress() const {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
return full->progress();
|
||||
return _large->progress();
|
||||
}
|
||||
|
||||
void PhotoData::setWaitingForAlbum() {
|
||||
|
@ -97,7 +89,7 @@ bool PhotoData::waitingForAlbum() const {
|
|||
}
|
||||
|
||||
int32 PhotoData::loadOffset() const {
|
||||
return full->loadOffset();
|
||||
return _large->loadOffset();
|
||||
}
|
||||
|
||||
bool PhotoData::uploading() const {
|
||||
|
@ -105,43 +97,42 @@ bool PhotoData::uploading() const {
|
|||
}
|
||||
|
||||
void PhotoData::unload() {
|
||||
// Forget thumb only when image cache limit exceeds.
|
||||
//thumb->unload();
|
||||
medium->unload();
|
||||
full->unload();
|
||||
_replyPreview = nullptr;
|
||||
// Forget thumbnail only when image cache limit exceeds.
|
||||
//_thumbnailInline->unload();
|
||||
_thumbnailSmall->unload();
|
||||
_thumbnail->unload();
|
||||
_large->unload();
|
||||
_replyPreview.clear();
|
||||
}
|
||||
|
||||
Image *PhotoData::getReplyPreview(Data::FileOrigin origin) {
|
||||
if (!_replyPreview && !thumb->isNull()) {
|
||||
const auto previewFromImage = [&](const ImagePtr &image) {
|
||||
if (!image->loaded()) {
|
||||
image->load(origin);
|
||||
return std::unique_ptr<Image>();
|
||||
}
|
||||
int w = image->width(), h = image->height();
|
||||
if (w <= 0) w = 1;
|
||||
if (h <= 0) h = 1;
|
||||
return std::make_unique<Image>(
|
||||
std::make_unique<Images::ImageSource>(
|
||||
(w > h
|
||||
? image->pix(
|
||||
origin,
|
||||
w * st::msgReplyBarSize.height() / h,
|
||||
st::msgReplyBarSize.height())
|
||||
: image->pix(origin, st::msgReplyBarSize.height())
|
||||
).toImage(),
|
||||
"PNG"));
|
||||
};
|
||||
if (thumb->isDelayedStorageImage()
|
||||
&& !full->isNull()
|
||||
&& !full->isDelayedStorageImage()) {
|
||||
_replyPreview = previewFromImage(full);
|
||||
} else {
|
||||
_replyPreview = previewFromImage(thumb);
|
||||
if (_replyPreview
|
||||
&& (_replyPreview.good() || !_thumbnailSmall->loaded())) {
|
||||
return _replyPreview.image();
|
||||
}
|
||||
if (_thumbnailSmall->isDelayedStorageImage()
|
||||
&& !_large->isNull()
|
||||
&& !_large->isDelayedStorageImage()
|
||||
&& _large->loaded()) {
|
||||
_replyPreview.prepare(
|
||||
_large.get(),
|
||||
origin,
|
||||
Images::Option(0));
|
||||
} else if (_thumbnailSmall->loaded()) {
|
||||
_replyPreview.prepare(
|
||||
_thumbnailSmall.get(),
|
||||
origin,
|
||||
Images::Option(0));
|
||||
} else {
|
||||
_thumbnailSmall->load(origin);
|
||||
if (_thumbnailInline) {
|
||||
_replyPreview.prepare(
|
||||
_thumbnailInline.get(),
|
||||
origin,
|
||||
Images::Option::Blurred);
|
||||
}
|
||||
}
|
||||
return _replyPreview.get();
|
||||
return _replyPreview.image();
|
||||
}
|
||||
|
||||
MTPInputPhoto PhotoData::mtpInput() const {
|
||||
|
@ -151,19 +142,88 @@ MTPInputPhoto PhotoData::mtpInput() const {
|
|||
MTP_bytes(fileReference));
|
||||
}
|
||||
|
||||
void PhotoData::collectLocalData(PhotoData *local) {
|
||||
if (local == this) return;
|
||||
void PhotoData::collectLocalData(not_null<PhotoData*> local) {
|
||||
if (local == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto copyImage = [](const ImagePtr &src, const ImagePtr &dst) {
|
||||
const auto copyImage = [&](const ImagePtr &src, const ImagePtr &dst) {
|
||||
if (const auto from = src->cacheKey()) {
|
||||
if (const auto to = dst->cacheKey()) {
|
||||
Auth().data().cache().copyIfEmpty(*from, *to);
|
||||
_owner->cache().copyIfEmpty(*from, *to);
|
||||
}
|
||||
}
|
||||
};
|
||||
copyImage(local->thumb, thumb);
|
||||
copyImage(local->medium, medium);
|
||||
copyImage(local->full, full);
|
||||
copyImage(local->_thumbnailSmall, _thumbnailSmall);
|
||||
copyImage(local->_thumbnail, _thumbnail);
|
||||
copyImage(local->_large, _large);
|
||||
}
|
||||
|
||||
bool PhotoData::isNull() const {
|
||||
return _large->isNull();
|
||||
}
|
||||
|
||||
void PhotoData::loadThumbnail(Data::FileOrigin origin) {
|
||||
_thumbnail->load(origin);
|
||||
}
|
||||
|
||||
void PhotoData::loadThumbnailSmall(Data::FileOrigin origin) {
|
||||
_thumbnailSmall->load(origin);
|
||||
}
|
||||
|
||||
Image *PhotoData::thumbnailInline() const {
|
||||
return _thumbnailInline ? _thumbnailInline.get() : nullptr;
|
||||
}
|
||||
|
||||
not_null<Image*> PhotoData::thumbnailSmall() const {
|
||||
return _thumbnailSmall.get();
|
||||
}
|
||||
|
||||
not_null<Image*> PhotoData::thumbnail() const {
|
||||
return _thumbnail.get();
|
||||
}
|
||||
|
||||
void PhotoData::load(Data::FileOrigin origin) {
|
||||
_large->load(origin);
|
||||
}
|
||||
|
||||
not_null<Image*> PhotoData::large() const {
|
||||
return _large.get();
|
||||
}
|
||||
|
||||
void PhotoData::updateImages(
|
||||
ImagePtr thumbnailInline,
|
||||
ImagePtr thumbnailSmall,
|
||||
ImagePtr thumbnail,
|
||||
ImagePtr large) {
|
||||
if (!thumbnailSmall || !thumbnail || !large) {
|
||||
return;
|
||||
}
|
||||
if (thumbnailInline && !_thumbnailInline) {
|
||||
_thumbnailInline = thumbnailInline;
|
||||
}
|
||||
const auto update = [](ImagePtr &was, ImagePtr now) {
|
||||
if (!was) {
|
||||
was = now;
|
||||
} else if (was->isDelayedStorageImage()) {
|
||||
if (const auto location = now->location(); !location.isNull()) {
|
||||
was->setDelayedStorageLocation(
|
||||
Data::FileOrigin(),
|
||||
location);
|
||||
}
|
||||
}
|
||||
};
|
||||
update(_thumbnailSmall, thumbnailSmall);
|
||||
update(_thumbnail, thumbnail);
|
||||
update(_large, large);
|
||||
}
|
||||
|
||||
int PhotoData::width() const {
|
||||
return _large->width();
|
||||
}
|
||||
|
||||
int PhotoData::height() const {
|
||||
return _large->height();
|
||||
}
|
||||
|
||||
void PhotoOpenClickHandler::onClickImpl() const {
|
||||
|
|
|
@ -9,17 +9,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "data/data_types.h"
|
||||
|
||||
class AuthSession;
|
||||
|
||||
namespace Data {
|
||||
class Session;
|
||||
} // namespace Data
|
||||
|
||||
class PhotoData {
|
||||
public:
|
||||
explicit PhotoData(const PhotoId &id);
|
||||
PhotoData(
|
||||
const PhotoId &id,
|
||||
const uint64 &access,
|
||||
const QByteArray &fileReference,
|
||||
TimeId date,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &medium,
|
||||
const ImagePtr &full);
|
||||
PhotoData(not_null<Data::Session*> owner, PhotoId id);
|
||||
|
||||
[[nodiscard]] Data::Session &owner() const;
|
||||
[[nodiscard]] AuthSession &session() const;
|
||||
|
||||
void automaticLoad(
|
||||
Data::FileOrigin origin,
|
||||
|
@ -27,35 +28,53 @@ public:
|
|||
void automaticLoadSettingsChanged();
|
||||
|
||||
void download(Data::FileOrigin origin);
|
||||
bool loaded() const;
|
||||
bool loading() const;
|
||||
bool displayLoading() const;
|
||||
[[nodiscard]] bool loaded() const;
|
||||
[[nodiscard]] bool loading() const;
|
||||
[[nodiscard]] bool displayLoading() const;
|
||||
void cancel();
|
||||
float64 progress() const;
|
||||
int32 loadOffset() const;
|
||||
bool uploading() const;
|
||||
[[nodiscard]] float64 progress() const;
|
||||
[[nodiscard]] int32 loadOffset() const;
|
||||
[[nodiscard]] bool uploading() const;
|
||||
|
||||
void setWaitingForAlbum();
|
||||
bool waitingForAlbum() const;
|
||||
[[nodiscard]] bool waitingForAlbum() const;
|
||||
|
||||
void unload();
|
||||
Image *getReplyPreview(Data::FileOrigin origin);
|
||||
[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
|
||||
|
||||
MTPInputPhoto mtpInput() const;
|
||||
[[nodiscard]] MTPInputPhoto mtpInput() const;
|
||||
|
||||
// When we have some client-side generated photo
|
||||
// (for example for displaying an external inline bot result)
|
||||
// and it has downloaded full image, we can collect image from it
|
||||
// to (this) received from the server "same" photo.
|
||||
void collectLocalData(PhotoData *local);
|
||||
void collectLocalData(not_null<PhotoData*> local);
|
||||
|
||||
bool isNull() const;
|
||||
|
||||
void loadThumbnail(Data::FileOrigin origin);
|
||||
void loadThumbnailSmall(Data::FileOrigin origin);
|
||||
Image *thumbnailInline() const;
|
||||
not_null<Image*> thumbnailSmall() const;
|
||||
not_null<Image*> thumbnail() const;
|
||||
|
||||
void load(Data::FileOrigin origin);
|
||||
not_null<Image*> large() const;
|
||||
|
||||
// For now they return size of the 'large' image.
|
||||
int width() const;
|
||||
int height() const;
|
||||
|
||||
void updateImages(
|
||||
ImagePtr thumbnailInline,
|
||||
ImagePtr thumbnailSmall,
|
||||
ImagePtr thumbnail,
|
||||
ImagePtr large);
|
||||
|
||||
PhotoId id = 0;
|
||||
uint64 access = 0;
|
||||
QByteArray fileReference;
|
||||
TimeId date = 0;
|
||||
ImagePtr thumb;
|
||||
ImagePtr medium;
|
||||
ImagePtr full;
|
||||
|
||||
PeerData *peer = nullptr; // for chat and channel photos connection
|
||||
// geo, caption
|
||||
|
@ -63,7 +82,14 @@ public:
|
|||
std::unique_ptr<Data::UploadState> uploadingData;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Image> _replyPreview;
|
||||
ImagePtr _thumbnailInline;
|
||||
ImagePtr _thumbnailSmall;
|
||||
ImagePtr _thumbnail;
|
||||
ImagePtr _large;
|
||||
|
||||
Data::ReplyPreview _replyPreview;
|
||||
|
||||
not_null<Data::Session*> _owner;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -57,23 +57,10 @@ using ViewElement = HistoryView::Element;
|
|||
// b: crop 320x320
|
||||
// c: crop 640x640
|
||||
// d: crop 1280x1280
|
||||
const auto ThumbLevels = QByteArray::fromRawData("isambcxydw", 10);
|
||||
const auto MediumLevels = QByteArray::fromRawData("mbcxasydwi", 10);
|
||||
const auto FullLevels = QByteArray::fromRawData("yxwmsdcbai", 10);
|
||||
|
||||
void UpdateImage(ImagePtr &old, ImagePtr now) {
|
||||
if (now->isNull()) {
|
||||
return;
|
||||
}
|
||||
if (old->isNull()) {
|
||||
old = now;
|
||||
} else if (old->isDelayedStorageImage()) {
|
||||
const auto location = now->location();
|
||||
if (!location.isNull()) {
|
||||
old->setDelayedStorageLocation(Data::FileOrigin(), location);
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto InlineLevels = QByteArray::fromRawData("i", 1);
|
||||
const auto SmallLevels = QByteArray::fromRawData("sambcxydwi", 10);
|
||||
const auto ThumbnailLevels = QByteArray::fromRawData("mbcxasydwi", 10);
|
||||
const auto LargeLevels = QByteArray::fromRawData("yxwmsdcbai", 10);
|
||||
|
||||
void CheckForSwitchInlineButton(not_null<HistoryItem*> item) {
|
||||
if (item->out() || !item->hasSwitchInlineButton()) {
|
||||
|
@ -121,22 +108,31 @@ QString ExtractUnavailableReason(const QString &restriction) {
|
|||
return QString();
|
||||
}
|
||||
|
||||
MTPPhotoSize FindDocumentThumb(const MTPDdocument &data) {
|
||||
MTPPhotoSize FindDocumentInlineThumbnail(const MTPDdocument &data) {
|
||||
const auto &thumbs = data.vthumbs.v;
|
||||
const auto i = ranges::find(
|
||||
thumbs,
|
||||
mtpc_photoStrippedSize,
|
||||
&MTPPhotoSize::type);
|
||||
return (i != thumbs.end())
|
||||
? (*i)
|
||||
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string("")));
|
||||
}
|
||||
|
||||
MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
|
||||
const auto area = [](const MTPPhotoSize &size) {
|
||||
static constexpr auto kInvalid = std::numeric_limits<int>::max();
|
||||
static constexpr auto kInvalid = 0;
|
||||
return size.match([](const MTPDphotoSizeEmpty &) {
|
||||
return kInvalid;
|
||||
}, [](const MTPDphotoStrippedSize &) {
|
||||
return kInvalid;
|
||||
}, [](const auto &data) {
|
||||
return (data.vw.v >= 90 || data.vh.v >= 90)
|
||||
? (data.vw.v * data.vh.v)
|
||||
: kInvalid;
|
||||
return (data.vw.v * data.vh.v);
|
||||
});
|
||||
};
|
||||
const auto &thumbs = data.vthumbs.v;
|
||||
const auto i = ranges::max_element(thumbs, std::greater<>(), area);
|
||||
return (i != thumbs.end())
|
||||
const auto i = ranges::max_element(thumbs, std::less<>(), area);
|
||||
return (i != thumbs.end() && area(*i) > 0)
|
||||
? (*i)
|
||||
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string("")));
|
||||
}
|
||||
|
@ -1609,20 +1605,19 @@ void Session::checkSelfDestructItems() {
|
|||
not_null<PhotoData*> Session::photo(PhotoId id) {
|
||||
auto i = _photos.find(id);
|
||||
if (i == _photos.end()) {
|
||||
i = _photos.emplace(id, std::make_unique<PhotoData>(id)).first;
|
||||
i = _photos.emplace(
|
||||
id,
|
||||
std::make_unique<PhotoData>(this, id)).first;
|
||||
}
|
||||
return i->second.get();
|
||||
}
|
||||
|
||||
not_null<PhotoData*> Session::processPhoto(const MTPPhoto &data) {
|
||||
switch (data.type()) {
|
||||
case mtpc_photo:
|
||||
return processPhoto(data.c_photo());
|
||||
|
||||
case mtpc_photoEmpty:
|
||||
return photo(data.c_photoEmpty().vid.v);
|
||||
}
|
||||
Unexpected("Type in Session::photo().");
|
||||
return data.match([&](const MTPDphoto &data) {
|
||||
return processPhoto(data);
|
||||
}, [&](const MTPDphotoEmpty &data) {
|
||||
return photo(data.vid.v);
|
||||
});
|
||||
}
|
||||
|
||||
not_null<PhotoData*> Session::processPhoto(const MTPDphoto &data) {
|
||||
|
@ -1634,50 +1629,44 @@ not_null<PhotoData*> Session::processPhoto(const MTPDphoto &data) {
|
|||
not_null<PhotoData*> Session::processPhoto(
|
||||
const MTPPhoto &data,
|
||||
const PreparedPhotoThumbs &thumbs) {
|
||||
auto thumb = (const QImage*)nullptr;
|
||||
auto medium = (const QImage*)nullptr;
|
||||
auto full = (const QImage*)nullptr;
|
||||
auto thumbLevel = -1;
|
||||
auto mediumLevel = -1;
|
||||
auto fullLevel = -1;
|
||||
for (auto i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) {
|
||||
const auto newThumbLevel = ThumbLevels.indexOf(i.key());
|
||||
const auto newMediumLevel = MediumLevels.indexOf(i.key());
|
||||
const auto newFullLevel = FullLevels.indexOf(i.key());
|
||||
if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) {
|
||||
continue;
|
||||
}
|
||||
if (thumbLevel < 0 || newThumbLevel < thumbLevel) {
|
||||
thumbLevel = newThumbLevel;
|
||||
thumb = &i.value();
|
||||
}
|
||||
if (mediumLevel < 0 || newMediumLevel < mediumLevel) {
|
||||
mediumLevel = newMediumLevel;
|
||||
medium = &i.value();
|
||||
}
|
||||
if (fullLevel < 0 || newFullLevel < fullLevel) {
|
||||
fullLevel = newFullLevel;
|
||||
full = &i.value();
|
||||
}
|
||||
}
|
||||
if (!thumb || !medium || !full) {
|
||||
return photo(0);
|
||||
}
|
||||
switch (data.type()) {
|
||||
case mtpc_photo:
|
||||
return photo(
|
||||
data.c_photo().vid.v,
|
||||
data.c_photo().vaccess_hash.v,
|
||||
data.c_photo().vfile_reference.v,
|
||||
data.c_photo().vdate.v,
|
||||
Images::Create(base::duplicate(*thumb), "JPG"),
|
||||
Images::Create(base::duplicate(*medium), "JPG"),
|
||||
Images::Create(base::duplicate(*full), "JPG"));
|
||||
Expects(!thumbs.empty());
|
||||
|
||||
case mtpc_photoEmpty:
|
||||
return photo(data.c_photoEmpty().vid.v);
|
||||
}
|
||||
Unexpected("Type in Session::photo() with prepared thumbs.");
|
||||
const auto find = [&](const QByteArray &levels) {
|
||||
const auto kInvalidIndex = int(levels.size());
|
||||
const auto level = [&](const auto &pair) {
|
||||
const auto letter = pair.first;
|
||||
const auto index = levels.indexOf(letter);
|
||||
return (index >= 0) ? index : kInvalidIndex;
|
||||
};
|
||||
const auto result = ranges::max_element(
|
||||
thumbs,
|
||||
std::greater<>(),
|
||||
level);
|
||||
return (level(*result) == kInvalidIndex) ? thumbs.end() : result;
|
||||
};
|
||||
const auto image = [&](const QByteArray &levels) {
|
||||
const auto i = find(levels);
|
||||
return (i == thumbs.end())
|
||||
? ImagePtr()
|
||||
: Images::Create(base::duplicate(i->second), "JPG");
|
||||
};
|
||||
const auto thumbnailInline = image(InlineLevels);
|
||||
const auto thumbnailSmall = image(SmallLevels);
|
||||
const auto thumbnail = image(ThumbnailLevels);
|
||||
const auto large = image(LargeLevels);
|
||||
return data.match([&](const MTPDphoto &data) {
|
||||
return photo(
|
||||
data.vid.v,
|
||||
data.vaccess_hash.v,
|
||||
data.vfile_reference.v,
|
||||
data.vdate.v,
|
||||
thumbnailInline,
|
||||
thumbnailSmall,
|
||||
thumbnail,
|
||||
large);
|
||||
}, [&](const MTPDphotoEmpty &data) {
|
||||
return photo(data.vid.v);
|
||||
});
|
||||
}
|
||||
|
||||
not_null<PhotoData*> Session::photo(
|
||||
|
@ -1685,31 +1674,29 @@ not_null<PhotoData*> Session::photo(
|
|||
const uint64 &access,
|
||||
const QByteArray &fileReference,
|
||||
TimeId date,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &medium,
|
||||
const ImagePtr &full) {
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnailSmall,
|
||||
const ImagePtr &thumbnail,
|
||||
const ImagePtr &large) {
|
||||
const auto result = photo(id);
|
||||
photoApplyFields(
|
||||
result,
|
||||
access,
|
||||
fileReference,
|
||||
date,
|
||||
thumb,
|
||||
medium,
|
||||
full);
|
||||
thumbnailInline,
|
||||
thumbnailSmall,
|
||||
thumbnail,
|
||||
large);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Session::photoConvert(
|
||||
not_null<PhotoData*> original,
|
||||
const MTPPhoto &data) {
|
||||
const auto id = [&] {
|
||||
switch (data.type()) {
|
||||
case mtpc_photo: return data.c_photo().vid.v;
|
||||
case mtpc_photoEmpty: return data.c_photoEmpty().vid.v;
|
||||
}
|
||||
Unexpected("Type in Session::photoConvert().");
|
||||
}();
|
||||
const auto id = data.match([](const auto &data) {
|
||||
return data.vid.v;
|
||||
});
|
||||
if (original->id != id) {
|
||||
auto i = _photos.find(id);
|
||||
if (i == _photos.end()) {
|
||||
|
@ -1732,23 +1719,26 @@ void Session::photoConvert(
|
|||
|
||||
PhotoData *Session::photoFromWeb(
|
||||
const MTPWebDocument &data,
|
||||
ImagePtr thumb,
|
||||
ImagePtr thumbnailSmall,
|
||||
bool willBecomeNormal) {
|
||||
const auto full = Images::Create(data);
|
||||
if (full->isNull()) {
|
||||
const auto large = Images::Create(data);
|
||||
const auto thumbnailInline = ImagePtr();
|
||||
if (large->isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto medium = ImagePtr();
|
||||
auto thumbnail = large;
|
||||
if (willBecomeNormal) {
|
||||
const auto width = full->width();
|
||||
const auto height = full->height();
|
||||
if (thumb->isNull()) {
|
||||
const auto width = large->width();
|
||||
const auto height = large->height();
|
||||
if (thumbnailSmall->isNull()) {
|
||||
auto thumbsize = shrinkToKeepAspect(width, height, 100, 100);
|
||||
thumb = Images::Create(thumbsize.width(), thumbsize.height());
|
||||
thumbnailSmall = Images::Create(thumbsize.width(), thumbsize.height());
|
||||
}
|
||||
|
||||
auto mediumsize = shrinkToKeepAspect(width, height, 320, 320);
|
||||
medium = Images::Create(mediumsize.width(), mediumsize.height());
|
||||
thumbnail = Images::Create(mediumsize.width(), mediumsize.height());
|
||||
} else if (thumbnailSmall->isNull()) {
|
||||
thumbnailSmall = large;
|
||||
}
|
||||
|
||||
return photo(
|
||||
|
@ -1756,9 +1746,10 @@ PhotoData *Session::photoFromWeb(
|
|||
uint64(0),
|
||||
QByteArray(),
|
||||
unixtime(),
|
||||
thumb,
|
||||
medium,
|
||||
full);
|
||||
thumbnailInline,
|
||||
thumbnailSmall,
|
||||
thumbnail,
|
||||
large);
|
||||
}
|
||||
|
||||
void Session::photoApplyFields(
|
||||
|
@ -1772,48 +1763,42 @@ void Session::photoApplyFields(
|
|||
void Session::photoApplyFields(
|
||||
not_null<PhotoData*> photo,
|
||||
const MTPDphoto &data) {
|
||||
auto thumb = (const MTPPhotoSize*)nullptr;
|
||||
auto medium = (const MTPPhotoSize*)nullptr;
|
||||
auto full = (const MTPPhotoSize*)nullptr;
|
||||
auto thumbLevel = -1;
|
||||
auto mediumLevel = -1;
|
||||
auto fullLevel = -1;
|
||||
for (const auto &sizeData : data.vsizes.v) {
|
||||
const auto sizeLetter = sizeData.match([](MTPDphotoSizeEmpty) {
|
||||
return char(0);
|
||||
}, [](const auto &size) {
|
||||
return size.vtype.v.isEmpty() ? char(0) : size.vtype.v[0];
|
||||
});
|
||||
if (!sizeLetter) continue;
|
||||
|
||||
const auto newThumbLevel = ThumbLevels.indexOf(sizeLetter);
|
||||
const auto newMediumLevel = MediumLevels.indexOf(sizeLetter);
|
||||
const auto newFullLevel = FullLevels.indexOf(sizeLetter);
|
||||
if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) {
|
||||
continue;
|
||||
}
|
||||
if (thumbLevel < 0 || newThumbLevel < thumbLevel) {
|
||||
thumbLevel = newThumbLevel;
|
||||
thumb = &sizeData;
|
||||
}
|
||||
if (mediumLevel < 0 || newMediumLevel < mediumLevel) {
|
||||
mediumLevel = newMediumLevel;
|
||||
medium = &sizeData;
|
||||
}
|
||||
if (fullLevel < 0 || newFullLevel < fullLevel) {
|
||||
fullLevel = newFullLevel;
|
||||
full = &sizeData;
|
||||
}
|
||||
}
|
||||
if (thumb && medium && full) {
|
||||
const auto &sizes = data.vsizes.v;
|
||||
const auto find = [&](const QByteArray &levels) {
|
||||
const auto kInvalidIndex = int(levels.size());
|
||||
const auto level = [&](const MTPPhotoSize &size) {
|
||||
const auto letter = size.match([](const MTPDphotoSizeEmpty &) {
|
||||
return char(0);
|
||||
}, [](const auto &size) {
|
||||
return size.vtype.v.isEmpty() ? char(0) : size.vtype.v[0];
|
||||
});
|
||||
const auto index = levels.indexOf(letter);
|
||||
return (index >= 0) ? index : kInvalidIndex;
|
||||
};
|
||||
const auto result = ranges::max_element(
|
||||
sizes,
|
||||
std::greater<>(),
|
||||
level);
|
||||
return (level(*result) == kInvalidIndex) ? sizes.end() : result;
|
||||
};
|
||||
const auto image = [&](const QByteArray &levels) {
|
||||
const auto i = find(levels);
|
||||
return (i == sizes.end()) ? ImagePtr() : App::image(*i);
|
||||
};
|
||||
const auto thumbnailInline = image(InlineLevels);
|
||||
const auto thumbnailSmall = image(SmallLevels);
|
||||
const auto thumbnail = image(ThumbnailLevels);
|
||||
const auto large = image(LargeLevels);
|
||||
if (thumbnailSmall && thumbnail && large) {
|
||||
photoApplyFields(
|
||||
photo,
|
||||
data.vaccess_hash.v,
|
||||
data.vfile_reference.v,
|
||||
data.vdate.v,
|
||||
App::image(*thumb),
|
||||
App::image(*medium),
|
||||
App::image(*full));
|
||||
thumbnailInline,
|
||||
thumbnailSmall,
|
||||
thumbnail,
|
||||
large);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1822,18 +1807,21 @@ void Session::photoApplyFields(
|
|||
const uint64 &access,
|
||||
const QByteArray &fileReference,
|
||||
TimeId date,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &medium,
|
||||
const ImagePtr &full) {
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnailSmall,
|
||||
const ImagePtr &thumbnail,
|
||||
const ImagePtr &large) {
|
||||
if (!date) {
|
||||
return;
|
||||
}
|
||||
photo->access = access;
|
||||
photo->fileReference = fileReference;
|
||||
photo->date = date;
|
||||
UpdateImage(photo->thumb, thumb);
|
||||
UpdateImage(photo->medium, medium);
|
||||
UpdateImage(photo->full, full);
|
||||
photo->updateImages(
|
||||
thumbnailInline,
|
||||
thumbnailSmall,
|
||||
thumbnail,
|
||||
large);
|
||||
}
|
||||
|
||||
not_null<DocumentData*> Session::document(DocumentId id) {
|
||||
|
@ -1841,7 +1829,7 @@ not_null<DocumentData*> Session::document(DocumentId id) {
|
|||
if (i == _documents.cend()) {
|
||||
i = _documents.emplace(
|
||||
id,
|
||||
std::make_unique<DocumentData>(id, _session)).first;
|
||||
std::make_unique<DocumentData>(this, id)).first;
|
||||
}
|
||||
return i->second.get();
|
||||
}
|
||||
|
@ -1879,6 +1867,7 @@ not_null<DocumentData*> Session::processDocument(
|
|||
fields.vdate.v,
|
||||
fields.vattributes.v,
|
||||
qs(fields.vmime_type),
|
||||
ImagePtr(),
|
||||
Images::Create(std::move(thumb), "JPG"),
|
||||
fields.vdc_id.v,
|
||||
fields.vsize.v,
|
||||
|
@ -1895,7 +1884,8 @@ not_null<DocumentData*> Session::document(
|
|||
TimeId date,
|
||||
const QVector<MTPDocumentAttribute> &attributes,
|
||||
const QString &mime,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnail,
|
||||
int32 dc,
|
||||
int32 size,
|
||||
const StorageImageLocation &thumbLocation) {
|
||||
|
@ -1907,7 +1897,8 @@ not_null<DocumentData*> Session::document(
|
|||
date,
|
||||
attributes,
|
||||
mime,
|
||||
thumb,
|
||||
thumbnailInline,
|
||||
thumbnail,
|
||||
dc,
|
||||
size,
|
||||
thumbLocation);
|
||||
|
@ -1979,6 +1970,7 @@ DocumentData *Session::documentFromWeb(
|
|||
unixtime(),
|
||||
data.vattributes.v,
|
||||
data.vmime_type.v,
|
||||
ImagePtr(),
|
||||
thumb,
|
||||
MTP::maindc(),
|
||||
int32(0), // data.vsize.v
|
||||
|
@ -2000,6 +1992,7 @@ DocumentData *Session::documentFromWeb(
|
|||
unixtime(),
|
||||
data.vattributes.v,
|
||||
data.vmime_type.v,
|
||||
ImagePtr(),
|
||||
thumb,
|
||||
MTP::maindc(),
|
||||
int32(0), // data.vsize.v
|
||||
|
@ -2019,7 +2012,8 @@ void Session::documentApplyFields(
|
|||
void Session::documentApplyFields(
|
||||
not_null<DocumentData*> document,
|
||||
const MTPDdocument &data) {
|
||||
const auto thumb = FindDocumentThumb(data);
|
||||
const auto thumbnailInline = FindDocumentInlineThumbnail(data);
|
||||
const auto thumbnail = FindDocumentThumbnail(data);
|
||||
documentApplyFields(
|
||||
document,
|
||||
data.vaccess_hash.v,
|
||||
|
@ -2027,10 +2021,11 @@ void Session::documentApplyFields(
|
|||
data.vdate.v,
|
||||
data.vattributes.v,
|
||||
qs(data.vmime_type),
|
||||
App::image(thumb),
|
||||
App::image(thumbnailInline),
|
||||
App::image(thumbnail),
|
||||
data.vdc_id.v,
|
||||
data.vsize.v,
|
||||
StorageImageLocation::FromMTP(thumb));
|
||||
StorageImageLocation::FromMTP(thumbnail));
|
||||
}
|
||||
|
||||
void Session::documentApplyFields(
|
||||
|
@ -2040,7 +2035,8 @@ void Session::documentApplyFields(
|
|||
TimeId date,
|
||||
const QVector<MTPDocumentAttribute> &attributes,
|
||||
const QString &mime,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnail,
|
||||
int32 dc,
|
||||
int32 size,
|
||||
const StorageImageLocation &thumbLocation) {
|
||||
|
@ -2053,13 +2049,7 @@ void Session::documentApplyFields(
|
|||
}
|
||||
document->date = date;
|
||||
document->setMimeString(mime);
|
||||
if (!thumb->isNull()
|
||||
&& (document->thumb->isNull()
|
||||
|| (document->sticker()
|
||||
&& (document->thumb->width() < thumb->width()
|
||||
|| document->thumb->height() < thumb->height())))) {
|
||||
document->thumb = thumb;
|
||||
}
|
||||
document->updateThumbnails(thumbnailInline, thumbnail);
|
||||
document->size = size;
|
||||
document->recountIsImage();
|
||||
if (document->sticker()
|
||||
|
@ -3085,7 +3075,7 @@ void Session::setWallpapers(const QVector<MTPWallPaper> &data, int32 hash) {
|
|||
0ULL, // access_hash
|
||||
MTPDwallPaper::Flags(0),
|
||||
QString(), // slug
|
||||
defaultBackground
|
||||
defaultBackground.get()
|
||||
});
|
||||
}
|
||||
const auto oldBackground = Images::Create(
|
||||
|
@ -3097,7 +3087,7 @@ void Session::setWallpapers(const QVector<MTPWallPaper> &data, int32 hash) {
|
|||
0ULL, // access_hash
|
||||
MTPDwallPaper::Flags(0),
|
||||
QString(), // slug
|
||||
oldBackground
|
||||
oldBackground.get()
|
||||
});
|
||||
}
|
||||
for (const auto &paper : data) {
|
||||
|
@ -3109,7 +3099,7 @@ void Session::setWallpapers(const QVector<MTPWallPaper> &data, int32 hash) {
|
|||
paper.vaccess_hash.v,
|
||||
paper.vflags.v,
|
||||
qs(paper.vslug),
|
||||
document->thumb,
|
||||
document->thumbnail(),
|
||||
document,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -342,15 +342,16 @@ public:
|
|||
const uint64 &access,
|
||||
const QByteArray &fileReference,
|
||||
TimeId date,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &medium,
|
||||
const ImagePtr &full);
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnailSmall,
|
||||
const ImagePtr &thumbnail,
|
||||
const ImagePtr &large);
|
||||
void photoConvert(
|
||||
not_null<PhotoData*> original,
|
||||
const MTPPhoto &data);
|
||||
[[nodiscard]] PhotoData *photoFromWeb(
|
||||
const MTPWebDocument &data,
|
||||
ImagePtr thumb = ImagePtr(),
|
||||
ImagePtr thumbnailSmall = ImagePtr(),
|
||||
bool willBecomeNormal = false);
|
||||
|
||||
[[nodiscard]] not_null<DocumentData*> document(DocumentId id);
|
||||
|
@ -366,7 +367,8 @@ public:
|
|||
TimeId date,
|
||||
const QVector<MTPDocumentAttribute> &attributes,
|
||||
const QString &mime,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnail,
|
||||
int32 dc,
|
||||
int32 size,
|
||||
const StorageImageLocation &thumbLocation);
|
||||
|
@ -571,9 +573,10 @@ private:
|
|||
const uint64 &access,
|
||||
const QByteArray &fileReference,
|
||||
TimeId date,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &medium,
|
||||
const ImagePtr &full);
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnailSmall,
|
||||
const ImagePtr &thumbnail,
|
||||
const ImagePtr &large);
|
||||
|
||||
void documentApplyFields(
|
||||
not_null<DocumentData*> document,
|
||||
|
@ -588,7 +591,8 @@ private:
|
|||
TimeId date,
|
||||
const QVector<MTPDocumentAttribute> &attributes,
|
||||
const QString &mime,
|
||||
const ImagePtr &thumb,
|
||||
const ImagePtr &thumbnailInline,
|
||||
const ImagePtr &thumbnail,
|
||||
int32 dc,
|
||||
int32 size,
|
||||
const StorageImageLocation &thumbLocation);
|
||||
|
|
|
@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_types.h"
|
||||
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "ui/image/image_source.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "storage/cache/storage_cache_types.h"
|
||||
#include "base/openssl_help.h"
|
||||
|
@ -30,6 +32,20 @@ constexpr auto kGeoPointCacheMask = 0x000000FFFFFFFFFFULL;
|
|||
|
||||
} // namespace
|
||||
|
||||
struct ReplyPreview::Data {
|
||||
Data(std::unique_ptr<Images::Source> &&source, bool good);
|
||||
|
||||
Image image;
|
||||
bool good = false;
|
||||
};
|
||||
|
||||
ReplyPreview::Data::Data(
|
||||
std::unique_ptr<Images::Source> &&source,
|
||||
bool good)
|
||||
: image(std::move(source))
|
||||
, good(good) {
|
||||
}
|
||||
|
||||
Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id) {
|
||||
return Storage::Cache::Key{
|
||||
Data::kDocumentCacheTag | (uint64(dcId) & Data::kDocumentCacheMask),
|
||||
|
@ -98,6 +114,63 @@ Storage::Cache::Key GeoPointCacheKey(const GeoPointLocation &location) {
|
|||
};
|
||||
}
|
||||
|
||||
ReplyPreview::ReplyPreview() = default;
|
||||
|
||||
ReplyPreview::ReplyPreview(ReplyPreview &&other) = default;
|
||||
|
||||
ReplyPreview &ReplyPreview::operator=(ReplyPreview &&other) = default;
|
||||
|
||||
ReplyPreview::~ReplyPreview() = default;
|
||||
|
||||
void ReplyPreview::prepare(
|
||||
not_null<Image*> image,
|
||||
FileOrigin origin,
|
||||
Images::Options options) {
|
||||
int w = image->width(), h = image->height();
|
||||
if (w <= 0) w = 1;
|
||||
if (h <= 0) h = 1;
|
||||
auto thumbSize = (w > h)
|
||||
? QSize(
|
||||
w * st::msgReplyBarSize.height() / h,
|
||||
st::msgReplyBarSize.height())
|
||||
: QSize(
|
||||
st::msgReplyBarSize.height(),
|
||||
h * st::msgReplyBarSize.height() / w);
|
||||
thumbSize *= cIntRetinaFactor();
|
||||
const auto prepareOptions = Images::Option::Smooth
|
||||
| Images::Option::TransparentBackground
|
||||
| options;
|
||||
auto outerSize = st::msgReplyBarSize.height();
|
||||
auto bitmap = image->pixNoCache(
|
||||
origin,
|
||||
thumbSize.width(),
|
||||
thumbSize.height(),
|
||||
prepareOptions,
|
||||
outerSize,
|
||||
outerSize);
|
||||
_data = std::make_unique<ReplyPreview::Data>(
|
||||
std::make_unique<Images::ImageSource>(
|
||||
bitmap.toImage(),
|
||||
"PNG"),
|
||||
((options & Images::Option::Blurred) == 0));
|
||||
}
|
||||
|
||||
void ReplyPreview::clear() {
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
Image *ReplyPreview::image() const {
|
||||
return _data ? &_data->image : nullptr;
|
||||
}
|
||||
|
||||
bool ReplyPreview::good() const {
|
||||
return !empty() && _data->good;
|
||||
}
|
||||
|
||||
bool ReplyPreview::empty() const {
|
||||
return !_data;
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
void AudioMsgId::setTypeFromAudio() {
|
||||
|
|
|
@ -23,6 +23,11 @@ namespace Ui {
|
|||
class InputField;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Images {
|
||||
enum class Option;
|
||||
using Options = base::flags<Option>;
|
||||
} // namespace Images
|
||||
|
||||
class StorageImageLocation;
|
||||
class WebFileLocation;
|
||||
struct GeoPointLocation;
|
||||
|
@ -50,6 +55,35 @@ constexpr auto kVoiceMessageCacheTag = uint8(0x03);
|
|||
constexpr auto kVideoMessageCacheTag = uint8(0x04);
|
||||
constexpr auto kAnimationCacheTag = uint8(0x05);
|
||||
|
||||
struct FileOrigin;
|
||||
|
||||
class ReplyPreview {
|
||||
public:
|
||||
ReplyPreview();
|
||||
ReplyPreview(ReplyPreview &&other);
|
||||
ReplyPreview &operator=(ReplyPreview &&other);
|
||||
~ReplyPreview();
|
||||
|
||||
void prepare(
|
||||
not_null<Image*> image,
|
||||
FileOrigin origin,
|
||||
Images::Options options);
|
||||
void clear();
|
||||
|
||||
[[nodiscard]] Image *image() const;
|
||||
[[nodiscard]] bool good() const;
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return !empty();
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data;
|
||||
std::unique_ptr<Data> _data;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
||||
struct MessageGroupId {
|
||||
|
@ -273,7 +307,7 @@ using PollId = uint64;
|
|||
using WallPaperId = uint64;
|
||||
constexpr auto CancelledWebPageId = WebPageId(0xFFFFFFFFFFFFFFFFULL);
|
||||
|
||||
using PreparedPhotoThumbs = QMap<char, QImage>;
|
||||
using PreparedPhotoThumbs = base::flat_map<char, QImage>;
|
||||
|
||||
// [0] == -1 -- counting, [0] == -2 -- could not count
|
||||
using VoiceWaveform = QVector<signed char>;
|
||||
|
|
|
@ -63,7 +63,7 @@ WebPageCollage ExtractCollage(
|
|||
for (const auto &item : items) {
|
||||
const auto good = item.match([&](const MTPDpageBlockPhoto &data) {
|
||||
const auto photo = storage.photo(data.vphoto_id.v);
|
||||
if (photo->full->isNull()) {
|
||||
if (photo->isNull()) {
|
||||
return false;
|
||||
}
|
||||
result.items.push_back(photo);
|
||||
|
@ -231,12 +231,12 @@ void WebPageData::replaceDocumentGoodThumbnail() {
|
|||
if (!document || !photo || !document->goodThumbnail()) {
|
||||
return;
|
||||
}
|
||||
const auto &location = photo->full->location();
|
||||
const auto &location = photo->large()->location();
|
||||
if (!location.isNull()) {
|
||||
document->replaceGoodThumbnail(
|
||||
std::make_unique<Images::StorageSource>(
|
||||
location,
|
||||
photo->full->bytesSize()));
|
||||
photo->large()->bytesSize()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1074,7 +1074,7 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
}
|
||||
|
||||
void InnerWidget::savePhotoToFile(PhotoData *photo) {
|
||||
if (!photo || !photo->date || !photo->loaded()) {
|
||||
if (!photo || photo->isNull() || !photo->loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1086,7 +1086,7 @@ void InnerWidget::savePhotoToFile(PhotoData *photo) {
|
|||
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
|
||||
crl::guard(this, [=](const QString &result) {
|
||||
if (!result.isEmpty()) {
|
||||
photo->full->pix(Data::FileOrigin()).toImage().save(result, "JPG");
|
||||
photo->large()->original().save(result, "JPG");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -1096,9 +1096,9 @@ void InnerWidget::saveDocumentToFile(DocumentData *document) {
|
|||
}
|
||||
|
||||
void InnerWidget::copyContextImage(PhotoData *photo) {
|
||||
if (!photo || !photo->date || !photo->loaded()) return;
|
||||
if (!photo || photo->isNull() || !photo->loaded()) return;
|
||||
|
||||
QApplication::clipboard()->setPixmap(photo->full->pix(Data::FileOrigin()));
|
||||
QApplication::clipboard()->setImage(photo->large()->original());
|
||||
}
|
||||
|
||||
void InnerWidget::copySelectedText() {
|
||||
|
|
|
@ -1771,7 +1771,7 @@ void HistoryInner::copySelectedText() {
|
|||
}
|
||||
|
||||
void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
|
||||
if (!photo->date || !photo->loaded()) return;
|
||||
if (photo->isNull() || !photo->loaded()) return;
|
||||
|
||||
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
|
||||
FileDialog::GetWritePath(
|
||||
|
@ -1783,15 +1783,15 @@ void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
|
|||
qsl(".jpg")),
|
||||
crl::guard(this, [=](const QString &result) {
|
||||
if (!result.isEmpty()) {
|
||||
photo->full->pix(Data::FileOrigin()).toImage().save(result, "JPG");
|
||||
photo->large()->original().save(result, "JPG");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void HistoryInner::copyContextImage(not_null<PhotoData*> photo) {
|
||||
if (!photo->date || !photo->loaded()) return;
|
||||
if (photo->isNull() || !photo->loaded()) return;
|
||||
|
||||
QApplication::clipboard()->setPixmap(photo->full->pix(Data::FileOrigin()));
|
||||
QApplication::clipboard()->setImage(photo->large()->original());
|
||||
}
|
||||
|
||||
void HistoryInner::showStickerPackInfo(not_null<DocumentData*> document) {
|
||||
|
|
|
@ -6361,7 +6361,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
|||
if (drawWebPagePreview) {
|
||||
auto previewLeft = st::historyReplySkip + st::webPageLeft;
|
||||
p.fillRect(st::historyReplySkip, backy + st::msgReplyPadding.top(), st::webPageBar, st::msgReplyBarSize.height(), st::msgInReplyBarColor);
|
||||
if ((_previewData->photo && !_previewData->photo->thumb->isNull()) || (_previewData->document && !_previewData->document->thumb->isNull())) {
|
||||
if ((_previewData->photo && !_previewData->photo->isNull()) || (_previewData->document && _previewData->document->hasThumbnail())) {
|
||||
const auto preview = _previewData->photo
|
||||
? _previewData->photo->getReplyPreview(Data::FileOrigin())
|
||||
: _previewData->document->getReplyPreview(Data::FileOrigin());
|
||||
|
|
|
@ -69,12 +69,13 @@ void HistoryDocument::createComponents(bool caption) {
|
|||
mask |= HistoryDocumentVoice::Bit();
|
||||
} else {
|
||||
mask |= HistoryDocumentNamed::Bit();
|
||||
if (!_data->isSong()
|
||||
&& !_data->thumb->isNull()
|
||||
&& _data->thumb->width()
|
||||
&& _data->thumb->height()
|
||||
&& !Data::IsExecutableName(_data->filename())) {
|
||||
mask |= HistoryDocumentThumbed::Bit();
|
||||
if (const auto thumb = _data->thumbnail()) {
|
||||
if (!_data->isSong()
|
||||
&& thumb->width()
|
||||
&& thumb->height()
|
||||
&& !Data::IsExecutableName(_data->filename())) {
|
||||
mask |= HistoryDocumentThumbed::Bit();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (caption) {
|
||||
|
@ -117,9 +118,9 @@ QSize HistoryDocument::countOptimalSize() {
|
|||
}
|
||||
auto thumbed = Get<HistoryDocumentThumbed>();
|
||||
if (thumbed) {
|
||||
_data->thumb->load(_realParent->fullId());
|
||||
auto tw = ConvertScale(_data->thumb->width());
|
||||
auto th = ConvertScale(_data->thumb->height());
|
||||
_data->loadThumbnail(_realParent->fullId());
|
||||
auto tw = ConvertScale(_data->thumbnail()->width());
|
||||
auto th = ConvertScale(_data->thumbnail()->height());
|
||||
if (tw > th) {
|
||||
thumbed->_thumbw = (tw * st::msgFileThumbSize) / th;
|
||||
} else {
|
||||
|
@ -232,10 +233,12 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection,
|
|||
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
|
||||
QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top() - topMinus, st::msgFileThumbSize, st::msgFileThumbSize, width()));
|
||||
QPixmap thumb;
|
||||
if (loaded) {
|
||||
thumb = _data->thumb->pixSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
||||
} else {
|
||||
thumb = _data->thumb->pixBlurredSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
||||
if (const auto normal = _data->thumbnail()) {
|
||||
if (normal->loaded()) {
|
||||
thumb = normal->pixSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
||||
thumb = blurred->pixBlurredSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
||||
}
|
||||
}
|
||||
p.drawPixmap(rthumb.topLeft(), thumb);
|
||||
if (selected) {
|
||||
|
@ -528,7 +531,7 @@ TextState HistoryDocument::textState(QPoint point, StateRequest request) const {
|
|||
painth -= st::msgPadding.bottom();
|
||||
}
|
||||
}
|
||||
if (QRect(0, 0, width(), painth).contains(point) && !_data->loading() && !_data->uploading() && _data->isValid()) {
|
||||
if (QRect(0, 0, width(), painth).contains(point) && !_data->loading() && !_data->uploading() && !_data->isNull()) {
|
||||
result.link = _openl;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ HistoryGif::HistoryGif(
|
|||
setStatusSize(FileStatusSizeReady);
|
||||
|
||||
_caption = createCaption(item);
|
||||
_data->thumb->load(item->fullId());
|
||||
_data->loadThumbnail(item->fullId());
|
||||
}
|
||||
|
||||
QSize HistoryGif::countOptimalSize() {
|
||||
|
@ -89,8 +89,8 @@ QSize HistoryGif::countOptimalSize() {
|
|||
} else {
|
||||
tw = ConvertScale(_data->dimensions.width()), th = ConvertScale(_data->dimensions.height());
|
||||
if (!tw || !th) {
|
||||
tw = ConvertScale(_data->thumb->width());
|
||||
th = ConvertScale(_data->thumb->height());
|
||||
tw = ConvertScale(_data->thumbnail()->width());
|
||||
th = ConvertScale(_data->thumbnail()->height());
|
||||
}
|
||||
}
|
||||
const auto maxSize = _data->isVideoMessage()
|
||||
|
@ -147,8 +147,8 @@ QSize HistoryGif::countCurrentSize(int newWidth) {
|
|||
} else {
|
||||
tw = ConvertScale(_data->dimensions.width()), th = ConvertScale(_data->dimensions.height());
|
||||
if (!tw || !th) {
|
||||
tw = ConvertScale(_data->thumb->width());
|
||||
th = ConvertScale(_data->thumb->height());
|
||||
tw = ConvertScale(_data->thumbnail()->width());
|
||||
th = ConvertScale(_data->thumbnail()->height());
|
||||
}
|
||||
}
|
||||
const auto maxSize = _data->isVideoMessage()
|
||||
|
@ -347,7 +347,13 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
|
|||
if (good) {
|
||||
good->load({});
|
||||
}
|
||||
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
|
||||
if (const auto normal = _data->thumbnail()) {
|
||||
if (normal->loaded()) {
|
||||
p.drawPixmap(rthumb.topLeft(), _data->thumbnail()->pixSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
|
||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
||||
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,11 @@ void HistoryPhoto::create(FullMsgId contextId, PeerData *chat) {
|
|||
std::make_shared<PhotoOpenClickHandler>(_data, contextId, chat),
|
||||
std::make_shared<PhotoSaveClickHandler>(_data, contextId, chat),
|
||||
std::make_shared<PhotoCancelClickHandler>(_data, contextId, chat));
|
||||
_data->thumb->load(contextId);
|
||||
if (!_data->thumbnailInline()
|
||||
&& !_data->loaded()
|
||||
&& !_data->thumbnail()->loaded()) {
|
||||
_data->thumbnailSmall()->load(contextId);
|
||||
}
|
||||
}
|
||||
|
||||
QSize HistoryPhoto::countOptimalSize() {
|
||||
|
@ -74,8 +78,8 @@ QSize HistoryPhoto::countOptimalSize() {
|
|||
auto maxWidth = 0;
|
||||
auto minHeight = 0;
|
||||
|
||||
auto tw = ConvertScale(_data->full->width());
|
||||
auto th = ConvertScale(_data->full->height());
|
||||
auto tw = ConvertScale(_data->width());
|
||||
auto th = ConvertScale(_data->height());
|
||||
if (!tw || !th) {
|
||||
tw = th = 1;
|
||||
}
|
||||
|
@ -106,7 +110,7 @@ QSize HistoryPhoto::countOptimalSize() {
|
|||
}
|
||||
|
||||
QSize HistoryPhoto::countCurrentSize(int newWidth) {
|
||||
int tw = ConvertScale(_data->full->width()), th = ConvertScale(_data->full->height());
|
||||
int tw = ConvertScale(_data->width()), th = ConvertScale(_data->height());
|
||||
if (tw > st::maxMediaSize) {
|
||||
th = (st::maxMediaSize * th) / tw;
|
||||
tw = st::maxMediaSize;
|
||||
|
@ -169,9 +173,19 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim
|
|||
|
||||
auto rthumb = rtlrect(paintx, painty, paintw, painth, width());
|
||||
if (_serviceWidth > 0) {
|
||||
const auto pix = loaded
|
||||
? _data->full->pixCircled(_realParent->fullId(), _pixw, _pixh)
|
||||
: _data->thumb->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
||||
const auto pix = [&] {
|
||||
if (loaded) {
|
||||
return _data->large()->pixCircled(_realParent->fullId(), _pixw, _pixh);
|
||||
} else if (_data->thumbnail()->loaded()) {
|
||||
return _data->thumbnail()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
||||
} else if (_data->thumbnailSmall()->loaded()) {
|
||||
return _data->thumbnailSmall()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
||||
return blurred->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh);
|
||||
} else {
|
||||
return QPixmap();
|
||||
}
|
||||
}();
|
||||
p.drawPixmap(rthumb.topLeft(), pix);
|
||||
} else {
|
||||
if (bubble) {
|
||||
|
@ -189,9 +203,19 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim
|
|||
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
|
||||
auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
|
||||
| ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
|
||||
const auto pix = loaded
|
||||
? _data->full->pixSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners)
|
||||
: _data->thumb->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||
const auto pix = [&] {
|
||||
if (loaded) {
|
||||
return _data->large()->pixSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||
} else if (_data->thumbnail()->loaded()) {
|
||||
return _data->thumbnail()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||
} else if (_data->thumbnailSmall()->loaded()) {
|
||||
return _data->thumbnailSmall()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
||||
return blurred->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners);
|
||||
} else {
|
||||
return QPixmap();
|
||||
}
|
||||
}();
|
||||
p.drawPixmap(rthumb.topLeft(), pix);
|
||||
if (selected) {
|
||||
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
|
||||
|
@ -224,7 +248,7 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim
|
|||
auto icon = ([radial, this, selected]() -> const style::icon* {
|
||||
if (radial || _data->loading()) {
|
||||
if (_data->uploading()
|
||||
|| !_data->full->location().isNull()) {
|
||||
|| !_data->large()->location().isNull()) {
|
||||
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -292,7 +316,7 @@ TextState HistoryPhoto::textState(QPoint point, StateRequest request) const {
|
|||
} else if (_data->loaded()) {
|
||||
result.link = _openl;
|
||||
} else if (_data->loading()) {
|
||||
if (!_data->full->location().isNull()) {
|
||||
if (!_data->large()->location().isNull()) {
|
||||
result.link = _cancell;
|
||||
}
|
||||
} else {
|
||||
|
@ -317,8 +341,8 @@ TextState HistoryPhoto::textState(QPoint point, StateRequest request) const {
|
|||
}
|
||||
|
||||
QSize HistoryPhoto::sizeForGrouping() const {
|
||||
const auto width = _data->full->width();
|
||||
const auto height = _data->full->height();
|
||||
const auto width = _data->width();
|
||||
const auto height = _data->height();
|
||||
return { std::max(width, 1), std::max(height, 1) };
|
||||
}
|
||||
|
||||
|
@ -395,7 +419,7 @@ void HistoryPhoto::drawGrouped(
|
|||
if (_data->waitingForAlbum()) {
|
||||
return &(selected ? st::historyFileThumbWaitingSelected : st::historyFileThumbWaiting);
|
||||
} else if (radial || _data->loading()) {
|
||||
if (_data->uploading() || !_data->full->location().isNull()) {
|
||||
if (_data->uploading() || !_data->large()->location().isNull()) {
|
||||
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -440,7 +464,7 @@ TextState HistoryPhoto::getStateGrouped(
|
|||
: _data->loaded()
|
||||
? _openl
|
||||
: _data->loading()
|
||||
? (_data->full->location().isNull()
|
||||
? (_data->large()->location().isNull()
|
||||
? ClickHandlerPtr()
|
||||
: _cancell)
|
||||
: _savel);
|
||||
|
@ -470,7 +494,13 @@ void HistoryPhoto::validateGroupedCache(
|
|||
not_null<QPixmap*> cache) const {
|
||||
using Option = Images::Option;
|
||||
const auto loaded = _data->loaded();
|
||||
const auto loadLevel = loaded ? 2 : _data->thumb->loaded() ? 1 : 0;
|
||||
const auto loadLevel = loaded
|
||||
? 2
|
||||
: (_data->thumbnailInline()
|
||||
|| _data->thumbnail()->loaded()
|
||||
|| _data->thumbnailSmall()->loaded())
|
||||
? 1
|
||||
: 0;
|
||||
const auto width = geometry.width();
|
||||
const auto height = geometry.height();
|
||||
const auto options = Option::Smooth
|
||||
|
@ -488,14 +518,22 @@ void HistoryPhoto::validateGroupedCache(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto originalWidth = ConvertScale(_data->full->width());
|
||||
const auto originalHeight = ConvertScale(_data->full->height());
|
||||
const auto originalWidth = ConvertScale(_data->width());
|
||||
const auto originalHeight = ConvertScale(_data->height());
|
||||
const auto pixSize = Ui::GetImageScaleSizeForGeometry(
|
||||
{ originalWidth, originalHeight },
|
||||
{ width, height });
|
||||
const auto pixWidth = pixSize.width() * cIntRetinaFactor();
|
||||
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
|
||||
const auto &image = loaded ? _data->full : _data->thumb;
|
||||
const auto image = loaded
|
||||
? _data->large().get()
|
||||
: _data->thumbnail()->loaded()
|
||||
? _data->thumbnail().get()
|
||||
: _data->thumbnailSmall()->loaded()
|
||||
? _data->thumbnailSmall().get()
|
||||
: _data->thumbnailInline()
|
||||
? _data->thumbnailInline()
|
||||
: Image::Blank().get();
|
||||
|
||||
*cacheKey = key;
|
||||
*cache = image->pixNoCache(_realParent->fullId(), pixWidth, pixHeight, options, width, height);
|
||||
|
|
|
@ -30,8 +30,8 @@ HistorySticker::HistorySticker(
|
|||
: HistoryMedia(parent)
|
||||
, _data(document)
|
||||
, _emoji(_data->sticker()->alt) {
|
||||
_data->thumb->load(parent->data()->fullId());
|
||||
if (auto emoji = Ui::Emoji::Find(_emoji)) {
|
||||
_data->loadThumbnail(parent->data()->fullId());
|
||||
if (const auto emoji = Ui::Emoji::Find(_emoji)) {
|
||||
_emoji = emoji->text();
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, T
|
|||
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
|
||||
_data->checkSticker();
|
||||
_data->checkStickerLarge();
|
||||
bool loaded = _data->loaded();
|
||||
bool selected = (selection == FullSelection);
|
||||
|
||||
|
@ -117,14 +117,25 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, T
|
|||
const auto w = _pixw;
|
||||
const auto h = _pixh;
|
||||
const auto &c = st::msgStickerOverlay;
|
||||
if (const auto image = _data->getStickerImage()) {
|
||||
if (const auto image = _data->getStickerLarge()) {
|
||||
return selected
|
||||
? image->pixColored(o, c, w, h)
|
||||
: image->pix(o, w, h);
|
||||
//
|
||||
// Inline thumbnails can't have alpha channel.
|
||||
//
|
||||
//} else if (const auto blurred = _data->thumbnailInline()) {
|
||||
// return selected
|
||||
// ? blurred->pixBlurredColored(o, c, w, h)
|
||||
// : blurred->pixBlurred(o, w, h);
|
||||
} else if (const auto thumbnail = _data->thumbnail()) {
|
||||
return selected
|
||||
? thumbnail->pixBlurredColored(o, c, w, h)
|
||||
: thumbnail->pixBlurred(o, w, h);
|
||||
} else {
|
||||
static QPixmap empty;
|
||||
return empty;
|
||||
}
|
||||
return selected
|
||||
? _data->thumb->pixBlurredColored(o, c, w, h)
|
||||
: _data->thumb->pixBlurred(o, w, h);
|
||||
}();
|
||||
p.drawPixmap(
|
||||
QPoint{ usex + (usew - _pixw) / 2, (minHeight() - _pixh) / 2 },
|
||||
|
|
|
@ -41,7 +41,21 @@ HistoryVideo::HistoryVideo(
|
|||
|
||||
setStatusSize(FileStatusSizeReady);
|
||||
|
||||
_data->thumb->load(realParent->fullId());
|
||||
_data->loadThumbnail(realParent->fullId());
|
||||
}
|
||||
|
||||
QSize HistoryVideo::sizeForAspectRatio() const {
|
||||
// We use size only for aspect ratio and we want to have it
|
||||
// as close to the thumbnail as possible.
|
||||
//if (!_data->dimensions.isEmpty()) {
|
||||
// return _data->dimensions;
|
||||
//}
|
||||
if (const auto thumb = _data->thumbnail()) {
|
||||
if (!thumb->size().isEmpty()) {
|
||||
return thumb->size();
|
||||
}
|
||||
}
|
||||
return { 1, 1 };
|
||||
}
|
||||
|
||||
QSize HistoryVideo::countOptimalSize() {
|
||||
|
@ -53,8 +67,9 @@ QSize HistoryVideo::countOptimalSize() {
|
|||
_parent->skipBlockHeight());
|
||||
}
|
||||
|
||||
auto tw = ConvertScale(_data->thumb->width());
|
||||
auto th = ConvertScale(_data->thumb->height());
|
||||
const auto size = sizeForAspectRatio();
|
||||
auto tw = ConvertScale(size.width());
|
||||
auto th = ConvertScale(size.height());
|
||||
if (!tw || !th) {
|
||||
tw = th = 1;
|
||||
}
|
||||
|
@ -86,7 +101,9 @@ QSize HistoryVideo::countOptimalSize() {
|
|||
}
|
||||
|
||||
QSize HistoryVideo::countCurrentSize(int newWidth) {
|
||||
int tw = ConvertScale(_data->thumb->width()), th = ConvertScale(_data->thumb->height());
|
||||
const auto size = sizeForAspectRatio();
|
||||
auto tw = ConvertScale(size.width());
|
||||
auto th = ConvertScale(size.height());
|
||||
if (!tw || !th) {
|
||||
tw = th = 1;
|
||||
}
|
||||
|
@ -166,7 +183,12 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, Tim
|
|||
if (good) {
|
||||
good->load({});
|
||||
}
|
||||
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners));
|
||||
if (const auto normal = _data->thumbnail()) {
|
||||
const auto use = (normal->loaded() || !_data->thumbnailInline())
|
||||
? normal
|
||||
: _data->thumbnailInline();
|
||||
p.drawPixmap(rthumb.topLeft(), use->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners));
|
||||
}
|
||||
}
|
||||
if (selected) {
|
||||
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
|
||||
|
@ -288,13 +310,7 @@ TextState HistoryVideo::textState(QPoint point, StateRequest request) const {
|
|||
}
|
||||
|
||||
QSize HistoryVideo::sizeForGrouping() const {
|
||||
const auto width = _data->dimensions.isEmpty()
|
||||
? _data->thumb->width()
|
||||
: _data->dimensions.width();
|
||||
const auto height = _data->dimensions.isEmpty()
|
||||
? _data->thumb->height()
|
||||
: _data->dimensions.height();
|
||||
return { std::max(width, 1), std::max(height, 1) };
|
||||
return sizeForAspectRatio();
|
||||
}
|
||||
|
||||
void HistoryVideo::drawGrouped(
|
||||
|
@ -384,7 +400,6 @@ void HistoryVideo::drawGrouped(
|
|||
p.setOpacity(backOpacity);
|
||||
if (icon) {
|
||||
if (previous && radialOpacity > 0. && radialOpacity < 1.) {
|
||||
LOG(("INTERPOLATING: %1").arg(radialOpacity));
|
||||
PaintInterpolatedIcon(p, *icon, *previous, radialOpacity, inner);
|
||||
} else {
|
||||
icon->paintInCenter(p, inner);
|
||||
|
@ -442,13 +457,18 @@ void HistoryVideo::validateGroupedCache(
|
|||
using Option = Images::Option;
|
||||
const auto good = _data->goodThumbnail();
|
||||
const auto useGood = (good && good->loaded());
|
||||
const auto image = useGood ? good : _data->thumb.get();
|
||||
const auto thumb = _data->thumbnail();
|
||||
const auto useThumb = (thumb && thumb->loaded());
|
||||
const auto image = useGood
|
||||
? good
|
||||
: useThumb
|
||||
? thumb
|
||||
: _data->thumbnailInline();
|
||||
if (good && !useGood) {
|
||||
good->load({});
|
||||
}
|
||||
|
||||
const auto loaded = useGood ? true : _data->thumb->loaded();
|
||||
const auto loadLevel = loaded ? 1 : 0;
|
||||
const auto loadLevel = useGood ? 3 : useThumb ? 2 : image ? 1 : 0;
|
||||
const auto width = geometry.width();
|
||||
const auto height = geometry.height();
|
||||
const auto options = Option::Smooth
|
||||
|
@ -466,8 +486,9 @@ void HistoryVideo::validateGroupedCache(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto originalWidth = ConvertScale(_data->thumb->width());
|
||||
const auto originalHeight = ConvertScale(_data->thumb->height());
|
||||
const auto original = sizeForAspectRatio();
|
||||
const auto originalWidth = ConvertScale(original.width());
|
||||
const auto originalHeight = ConvertScale(original.height());
|
||||
const auto pixSize = Ui::GetImageScaleSizeForGeometry(
|
||||
{ originalWidth, originalHeight },
|
||||
{ width, height });
|
||||
|
@ -475,7 +496,7 @@ void HistoryVideo::validateGroupedCache(
|
|||
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
|
||||
|
||||
*cacheKey = key;
|
||||
*cache = image->pixNoCache(_realParent->fullId(), pixWidth, pixHeight, options, width, height);
|
||||
*cache = (image ? image : Image::Blank().get())->pixNoCache(_realParent->fullId(), pixWidth, pixHeight, options, width, height);
|
||||
}
|
||||
|
||||
void HistoryVideo::setStatusSize(int newSize) const {
|
||||
|
|
|
@ -83,6 +83,7 @@ private:
|
|||
not_null<QPixmap*> cache) const;
|
||||
void setStatusSize(int newSize) const;
|
||||
void updateStatusText() const;
|
||||
QSize sizeForAspectRatio() const;
|
||||
|
||||
not_null<DocumentData*> _data;
|
||||
int _thumbw = 1;
|
||||
|
|
|
@ -34,14 +34,16 @@ namespace {
|
|||
|
||||
constexpr auto kMaxOriginalEntryLines = 8192;
|
||||
|
||||
int articleThumbWidth(PhotoData *thumb, int height) {
|
||||
auto w = thumb->medium->width();
|
||||
auto h = thumb->medium->height();
|
||||
int articleThumbWidth(not_null<PhotoData*> thumb, int height) {
|
||||
auto w = thumb->thumbnail()->width();
|
||||
auto h = thumb->thumbnail()->height();
|
||||
return qMax(qMin(height * w / h, height), 1);
|
||||
}
|
||||
|
||||
int articleThumbHeight(PhotoData *thumb, int width) {
|
||||
return qMax(thumb->medium->height() * width / thumb->medium->width(), 1);
|
||||
int articleThumbHeight(not_null<PhotoData*> thumb, int width) {
|
||||
return qMax(
|
||||
thumb->thumbnail()->height() * width / thumb->thumbnail()->width(),
|
||||
1);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Data::Media>> PrepareCollageMedia(
|
||||
|
@ -410,22 +412,25 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, T
|
|||
auto lineHeight = unitedLineHeight();
|
||||
if (_asArticle) {
|
||||
const auto contextId = _parent->data()->fullId();
|
||||
_data->photo->medium->load(contextId, false, false);
|
||||
bool full = _data->photo->medium->loaded();
|
||||
_data->photo->loadThumbnail(contextId);
|
||||
bool full = _data->photo->thumbnail()->loaded();
|
||||
QPixmap pix;
|
||||
auto pw = qMax(_pixw, lineHeight);
|
||||
auto ph = _pixh;
|
||||
auto pixw = _pixw, pixh = articleThumbHeight(_data->photo, _pixw);
|
||||
auto maxw = ConvertScale(_data->photo->medium->width()), maxh = ConvertScale(_data->photo->medium->height());
|
||||
const auto maxw = ConvertScale(_data->photo->thumbnail()->width());
|
||||
const auto maxh = ConvertScale(_data->photo->thumbnail()->height());
|
||||
if (pixw * ph != pixh * pw) {
|
||||
float64 coef = (pixw * ph > pixh * pw) ? qMin(ph / float64(pixh), maxh / float64(pixh)) : qMin(pw / float64(pixw), maxw / float64(pixw));
|
||||
pixh = qRound(pixh * coef);
|
||||
pixw = qRound(pixw * coef);
|
||||
}
|
||||
if (full) {
|
||||
pix = _data->photo->medium->pixSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
||||
} else {
|
||||
pix = _data->photo->thumb->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
||||
pix = _data->photo->thumbnail()->pixSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
||||
} else if (_data->photo->thumbnailSmall()->loaded()) {
|
||||
pix = _data->photo->thumbnailSmall()->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
||||
} else if (const auto blurred = _data->photo->thumbnailInline()) {
|
||||
pix = blurred->pixBlurredSingle(contextId, pixw, pixh, pw, ph, ImageRoundRadius::Small);
|
||||
}
|
||||
p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix);
|
||||
if (selected) {
|
||||
|
|
|
@ -49,7 +49,7 @@ void AddToggleGroupingAction(
|
|||
}
|
||||
|
||||
void SavePhotoToFile(not_null<PhotoData*> photo) {
|
||||
if (!photo->date || !photo->loaded()) {
|
||||
if (photo->isNull() || !photo->loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,17 +60,17 @@ void SavePhotoToFile(not_null<PhotoData*> photo) {
|
|||
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
|
||||
crl::guard(&Auth(), [=](const QString &result) {
|
||||
if (!result.isEmpty()) {
|
||||
photo->full->pix(Data::FileOrigin()).toImage().save(result, "JPG");
|
||||
photo->large()->original().save(result, "JPG");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void CopyImage(not_null<PhotoData*> photo) {
|
||||
if (!photo->date || !photo->loaded()) {
|
||||
if (photo->isNull() || !photo->loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QApplication::clipboard()->setPixmap(photo->full->pix(Data::FileOrigin()));
|
||||
QApplication::clipboard()->setImage(photo->large()->original());
|
||||
}
|
||||
|
||||
void ShowStickerPackInfo(not_null<DocumentData*> document) {
|
||||
|
|
|
@ -48,23 +48,25 @@ DocumentData *FileBase::getShownDocument() const {
|
|||
}
|
||||
|
||||
int FileBase::content_width() const {
|
||||
DocumentData *document = getShownDocument();
|
||||
if (document->dimensions.width() > 0) {
|
||||
return document->dimensions.width();
|
||||
}
|
||||
if (!document->thumb->isNull()) {
|
||||
return ConvertScale(document->thumb->width());
|
||||
if (const auto document = getShownDocument()) {
|
||||
if (document->dimensions.width() > 0) {
|
||||
return document->dimensions.width();
|
||||
}
|
||||
if (const auto thumb = document->thumbnail()) {
|
||||
return ConvertScale(thumb->width());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileBase::content_height() const {
|
||||
DocumentData *document = getShownDocument();
|
||||
if (document->dimensions.height() > 0) {
|
||||
return document->dimensions.height();
|
||||
}
|
||||
if (!document->thumb->isNull()) {
|
||||
return ConvertScale(document->thumb->height());
|
||||
if (const auto document = getShownDocument()) {
|
||||
if (document->dimensions.height() > 0) {
|
||||
return document->dimensions.height();
|
||||
}
|
||||
if (const auto thumb = document->thumbnail()) {
|
||||
return ConvertScale(thumb->height());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -82,10 +84,10 @@ int FileBase::content_duration() const {
|
|||
return getResultDuration();
|
||||
}
|
||||
|
||||
ImagePtr FileBase::content_thumb() const {
|
||||
if (DocumentData *document = getShownDocument()) {
|
||||
if (!document->thumb->isNull()) {
|
||||
return document->thumb;
|
||||
Image *FileBase::content_thumb() const {
|
||||
if (const auto document = getShownDocument()) {
|
||||
if (const auto thumb = document->thumbnail()) {
|
||||
return thumb;
|
||||
}
|
||||
}
|
||||
return getResultThumb();
|
||||
|
@ -166,7 +168,7 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
|
|||
auto pixmap = _gif->current(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, RectPart::None, context->paused ? 0 : context->ms);
|
||||
p.drawPixmap(r.topLeft(), pixmap);
|
||||
} else {
|
||||
prepareThumb(_width, height, frame);
|
||||
prepareThumbnail({ _width, height }, frame);
|
||||
if (_thumb.isNull()) {
|
||||
p.fillRect(r, st::overviewPhotoBg);
|
||||
} else {
|
||||
|
@ -287,29 +289,37 @@ QSize Gif::countFrameSize() const {
|
|||
return QSize(framew, frameh);
|
||||
}
|
||||
|
||||
void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
|
||||
const auto origin = fileOrigin();
|
||||
void Gif::validateThumbnail(
|
||||
Image *image,
|
||||
QSize size,
|
||||
QSize frame,
|
||||
bool good) const {
|
||||
if (!image || (_thumbGood && !good)) {
|
||||
return;
|
||||
} else if (!image->loaded()) {
|
||||
image->load(fileOrigin());
|
||||
return;
|
||||
} else if ((_thumb.size() == size * cIntRetinaFactor())
|
||||
&& (_thumbGood || !good)) {
|
||||
return;
|
||||
}
|
||||
_thumbGood = good;
|
||||
_thumb = image->pixNoCache(
|
||||
fileOrigin(),
|
||||
frame.width() * cIntRetinaFactor(),
|
||||
frame.height() * cIntRetinaFactor(),
|
||||
(Images::Option::Smooth
|
||||
| (good ? Images::Option::None : Images::Option::Blurred)),
|
||||
size.width(),
|
||||
size.height());
|
||||
}
|
||||
|
||||
void Gif::prepareThumbnail(QSize size, QSize frame) const {
|
||||
if (const auto document = getShownDocument()) {
|
||||
if (!document->thumb->isNull()) {
|
||||
if (document->thumb->loaded()) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
_thumb = document->thumb->pixNoCache(origin, frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||
}
|
||||
} else {
|
||||
document->thumb->load(origin);
|
||||
}
|
||||
}
|
||||
validateThumbnail(document->thumbnail(), size, frame, true);
|
||||
validateThumbnail(document->thumbnailInline(), size, frame, false);
|
||||
} else {
|
||||
const auto thumb = getResultThumb();
|
||||
if (!thumb->isNull()) {
|
||||
if (thumb->loaded()) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
_thumb = thumb->pixNoCache(origin, frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||
}
|
||||
} else {
|
||||
thumb->load(origin);
|
||||
}
|
||||
}
|
||||
validateThumbnail(getResultThumb(), size, frame, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,7 +396,7 @@ void Sticker::initDimensions() {
|
|||
|
||||
void Sticker::preload() const {
|
||||
if (const auto document = getShownDocument()) {
|
||||
document->checkStickerThumb();
|
||||
document->checkStickerSmall();
|
||||
} else if (const auto thumb = getResultThumb()) {
|
||||
thumb->load(fileOrigin());
|
||||
}
|
||||
|
@ -402,7 +412,7 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
|
|||
p.setOpacity(1);
|
||||
}
|
||||
|
||||
prepareThumb();
|
||||
prepareThumbnail();
|
||||
if (!_thumb.isNull()) {
|
||||
int w = _thumb.width() / cIntRetinaFactor(), h = _thumb.height() / cIntRetinaFactor();
|
||||
QPoint pos = QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
|
||||
|
@ -442,10 +452,10 @@ QSize Sticker::getThumbSize() const {
|
|||
return QSize(qMax(w, 1), qMax(h, 1));
|
||||
}
|
||||
|
||||
void Sticker::prepareThumb() const {
|
||||
void Sticker::prepareThumbnail() const {
|
||||
if (const auto document = getShownDocument()) {
|
||||
document->checkStickerThumb();
|
||||
if (const auto sticker = document->getStickerThumb()) {
|
||||
document->checkStickerSmall();
|
||||
if (const auto sticker = document->getStickerSmall()) {
|
||||
if (!_thumbLoaded && sticker->loaded()) {
|
||||
const auto thumbSize = getThumbSize();
|
||||
_thumb = sticker->pix(
|
||||
|
@ -457,18 +467,19 @@ void Sticker::prepareThumb() const {
|
|||
}
|
||||
} else {
|
||||
const auto origin = fileOrigin();
|
||||
const auto thumb = getResultThumb();
|
||||
if (thumb->loaded()) {
|
||||
if (!_thumbLoaded) {
|
||||
const auto thumbSize = getThumbSize();
|
||||
_thumb = thumb->pix(
|
||||
origin,
|
||||
thumbSize.width(),
|
||||
thumbSize.height());
|
||||
_thumbLoaded = true;
|
||||
if (const auto thumb = getResultThumb()) {
|
||||
if (thumb->loaded()) {
|
||||
if (!_thumbLoaded) {
|
||||
const auto thumbSize = getThumbSize();
|
||||
_thumb = thumb->pix(
|
||||
origin,
|
||||
thumbSize.width(),
|
||||
thumbSize.height());
|
||||
_thumbLoaded = true;
|
||||
}
|
||||
} else {
|
||||
thumb->load(origin);
|
||||
}
|
||||
} else {
|
||||
thumb->load(origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,8 +489,8 @@ Photo::Photo(not_null<Context*> context, Result *result)
|
|||
}
|
||||
|
||||
void Photo::initDimensions() {
|
||||
PhotoData *photo = getShownPhoto();
|
||||
int32 w = photo->full->width(), h = photo->full->height();
|
||||
const auto photo = getShownPhoto();
|
||||
int32 w = photo->width(), h = photo->height();
|
||||
if (w <= 0 || h <= 0) {
|
||||
_maxw = 0;
|
||||
} else {
|
||||
|
@ -495,7 +506,7 @@ void Photo::paint(Painter &p, const QRect &clip, const PaintContext *context) co
|
|||
|
||||
QRect r(0, 0, _width, height);
|
||||
|
||||
prepareThumb(_width, height, frame);
|
||||
prepareThumbnail({ _width, height }, frame);
|
||||
if (_thumb.isNull()) {
|
||||
p.fillRect(r, st::overviewPhotoBg);
|
||||
} else {
|
||||
|
@ -521,7 +532,7 @@ PhotoData *Photo::getShownPhoto() const {
|
|||
|
||||
QSize Photo::countFrameSize() const {
|
||||
PhotoData *photo = getShownPhoto();
|
||||
int32 framew = photo->full->width(), frameh = photo->full->height(), height = st::inlineMediaHeight;
|
||||
int32 framew = photo->width(), frameh = photo->height(), height = st::inlineMediaHeight;
|
||||
if (framew * height > frameh * _width) {
|
||||
if (framew < st::maxStickerSize || frameh > height) {
|
||||
if (frameh > height || (framew * height / frameh) <= st::maxStickerSize) {
|
||||
|
@ -546,31 +557,38 @@ QSize Photo::countFrameSize() const {
|
|||
return QSize(framew, frameh);
|
||||
}
|
||||
|
||||
void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
|
||||
void Photo::validateThumbnail(
|
||||
Image *image,
|
||||
QSize size,
|
||||
QSize frame,
|
||||
bool good) const {
|
||||
if (!image || (_thumbGood && !good)) {
|
||||
return;
|
||||
} else if (!image->loaded()) {
|
||||
image->load(fileOrigin());
|
||||
return;
|
||||
} else if ((_thumb.size() == size * cIntRetinaFactor())
|
||||
&& (_thumbGood || !good)) {
|
||||
return;
|
||||
}
|
||||
const auto origin = fileOrigin();
|
||||
_thumb = image->pixNoCache(
|
||||
origin,
|
||||
frame.width() * cIntRetinaFactor(),
|
||||
frame.height() * cIntRetinaFactor(),
|
||||
Images::Option::Smooth | (good ? Images::Option(0) : Images::Option::Blurred),
|
||||
size.width(),
|
||||
size.height());
|
||||
_thumbGood = good;
|
||||
}
|
||||
|
||||
void Photo::prepareThumbnail(QSize size, QSize frame) const {
|
||||
if (const auto photo = getShownPhoto()) {
|
||||
if (photo->medium->loaded()) {
|
||||
if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
_thumb = photo->medium->pixNoCache(origin, frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||
}
|
||||
_thumbLoaded = true;
|
||||
} else {
|
||||
if (photo->thumb->loaded()) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
_thumb = photo->thumb->pixNoCache(origin, frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||
}
|
||||
}
|
||||
photo->medium->load(origin);
|
||||
}
|
||||
} else {
|
||||
const auto thumb = getResultThumb();
|
||||
if (thumb->loaded()) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
_thumb = thumb->pixNoCache(origin, frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||
}
|
||||
} else {
|
||||
thumb->load(origin);
|
||||
}
|
||||
validateThumbnail(photo->thumbnail(), size, frame, true);
|
||||
validateThumbnail(photo->thumbnailSmall(), size, frame, false);
|
||||
validateThumbnail(photo->thumbnailInline(), size, frame, false);
|
||||
} else if (const auto thumbnail = getResultThumb()) {
|
||||
validateThumbnail(thumbnail, size, frame, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -585,7 +603,7 @@ Video::Video(not_null<Context*> context, Result *result) : FileBase(context, res
|
|||
}
|
||||
|
||||
void Video::initDimensions() {
|
||||
bool withThumb = !content_thumb()->isNull();
|
||||
const auto withThumb = (content_thumb() != nullptr);
|
||||
|
||||
_maxw = st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft;
|
||||
int32 textWidth = _maxw - (withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : 0);
|
||||
|
@ -614,9 +632,9 @@ void Video::initDimensions() {
|
|||
void Video::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||
int left = st::inlineThumbSize + st::inlineThumbSkip;
|
||||
|
||||
bool withThumb = !content_thumb()->isNull();
|
||||
const auto withThumb = (content_thumb() != nullptr);
|
||||
if (withThumb) {
|
||||
prepareThumb(st::inlineThumbSize, st::inlineThumbSize);
|
||||
prepareThumbnail({ st::inlineThumbSize, st::inlineThumbSize });
|
||||
if (_thumb.isNull()) {
|
||||
p.fillRect(rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width), st::overviewPhotoBg);
|
||||
} else {
|
||||
|
@ -661,11 +679,15 @@ TextState Video::getState(
|
|||
return {};
|
||||
}
|
||||
|
||||
void Video::prepareThumb(int32 width, int32 height) const {
|
||||
void Video::prepareThumbnail(QSize size) const {
|
||||
Expects(content_thumb() != nullptr);
|
||||
|
||||
const auto thumb = content_thumb();
|
||||
const auto origin = fileOrigin();
|
||||
if (thumb->loaded()) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
if (_thumb.size() != size * cIntRetinaFactor()) {
|
||||
const auto width = size.width();
|
||||
const auto height = size.height();
|
||||
int32 w = qMax(ConvertScale(thumb->width()), 1), h = qMax(ConvertScale(thumb->height()), 1);
|
||||
if (w * height > h * width) {
|
||||
if (height < h) {
|
||||
|
@ -948,7 +970,7 @@ void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context)
|
|||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
||||
|
||||
left = st::msgFileSize + st::inlineThumbSkip;
|
||||
prepareThumb(st::msgFileSize, st::msgFileSize);
|
||||
prepareThumbnail(st::msgFileSize, st::msgFileSize);
|
||||
QRect rthumb(rtlrect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize, _width));
|
||||
p.drawPixmapLeft(rthumb.topLeft(), _width, _thumb);
|
||||
|
||||
|
@ -978,9 +1000,9 @@ TextState Contact::getState(
|
|||
return {};
|
||||
}
|
||||
|
||||
void Contact::prepareThumb(int width, int height) const {
|
||||
void Contact::prepareThumbnail(int width, int height) const {
|
||||
const auto thumb = getResultThumb();
|
||||
if (thumb->isNull()) {
|
||||
if (!thumb) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
_thumb = getResultContactAvatar(width, height);
|
||||
}
|
||||
|
@ -1059,11 +1081,11 @@ void Article::paint(Painter &p, const QRect &clip, const PaintContext *context)
|
|||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
||||
if (_withThumb) {
|
||||
left = st::inlineThumbSize + st::inlineThumbSkip;
|
||||
prepareThumb(st::inlineThumbSize, st::inlineThumbSize);
|
||||
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
|
||||
QRect rthumb(rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width));
|
||||
if (_thumb.isNull()) {
|
||||
ImagePtr thumb = getResultThumb();
|
||||
if (thumb->isNull() && !_thumbLetter.isEmpty()) {
|
||||
const auto thumb = getResultThumb();
|
||||
if (!thumb && !_thumbLetter.isEmpty()) {
|
||||
int32 index = (_thumbLetter.at(0).unicode() % 4);
|
||||
style::color colors[] = {
|
||||
st::msgFile3Bg,
|
||||
|
@ -1126,9 +1148,9 @@ TextState Article::getState(
|
|||
return {};
|
||||
}
|
||||
|
||||
void Article::prepareThumb(int width, int height) const {
|
||||
void Article::prepareThumbnail(int width, int height) const {
|
||||
const auto thumb = getResultThumb();
|
||||
if (thumb->isNull()) {
|
||||
if (!thumb) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
_thumb = getResultContactAvatar(width, height);
|
||||
}
|
||||
|
@ -1258,7 +1280,7 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
|
|||
}
|
||||
|
||||
if (!thumbDisplayed) {
|
||||
prepareThumb(st::inlineThumbSize, st::inlineThumbSize);
|
||||
prepareThumbnail({ st::inlineThumbSize, st::inlineThumbSize });
|
||||
if (_thumb.isNull()) {
|
||||
p.fillRect(rthumb, st::overviewPhotoBg);
|
||||
} else {
|
||||
|
@ -1302,41 +1324,52 @@ TextState Game::getState(
|
|||
return {};
|
||||
}
|
||||
|
||||
void Game::prepareThumb(int width, int height) const {
|
||||
const auto thumb = [this] {
|
||||
if (auto photo = getResultPhoto()) {
|
||||
return photo->medium;
|
||||
} else if (auto document = getResultDocument()) {
|
||||
return document->thumb;
|
||||
}
|
||||
return ImagePtr();
|
||||
}();
|
||||
if (thumb->isNull()) {
|
||||
void Game::prepareThumbnail(QSize size) const {
|
||||
if (const auto photo = getResultPhoto()) {
|
||||
validateThumbnail(photo->thumbnail(), size, true);
|
||||
validateThumbnail(photo->thumbnailInline(), size, false);
|
||||
} else if (const auto document = getResultDocument()) {
|
||||
validateThumbnail(document->thumbnail(), size, true);
|
||||
validateThumbnail(document->thumbnailInline(), size, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::validateThumbnail(Image *image, QSize size, bool good) const {
|
||||
if (!image || (_thumbGood && !good)) {
|
||||
return;
|
||||
} else if (!image->loaded()) {
|
||||
image->load(fileOrigin());
|
||||
return;
|
||||
} else if ((_thumb.size() == size * cIntRetinaFactor())
|
||||
&& (_thumbGood || !good)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto origin = fileOrigin();
|
||||
if (thumb->loaded()) {
|
||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||
int w = qMax(ConvertScale(thumb->width()), 1), h = qMax(ConvertScale(thumb->height()), 1);
|
||||
auto resizeByHeight1 = (w * height > h * width) && (h >= height);
|
||||
auto resizeByHeight2 = (h * width >= w * height) && (w < width);
|
||||
if (resizeByHeight1 || resizeByHeight2) {
|
||||
if (h > height) {
|
||||
w = w * height / h;
|
||||
h = height;
|
||||
}
|
||||
} else {
|
||||
if (w > width) {
|
||||
h = h * width / w;
|
||||
w = width;
|
||||
}
|
||||
}
|
||||
_thumb = thumb->pixNoCache(origin, w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||
const auto width = size.width();
|
||||
const auto height = size.height();
|
||||
auto w = qMax(ConvertScale(image->width()), 1);
|
||||
auto h = qMax(ConvertScale(image->height()), 1);
|
||||
auto resizeByHeight1 = (w * height > h * width) && (h >= height);
|
||||
auto resizeByHeight2 = (h * width >= w * height) && (w < width);
|
||||
if (resizeByHeight1 || resizeByHeight2) {
|
||||
if (h > height) {
|
||||
w = w * height / h;
|
||||
h = height;
|
||||
}
|
||||
} else {
|
||||
thumb->load(origin);
|
||||
if (w > width) {
|
||||
h = h * width / w;
|
||||
w = width;
|
||||
}
|
||||
}
|
||||
_thumbGood = good;
|
||||
_thumb = image->pixNoCache(
|
||||
fileOrigin(),
|
||||
w * cIntRetinaFactor(),
|
||||
h * cIntRetinaFactor(),
|
||||
(Images::Option::Smooth
|
||||
| (good ? Images::Option::None : Images::Option::Blurred)),
|
||||
size.width(),
|
||||
size.height());
|
||||
}
|
||||
|
||||
bool Game::isRadialAnimation(TimeMs ms) const {
|
||||
|
|
|
@ -28,7 +28,7 @@ protected:
|
|||
int content_width() const;
|
||||
int content_height() const;
|
||||
int content_duration() const;
|
||||
ImagePtr content_thumb() const;
|
||||
Image *content_thumb() const;
|
||||
};
|
||||
|
||||
class DeleteSavedGifClickHandler : public LeftButtonClickHandler {
|
||||
|
@ -83,7 +83,13 @@ private:
|
|||
Media::Clip::ReaderPointer _gif;
|
||||
ClickHandlerPtr _delete;
|
||||
mutable QPixmap _thumb;
|
||||
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
||||
mutable bool _thumbGood = false;
|
||||
void validateThumbnail(
|
||||
Image *image,
|
||||
QSize size,
|
||||
QSize frame,
|
||||
bool good) const;
|
||||
void prepareThumbnail(QSize size, QSize frame) const;
|
||||
|
||||
void ensureAnimation() const;
|
||||
bool isRadialAnimation(TimeMs ms) const;
|
||||
|
@ -131,8 +137,13 @@ private:
|
|||
QSize countFrameSize() const;
|
||||
|
||||
mutable QPixmap _thumb;
|
||||
mutable bool _thumbLoaded = false;
|
||||
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
||||
mutable bool _thumbGood = false;
|
||||
void prepareThumbnail(QSize size, QSize frame) const;
|
||||
void validateThumbnail(
|
||||
Image *image,
|
||||
QSize size,
|
||||
QSize frame,
|
||||
bool good) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -168,7 +179,7 @@ private:
|
|||
|
||||
mutable QPixmap _thumb;
|
||||
mutable bool _thumbLoaded = false;
|
||||
void prepareThumb() const;
|
||||
void prepareThumbnail() const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -191,7 +202,7 @@ private:
|
|||
QString _duration;
|
||||
int _durationWidth = 0;
|
||||
|
||||
void prepareThumb(int32 width, int32 height) const;
|
||||
void prepareThumbnail(QSize size) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -302,7 +313,7 @@ private:
|
|||
mutable QPixmap _thumb;
|
||||
Text _title, _description;
|
||||
|
||||
void prepareThumb(int width, int height) const;
|
||||
void prepareThumbnail(int width, int height) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -327,7 +338,7 @@ private:
|
|||
QString _thumbLetter, _urlText;
|
||||
int32 _urlWidth;
|
||||
|
||||
void prepareThumb(int width, int height) const;
|
||||
void prepareThumbnail(int width, int height) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -346,7 +357,8 @@ public:
|
|||
private:
|
||||
void countFrameSize();
|
||||
|
||||
void prepareThumb(int32 width, int32 height) const;
|
||||
void prepareThumbnail(QSize size) const;
|
||||
void validateThumbnail(Image *image, QSize size, bool good) const;
|
||||
|
||||
bool isRadialAnimation(TimeMs ms) const;
|
||||
void step_radial(TimeMs ms, bool timer);
|
||||
|
@ -355,6 +367,7 @@ private:
|
|||
|
||||
Media::Clip::ReaderPointer _gif;
|
||||
mutable QPixmap _thumb;
|
||||
mutable bool _thumbGood = false;
|
||||
mutable std::unique_ptr<Ui::RadialAnimation> _radial;
|
||||
Text _title, _description;
|
||||
|
||||
|
|
|
@ -78,16 +78,16 @@ void ItemBase::preload() const {
|
|||
const auto origin = fileOrigin();
|
||||
if (_result) {
|
||||
if (_result->_photo) {
|
||||
_result->_photo->thumb->load(origin);
|
||||
_result->_photo->loadThumbnail(origin);
|
||||
} else if (_result->_document) {
|
||||
_result->_document->thumb->load(origin);
|
||||
_result->_document->loadThumbnail(origin);
|
||||
} else if (!_result->_thumb->isNull()) {
|
||||
_result->_thumb->load(origin);
|
||||
}
|
||||
} else if (_doc) {
|
||||
_doc->thumb->load(origin);
|
||||
_doc->loadThumbnail(origin);
|
||||
} else if (_photo) {
|
||||
_photo->medium->load(origin);
|
||||
_photo->loadThumbnail(origin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,17 +145,17 @@ PhotoData *ItemBase::getResultPhoto() const {
|
|||
return _result ? _result->_photo : nullptr;
|
||||
}
|
||||
|
||||
ImagePtr ItemBase::getResultThumb() const {
|
||||
Image *ItemBase::getResultThumb() const {
|
||||
if (_result) {
|
||||
if (_result->_photo && !_result->_photo->thumb->isNull()) {
|
||||
return _result->_photo->thumb;
|
||||
if (_result->_photo) {
|
||||
return _result->_photo->thumbnail();
|
||||
} else if (!_result->_thumb->isNull()) {
|
||||
return _result->_thumb.get();
|
||||
} else if (!_result->_locationThumb->isNull()) {
|
||||
return _result->_locationThumb.get();
|
||||
}
|
||||
if (!_result->_thumb->isNull()) {
|
||||
return _result->_thumb;
|
||||
}
|
||||
return _result->_locationThumb;
|
||||
}
|
||||
return ImagePtr();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QPixmap ItemBase::getResultContactAvatar(int width, int height) const {
|
||||
|
|
|
@ -95,7 +95,7 @@ public:
|
|||
protected:
|
||||
DocumentData *getResultDocument() const;
|
||||
PhotoData *getResultPhoto() const;
|
||||
ImagePtr getResultThumb() const;
|
||||
Image *getResultThumb() const;
|
||||
QPixmap getResultContactAvatar(int width, int height) const;
|
||||
int getResultDuration() const;
|
||||
QString getResultUrl() const;
|
||||
|
|
|
@ -110,8 +110,8 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
|
|||
message = &r.vsend_message;
|
||||
} break;
|
||||
}
|
||||
auto badAttachment = (result->_photo && result->_photo->full->isNull())
|
||||
|| (result->_document && !result->_document->isValid());
|
||||
auto badAttachment = (result->_photo && result->_photo->isNull())
|
||||
|| (result->_document && result->_document->isNull());
|
||||
|
||||
if (!message) {
|
||||
return nullptr;
|
||||
|
@ -246,11 +246,10 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult
|
|||
|
||||
bool Result::onChoose(Layout::ItemBase *layout) {
|
||||
if (_photo && _type == Type::Photo) {
|
||||
if (_photo->medium->loaded() || _photo->thumb->loaded()) {
|
||||
if (_photo->thumbnail()->loaded()) {
|
||||
return true;
|
||||
} else if (!_photo->medium->loading()) {
|
||||
_photo->thumb->loadEvenCancelled(Data::FileOrigin());
|
||||
_photo->medium->loadEvenCancelled(Data::FileOrigin());
|
||||
} else if (!_photo->thumbnail()->loading()) {
|
||||
_photo->thumbnail()->loadEvenCancelled(Data::FileOrigin());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1640,8 +1640,8 @@ void MainWidget::checkChatBackground() {
|
|||
});
|
||||
}
|
||||
|
||||
ImagePtr MainWidget::newBackgroundThumb() {
|
||||
return _background ? _background->data.thumb : ImagePtr();
|
||||
Image *MainWidget::newBackgroundThumb() {
|
||||
return _background ? _background->data.thumb : nullptr;
|
||||
}
|
||||
|
||||
void MainWidget::messageDataReceived(ChannelData *channel, MsgId msgId) {
|
||||
|
|
|
@ -237,7 +237,7 @@ public:
|
|||
bool chatBackgroundLoading();
|
||||
float64 chatBackgroundProgress() const;
|
||||
void checkChatBackground();
|
||||
ImagePtr newBackgroundThumb();
|
||||
Image *newBackgroundThumb();
|
||||
|
||||
void messageDataReceived(ChannelData *channel, MsgId msgId);
|
||||
void updateBotKeyboard(History *h);
|
||||
|
|
|
@ -318,7 +318,7 @@ void Instance::play(const AudioMsgId &audioId) {
|
|||
}
|
||||
}
|
||||
if (document->isVoiceMessage() || document->isVideoMessage()) {
|
||||
document->session()->data().markMediaRead(document);
|
||||
document->owner().markMediaRead(document);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ public:
|
|||
|
||||
Thumb(
|
||||
Key key,
|
||||
ImagePtr image,
|
||||
Image *image,
|
||||
Data::FileOrigin origin,
|
||||
Fn<void()> handler);
|
||||
|
||||
|
@ -157,7 +157,7 @@ private:
|
|||
|
||||
ClickHandlerPtr _link;
|
||||
const Key _key;
|
||||
ImagePtr _image;
|
||||
Image *_image = nullptr;
|
||||
Data::FileOrigin _origin;
|
||||
State _state = State::Alive;
|
||||
QPixmap _full;
|
||||
|
@ -172,7 +172,7 @@ private:
|
|||
|
||||
GroupThumbs::Thumb::Thumb(
|
||||
Key key,
|
||||
ImagePtr image,
|
||||
Image *image,
|
||||
Data::FileOrigin origin,
|
||||
Fn<void()> handler)
|
||||
: _key(key)
|
||||
|
@ -186,15 +186,15 @@ GroupThumbs::Thumb::Thumb(
|
|||
}
|
||||
|
||||
QSize GroupThumbs::Thumb::wantedPixSize() const {
|
||||
const auto originalWidth = std::max(_image->width(), 1);
|
||||
const auto originalHeight = std::max(_image->height(), 1);
|
||||
const auto originalWidth = _image ? std::max(_image->width(), 1) : 1;
|
||||
const auto originalHeight = _image ? std::max(_image->height(), 1) : 1;
|
||||
const auto pixHeight = st::mediaviewGroupHeight;
|
||||
const auto pixWidth = originalWidth * pixHeight / originalHeight;
|
||||
return { pixWidth, pixHeight };
|
||||
}
|
||||
|
||||
void GroupThumbs::Thumb::validateImage() {
|
||||
if (!_full.isNull()) {
|
||||
if (!_full.isNull() || !_image) {
|
||||
return;
|
||||
}
|
||||
_image->load(_origin);
|
||||
|
@ -516,20 +516,18 @@ auto GroupThumbs::createThumb(Key key)
|
|||
-> std::unique_ptr<Thumb> {
|
||||
if (const auto photoId = base::get_if<PhotoId>(&key)) {
|
||||
const auto photo = Auth().data().photo(*photoId);
|
||||
return createThumb(
|
||||
key,
|
||||
photo->date ? photo->thumb : ImagePtr());
|
||||
return createThumb(key, photo->thumbnail());
|
||||
} else if (const auto msgId = base::get_if<FullMsgId>(&key)) {
|
||||
if (const auto item = App::histItemById(*msgId)) {
|
||||
if (const auto media = item->media()) {
|
||||
if (const auto photo = media->photo()) {
|
||||
return createThumb(key, photo->thumb);
|
||||
return createThumb(key, photo->thumbnail());
|
||||
} else if (const auto document = media->document()) {
|
||||
return createThumb(key, document->thumb);
|
||||
return createThumb(key, document->thumbnail());
|
||||
}
|
||||
}
|
||||
}
|
||||
return createThumb(key, ImagePtr());
|
||||
return createThumb(key, nullptr);
|
||||
} else if (const auto collageKey = base::get_if<CollageKey>(&key)) {
|
||||
if (const auto itemId = base::get_if<FullMsgId>(&_context)) {
|
||||
if (const auto item = App::histItemById(*itemId)) {
|
||||
|
@ -543,7 +541,7 @@ auto GroupThumbs::createThumb(Key key)
|
|||
}
|
||||
}
|
||||
}
|
||||
return createThumb(key, ImagePtr());
|
||||
return createThumb(key, nullptr);
|
||||
}
|
||||
Unexpected("Value of Key in GroupThumbs::createThumb()");
|
||||
}
|
||||
|
@ -554,18 +552,18 @@ auto GroupThumbs::createThumb(
|
|||
int index)
|
||||
-> std::unique_ptr<Thumb> {
|
||||
if (index < 0 || index >= collage.items.size()) {
|
||||
return createThumb(key, ImagePtr());
|
||||
return createThumb(key, nullptr);
|
||||
}
|
||||
const auto &item = collage.items[index];
|
||||
if (const auto photo = base::get_if<PhotoData*>(&item)) {
|
||||
return createThumb(key, (*photo)->thumb);
|
||||
return createThumb(key, (*photo)->thumbnail());
|
||||
} else if (const auto document = base::get_if<DocumentData*>(&item)) {
|
||||
return createThumb(key, (*document)->thumb);
|
||||
return createThumb(key, (*document)->thumbnail());
|
||||
}
|
||||
return createThumb(key, ImagePtr());
|
||||
return createThumb(key, nullptr);
|
||||
}
|
||||
|
||||
auto GroupThumbs::createThumb(Key key, ImagePtr image)
|
||||
auto GroupThumbs::createThumb(Key key, Image *image)
|
||||
-> std::unique_ptr<Thumb> {
|
||||
const auto weak = base::make_weak(this);
|
||||
const auto origin = ComputeFileOrigin(key, _context);
|
||||
|
|
|
@ -99,7 +99,7 @@ private:
|
|||
Key key,
|
||||
const WebPageCollage &collage,
|
||||
int index);
|
||||
std::unique_ptr<Thumb> createThumb(Key key, ImagePtr image);
|
||||
std::unique_ptr<Thumb> createThumb(Key key, Image *image);
|
||||
|
||||
void update();
|
||||
void countUpdatedRect();
|
||||
|
|
|
@ -565,7 +565,7 @@ float64 MediaView::radialProgress() const {
|
|||
if (_doc) {
|
||||
return _doc->progress();
|
||||
} else if (_photo) {
|
||||
return _photo->full->progress();
|
||||
return _photo->large()->progress();
|
||||
}
|
||||
return 1.;
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ bool MediaView::radialLoading() const {
|
|||
if (_doc) {
|
||||
return _doc->loading();
|
||||
} else if (_photo) {
|
||||
return _photo->full->loading();
|
||||
return _photo->large()->loading();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -897,7 +897,7 @@ void MediaView::onSaveAs() {
|
|||
_photo->date),
|
||||
crl::guard(this, [this, photo = _photo](const QString &result) {
|
||||
if (!result.isEmpty() && _photo == photo && photo->loaded()) {
|
||||
photo->full->pix(fileOrigin()).toImage().save(result, "JPG");
|
||||
photo->large()->original().save(result, "JPG");
|
||||
}
|
||||
psShowOverAll(this);
|
||||
}), crl::guard(this, [this] {
|
||||
|
@ -1019,7 +1019,7 @@ void MediaView::onDownload() {
|
|||
} else {
|
||||
if (!QDir().exists(path)) QDir().mkpath(path);
|
||||
toName = filedialogDefaultName(qsl("photo"), qsl(".jpg"), path);
|
||||
if (!_photo->full->pix(fileOrigin()).toImage().save(toName, "JPG")) {
|
||||
if (!_photo->large()->original().save(toName, "JPG")) {
|
||||
toName = QString();
|
||||
}
|
||||
}
|
||||
|
@ -1098,7 +1098,7 @@ void MediaView::onCopy() {
|
|||
} else {
|
||||
if (!_photo || !_photo->loaded()) return;
|
||||
|
||||
QApplication::clipboard()->setPixmap(_photo->full->pix(fileOrigin()));
|
||||
QApplication::clipboard()->setPixmap(_photo->large()->pix(fileOrigin()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1538,6 +1538,10 @@ void MediaView::showDocument(not_null<DocumentData*> document, HistoryItem *cont
|
|||
}
|
||||
|
||||
void MediaView::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item) {
|
||||
if (photo->isNull()) {
|
||||
displayDocument(nullptr, item);
|
||||
return;
|
||||
}
|
||||
stopGif();
|
||||
destroyThemePreview();
|
||||
_doc = _autoplayVideoDocument = nullptr;
|
||||
|
@ -1555,11 +1559,11 @@ void MediaView::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item) {
|
|||
|
||||
_zoomToScreen = 0;
|
||||
Auth().downloader().clearPriorities();
|
||||
_full = -1;
|
||||
_blurred = true;
|
||||
_current = QPixmap();
|
||||
_down = OverNone;
|
||||
_w = ConvertScale(photo->full->width());
|
||||
_h = ConvertScale(photo->full->height());
|
||||
_w = ConvertScale(photo->width());
|
||||
_h = ConvertScale(photo->height());
|
||||
if (isHidden()) {
|
||||
moveToScreen();
|
||||
}
|
||||
|
@ -1618,10 +1622,10 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
|
|||
}
|
||||
if (_doc) {
|
||||
if (_doc->sticker()) {
|
||||
if (const auto image = _doc->getStickerImage()) {
|
||||
if (const auto image = _doc->getStickerLarge()) {
|
||||
_current = image->pix(fileOrigin());
|
||||
} else {
|
||||
_current = _doc->thumb->pixBlurred(
|
||||
} else if (_doc->hasThumbnail()) {
|
||||
_current = _doc->thumbnail()->pixBlurred(
|
||||
fileOrigin(),
|
||||
_doc->dimensions.width(),
|
||||
_doc->dimensions.height());
|
||||
|
@ -1647,7 +1651,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
|
|||
|
||||
_docIconRect = QRect((width() - st::mediaviewFileIconSize) / 2, (height() - st::mediaviewFileIconSize) / 2, st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
||||
if (fileBubbleShown()) {
|
||||
if (!_doc || _doc->thumb->isNull()) {
|
||||
if (!_doc || !_doc->hasThumbnail()) {
|
||||
int32 colorIndex = documentColorIndex(_doc, _docExt);
|
||||
_docIconColor = documentColor(colorIndex);
|
||||
const style::icon *(thumbs[]) = { &st::mediaviewFileBlue, &st::mediaviewFileGreen, &st::mediaviewFileRed, &st::mediaviewFileYellow };
|
||||
|
@ -1660,8 +1664,8 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
|
|||
_docExtWidth = st::mediaviewFileExtFont->width(_docExt);
|
||||
}
|
||||
} else {
|
||||
_doc->thumb->load(fileOrigin());
|
||||
int32 tw = _doc->thumb->width(), th = _doc->thumb->height();
|
||||
_doc->loadThumbnail(fileOrigin());
|
||||
int32 tw = _doc->thumbnail()->width(), th = _doc->thumbnail()->height();
|
||||
if (!tw || !th) {
|
||||
_docThumbx = _docThumby = _docThumbw = 0;
|
||||
} else if (tw > th) {
|
||||
|
@ -1745,7 +1749,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
|
|||
} else {
|
||||
_from = _user;
|
||||
}
|
||||
_full = 1;
|
||||
_blurred = false;
|
||||
displayFinished();
|
||||
}
|
||||
|
||||
|
@ -1794,10 +1798,10 @@ void MediaView::initAnimation() {
|
|||
} else if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
||||
auto w = _doc->dimensions.width();
|
||||
auto h = _doc->dimensions.height();
|
||||
_current = _doc->thumb->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
||||
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
||||
_current.setDevicePixelRatio(cRetinaFactor());
|
||||
} else {
|
||||
_current = _doc->thumb->pixNoCache(fileOrigin(), _doc->thumb->width(), _doc->thumb->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
||||
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), _doc->thumbnail()->width(), _doc->thumbnail()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1810,10 +1814,10 @@ void MediaView::createClipReader() {
|
|||
if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
||||
int w = _doc->dimensions.width();
|
||||
int h = _doc->dimensions.height();
|
||||
_current = _doc->thumb->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
||||
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
||||
_current.setDevicePixelRatio(cRetinaFactor());
|
||||
} else {
|
||||
_current = _doc->thumb->pixNoCache(fileOrigin(), _doc->thumb->width(), _doc->thumb->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
||||
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), _doc->thumbnail()->width(), _doc->thumbnail()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
||||
}
|
||||
auto mode = (_doc->isVideoFile() || _doc->isVideoMessage())
|
||||
? Media::Clip::Reader::Mode::Video
|
||||
|
@ -2050,6 +2054,38 @@ void MediaView::updateSilentVideoPlaybackState() {
|
|||
updateVideoPlaybackState(state);
|
||||
}
|
||||
|
||||
void MediaView::validatePhotoImage(Image *image, bool blurred) {
|
||||
if (!image || !image->loaded()) {
|
||||
if (!blurred) {
|
||||
image->load(fileOrigin());
|
||||
}
|
||||
return;
|
||||
} else if (!_current.isNull() && (blurred || !_blurred)) {
|
||||
return;
|
||||
}
|
||||
const auto w = _width * cIntRetinaFactor();
|
||||
const auto h = int((_photo->height() * (qreal(w) / qreal(_photo->width()))) + 0.9999);
|
||||
_current = image->pixNoCache(
|
||||
fileOrigin(),
|
||||
w,
|
||||
h,
|
||||
Images::Option::Smooth
|
||||
| (blurred ? Images::Option::Blurred : Images::Option(0)));
|
||||
_current.setDevicePixelRatio(cRetinaFactor());
|
||||
_blurred = blurred;
|
||||
}
|
||||
|
||||
void MediaView::validatePhotoCurrentImage() {
|
||||
validatePhotoImage(_photo->large(), false);
|
||||
validatePhotoImage(_photo->thumbnail(), true);
|
||||
validatePhotoImage(_photo->thumbnailSmall(), true);
|
||||
validatePhotoImage(_photo->thumbnailInline(), true);
|
||||
if (_current.isNull()) {
|
||||
_photo->loadThumbnailSmall(fileOrigin());
|
||||
validatePhotoImage(Image::Blank().get(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaView::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
QRegion region(e->region());
|
||||
|
@ -2082,39 +2118,24 @@ void MediaView::paintEvent(QPaintEvent *e) {
|
|||
|
||||
// photo
|
||||
if (_photo) {
|
||||
int32 w = _width * cIntRetinaFactor();
|
||||
if (_full <= 0 && _photo->loaded()) {
|
||||
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
||||
_current = _photo->full->pixNoCache(fileOrigin(), w, h, Images::Option::Smooth);
|
||||
_current.setDevicePixelRatio(cRetinaFactor());
|
||||
_full = 1;
|
||||
} else if (_full < 0 && _photo->medium->loaded()) {
|
||||
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
||||
_current = _photo->medium->pixNoCache(fileOrigin(), w, h, Images::Option::Smooth | Images::Option::Blurred);
|
||||
_current.setDevicePixelRatio(cRetinaFactor());
|
||||
_full = 0;
|
||||
} else if (_current.isNull() && _photo->thumb->loaded()) {
|
||||
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
||||
_current = _photo->thumb->pixNoCache(fileOrigin(), w, h, Images::Option::Smooth | Images::Option::Blurred);
|
||||
_current.setDevicePixelRatio(cRetinaFactor());
|
||||
} else if (_current.isNull()) {
|
||||
_current = _photo->thumb->pix(fileOrigin());
|
||||
}
|
||||
validatePhotoCurrentImage();
|
||||
}
|
||||
p.setOpacity(1);
|
||||
if (_photo || fileShown()) {
|
||||
QRect imgRect(_x, _y, _w, _h);
|
||||
if (imgRect.intersects(r)) {
|
||||
auto rounding = (_doc && _doc->isVideoMessage()) ? ImageRoundRadius::Ellipse : ImageRoundRadius::None;
|
||||
auto toDraw = _current.isNull() ? _gif->current(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), rounding, RectPart::AllCorners, ms) : _current;
|
||||
if (!_gif && (!_doc || !_doc->getStickerImage()) && toDraw.hasAlpha()) {
|
||||
const auto rounding = (_doc && _doc->isVideoMessage()) ? ImageRoundRadius::Ellipse : ImageRoundRadius::None;
|
||||
const auto toDraw = (_current.isNull() && _gif) ? _gif->current(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), rounding, RectPart::AllCorners, ms) : _current;
|
||||
if (!_gif && (!_doc || !_doc->getStickerLarge()) && (toDraw.hasAlpha() || toDraw.isNull())) {
|
||||
p.fillRect(imgRect, _transparentBrush);
|
||||
}
|
||||
if (toDraw.width() != _w * cIntRetinaFactor()) {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawPixmap(QRect(_x, _y, _w, _h), toDraw);
|
||||
} else {
|
||||
p.drawPixmap(_x, _y, toDraw);
|
||||
if (!toDraw.isNull()) {
|
||||
if (toDraw.width() != _w * cIntRetinaFactor()) {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawPixmap(QRect(_x, _y, _w, _h), toDraw);
|
||||
} else {
|
||||
p.drawPixmap(_x, _y, toDraw);
|
||||
}
|
||||
}
|
||||
|
||||
bool radial = false;
|
||||
|
@ -2165,7 +2186,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
|
|||
p.restoreTextPalette();
|
||||
p.setOpacity(1);
|
||||
}
|
||||
if (_full >= 1) {
|
||||
if (!_blurred) {
|
||||
auto nextFrame = (dt < st::mediaviewSaveMsgShowing || hidingDt >= 0) ? int(AnimationTimerDelta) : (st::mediaviewSaveMsgShowing + st::mediaviewSaveMsgShown + 1 - dt);
|
||||
_saveMsgUpdater.start(nextFrame);
|
||||
}
|
||||
|
@ -2187,7 +2208,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
|
|||
radial = _radial.animating();
|
||||
radialOpacity = _radial.opacity();
|
||||
}
|
||||
if (!_doc || _doc->thumb->isNull()) {
|
||||
if (!_doc || !_doc->hasThumbnail()) {
|
||||
p.fillRect(_docIconRect, _docIconColor);
|
||||
if ((!_doc || _doc->loaded()) && (!radial || radialOpacity < 1) && _docIcon) {
|
||||
_docIcon->paint(p, _docIconRect.x() + (_docIconRect.width() - _docIcon->width()), _docIconRect.y(), width());
|
||||
|
@ -2199,7 +2220,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
} else {
|
||||
int32 rf(cIntRetinaFactor());
|
||||
p.drawPixmap(_docIconRect.topLeft(), _doc->thumb->pix(fileOrigin(), _docThumbw), QRect(_docThumbx * rf, _docThumby * rf, st::mediaviewFileIconSize * rf, st::mediaviewFileIconSize * rf));
|
||||
p.drawPixmap(_docIconRect.topLeft(), _doc->thumbnail()->pix(fileOrigin(), _docThumbw), QRect(_docThumbx * rf, _docThumby * rf, st::mediaviewFileIconSize * rf, st::mediaviewFileIconSize * rf));
|
||||
}
|
||||
|
||||
paintDocRadialLoading(p, radial, radialOpacity);
|
||||
|
@ -2720,10 +2741,10 @@ void MediaView::preloadData(int delta) {
|
|||
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
|
||||
(*photo)->download(fileOrigin());
|
||||
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
|
||||
if (const auto image = (*document)->getStickerImage()) {
|
||||
if (const auto image = (*document)->getStickerLarge()) {
|
||||
image->load(fileOrigin());
|
||||
} else {
|
||||
(*document)->thumb->load(fileOrigin());
|
||||
(*document)->loadThumbnail(fileOrigin());
|
||||
(*document)->automaticLoad(fileOrigin(), entity.item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,6 +251,9 @@ private:
|
|||
void checkGroupThumbsAnimation();
|
||||
void initGroupThumbs();
|
||||
|
||||
void validatePhotoImage(Image *image, bool blurred);
|
||||
void validatePhotoCurrentImage();
|
||||
|
||||
QBrush _transparentBrush;
|
||||
|
||||
PhotoData *_photo = nullptr;
|
||||
|
@ -299,7 +302,7 @@ private:
|
|||
int32 _dragging = 0;
|
||||
QPixmap _current;
|
||||
Media::Clip::ReaderPointer _gif;
|
||||
int32 _full = -1; // -1 - thumb, 0 - medium, 1 - full
|
||||
bool _blurred = true;
|
||||
|
||||
// Video without audio stream playback information.
|
||||
bool _videoIsSilent = false;
|
||||
|
|
|
@ -328,33 +328,23 @@ int32 Photo::resizeGetHeight(int32 width) {
|
|||
void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
|
||||
bool good = _data->loaded(), selected = (selection == FullSelection);
|
||||
if (!good) {
|
||||
_data->medium->automaticLoad(parent()->fullId(), parent());
|
||||
good = _data->medium->loaded();
|
||||
_data->thumbnail()->automaticLoad(parent()->fullId(), parent());
|
||||
good = _data->thumbnail()->loaded();
|
||||
}
|
||||
if ((good && !_goodLoaded) || _pix.width() != _width * cIntRetinaFactor()) {
|
||||
_goodLoaded = good;
|
||||
|
||||
int32 size = _width * cIntRetinaFactor();
|
||||
if (_goodLoaded || _data->thumb->loaded()) {
|
||||
auto img = (_data->loaded() ? _data->full : (_data->medium->loaded() ? _data->medium : _data->thumb))->pix(parent()->fullId()).toImage();
|
||||
if (!_goodLoaded) {
|
||||
img = Images::prepareBlur(std::move(img));
|
||||
_pix = QPixmap();
|
||||
if (_goodLoaded) {
|
||||
setPixFrom(_data->loaded()
|
||||
? _data->large()
|
||||
: _data->thumbnail());
|
||||
} else if (_data->thumbnailSmall()->loaded()) {
|
||||
setPixFrom(_data->thumbnailSmall());
|
||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
||||
blurred->load({});
|
||||
if (blurred->loaded()) {
|
||||
setPixFrom(blurred);
|
||||
}
|
||||
if (img.width() == img.height()) {
|
||||
if (img.width() != size) {
|
||||
img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
} else if (img.width() > img.height()) {
|
||||
img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
} else {
|
||||
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
img.setDevicePixelRatio(cRetinaFactor());
|
||||
_data->unload();
|
||||
|
||||
_pix = App::pixmapFromImageInPlace(std::move(img));
|
||||
} else if (!_pix.isNull()) {
|
||||
_pix = QPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,6 +363,29 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
|||
paintCheckbox(p, { checkLeft, checkTop }, selected, context);
|
||||
}
|
||||
|
||||
void Photo::setPixFrom(not_null<Image*> image) {
|
||||
Expects(image->loaded());
|
||||
|
||||
const auto size = _width * cIntRetinaFactor();
|
||||
auto img = image->original();
|
||||
if (!_goodLoaded) {
|
||||
img = Images::prepareBlur(std::move(img));
|
||||
}
|
||||
if (img.width() == img.height()) {
|
||||
if (img.width() != size) {
|
||||
img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
} else if (img.width() > img.height()) {
|
||||
img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
} else {
|
||||
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
img.setDevicePixelRatio(cRetinaFactor());
|
||||
_data->unload();
|
||||
|
||||
_pix = App::pixmapFromImageInPlace(std::move(img));
|
||||
}
|
||||
|
||||
TextState Photo::getState(
|
||||
QPoint point,
|
||||
StateRequest request) const {
|
||||
|
@ -387,10 +400,9 @@ Video::Video(
|
|||
not_null<DocumentData*> video)
|
||||
: RadialProgressItem(parent)
|
||||
, _data(video)
|
||||
, _duration(formatDurationText(_data->duration()))
|
||||
, _thumbLoaded(false) {
|
||||
, _duration(formatDurationText(_data->duration())) {
|
||||
setDocumentLinks(_data);
|
||||
_data->thumb->load(parent->fullId());
|
||||
_data->loadThumbnail(parent->fullId());
|
||||
}
|
||||
|
||||
void Video::initDimensions() {
|
||||
|
@ -405,7 +417,10 @@ int32 Video::resizeGetHeight(int32 width) {
|
|||
}
|
||||
|
||||
void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
|
||||
bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded();
|
||||
const auto selected = (selection == FullSelection);
|
||||
const auto blurred = _data->thumbnailInline();
|
||||
const auto thumbLoaded = _data->hasThumbnail()
|
||||
&& _data->thumbnail()->loaded();
|
||||
|
||||
_data->automaticLoad(parent()->fullId(), parent());
|
||||
bool loaded = _data->loaded(), displayLoading = _data->displayLoading();
|
||||
|
@ -418,28 +433,25 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
|||
updateStatusText();
|
||||
bool radial = isRadialAnimation(context->ms);
|
||||
|
||||
if ((thumbLoaded && !_thumbLoaded) || (_pix.width() != _width * cIntRetinaFactor())) {
|
||||
_thumbLoaded = thumbLoaded;
|
||||
|
||||
if (_thumbLoaded && !_data->thumb->isNull()) {
|
||||
auto size = _width * cIntRetinaFactor();
|
||||
auto img = Images::prepareBlur(_data->thumb->pix(parent()->fullId()).toImage());
|
||||
if (img.width() == img.height()) {
|
||||
if (img.width() != size) {
|
||||
img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
} else if (img.width() > img.height()) {
|
||||
img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
} else {
|
||||
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
if ((blurred || thumbLoaded)
|
||||
&& (_pix.width() != _width * cIntRetinaFactor())) {
|
||||
auto size = _width * cIntRetinaFactor();
|
||||
auto img = thumbLoaded
|
||||
? _data->thumbnail()->original()
|
||||
: Images::prepareBlur(blurred->original());
|
||||
if (img.width() == img.height()) {
|
||||
if (img.width() != size) {
|
||||
img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
img.setDevicePixelRatio(cRetinaFactor());
|
||||
_data->unload();
|
||||
|
||||
_pix = App::pixmapFromImageInPlace(std::move(img));
|
||||
} else if (!_pix.isNull()) {
|
||||
_pix = QPixmap();
|
||||
} else if (img.width() > img.height()) {
|
||||
img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
} else {
|
||||
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
img.setDevicePixelRatio(cRetinaFactor());
|
||||
_data->unload();
|
||||
|
||||
_pix = App::pixmapFromImageInPlace(std::move(img));
|
||||
}
|
||||
|
||||
if (_pix.isNull()) {
|
||||
|
@ -582,7 +594,7 @@ Voice::Voice(
|
|||
AddComponents(Info::Bit());
|
||||
|
||||
setDocumentLinks(_data);
|
||||
_data->thumb->load(parent->fullId());
|
||||
_data->loadThumbnail(parent->fullId());
|
||||
|
||||
updateName();
|
||||
const auto dateText = textcmdLink(
|
||||
|
@ -641,22 +653,28 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
|||
_width);
|
||||
if (clip.intersects(inner)) {
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto drawThumb = !_data->thumb->isNull()
|
||||
&& _data->thumb->loaded();
|
||||
if (drawThumb) {
|
||||
const auto thumb = _data->thumb->pixCircled(
|
||||
parent()->fullId(),
|
||||
inner.width(),
|
||||
inner.height());
|
||||
const auto thumbLoaded = _data->hasThumbnail()
|
||||
&& _data->thumbnail()->loaded();
|
||||
const auto blurred = _data->thumbnailInline();
|
||||
if (thumbLoaded || blurred) {
|
||||
const auto thumb = thumbLoaded
|
||||
? _data->thumbnail()->pixCircled(
|
||||
parent()->fullId(),
|
||||
inner.width(),
|
||||
inner.height())
|
||||
: blurred->pixBlurredCircled(
|
||||
parent()->fullId(),
|
||||
inner.width(),
|
||||
inner.height());
|
||||
p.drawPixmap(inner.topLeft(), thumb);
|
||||
} else if (!_data->thumb->isNull()) {
|
||||
} else if (_data->hasThumbnail()) {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.setBrush(st::imageBg);
|
||||
p.drawEllipse(inner);
|
||||
}
|
||||
if (selected) {
|
||||
p.setBrush(drawThumb ? st::msgDateImgBgSelected : st::msgFileInBgSelected);
|
||||
} else if (!_data->thumb->isNull()) {
|
||||
p.setBrush((thumbLoaded || blurred) ? st::msgDateImgBgSelected : st::msgFileInBgSelected);
|
||||
} else if (_data->hasThumbnail()) {
|
||||
auto over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl));
|
||||
p.setBrush(anim::brush(st::msgDateImgBg, st::msgDateImgBgOver, _a_iconOver.current(context->ms, over ? 1. : 0.)));
|
||||
} else {
|
||||
|
@ -868,8 +886,8 @@ Document::Document(
|
|||
_status.update(FileStatusSizeReady, _data->size, _data->isSong() ? _data->song()->duration : -1, 0);
|
||||
|
||||
if (withThumb()) {
|
||||
_data->thumb->load(parent->fullId());
|
||||
int32 tw = ConvertScale(_data->thumb->width()), th = ConvertScale(_data->thumb->height());
|
||||
_data->loadThumbnail(parent->fullId());
|
||||
int32 tw = ConvertScale(_data->thumbnail()->width()), th = ConvertScale(_data->thumbnail()->height());
|
||||
if (tw > th) {
|
||||
_thumbw = (tw * _st.fileThumbSize) / th;
|
||||
} else {
|
||||
|
@ -967,12 +985,16 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
|
|||
QRect rthumb(rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width));
|
||||
if (clip.intersects(rthumb)) {
|
||||
if (wthumb) {
|
||||
if (_data->thumb->loaded()) {
|
||||
if (_thumb.isNull() || loaded != _thumbForLoaded) {
|
||||
_thumbForLoaded = loaded;
|
||||
const auto thumbLoaded = _data->thumbnail()->loaded();
|
||||
const auto blurred = _data->thumbnailInline();
|
||||
if (thumbLoaded || blurred) {
|
||||
if (_thumb.isNull() || (thumbLoaded && !_thumbLoaded)) {
|
||||
_thumbLoaded = thumbLoaded;
|
||||
auto options = Images::Option::Smooth | Images::Option::None;
|
||||
if (!_thumbForLoaded) options |= Images::Option::Blurred;
|
||||
_thumb = _data->thumb->pixNoCache(parent()->fullId(), _thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize);
|
||||
if (!_thumbLoaded) options |= Images::Option::Blurred;
|
||||
_thumb = (_thumbLoaded
|
||||
? _data->thumbnail()
|
||||
: blurred)->pixNoCache(parent()->fullId(), _thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize);
|
||||
}
|
||||
p.drawPixmap(rthumb.topLeft(), _thumb);
|
||||
} else {
|
||||
|
@ -1132,7 +1154,7 @@ TextState Document::getState(
|
|||
return { parent(), _msgl };
|
||||
}
|
||||
}
|
||||
if (!_data->loading() && _data->isValid()) {
|
||||
if (!_data->loading() && !_data->isNull()) {
|
||||
auto leftofnamerect = rtlrect(
|
||||
0,
|
||||
st::linksBorder,
|
||||
|
@ -1180,9 +1202,9 @@ bool Document::iconAnimated() const {
|
|||
|
||||
bool Document::withThumb() const {
|
||||
return !_data->isSong()
|
||||
&& !_data->thumb->isNull()
|
||||
&& _data->thumb->width()
|
||||
&& _data->thumb->height()
|
||||
&& _data->hasThumbnail()
|
||||
&& _data->thumbnail()->width()
|
||||
&& _data->thumbnail()->height()
|
||||
&& !Data::IsExecutableName(_data->filename());
|
||||
}
|
||||
|
||||
|
@ -1304,19 +1326,19 @@ Link::Link(
|
|||
}
|
||||
int32 tw = 0, th = 0;
|
||||
if (_page && _page->photo) {
|
||||
if (!_page->photo->loaded()) {
|
||||
_page->photo->thumb->load(parent->fullId(), false, false);
|
||||
if (!_page->photo->loaded()
|
||||
&& !_page->photo->thumbnail()->loaded()
|
||||
&& !_page->photo->thumbnailSmall()->loaded()) {
|
||||
_page->photo->loadThumbnailSmall(parent->fullId());
|
||||
}
|
||||
|
||||
tw = ConvertScale(_page->photo->thumb->width());
|
||||
th = ConvertScale(_page->photo->thumb->height());
|
||||
} else if (_page && _page->document) {
|
||||
if (!_page->document->thumb->loaded()) {
|
||||
_page->document->thumb->load(parent->fullId(), false, false);
|
||||
}
|
||||
tw = ConvertScale(_page->photo->width());
|
||||
th = ConvertScale(_page->photo->height());
|
||||
} else if (_page && _page->document && _page->document->hasThumbnail()) {
|
||||
_page->document->loadThumbnail(parent->fullId());
|
||||
|
||||
tw = ConvertScale(_page->document->thumb->width());
|
||||
th = ConvertScale(_page->document->thumb->height());
|
||||
tw = ConvertScale(_page->document->thumbnail()->width());
|
||||
th = ConvertScale(_page->document->thumbnail()->height());
|
||||
}
|
||||
if (tw > st::linksPhotoSize) {
|
||||
if (th > tw) {
|
||||
|
@ -1397,19 +1419,21 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P
|
|||
if (clip.intersects(rtlrect(0, pixTop, st::linksPhotoSize, st::linksPhotoSize, _width))) {
|
||||
if (_page && _page->photo) {
|
||||
QPixmap pix;
|
||||
if (_page->photo->medium->loaded()) {
|
||||
pix = _page->photo->medium->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
if (_page->photo->thumbnail()->loaded()) {
|
||||
pix = _page->photo->thumbnail()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
} else if (_page->photo->loaded()) {
|
||||
pix = _page->photo->full->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
} else {
|
||||
pix = _page->photo->thumb->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
pix = _page->photo->large()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
} else if (_page->photo->thumbnailSmall()->loaded()) {
|
||||
pix = _page->photo->thumbnailSmall()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
} else if (const auto blurred = _page->photo->thumbnailInline()) {
|
||||
pix = blurred->pixBlurredSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
}
|
||||
p.drawPixmapLeft(pixLeft, pixTop, _width, pix);
|
||||
} else if (_page && _page->document && !_page->document->thumb->isNull()) {
|
||||
} else if (_page && _page->document && _page->document->hasThumbnail()) {
|
||||
auto roundRadius = _page->document->isVideoMessage()
|
||||
? ImageRoundRadius::Ellipse
|
||||
: ImageRoundRadius::Small;
|
||||
p.drawPixmapLeft(pixLeft, pixTop, _width, _page->document->thumb->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius));
|
||||
p.drawPixmapLeft(pixLeft, pixTop, _width, _page->document->thumbnail()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius));
|
||||
} else {
|
||||
const auto index = _letter.isEmpty()
|
||||
? 0
|
||||
|
|
|
@ -208,6 +208,8 @@ public:
|
|||
StateRequest request) const override;
|
||||
|
||||
private:
|
||||
void setPixFrom(not_null<Image*> image);
|
||||
|
||||
not_null<PhotoData*> _data;
|
||||
ClickHandlerPtr _link;
|
||||
|
||||
|
@ -241,7 +243,6 @@ private:
|
|||
|
||||
QString _duration;
|
||||
QPixmap _pix;
|
||||
bool _thumbLoaded = false;
|
||||
|
||||
void updateStatusText();
|
||||
|
||||
|
@ -315,7 +316,7 @@ private:
|
|||
|
||||
const style::OverviewFileLayout &_st;
|
||||
|
||||
bool _thumbForLoaded = false;
|
||||
bool _thumbLoaded = false;
|
||||
QPixmap _thumb;
|
||||
|
||||
Text _name;
|
||||
|
|
|
@ -146,7 +146,7 @@ void BackgroundRow::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
if (radial) {
|
||||
const auto backThumb = App::main()->newBackgroundThumb();
|
||||
if (backThumb->isNull()) {
|
||||
if (!backThumb) {
|
||||
p.drawPixmap(0, 0, _background);
|
||||
} else {
|
||||
const auto &pix = backThumb->pixBlurred(
|
||||
|
|
|
@ -150,11 +150,11 @@ void Uploader::uploadMedia(
|
|||
Auth().data().processPhoto(media.photo, media.photoThumbs);
|
||||
} else if (media.type == SendMediaType::File
|
||||
|| media.type == SendMediaType::Audio) {
|
||||
const auto document = media.photoThumbs.isEmpty()
|
||||
const auto document = media.photoThumbs.empty()
|
||||
? Auth().data().processDocument(media.document)
|
||||
: Auth().data().processDocument(
|
||||
media.document,
|
||||
base::duplicate(media.photoThumbs.begin().value()));
|
||||
base::duplicate(media.photoThumbs.front().second));
|
||||
if (!media.data.isEmpty()) {
|
||||
document->setData(media.data);
|
||||
if (document->saveToCache()
|
||||
|
|
|
@ -198,7 +198,7 @@ SendMediaReady PreparePeerPhoto(PeerId peerId, QImage &&image) {
|
|||
MTP_long(0)),
|
||||
MTP_int(image.width()),
|
||||
MTP_int(image.height()), MTP_int(0)));
|
||||
photoThumbs.insert(type[0], std::move(image));
|
||||
photoThumbs.emplace(type[0], std::move(image));
|
||||
};
|
||||
push("a", scaled(160));
|
||||
push("b", scaled(320));
|
||||
|
@ -795,15 +795,15 @@ void FileLoadTask::process() {
|
|||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (_type != SendMediaType::File) {
|
||||
auto thumb = (w > 100 || h > 100) ? fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage;
|
||||
photoThumbs.insert('s', thumb);
|
||||
photoThumbs.emplace('s', thumb);
|
||||
photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
|
||||
|
||||
auto medium = (w > 320 || h > 320) ? fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage;
|
||||
photoThumbs.insert('m', medium);
|
||||
photoThumbs.emplace('m', medium);
|
||||
photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));
|
||||
|
||||
auto full = (w > 1280 || h > 1280) ? fullimage.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage;
|
||||
photoThumbs.insert('y', full);
|
||||
photoThumbs.emplace('y', full);
|
||||
photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));
|
||||
|
||||
{
|
||||
|
|
|
@ -3753,6 +3753,7 @@ void importOldRecentStickers() {
|
|||
attributes,
|
||||
mime,
|
||||
ImagePtr(),
|
||||
ImagePtr(),
|
||||
dc,
|
||||
size,
|
||||
StorageImageLocation());
|
||||
|
|
|
@ -49,7 +49,11 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) {
|
|||
writeStorageImageLocation(stream, document->sticker()->loc);
|
||||
} else {
|
||||
stream << qint32(document->duration());
|
||||
writeStorageImageLocation(stream, document->thumb->location());
|
||||
if (const auto thumb = document->thumbnail()) {
|
||||
writeStorageImageLocation(stream, thumb->location());
|
||||
} else {
|
||||
writeStorageImageLocation(stream, StorageImageLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,6 +141,7 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &
|
|||
date,
|
||||
attributes,
|
||||
mime,
|
||||
ImagePtr(),
|
||||
thumb.isNull() ? ImagePtr() : Images::Create(thumb),
|
||||
dc,
|
||||
size,
|
||||
|
@ -172,7 +177,11 @@ int Document::sizeInStream(DocumentData *document) {
|
|||
// + duration
|
||||
result += sizeof(qint32);
|
||||
// + thumb loc
|
||||
result += Serialize::storageImageLocationSize(document->thumb->location());
|
||||
if (const auto thumb = document->thumbnail()) {
|
||||
result += Serialize::storageImageLocationSize(thumb->location());
|
||||
} else {
|
||||
result += Serialize::storageImageLocationSize(StorageImageLocation());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -755,7 +755,9 @@ QImage Image::original() const {
|
|||
return _data;
|
||||
}
|
||||
|
||||
void Image::automaticLoad(Data::FileOrigin origin, const HistoryItem *item) {
|
||||
void Image::automaticLoad(
|
||||
Data::FileOrigin origin,
|
||||
const HistoryItem *item) {
|
||||
if (!loaded()) {
|
||||
_source->automaticLoad(origin, item);
|
||||
}
|
||||
|
|
|
@ -198,6 +198,9 @@ public:
|
|||
int height() const {
|
||||
return _source->height();
|
||||
}
|
||||
QSize size() const {
|
||||
return { width(), height() };
|
||||
}
|
||||
int bytesSize() const {
|
||||
return _source->bytesSize();
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ QPixmap PixmapFast(QImage &&image) {
|
|||
}
|
||||
|
||||
QImage prepareBlur(QImage img) {
|
||||
if (img.isNull()) {
|
||||
return img;
|
||||
}
|
||||
auto ratio = img.devicePixelRatio();
|
||||
auto fmt = img.format();
|
||||
if (fmt != QImage::Format_RGB32 && fmt != QImage::Format_ARGB32_Premultiplied) {
|
||||
|
|
|
@ -892,11 +892,6 @@ void MediaPreviewWidget::showPreview(
|
|||
void MediaPreviewWidget::showPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PhotoData*> photo) {
|
||||
if (photo->full->isNull()) {
|
||||
hidePreview();
|
||||
return;
|
||||
}
|
||||
|
||||
startShow();
|
||||
_origin = origin;
|
||||
_photo = photo;
|
||||
|
@ -965,7 +960,7 @@ QSize MediaPreviewWidget::currentDimensions() const {
|
|||
|
||||
QSize result, box;
|
||||
if (_photo) {
|
||||
result = QSize(_photo->full->width(), _photo->full->height());
|
||||
result = QSize(_photo->width(), _photo->height());
|
||||
box = QSize(width() - 2 * st::boxVerticalMargin, height() - 2 * st::boxVerticalMargin);
|
||||
} else {
|
||||
result = _document->dimensions;
|
||||
|
@ -997,13 +992,15 @@ QPixmap MediaPreviewWidget::currentImage() const {
|
|||
if (_document) {
|
||||
if (_document->sticker()) {
|
||||
if (_cacheStatus != CacheLoaded) {
|
||||
if (const auto image = _document->getStickerImage()) {
|
||||
if (const auto image = _document->getStickerLarge()) {
|
||||
QSize s = currentDimensions();
|
||||
_cache = image->pix(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheLoaded;
|
||||
} else if (_cacheStatus != CacheThumbLoaded && _document->thumb->loaded()) {
|
||||
} else if (_cacheStatus != CacheThumbLoaded
|
||||
&& _document->hasThumbnail()
|
||||
&& _document->thumbnail()->loaded()) {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _document->thumb->pixBlurred(_origin, s.width(), s.height());
|
||||
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
}
|
||||
}
|
||||
|
@ -1023,26 +1020,43 @@ QPixmap MediaPreviewWidget::currentImage() const {
|
|||
auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::MediaPreview);
|
||||
return _gif->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : getms());
|
||||
}
|
||||
if (_cacheStatus != CacheThumbLoaded && _document->thumb->loaded()) {
|
||||
if (_cacheStatus != CacheThumbLoaded
|
||||
&& _document->hasThumbnail()) {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _document->thumb->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
if (_document->thumbnail()->loaded()) {
|
||||
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
} else if (const auto blurred = _document->thumbnailInline()) {
|
||||
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
} else {
|
||||
_document->thumbnail()->load(_origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (_photo) {
|
||||
if (_cacheStatus != CacheLoaded) {
|
||||
if (_photo->full->loaded()) {
|
||||
if (_photo->loaded()) {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _photo->full->pix(_origin, s.width(), s.height());
|
||||
_cache = _photo->large()->pix(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheLoaded;
|
||||
} else {
|
||||
if (_cacheStatus != CacheThumbLoaded && _photo->thumb->loaded()) {
|
||||
_photo->load(_origin);
|
||||
if (_cacheStatus != CacheThumbLoaded) {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _photo->thumb->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
if (_photo->thumbnail()->loaded()) {
|
||||
_cache = _photo->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
} else if (_photo->thumbnailSmall()->loaded()) {
|
||||
_cache = _photo->thumbnailSmall()->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
} else if (const auto blurred = _photo->thumbnailInline()) {
|
||||
_cache = blurred->pixBlurred(_origin, s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
} else {
|
||||
_photo->thumbnailSmall()->load(_origin);
|
||||
}
|
||||
}
|
||||
_photo->thumb->load(_origin);
|
||||
_photo->full->load(_origin);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
class Image;
|
||||
|
||||
namespace Data {
|
||||
|
||||
struct WallPaper {
|
||||
|
@ -14,7 +16,7 @@ struct WallPaper {
|
|||
uint64 accessHash = 0;
|
||||
MTPDwallPaper::Flags flags;
|
||||
QString slug;
|
||||
ImagePtr thumb;
|
||||
Image *thumb = nullptr;
|
||||
DocumentData *document = nullptr;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue