diff --git a/Telegram/SourceFiles/data/data_cloud_file.cpp b/Telegram/SourceFiles/data/data_cloud_file.cpp index e8e8801d56..35f57f4c5c 100644 --- a/Telegram/SourceFiles/data/data_cloud_file.cpp +++ b/Telegram/SourceFiles/data/data_cloud_file.cpp @@ -17,6 +17,7 @@ void UpdateCloudFile( CloudFile &file, const ImageWithLocation &data, Storage::Cache::Database &cache, + uint8 cacheTag, Fn restartLoader, Fn usePreloaded) { if (!data.location.valid()) { @@ -42,7 +43,7 @@ void UpdateCloudFile( cacheKey, Storage::Cache::Database::TaggedValue( std::move(cacheBytes), - Data::kImageCacheTag)); + cacheTag)); } } file.location = data.location; @@ -58,4 +59,132 @@ void UpdateCloudFile( } } +void LoadCloudFile( + CloudFile &file, + FileOrigin origin, + LoadFromCloudSetting fromCloud, + bool autoLoading, + uint8 cacheTag, + Fn finalCheck, + Fn done, + Fn fail, + Fn progress) { + if (file.loader) { + if (fromCloud == LoadFromCloudOrLocal) { + file.loader->permitLoadFromCloud(); + } + return; + } else if ((file.flags & CloudFile::Flag::Failed) + || !file.location.valid() + || (finalCheck && !finalCheck())) { + return; + } + file.flags &= ~CloudFile::Flag::Cancelled; + file.loader = CreateFileLoader( + file.location.file(), + origin, + QString(), + file.byteSize, + UnknownFileLocation, + LoadToCacheAsWell, + fromCloud, + autoLoading, + cacheTag); + + const auto finish = [done](CloudFile &file) { + if (!file.loader || file.loader->cancelled()) { + file.flags |= CloudFile::Flag::Cancelled; + } else { + done(file); + } + // NB! file.loader may be in ~FileLoader() already. + if (const auto loader = base::take(file.loader)) { + if (file.flags & CloudFile::Flag::Cancelled) { + loader->cancel(); + } + } + }; + + file.loader->updates( + ) | rpl::start_with_next_error_done([=] { + if (const auto onstack = progress) { + onstack(); + } + }, [=, &file](bool started) { + finish(file); + file.flags |= CloudFile::Flag::Failed; + if (const auto onstack = fail) { + onstack(started); + } + }, [=, &file] { + finish(file); + }, file.loader->lifetime()); + + file.loader->start(); +} + +void LoadCloudFile( + CloudFile &file, + FileOrigin origin, + LoadFromCloudSetting fromCloud, + bool autoLoading, + uint8 cacheTag, + Fn finalCheck, + Fn done, + Fn fail, + Fn progress) { + const auto callback = [=](CloudFile &file) { + if (auto read = file.loader->imageData(); read.isNull()) { + file.flags |= CloudFile::Flag::Failed; + if (const auto onstack = fail) { + onstack(true); + } + } else if (const auto onstack = done) { + onstack(std::move(read)); + } + }; + LoadCloudFile( + file, + origin, + fromCloud, + autoLoading, + cacheTag, + finalCheck, + callback, + std::move(fail), + std::move(progress)); +} + +void LoadCloudFile( + CloudFile &file, + FileOrigin origin, + LoadFromCloudSetting fromCloud, + bool autoLoading, + uint8 cacheTag, + Fn finalCheck, + Fn done, + Fn fail, + Fn progress) { + const auto callback = [=](CloudFile &file) { + if (auto bytes = file.loader->bytes(); bytes.isEmpty()) { + file.flags |= Data::CloudFile::Flag::Failed; + if (const auto onstack = fail) { + onstack(true); + } + } else if (const auto onstack = done) { + onstack(std::move(bytes)); + } + }; + LoadCloudFile( + file, + origin, + fromCloud, + autoLoading, + cacheTag, + finalCheck, + callback, + std::move(fail), + std::move(progress)); +} + } // namespace Data \ No newline at end of file diff --git a/Telegram/SourceFiles/data/data_cloud_file.h b/Telegram/SourceFiles/data/data_cloud_file.h index b9ffb22287..4fb1c6410d 100644 --- a/Telegram/SourceFiles/data/data_cloud_file.h +++ b/Telegram/SourceFiles/data/data_cloud_file.h @@ -39,7 +39,30 @@ void UpdateCloudFile( CloudFile &file, const ImageWithLocation &data, Storage::Cache::Database &cache, + uint8 cacheTag, Fn restartLoader, Fn usePreloaded = nullptr); +void LoadCloudFile( + CloudFile &file, + FileOrigin origin, + LoadFromCloudSetting fromCloud, + bool autoLoading, + uint8 cacheTag, + Fn finalCheck, + Fn done, + Fn fail = nullptr, + Fn progress = nullptr); + +void LoadCloudFile( + CloudFile &file, + FileOrigin origin, + LoadFromCloudSetting fromCloud, + bool autoLoading, + uint8 cacheTag, + Fn finalCheck, + Fn done, + Fn fail = nullptr, + Fn progress = nullptr); + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 665cec00ce..f84fce0ba0 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -617,6 +617,7 @@ void DocumentData::updateThumbnails( _thumbnail, thumbnail, owner().cache(), + Data::kImageCacheTag, [&](Data::FileOrigin origin) { loadThumbnail(origin); }, [&](QImage preloaded) { if (const auto media = activeMediaView()) { @@ -627,6 +628,7 @@ void DocumentData::updateThumbnails( _videoThumbnail, videoThumbnail, owner().cache(), + Data::kAnimationCacheTag, [&](Data::FileOrigin origin) { loadVideoThumbnail(origin); }); } @@ -647,47 +649,24 @@ bool DocumentData::thumbnailLoading() const { } bool DocumentData::thumbnailFailed() const { - return (_flags & Flag::ThumbnailFailed); + return (_thumbnail.flags & Data::CloudFile::Flag::Failed); } void DocumentData::loadThumbnail(Data::FileOrigin origin) { - if (_thumbnail.loader - || (_flags & Flag::ThumbnailFailed) - || !_thumbnail.location.valid()) { - return; - } else if (const auto active = activeMediaView()) { - if (active->thumbnail()) { - return; - } - } + auto &file = _thumbnail; + const auto fromCloud = LoadFromCloudOrLocal; + const auto cacheTag = Data::kImageCacheTag; const auto autoLoading = false; - _thumbnail.loader = CreateFileLoader( - _thumbnail.location.file(), - origin, - QString(), - _thumbnail.byteSize, - UnknownFileLocation, - LoadToCacheAsWell, - LoadFromCloudOrLocal, - autoLoading, - Data::kImageCacheTag); - - _thumbnail.loader->updates( - ) | rpl::start_with_error_done([=](bool started) { - _thumbnail.loader = nullptr; - _flags |= Flag::ThumbnailFailed; - }, [=] { - if (_thumbnail.loader && !_thumbnail.loader->cancelled()) { - if (auto read = _thumbnail.loader->imageData(); read.isNull()) { - _flags |= Flag::ThumbnailFailed; - } else if (const auto active = activeMediaView()) { - active->setThumbnail(std::move(read)); - } + Data::LoadCloudFile(file, origin, fromCloud, autoLoading, cacheTag, [=] { + if (const auto active = activeMediaView()) { + return !active->thumbnail(); } - _thumbnail.loader = nullptr; - }, _thumbnail.loader->lifetime()); - - _thumbnail.loader->start(); + return true; + }, [=](QImage result) { + if (const auto active = activeMediaView()) { + active->setThumbnail(std::move(result)); + } + }); } const ImageLocation &DocumentData::thumbnailLocation() const { @@ -707,48 +686,24 @@ bool DocumentData::videoThumbnailLoading() const { } bool DocumentData::videoThumbnailFailed() const { - return (_flags & Flag::VideoThumbnailFailed); + return (_videoThumbnail.flags & Data::CloudFile::Flag::Failed); } void DocumentData::loadVideoThumbnail(Data::FileOrigin origin) { - if (_videoThumbnail.loader - || (_flags & Flag::VideoThumbnailFailed) - || !_videoThumbnail.location.valid()) { - return; - } else if (const auto active = activeMediaView()) { - if (!active->videoThumbnailContent().isEmpty()) { - return; - } - } + auto &file = _videoThumbnail; + const auto fromCloud = LoadFromCloudOrLocal; + const auto cacheTag = Data::kAnimationCacheTag; const auto autoLoading = false; - _videoThumbnail.loader = CreateFileLoader( - _videoThumbnail.location.file(), - origin, - QString(), - _videoThumbnail.byteSize, - UnknownFileLocation, - LoadToCacheAsWell, - LoadFromCloudOrLocal, - autoLoading, - Data::kAnimationCacheTag); - - _videoThumbnail.loader->updates( - ) | rpl::start_with_error_done([=](bool started) { - _videoThumbnail.loader = nullptr; - _flags |= Flag::VideoThumbnailFailed; - }, [=] { - if (_videoThumbnail.loader && !_videoThumbnail.loader->cancelled()) { - auto bytes = _videoThumbnail.loader->bytes(); - if (bytes.isEmpty()) { - _flags |= Flag::VideoThumbnailFailed; - } else if (const auto active = activeMediaView()) { - active->setVideoThumbnail(std::move(bytes)); - } + Data::LoadCloudFile(file, origin, fromCloud, autoLoading, cacheTag, [=] { + if (const auto active = activeMediaView()) { + return active->videoThumbnailContent().isEmpty(); } - _videoThumbnail.loader = nullptr; - }, _videoThumbnail.loader->lifetime()); - - _videoThumbnail.loader->start(); + return true; + }, [=](QByteArray result) { + if (const auto active = activeMediaView()) { + active->setVideoThumbnail(std::move(result)); + } + }); } const ImageLocation &DocumentData::videoThumbnailLocation() const { diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 9cea52ba62..4af95d1c93 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -257,8 +257,6 @@ private: ImageType = 0x08, DownloadCancelled = 0x10, LoadedInMediaCache = 0x20, - ThumbnailFailed = 0x40, - VideoThumbnailFailed = 0x80, }; using Flags = base::flags; friend constexpr bool is_flag_type(Flag) { return true; }; diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp index c58b65f92e..7f21d2daf0 100644 --- a/Telegram/SourceFiles/data/data_photo.cpp +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -127,14 +127,9 @@ bool PhotoData::displayLoading() const { } void PhotoData::cancel() { - if (!loading()) { - return; + if (loading()) { + _images[PhotoSizeIndex(PhotoSize::Large)].loader->cancel(); } - - const auto index = PhotoSizeIndex(PhotoSize::Large); - _images[index].flags |= Data::CloudFile::Flag::Cancelled; - destroyLoader(PhotoSize::Large); - _owner->photoLoadDone(this); } float64 PhotoData::progress() const { @@ -244,91 +239,37 @@ void PhotoData::load( bool autoLoading) { const auto index = validSizeIndex(size); auto &image = _images[index]; - if (image.loader) { - if (fromCloud == LoadFromCloudOrLocal) { - image.loader->permitLoadFromCloud(); - } - return; - } else if ((image.flags & Data::CloudFile::Flag::Failed) - || !image.location.valid()) { - return; - } else if (const auto active = activeMediaView()) { - if (active->image(size)) { - return; - } - } + // Could've changed, if the requested size didn't have a location. - size = static_cast(index); - - image.flags &= ~Data::CloudFile::Flag::Cancelled; - image.loader = CreateFileLoader( - image.location.file(), - origin, - QString(), - image.byteSize, - UnknownFileLocation, - LoadToCacheAsWell, - fromCloud, - autoLoading, - Data::kImageCacheTag); - - image.loader->updates( - ) | rpl::start_with_next_error_done([=] { - if (size == PhotoSize::Large) { - _owner->photoLoadProgress(this); + const auto loadingSize = static_cast(index); + const auto cacheTag = Data::kImageCacheTag; + Data::LoadCloudFile(image, origin, fromCloud, autoLoading, cacheTag, [=] { + if (const auto active = activeMediaView()) { + return !active->image(size); } - }, [=, &image](bool started) { - finishLoad(size); - image.flags |= Data::CloudFile::Flag::Failed; - if (size == PhotoSize::Large) { + return true; + }, [=](QImage result) { + if (const auto active = activeMediaView()) { + active->set(loadingSize, std::move(result)); + } + if (loadingSize == PhotoSize::Large) { + _owner->photoLoadDone(this); + } + }, [=](bool started) { + if (loadingSize == PhotoSize::Large) { _owner->photoLoadFail(this, started); } }, [=] { - finishLoad(size); - if (size == PhotoSize::Large) { - _owner->photoLoadDone(this); + if (loadingSize == PhotoSize::Large) { + _owner->photoLoadProgress(this); } - }, image.loader->lifetime()); - - image.loader->start(); + }); if (size == PhotoSize::Large) { _owner->notifyPhotoLayoutChanged(this); } } -void PhotoData::finishLoad(PhotoSize size) { - const auto index = PhotoSizeIndex(size); - auto &image = _images[index]; - - // NB! image.loader may be in ~FileLoader() already. - const auto guard = gsl::finally([&] { - destroyLoader(size); - }); - if (!image.loader || image.loader->cancelled()) { - image.flags |= Data::CloudFile::Flag::Cancelled; - return; - } else if (auto read = image.loader->imageData(); read.isNull()) { - image.flags |= Data::CloudFile::Flag::Failed; - } else if (const auto active = activeMediaView()) { - active->set(size, std::move(read)); - } -} - -void PhotoData::destroyLoader(PhotoSize size) { - const auto index = PhotoSizeIndex(size); - auto &image = _images[index]; - - // NB! image.loader may be in ~FileLoader() already. - if (!image.loader) { - return; - } - const auto loader = base::take(image.loader); - if (image.flags & Data::CloudFile::Flag::Cancelled) { - loader->cancel(); - } -} - std::shared_ptr PhotoData::createMediaView() { if (auto result = activeMediaView()) { return result; @@ -356,6 +297,7 @@ void PhotoData::updateImages( _images[PhotoSizeIndex(size)], data, owner().cache(), + Data::kImageCacheTag, [=](Data::FileOrigin origin) { load(size, origin); }, [=](QImage preloaded) { if (const auto media = activeMediaView()) { diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h index 45185524dc..976d0b35a8 100644 --- a/Telegram/SourceFiles/data/data_photo.h +++ b/Telegram/SourceFiles/data/data_photo.h @@ -124,9 +124,6 @@ public: std::unique_ptr uploadingData; private: - void finishLoad(Data::PhotoSize size); - void destroyLoader(Data::PhotoSize size); - QByteArray _inlineThumbnailBytes; std::array _images; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 23979583ae..2db6b7bc69 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -71,7 +71,7 @@ namespace Media { namespace View { namespace { -constexpr auto kPreloadCount = 4; +constexpr auto kPreloadCount = 3; constexpr auto kMaxZoomLevel = 7; // x8 constexpr auto kZoomToScreenLevel = 1024; constexpr auto kOverlayLoaderPriority = 2; @@ -939,7 +939,7 @@ bool OverlayWidget::radialLoading() const { if (_document) { return _document->loading() && !_streamed; } else if (_photo) { - return _photo->loading(); + return _photo->displayLoading(); } return false; } @@ -1122,8 +1122,8 @@ void OverlayWidget::assignMediaPointer(not_null photo) { if (_photo != photo) { _photo = photo; _photoMedia = _photo->createMediaView(); - _photoMedia->wanted(Data::PhotoSize::Large, fileOrigin()); _photoMedia->wanted(Data::PhotoSize::Small, fileOrigin()); + _photo->load(fileOrigin(), LoadFromCloudOrLocal, true); } } @@ -1739,7 +1739,6 @@ void OverlayWidget::refreshMediaViewer() { } findCurrent(); updateControls(); - preloadData(0); } void OverlayWidget::refreshFromLabel(HistoryItem *item) { @@ -3463,7 +3462,7 @@ bool OverlayWidget::moveToNext(int delta) { return false; } auto newIndex = *_index + delta; - return moveToEntity(entityByIndex(newIndex)); + return moveToEntity(entityByIndex(newIndex), delta); } bool OverlayWidget::moveToEntity(const Entity &entity, int preloadDelta) { @@ -3498,22 +3497,14 @@ void OverlayWidget::preloadData(int delta) { auto till = *_index + (delta ? delta * kPreloadCount : 1); if (from > till) std::swap(from, till); - if (delta != 0) { - auto forgetIndex = *_index - delta * 2; - auto entity = entityByIndex(forgetIndex); - if (auto photo = base::get_if>(&entity.data)) { - (*photo)->unload(); - } - } - auto photos = base::flat_set>(); auto documents = base::flat_set>(); - for (auto index = from; index != till; ++index) { + for (auto index = from; index != till + 1; ++index) { auto entity = entityByIndex(index); if (auto photo = base::get_if>(&entity.data)) { const auto [i, ok] = photos.emplace((*photo)->createMediaView()); (*i)->wanted(Data::PhotoSize::Small, fileOrigin()); - (*i)->wanted(Data::PhotoSize::Large, fileOrigin()); + (*photo)->load(fileOrigin(), LoadFromCloudOrLocal, true); } else if (auto document = base::get_if>( &entity.data)) { const auto [i, ok] = documents.emplace(