1aa3a59ca9
The firmware knew where apps, data and modules lived, called four globals, and painted a status bar into a strip it clipped every app out of. None of that was its business, and the viewport made the bar something an app could neither compose with nor replace. It now loads one file. main.lua mounts the route inside its own node tree, so the bar is a sibling of the app rather than chrome painted over it: one layout, one hit test, no inset arithmetic and no invalidation flags on the C++ side. Apps and main.lua are tables -- they share a lua_State, so globals would collide -- and a screen changes by rebuilding from node().
75 lines
2.7 KiB
Lua
75 lines
2.7 KiB
Lua
-- Run: lua test/statusbar_dirty.lua
|
|
-- The bar is part of the tree, so a tick has to repaint the field that changed and leave
|
|
-- the rest of the screen alone. The clock is pinned unsynced so its text is constant and
|
|
-- every other field can be steered on its own.
|
|
package.path = "sdcard/.lua/lib/?.lua;test/?.lua;" .. package.path
|
|
|
|
local device = require("fake_device").install()
|
|
local ui = require "ui"
|
|
local statusbar = require "statusbar"
|
|
|
|
device.clockSynced = false
|
|
device.canGoBack = true
|
|
|
|
-- What main.lua builds, minus the app: chrome above, whatever is left below.
|
|
local function screen()
|
|
if not statusbar.isVisible() then
|
|
return ui.box { w = "fill", h = "fill" }
|
|
end
|
|
return ui.box { w = "fill", h = "fill", statusbar.node(), ui.box { w = "fill", h = "fill" } }
|
|
end
|
|
|
|
ui.mount(screen)
|
|
local built = node.getCount()
|
|
assert(device.labelled "--:--:--", "the bar built no clock")
|
|
assert(device.labelled "117kB", "the bar built no memory slot")
|
|
assert(device.labelled(device.appName), "the bar built no title")
|
|
|
|
local function tick()
|
|
device.invalidated = {}
|
|
statusbar.tick()
|
|
return #device.invalidated
|
|
end
|
|
|
|
assert(tick() == 0, "an unchanged bar repaints nothing")
|
|
|
|
device.freeHeap = device.freeHeap - 32000
|
|
assert(tick() == 1, "only the memory slot repaints")
|
|
assert(device.labelled "148kB", "the memory slot kept its old text")
|
|
assert(node.getCount() == built, "a field update rebuilt the screen")
|
|
|
|
device.status = { state = "connected", ssid = "x", ip = "", rssi = -50 }
|
|
assert(tick() == 1, "the signal strength repaints the icon and nothing else")
|
|
assert(tick() == 0, "and settles again afterwards")
|
|
|
|
-- A longer title needs a wider box, which only a rebuild can give it.
|
|
sys.setAppTitle "settings - wifi"
|
|
statusbar.tick()
|
|
assert(device.labelled "settings - wifi", "a renamed app did not reach the bar")
|
|
assert(tick() == 0, "and settles again afterwards")
|
|
|
|
-- The back control is offered only when there is somewhere to go back to. It carries no
|
|
-- label, so it is counted as what it is: the one thing in the bar a finger can press.
|
|
local function pressable()
|
|
local count = 0
|
|
for _, entry in ipairs(device.nodes) do
|
|
if entry.interactive then
|
|
count = count + 1
|
|
end
|
|
end
|
|
return count
|
|
end
|
|
|
|
assert(pressable() == 1, "the bar offered no back control with history behind it")
|
|
device.canGoBack = false
|
|
ui.rebuild()
|
|
assert(pressable() == 0, "the bar offered back with no history behind it")
|
|
|
|
-- Fullscreen is chrome choosing not to build itself, so the app's node is the whole tree.
|
|
statusbar.setFullscreen(true)
|
|
assert(not device.labelled "--:--:--", "the bar survived fullscreen")
|
|
statusbar.setFullscreen(false)
|
|
assert(device.labelled "--:--:--", "the bar did not come back")
|
|
|
|
print "ok"
|