components_dialogs_JRListDialogRow.bs
import "pkg:/source/utils/dialogLayout.bs"
import "pkg:/source/utils/misc.bs"
' See JRListDialogRow.xml for why the check is a tinted Poster rather than a
' RadioButtonList.
' The gutter and padding live in dialogLayout.bs (LIST_ROW_CHECK_GUTTER /
' LIST_ROW_PADDING) so the spacing gate covers them.
'
' CHECK_ICON_SIZE stays HERE and stays off the 6px scale on purpose: it is the
' source bitmap's size, not a spacing choice. The $$RES$$ pipeline substitutes a
' 23x23 _hd asset decoded at physical output size, so 35 design units is 1:1 on
' both tiers — rounding it to 36 would break that and soften the glyph.
const CHECK_ICON_SIZE = 35
sub init()
m.selectedBackground = m.top.findNode("selectedBackground")
m.checkIcon = m.top.findNode("checkIcon")
m.rowLabel = m.top.findNode("rowLabel")
constants = m.global.constants
m.selectedBackground.blendColor = constants.colorBackgroundSecondary
' Sized 1:1 with the source bitmap so it renders crisp at native resolution,
' the same way the app's other inline icons are declared.
m.checkIcon.uri = constants.iconCheckWhite
m.checkIcon.width = CHECK_ICON_SIZE
m.checkIcon.height = CHECK_ICON_SIZE
' colorSecondary, NOT colorPrimary. The theme table reserves colorPrimary for
' things the user can focus or act on — it is the focus ring around this very
' row — and defines colorSecondary as non-focusable emphasis, which is exactly
' what "this is your current pick" is. JRDropdownItem marks its selected item
' the same way.
m.checkIcon.blendColor = constants.colorSecondary
end sub
sub onItemContentChanged()
content = m.top.itemContent
if not isValid(content) then return
m.rowLabel.text = content.title
' isSelected is added to the ContentNode by JRListDialog. Absent (a row built
' by anything else) reads as not selected rather than faulting.
'
' Two signals for one state, covering each other's blind spot: the check is a
' SHAPE (survives any palette and colour-blindness), and the surface gives the
' row weight in a long single-colour list.
isSelected = isValid(content.isSelected) and content.isSelected
m.checkIcon.visible = isSelected
m.selectedBackground.visible = isSelected
' The LABEL stays colorTextPrimary either way. Recolouring it to match the
' check was tried and read as too much contrast on device once the surface
' landed: three simultaneous treatments on one row is louder than the state
' warrants, and the row's job is to be readable first.
'
' The accessibility argument that motivated the hue is carried by the CHECK,
' which is a SHAPE — it survives colour-blindness and a dim or badly
' calibrated panel, which is more than a hue swap ever did. The surface adds
' weight for everyone else.
layoutRow()
end sub
sub onSizeChanged()
layoutRow()
end sub
sub layoutRow()
rowWidth = m.top.width
rowHeight = m.top.height
if rowWidth <= 0 or rowHeight <= 0 then return
m.selectedBackground.width = rowWidth
m.selectedBackground.height = rowHeight
m.checkIcon.translation = [LIST_ROW_PADDING, int((rowHeight - CHECK_ICON_SIZE) / 2)]
m.rowLabel.translation = [LIST_ROW_CHECK_GUTTER, 0]
m.rowLabel.width = rowWidth - LIST_ROW_CHECK_GUTTER - LIST_ROW_PADDING
m.rowLabel.height = rowHeight
end sub