// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2026 A-La-Karte Contributors #include "flatpakimporter.h" #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 { QSettings desktop(desktopFilePath, QSettings::IniFormat); desktop.beginGroup(QStringLiteral("Desktop Entry")); QString type = desktop.value(QStringLiteral("Type")).toString(); if (type != QStringLiteral("Application")) { return false; } if (desktop.value(QStringLiteral("Hidden"), false).toBool()) { return false; } if (desktop.value(QStringLiteral("NoDisplay"), false).toBool()) { return false; } QString categories = desktop.value(QStringLiteral("Categories")).toString(); QStringList gameCategories = {QStringLiteral("Game"), QStringLiteral("ArcadeGame"), QStringLiteral("ActionGame"), QStringLiteral("AdventureGame"), QStringLiteral("BlocksGame"), QStringLiteral("BoardGame"), QStringLiteral("CardGame"), QStringLiteral("KidsGame"), QStringLiteral("LogicGame"), QStringLiteral("RolePlaying"), QStringLiteral("Shooter"), QStringLiteral("Simulation"), QStringLiteral("SportsGame"), QStringLiteral("StrategyGame")}; for (const QString &cat : gameCategories) { if (categories.contains(cat, Qt::CaseInsensitive)) { return true; } } return false; } Game *FlatpakImporter::parseDesktopFile(const QString &filePath, const QString &appId) const { QSettings desktop(filePath, QSettings::IniFormat); desktop.beginGroup(QStringLiteral("Desktop Entry")); QString name = desktop.value(QStringLiteral("Name")).toString(); QString icon = desktop.value(QStringLiteral("Icon")).toString(); QString comment = desktop.value(QStringLiteral("Comment")).toString(); 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(platformId()); 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; }