components_config_LoginScene.bs
import "pkg:/source/roku_modules/log/LogMixin.brs"
import "pkg:/source/translationKeys.bs"
import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/misc.bs"
import "pkg:/source/utils/translate.bs"
sub init()
m.log = new log.Logger("LoginScene")
m.top.setFocus(true)
m.top.isOptionsAvailable = false
' Overhang config — declarative field projected onto the overhang by JRScene (registerOverhangData).
m.top.isLogoVisible = true
' The sign-in screen. Build the username/password config + the save-credentials checkbox
' here; submit/back emit intents the loginRouter handles.
m.top.findNode("prompt").text = translate(translationKeys.ButtonSignIn)
m.list = m.top.findNode("configOptions")
m.checkbox = m.top.findNode("onOff")
m.buttons = m.top.findNode("buttons")
m.top.findNode("submit").text = translate(translationKeys.ButtonSubmit)
m.buttons.observeField("buttonSelected", "onButtonSelected")
end sub
' Build the username/password config fields + the save-credentials checkbox
' (was CreateSigninGroup 507-535). Built in onScreenShown (not init) so the prefilled
' username — resolved from the route context (a user picked in UserSelect) or the saved
' username setting — is set BEFORE configItems is assigned (ConfigList snapshots on
' assignment, so a later value write would not display). Guarded to build once.
sub buildConfig()
contextUsername = ""
route = m.top.route
if isValid(route) and isValid(route.context) and isValid(route.context.username)
contextUsername = route.context.username
end if
m.usernameField = CreateObject("roSGNode", "ConfigData")
m.usernameField.label = translate(translationKeys.LabelUsername)
m.usernameField.field = "username"
m.usernameField.type = "string"
if contextUsername = "" and isValid(getSetting("username"))
m.usernameField.value = getSetting("username")
else
m.usernameField.value = contextUsername
end if
m.passwordField = CreateObject("roSGNode", "ConfigData")
m.passwordField.label = translate(translationKeys.LabelPassword)
m.passwordField.field = "password"
m.passwordField.type = "password"
registryPassword = getSetting("password")
if isValid(registryPassword)
m.passwordField.value = registryPassword
end if
' Save-credentials checkbox
items = CreateObject("roSGNode", "ContentNode")
saveCheckBox = CreateObject("roSGNode", "ContentNode")
saveCheckBox.title = translate(translationKeys.MessageSaveCredentials)
items.appendChild(saveCheckBox)
m.checkbox.content = items
m.list.configItems = [m.usernameField, m.passwordField]
end sub
' JRScreen hook.
sub onScreenShown()
' Build the sign-in config the first time the view is shown (m.top.route is set by the
' router before this fires), so the prefilled username is in place before ConfigList
' snapshots configItems.
if m.configBuilt <> true
buildConfig()
m.configBuilt = true
end if
' Clear backdrop on login screens
m.global.sceneManager.callFunc("setBackgroundImage", "")
end sub
' Submit pressed → publish the entered credentials + save flag, emit the intent.
' The coordinator (loginRouter.onCredentialsSubmitted) runs the blocking getToken.
sub onButtonSelected(event as object)
buttonGroup = event.getRoSGNode()
btn = buttonGroup.getChild(event.getData())
if not isValid(btn) or btn.id <> "submit" then return
usernameField = m.list.content.getChild(0)
passwordField = m.list.content.getChild(1)
m.top.enteredUsername = usernameField.value
m.top.enteredPassword = passwordField.value
m.top.saveCredentials = (m.checkbox.checkedState[0] = true)
m.top.getScene().preLoginIntent = "credentialsSubmitted"
end sub
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false
if key = "back"
' Back → coordinator decides (user picker if there were public users, else server select).
' Consume so the outlet's goBack doesn't also fire.
m.top.getScene().preLoginIntent = "loginBack"
return true
else if key = "down" and not isValid(m.checkbox.focusedChild) and not isValid(m.buttons.focusedChild)
limit = m.list.content.getChildren(-1, 0).count() - 1
if limit = m.list.itemFocused
m.checkbox.setFocus(true)
return true
end if
else if key = "down" and not isValid(m.buttons.focusedChild)
m.buttons.setFocus(true)
return true
else if key = "up" and isValid(m.buttons.focusedChild)
m.checkbox.setFocus(true)
return true
else if key = "up" and isValid(m.checkbox.focusedChild)
m.list.setFocus(true)
return true
end if
return false
end function
' onDestroy: Full teardown releasing all resources before component removal
' Called automatically via JRScreen.beforeViewClose when sgRouter permanently closes this view.
sub onDestroy()
m.log.verbose("onDestroy")
' Release the submit observer.
if isValid(m.buttons) then m.buttons.unobserveField("buttonSelected")
' Clear node references
m.list = invalid
m.checkbox = invalid
m.buttons = invalid
m.usernameField = invalid
m.passwordField = invalid
end sub