[multimedia/kasts] src: Replace image loading and caching with normal qml image loading and QNetworkDiskCache
Bart De Vries <[email protected]> Tue, 4 Aug 2026 12:39:01 +0000 (UTC)
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit c2bcbb8e1e79d8c4a438cd965d2161302de8b564 by Bart De Vries, on behalf of Tobias Fella.
Committed on 04/08/2026 at 07:43.
Pushed by bdevries into branch 'master'.
Replace image loading and caching with normal qml image loading and QNetworkDiskCache
M +1 -1 src/audiomanager.cpp
M +1 -24 src/chapter.cpp
M +0 -3 src/chapter.h
M +0 -1 src/enclosure.cpp
M +0 -28 src/entry.cpp
M +0 -3 src/entry.h
M +0 -12 src/feed.cpp
M +0 -3 src/feed.h
M +0 -48 src/fetcher.cpp
M +0 -1 src/fetcher.h
M +22 -0 src/main.cpp
M +1 -1 src/qml/ChapterListDelegate.qml
M +2 -2 src/qml/Desktop/HeaderBar.qml
M +1 -1 src/qml/EntryPage.qml
M +1 -1 src/qml/FeedDetailsPage.qml
M +1 -1 src/qml/FeedListDelegate.qml
M +1 -1 src/qml/GenericEntryDelegate.qml
M +1 -1 src/qml/GlobalSearchField.qml
M +11 -3 src/qml/ImageWithFallback.qml
M +1 -1 src/qml/Mobile/FooterBar.qml
M +1 -1 src/qml/Mobile/MinimizedPlayerControls.qml
M +2 -2 src/qml/Mobile/MobilePlayerControls.qml
https://invent.kde.org/multimedia/kasts/-/commit/c2bcbb8e1e79d8c4a438cd965d2161302de8b564
diff --git a/src/audiomanager.cpp b/src/audiomanager.cpp
index c2389d00..8d303995 100644
--- a/src/audiomanager.cpp
+++ b/src/audiomanager.cpp
@@ -807,7 +807,7 @@ void AudioManager::updateMetaData()
d->m_player.metaData()->setArtist(d->m_entry->authors());
}
if (!d->m_entry->image().isEmpty()) {
- d->m_player.metaData()->setArtworkUrl(QUrl(d->m_entry->cachedImage()));
+ d->m_player.metaData()->setArtworkUrl(QUrl(d->m_entry->image()));
}
}
diff --git a/src/chapter.cpp b/src/chapter.cpp
index 951e566b..3128562e 100644
--- a/src/chapter.cpp
+++ b/src/chapter.cpp
@@ -18,12 +18,6 @@ Chapter::Chapter(Entry *entry, const QString &title, const QString &link, const
, m_start(start)
{
qCDebug(kastsObjects) << "Chapter object constructed: entryuid" << m_entry->entryuid() << ", chapter start" << m_start;
- connect(&Fetcher::instance(), &Fetcher::downloadFinished, this, [this](QString url) {
- if (url == m_image) {
- Q_EMIT imageChanged(url);
- Q_EMIT cachedImageChanged(cachedImage());
- }
- });
}
Chapter::~Chapter()
@@ -53,24 +47,8 @@ QString Chapter::image() const
} else if (m_entry) {
// fall back to entry image
return m_entry->image();
- } else {
- return QStringLiteral("no-image");
}
-}
-
-QString Chapter::cachedImage() const
-{
- // First check for the feed image, fall back if needed
- QString image = m_image;
- if (image.isEmpty()) {
- if (m_entry) {
- return m_entry->cachedImage();
- } else {
- return QStringLiteral("no-image");
- }
- }
-
- return Fetcher::instance().image(image);
+ return {};
}
int Chapter::start() const
@@ -104,7 +82,6 @@ void Chapter::setImage(const QString &image, bool emitSignal)
m_image = image;
if (emitSignal) {
Q_EMIT imageChanged(m_image);
- Q_EMIT cachedImageChanged(cachedImage());
}
}
}
diff --git a/src/chapter.h b/src/chapter.h
index 3c7dbb06..6cdca065 100644
--- a/src/chapter.h
+++ b/src/chapter.h
@@ -23,7 +23,6 @@ class Chapter : public QObject
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
Q_PROPERTY(QString link READ link NOTIFY linkChanged)
Q_PROPERTY(QString image READ image NOTIFY imageChanged)
- Q_PROPERTY(QString cachedImage READ cachedImage NOTIFY cachedImageChanged)
Q_PROPERTY(int start READ start NOTIFY startChanged)
public:
@@ -34,7 +33,6 @@ public:
QString title() const;
QString link() const;
QString image() const;
- QString cachedImage() const;
int start() const;
void setTitle(const QString &title, bool emitSignal = true);
@@ -46,7 +44,6 @@ Q_SIGNALS:
void titleChanged(const QString &title);
void linkChanged(const QString &link);
void imageChanged(const QString &url);
- void cachedImageChanged(const QString &imagePath);
void startChanged(const int &start);
private:
diff --git a/src/enclosure.cpp b/src/enclosure.cpp
index 206535ad..d0a6616b 100644
--- a/src/enclosure.cpp
+++ b/src/enclosure.cpp
@@ -311,7 +311,6 @@ void Enclosure::processDownloadedFile()
// Trigger update of image since the downloaded file can have an embedded image
Q_EMIT m_entry->imageChanged(m_entry->image());
- Q_EMIT m_entry->cachedImageChanged(m_entry->cachedImage());
}
void Enclosure::deleteFile()
diff --git a/src/entry.cpp b/src/entry.cpp
index 91d9784e..99f858a0 100644
--- a/src/entry.cpp
+++ b/src/entry.cpp
@@ -52,15 +52,6 @@ Entry::Entry(const qint64 entryuid, QObject *parent)
Q_EMIT queueStatusChanged(state);
}
});
- connect(&Fetcher::instance(), &Fetcher::downloadFinished, this, [this](const QString url) {
- if (url == m_image) {
- Q_EMIT imageChanged(url);
- Q_EMIT cachedImageChanged(cachedImage());
- } else if (m_image.isEmpty() && url == m_feed->image()) {
- Q_EMIT imageChanged(url);
- Q_EMIT cachedImageChanged(cachedImage());
- }
- });
connect(&Fetcher::instance(), &Fetcher::entryUpdated, this, [this](const qint64 entryuid) {
if (m_entryuid == entryuid) {
updateFromDb();
@@ -292,7 +283,6 @@ void Entry::setImage(const QString &image, bool emitSignal)
m_image = image;
if (emitSignal) {
Q_EMIT imageChanged(m_image);
- Q_EMIT cachedImageChanged(cachedImage());
}
}
}
@@ -442,24 +432,6 @@ QString Entry::image() const
}
}
-QString Entry::cachedImage() const
-{
- // First check for an image in the downloaded file
- if (m_hasenclosure && !m_enclosure->cachedEmbeddedImage().isEmpty()) {
- // use embedded image if available
- return m_enclosure->cachedEmbeddedImage();
- }
-
- // Then check for the entry image, fall back if needed to feed image
- QString image = m_image;
- if (image.isEmpty()) {
- // else fall back to feed image
- image = m_feed->image();
- }
-
- return Fetcher::instance().image(image);
-}
-
bool Entry::queueStatus() const
{
return QueueModel::instance().entryInQueue(m_entryuid);
diff --git a/src/entry.h b/src/entry.h
index 84337001..9ab5816f 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -40,7 +40,6 @@ class Entry : public QObject
Q_PROPERTY(Enclosure *enclosure READ enclosure CONSTANT)
Q_PROPERTY(bool hasEnclosure READ hasEnclosure NOTIFY hasEnclosureChanged)
Q_PROPERTY(QString image READ image NOTIFY imageChanged)
- Q_PROPERTY(QString cachedImage READ cachedImage NOTIFY cachedImageChanged)
Q_PROPERTY(bool queueStatus READ queueStatus WRITE setQueueStatus NOTIFY queueStatusChanged)
public:
@@ -63,7 +62,6 @@ public:
Enclosure *enclosure() const;
bool hasEnclosure() const;
QString image() const;
- QString cachedImage() const;
bool queueStatus() const;
Feed *feed() const;
@@ -90,7 +88,6 @@ Q_SIGNALS:
void removedChanged(bool removed);
void hasEnclosureChanged(bool hasEnclosure);
void imageChanged(const QString &url);
- void cachedImageChanged(const QString &imagePath);
void queueStatusChanged(bool queueStatus);
private:
diff --git a/src/feed.cpp b/src/feed.cpp
index 2761a831..452baaad 100644
--- a/src/feed.cpp
+++ b/src/feed.cpp
@@ -105,12 +105,6 @@ Feed::Feed(const qint64 feeduid, QObject *parent)
setRefreshing(false);
}
});
- connect(&Fetcher::instance(), &Fetcher::downloadFinished, this, [this](QString url) {
- if (url == m_image) {
- Q_EMIT imageChanged(url);
- Q_EMIT cachedImageChanged(cachedImage());
- }
- });
m_entries = new EntriesProxyModel(m_feeduid, this);
@@ -257,11 +251,6 @@ QString Feed::image() const
return m_image;
}
-QString Feed::cachedImage() const
-{
- return Fetcher::instance().image(m_image);
-}
-
QString Feed::link() const
{
return m_link;
@@ -340,7 +329,6 @@ void Feed::setImage(const QString &image)
if (image != m_image) {
m_image = image;
Q_EMIT imageChanged(m_image);
- Q_EMIT cachedImageChanged(cachedImage());
}
}
diff --git a/src/feed.h b/src/feed.h
index 1a561062..cf708f7e 100644
--- a/src/feed.h
+++ b/src/feed.h
@@ -25,7 +25,6 @@ class Feed : public QObject
Q_PROPERTY(QString url READ url CONSTANT)
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(QString image READ image NOTIFY imageChanged)
- Q_PROPERTY(QString cachedImage READ cachedImage NOTIFY cachedImageChanged)
Q_PROPERTY(QString link READ link NOTIFY linkChanged)
Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
Q_PROPERTY(QString authors READ authors NOTIFY authorsChanged)
@@ -50,7 +49,6 @@ public:
QString url() const;
QString name() const;
QString image() const;
- QString cachedImage() const;
QString link() const;
QString description() const;
QString authors() const;
@@ -82,7 +80,6 @@ public:
Q_SIGNALS:
void nameChanged(const QString &name);
void imageChanged(const QString &image);
- void cachedImageChanged(const QString &imagePath);
void linkChanged(const QString &link);
void descriptionChanged(const QString &description);
void authorsChanged(const QString &authors);
diff --git a/src/fetcher.cpp b/src/fetcher.cpp
index 336090e7..645d8cef 100644
--- a/src/fetcher.cpp
+++ b/src/fetcher.cpp
@@ -115,54 +115,6 @@ void Fetcher::fetch(const QStringList &urls)
qCDebug(kastsFetcher) << "end of Fetcher::fetch";
}
-QString Fetcher::image(const QString &url)
-{
- if (url.isEmpty()) {
- return QLatin1String("no-image");
- }
-
- // if image is already cached, then return the path
- QString path = StorageManager::instance().imagePath(url);
- if (QFileInfo::exists(path)) {
- if (QFileInfo(path).size() != 0) {
- return QUrl::fromLocalFile(path).toString();
- }
- }
-
- // avoid restarting an image download if it's already running
- if (m_ongoingImageDownloads.contains(url)) {
- return QLatin1String("fetching");
- }
-
- // if image has not yet been cached, then check for network connectivity if
- // possible; and download the image
- if (!NetworkConnectionManager::instance().imageDownloadsAllowed()) {
- return QLatin1String("no-image");
- }
-
- m_ongoingImageDownloads.insert(url);
- QNetworkRequest request((QUrl(url)));
- request.setTransferTimeout();
- QNetworkReply *reply = get(request);
- connect(reply, &QNetworkReply::finished, this, [this, reply, path, url]() {
- if (reply->isOpen() && !reply->error()) {
- QByteArray data = reply->readAll();
- QFile file(path);
-
- // TODO: We currently don't handle the case where we can't store the image locally.
- // Maybe we should emit an error? But this would probably flood the error log.
- if (file.open(QIODevice::WriteOnly)) {
- file.write(data);
- file.close();
- Q_EMIT downloadFinished(url);
- }
- }
- m_ongoingImageDownloads.remove(url);
- reply->deleteLater();
- });
- return QLatin1String("fetching");
-}
-
EnclosureDownloadJob *Fetcher::enqueueEnclosureDownload(const qint64 entryuid, const QString &url, const QString &path, const QString &title)
{
QPointer<EnclosureDownloadJob> newDownloadJob = new EnclosureDownloadJob(entryuid, url, path, title);
diff --git a/src/fetcher.h b/src/fetcher.h
index 50ebffad..8be8a9c7 100644
--- a/src/fetcher.h
+++ b/src/fetcher.h
@@ -47,7 +47,6 @@ public:
Q_INVOKABLE void fetch(const QString &url);
Q_INVOKABLE void fetch(const QStringList &urls);
Q_INVOKABLE void fetchAll();
- Q_INVOKABLE QString image(const QString &url);
EnclosureDownloadJob *enqueueEnclosureDownload(const qint64 entryuid, const QString &url, const QString &path, const QString &title);
void processEnclosureDownloadQueue();
diff --git a/src/main.cpp b/src/main.cpp
index 0b72f4d7..7785fae1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -10,9 +10,12 @@
#include <QFile>
#include <QIcon>
#include <QLoggingCategory>
+#include <QNetworkAccessManager>
+#include <QNetworkDiskCache>
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlContext>
+#include <QQmlNetworkAccessManagerFactory>
#include <QQuickStyle>
#include <QQuickView>
#include <QSettings>
@@ -63,6 +66,23 @@
Q_DECL_EXPORT
#endif
+class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
+{
+public:
+ QNetworkAccessManager *create(QObject *parent) override
+ {
+ static QNetworkAccessManager *manager = nullptr;
+ if (!manager) {
+ manager = new QNetworkAccessManager(parent);
+ auto cache = new QNetworkDiskCache(manager);
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1StringView("/cacheDir/");
+ cache->setCacheDirectory(directory);
+ manager->setCache(cache);
+ }
+ return manager;
+ }
+};
+
int main(int argc, char *argv[])
{
// Check if we need to force the interface to mobile or desktop, or stick
@@ -138,6 +158,8 @@ int main(int argc, char *argv[])
}
QQmlApplicationEngine engine;
+ NetworkAccessManagerFactory networkAccessManagerFactory;
+ engine.setNetworkAccessManagerFactory(&networkAccessManagerFactory);
KLocalization::setupLocalizedContext(&engine);
QCommandLineParser parser;
diff --git a/src/qml/ChapterListDelegate.qml b/src/qml/ChapterListDelegate.qml
index 67352b1f..657eb6ad 100644
--- a/src/qml/ChapterListDelegate.qml
+++ b/src/qml/ChapterListDelegate.qml
@@ -37,7 +37,7 @@ AddonDelegates.RoundedItemDelegate {
contentItem: RowLayout {
Delegates.IconTitleSubtitle {
- icon.source: root.chapter ? root.chapter.cachedImage : ""
+ icon.source: root.chapter ? root.chapter.image : ""
title: root.title
subtitle: root.formattedStart
Layout.fillWidth: true
diff --git a/src/qml/Desktop/HeaderBar.qml b/src/qml/Desktop/HeaderBar.qml
index d8b6dd8f..7d615e92 100644
--- a/src/qml/Desktop/HeaderBar.qml
+++ b/src/qml/Desktop/HeaderBar.qml
@@ -29,8 +29,8 @@ FocusScope {
property int authorCollapseHeight: Kirigami.Units.gridUnit * 4
property int disappearHeight: Kirigami.Units.gridUnit * 1.0
- property string image: AudioManager.entry ? ((root.desktopPlayerControls.chapterModel.currentChapter && root.desktopPlayerControls.chapterModel.currentChapter !== undefined) ? root.desktopPlayerControls.chapterModel.currentChapter.cachedImage : AudioManager.entry.cachedImage) : "no-image"
- property string blurredImage: AudioManager.entry ? AudioManager.entry.cachedImage : "no-image"
+ property string image: AudioManager.entry ? ((root.desktopPlayerControls.chapterModel.currentChapter && root.desktopPlayerControls.chapterModel.currentChapter !== undefined) ? root.desktopPlayerControls.chapterModel.currentChapter.image : AudioManager.entry.image) : ""
+ property string blurredImage: AudioManager.entry ? AudioManager.entry.image : ""
property string title: AudioManager.entry ? AudioManager.entry.title : KI18n.i18n("No Episode Title")
property Item headerMetaData: _headerMetaData
diff --git a/src/qml/EntryPage.qml b/src/qml/EntryPage.qml
index 96b39138..3fd54cb0 100644
--- a/src/qml/EntryPage.qml
+++ b/src/qml/EntryPage.qml
@@ -74,7 +74,7 @@ Kirigami.ScrollablePage {
GenericHeader {
id: infoHeader
Layout.fillWidth: true
- image: root.entry.cachedImage
+ image: root.entry.image
title: root.entry.title
subtitle: root.entry.feed.name
subtitleClickable: true
diff --git a/src/qml/FeedDetailsPage.qml b/src/qml/FeedDetailsPage.qml
index 92db9c7d..4b532544 100644
--- a/src/qml/FeedDetailsPage.qml
+++ b/src/qml/FeedDetailsPage.qml
@@ -126,7 +126,7 @@ Kirigami.ScrollablePage {
property string authors: isSubscribed ? feed.authors : feed.author
- image: isSubscribed ? feed.cachedImage : feed.image
+ image: isSubscribed ? feed.image : feed.image
title: isSubscribed ? feed.name : feed.title
subtitle: authors ? KI18n.i18nc("by <author(s)>", "by %1", authors) : ""
}
diff --git a/src/qml/FeedListDelegate.qml b/src/qml/FeedListDelegate.qml
index 0402d579..3ba7f1a0 100644
--- a/src/qml/FeedListDelegate.qml
+++ b/src/qml/FeedListDelegate.qml
@@ -166,7 +166,7 @@ Controls.ItemDelegate {
ImageWithFallback {
id: img
anchors.fill: parent
- imageSource: root.feed.cachedImage
+ imageSource: root.feed.image
imageTitle: root.feed.name
imageResize: false // no "stuttering" on resizing the window
isLoading: root.feed.refreshing
diff --git a/src/qml/GenericEntryDelegate.qml b/src/qml/GenericEntryDelegate.qml
index 01dd18de..3f1b5bc1 100644
--- a/src/qml/GenericEntryDelegate.qml
+++ b/src/qml/GenericEntryDelegate.qml
@@ -200,7 +200,7 @@ AddonDelegates.RoundedItemDelegate {
ImageWithFallback {
id: img
- imageSource: root.showFeedImage ? root.entry.feed.cachedImage : root.entry.cachedImage
+ imageSource: root.showFeedImage ? root.entry.feed.image : root.entry.image
property int size: Kirigami.Units.gridUnit * 3
Layout.preferredHeight: size
Layout.preferredWidth: size
diff --git a/src/qml/GlobalSearchField.qml b/src/qml/GlobalSearchField.qml
index 0d06c5d6..804b4069 100644
--- a/src/qml/GlobalSearchField.qml
+++ b/src/qml/GlobalSearchField.qml
@@ -99,7 +99,7 @@ Kirigami.SearchField {
required property int entryuid
contentItem: Delegates.IconTitleSubtitle {
- icon.source: albumDelegate.entry.cachedImage
+ icon.source: albumDelegate.entry.image
title: albumDelegate.entry.title
subtitle: albumDelegate.entry.feed.name
}
diff --git a/src/qml/ImageWithFallback.qml b/src/qml/ImageWithFallback.qml
index 214a4e7f..21876220 100644
--- a/src/qml/ImageWithFallback.qml
+++ b/src/qml/ImageWithFallback.qml
@@ -17,7 +17,8 @@ import org.kde.kasts
Item {
id: root
- property string imageSource: "no-image"
+
+ required property string imageSource
property real imageOpacity: 1
property int absoluteRadius: 0
property real fractionalRadius: 0.0
@@ -30,7 +31,7 @@ Item {
id: imageLoader
anchors.fill: parent
visible: GraphicsInfo.api === GraphicsInfo.Software
- sourceComponent: (root.imageSource === "no-image" || root.imageSource === "") ? fallbackImg : (root.imageSource === "fetching" ? loaderSymbol : realImg)
+ sourceComponent: root.imageSource === "" ? fallbackImg : realImg
}
MultiEffect {
@@ -55,6 +56,7 @@ Item {
Component {
id: realImg
Image {
+ id: image
anchors.fill: parent
source: root.imageSource
fillMode: root.imageFillMode
@@ -66,6 +68,12 @@ Item {
// will ever have (this is mainly the MobilePlayerControls)
sourceSize.width: root.imageResize ? width * Screen.devicePixelRatio : Kirigami.Units.gridUnit * 40
sourceSize.height: root.imageResize ? height * Screen.devicePixelRatio : Kirigami.Units.gridUnit * 40
+
+ Loader {
+ active: image.status === Image.Loading
+ anchors.fill: parent
+ sourceComponent: loaderSymbol
+ }
}
}
@@ -114,7 +122,7 @@ Item {
Loader {
anchors.fill: parent
- active: root.imageTitle !== "" && (SettingsManager.alwaysShowFeedTitles ? true : (root.imageSource === "no-image" || root.imageSource === "fetching"))
+ active: root.imageTitle.length > 0 && (SettingsManager.alwaysShowFeedTitles || root.imageSource.length === 0)
sourceComponent: imageText
}
diff --git a/src/qml/Mobile/FooterBar.qml b/src/qml/Mobile/FooterBar.qml
index 3e907244..b01641cf 100644
--- a/src/qml/Mobile/FooterBar.qml
+++ b/src/qml/Mobile/FooterBar.qml
@@ -142,7 +142,7 @@ Flickable {
Image {
id: backgroundImage
- source: AudioManager.entry.cachedImage
+ source: AudioManager.entry.image
asynchronous: true
visible: GraphicsInfo.api === GraphicsInfo.Software
anchors.fill: parent
diff --git a/src/qml/Mobile/MinimizedPlayerControls.qml b/src/qml/Mobile/MinimizedPlayerControls.qml
index fb75624e..09a7b5d8 100644
--- a/src/qml/Mobile/MinimizedPlayerControls.qml
+++ b/src/qml/Mobile/MinimizedPlayerControls.qml
@@ -62,7 +62,7 @@ Item {
anchors.fill: parent
ImageWithFallback {
- imageSource: (AudioManager.entryuid > 0 && AudioManager.entry) ? ((chapterModel.currentChapter && chapterModel.currentChapter !== undefined) ? chapterModel.currentChapter.cachedImage : AudioManager.entry.cachedImage) : "no-image"
+ imageSource: (AudioManager.entryuid > 0 && AudioManager.entry) ? ((chapterModel.currentChapter && chapterModel.currentChapter !== undefined) ? chapterModel.currentChapter.image : AudioManager.entry.image) : ""
Layout.fillHeight: true
Layout.preferredWidth: height
}
diff --git a/src/qml/Mobile/MobilePlayerControls.qml b/src/qml/Mobile/MobilePlayerControls.qml
index f758327f..6c170c40 100644
--- a/src/qml/Mobile/MobilePlayerControls.qml
+++ b/src/qml/Mobile/MobilePlayerControls.qml
@@ -61,7 +61,7 @@ Kirigami.Page {
Image {
id: backgroundImage
- source: AudioManager.entry.cachedImage
+ source: AudioManager.entry.image
asynchronous: true
visible: GraphicsInfo.api === GraphicsInfo.Software
anchors.fill: parent
@@ -120,7 +120,7 @@ Kirigami.Page {
width: Utils.isWidescreen ? Math.min(parent.height, parent.width / 2) : Math.min(parent.width, height)
ImageWithFallback {
- imageSource: (AudioManager.entryuid > 0 && AudioManager.entry) ? ((root.chapterModel.currentChapter && root.chapterModel.currentChapter !== undefined) ? root.chapterModel.currentChapter.cachedImage : AudioManager.entry.cachedImage) : "no-image"
+ imageSource: (AudioManager.entryuid > 0 && AudioManager.entry) ? ((root.chapterModel.currentChapter && root.chapterModel.currentChapter !== undefined) ? root.chapterModel.currentChapter.image : AudioManager.entry.image) : ""
imageResize: false // prevent stuttering when resizing
imageFillMode: Image.PreserveAspectCrop
anchors.centerIn: parent