File indexing completed on 2024-05-12 16:23:46

0001 // SPDX-FileCopyrightText: 2021 Jonah Brüchert <jbb@kaidan.im>
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-or-later
0004 
0005 #include "webappmanager.h"
0006 
0007 #include <QImage>
0008 #include <QStandardPaths>
0009 #include <QStringBuilder>
0010 
0011 #include <KConfigGroup>
0012 #include <KDesktopFile>
0013 #include <KSandbox>
0014 
0015 WebAppManager::WebAppManager(QObject *parent)
0016     : QObject(parent)
0017     , m_desktopFileDirectory(desktopFileDirectory())
0018 {
0019     const auto fileInfos = m_desktopFileDirectory.entryInfoList(QDir::Files);
0020 
0021     // Likely almost all files in the directory are webapps, so this should be worth it
0022     m_webApps.reserve(fileInfos.size());
0023 
0024     for (const auto &file : fileInfos) {
0025         // Make sure to only parse desktop files
0026         if (file.fileName().contains(QStringView(u".desktop"))) {
0027             KDesktopFile desktopFile(file.filePath());
0028 
0029             // Only handle desktop files referencing angelfish-webapp
0030             if (desktopFile.group(QStringLiteral("Desktop Entry")).readEntry("Exec").contains(QStringView(u"angelfish-webapp"))) {
0031                 WebApp app{desktopFile.readName(), desktopFile.readIcon(), desktopFile.readUrl()};
0032 
0033                 m_webApps.push_back(std::move(app));
0034             }
0035         }
0036     }
0037 }
0038 
0039 QString WebAppManager::desktopFileDirectory()
0040 {
0041     auto dir = []() -> QString {
0042         if (KSandbox::isFlatpak()) {
0043             return qEnvironmentVariable("HOME") % u"/.local/share/applications/";
0044         }
0045         return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
0046     }();
0047 
0048     QDir(dir).mkpath(QStringLiteral("."));
0049 
0050     return dir;
0051 }
0052 
0053 QString WebAppManager::iconDirectory()
0054 {
0055     auto dir = []() -> QString {
0056         if (KSandbox::isFlatpak()) {
0057             return qEnvironmentVariable("HOME") % u"/.local/share/icons/hicolor/16x16/apps/";
0058         }
0059         return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/icons/hicolor/16x16/apps/");
0060     }();
0061 
0062     QDir(dir).mkpath(QStringLiteral("."));
0063 
0064     return dir;
0065 }
0066 
0067 const std::vector<WebApp> &WebAppManager::applications() const
0068 {
0069     return m_webApps;
0070 }
0071 
0072 void WebAppManager::addApp(const QString &name, const QString &url, const QImage &icon)
0073 {
0074     const QString filename = generateFileName(name);
0075     const QString desktopFileName = generateDesktopFileName(name);
0076 
0077     icon.save(iconDirectory() % QDir::separator() % filename % u".png", "PNG");
0078     KConfig desktopFile(desktopFileDirectory() % QDir::separator() % desktopFileName, KConfig::SimpleConfig);
0079 
0080     auto desktopEntry = desktopFile.group(QStringLiteral("Desktop Entry"));
0081     desktopEntry.writeEntry(QStringLiteral("Type"), QStringLiteral("Application"));
0082     desktopEntry.writeEntry(QStringLiteral("URL"), url);
0083     desktopEntry.writeEntry(QStringLiteral("Name"), name);
0084     desktopEntry.writeEntry(QStringLiteral("Exec"), QString(webAppCommand() % u' ' % desktopFileName));
0085     desktopEntry.writeEntry(QStringLiteral("Icon"), filename);
0086 
0087     m_webApps.push_back(WebApp{name, filename, url});
0088 
0089     desktopFile.sync();
0090 
0091     Q_EMIT applicationsChanged();
0092 }
0093 
0094 bool WebAppManager::exists(const QString &name)
0095 {
0096     const QString location = desktopFileDirectory();
0097     const QString filename = generateDesktopFileName(name);
0098 
0099     return QFile::exists(location % QDir::separator() % filename);
0100 }
0101 
0102 bool WebAppManager::removeApp(const QString &name)
0103 {
0104     const QString location = desktopFileDirectory();
0105     const QString filename = generateDesktopFileName(name);
0106 
0107     auto it = std::remove_if(m_webApps.begin(), m_webApps.end(), [&name](const WebApp &app) {
0108         return app.name == name;
0109     });
0110 
0111     m_webApps.erase(it);
0112 
0113     bool success = QFile::remove(location % QDir::separator() % filename);
0114     Q_EMIT applicationsChanged();
0115     return success;
0116 }
0117 
0118 WebAppManager &WebAppManager::instance()
0119 {
0120     static WebAppManager instance;
0121     return instance;
0122 }
0123 
0124 QString WebAppManager::generateFileName(const QString &name)
0125 {
0126     QString filename = name.toLower();
0127     filename.replace(QChar(u' '), QChar(u'_'));
0128     filename.remove(u'/');
0129     filename.remove(u'"');
0130     filename.remove(u'\'');
0131     filename.remove(u',');
0132     filename.remove(u'.');
0133     filename.remove(u'|');
0134     return filename;
0135 }
0136 
0137 QString WebAppManager::generateDesktopFileName(const QString &name)
0138 {
0139     return generateFileName(name) % u".desktop";
0140 }
0141 
0142 QString WebAppManager::webAppCommand()
0143 {
0144     if (KSandbox::isFlatpak()) {
0145         return QStringLiteral(
0146                    "flatpak run "
0147                    "--command=angelfish-webapp "
0148                    "--filesystem=%1 "
0149                    "org.kde.angelfish")
0150             .arg(desktopFileDirectory());
0151     }
0152 
0153     return QStringLiteral("angelfish-webapp");
0154 }
0155 
0156 #include "moc_webappmanager.cpp"