Use target app and version in themes meta

This commit is contained in:
luisangelsm
2026-03-06 12:29:06 +01:00
parent 9024ff7d0c
commit 86b5003f07
14 changed files with 60 additions and 19 deletions

View File

@ -264,10 +264,13 @@ void AppearanceTabWidget::importTheme()
if (path.isEmpty() || !repository)
return;
const QString id = repository->importThemeFromFile(path);
QString errorMessage;
const QString id = repository->importThemeFromFile(path, &errorMessage);
if (id.isEmpty()) {
QMessageBox::warning(this, tr("Import failed"),
tr("Could not import theme from:\n%1").arg(path));
const QString detail = errorMessage.isEmpty()
? tr("Could not import theme from:\n%1").arg(path)
: tr("Could not import theme from:\n%1\n\n%2").arg(path, errorMessage);
QMessageBox::warning(this, tr("Import failed"), detail);
return;
}

View File

@ -9,6 +9,8 @@ struct ThemeMeta {
QString id;
QString displayName;
ThemeVariant variant;
QString targetApp;
QString version;
};
#endif // THEME_META_H

View File

@ -6,8 +6,8 @@
#include <QJsonObject>
#include <QUuid>
ThemeRepository::ThemeRepository(const QString &qrcPrefix, const QString &userThemesDir)
: qrcPrefix(qrcPrefix), userThemesDir(userThemesDir)
ThemeRepository::ThemeRepository(const QString &qrcPrefix, const QString &userThemesDir, const QString &targetApp)
: qrcPrefix(qrcPrefix), userThemesDir(userThemesDir), targetApp(targetApp)
{
scanBuiltins();
scanUserThemes();
@ -64,9 +64,14 @@ QString ThemeRepository::saveUserTheme(QJsonObject themeJson)
const QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
id = "user/" + uuid;
metaObj["id"] = id;
themeJson["meta"] = metaObj;
}
// Always stamp targetApp so saved themes are always identifiable
if (metaObj["targetApp"].toString().isEmpty())
metaObj["targetApp"] = targetApp;
themeJson["meta"] = metaObj;
// Extract uuid from "user/<uuid>"
const QString uuid = id.mid(5); // skip "user/"
const QString filePath = filePathForUserTheme(uuid);
@ -100,11 +105,23 @@ bool ThemeRepository::deleteUserTheme(const QString &themeId)
return false;
}
QString ThemeRepository::importThemeFromFile(const QString &filePath)
QString ThemeRepository::importThemeFromFile(const QString &filePath, QString *errorMessage)
{
QJsonObject json = readJsonFile(filePath);
if (json.isEmpty())
if (json.isEmpty()) {
if (errorMessage)
*errorMessage = QObject::tr("The file could not be read or is not valid JSON.");
return { };
}
// Check that the theme targets the correct application
const auto metaIn = json["meta"].toObject();
const QString themeTargetApp = metaIn["targetApp"].toString();
if (!themeTargetApp.isEmpty() && themeTargetApp != targetApp) {
if (errorMessage)
*errorMessage = QObject::tr("This theme is for %1, not %2.").arg(themeTargetApp, targetApp);
return { };
}
// Force a new user id regardless of what the file contains
auto metaObj = json["meta"].toObject();
@ -181,7 +198,9 @@ ThemeMeta ThemeRepository::extractMeta(const QJsonObject &json)
return ThemeMeta {
meta["id"].toString(),
meta["displayName"].toString(),
(meta["variant"].toString() == "light") ? ThemeVariant::Light : ThemeVariant::Dark
(meta["variant"].toString() == "light") ? ThemeVariant::Light : ThemeVariant::Dark,
meta["targetApp"].toString(),
meta["version"].toString()
};
}

View File

@ -17,7 +17,7 @@ struct ThemeListEntry {
class ThemeRepository
{
public:
explicit ThemeRepository(const QString &qrcPrefix, const QString &userThemesDir);
explicit ThemeRepository(const QString &qrcPrefix, const QString &userThemesDir, const QString &targetApp);
QList<ThemeListEntry> availableThemes() const;
bool contains(const QString &themeId) const;
@ -25,13 +25,14 @@ public:
QString saveUserTheme(QJsonObject themeJson);
bool deleteUserTheme(const QString &themeId);
QString importThemeFromFile(const QString &filePath);
QString importThemeFromFile(const QString &filePath, QString *errorMessage = nullptr);
void refresh();
private:
QString qrcPrefix;
QString userThemesDir;
QString targetApp;
struct BuiltinEntry {
QString id;