Fixes and improvements (#616)

This commit is contained in:
Ken Van Hoeylandt
2026-08-18 20:43:07 +02:00
committed by GitHub
parent f943c4dd69
commit b03759a111
141 changed files with 899 additions and 221 deletions
+1 -1
View File
@@ -237,7 +237,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "AddGps",
.id = "tactility.addgps",
.name = "Add GPS",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -152,7 +152,7 @@ uint32_t start(uint32_t callerAppInstanceId, const std::string& title, const std
}
extern const ::AppManifest manifest = {
.id = "AlertDialog",
.id = "tactility.alertdialog",
.name = "Alert Dialog",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -162,7 +162,7 @@ void start(const std::string& appId) {
}
extern const ::AppManifest manifest = {
.id = "AppDetails",
.id = "tactility.appdetails",
.name = "App Details",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
+33 -7
View File
@@ -36,8 +36,11 @@ struct Context {
lv_obj_t* contentWrapper = nullptr;
lv_obj_t* refreshButton = nullptr;
std::string cachedAppsJsonFile = std::format("{}/app_hub.json", getTempPath());
std::vector<AppHubEntry> entries;
AppHubEntryList entries;
Mutex mutex;
// Survives across a bury/resurface cycle (e.g. opening AppHubDetailsApp and returning),
int32_t scrollY = 0;
};
@@ -46,10 +49,6 @@ void refresh(Context* ctx);
void onBackPressed(lv_event_t* event) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(event));
// Async, non-blocking - must NOT call app_manager_stop() directly here: that bound-waits
// (thread_join) for this app's own thread to finish, which needs the LVGL lock
// (window_manager_remove()) - but this callback runs ON the LVGL task, which would
// deadlock against itself.
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
app_event_emit(ctx->appInstanceId, &closeEvent);
}
@@ -86,9 +85,25 @@ void showNoInternet(Context* ctx) {
}
void showApps(Context* ctx) {
// Refresh rebuilds the list from scratch (cached copy, then again once the network fetch
// lands), which would otherwise reset the user's scroll position each time.
auto scrollY = lv_obj_get_scroll_y(ctx->contentWrapper);
lv_obj_clean(ctx->contentWrapper);
ctx->mutex.lock();
if (parseJson(ctx->cachedAppsJsonFile, ctx->entries)) {
// An empty targetPlatforms list means the entry runs everywhere; otherwise it must name
// this build's own target to be installable here. The simulator isn't a real MCU target,
// so it has nothing to match against and skips this filter entirely.
std::erase_if(ctx->entries, [](const AppHubEntry& entry) {
#ifdef ESP_PLATFORM
return !entry.targetPlatforms.empty() &&
std::ranges::find(entry.targetPlatforms, CONFIG_IDF_TARGET) == entry.targetPlatforms.end();
#else
(void)entry;
return false;
#endif
});
std::ranges::sort(ctx->entries, [](auto left, auto right) {
return left.appName < right.appName;
});
@@ -106,6 +121,8 @@ void showApps(Context* ctx) {
lv_obj_set_user_data(entry_button, int_as_voidptr);
lv_obj_add_event_cb(entry_button, onAppPressed, LV_EVENT_SHORT_CLICKED, ctx);
}
lv_obj_scroll_to_y(ctx->contentWrapper, scrollY, LV_ANIM_OFF);
} else {
showRefreshFailedError(ctx, "Failed to load content");
}
@@ -169,6 +186,15 @@ void createWidgets(lv_obj_t* parent, void* userData) {
lv_obj_set_style_pad_ver(ctx->contentWrapper, 0, LV_STATE_DEFAULT);
refresh(ctx);
lv_obj_scroll_to_y(ctx->contentWrapper, ctx->scrollY, LV_ANIM_OFF);
}
void destroyWidgets(void* userData) {
auto* ctx = static_cast<Context*>(userData);
ctx->scrollY = lv_obj_get_scroll_y(ctx->contentWrapper);
ctx->contentWrapper = nullptr;
ctx->refreshButton = nullptr;
}
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
@@ -179,7 +205,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
sub.app_instance_id = appInstanceId;
app_event_subscribe(&sub);
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
WindowId window = window_manager_create_ext(appInstanceId, createWidgets, destroyWidgets, &ctx);
bool shouldClose = false;
while (!shouldClose) {
@@ -206,7 +232,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "AppHub",
.id = "tactility.apphub",
.name = "App Hub",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+1 -1
View File
@@ -20,7 +20,7 @@ static bool parseEntry(const cJSON* object, AppHubEntry& entry) {
reader.readStringArray("targetPlatforms", entry.targetPlatforms);
}
bool parseJson(const std::string& filePath, std::vector<AppHubEntry>& entries) {
bool parseJson(const std::string& filePath, AppHubEntryList& entries) {
file::FileMutexGuard guard(filePath);
auto data = file::readString(filePath);
@@ -1,7 +1,3 @@
#include "../../../../Modules/app-module/private/app/private/app_ledger.h"
#include "app/metadata.h"
#include <Tactility/DeprecatedPaths.h>
#include <Tactility/StringUtils.h>
#include <Tactility/app/alertdialog/AlertDialog.h>
@@ -12,6 +8,7 @@
#include <app/event.h>
#include <app/install.h>
#include <app/metadata.h>
#include <app/manager.h>
#include <app/manifest.h>
@@ -64,10 +61,6 @@ uint32_t showConfirmDialog(Context* ctx, const char* action) {
void onBackPressed(lv_event_t* e) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
// Async, non-blocking - must NOT call app_manager_stop() directly here: that bound-waits
// (thread_join) for this app's own thread to finish, which needs the LVGL lock
// (window_manager_remove()) - but this callback runs ON the LVGL task, which would
// deadlock against itself.
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
app_event_emit(ctx->appInstanceId, &closeEvent);
}
@@ -308,7 +301,7 @@ void start(const apphub::AppHubEntry& entry) {
}
extern const ::AppManifest manifest = {
.id = "AppHubDetails",
.id = "tactility.apphubdetails",
.name = "App Details",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
+1 -1
View File
@@ -106,7 +106,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "AppList",
.id = "tactility.applist",
.name = "Apps",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -121,7 +121,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "AppSettings",
.id = "tactility.appsettings",
.name = "Apps",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -176,7 +176,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "ApWebServer",
.id = "tactility.apwebserver",
.name = "AP Web Server",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -251,7 +251,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "AudioSettings",
.id = "tactility.audiosettings",
.name = "Audio",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+1 -1
View File
@@ -326,7 +326,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Boot",
.id = "tactility.boot",
.name = "Boot",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
+1 -1
View File
@@ -283,7 +283,7 @@ uint32_t start() {
}
extern const ::AppManifest manifest = {
.id = "BtManage",
.id = "tactility.btmanage",
.name = "Bluetooth",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -256,7 +256,7 @@ void start(const std::string& addrHex) {
}
extern const ::AppManifest manifest = {
.id = "BtPeerSettings",
.id = "tactility.btpeersettings",
.name = "BT Device Settings",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
+1 -1
View File
@@ -219,7 +219,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Chat",
.id = "tactility.chat",
.name = "Chat",
.category = APP_CATEGORY_USER,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+6 -2
View File
@@ -7,10 +7,10 @@
#include <Tactility/app/chat/ChatSettings.h>
#include <Tactility/app/chat/ChatProtocol.h>
#include <Tactility/DeprecatedPaths.h>
#include <Tactility/file/File.h>
#include <Tactility/file/PropertiesFile.h>
#include <app/paths.h>
#include <crypt/crypt.h>
#include <esp_random.h>
@@ -28,7 +28,11 @@ namespace tt::app::chat {
constexpr auto* TAG = "ChatSettings";
static std::string getSettingsFilePath() {
return getUserDataPath() + "/settings/chat.properties";
char path[256];
if (app_paths_get_user_data_path("tactility.chat", "chat.properties", path, sizeof(path)) != ERROR_NONE) {
return "";
}
return path;
}
constexpr auto* KEY_SENDER_ID = "senderId";
@@ -199,7 +199,7 @@ void start() {
}
extern const ::AppManifest manifest = {
.id = "CrashDiagnostics",
.id = "tactility.crashdiagnostics",
.name = "Crash Diagnostics",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -226,7 +226,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Development",
.id = "tactility.development",
.name = "Development",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+1 -1
View File
@@ -66,7 +66,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Files",
.id = "tactility.files",
.name = "Files",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -106,7 +106,7 @@ uint32_t startForExistingOrNewFile(uint32_t callerAppInstanceId) {
}
extern const ::AppManifest manifest = {
.id = "FileSelection",
.id = "tactility.fileselection",
.name = "File Selection",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -320,7 +320,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "GpsSettings",
.id = "tactility.gpssettings",
.name = "GPS",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -124,7 +124,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "GroveSettings",
.id = "tactility.grovesettings",
.name = "Grove",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -419,7 +419,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "I2cScanner",
.id = "tactility.i2cscanner",
.name = "I2C Scanner",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -126,7 +126,7 @@ void start(const std::string& file) {
}
extern const ::AppManifest manifest = {
.id = "ImageViewer",
.id = "tactility.imageviewer",
.name = "Image Viewer",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -148,7 +148,7 @@ std::string getLastText() {
}
extern const ::AppManifest manifest = {
.id = "InputDialog",
.id = "tactility.inputdialog",
.name = "Input Dialog",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -340,7 +340,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Display",
.id = "tactility.display",
.name = "Display",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -241,7 +241,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "KeyboardSettings",
.id = "tactility.keyboardsettings",
.name = "Keyboard",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+5 -5
View File
@@ -168,9 +168,9 @@ void createWidgets(lv_obj_t* parent, void*) {
? computeButtonMargin(lv_display_get_horizontal_resolution(display), total_button_size)
: computeButtonMargin(lv_display_get_vertical_resolution(display), total_button_size);
auto* app_list_button = createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_APPS, "AppList", margin, is_landscape_display);
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_FOLDER, "Files", margin, is_landscape_display);
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_SETTINGS, "Settings", margin, is_landscape_display);
auto* app_list_button = createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_APPS, "tactility.applist", margin, is_landscape_display);
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_FOLDER, "tactility.files", margin, is_landscape_display);
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_SETTINGS, "tactility.settings", margin, is_landscape_display);
// The launcher's container is several levels below the screen, and LVGL only sends
// LV_EVENT_SIZE_CHANGED to the screen object itself on a resolution change - so the
@@ -184,7 +184,7 @@ void createWidgets(lv_obj_t* parent, void*) {
auto* power_button = lv_button_create(parent);
lv_obj_set_style_pad_all(power_button, 8, 0);
lv_obj_align(power_button, LV_ALIGN_BOTTOM_MID, 0, -10);
lv_obj_add_event_cb(power_button, onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)"PowerOff");
lv_obj_add_event_cb(power_button, onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)"tactility.poweroff");
lv_obj_set_style_shadow_width(power_button, 0, LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(power_button, 0, LV_PART_MAIN);
@@ -261,7 +261,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Launcher",
.id = "tactility.launcher",
.name = "Launcher",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -176,7 +176,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "LocaleSettings",
.id = "tactility.localesettings",
.name = "Region & Language",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+1 -1
View File
@@ -249,7 +249,7 @@ void start(const std::string& filePath) {
}
extern const ::AppManifest manifest = {
.id = "Notes",
.id = "tactility.notes",
.name = "Notes",
.category = APP_CATEGORY_USER,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+1 -1
View File
@@ -273,7 +273,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Power",
.id = "tactility.power",
.name = "Power",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+1 -1
View File
@@ -167,7 +167,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "PowerOff",
.id = "tactility.poweroff",
.name = "Power Off",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -285,7 +285,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Screenshot",
.id = "tactility.screenshot",
.name = "Screenshot",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -150,7 +150,7 @@ AppInstanceId start(AppInstanceId callerAppInstanceId, const std::string& title,
}
extern const AppManifest manifest = {
.id = "SelectionDialog",
.id = "tactility.selectiondialog",
.name = "Selection Dialog",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
+1 -1
View File
@@ -104,7 +104,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "Settings",
.id = "tactility.settings",
.name = "Settings",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
+1 -1
View File
@@ -271,7 +271,7 @@ void start() {
}
extern const ::AppManifest manifest = {
.id = "Setup",
.id = "tactility.setup",
.name = "Setup",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -452,7 +452,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "SystemInfo",
.id = "tactility.systeminfo",
.name = "System Info",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -209,7 +209,7 @@ uint32_t start() {
}
extern const ::AppManifest manifest = {
.id = "TimeDateSettings",
.id = "tactility.timedatesettings",
.name = "Time & Date",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
+1 -1
View File
@@ -283,7 +283,7 @@ std::string getLastCode() {
}
extern const ::AppManifest manifest = {
.id = "TimeZone",
.id = "tactility.timezone",
.name = "Select Time zone",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -288,7 +288,7 @@ uint32_t start(uint32_t callerAppInstanceId) {
}
extern const ::AppManifest manifest = {
.id = "TouchCalibration",
.id = "tactility.touchcalibration",
.name = "Touch Calibration",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -304,7 +304,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "TrackballSettings",
.id = "tactility.trackballsettings",
.name = "Trackball",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -116,7 +116,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "UsbSettings",
.id = "tactility.usbsettings",
.name = "USB",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -431,7 +431,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
} // namespace
extern const ::AppManifest manifest = {
.id = "WebServerSettings",
.id = "tactility.webserversettings",
.name = "Web Server",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
@@ -272,7 +272,7 @@ void start(const std::string& ssid) {
}
extern const ::AppManifest manifest = {
.id = "WifiApSettings",
.id = "tactility.wifiapsettings",
.name = "Wi-Fi AP Settings",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -360,7 +360,7 @@ void start(const std::string& ssid, const std::string& password) {
}
extern const ::AppManifest manifest = {
.id = "WifiConnect",
.id = "tactility.wificonnect",
.name = "Wi-Fi Connect",
.category = APP_CATEGORY_SYSTEM,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
@@ -188,7 +188,7 @@ uint32_t start(uint32_t callerAppInstanceId) {
}
extern const ::AppManifest manifest = {
.id = "WifiManage",
.id = "tactility.wifimanage",
.name = "Wi-Fi",
.category = APP_CATEGORY_SETTINGS,
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }