275 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| This file is part of Telegram Desktop,
 | |
| the official desktop application for the Telegram messaging service.
 | |
| 
 | |
| For license and copyright information please follow this link:
 | |
| https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | |
| */
 | |
| #include "data/data_photo.h"
 | |
| 
 | |
| #include "data/data_session.h"
 | |
| #include "data/data_file_origin.h"
 | |
| #include "ui/image/image.h"
 | |
| #include "ui/image/image_source.h"
 | |
| #include "mainwidget.h"
 | |
| #include "core/application.h"
 | |
| #include "facades.h"
 | |
| #include "app.h"
 | |
| 
 | |
| PhotoData::PhotoData(not_null<Data::Session*> owner, PhotoId id)
 | |
| : id(id)
 | |
| , _owner(owner) {
 | |
| }
 | |
| 
 | |
| Data::Session &PhotoData::owner() const {
 | |
| 	return *_owner;
 | |
| }
 | |
| 
 | |
| Main::Session &PhotoData::session() const {
 | |
| 	return _owner->session();
 | |
| }
 | |
| 
 | |
| void PhotoData::automaticLoad(
 | |
| 		Data::FileOrigin origin,
 | |
| 		const HistoryItem *item) {
 | |
| 	_large->automaticLoad(origin, item);
 | |
| }
 | |
| 
 | |
| void PhotoData::automaticLoadSettingsChanged() {
 | |
| 	_large->automaticLoadSettingsChanged();
 | |
| }
 | |
| 
 | |
| void PhotoData::download(Data::FileOrigin origin) {
 | |
| 	_large->loadEvenCancelled(origin);
 | |
| 	_owner->notifyPhotoLayoutChanged(this);
 | |
| }
 | |
| 
 | |
| bool PhotoData::loaded() const {
 | |
| 	bool wasLoading = loading();
 | |
| 	if (_large->loaded()) {
 | |
| 		if (wasLoading) {
 | |
| 			_owner->notifyPhotoLayoutChanged(this);
 | |
| 		}
 | |
| 		return true;
 | |
| 	}
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| bool PhotoData::loading() const {
 | |
| 	return _large->loading();
 | |
| }
 | |
| 
 | |
| bool PhotoData::displayLoading() const {
 | |
| 	return _large->loading()
 | |
| 		? _large->displayLoading()
 | |
| 		: (uploading() && !waitingForAlbum());
 | |
| }
 | |
| 
 | |
| void PhotoData::cancel() {
 | |
| 	_large->cancel();
 | |
| 	_owner->notifyPhotoLayoutChanged(this);
 | |
| }
 | |
| 
 | |
| float64 PhotoData::progress() const {
 | |
| 	if (uploading()) {
 | |
| 		if (uploadingData->size > 0) {
 | |
| 			return float64(uploadingData->offset) / uploadingData->size;
 | |
| 		}
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return _large->progress();
 | |
| }
 | |
| 
 | |
| void PhotoData::setWaitingForAlbum() {
 | |
| 	if (uploading()) {
 | |
| 		uploadingData->waitingForAlbum = true;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool PhotoData::waitingForAlbum() const {
 | |
| 	return uploading() && uploadingData->waitingForAlbum;
 | |
| }
 | |
| 
 | |
| int32 PhotoData::loadOffset() const {
 | |
| 	return _large->loadOffset();
 | |
| }
 | |
| 
 | |
| bool PhotoData::uploading() const {
 | |
| 	return (uploadingData != nullptr);
 | |
| }
 | |
| 
 | |
| void PhotoData::unload() {
 | |
| 	// 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
 | |
| 		&& (_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.image();
 | |
| }
 | |
| 
 | |
| void PhotoData::setRemoteLocation(
 | |
| 		int32 dc,
 | |
| 		uint64 access,
 | |
| 		const QByteArray &fileReference) {
 | |
| 	_fileReference = fileReference;
 | |
| 	if (_dc != dc || _access != access) {
 | |
| 		_dc = dc;
 | |
| 		_access = access;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| MTPInputPhoto PhotoData::mtpInput() const {
 | |
| 	return MTP_inputPhoto(
 | |
| 		MTP_long(id),
 | |
| 		MTP_long(_access),
 | |
| 		MTP_bytes(_fileReference));
 | |
| }
 | |
| 
 | |
| QByteArray PhotoData::fileReference() const {
 | |
| 	return _fileReference;
 | |
| }
 | |
| 
 | |
| void PhotoData::refreshFileReference(const QByteArray &value) {
 | |
| 	_fileReference = value;
 | |
| 	_thumbnailSmall->refreshFileReference(value);
 | |
| 	_thumbnail->refreshFileReference(value);
 | |
| 	_large->refreshFileReference(value);
 | |
| }
 | |
| 
 | |
| void PhotoData::collectLocalData(not_null<PhotoData*> local) {
 | |
| 	if (local == this) {
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	const auto copyImage = [&](const ImagePtr &src, const ImagePtr &dst) {
 | |
| 		if (const auto from = src->cacheKey()) {
 | |
| 			if (const auto to = dst->cacheKey()) {
 | |
| 				_owner->cache().copyIfEmpty(*from, *to);
 | |
| 			}
 | |
| 		}
 | |
| 	};
 | |
| 	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.valid()) {
 | |
| 				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 {
 | |
| 	Core::App().showPhoto(this);
 | |
| }
 | |
| 
 | |
| void PhotoSaveClickHandler::onClickImpl() const {
 | |
| 	auto data = photo();
 | |
| 	if (!data->date) return;
 | |
| 
 | |
| 	data->download(context());
 | |
| }
 | |
| 
 | |
| void PhotoCancelClickHandler::onClickImpl() const {
 | |
| 	auto data = photo();
 | |
| 	if (!data->date) return;
 | |
| 
 | |
| 	if (data->uploading()) {
 | |
| 		if (const auto item = data->owner().message(context())) {
 | |
| 			App::main()->cancelUploadLayer(item);
 | |
| 		}
 | |
| 	} else {
 | |
| 		data->cancel();
 | |
| 	}
 | |
| }
 | 
