Files
slate32/sdcard/.lua/apps/Home/main.lua
T
evan 1adf121dc6 feat(nav)!: own routing in Lua now that the runtime only carries arguments
sys.startApp(path, args) tears the runtime down and starts over from a
file, and keeps nothing else: no history, no title, no app identity. All
of that can ride in the arguments, so it does, and sdcard/.lua/lib/nav.lua
is the single writer of that table.

nav owns the back stack, the bar's title and /.lua/data/<AppId>, which
means the launcher, what "back" reaches and how deep a route nests are
editable on the card rather than in a reflash. Apps call nav.launch,
nav.replace and nav.back; sys.startApp has one caller.

Boot passes no arguments at all, which is how main.lua tells a cold start
from a navigation and opens its own launcher, replacing the home field the
runtime used to read. Arguments cross as JSON, so history is a list of
tables rather than a packed string, and an app passing something JSON
cannot carry sees the error at its own nav call.
2026-08-05 17:04:49 -04:00

63 lines
1.6 KiB
Lua

local nav = require "nav"
local ui = require "ui"
local PAD, GAP = 12, 8
---@class HomeApp : SlateApp
local M = {}
local names = {}
local function card(name, side)
return ui.button {
w = side,
h = side,
justify = "center",
align = "center",
on_click = function()
nav.launch(name)
end,
ui.label(name, { font = screen.FONT_UI, fit = side - 16 }),
}
end
function M.init()
for _, name in ipairs(fs.listDirs "/.lua/apps") do
if name ~= "Home" then
names[#names + 1] = name
end
end
table.sort(names)
log.info "home ready"
end
function M.node()
local side, cols = ui.cardSide(math.max(#names, 1), PAD, GAP)
-- Rows are filled before ui.box() sees them: the constructor moves a spec's array part
-- into its children, so anything appended afterwards is never laid out.
local rows = {}
for _, name in ipairs(names) do
local row = rows[#rows]
if not row or #row >= cols then
row = {}
rows[#rows + 1] = row
end
row[#row + 1] = card(name, side)
end
-- Centred left to right as a unit, still top aligned: the gaps inside the grid are
-- fixed, so the leftover width belongs beside the block, not to its last column.
local items = { pad = PAD, gap = GAP, w = "fill", h = "fill", align = "center" }
local gridW = cols * side + (cols - 1) * GAP
for _, row in ipairs(rows) do
row.row, row.gap, row.w = true, GAP, gridW
items[#items + 1] = ui.box(row)
end
if #rows == 0 then
items[#items + 1] = ui.text("no apps in /.lua/apps", { color = ui.theme.muted })
end
return ui.box(items)
end
return M