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