-- Run: lua test/ui_theme.lua -- Asserts the palette ui.lua derives from a theme's three seed colors. The fake packs -- channels into one integer, so contrast between roles stays checkable. package.path = "sdcard/lib/?.lua;test/?.lua;" .. package.path local device = require("fake_device").install() local ui = require("ui") local BLACK, WHITE = gui.color(0, 0, 0), gui.color(255, 255, 255) local function reload(name) device.theme = name return ui.reloadTheme() end -- Seeds pass through untouched. local light = reload("light") assert(light.bg == WHITE, "light bg") assert(light.fg == BLACK, "light fg") assert(light.accent == gui.color(0, 120, 255), "light accent") -- Muted sits between the text and the surface, so it reads as secondary on both. assert(light.muted > BLACK and light.muted < WHITE, "muted between fg and bg") -- Contrast is derived, never configured: text on a dark accent must be light. assert(light.accent_fg == WHITE, "white text on the blue accent") assert(reload("mono").accent_fg == WHITE, "white text on the black accent") -- A pale accent has to flip the label to black; no theme file can get this wrong. local pale = ui.themeNames() -- force the module to be loaded before patching it assert(#pale >= 3, "expected the canned themes") package.loaded["theme"].pale = {bg = {255, 255, 255}, fg = {0, 0, 0}, accent = {255, 235, 120}} assert(reload("pale").accent_fg == BLACK, "black text on a pale accent") -- Dark inverts the surface without any per-component configuration. local dark = reload("dark") assert(dark.bg < dark.fg, "dark theme keeps light text on a dark surface") assert(#dark.face == 2 and #dark.face_pressed == 2, "button gradients are pairs") -- Pinned roles win over derived ones, which is the deviation hatch. assert(reload("mono").radius == 0, "mono pins radius") assert(light.radius == 6, "light keeps the derived radius") -- An unknown name must not leave an app without colors. local missing = reload("does-not-exist") assert(missing.bg == WHITE and missing.fg == BLACK, "unknown theme falls back to light") -- The root seeds the tree, so an app naming no colors still gets themed. reload("dark") local button = ui.button{label = "go", on_press = function() end} local screen = ui.screen(ui.box{pad = 12, button}) assert(screen.root.bg == ui.theme.bg, "root takes the theme surface") assert(screen.root.color == ui.theme.fg, "root takes the theme text") screen:draw() assert(button.color == ui.theme.fg, "the button inherited the theme") assert(button.press_bg == ui.theme.accent, "the button inherited the accent") -- An explicit value still wins over the theme. local custom = ui.button{label = "delete", press_bg = 123, on_press = function() end} ui.screen(ui.box{pad = 12, custom}):draw() assert(custom.press_bg == 123, "explicit styling overrides the theme") print("ok")