[plasma/discover] libdiscover: pk+flatpak: Simplify fetching icons by reusing code

Aleix Pol Gonzalez <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 95e6cad9e87e4be3227e31a95c8cb1dc6dcdf5a1 by Aleix Pol Gonzalez, on behalf of Aleix Pol.
Committed on 24/07/2026 at 09:42.
Pushed by apol into branch 'master'.

pk+flatpak: Simplify fetching icons by reusing code

M  +39   -0    libdiscover/appstream/AppStreamUtils.cpp
M  +4    -0    libdiscover/appstream/AppStreamUtils.h
M  +12   -44   libdiscover/backends/FlatpakBackend/FlatpakResource.cpp
M  +0    -1    libdiscover/backends/FlatpakBackend/FlatpakResource.h
M  +4    -33   libdiscover/backends/PackageKitBackend/AppPackageKitResource.cpp

https://invent.kde.org/plasma/discover/-/commit/95e6cad9e87e4be3227e31a95c8cb1dc6dcdf5a1

diff --git a/libdiscover/appstream/AppStreamUtils.cpp b/libdiscover/appstream/AppStreamUtils.cpp
index 3fe58a0aa..23f4bf290 100644
--- a/libdiscover/appstream/AppStreamUtils.cpp
+++ b/libdiscover/appstream/AppStreamUtils.cpp
@@ -9,6 +9,7 @@
 #include "utils.h"
 #include <AppStreamQt/category.h>
 #include <AppStreamQt/component.h>
+#include <AppStreamQt/icon.h>
 #include <AppStreamQt/pool.h>
 #include <AppStreamQt/release.h>
 #include <AppStreamQt/screenshot.h>
@@ -19,6 +20,8 @@
 #include <KLocalizedString>
 #include <QCoroTimer>
 #include <QDebug>
+#include <QDir>
+#include <QDirIterator>
 #include <QJsonArray>
 #include <QJsonObject>
 #include <QMetaEnum>
@@ -235,3 +238,39 @@ DISCOVERCOMMON_EXPORT bool AppStreamUtils::kIconLoaderHasIcon(const QString &nam
     }();
     return icons.contains(name);
 }
+
+QIcon AppStreamUtils::iconForComponent(const AppStream::Component &component, const QString &iconPath)
+{
+    QIcon ret;
+    for (const AppStream::Icon &icon : component.icons()) {
+        switch (icon.kind()) {
+        case AppStream::Icon::KindLocal:
+        case AppStream::Icon::KindCached: {
+            const QString path = icon.url().toLocalFile();
+            if (QDir::isRelativePath(path) && !iconPath.isEmpty()) {
+                QDirIterator it(iconPath, QDirIterator::Subdirectories);
+                while (it.hasNext()) {
+                    const auto currentPath = it.next();
+                    if (it.fileName() == path) {
+                        ret.addFile(currentPath, icon.size());
+                    }
+                }
+            } else {
+                ret.addFile(path, icon.size());
+            }
+            break;
+        }
+        case AppStream::Icon::KindRemote:
+            break;
+        case AppStream::Icon::KindStock:
+            if (kIconLoaderHasIcon(icon.name())) {
+                ret = QIcon::fromTheme(icon.name());
+            }
+            break;
+        case AppStream::Icon::KindUnknown:
+            break;
+        }
+    }
+
+    return ret;
+}
diff --git a/libdiscover/appstream/AppStreamUtils.h b/libdiscover/appstream/AppStreamUtils.h
index f3f66f944..b8cee929c 100644
--- a/libdiscover/appstream/AppStreamUtils.h
+++ b/libdiscover/appstream/AppStreamUtils.h
@@ -7,9 +7,11 @@
 #pragma once
 
 #include <AppStreamQt/component.h>
+#include <AppStreamQt/icon.h>
 #include <AppStreamQt/image.h>
 #include <AppStreamQt/pool.h>
 #include <QColor>
+#include <QIcon>
 #include <QList>
 #include <QUrl>
 #include <resources/AbstractResource.h>
