source_home_homeScreenLoad.bs
import "pkg:/source/utils/misc.bs"
' Decision layer for Home's screen-load milestones — when has Home PAINTED?
'
' Home's rows fill from several independent tasks, so no single handler is "the" paint. The
' ledger (source/utils/screenReadiness.bs) declares one fill per row, keyed by sectionId, and
' this decides when the rows the user is LOOKING AT have all landed:
'
' paint - every row in the visible span has resolved (data, empty, or failed)
' settled - every row has resolved; the ledger derives that on its own
'
' "Visible" is the span textureManager already maintains in `loadedRowRange` — the same
' signal cells use to decide which textures to load, and the one lazy row hydration would key
' on. It is `[focusedRow, focusedRow + numRows - 1]`, which is the app's definition of the
' viewport rather than a measurement of pixels on screen.
'
' Lives in source/ rather than in HomeRows.bs for the same reason as latestRows.bs: a Rooibos
' suite cannot call a component's functions without a callFunc seam on the XML.
namespace homeScreenLoad
' Have all rows in the visible span resolved?
'
' Rows only get SHORTER between the range being computed and this being asked — nothing
' recomputes `loadedRowRange` when a row is removed, only on focus changes — so the end of
' the span is clamped to the rows that exist now. Rows that shift up into the span after a
' removal are therefore counted, which is what the user sees.
'
' An unset range on a non-empty row list answers false rather than true: painting on a
' range nobody computed would publish a paint time that describes no viewport. The run then
' never settles, which the measurement tooling reports as unmeasurable — the loud failure.
'
' @param loadedRowRange - the content root's [bufferStart, visibleStart, visibleEnd, bufferEnd]
' @param rowSectionIds - every row's sectionId, in content order
' @param openFills - the ledger's outstanding fills, keyed by id
' @return true when no row in the visible span is still outstanding
function visibleRowsResolved(loadedRowRange as dynamic, rowSectionIds as object, openFills as object) as boolean
rowCount = rowSectionIds.count()
if rowCount = 0 then return true
if not isValid(loadedRowRange) or loadedRowRange.count() < 4 then return false
visibleStart = loadedRowRange[1]
visibleEnd = loadedRowRange[2]
if visibleStart < 0 or visibleEnd < 0 then return false
if visibleEnd > rowCount - 1 then visibleEnd = rowCount - 1
for i = visibleStart to visibleEnd
if openFills.doesExist(rowSectionIds[i]) then return false
end for
return true
end function
end namespace