components_settings_settings.bs

import "pkg:/source/roku_modules/log/LogMixin.brs"
import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/misc.bs"
' post device profile
import "pkg:/source/utils/deviceCapabilities.bs"

sub init()
  m.log = log.Logger("Settings")
  m.top.overhangTitle = tr("Settings")
  m.top.optionsAvailable = false

  m.userLocation = []

  versionLabel = m.top.findNode("versionLabel")
  versionLabel.text = "v" + m.global.app.version
  m.settingsMenu = m.top.findNode("settingsMenu")
  m.settingDetail = m.top.findNode("settingDetail")
  m.settingDesc = m.top.findNode("settingDesc")
  m.path = m.top.findNode("path")
  m.top.findNode("rightPanelBackground").blendColor = m.global.constants.colorBackgroundSecondary

  m.boolSetting = m.top.findNode("boolSetting")
  m.integerSetting = m.top.findNode("integerSetting")
  m.radioSetting = m.top.findNode("radioSetting")

  m.integerSetting.observeField("submit", "onKeyGridSubmit")
  m.integerSetting.observeField("escape", "onKeyGridEscape")

  m.settingsMenu.setFocus(true)
  m.settingsMenu.observeField("itemFocused", "settingFocused")
  m.settingsMenu.observeField("itemSelected", "settingSelected")

  m.boolSetting.observeField("checkedItem", "boolSettingChanged")
  m.radioSetting.observeField("checkedItem", "radioSettingChanged")

  m.postTask = createObject("roSGNode", "PostTask")

  ' Load Configuration Tree
  m.configTree = GetConfigTree()
  LoadMenu({ children: m.configTree })
end sub

sub onKeyGridSubmit()
  selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused]
  newValue = m.integerSetting.text

  ' Update node field - observer handles registry persistence
  user.settings.Save(selectedSetting.settingName, newValue)

  m.settingsMenu.setFocus(true)
end sub

sub onKeyGridEscape()
  if m.integerSetting.escape = "left" or m.integerSetting.escape = "back"
    m.settingsMenu.setFocus(true)
  end if
end sub

sub LoadMenu(configSection)
  if not isValid(configSection.children)
    ' Load parent menu
    m.userLocation.pop()
    configSection = m.userLocation.peek()
  else
    if m.userLocation.Count() > 0 then m.userLocation.peek().selectedIndex = m.settingsMenu.itemFocused
    m.userLocation.push(configSection)
  end if

  result = CreateObject("roSGNode", "ContentNode")

  for each item in configSection.children
    listItem = result.CreateChild("ContentNode")
    listItem.title = tr(item.title)
    listItem.Description = tr(item.description)
    listItem.id = item.id
  end for

  m.settingsMenu.content = result

  if isValid(configSection.selectedIndex) and configSection.selectedIndex > -1
    m.settingsMenu.jumpToItem = configSection.selectedIndex
  end if

  ' Set Path display
  m.path.text = ""
  for each level in m.userLocation
    if isValid(level.title)
      if m.path.text = ""
        m.path.text = tr(level.title)
      else
        m.path.text += " / " + tr(level.title)
      end if
    end if
  end for
end sub

sub settingFocused()

  selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused]
  m.settingDesc.text = tr(selectedSetting.Description)

  ' Hide Settings
  m.boolSetting.visible = false
  m.integerSetting.visible = false
  m.radioSetting.visible = false

  userSettings = m.global.user.settings

  if not isValid(selectedSetting.type)
    return
  else if selectedSetting.type = "bool"

    m.boolSetting.visible = true

    if userSettings[selectedSetting.settingName] = true
      m.boolSetting.checkedItem = 1
    else
      m.boolSetting.checkedItem = 0
    end if
  else if selectedSetting.type = "integer"
    integerValue = userSettings[selectedSetting.settingName].ToStr()
    if isValid(integerValue)
      m.integerSetting.text = integerValue
    end if
    m.integerSetting.visible = true
  else if LCase(selectedSetting.type) = "radio"

    selectedValue = userSettings[selectedSetting.settingName]

    radioContent = CreateObject("roSGNode", "ContentNode")

    itemIndex = 0
    for each item in m.userLocation.peek().children[m.settingsMenu.itemFocused].options
      listItem = radioContent.CreateChild("ContentNode")
      listItem.title = tr(item.title)
      listItem.id = item.id
      if selectedValue = item.id
        m.radioSetting.checkedItem = itemIndex
      end if
      itemIndex++
    end for

    m.radioSetting.content = radioContent

    m.radioSetting.visible = true
  else
    m.log.warn("Unknown setting type", selectedSetting.type)
  end if