@@ -40,4 +42,6 @@ DISCOVERCOMMON_EXPORT QFuture<AppStream::ComponentBox>
 componentsByCategoriesTask(AppStream::ConcurrentPool *pool, const std::shared_ptr<Category> &cat, AppStream::Bundle::Kind kind);
 
 DISCOVERCOMMON_EXPORT bool kIconLoaderHasIcon(const QString &name);
+
+DISCOVERCOMMON_EXPORT QIcon iconForComponent(const AppStream::Component &component, const QString &iconPath = {});
 }
diff --git a/libdiscover/backends/FlatpakBackend/FlatpakResource.cpp b/libdiscover/backends/FlatpakBackend/FlatpakResource.cpp
index 2e6660da9..3bd3beafa 100644
--- a/libdiscover/backends/FlatpakBackend/FlatpakResource.cpp
+++ b/libdiscover/backends/FlatpakBackend/FlatpakResource.cpp
@@ -34,7 +34,6 @@
 #include <QCoroCore>
 #include <QDesktopServices>
 #include <QDir>
-#include <QDirIterator>
 #include <QEvent>
 #include <QFileInfo>
 #include <QFutureWatcher>
@@ -189,13 +188,12 @@ quint64 FlatpakResource::downloadSize() const
 
 void FlatpakResource::resolveIcon()
 {
-    m_icon = QIcon();
     const auto icons = m_appdata.icons();
 
-    m_stockIcon = std::ranges::any_of(icons, [](const AppStream::Icon &icon) {
+    const bool hasStockIcon = std::ranges::any_of(icons, [](const AppStream::Icon &icon) {
         return icon.kind() == AppStream::Icon::KindStock && AppStreamUtils::kIconLoaderHasIcon(icon.name());
     });
-    if (!m_remoteIconFetchInitiated && !m_stockIcon && !icons.isEmpty() && !std::ranges::any_of(icons, [](const AppStream::Icon &icon) {
+    if (!m_remoteIconFetchInitiated && !hasStockIcon && !icons.isEmpty() && !std::ranges::any_of(icons, [](const AppStream::Icon &icon) {
             return icon.kind() == AppStream::Icon::KindLocal || icon.kind() == AppStream::Icon::KindCached;
         })) {
         m_remoteIconFetchInitiated = true;
@@ -230,50 +228,20 @@ void FlatpakResource::resolveIcon()
 
     if (!m_bundledIcon.isNull()) {
         m_icon = QIcon(m_bundledIcon);
-    } else if (icons.isEmpty()) {
-        m_icon = QIcon::fromTheme(QStringLiteral("package-x-generic"));
     } else {
-        for (const AppStream::Icon &icon : icons) {
-            switch (icon.kind()) {
-            case AppStream::Icon::KindLocal:
-            case AppStream::Icon::KindCached: {
-                const QString path = icon.url().toLocalFile();
-                if (QDir::isRelativePath(path)) {
-                    const QString appstreamLocation =
-                        installationPath() + "/appstream/"_L1 + origin() + '/'_L1 + QString::fromUtf8(flatpak_get_default_arch()) + "/active/icons/"_L1;
-                    QDirIterator dit(appstreamLocation, QDirIterator::Subdirectories);
-                    while (dit.hasNext()) {
-                        const auto currentPath = dit.next();
-                        if (dit.fileName() == path) {
-                            m_icon->addFile(currentPath, icon.size());
-                        }
-                    }
-                } else {
-                    m_icon->addFile(path, icon.size());
-                }
-                break;
-            }
-            case AppStream::Icon::KindStock: {
-                if (m_stockIcon) {
-                    m_icon = QIcon::fromTheme(icon.name());
-                }
-                break;
-            }
-            case AppStream::Icon::KindRemote: {
-                const QString fileName = iconCachePath(icon);
-                if (QFileInfo::exists(fileName)) {
-                    m_icon->addFile(fileName, icon.size());
-                }
-                break;
+        m_icon = AppStreamUtils::iconForComponent(m_appdata, m_iconPath);
+        for (const auto &icon : icons) {
+            if (icon.kind() != AppStream::Icon::KindRemote) {
+                continue;
             }
-            case AppStream::Icon::KindUnknown:
-                break;
+            const QString fileName = iconCachePath(icon);
+            if (QFileInfo::exists(fileName)) {
+                m_icon->addFile(fileName, icon.size());
             }
         }
-    }
-
-    if (m_icon->isNull()) {
-        m_icon = QIcon::fromTheme(QStringLiteral("package-x-generic"));
+        if (m_icon->isNull()) {
+            m_icon = QIcon::fromTheme(QStringLiteral("package-x-generic"));
+        }
     }
 
     Q_EMIT iconChanged();
diff --git a/libdiscover/backends/FlatpakBackend/FlatpakResource.h b/libdiscover/backends/FlatpakBackend/FlatpakResource.h
index 22436362f..33123bef0 100644
--- a/libdiscover/backends/FlatpakBackend/FlatpakResource.h
+++ b/libdiscover/backends/FlatpakBackend/FlatpakResource.h
@@ -263,7 +263,6 @@ private:
     static const QStringList s_topObjects;
     static const QStringList s_bottomObjects;
     QVector<QByteArray> m_toUpdate;
-    bool m_stockIcon = false;
     bool m_remoteIconFetchInitiated = false;
     std::optional<QIcon> m_icon;
     QString m_newPermissions;
diff --git a/libdiscover/backends/PackageKitBackend/AppPackageKitResource.cpp b/libdiscover/backends/PackageKitBackend/AppPackageKitResource.cpp
index a51e74c6d..5e147f8db 100644
--- a/libdiscover/backends/PackageKitBackend/AppPackageKitResource.cpp
+++ b/libdiscover/backends/PackageKitBackend/AppPackageKitResource.cpp
@@ -8,7 +8,6 @@
 #include "utils.h"
 #include <AppStreamQt/component.h>
 #include <AppStreamQt/developer.h>
-#include <AppStreamQt/icon.h>
 #include <AppStreamQt/image.h>
 #include <AppStreamQt/provided.h>
 #include <AppStreamQt/release.h>
@@ -20,10 +19,7 @@
 #include <LazyIconResolver.h>
 #include <PackageKit/Daemon>
 #include <QDebug>
-#include <QFile>
 #include <QIcon>
-#include <QProcess>
-#include <QStandardPaths>
 #include <QUrlQuery>
 #include <appstream/AppStreamUtils.h>
 
@@ -66,34 +62,6 @@ QString AppPackageKitResource::longDescription()
     return PackageKitResource::longDescription();
 }
 
-static QIcon componentIcon(const AppStream::Component &comp)
-{
-    QIcon ret;
-    const auto icons = comp.icons();
-    for (const AppStream::Icon &icon : icons) {
-        switch (icon.kind()) {
-        case AppStream::Icon::KindLocal:
-            ret.addFile(icon.url().toLocalFile(), icon.size());
-            break;
-        case AppStream::Icon::KindCached:
-            ret.addFile(icon.url().toLocalFile(), icon.size());
-            break;
-        case AppStream::Icon::KindStock: {
-            if (AppStreamUtils::kIconLoaderHasIcon(icon.name())) {
-                return QIcon::fromTheme(icon.name());
-            }
-            break;
-        }
-        default:
-            break;
-        }
-    }
-    if (ret.isNull()) {
-        ret = QIcon::fromTheme(QStringLiteral("package-x-generic"));
-    }
-    return ret;
-}
-
 QVariant AppPackageKitResource::icon() const
 {
     if (m_icon.has_value()) {
@@ -324,7 +292,10 @@ bool AppPackageKitResource::hasResolvedIcon() const
 
 void AppPackageKitResource::resolveIcon()
 {
-    m_icon = componentIcon(m_appdata);
+    m_icon = AppStreamUtils::iconForComponent(m_appdata);
+    if (m_icon->isNull()) {
+        m_icon = QIcon::fromTheme(QStringLiteral("package-x-generic"));
+    }
     Q_EMIT iconChanged();
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.