94d298dd45
The card sits in a scroll container of its own height over an empty strip of the same, so the slide is a setScroll() delta on the laid-out tree rather than a rebuild a frame, and the container scissors the part not yet arrived.
95 lines
2.3 KiB
Lua
95 lines
2.3 KiB
Lua
-- A message that slides up from the bottom edge, holds, then slides back down.
|
|
--
|
|
-- The card sits inside a scroll container of its own height whose content is twice that:
|
|
-- an empty strip above the card. Sliding is therefore ui.setScroll() on the tree already
|
|
-- laid out -- a delta on stored coordinates -- rather than a rebuild a frame, and the
|
|
-- container scissors the half of the card that has not arrived yet.
|
|
--
|
|
-- Whatever mounts the tree includes toast.node() and calls toast.draw(deltaMs); show()
|
|
-- rebuilds so the node exists, and hide() rebuilds to drop it.
|
|
|
|
local ui = require "ui"
|
|
|
|
local M = {}
|
|
|
|
local HEIGHT = 44
|
|
local MARGIN = 12
|
|
local SLIDE_MS = 180
|
|
|
|
local text, box
|
|
-- nil, or "in" / "hold" / "out" with the milliseconds spent in it.
|
|
local phase, elapsed, holdMs
|
|
|
|
---@param message string
|
|
---@param durationMs? integer How long the card holds before it slides away.
|
|
function M.show(message, durationMs)
|
|
text, holdMs = message, durationMs or 1500
|
|
phase, elapsed = "in", 0
|
|
ui.rebuild()
|
|
end
|
|
|
|
function M.hide()
|
|
if phase then
|
|
phase, text, box = nil, nil, nil
|
|
ui.rebuild()
|
|
end
|
|
end
|
|
|
|
---@return NodeId|nil
|
|
function M.node()
|
|
if not phase then
|
|
return nil
|
|
end
|
|
box = ui.box {
|
|
at = { x = MARGIN, y = screen.getHeight() - HEIGHT - MARGIN },
|
|
w = screen.getWidth() - 2 * MARGIN,
|
|
h = HEIGHT,
|
|
scrollY = true,
|
|
ui.box {
|
|
w = "fill",
|
|
ui.spacer { w = "fill", h = HEIGHT },
|
|
ui.box {
|
|
w = "fill",
|
|
h = HEIGHT,
|
|
align = "center",
|
|
justify = "center",
|
|
background = ui.theme.face,
|
|
border = ui.theme.muted,
|
|
ui.text(text),
|
|
},
|
|
},
|
|
}
|
|
return box
|
|
end
|
|
|
|
local function progress()
|
|
if phase == "in" then
|
|
return elapsed / SLIDE_MS
|
|
elseif phase == "out" then
|
|
return 1 - elapsed / SLIDE_MS
|
|
end
|
|
return 1
|
|
end
|
|
|
|
---Advances the slide. Safe to call every frame whether or not a toast is up.
|
|
---@param deltaMs integer
|
|
function M.draw(deltaMs)
|
|
if not phase then
|
|
return
|
|
end
|
|
elapsed = elapsed + deltaMs
|
|
if phase == "in" and elapsed >= SLIDE_MS then
|
|
phase, elapsed = "hold", 0
|
|
elseif phase == "hold" and elapsed >= holdMs then
|
|
phase, elapsed = "out", 0
|
|
elseif phase == "out" and elapsed >= SLIDE_MS then
|
|
M.hide()
|
|
return
|
|
end
|
|
if box then
|
|
ui.setScroll(box, 0, math.floor(HEIGHT * progress()))
|
|
end
|
|
end
|
|
|
|
return M
|