Initial commit

This commit is contained in:
Gericom
2025-11-22 17:21:45 +01:00
commit 5d6f67c612
517 changed files with 63025 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
#pragma once
#include <memory>
#include "core/String.h"
#include "RomBrowserDisplaySettings.h"
#include "FileAssociation.h"
class AppSettings
{
public:
String<char, 16> language = "english";
String<char, 64> theme = "material";
String<char, 256> lastUsedFilePath = "";
RomBrowserDisplaySettings romBrowserDisplaySettings;
std::unique_ptr<FileAssociation[]> fileAssociations;
u32 numberOfFileAssociations = 0;
};

View File

@@ -0,0 +1,14 @@
#pragma once
#include "core/String.h"
class FileAssociation
{
public:
FileAssociation() { }
FileAssociation(const char* extension, const char* applicationPath)
: extension(extension), applicationPath(applicationPath) { }
String<char, 8> extension;
String<char, 256> applicationPath;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include "AppSettings.h"
class IAppSettingsService
{
public:
virtual ~IAppSettingsService() { }
virtual AppSettings& GetAppSettings() = 0;
virtual const AppSettings& GetAppSettings() const = 0;
virtual void Save() const = 0;
};

View File

@@ -0,0 +1,9 @@
#pragma once
class AppSettings;
class JsonAppSettingsSerializer
{
public:
void Serialize(const AppSettings* appSettings, const char* filePath) const;
bool Deserialize(AppSettings* appSettings, const char* filePath) const;
};

View File

@@ -0,0 +1,211 @@
#include "common.h"
#include <memory>
#include "json/ArduinoJson.h"
#include "AppSettings.h"
#include "fat/File.h"
#include "JsonAppSettingsSerializer.h"
#pragma GCC optimize("Os")
#define JSON_RESERVED_SIZE 2048
#define KEY_LANGUAGE "language"
#define KEY_ROM_BROWSER_LAYOUT "romBrowserLayout"
#define KEY_ROM_BROWSER_SORT_MODE "romBrowserSortMode"
#define KEY_THEME "theme"
#define KEY_LAST_USED_FILE_PATH "lastUsedFilePath"
#define KEY_FILE_ASSOCIATIONS "fileAssociations"
#define KEY_FILE_ASSOCIATIONS_APPLICATION_PATH "appPath"
static const char* serializeRomBrowserLayout(RomBrowserLayout romBrowserLayout)
{
switch (romBrowserLayout)
{
case RomBrowserLayout::HorizontalIconGrid:
return "HorizontalIconGrid";
case RomBrowserLayout::VerticalIconGrid:
return "VerticalIconGrid";
case RomBrowserLayout::BannerList:
return "BannerList";
case RomBrowserLayout::FileList:
return "FileList";
case RomBrowserLayout::CoverFlow:
return "CoverFlow";
default:
return "";
}
}
static bool tryParseRomBrowserLayout(
const char* romBrowserLayoutString, RomBrowserLayout& romBrowserLayout)
{
if (!romBrowserLayoutString)
return false;
if (!strcasecmp(romBrowserLayoutString, "HorizontalIconGrid"))
romBrowserLayout = RomBrowserLayout::HorizontalIconGrid;
else if (!strcasecmp(romBrowserLayoutString, "VerticalIconGrid"))
romBrowserLayout = RomBrowserLayout::VerticalIconGrid;
else if (!strcasecmp(romBrowserLayoutString, "BannerList"))
romBrowserLayout = RomBrowserLayout::BannerList;
else if (!strcasecmp(romBrowserLayoutString, "FileList"))
romBrowserLayout = RomBrowserLayout::FileList;
else if (!strcasecmp(romBrowserLayoutString, "CoverFlow"))
romBrowserLayout = RomBrowserLayout::CoverFlow;
else
return false;
return true;
}
static const char* serializeRomBrowserSortMode(RomBrowserSortMode romBrowserSortMode)
{
switch (romBrowserSortMode)
{
case RomBrowserSortMode::NameAscending:
return "NameAscending";
case RomBrowserSortMode::NameDescending:
return "NameDescending";
case RomBrowserSortMode::LastModified:
return "LastModified";
default:
return "";
}
}
static bool tryParseRomBrowserSortMode(
const char* romBrowserDisplayModeString, RomBrowserSortMode& romBrowserSortMode)
{
if (!romBrowserDisplayModeString)
return false;
if (!strcasecmp(romBrowserDisplayModeString, "NameAscending"))
romBrowserSortMode = RomBrowserSortMode::NameAscending;
else if (!strcasecmp(romBrowserDisplayModeString, "NameDescending"))
romBrowserSortMode = RomBrowserSortMode::NameDescending;
else if (!strcasecmp(romBrowserDisplayModeString, "LastModified"))
romBrowserSortMode = RomBrowserSortMode::LastModified;
else
return false;
return true;
}
static bool tryParseFileAssociations(const JsonObjectConst& json, AppSettings* appSettings)
{
if (json.isNull())
{
return false;
}
appSettings->fileAssociations = std::make_unique_for_overwrite<FileAssociation[]>(json.size());
int i = 0;
for (auto item : json)
{
auto extension = item.key().c_str();
auto appPath = item.value()[KEY_FILE_ASSOCIATIONS_APPLICATION_PATH].as<const char*>();
appSettings->fileAssociations[i++] = FileAssociation(extension, appPath);
}
appSettings->numberOfFileAssociations = i;
return true;
}
static void serializeFileAssociations(DynamicJsonDocument& json, const AppSettings* appSettings)
{
auto jsonObject = json[KEY_FILE_ASSOCIATIONS].to<JsonObject>();
for (u32 i = 0; i < appSettings->numberOfFileAssociations; i++)
{
const auto& fileAssociation = appSettings->fileAssociations[i];
auto jsonAssociation = jsonObject[fileAssociation.extension.GetString()].to<JsonObject>();
jsonAssociation[KEY_FILE_ASSOCIATIONS_APPLICATION_PATH] = fileAssociation.applicationPath.GetString();
}
}
static std::unique_ptr<u8[]> writeJson(const AppSettings* appSettings, u32& length)
{
DynamicJsonDocument json(JSON_RESERVED_SIZE);
json[KEY_LANGUAGE] = appSettings->language.GetString();
json[KEY_ROM_BROWSER_LAYOUT] = serializeRomBrowserLayout(appSettings->romBrowserDisplaySettings.layout);
json[KEY_ROM_BROWSER_SORT_MODE] = serializeRomBrowserSortMode(appSettings->romBrowserDisplaySettings.sortMode);
json[KEY_THEME] = appSettings->theme.GetString();
json[KEY_LAST_USED_FILE_PATH] = appSettings->lastUsedFilePath.GetString();
serializeFileAssociations(json, appSettings);
u32 outputSize = measureJsonPretty(json);
std::unique_ptr<u8[]> fileData(new(cache_align) u8[outputSize]);
serializeJsonPretty(json, fileData.get(), outputSize);
length = outputSize;
return fileData;
}
void JsonAppSettingsSerializer::Serialize(const AppSettings* appSettings, const char* filePath) const
{
u32 length = 0;
std::unique_ptr<u8[]> fileData = writeJson(appSettings, length);
const auto file = std::make_unique<File>();
if (file->Open(filePath, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
{
LOG_ERROR("Couldn't open settings file for writing\n");
return;
}
u32 bytesWritten;
if (file->Write(fileData.get(), length, bytesWritten) != FR_OK || bytesWritten != length)
{
LOG_ERROR("Error while writing settings file\n");
return;
}
LOG_DEBUG("Settings file written\n");
}
static void readJson(AppSettings* appSettings, const JsonDocument& json)
{
appSettings->language = json[KEY_LANGUAGE] | appSettings->language.GetString();
appSettings->theme = json[KEY_THEME] | appSettings->theme.GetString();
appSettings->lastUsedFilePath = json[KEY_LAST_USED_FILE_PATH] | appSettings->lastUsedFilePath.GetString();
RomBrowserLayout romBrowserLayout;
if (tryParseRomBrowserLayout(json[KEY_ROM_BROWSER_LAYOUT].as<const char*>(),
romBrowserLayout))
{
appSettings->romBrowserDisplaySettings.layout = romBrowserLayout;
}
RomBrowserSortMode romBrowserSortMode;
if (tryParseRomBrowserSortMode(json[KEY_ROM_BROWSER_SORT_MODE].as<const char*>(),
romBrowserSortMode))
{
appSettings->romBrowserDisplaySettings.sortMode = romBrowserSortMode;
}
tryParseFileAssociations(json[KEY_FILE_ASSOCIATIONS], appSettings);
}
bool JsonAppSettingsSerializer::Deserialize(AppSettings* appSettings, const char* filePath) const
{
const auto file = std::make_unique<File>();
if (file->Open(filePath, FA_READ | FA_OPEN_EXISTING) != FR_OK)
return false;
u32 fileSize = file->GetSize();
if (fileSize == 0)
return false;
std::unique_ptr<u8[]> fileData(new(cache_align) u8[fileSize]);
u8* fileDataPtr = fileData.get();
u32 bytesRead = 0;
if (file->Read(fileDataPtr, fileSize, bytesRead) != FR_OK)
return false;
DynamicJsonDocument json(JSON_RESERVED_SIZE);
if (deserializeJson(json, fileDataPtr, fileSize) != DeserializationError::Ok)
return false;
readJson(appSettings, json);
return true;
}

View File

@@ -0,0 +1,9 @@
#include "common.h"
#include "JsonAppSettingsService.h"
JsonAppSettingsService::JsonAppSettingsService(const char* filePath)
: _filePath(filePath)
{
if (!_serializer.Deserialize(&_appSettings, _filePath))
Save();
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include "IAppSettingsService.h"
#include "JsonAppSettingsSerializer.h"
class JsonAppSettingsService : public IAppSettingsService
{
JsonAppSettingsSerializer _serializer;
AppSettings _appSettings;
const char* _filePath;
public:
explicit JsonAppSettingsService(const char* filePath);
AppSettings& GetAppSettings() override { return _appSettings; }
const AppSettings& GetAppSettings() const override { return _appSettings; }
void Save() const override
{
_serializer.Serialize(&_appSettings, _filePath);
}
};

View File

@@ -0,0 +1,10 @@
#pragma once
#include "RomBrowserLayout.h"
#include "RomBrowserSortMode.h"
class RomBrowserDisplaySettings
{
public:
RomBrowserLayout layout = RomBrowserLayout::HorizontalIconGrid;
RomBrowserSortMode sortMode = RomBrowserSortMode::NameAscending;
};

View File

@@ -0,0 +1,10 @@
#pragma once
enum class RomBrowserLayout
{
HorizontalIconGrid,
VerticalIconGrid,
BannerList,
FileList,
CoverFlow
};

View File

@@ -0,0 +1,8 @@
#pragma once
enum class RomBrowserSortMode
{
NameAscending,
NameDescending,
LastModified
};