-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add AsyncImage * Add CacheThumbnailImageProvider * Add AbstractCache * Add and use DiskCache * Add cacheUpdated signal * Fix hanging on close * Fix crash * cleanup includes
- Loading branch information
Showing
11 changed files
with
300 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import QtQuick 2.15 | ||
import QtQuick.Controls 2.15 | ||
|
||
Item { | ||
id: root | ||
|
||
property bool cached: false | ||
|
||
property string source | ||
|
||
Image { | ||
id: image | ||
anchors.fill: parent | ||
|
||
fillMode: Image.PreserveAspectFit | ||
asynchronous: true | ||
|
||
sourceSize.width: image.width | ||
sourceSize.height: image.height | ||
|
||
source: root.cached ? `image://cache_thumbnail/${root.source}` : root.source | ||
} | ||
|
||
BusyIndicator { | ||
anchors.fill: parent | ||
visible: image.status === Image.Loading | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import QtQuick 2.15 | ||
|
||
import "../MDI" as MDI | ||
import ".." as Core | ||
|
||
Item { | ||
id: root | ||
|
||
property string name | ||
property string mime | ||
property string path | ||
|
||
readonly property bool isImage: root.mime.startsWith("image/") | ||
|
||
MDI.Icon { | ||
id: icon | ||
anchors.fill: parent | ||
|
||
name: root.name | ||
visible: !root.isImage | ||
} | ||
|
||
Core.AsyncImage { | ||
anchors.fill: parent | ||
source: path | ||
cached: true | ||
visible: root.isImage | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#include "abstractcache.h" | ||
|
||
AbstractCache::AbstractCache(QObject *parent) : QObject{parent} {} | ||
|
||
QByteArray AbstractCache::withCache(const QString &key, std::function<QByteArray()> f) { | ||
if (!exists(key)) { | ||
set(key, f()); | ||
} | ||
|
||
return get(key); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#pragma once | ||
|
||
#include <QObject> | ||
#include <functional> | ||
|
||
class AbstractCache : public QObject { | ||
Q_OBJECT | ||
public: | ||
explicit AbstractCache(QObject *parent = nullptr); | ||
|
||
virtual QByteArray get(const QString &) const = 0; | ||
virtual void set(const QString &, const QByteArray &) = 0; | ||
virtual bool exists(const QString &) const = 0; | ||
|
||
QByteArray withCache(const QString &, std::function<QByteArray()>); | ||
|
||
signals: | ||
void cacheUpdated(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#include "cachethumbnailimageprovider.h" | ||
|
||
#include <QFutureWatcher> | ||
#include <QQuickImageResponse> | ||
#include <QtConcurrent/QtConcurrent> | ||
|
||
#include "abstractcache.h" | ||
|
||
class AsyncImageResponse : public QQuickImageResponse { | ||
public: | ||
AsyncImageResponse(const QString &id, const QSize &requestedSize, AbstractCache *cache) { | ||
auto watcher = new QFutureWatcher<QImage>(); | ||
|
||
auto f = QtConcurrent::run([id, requestedSize, this, cache]() { | ||
QImage result; | ||
|
||
if (requestedSize.isEmpty()) { | ||
return result; | ||
} | ||
|
||
if (cache != nullptr) { | ||
auto data = cache->withCache(imageCacheId(id, requestedSize), [id, requestedSize]() { | ||
QByteArray ba; | ||
QImage image(id); // TODO: add support for network sources | ||
if (image.isNull()) { | ||
return ba; | ||
} | ||
if (!image.isNull()) { | ||
image = image.scaled(requestedSize, Qt::KeepAspectRatio); | ||
} | ||
QBuffer buffer(&ba); | ||
buffer.open(QIODevice::WriteOnly); | ||
Q_ASSERT(image.save(&buffer, "png")); | ||
qDebug() << ba.size(); | ||
return ba; | ||
}); | ||
|
||
result.loadFromData(data); | ||
} else { | ||
QImage image(id); // TODO: add support for network sources | ||
if (!image.isNull()) { | ||
result = image.scaled(requestedSize, Qt::KeepAspectRatio); | ||
} | ||
} | ||
return result; | ||
}); | ||
|
||
connect(watcher, &QFutureWatcher<QImage>::finished, watcher, [this, f, watcher]() { | ||
m_image = f.result(); | ||
emit finished(); | ||
watcher->deleteLater(); | ||
}); | ||
|
||
watcher->setFuture(f); | ||
} | ||
|
||
QQuickTextureFactory *textureFactory() const override { | ||
return QQuickTextureFactory::textureFactoryForImage(m_image); | ||
} | ||
|
||
private: | ||
QImage m_image; | ||
|
||
QString imageCacheId(const QString &id, const QSize &size) const { | ||
return QString("%1//%2x%3").arg(id).arg(size.width()).arg(size.height()); | ||
} | ||
}; | ||
|
||
QQuickImageResponse *CacheThumbnailImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize) { | ||
return new AsyncImageResponse(id, requestedSize, m_cache); | ||
} | ||
|
||
AbstractCache *CacheThumbnailImageProvider::cache() const { return m_cache; } | ||
|
||
void CacheThumbnailImageProvider::setCache(AbstractCache *newCache) { m_cache = newCache; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#pragma once | ||
|
||
#include <QQuickAsyncImageProvider> | ||
#include <QThreadPool> | ||
|
||
class AbstractCache; | ||
|
||
class CacheThumbnailImageProvider : public QQuickAsyncImageProvider { | ||
public: | ||
virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize); | ||
|
||
AbstractCache *cache() const; | ||
void setCache(AbstractCache *newCache); | ||
|
||
private: | ||
AbstractCache *m_cache = nullptr; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#include "diskcache.h" | ||
|
||
#include <QCryptographicHash> | ||
#include <QStandardPaths> | ||
|
||
DiskCache::DiskCache(QObject *parent) : AbstractCache{parent} { | ||
m_root = QDir(QStandardPaths::standardLocations(QStandardPaths::CacheLocation)[0]); | ||
m_root.mkpath("thumbnails"); | ||
m_root.cd("thumbnails"); | ||
|
||
Q_ASSERT(m_root.exists()); | ||
} | ||
|
||
QByteArray DiskCache::get(const QString &key) const { | ||
auto info = keyToPath(key); | ||
if (m_root.exists(info.filePath())) { | ||
QFile f(m_root.absoluteFilePath(info.filePath())); | ||
f.open(QIODevice::ReadOnly); | ||
auto data = f.readAll(); | ||
f.close(); | ||
return data; | ||
} else { | ||
return QByteArray(); | ||
} | ||
} | ||
|
||
void DiskCache::set(const QString &key, const QByteArray &data) { | ||
auto info = keyToPath(key); | ||
Q_ASSERT(m_root.mkpath(info.path())); | ||
|
||
QFile file(m_root.absoluteFilePath(info.filePath())); | ||
|
||
Q_ASSERT(file.open(QIODevice::WriteOnly)); | ||
|
||
file.write(data); | ||
file.close(); | ||
emit cacheUpdated(); | ||
} | ||
|
||
bool DiskCache::exists(const QString &key) const { return m_root.exists(keyToPath(key).filePath()); } | ||
|
||
QFileInfo DiskCache::keyToPath(const QString &key) const { | ||
auto parts = key.split("//"); | ||
QFileInfo info(parts[0]); | ||
Q_ASSERT(info.exists()); | ||
|
||
auto size = parts[1].split("x"); | ||
Q_ASSERT(size.length() == 2); | ||
|
||
QCryptographicHash hash(QCryptographicHash::Sha256); | ||
hash.addData(info.absoluteFilePath().toLocal8Bit()); | ||
|
||
auto hashStr = hash.result().toHex(); | ||
|
||
return QFileInfo(QString("%1/%2/%3/%4_%5x%6.%7") | ||
.arg(hashStr[0]) | ||
.arg(hashStr[1]) | ||
.arg(hashStr[2]) | ||
.arg(QString(hashStr)) | ||
.arg(size[0]) | ||
.arg(size[1]) | ||
.arg(info.suffix())); | ||
} |
Oops, something went wrong.