Files
slate32/sdcard/.lua/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

76 lines
1.6 KiB
Lua

package.path = "/.lua/lib/?.lua"
local ui = require "ui"
local nav = require "nav"
local statusbar = require "statusbar"
local APPS = "/.lua/apps/"
---@class Main : App, TouchHandlers
local M = {}
---@class SlateApp
---@field init? fun(arg?: string) Builds state before the tree is mounted.
---@field node? fun(): NodeId The app's subtree, built inside the chrome.
---@field draw? fun(deltaMs: integer)
local app
---@param args table|nil What the previous state passed to sys.startApp, or nil at boot.
function M.start(args)
nav.start(args)
local dir = APPS .. nav.getRoute()
package.path = dir .. "/?.lua;/.lua/lib/?.lua"
app = assert(loadfile(dir .. "/main.lua"))()
if app.init then
app.init(nav.getArg())
end
ui.mount(M.node)
timer.every(1000, statusbar.tick)
end
---@return NodeId
function M.node()
ui.setInset(statusbar.isVisible() and statusbar.height or 0)
local body = ui.box { w = "fill", h = "fill", app.node and app.node() or nil }
if not statusbar.isVisible() then
return body
end
return ui.box { w = "fill", h = "fill", statusbar.node(), body }
end
function M.draw(deltaMs)
if app.draw then
app.draw(deltaMs)
end
ui.draw()
end
function M.onTouchDown(x, y)
ui.down(x, y)
if app.onTouchDown then
app.onTouchDown(x, y)
end
end
function M.onTouchMove(x, y)
ui.move(x, y)
if app.onTouchMove then
app.onTouchMove(x, y)
end
end
function M.onTouchUp(x, y)
ui.up(x, y)
if app.onTouchUp then
app.onTouchUp(x, y)
end
end
function M.onTouch(x, y)
if app.onTouch then
app.onTouch(x, y)
end
end
return M