components_quickConnect_QuickConnectDialog.bs
import "pkg:/source/api/baseRequest.bs"
import "pkg:/source/api/userAuth.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/session.bs"
import "pkg:/source/utils/translate.bs"
' Dialog has two phases:
' "waiting" - QC code shown, polling server for user approval
' "prompt" - auth succeeded in-memory; asking whether to persist credentials
sub init()
m.log = new log.Logger("QuickConnectDialog")
m.phase = "waiting"
m.quickConnectTimer = m.top.findNode("quickConnectTimer")
m.quickConnectTimer.observeField("fire", "quickConnectStatus")
m.quickConnectTimer.control = "start"
m.top.observeFieldScoped("buttonSelected", "onButtonSelected")
end sub
sub quickConnectStatus()
m.quickConnectTimer.control = "stop"
m.checkTask = CreateObject("roSGNode", "QuickConnect")
m.checkTask.secret = m.top.quickConnectJson.secret
m.checkTask.observeField("authenticated", "onAuthenticated")
m.checkTask.control = "run"
end sub
sub onAuthenticated()
m.checkTask.control = "stop"
m.checkTask.unobserveField("authenticated")
authenticated = m.checkTask.authenticated
if authenticated < 0
' Not yet approved; resume polling.
m.checkTask = invalid
m.quickConnectTimer.control = "start"
else if authenticated > 0
' Auth succeeded; user.Login() already hydrated in-memory state with
' saveCredentials=false. Now ask whether to persist to registry.
m.checkTask = invalid
showSaveCredentialsPrompt()
end if
end sub
' Mutates the open dialog in place to show a Yes/No prompt.
' Keeps the same dialog node so there is no visual flicker.
sub showSaveCredentialsPrompt()
m.log.info("Quick Connect authenticated - prompting to save credentials")
m.phase = "prompt"
m.top.message = [translate(translationKeys.MessageQuickConnectAuthenticatedSaveCredentials)]
m.top.buttons = [translate(translationKeys.ButtonYes), translate(translationKeys.ButtonNo)]
' Replacing the buttons array destroys and recreates the dialog's internal
' button group; focus does not automatically follow, so re-acquire it here.
' Without this, remote input routes back to the underlying scene and the
' dialog becomes visually present but non-interactive.
m.top.setFocus(true)
end sub
sub onButtonSelected()
if m.phase = "waiting"
' Cancel button in the waiting phase - abort before login completes.
quickConnectCancelled()
else if m.phase = "prompt"
' Yes = index 0 (save), No = index 1 (don't save).
finishQuickConnect(m.top.buttonSelected = 0)
end if
end sub
' User abandoned Quick Connect before server approval. Do NOT signal
' success - showScenes sees the dialog close and treats it as a cancel.
sub quickConnectCancelled()
m.log.info("Quick Connect cancelled")
m.quickConnectTimer.control = "stop"
if isValid(m.checkTask)
m.checkTask.control = "stop"
m.checkTask.unobserveField("authenticated")
m.checkTask = invalid
end if
m.top.close = true
end sub
' Phase 2 exit. Conditionally persist credentials, then signal success so
' showScenes can complete the login flow.
sub finishQuickConnect(saveCredentials as boolean)
if saveCredentials
m.log.info("Credentials saved")
persistCurrentUserCredentials()
else
m.log.info("Credentials not saved")
end if
m.top.isAuthenticated = true
m.top.close = true
end sub
' Writes authToken / username / primaryImageTag to the current user's
' registry section. The QuickConnect task called user.Login(user, false)
' earlier, which left m.global.user hydrated without touching the registry.
sub persistCurrentUserCredentials()
globalUser = m.global.user
if isValidAndNotEmpty(globalUser.authToken)
setUserSetting("authToken", globalUser.authToken)
end if
if isValidAndNotEmpty(globalUser.name)
setUserSetting("username", globalUser.name)
end if
if isValidAndNotEmpty(globalUser.primaryImageTag)
setUserSetting("primaryImageTag", globalUser.primaryImageTag)
end if
end sub
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false
' "OK" does not route here - handled via onButtonSelected above.
if key = "back"
if m.phase = "waiting"
quickConnectCancelled()
else if m.phase = "prompt"
' Back on the save prompt = decline to persist; login already succeeded.
finishQuickConnect(false)
end if
return true
end if
return false
end function