EDIT: Added another file
Hello, I am fairly new to Roku development and am running into an incredibly frustrating issue left behind by a previous dev. I have an app that lets you navigate between a list of fullscreen videos and photos. Going between them mostly works fine, however when I transition from a video into a photo, the app completely stops accepting any input from my remote. I have monitored all onKeyEvent triggers and can confirm that none of them throughout the app trigger once this state is made. The app doesn’t crash and it doesn’t give any errors in the debug console. Backing out of the fullscreen mode is impossible once this happens as well. Thankfully, the home button still works so I can exit the app but that’s it. There is no further functionality within the app. I’m at a complete loss as to what this issue may be. Below I share some of the core functions used in this functionality, but please let me know if there’s anything more specific I may be able to pass along that could help us to figure out how to solve this issue.
sub _onCurrentMediaIndexChanged(event)
print "onCurrentMediaIndexChanged"
index = event.getData()
currentItemNode = m.top.mediaPlaylistNode.getChild(index)
print "onCurrentMediaIndexChanged", currentItemNode
_showMedia(currentItemNode)
end sub
sub _addImageViewForPreviewMediaItems(previewImages)
' print "addImageViewForPreviewMediaItems", m._slideShow
if IsInvalid(m._slideShow)
m._slideShow = m.top.createChild("ImageSlideshow")
end if
m._slideShow.update({
id: "slideShow"
uri: previewImages[0][ToString(displaySize().width)]
loadDisplayMode: "limitSize"
loadWidth: 1920
loadHeight: 1080
animationDuration: 3
content: previewImages
interval: 7
control: "start"
opacity: 0.5
})
end sub
sub _showMedia(mediaItemNode as object)
print "showMedia"
m.itemMediaType = getValueForPath(mediaItemNode, "dataItem.elementType")
if m._lastMediaType <> m.itemMediaType
_cleanUpSubviews()
end if
' print mediaItemNode
' print mediaItemNode.dataItem
' print mediaItemNode.dataItem.elementType
if mediaItemNode.dataItem.elementType = "photo"
' m.continuesPlaytimer.control = "stop"
print "ADD PHOTO"
_addPhotoViewForMediaItem(mediaItemNode.dataItem)
else if mediaItemNode.dataItem.elementType = "video"
_addVideoViewForMediaItem(mediaItemNode.dataItem)
end if
m._lastMediaType = m.itemMediaType
end sub
sub _addPhotoViewForMediaItem(item as object)
print "addPhotoViewForMediaItem"
if m.top.isContinuousPlayEnabled then
m.continuesPlaytimer.control = "stop"
m.continuesPlaytimer.control = "start"
end if
if IsInvalid(m._photoView)
m._photoView = m.top.createChild("FadingBackground")
end if
m._photoView.update({
id: "photoView"
uri: getValueForPath(item, "srcMediaUrl")
width: 1920
height: 1080
loadDisplayMode: "scaleToFit"
loadWidth: 1920
loadHeight: 1080
animationDuration: 0.5
})
end sub
sub _addVideoComponent()
' print "addVideoComponent"
if IsInvalid(m._videoView)
m._videoView = m.top.createChild("Video")
m._videoView.observeField("state", "_onVideoStateChanged")
end if
end sub
sub _addCustomPlayer()
' print "addCustomPlayer"
if IsInvalid(m._customPlayer)
m._customPlayer = m.top.createChild("PlayerScreen")
m._customPlayer.observeField("showPrevious", "_showPrevious")
m._customPlayer.observeField("showNext", "_showNext")
m._customPlayer.observeField("state", "_onVideoPlayerStateChanged")
end if
end sub
sub _addVideoViewForPreviewMediaItems(items as object)
' print "addVideoViewForPreviewMediaItems"
_addVideoComponent()
m._videoView.update({
id: "videoView"
content: _getPreviewVideoContentNodeFor(items)
width: 1920
height: 1080
contentIsPlaylist: true
contentIndex: 0
loop: true
mute: true
enableUI: false
})
m._videoView.control = PlaybackAction().play
m._videoPrewievMask = m.top.createChild("Poster")
m._videoPrewievMask.update({
uri: "pkg:/images/videoPrewievMask.png"
width: 1920
height: 1080
})
end sub
sub _addVideoViewForMediaItem(item as object)
print "addVideoViewForMediaItem"
_addCustomPlayer()
m._customPlayer.update({
id: "customPlayer"
content: _getVideoContentNodeFor(item)
width: 1920
height: 1080
control: PlaybackAction().play
})
m._customPlayer.setFocus(true)
end sub
sub _onVideoStateChanged(event)
' print "onVideoStateChanged"
state = event.getData()
errorMessage = m._videoView
if state = PlaybackState().finished and m.top.isPreview
showed = _showNext()
if not _showNext()
m.top.currentMediaIndex = 0
end if
end if
end sub
sub _cleanUpSubviews()
print "cleanUpSubviews"
if IsValid(m._photoView)
m.top.removeChild(m._photoView)
m._photoView = invalid
end if
if IsValid(m._videoView)
m.top.removeChild(m._videoView)
m._videoView = invalid
end if
if IsValid(m._customPlayer)
m.top.removeChild(m._customPlayer)
m._customPlayer = invalid
end if
if IsValid(m._slideShow)
m.top.removeChild(m._slideShow)
m._slideShow = invalid
end if
if IsValid(m._videoPrewievMask)
m.top.removeChild(m._videoPrewievMask)
m._videoPrewievMask = invalid
end if
end sub
function _getVideoContentNodeFor(item) as object
' print "getVideoContentNodeFor"
webCQUrl = getValueForPath(item, "editor_streams.web_cq.url")
hlsUrl = getValueForPath(item, "editor_streams.hls.url", webCQUrl)
content = CreateObject("roSGnode", "ContentNode")
content.url = defaultValueIfInvalid(getValue(item, "srcMediaUrl"), defaultValueIfInvalid(webCQUrl, hlsUrl))
if item.isEdited
content.url = defaultValueIfInvalid(defaultValueIfInvalid(webCQUrl, hlsUrl), getValue(item, "srcMediaUrl"))
end if
return content
end function
function _getPreviewVideoContentNodeFor(items) as object
' print "getPreviewVideoContentNodeFor"
content = CreateObject("roSGnode", "ContentNode")
for each item in items
webCQUrl = getValueForPath(item, "web_cq.url")
hlsUrl = getValueForPath(item, "hls.url", webCQUrl)
itemContent = content.createChild("ContentNode")
itemContent.url = defaultValueIfInvalid(getValue(item, "srcMediaUrl"), defaultValueIfInvalid(webCQUrl, hlsUrl))
end for
return content
end function
sub _onVideoPlayerStateChanged(event as object)
' print "onVideoPlayerStateChanged"
state = event.GetData()
if state = PlaybackState().finished and m.top.isContinuousPlayEnabled then
_showNext()
end if
end sub
function _showNext() as boolean
print "showNext", m.itemMediaType
' print m
' print m.top
nextIndex = m.top.currentMediaIndex + 1
print nextIndex
if nextIndex < m.top.mediaPlaylistNode.getChildCount()
m.top.currentMediaIndex = nextIndex
return true
end if
return false
end function
function _showPrevious() as boolean
' print "showPrevious", m.itemMediaType
if m.itemMediaType = "photo" then
m.continuesPlaytimer.control = "stop"
end if
nextIndex = m.top.currentMediaIndex - 1
if nextIndex >= 0
m.top.currentMediaIndex = nextIndex
return true
end if
return false
end function
function onKeyEvent(key as string, press as boolean) as boolean
print "onKeyEvent FullscreenMediaPage", key, press
result = false
if not press then return result
if key = RemoteKeys().right
result = _showNext()
else if key = RemoteKeys().Left
result = _showPrevious()
end if
return result
end function
After sleuthing around more, I found another file that might be relevant to this issue. Funnily enough, this has a comment that is aware of the issue and has a “fix” commented out. However, when trying to implement the fix, it breaks far more than it fixes and the onKeyEvent trigger still won’t fire anyway.
sub init()
_initSubviews()
_initVars()
_setObservers()
end sub
sub _initSubviews()
m._clickTimer = m.top.findNode("clickTimer")
m._longPressObserveTimer = m.top.findNode("longPressObserveTimer")
m._forwardTimer = m.top.findNode("forwardTimer")
m._rewindTimer = m.top.findNode("rewindTimer")
end sub
sub _initVars()
m.top.notificationInterval = 1
m._stateVariable = PlaybackState().buffering
m._clickTimer.duration = 0.5
m._rightClickCount = 0
m._leftClickCount = 0
m._secondsToShowNext = 5
end sub
sub _setObservers()
m.top.observeField("state", "_onStateChanged")
m._clickTimer.observeField("fire", "_onClickTimer")
end sub
sub _onStateChanged(event)
m._stateVariable = event.getData()
end sub
sub _onClickTimer()
m._rightClickCount = 0
m._leftClickCount = 0
end sub
' issue is that when display first image after last video its not navigate to FullscreenMediaPage but it should
' because the right click key event and showNext() are in FullscreenMediaPage so to navigate it....
' i made this function to navigate to FullscreenMediaPage after click the double click when video is playing
' function showFullscreenMediaPage() as void
' print "showFullscreenMediaPage", m.top
' if m.top <> invalid then
' ' Navigate directly to FullscreenMediaPage
' fullscreenMediaPage = CreateObject("roSGNode", "FullscreenMediaPage")
' if fullscreenMediaPage <> invalid then
' m.top.appendChild(fullscreenMediaPage)
' fullscreenMediaPage.setFocus(true)
' else
' print "Error: Failed to create FullscreenMediaPage scene."
' end if
' else
' print "Error: m.top is invalid."
' end if
' end function
sub _onRightButton()
print "onRightButton"
m._rightClickCount += 1
if m._stateVariable <> PlaybackState().buffering
if (m._rightClickCount = 1 and m.top.position >= (m.top.duration - m._secondsToShowNext)) or m._rightClickCount = 2
m.top.control = "stop"
m.top.showNext = true
m._rightClickCount = 0
m._stateVariable = PlaybackState().buffering
' end if
else ' call this showFullscreenMediaPage after a certon condition .. not in else
' showFullscreenMediaPage()
end if
end if
end sub
sub _onLeftButton()
m._leftClickCount += 1
if m._stateVariable <> PlaybackState().buffering
if m._leftClickCount = 2
m.top.showPrevious = true
m._leftClickCount = 0
m._stateVariable = PlaybackState().buffering
end if
end if
end sub
function onKeyEvent(key, press) as boolean
print "onKeyEvent PlayerScreen"
handled = false
if press = true and (key = RemoteKeys().left or key = RemoteKeys().right)
m._clickTimer.control = ControlAction().start
if key = RemoteKeys().left
_onLeftButton()
else if key = RemoteKeys().right
_onRightButton()
end if
handled = true
end if
return handled
end function
