// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2026 A-La-Karte Contributors #include "flatpakimporter.h" #include #include #include #include #include #include FlatpakImporter::FlatpakImporter(QObject *parent) : PlatformImporter(parent) { } QString FlatpakImporter::platformName() const { return QStringLiteral("Flatpak"); } QString FlatpakImporter::platformId() const { return QStringLiteral("flatpak"); } QStringList FlatpakImporter::getFlatpakPaths() const { QStringList paths; // User Flatpak exports paths << expandPath(QStringLiteral("~/.local/share/flatpak/exports/share/applications")); // System Flatpak exports paths << QStringLiteral("/var/lib/flatpak/exports/share/applications"); return paths; } bool FlatpakImporter::isAvailable() const { return !findExecutable(QStringLiteral("flatpak")).isEmpty(); } bool FlatpakImporter::isGameApp(const QString &desktopFilePath) const { KDesktopFile desktopFile(desktopFilePath); KConfigGroup desktop = desktopFile.desktopGroup(); const QString type = desktop.readEntry(QStringLiteral("Type")); if (type != QStringLiteral("Application")) { return false; } if (desktop.readEntry(QStringLiteral("Hidden"), false)) { return false; } if (desktop.readEntry(QStringLiteral("NoDisplay"), false)) { return false; } const QStringList categories = desktop.readEntry(QStringLiteral("Categories")).split(QLatin1Char(';'), Qt::SkipEmptyParts); return hasGameCategory(categories); } Game *FlatpakImporter::parseDesktopFile(const QString &filePath, const QString &appId) const { KDesktopFile desktopFile(filePath); KConfigGroup desktop = desktopFile.desktopGroup(); const QString name = desktop.readEntry(QStringLiteral("Name")); const QString icon = desktop.readEntry(QStringLiteral("Icon")); const QString comment = desktop.readEntry(QStringLiteral("Comment")); if (name.isEmpty()) { return nullptr; } QString gameId = QStringLiteral("flatpak_") + appId.toLower().replace(QStringLiteral("."), QStringLiteral("_")); Game *game = new Game(gameId, name); game->setPlatform(platformName()); game->setPlatformId(appId); game->setLaunchCommand(QStringLiteral("flatpak run %1").arg(appId)); if (!comment.isEmpty()) { game->setDescription(comment); } // Try to find icon if (!icon.isEmpty()) { QStringList iconPaths = { expandPath(QStringLiteral("~/.local/share/flatpak/exports/share/icons/hicolor/256x256/apps/") + icon + QStringLiteral(".png")), QStringLiteral("/var/lib/flatpak/exports/share/icons/hicolor/256x256/apps/") + icon + QStringLiteral(".png"), expandPath(QStringLiteral("~/.local/share/flatpak/exports/share/icons/hicolor/128x128/apps/") + icon + QStringLiteral(".png")), QStringLiteral("/var/lib/flatpak/exports/share/icons/hicolor/128x128/apps/") + icon + QStringLiteral(".png"), }; for (const QString &iconPath : iconPaths) { if (QFile::exists(iconPath)) { const QUrl url = QUrl::fromLocalFile(iconPath); game->setIconUrl(url); if (!game->coverUrl().isValid() || game->coverUrl().isEmpty()) { game->setCoverUrl(url); } break; } } } return game; } QList FlatpakImporter::importGames() { QList games; for (const QString &path : getFlatpakPaths()) { QDir dir(path); if (!dir.exists()) { continue; } QStringList desktopFiles = dir.entryList({QStringLiteral("*.desktop")}, QDir::Files); int total = desktopFiles.count(); int current = 0; for (const QString &fileName : desktopFiles) { current++; Q_EMIT importProgress(current, total); QString filePath = dir.absoluteFilePath(fileName); if (!isGameApp(filePath)) { continue; } // Extract app ID from filename (e.g., "com.example.Game.desktop" -> "com.example.Game") QString appId = fileName; appId.chop(8); // Remove ".desktop" Game *game = parseDesktopFile(filePath, appId); if (game) { games.append(game); } } } return games; }