diff --git a/Provider/frontend/src/lib/DeviceManager.svelte b/Provider/frontend/src/lib/DeviceManager.svelte
index 75521c0..aa9fb2a 100644
--- a/Provider/frontend/src/lib/DeviceManager.svelte
+++ b/Provider/frontend/src/lib/DeviceManager.svelte
@@ -10,7 +10,7 @@
let savingMac = $state('');
let saveResult = $state('');
- const DEFAULT_XML = `\n \n \n`;
+ let defaultXml = $state('');
// Debug states
let debugRegistering = $state(false);
@@ -19,7 +19,9 @@
loading = true;
error = '';
try {
- devices = await getDevices();
+ const data = await getDevices();
+ devices = data.devices;
+ defaultXml = data.default_layout;
} catch (e) {
error = e.message || 'Failed to load devices';
} finally {
@@ -107,7 +109,7 @@
{#if device.has_layout}
- {#if device.xml_layout === DEFAULT_XML}
+ {#if device.xml_layout === defaultXml}
Default Layout
@@ -133,9 +135,9 @@
diff --git a/Provider/frontend/src/lib/api.js b/Provider/frontend/src/lib/api.js
index b6a9123..81ecfa4 100644
--- a/Provider/frontend/src/lib/api.js
+++ b/Provider/frontend/src/lib/api.js
@@ -278,8 +278,8 @@ export async function deleteTask(id) {
// ─── Device Management ───────────────────────────────────────────────────────
/**
- * Fetch all registered devices.
- * @returns {Promise
>}
+ * Fetch all registered devices and the default layout.
+ * @returns {Promise<{default_layout: string, devices: Array<{mac: string, has_layout: boolean, xml_layout: string}>}>}
*/
export async function getDevices() {
const res = await trackedFetch(`${API_BASE}/api/devices`);
diff --git a/Provider/main/api/devices/list.cpp b/Provider/main/api/devices/list.cpp
index bcef436..17a1140 100644
--- a/Provider/main/api/devices/list.cpp
+++ b/Provider/main/api/devices/list.cpp
@@ -11,7 +11,11 @@ internal esp_err_t api_devices_get_handler(httpd_req_t *req)
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+ cJSON *root = cJSON_CreateObject();
+ cJSON_AddStringToObject(root, "default_layout", kDefaultLayoutXml);
+
cJSON *arr = cJSON_CreateArray();
+ cJSON_AddItemToObject(root, "devices", arr);
for (int i = 0; i < MAX_DEVICES; i++)
{
@@ -25,11 +29,11 @@ internal esp_err_t api_devices_get_handler(httpd_req_t *req)
}
}
- const char *json = cJSON_PrintUnformatted(arr);
+ const char *json = cJSON_PrintUnformatted(root);
httpd_resp_sendstr(req, json);
free((void *)json);
- cJSON_Delete(arr);
+ cJSON_Delete(root);
return ESP_OK;
}
diff --git a/Provider/main/api/devices/screen_image.cpp b/Provider/main/api/devices/screen_image.cpp
index fa03e7a..4a61a64 100644
--- a/Provider/main/api/devices/screen_image.cpp
+++ b/Provider/main/api/devices/screen_image.cpp
@@ -89,21 +89,32 @@ internal esp_err_t api_devices_screen_image_handler(httpd_req_t *req)
bool render_success = false;
- // 1. Wrap the payload in a if it's missing (LVGL 9.4
- // requirement for register_component_from_data)
- char xml_buffer[2500];
- const char *xml_to_register = (const char *)dev->xml_layout;
+ // 1. Prepare the XML payload
+ const char *xml_to_register = NULL;
+ static char xml_buffer[DEVICE_XML_MAX + 100]; // static buffer to avoid stack overflow
- if (strstr(xml_to_register, "xml_layout[0] == '\0')
{
+ ESP_LOGI(kTagDeviceScreenImage, "Device %s has no layout xml.", mac);
+ return ESP_FAIL;
+ }
+
+ if (strstr(dev->xml_layout, " wrapped XML
+ xml_to_register = dev->xml_layout;
+ ESP_LOGI(kTagDeviceScreenImage,
+ "XML already contains , passing directly to parser.");
+ }
+ else
+ {
+ // Backwards compatibility for early setups - wrap it in screen and view
snprintf(xml_buffer, sizeof(xml_buffer),
- "\n\n%s\n\n",
+ "\n\n%s\n\n",
dev->xml_layout);
xml_to_register = xml_buffer;
ESP_LOGI(kTagDeviceScreenImage,
- "Wrapped widget XML in component/view for parsing.");
+ "Legacy XML without detected. Wrapped automatically.");
}
// 2. Register the XML payload as a component
@@ -115,43 +126,20 @@ internal esp_err_t api_devices_screen_image_handler(httpd_req_t *req)
ESP_LOGI(kTagDeviceScreenImage, "Successfully registered XML for device %s",
mac);
- // 3. Determine if this XML describes a full or just a
- // layout Simple heuristic: check if the string contains ", creating screen instance");
- lv_obj_t *new_scr = lv_xml_create_screen("current_device");
+ // 3. Since we enforce now, we always create a screen instance
+ lv_obj_t *new_scr = lv_xml_create_screen("current_device");
- if (new_scr)
- {
- // We must load this newly created screen to make it active before
- // rendering
- lv_screen_load(new_scr);
- scr = new_scr; // Update local pointer since active screen changed
- render_success = true;
- }
- else
- {
- ESP_LOGE(kTagDeviceScreenImage,
- "lv_xml_create_screen failed for device %s", mac);
- }
+ if (new_scr)
+ {
+ // We must load this newly created screen to make it active before rendering
+ lv_screen_load(new_scr);
+ scr = new_scr; // Update local pointer since active screen changed
+ render_success = true;
}
else
{
- ESP_LOGI(kTagDeviceScreenImage,
- "XML is a component/widget, creating on active screen");
- // Create the component directly on the currently active cleaned screen
- lv_obj_t *comp = (lv_obj_t *)lv_xml_create(scr, "current_device", NULL);
- if (comp)
- {
- render_success = true;
- }
- else
- {
- ESP_LOGE(kTagDeviceScreenImage, "lv_xml_create failed for device %s",
- mac);
- }
+ ESP_LOGE(kTagDeviceScreenImage,
+ "lv_xml_create_screen failed for device %s", mac);
}
}
else
diff --git a/Provider/main/device.hpp b/Provider/main/device.hpp
index 4289a80..16c2fa3 100644
--- a/Provider/main/device.hpp
+++ b/Provider/main/device.hpp
@@ -8,10 +8,12 @@ constexpr int MAX_DEVICES = 8;
constexpr int DEVICE_XML_MAX = 2048;
constexpr char kDefaultLayoutXml[] =
- "\n"
+ "\n"
+ " \n"
" \n"
" \n"
- "";
+ " \n"
+ "";
struct device_t
{