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.
76 lines
1.6 KiB
Lua
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
|