Hi guys. I'm just starting out in SG and am trying to add a "loading dialog" or "progress dialog" while my category content is being fetched. I'm using the Roku samples but in the old days it was easy to create a dialog message. If anyone can offer me some guidance, it would be much appreciated.
The code from the Roku example to fetch the content is UriHandler.brs:
' ********** Copyright 2016 Roku Corp. All Rights Reserved. **********
sub init()
print "UriHandler.brs - [init]"
m.port = createObject("roMessagePort")
' fields for checking if content has been loaded
m.top.count = 0
m.top.numRows = 0
m.top.numRowsReceived = 0
m.top.numBadRequests = 0
m.top.contentSet = false
' Stores the content if not all requests are ready
m.top.ContentCache = createObject("roSGNode", "ContentNode")
m.top.Cache = createObject("roSGNode", "Node")
' setting callbacks for url request and response
m.top.observeField("request", m.port)
m.top.observeField("encodeRequest", m.port)
m.top.observeField("ContentCache", m.port)
' setting the task thread function
m.top.functionName = "go"
m.top.control = "RUN"
end sub
'Task function
sub go()
print "UriHandler.brs - [go]"
' Holds requests by id
m.jobsById = {}
' UriFetcher event loop
while true
msg = wait(0, m.port)
mt = type(msg)
print "--------------------------------------------------------------------------"
print "Received event type '"; mt; "'"
' If a request was made
if mt = "roSGNodeEvent"
if msg.getField()="request"
if addRequest(msg.getData()) <> true then print "Invalid request"
else if msg.getField()="encodeRequest"
if encodeRequest(msg.getData()) <> true then print "Invalid request"
else if msg.getField()="ContentCache"
updateContent()
else
print "Error: unrecognized field '"; msg.getField() ; "'"
end if
' If a response was received
else if mt="roUrlEvent"
processResponse(msg)
' Handle unexpected cases
else
print "Error: unrecognized event type '"; mt ; "'"
end if
end while
end sub
' Encode the url and call addRequest
function encodeRequest(request as Object) as Boolean
encoder = createObject("roUrlTransfer")
encodedStr = encoder.escape(request.strToEncode)
newParam = { uri: request.context.parameters.uri + encodedStr }
request.context.parameters = newParam
return addRequest(request)
end function
' @Params:
' request: an AA containing a "context" node
' Context node fields:
' parameters: the request parameters: Headers, Method, and Url
' num: the number related to the request
function addRequest(request as Object) as Boolean
print "UriHandler.brs - [addRequest]"
if type(request) = "roAssociativeArray"
context = request.context
if type(context) = "roSGNode"
parameters = context.parameters
if type(parameters)="roAssociativeArray"
headers = parameters.headers
method = parameters.method
uri = parameters.uri
if type(uri) = "roString"
urlXfer = createObject("roUrlTransfer")
urlXfer.SetCertificatesFile("common:/certs/ca-bundle.crt")
urlXfer.InitClientCertificates()
urlXfer.setUrl(uri)
urlXfer.setPort(m.port)
' Add headers to the request
for each header in headers
urlXfer.AddHeader(header, headers.lookup(header))
end for
' should transfer more stuff from parameters to urlXfer
idKey = stri(urlXfer.getIdentity()).trim()
'Make request based on request method
' AsyncGetToString returns false if the request couldn't be issued
if method = "POST" or method = "PUT" or method = "DELETE"
urlXfer.setRequest(method)
ok = urlXfer.AsyncPostFromString("")
else
ok = urlXfer.AsyncGetToString()
end if
if ok then
m.jobsById[idKey] = {
context: request,
xfer: urlXfer
}
else
print "Error: request couldn't be issued"
end if
print "Initiating transfer '"; idkey; "' for URI '"; uri; "'"; " succeeded: "; ok
else
print "Error: invalid uri: "; uri
m.top.numBadRequests++
end if
else
print "Error: parameters is the wrong type: " + type(parameters)
return false
end if
else
print "Error: context is the wrong type: " + type(context)
return false
end if
else
print "Error: request is the wrong type: " + type(request)
return false
end if
print "--------------------------------------------------------------------------"
return true
end function
'Received a response
sub processResponse(msg as Object)
print "UriHandler.brs - [processResponse]"
idKey = stri(msg.GetSourceIdentity()).trim()
job = m.jobsById[idKey]
print "IDKEY: "+idKey
if job <> invalid
context = job.context
parameters = context.context.parameters
jobnum = job.context.context.num
uri = parameters.uri
des = job.context.context.des
print "Response for transfer '"; idkey; "' for URI '"; uri; "'";" ";des
result = {
code: msg.GetResponseCode(),
headers: msg.GetResponseHeaders(),
content: msg.GetString(),
num: jobnum,
des: des
}
' could handle various error codes, retry, etc. here
m.jobsById.delete(idKey)
job.context.context.response = result
if msg.GetResponseCode() = 200
if result.num = 3 or result.num = 4
parseFollowedContent(job)
else if result.num = 0
parseResponse(job)
else if result.num = 1
parseLeaf(job)
end if
else if msg.GetResponseCode() = 204 and result.num = -7
parseLogout(job)
else if msg.GetResponseCode() = 204 and result.num = -10
parseUnfollow(true)
else
if result.num > 0 and result.num < 3
m.top.numBadRequests++
m.top.numRowsReceived++
else
print "Error: status code was: " + (msg.GetResponseCode()).toStr()
end if
end if
else
print "Error: event for unknown job "; idkey
end if
print "--------------------------------------------------------------------------"
end sub
sub parseLeaf(job as object)
print "UriHandler.brs - [parseLeaf]"
result = job.context.context.response
str = result.content
num = result.num
title = job.context.context.title
xml = CreateObject("roXMLElement")
if xml.parse(result.content)
if xml.feed <> invalid
row = CreateObject("roSGNode", "ContentNode")
row.title = title
for each element in xml.getChildElements()
if element.getChildElements() <> invalid
contentNode = CreateObject("roSGNode","ContentNode")
contentNode.hdposterurl = [email="element@hdImg"]element@hdImg[/email]
contentNode.sdposterurl = [email="element@sdImg"]element@sdImg[/email]
for each child in element.getchildElements()
if child.getname() = "title"
contentNode.title = child.getText()
'print "LEAF TITLE: "+contentNode.title
else if child.getname() = "contentId"
contentnode.episodeNumber = child.gettext()
else if child.getname() = "genres"
contentnode.categories = child.getText()
else if child.getname() = "streamFormat"
contentnode.streamFormat = child.gettext()
'else if child.getname() = "contentQuality"
'contentnode.contentQuality = child.gettext()
else if child.getname() = "media"
for each item in child.getchildElements()
if item.getname() = "streamQuality"
contentnode.rating = item.gettext()
else if item.getname() = "streamBitrate"
contentNode.maxBandWidth = item.gettext().toint()
else if item.getname() = "streamUrl"
contentNode.url = item.gettext()
else
'print "PARSING LEAF FOR: " ; item.getName() ; item.getText()
end if
end for
else if child.getname() = "synopsis"
contentnode.description = child.gettext()
else if child.getname() = "genres"
contentnode.shortdescriptionline1 = child.gettext()
else if child.getname() = "runtime"
contentnode.shortdescriptionline2 = child.gettext()
end if
end for
row.appendChild(contentNode)
end if
end for
print "ROW TITLE: "+row.title
if m.top.contentcache.hasfield(m.top.numRowsReceived.tostr()) then m.top.numRowsReceived++
contentAA = {}
contentAA[m.top.numRowsReceived.toStr()] = row
m.top.contentCache.addFields(contentAA)
end if
end if
end sub
' For loading category rowlist content
sub parseResponse(job as object)
print "UriHandler.brs - [parseResponse]"
result = job.context.context.response
str = result.content
num = result.num
xml = CreateObject("roXMLElement")
if xml.parse(result.content)
if xml.category <> invalid
if xml.category[0].GetName() = "category"
print "begin category node parsing"
categories = xml.GetChildElements()
print "number of categories: " + categories.Count().toStr()
contentRoot = CreateObject("roSGNode","ContentNode")
contentRow = CreateObject("roSGNode","ContentNode")
'Create a category node for each category'
for each category in categories
if category.getname() = "banner_ad"
print "skipped banner_ad"
else if category.getname() = "category"
contentNode = CreateObject("roSGNode","ContentNode")
print "category: " + [email="category@title"]category@title[/email] + " | " + [email="category@description"]category@description[/email]
aa = {}
aa.title = [email="category@title"]category@title[/email]
aa.description = [email="category@description"]category@description[/email]
aa.shortdescriptionline1 = [email="category@title"]category@title[/email]
aa.shortdescriptionline2 = [email="category@description"]category@description[/email]
aa.sdPosterUrl = [email="category@sd_img"]category@sd_img[/email]
aa.hdposterurl = [email="category@hd_img"]category@hd_img[/email]
m.count = 0
categoryLeaves = category.getChildElements()
for each leaf in categoryLeaves
subAA = {}
subAA.title = [email="leaf@title"]leaf@title[/email]
subAA.url = [email="leaf@feed"]leaf@feed[/email]
subAA.des = [email="leaf@description"]leaf@description[/email]
a = {}
a[subAA.title] = subAA
AddAndSetFields(contentNode, a)
m.count++
end for
AddAndSetFields(contentNode,{count: m.count})
AddAndSetFields(contentNode, aa)
contentRow.appendChild(contentNode)
end if
end for
contentRoot.appendChild(contentRow)
m.top.content = contentRoot
end if
end if
end if
print "done with parseResponse"
end sub
' Callback function for when content has finished parsing
sub updateContent()
'screen = CreateObject("roSGScreen")
'm.port = CreateObject("roMessagePort")
'screen.setMessagePort(m.port)
'scene = screen.CreateScene("ProgressDialogExample")
'screen.show()
'while(true)
'msg = wait(0, m.port)
'msgType = type(msg)
'if msgType = "roSGScreenEvent"
'if msg.isScreenClosed() then return
'end if
'end while
print "UriHandler.brs - [updateContent]"
if m.top.contentSet return
if m.top.numRows - 1 = m.top.numRowsReceived
parent = createObject("roSGNode", "ContentNode")
newAA = {}
newA=[]
for i = (m.top.numRows - m.top.numCurrentRows) to m.top.numRowsReceived
leaftitle = m.top.contentCache.getField(i.toStr()).title
'print "UPDATE CONTENT: "+i.toStr()+" "+leaftitle+" "
'add to array
newAA.AddReplace(leaftitle,i.toStr())
'parent.appendchild(m.top.contentCache.getField(i.toStr()))
end for
newA.push(newAA)
newA.SortBy("key")
arr={}
for each arr in newA
for each item in arr.Items()
print "KEY: "+item.key +" VALUE: "+item.value
title=item.key
fieldname=item.value
newtitle = mid(title,6)
print "NEW TITLE: "+newtitle
m.top.contentCache.getField(fieldname.toStr()).title = newtitle
parent.appendchild(m.top.contentCache.getField(item.value))
end for
end for
print "All content has finished loading"
m.top.contentSet = true
m.top.categorycontent = parent
itemToCache = {}
itemToCache[m.top.category] = parent
AddAndSetFields(m.top.cache, itemToCache)
else
print "Not all content has finished loading yet"
end if
end sub
The component UriHandler.xml is:
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2016 Roku Corp. All Rights Reserved. -->
<component name="UriHandler" extends="Task">
<interface>
<!-- Field to issue a request to the handler -->
<field id="request" type="assocarray"/>
<!-- Issue a request to encode to the handler (contains top game content) -->
<field id="encodeRequest" type="assocarray"/>
<!-- Contains main menu content -->
<field id="content" type="node"/>
<field id="categorycontent" type="node"/>
<field id="count" type="integer"/>
<!-- The # of rows to populate -->
<field id="numRows" type="integer"/>
<!-- # of rows of content received -->
<field id="numRowsReceived" type="integer"/>
<!-- # of requests that have bad/no content -->
<field id="numBadRequests" type="integer" value="0"/>
<field id="numCurrentRows" type="integer" value="0"/>
<!-- variable so updateContent only runs once -->
<field id="contentSet" type="boolean"/>
<!-- Caching content removes redundant url requests -->
<field id="ContentCache" type="node"/>
<field id="Cache" type="node"/>
<!-- Field to store category tag for the current content item -->
<field id="Category" type="string"/>
</interface>
<script type="text/brightscript" uri="pkg:/components/SGHelperFunctions.brs"/>
<script type="text/brightscript" uri="pkg:/components/UriHandler.brs"/>
</component>
And lastly, the component for the progressdialogscene.xml is:
<?xml version = "1.0" encoding = "utf-8" ?>
<!--********** Copyright 2016 Roku Corp. All Rights Reserved. **********-->
<component name = "ProgressDialogExample" extends = "Scene" >
<script type = "text/brightscript" >
<![CDATA[
sub init()
'm.top.backgroundURI = "pkg:/images/rsgde_bg_hd.jpg"
'example = m.top.findNode("instructLabel")
'examplerect = example.boundingRect()
'centerx = (1280 - examplerect.width) / 2
'centery = (720 - examplerect.height) / 2
'example.translation = [ centerx, centery ]
m.top.setFocus(true)
showdialog()
end sub
sub showdialog()
progressdialog = createObject("roSGNode", "ProgressDialog")
'progressdialog.backgroundUri = "pkg:/images/rsgde_dlg_bg_hd.9.png"
progressdialog.title = "Please wait...loading"
m.top.dialog = progressdialog
m.timer = createObject("RoSGNode", "Timer")
m.timer.duration = 5
m.timer.control = "start"
m.timer.ObserveField("fire", "dismissdialog")
end sub
sub dismissdialog()
m.top.dialog.close = true
end sub
function onKeyEvent(key as String, press as Boolean) as Boolean
if press then
'if key = "OK"
'dismissdialog()
'return true
'end if
end if
return false
end function
]]>
</script>
<children >
</children>
</component>
I was trying to create a screen with the progressidalogscene in updateContent() sub of UriHandler.brs and the screen seems to open ok but when I tried closing it with screen.close(), the screen goes black or shows the main category list. I'm thinking the roSGScreen I'm creating for the progress dialog is screwing up the roSGScreen that is supposed to display the category content (leafs, etc). Can anyone help me clue me in on how to add a loader/progress dialog that will automatically close once content is loaded? Thanks.