diff --git a/Tactility/Private/Tactility/app/AppManifestParsingInternal.h b/Tactility/Private/Tactility/app/AppManifestParsingInternal.h index 3083766f..a125f1da 100644 --- a/Tactility/Private/Tactility/app/AppManifestParsingInternal.h +++ b/Tactility/Private/Tactility/app/AppManifestParsingInternal.h @@ -14,6 +14,9 @@ bool isValidAppVersionName(const std::string& version); bool isValidAppVersionCode(const std::string& version); bool isValidName(const std::string& name); +/** Parses a comma-separated flags string (e.g. "HideStatusBar,Hidden") into appFlags bitmask. */ +uint16_t parseAppFlagsString(const std::string& raw); + /** Parses a V1 (sectioned INI, e.g. "[app]versionName=...") manifest map. */ bool parseManifestV1(const std::map& map, AppManifest& manifest); diff --git a/Tactility/Source/app/AppManifestParsing.cpp b/Tactility/Source/app/AppManifestParsing.cpp index 6a4295af..f8c8c031 100644 --- a/Tactility/Source/app/AppManifestParsing.cpp +++ b/Tactility/Source/app/AppManifestParsing.cpp @@ -56,6 +56,34 @@ bool isValidName(const std::string& name) { }); } +uint16_t parseAppFlagsString(const std::string& raw) { + uint16_t flags = AppManifest::Flags::None; + if (raw.empty()) { + return flags; + } + + auto parts = string::split(raw, ","); + for (auto& part : parts) { + std::string trimmed = string::trim(part, " \t\r\n"); + if (trimmed.empty()) { + continue; + } + std::string lower = string::lowercase(trimmed); + + if (lower == "hidestatusbar" || lower == "hide_statusbar" || lower == "hide-statusbar" || lower == "hide_status_bar") { + flags |= AppManifest::Flags::HideStatusBar; + } else if (lower == "hidden") { + flags |= AppManifest::Flags::Hidden; + } else if (lower == "none" || lower == "0" || lower == "") { + // keep as none, no additional flag + } else { + LOG_W(TAG, "Unknown app flag \"%s\" - ignoring", trimmed.c_str()); + } + } + + return flags; +} + /** The V1 format's first line is always the literal "[manifest]" section header; V2 files are flat from the first line onward. */ static bool detectIsV1Format(const std::string& filePath) { std::string first_line; diff --git a/Tactility/Source/app/AppManifestParsingV1.cpp b/Tactility/Source/app/AppManifestParsingV1.cpp index 0858962b..cf21d1ea 100644 --- a/Tactility/Source/app/AppManifestParsingV1.cpp +++ b/Tactility/Source/app/AppManifestParsingV1.cpp @@ -71,6 +71,12 @@ bool parseManifestV1(const std::map& map, AppManifest& return false; } + // Optional: [app]flags - e.g. "HideStatusBar" or "HideStatusBar,Hidden" + auto flags_it = map.find("[app]flags"); + if (flags_it != map.end()) { + manifest.appFlags = parseAppFlagsString(flags_it->second); + } + return true; } diff --git a/Tactility/Source/app/AppManifestParsingV2.cpp b/Tactility/Source/app/AppManifestParsingV2.cpp index b2929190..4b4b5635 100644 --- a/Tactility/Source/app/AppManifestParsingV2.cpp +++ b/Tactility/Source/app/AppManifestParsingV2.cpp @@ -71,6 +71,12 @@ bool parseManifestV2(const std::map& map, AppManifest& return false; } + // Optional: app.flags - e.g. "HideStatusBar" or "HideStatusBar,Hidden" + auto flags_it = map.find("app.flags"); + if (flags_it != map.end()) { + manifest.appFlags = parseAppFlagsString(flags_it->second); + } + return true; } diff --git a/Tests/Tactility/Source/AppManifestParsingTest.cpp b/Tests/Tactility/Source/AppManifestParsingTest.cpp index 7b83c269..4d62ff7d 100644 --- a/Tests/Tactility/Source/AppManifestParsingTest.cpp +++ b/Tests/Tactility/Source/AppManifestParsingTest.cpp @@ -81,3 +81,70 @@ TEST_CASE("parseManifestV2() should fail when the app id is invalid") { AppManifest manifest; CHECK_EQ(parseManifestV2(properties, manifest), false); } + +TEST_CASE("parseAppFlagsString() should parse various flag combinations") { + CHECK_EQ(parseAppFlagsString(""), 0); + CHECK_EQ(parseAppFlagsString("None"), 0); + CHECK_EQ(parseAppFlagsString("HideStatusBar"), AppManifest::Flags::HideStatusBar); + CHECK_EQ(parseAppFlagsString("hidden"), AppManifest::Flags::Hidden); + CHECK_EQ(parseAppFlagsString("HideStatusBar,Hidden"), AppManifest::Flags::HideStatusBar | AppManifest::Flags::Hidden); + CHECK_EQ(parseAppFlagsString(" hidestatusbar , hidden "), AppManifest::Flags::HideStatusBar | AppManifest::Flags::Hidden); + CHECK_EQ(parseAppFlagsString("HideStatusBar, Hidden"), AppManifest::Flags::HideStatusBar | AppManifest::Flags::Hidden); +} + +TEST_CASE("parseManifest() should parse V1 flags for fullscreen") { + TestFile file("test-manifest-v1-flags.properties"); + file.writeData( + "[manifest]\n" + "version=0.1\n" + "[target]\n" + "sdk=0.0.0\n" + "platforms=esp32\n" + "[app]\n" + "id=one.tactility.sdktest\n" + "versionName=0.1.0\n" + "versionCode=1\n" + "name=SDK Test\n" + "flags=HideStatusBar\n" + ); + + AppManifest manifest; + CHECK_EQ(parseManifest(file.getPath(), manifest), true); + CHECK_EQ(manifest.appFlags & AppManifest::Flags::HideStatusBar, AppManifest::Flags::HideStatusBar); +} + +TEST_CASE("parseManifest() should parse V2 flags for fullscreen") { + TestFile file("test-manifest-v2-flags.properties"); + file.writeData( + "manifest.version=0.1\n" + "target.sdk=0.0.0\n" + "target.platforms=esp32\n" + "app.id=one.tactility.sdktest\n" + "app.version.name=0.1.0\n" + "app.version.code=1\n" + "app.name=SDK Test\n" + "app.flags=HideStatusBar\n" + ); + + AppManifest manifest; + CHECK_EQ(parseManifest(file.getPath(), manifest), true); + CHECK_EQ(manifest.appFlags & AppManifest::Flags::HideStatusBar, AppManifest::Flags::HideStatusBar); +} + +TEST_CASE("parseManifest() should parse combined flags") { + TestFile file("test-manifest-v2-flags2.properties"); + file.writeData( + "manifest.version=0.1\n" + "target.sdk=0.0.0\n" + "target.platforms=esp32\n" + "app.id=one.tactility.sdktest\n" + "app.version.name=0.1.0\n" + "app.version.code=1\n" + "app.name=SDK Test\n" + "app.flags=HideStatusBar,Hidden\n" + ); + + AppManifest manifest; + CHECK_EQ(parseManifest(file.getPath(), manifest), true); + CHECK_EQ(manifest.appFlags, (AppManifest::Flags::HideStatusBar | AppManifest::Flags::Hidden)); +}