end sub


sub settingSelected()

  selectedItem = m.userLocation.peek().children[m.settingsMenu.itemFocused]

  if isValid(selectedItem.type) ' Show setting
    if selectedItem.type = "bool"
      m.boolSetting.setFocus(true)
    end if
    if selectedItem.type = "integer"
      m.integerSetting.setFocus(true)
    end if
    if (selectedItem.type) = "radio"
      m.radioSetting.setFocus(true)
    end if
  else if isValid(selectedItem.children) and selectedItem.children.Count() > 0 ' Show sub menu
    LoadMenu(selectedItem)
    m.settingsMenu.setFocus(true)
  else
    return
  end if

  m.settingDesc.text = m.settingsMenu.content.GetChild(m.settingsMenu.itemFocused).Description

end sub


sub boolSettingChanged()
  if not isValid(m.boolSetting.focusedChild) then return
  selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused]

  if m.boolSetting.checkedItem
    ' Update node field - observer handles registry persistence
    user.settings.Save(selectedSetting.settingName, "true")

    ' Special handling for globalRememberMe - set active_user in global registry
    if selectedSetting.settingName = "globalRememberMe"
      set_setting("active_user", m.global.user.id)
    end if
  else
    ' Update node field - observer handles registry persistence
    user.settings.Save(selectedSetting.settingName, "false")

    ' Special handling for globalRememberMe - remove active_user from global registry
    if selectedSetting.settingName = "globalRememberMe"
      unset_setting("active_user")
    end if
  end if
end sub

sub radioSettingChanged()
  if not isValid(m.radioSetting.focusedChild) then return
  selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused]
  newValue = m.radioSetting.content.getChild(m.radioSetting.checkedItem).id

  ' Update node field - observer handles registry persistence
  user.settings.Save(selectedSetting.settingName, newValue)
end sub

' JRScreen hook that gets ran when the screen is shown.
sub OnScreenShown()
  ' Clear backdrop on settings screens
  m.global.sceneManager.callFunc("setBackgroundImage", "")

  overhang = m.top.getScene().findNode("overhang")
  if not isValid(overhang) then return

  overhang.isLogoVisible = true
  overhang.currentUser = m.global.user.name
end sub

' JRScreen hook that gets ran as needed.
' Assumes settings were changed and they affect the device profile.
' Posts a new device profile to the server using the task thread.
sub OnScreenHidden()
  ' Post device profile updates
  m.postTask.arrayData = getDeviceCapabilities()
  m.postTask.apiUrl = "/Sessions/Capabilities/Full"
  m.postTask.control = "RUN"
  m.postTask.observeField("responseCode", "postFinished")
end sub

' Triggered by m.postTask after completing a post.
' Empty the task data when finished.
sub postFinished()
  m.postTask.unobserveField("responseCode")
  m.postTask.callFunc("empty")
end sub

' Returns true if any of the data entry forms are in focus
function isFormInFocus() as boolean
  if isValid(m.settingDetail.focusedChild) or m.radioSetting.hasFocus() or m.boolSetting.hasFocus() or m.integerSetting.hasFocus()
    return true
  end if
  return false
end function

function onKeyEvent(key as string, press as boolean) as boolean
  if not press then return false

  if (key = "back" or key = "left") and isValid(m.settingsMenu.focusedChild) and m.userLocation.Count() > 1
    LoadMenu({})
    return true
  else if (key = "back" or key = "left") and isFormInFocus()
    m.settingsMenu.setFocus(true)
    return true
  end if

  if key = "options"
    m.global.sceneManager.callFunc("popScene")
    return true
  end if

  if key = "right"
    settingSelected()
  end if

  if key = "up" and isValid(m.settingsMenu.focusedChild) and m.settingsMenu.itemFocused = 0
    m.settingsMenu.jumpToItem = m.settingsMenu.content.getChildCount() - 1

    return true
  end if

  if key = "down" and isValid(m.settingsMenu.focusedChild)
    if m.settingsMenu.itemFocused = m.settingsMenu.content.getChildCount() - 1
      m.settingsMenu.jumpToItem = 0

      return true
    end if
  end if

  return false
end function