import "pkg:/source/roku_modules/log/LogMixin.brs" import "pkg:/source/utils/misc.bs" sub init() m.log = log.Logger("SceneManager") m.groups = [] m.scene = m.top.getScene() m.content = m.scene.findNode("content") m.overhang = m.scene.findNode("overhang") end sub ' ' Push a new group onto the stack, replacing the existing group on the screen sub pushScene(newGroup) currentGroup = m.groups.peek() if newGroup <> invalid if currentGroup <> invalid 'Search through group and store off last focused item if currentGroup.focusedChild <> invalid focused = currentGroup.focusedChild while focused.hasFocus() = false focused = focused.focusedChild end while currentGroup.lastFocus = focused currentGroup.setFocus(false) else currentGroup.setFocus(false) end if if currentGroup.isSubType("JFGroup") unregisterOverhangData(currentGroup) end if currentGroup.visible = false if currentGroup.isSubType("JFScreen") currentGroup.callFunc("OnScreenHidden") end if end if m.groups.push(newGroup) if currentGroup <> invalid m.content.replaceChild(newGroup, 0) else m.content.appendChild(newGroup) end if if newGroup.isSubType("JFScreen") newGroup.callFunc("OnScreenShown") end if 'observe info about new group, set overhang title, etc. if newGroup.isSubType("JFGroup") registerOverhangData(newGroup) ' Some groups set focus to a specific component within init(), so we don't want to ' change if that is the case. if newGroup.isInFocusChain() = false newGroup.setFocus(true) end if else if newGroup.isSubType("JFVideo") newGroup.setFocus(true) newGroup.control = "play" m.overhang.visible = false end if else currentGroup.focusedChild.setFocus(true) end if end sub ' ' Remove the current group and load the last group from the stack sub popScene() group = m.groups.pop() if group <> invalid if group.isSubType("JFGroup") unregisterOverhangData(group) else if group.isSubType("JFVideo") ' Stop video to make sure app communicates stop playstate to server group.control = "stop" end if group.visible = false if group.isSubType("JFScreen") group.callFunc("OnScreenHidden") end if else ' Exit app if for some reason we don't have anything on the stack m.scene.exit = true end if group = m.groups.peek() if group <> invalid registerOverhangData(group) group.visible = true m.content.replaceChild(group, 0) if group.isSubType("JFScreen") group.callFunc("OnScreenShown") else ' Restore focus if group.lastFocus <> invalid group.lastFocus.setFocus(true) else if group.focusedChild <> invalid group.focusedChild.setFocus(true) else group.setFocus(true) end if end if end if else ' Exit app if the stack is empty after removing group m.scene.exit = true end if stopLoadingSpinner() end sub ' ' Return group at top of stack without removing function getActiveScene() as object return m.groups.peek() end function ' ' Clear all content from group stack sub clearScenes() if m.content <> invalid then m.content.removeChildrenIndex(m.content.getChildCount(), 0) for each group in m.groups if LCase(group.subtype()) = "jfscreen" group.callFunc("OnScreenHidden") end if end for m.groups = [] end sub ' ' Clear previous scene from group stack sub clearPreviousScene() m.groups.pop() end sub ' ' Delete scene from group stack at passed index sub deleteSceneAtIndex(index = 1) m.groups.Delete(index) end sub ' ' Display user/device settings screen sub settings() settingsScreen = createObject("roSGNode", "Settings") pushScene(settingsScreen) end sub ' ' Register observers for overhang data sub registerOverhangData(group) if group.isSubType("JFGroup") if group.overhangTitle <> invalid then m.overhang.title = group.overhangTitle if group.optionsAvailable m.overhang.showOptions = true else m.overhang.showOptions = false end if group.observeField("optionsAvailable", "updateOptions") group.observeField("overhangTitle", "updateOverhangTitle") if group.overhangVisible m.overhang.visible = true else m.overhang.visible = false end if group.observeField("overhangVisible", "updateOverhangVisible") else if group.isSubType("JFVideo") m.overhang.visible = false else m.log.error("registerOverhangData(): Unexpected group type.", group, group.subtype()) end if end sub ' ' Remove observers for overhang data sub unregisterOverhangData(group) group.unobserveField("overhangTitle") end sub ' ' Update overhang title sub updateOverhangTitle(msg) m.overhang.title = msg.getData() end sub ' ' Update options availability sub updateOptions(msg) m.overhang.showOptions = msg.getData() end sub ' ' Update whether the overhang is visible or not sub updateOverhangVisible(msg) m.overhang.visible = msg.getData() end sub ' ' Update username in overhang sub updateUser() ' Passthrough to overhang if m.overhang <> invalid then m.overhang.currentUser = m.top.currentUser end sub ' ' Reset time sub resetTime() ' Passthrough to overhang m.overhang.callFunc("resetTime") end sub ' ' Display dialog to user with an OK button sub userMessage(title as string, message as string) dialog = createObject("roSGNode", "StandardMessageDialog") dialog.title = title dialog.message = message dialog.buttons = [tr("OK")] dialog.observeField("buttonSelected", "dismissDialog") m.scene.dialog = dialog end sub ' ' Display dialog to user with an OK button sub standardDialog(title, message) dialog = createObject("roSGNode", "StandardDialog") dlgPalette = createObject("roSGNode", "RSGPalette") dlgPalette.colors = { DialogBackgroundColor: "0x262828FF", DialogFocusColor: "0xcececeFF", DialogFocusItemColor: "0x202020FF", DialogSecondaryTextColor: "0xf8f8f8ff", DialogSecondaryItemColor: "#00a4dcFF", DialogTextColor: "0xeeeeeeFF" } dialog.palette = dlgPalette dialog.observeField("buttonSelected", "dismissDialog") dialog.title = title dialog.contentData = message dialog.buttons = [tr("OK")] m.scene.dialog = dialog end sub ' ' Display dialog to user with an OK button sub radioDialog(title, message) dialog = createObject("roSGNode", "RadioDialog") dlgPalette = createObject("roSGNode", "RSGPalette") dlgPalette.colors = { DialogBackgroundColor: "0x262828FF", DialogFocusColor: "0xcececeFF", DialogFocusItemColor: "0x202020FF", DialogSecondaryTextColor: "0xf8f8f8ff", DialogSecondaryItemColor: "#00a4dcFF", DialogTextColor: "0xeeeeeeFF" } dialog.palette = dlgPalette dialog.observeField("buttonSelected", "dismissDialog") dialog.title = title dialog.contentData = message dialog.buttons = [tr("OK")] m.scene.dialog = dialog end sub ' ' Display dialog to user with an OK button sub optionDialog(title, message, buttons) m.top.dataReturned = false m.top.returnData = invalid m.userselection = false dialog = createObject("roSGNode", "StandardMessageDialog") dlgPalette = createObject("roSGNode", "RSGPalette") dlgPalette.colors = { DialogBackgroundColor: "0x262828FF", DialogFocusColor: "0xcececeFF", DialogFocusItemColor: "0x202020FF", DialogSecondaryTextColor: "0xf8f8f8ff", DialogSecondaryItemColor: "#00a4dcFF", DialogTextColor: "0xeeeeeeFF" } dialog.palette = dlgPalette dialog.observeField("buttonSelected", "optionSelected") dialog.observeField("wasClosed", "optionClosed") dialog.title = title dialog.message = message dialog.buttons = buttons m.scene.dialog = dialog end sub ' ' Return button the user selected sub optionClosed() if m.userselection then return m.top.returnData = { indexSelected: -1, buttonSelected: "" } m.top.dataReturned = true end sub ' ' Return button the user selected sub optionSelected() m.userselection = true m.top.returnData = { indexSelected: m.scene.dialog.buttonSelected, buttonSelected: m.scene.dialog.buttons[m.scene.dialog.buttonSelected] } m.top.dataReturned = true dismissDialog() end sub ' ' Close currently displayed dialog sub dismissDialog() m.scene.dialog.close = true end sub ' ' Returns bool indicating if dialog is currently displayed function isDialogOpen() as boolean return m.scene.dialog <> invalid end function