add base-apps with manifests, layout system, and testing documentation

- Rename test-apps to base-apps with proper manifest.json for each app
- Add is_system_app flag to app discovery and Lua API
- Fix icon path resolution for /system/icons/ paths
- Add layout.lua and layout.rcss for reusable UI components
- Update home screen to dynamically load all apps from manifests
- Update all app RML files to use layout components
- Comprehensive testing framework documentation with JSON action format
- Add tests/ directory structure for automated UI testing
This commit is contained in:
2026-01-20 09:14:05 +01:00
parent 5de087e8e0
commit 1f91d7508e
101 changed files with 13103 additions and 966 deletions

View File

@@ -34,27 +34,23 @@ function initHome(doc)
print("[Home] Initializing home screen...")
home_document = doc
-- Get installed third-party apps
-- Get all installed apps
if mosis and mosis.apps then
installed_apps = mosis.apps.getInstalled() or {}
print("[Home] Found " .. #installed_apps .. " installed apps")
-- Filter to only third-party (non-system) apps
local third_party = {}
-- Log each app
for _, app in ipairs(installed_apps) do
if not app.is_system_app then
table.insert(third_party, app)
print("[Home] Third-party app: " .. app.name .. " (" .. app.package_id .. ")")
end
local app_type = app.is_system_app and "System" or "Third-party"
print("[Home] " .. app_type .. " app: " .. app.name .. " (" .. app.package_id .. ")")
end
installed_apps = third_party
else
print("[Home] Warning: mosis.apps API not available")
installed_apps = {}
end
-- Render dynamic apps
renderThirdPartyApps()
-- Render all apps
renderInstalledApps()
end
-- Generate a color based on package_id
@@ -79,17 +75,17 @@ function getAppInitial(name)
return name:sub(1, 1):upper()
end
-- Render third-party apps into the grid
function renderThirdPartyApps()
-- Render all installed apps into the grid
function renderInstalledApps()
-- Use stored document reference
if not home_document then
print("[Home] Could not get document reference")
return
end
local grid = home_document:GetElementById("third-party-apps")
local grid = home_document:GetElementById("installed-apps")
if not grid then
print("[Home] third-party-apps container not found")
print("[Home] installed-apps container not found")
return
end
@@ -97,7 +93,7 @@ function renderThirdPartyApps()
grid.inner_rml = ""
if #installed_apps == 0 then
print("[Home] No third-party apps to display")
print("[Home] No apps to display")
return
end
@@ -110,25 +106,23 @@ function renderThirdPartyApps()
-- Check if app has an icon
if app.icon and app.icon ~= "" then
local icon_path
-- Check if icon is already a full path (starts with / or contains :/)
if app.icon:sub(1, 1) == "/" or app.icon:find(":/") then
-- Already a full path
icon_path = app.icon
elseif app.install_path and app.install_path ~= "" then
-- Relative filename - construct full path from install_path
icon_path = app.install_path .. "/" .. app.icon
else
icon_path = app.icon
end
-- Use file:// prefix for absolute paths to prevent RmlUi URL resolution
local src_path = icon_path
if icon_path:sub(1, 1) == "/" then
src_path = "file://" .. icon_path
local icon_path = app.icon
-- Handle /system/ paths - map to shared assets
if icon_path:sub(1, 8) == "/system/" then
-- Map /system/icons/foo.tga to ../../icons/foo.tga (relative to home)
icon_path = "../../" .. icon_path:sub(9) -- Remove "/system/" prefix
print("[Home] Mapped system icon: " .. app.icon .. " -> " .. icon_path)
elseif icon_path:sub(1, 1) ~= "/" and not icon_path:find(":/") then
-- Relative path - prepend install_path
if app.install_path and app.install_path ~= "" then
icon_path = app.install_path .. "/" .. icon_path
end
end
-- Use img tag for actual icon
icon_html = '<img src="' .. src_path .. '" style="width: 48px; height: 48px;"/>'
print("[Home] Loading icon: " .. src_path)
icon_html = '<img src="' .. icon_path .. '" style="width: 48px; height: 48px;"/>'
print("[Home] Loading icon: " .. icon_path)
else
-- Fallback to initial letter
icon_html = '<span style="font-size: 28px; color: #000000;">' .. initial .. '</span>'
@@ -137,7 +131,7 @@ function renderThirdPartyApps()
html = html .. [[
<div class="app-icon">
<div class="app-icon-image" style="background-color: ]] .. color .. [[;"
onclick="launchThirdPartyApp(']] .. app.package_id .. [[')">
onclick="launchApp(']] .. app.package_id .. [[')">
]] .. icon_html .. [[
</div>
<span class="app-icon-label">]] .. app.name .. [[</span>
@@ -146,7 +140,7 @@ function renderThirdPartyApps()
end
grid.inner_rml = html
print("[Home] Rendered " .. #installed_apps .. " third-party apps")
print("[Home] Rendered " .. #installed_apps .. " apps")
end
-- Get app info by package_id
@@ -159,8 +153,8 @@ function getAppInfo(package_id)
return nil
end
-- Launch a third-party app
function launchThirdPartyApp(package_id)
-- Launch an app by package_id
function launchApp(package_id)
print("[Home] Launching app: " .. package_id)
if mosis and mosis.apps then

View File

@@ -44,12 +44,13 @@
}
/* Third-party apps use same sizing as system apps */
#third-party-apps .app-icon {
#installed-apps .app-icon {
width: 25%;
box-sizing: border-box;
padding: 8px 0;
}
#third-party-apps .app-icon-image {
#installed-apps .app-icon-image {
width: 72px;
height: 72px;
border-radius: 18px;
@@ -60,11 +61,11 @@
cursor: pointer;
}
#third-party-apps .app-icon-image:hover {
#installed-apps .app-icon-image:hover {
transform: scale(1.05);
}
#third-party-apps .app-icon-label {
#installed-apps .app-icon-label {
display: block;
text-align: center;
font-size: 16px;
@@ -86,80 +87,8 @@
<!-- App Grid -->
<div class="home-content">
<div class="app-grid">
<!-- Row 1 -->
<div class="app-icon">
<div class="app-icon-image" style="background-color: #4CAF50;" onclick="navigateTo('dialer')"><img src="../../icons/phone.tga"/></div>
<span class="app-icon-label">Phone</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #2196F3;" onclick="navigateTo('messages')"><img src="../../icons/message.tga"/></div>
<span class="app-icon-label">Messages</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #FF9800;" onclick="navigateTo('contacts')"><img src="../../icons/contacts.tga"/></div>
<span class="app-icon-label">Contacts</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #F44336;" onclick="navigateTo('browser')"><img src="../../icons/browser.tga"/></div>
<span class="app-icon-label">Browser</span>
</div>
<!-- Row 2 -->
<div class="app-icon">
<div class="app-icon-image" style="background-color: #9C27B0;"><img src="../../icons/gallery.tga"/></div>
<span class="app-icon-label">Gallery</span>
</div>
<div id="app-camera" class="app-icon">
<div class="app-icon-image" style="background-color: #00BCD4;" onclick="navigateTo('camera')"><img src="../../icons/camera.tga"/></div>
<span class="app-icon-label">Camera</span>
</div>
<div id="app-settings" class="app-icon">
<div class="app-icon-image" style="background-color: #607D8B;" onclick="navigateTo('settings')"><img src="../../icons/settings.tga"/></div>
<span class="app-icon-label">Settings</span>
</div>
<div id="app-music" class="app-icon">
<div class="app-icon-image" style="background-color: #E91E63;" onclick="navigateTo('music')"><img src="../../icons/music.tga"/></div>
<span class="app-icon-label">Music</span>
</div>
<!-- Row 3 -->
<div class="app-icon">
<div class="app-icon-image" style="background-color: #3F51B5;"><img src="../../icons/calendar.tga"/></div>
<span class="app-icon-label">Calendar</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #009688;"><img src="../../icons/clock.tga"/></div>
<span class="app-icon-label">Clock</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #795548;"><img src="../../icons/notes.tga"/></div>
<span class="app-icon-label">Notes</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #FF5722;"><img src="../../icons/maps.tga"/></div>
<span class="app-icon-label">Maps</span>
</div>
<!-- Row 4 -->
<div id="app-store" class="app-icon">
<div class="app-icon-image" style="background-color: #8BC34A;" onclick="navigateTo('store')"><img src="../../icons/store.tga"/></div>
<span class="app-icon-label">Store</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #CDDC39;"><img src="../../icons/files.tga"/></div>
<span class="app-icon-label">Files</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #FFC107;"><img src="../../icons/calculator.tga"/></div>
<span class="app-icon-label">Calculator</span>
</div>
<div class="app-icon">
<div class="app-icon-image" style="background-color: #673AB7;"><img src="../../icons/weather.tga"/></div>
<span class="app-icon-label">Weather</span>
</div>
<!-- Third-party apps (dynamically populated by home.lua) -->
<div id="third-party-apps" class="app-grid-section">
<!-- All apps dynamically populated by home.lua -->
<div id="installed-apps" class="app-grid-section">
<!-- Apps will be rendered here by home.lua -->
</div>
</div>