diff --git a/src/messages/Image.cpp b/src/messages/Image.cpp index da606ef6e74..66a5390e9a9 100644 --- a/src/messages/Image.cpp +++ b/src/messages/Image.cpp @@ -24,6 +24,7 @@ #include #include #include +#include // Duration between each check of every Image instance const auto IMAGE_POOL_CLEANUP_INTERVAL = std::chrono::minutes(1); @@ -423,7 +424,7 @@ bool Image::loaded() const return this->frames_->current().has_value(); } -std::optional Image::pixmapOrLoad() const +std::optional Image::pixmapOrLoad(std::function cb) { assertInGuiThread(); @@ -432,6 +433,10 @@ std::optional Image::pixmapOrLoad() const // See src/messages/layouts/MessageLayoutElement.cpp ImageLayoutElement::paint, for example. this->lastUsed_ = std::chrono::steady_clock::now(); + if (cb != nullptr) + { + this->finishedLoadingCb_ = std::move(cb); + } this->load(); return this->frames_->current(); @@ -574,6 +579,20 @@ void Image::actuallyLoad() return true; }) + .finally([weak]() { + postToThread([weak]() { + auto shared = weak.lock(); + if (!shared) + { + return; + } + + if (shared->finishedLoadingCb_ != nullptr) + { + shared->finishedLoadingCb_(); + } + }); + }) .execute(); } diff --git a/src/messages/Image.hpp b/src/messages/Image.hpp index 6e1052a8a2e..7f82c4fab64 100644 --- a/src/messages/Image.hpp +++ b/src/messages/Image.hpp @@ -2,6 +2,7 @@ #include "common/Aliases.hpp" #include "common/Common.hpp" +#include "common/NetworkResult.hpp" #include #include @@ -13,6 +14,7 @@ #include #include +#include #include #include #include @@ -80,7 +82,7 @@ class Image : public std::enable_shared_from_this const Url &url() const; bool loaded() const; // either returns the current pixmap, or triggers loading it (lazy loading) - std::optional pixmapOrLoad() const; + std::optional pixmapOrLoad(std::function cb = nullptr); void load() const; qreal scale() const; bool isEmpty() const; @@ -111,6 +113,8 @@ class Image : public std::enable_shared_from_this // gui thread only std::unique_ptr frames_{}; + std::function finishedLoadingCb_; + friend class ImageExpirationPool; }; diff --git a/src/widgets/listview/ImagePtrItemDelegate.hpp b/src/widgets/listview/ImagePtrItemDelegate.hpp index 7b7a5163eb4..aa4b3e6b62d 100644 --- a/src/widgets/listview/ImagePtrItemDelegate.hpp +++ b/src/widgets/listview/ImagePtrItemDelegate.hpp @@ -1,19 +1,26 @@ #pragma once +#include "common/QLogging.hpp" #include "messages/Image.hpp" #include "messages/ImageSet.hpp" #include -#include #include #include +#include +#include namespace chatterino { class ImagePtrItemDelegate : public QStyledItemDelegate { std::map ownedImages_; + QTableView *view_; public: + ImagePtrItemDelegate(QTableView *view) + : view_(view) + { + } static constexpr auto IMAGE_URL_ROLE = Qt::UserRole + 1; void paint(QPainter *painter, const QStyleOptionViewItem &option, @@ -27,6 +34,14 @@ class ImagePtrItemDelegate : public QStyledItemDelegate auto opt = img->pixmapOrLoad(); if (!opt) // wait for next time { + if (img->isEmpty()) + { + painter->drawText(option.rect, "[Error]"); + } + else + { + painter->drawText(option.rect, "Loading"); + } return; } auto pixmap = *opt; @@ -56,7 +71,14 @@ class ImagePtrItemDelegate : public QStyledItemDelegate } auto img = Image::fromUrl(Url{url}); - img->pixmapOrLoad(); + img->pixmapOrLoad([this, index]() { + // wait for it to parse + QTimer::singleShot(100, [this, index]() { + this->view_->repaint(); + this->view_->update(index); + }); + }); + // You cannot stop me, clang-tidy auto *bleh = const_cast(this); bleh->ownedImages_[url] = img; diff --git a/src/widgets/settingspages/ImageUploaderPage.cpp b/src/widgets/settingspages/ImageUploaderPage.cpp index d75d53f5bf9..c3226aa4e1f 100644 --- a/src/widgets/settingspages/ImageUploaderPage.cpp +++ b/src/widgets/settingspages/ImageUploaderPage.cpp @@ -21,7 +21,6 @@ namespace chatterino { ImageUploaderPage::ImageUploaderPage() - : imgDelegate_(new ImagePtrItemDelegate()) { LayoutCreator layoutCreator(this); auto tabs = layoutCreator.emplace(); @@ -42,6 +41,7 @@ ImageUploaderPage::ImageUploaderPage() auto *view = layout.emplace().getElement(); view->setModel(model); + this->imgDelegate_ = new ImagePtrItemDelegate(view); view->setItemDelegateForColumn(0, this->imgDelegate_); view->setSelectionMode(QAbstractItemView::SingleSelection);