1adf121dc6
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.
63 lines
1.6 KiB
Lua
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
|