mirror of
https://github.com/jellyfin/jellyfin-roku.git
synced 2024-11-28 00:40:39 +00:00
Dont forget git add
This commit is contained in:
parent
34fb52591a
commit
1f91a96874
8
components/config/data.xml
Normal file
8
components/config/data.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="ConfigData" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="label" type="string" />
|
||||
<field id="value" type="string" />
|
||||
<field id="type" type="string" />
|
||||
</interface>
|
||||
</component>
|
51
components/config/item.xml
Normal file
51
components/config/item.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="ConfigItem" extends="Group">
|
||||
<children>
|
||||
<LayoutGroup
|
||||
layoutDirection="horiz"
|
||||
vertAlignment="center"
|
||||
itemSpacings="20"
|
||||
translation="[8,40]" >
|
||||
<Label id="label"
|
||||
horizAlign="left"
|
||||
width="196"
|
||||
height="60"
|
||||
color="#666666" />
|
||||
<Label id="value"
|
||||
horizAlign="left"
|
||||
width="196"
|
||||
height="60"
|
||||
color="#666666" />
|
||||
</LayoutGroup>
|
||||
</children>
|
||||
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged" />
|
||||
</interface>
|
||||
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub Init()
|
||||
m.name = m.top.findNode("label")
|
||||
m.value = m.top.findNode("value")
|
||||
end sub
|
||||
|
||||
sub itemContentChanged() as void
|
||||
data = m.top.itemContent
|
||||
|
||||
m.name.text = data.label
|
||||
if data.value = ""
|
||||
m.value.color = "#444444"
|
||||
m.value.text = "Enter a value..."
|
||||
else if data.type = "password"
|
||||
m.value.color = "#ffffff"
|
||||
m.value.text = "********"
|
||||
else
|
||||
m.value.color = "#ffffff"
|
||||
m.value.text = data.value
|
||||
end if
|
||||
end sub
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</component>
|
78
components/config/list.xml
Normal file
78
components/config/list.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="ConfigList" extends="MarkupList">
|
||||
<interface>
|
||||
<function name="setData" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="pkg:/source/config.brs" />
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub init()
|
||||
m.top.itemComponentName = "ConfigItem"
|
||||
|
||||
m.top.drawFocusFeedback = True
|
||||
m.top.vertFocusAnimationStyle = "floatingFocus"
|
||||
|
||||
m.top.observeField("itemSelected", "onItemSelected")
|
||||
|
||||
m.top.setfocus(true)
|
||||
|
||||
end sub
|
||||
|
||||
function setData(items)
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
|
||||
for each item in items
|
||||
config = data.CreateChild("ConfigData")
|
||||
config.label = item["label"]
|
||||
config.value = get_setting(item["field"])
|
||||
config.type = item["type"]
|
||||
end for
|
||||
|
||||
m.top.content = data
|
||||
end function
|
||||
|
||||
function onItemSelected()
|
||||
i = m.top.itemSelected
|
||||
itemField = m.top.content.getchild(i)
|
||||
|
||||
show_dialog(itemField)
|
||||
|
||||
end function
|
||||
|
||||
function onDialogButton()
|
||||
d = m.dialog
|
||||
button_text = d.buttons[d.buttonSelected]
|
||||
|
||||
if button_text = "OK"
|
||||
m.configField.value = d.text
|
||||
dismiss_dialog()
|
||||
return true
|
||||
else if button_text = "Cancel"
|
||||
dismiss_dialog()
|
||||
return false
|
||||
end if
|
||||
end function
|
||||
|
||||
|
||||
sub show_dialog(configField)
|
||||
dialog = createObject("roSGNode", "KeyboardDialog")
|
||||
m.configField = configField
|
||||
dialog.title = "Enter the " + configField.label
|
||||
dialog.buttons = ["OK", "Cancel"]
|
||||
|
||||
if configField.value <> "" then
|
||||
dialog.text = configField.value
|
||||
end if
|
||||
|
||||
m.top.getparent().dialog = dialog
|
||||
m.dialog = dialog
|
||||
|
||||
dialog.observeField("buttonSelected", "onDialogButton")
|
||||
end sub
|
||||
|
||||
sub dismiss_dialog()
|
||||
m.dialog.close = true
|
||||
end sub
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
58
components/config/scene.brs
Normal file
58
components/config/scene.brs
Normal file
@ -0,0 +1,58 @@
|
||||
sub init()
|
||||
m.top.backgroundColor = "#000b35ff"
|
||||
m.top.backgroundURI = ""
|
||||
|
||||
m.top.setFocus(true)
|
||||
end sub
|
||||
|
||||
function onKeyEvent(key as String, press as Boolean) as Boolean
|
||||
if not press then return false
|
||||
list = m.top.findNode("configOptions")
|
||||
button = m.top.findNode("submit")
|
||||
if key = "down" and button.focusedChild = invalid
|
||||
limit = list.content.getChildren(-1, 0).count() - 1
|
||||
|
||||
if limit = list.itemFocused
|
||||
m.top.setFocus(false)
|
||||
button.setFocus(true)
|
||||
return true
|
||||
end if
|
||||
else if key = "up" and button.focusedChild <> invalid
|
||||
list.setFocus(true)
|
||||
return true
|
||||
end if
|
||||
return false
|
||||
end function
|
||||
|
||||
function onDialogButton()
|
||||
d = m.top.dialog
|
||||
button_text = d.buttons[d.buttonSelected]
|
||||
|
||||
if button_text = "OK"
|
||||
m.focused_item.text = d.text
|
||||
dismiss_dialog()
|
||||
return true
|
||||
else if button_text = "Cancel"
|
||||
dismiss_dialog()
|
||||
return false
|
||||
end if
|
||||
end function
|
||||
|
||||
|
||||
sub show_dialog(title as String)
|
||||
dialog = createObject("roSGNode", "KeyboardDialog")
|
||||
dialog.title = "Enter the " + m.focused_item.id
|
||||
dialog.buttons = ["OK", "Cancel"]
|
||||
|
||||
if m.focused_item.text <> "" then
|
||||
dialog.text = m.focused_item.text
|
||||
end if
|
||||
|
||||
m.top.dialog = dialog
|
||||
|
||||
dialog.observeField("buttonSelected", "onDialogButton")
|
||||
end sub
|
||||
|
||||
sub dismiss_dialog()
|
||||
m.top.dialog.close = true
|
||||
end sub
|
23
components/config/scene.xml
Normal file
23
components/config/scene.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="ConfigScene" extends="Scene">
|
||||
<children>
|
||||
<label text="Enter Configuration"
|
||||
id="prompt"
|
||||
height="70"
|
||||
font="font:MediumBoldSystemFont"
|
||||
translation="[150, 150]" />
|
||||
<ConfigList
|
||||
id="configOptions"
|
||||
translation="[150, 250]"
|
||||
itemSize="[440, 40]"
|
||||
itemSpacing="[0, 20]"
|
||||
numRows="12" />
|
||||
<Button
|
||||
id="submit"
|
||||
text="Submit"
|
||||
showFocusFootprint="false"
|
||||
translation="[150, 350]"
|
||||
/>
|
||||
</children>
|
||||
<script type="text/brightscript" uri="pkg:/components/config/scene.brs"/>
|
||||
</component>
|
9
components/library/data.xml
Normal file
9
components/library/data.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="LibraryData" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="labelText" type="string" />
|
||||
<field id="libraryID" type="string" />
|
||||
<field id="libraryType" type="string" />
|
||||
<field id="data" type="associativearray" />
|
||||
</interface>
|
||||
</component>
|
36
components/library/item.xml
Normal file
36
components/library/item.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="LibItem" extends="Group">
|
||||
<children>
|
||||
<Label id="itemText" horizAlign="center" font="font:MediumSystemFont" height="75" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged"/>
|
||||
</interface>
|
||||
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub Init()
|
||||
m.itemText = m.top.findNode("itemText")
|
||||
m.itemText.text = "Loading..."
|
||||
|
||||
updateSize()
|
||||
end sub
|
||||
|
||||
sub updateSize()
|
||||
m.itemText = m.top.findNode("itemText")
|
||||
maxSize = m.top.getParent().itemSize
|
||||
m.itemText.width = maxSize[0]
|
||||
|
||||
m.itemText.translation = [0, (maxSize[1] / 2) - 15]
|
||||
end sub
|
||||
|
||||
function itemContentChanged() as void
|
||||
m.itemText = m.top.findNode("itemText")
|
||||
itemData = m.top.itemContent
|
||||
m.itemText.text = itemData.labelText
|
||||
updateSize()
|
||||
end function
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</component>
|
92
components/library/rowlist.xml
Normal file
92
components/library/rowlist.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="LibraryRow" extends="RowList">
|
||||
<interface>
|
||||
<field id="rowSize" type="int" />
|
||||
<field id="libList" type="associativearray" onChange="setData" />
|
||||
</interface>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub init()
|
||||
m.top.itemComponentName = "LibItem"
|
||||
m.top.content = getData()
|
||||
|
||||
m.top.rowFocusAnimationStyle = "floatingFocus"
|
||||
m.top.vertFocusAnimationStyle = "floatingFocus"
|
||||
|
||||
m.top.showRowLabel = [false]
|
||||
|
||||
updateSize()
|
||||
|
||||
m.top.setfocus(true)
|
||||
end sub
|
||||
|
||||
sub updateSize()
|
||||
m.top.numrows = 1
|
||||
m.top.rowSize = 5
|
||||
|
||||
dimensions = m.top.getScene().currentDesignResolution
|
||||
|
||||
border = 200
|
||||
m.top.translation = [border, border + 115]
|
||||
|
||||
itemWidth = (dimensions["width"] - border*2) / m.top.rowSize
|
||||
itemHeight = 75
|
||||
|
||||
m.top.visible = true
|
||||
|
||||
' size of the whole row
|
||||
m.top.itemSize = [dimensions["width"] - border*2, itemHeight]
|
||||
' spacing between rows
|
||||
m.top.itemSpacing = [ 0, 30 ]
|
||||
|
||||
' size of the item in the row
|
||||
m.top.rowItemSize = [ itemWidth, itemHeight ]
|
||||
' spacing between items in a row
|
||||
m.top.rowItemSpacing = [ 0, 0 ]
|
||||
end sub
|
||||
|
||||
function setData()
|
||||
libs = m.top.liblist
|
||||
rowsize = m.top.rowSize
|
||||
|
||||
n = libs.TotalRecordCount
|
||||
|
||||
' Test for no remainder
|
||||
if int(n/rowsize) = n/rowsize then
|
||||
m.top.numRows = n/rowsize
|
||||
else
|
||||
m.top.numRows = n/rowsize + 1
|
||||
end if
|
||||
|
||||
m.top.content = getData()
|
||||
end function
|
||||
|
||||
function getData()
|
||||
if m.top.libList = invalid then
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
return data
|
||||
end if
|
||||
|
||||
libs = m.top.libList
|
||||
rowsize = m.top.rowSize
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
for rownum=1 to m.top.numRows
|
||||
row = data.CreateChild("ContentNode")
|
||||
for i=1 to rowsize
|
||||
index = (rownum - 1) * rowsize + i
|
||||
if index > libs.TotalRecordCount then
|
||||
exit for
|
||||
end if
|
||||
datum = libs.Items[index-1]
|
||||
item = row.CreateChild("LibraryData")
|
||||
item.labelText = datum.name
|
||||
item.libraryID = datum.id
|
||||
item.libraryType = datum.CollectionType
|
||||
item.data = datum
|
||||
end for
|
||||
end for
|
||||
return data
|
||||
end function
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
9
components/library/scene.xml
Normal file
9
components/library/scene.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="Library" extends="Scene">
|
||||
<children>
|
||||
<LibraryRow id="LibrarySelect" />
|
||||
<Overhang id="overhang" title="My Media" />
|
||||
<Rectangle id="footerBackdrop" height="200" />
|
||||
<SearchBox id="search" />
|
||||
</children>
|
||||
</component>
|
31
components/movies/data.xml
Normal file
31
components/movies/data.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MovieData" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="title" type="string" />
|
||||
<field id="posterUrl" type="string" />
|
||||
<field id="movieID" type="string" />
|
||||
<field id="description" type="string" />
|
||||
<field id="favorite" type="boolean" />
|
||||
<field id="watched" type="boolean" />
|
||||
<field id="seasons" type="associativearray" />
|
||||
<field id="full_data" type="associativearray" onChange="setFields" />
|
||||
<function name="favorite_toggle" />
|
||||
</interface>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub setFields()
|
||||
datum = m.top.full_data
|
||||
m.top.title = datum.name
|
||||
m.top.movieID = datum.id
|
||||
if datum.posterURL <> invalid
|
||||
m.top.posterURL = datum.posterURL
|
||||
else
|
||||
m.top.posterURL = ""
|
||||
end if
|
||||
m.top.description = datum.overview
|
||||
m.top.favorite = datum.UserData.isFavorite
|
||||
m.top.watched = datum.UserData.played
|
||||
end sub
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
114
components/movies/details.brs
Normal file
114
components/movies/details.brs
Normal file
@ -0,0 +1,114 @@
|
||||
sub itemContentChanged()
|
||||
itemData = m.top.itemContent.full_data
|
||||
|
||||
m.top.findNode("moviePoster").uri = m.top.itemContent.posterURL
|
||||
|
||||
' Handle all "As Is" fields
|
||||
setFieldText("title", itemData.name)
|
||||
setFieldText("releaseYear", itemData.productionYear)
|
||||
setFieldText("officialRating", itemData.officialRating)
|
||||
setFieldText("communityRating", str(itemData.communityRating))
|
||||
setFieldText("overview", itemData.overview)
|
||||
|
||||
setFieldText("runtime", stri(getRuntime()) + " mins")
|
||||
setFieldText("ends-at", "Ends at " + getEndTime())
|
||||
|
||||
if itemData.genres.count() > 0
|
||||
setFieldText("genres", itemData.genres.join(", "))
|
||||
end if
|
||||
director = invalid
|
||||
for each person in itemData.people
|
||||
if person.type = "Director"
|
||||
director = person.name
|
||||
exit for
|
||||
end if
|
||||
end for
|
||||
if director <> invalid
|
||||
setFieldText("director", "Director: " + director)
|
||||
end if
|
||||
setFieldText("video_codec", "Video: " + itemData.mediaStreams[0].displayTitle)
|
||||
setFieldText("audio_codec", "Audio: " + itemData.mediaStreams[1].displayTitle)
|
||||
' TODO - cmon now. these are buttons, not words
|
||||
if itemData.taglines.count() > 0
|
||||
setFieldText("tagline", itemData.taglines[0])
|
||||
end if
|
||||
setFavoriteColor()
|
||||
setWatchedColor()
|
||||
end sub
|
||||
|
||||
sub setFieldText(field as string, value)
|
||||
node = m.top.findNode(field)
|
||||
if node = invalid then return
|
||||
|
||||
node.text = value
|
||||
end sub
|
||||
|
||||
function getRuntime() as Integer
|
||||
itemData = m.top.itemContent.full_data
|
||||
|
||||
' A tick is .1ms, so 1/10,000,000 for ticks to seconds,
|
||||
' then 1/60 for seconds to minutess... 1/600,000,000
|
||||
return round(itemData.RunTimeTicks / 600000000.0)
|
||||
end function
|
||||
|
||||
function getEndTime() as string
|
||||
itemData = m.top.itemContent.full_data
|
||||
|
||||
date = CreateObject("roDateTime")
|
||||
duration_s = int(itemData.RunTimeTicks / 10000000.0)
|
||||
date.fromSeconds(date.asSeconds() + duration_s)
|
||||
date.toLocalTime()
|
||||
hours = date.getHours()
|
||||
meridian = "AM"
|
||||
if hours = 0
|
||||
hours = 12
|
||||
meridian = "AM"
|
||||
else if hours = 12
|
||||
hours = 12
|
||||
meridian = "PM"
|
||||
else if hours > 12
|
||||
hours = hours - 12
|
||||
meridian = "PM"
|
||||
end if
|
||||
|
||||
return Substitute("{0}:{1} {2}", stri(hours).trim(), stri(date.getMinutes()).trim(), meridian)
|
||||
end function
|
||||
|
||||
sub setFavoriteColor()
|
||||
fave = m.top.itemContent.favorite
|
||||
fave_button = m.top.findNode("favorite-button")
|
||||
if fave
|
||||
fave_button.textColor = "#00ff00ff"
|
||||
fave_button.focusedTextColor = "#269926ff"
|
||||
else
|
||||
fave_button.textColor = "0xddddddff"
|
||||
fave_button.focusedTextColor = "#262626ff"
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub setWatchedColor()
|
||||
watched = m.top.itemContent.watched
|
||||
watched_button = m.top.findNode("watched-button")
|
||||
if watched
|
||||
watched_button.textColor = "#ff0000ff"
|
||||
watched_button.focusedTextColor = "#992626ff"
|
||||
else
|
||||
watched_button.textColor = "0xddddddff"
|
||||
watched_button.focusedTextColor = "#262626ff"
|
||||
end if
|
||||
end sub
|
||||
|
||||
function round(f as Float) as Integer
|
||||
' BrightScript only has a "floor" round
|
||||
' This compares floor to floor + 1 to find which is closer
|
||||
m = int(f)
|
||||
n = m + 1
|
||||
x = abs(f - m)
|
||||
y = abs(f - n)
|
||||
if y > x
|
||||
return m
|
||||
else
|
||||
return n
|
||||
end if
|
||||
end function
|
||||
|
48
components/movies/details.xml
Normal file
48
components/movies/details.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MovieItemDetailScene" extends="Scene">
|
||||
<children>
|
||||
<LayoutGroup id="main_group" layoutDirection="horiz" >
|
||||
<Poster id="moviePoster"
|
||||
translation="[150,150]"
|
||||
width="400" height="600" />
|
||||
<LayoutGroup layoutDirection="vert" translation="[355, 150]" itemSpacings="[25]">
|
||||
<Label id="title" font="font:LargeBoldSystemFont" />
|
||||
<LayoutGroup layoutDirection="horiz" itemSpacings="[150]">
|
||||
<Label id="releaseYear" />
|
||||
<Label id="runtime" />
|
||||
<Label id="officialRating" />
|
||||
<Label id="communityRating" />
|
||||
<Label id="ends-at" />
|
||||
</LayoutGroup>
|
||||
<Label id="genres" />
|
||||
<Label id="director" />
|
||||
<Label id="video_codec" />
|
||||
<Label id="audio_codec" />
|
||||
<ButtonGroupHoriz id="buttons" itemSpacings="[10]">
|
||||
<Button text="Play" id="play-button" />
|
||||
<Button text="Watched" id="watched-button" />
|
||||
<Button text="Favorite" id="favorite-button" />
|
||||
</ButtonGroupHoriz>
|
||||
<Label id="tagline" />
|
||||
<Label id="overview" />
|
||||
|
||||
</LayoutGroup>
|
||||
</LayoutGroup>
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="pkg:/components/movies/details.brs" />
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub init()
|
||||
main = m.top.findNode("main_group")
|
||||
dimensions = m.top.getScene().currentDesignResolution
|
||||
|
||||
main.translation=[50, 50]
|
||||
|
||||
m.top.findNode("buttons").setFocus(true)
|
||||
end sub
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
33
components/movies/minimal-details.xml
Normal file
33
components/movies/minimal-details.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MovieItemMinimal" extends="Group">
|
||||
<children>
|
||||
<Label id="title"
|
||||
horizAlign="center"
|
||||
translation="[0,319]"
|
||||
font="font:MediumSystemFont"
|
||||
width="196"
|
||||
height="65" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged"/>
|
||||
</interface>
|
||||
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub Init()
|
||||
m.title = m.top.findNode("title")
|
||||
m.title.text = "Loading..."
|
||||
end sub
|
||||
|
||||
function itemContentChanged() as void
|
||||
' re-declare this because init doesnt re-run
|
||||
' when we come back from elsewhere
|
||||
m.title = m.top.findNode("title")
|
||||
|
||||
itemData = m.top.itemContent
|
||||
m.title.text = itemData.title
|
||||
end function
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</component>
|
104
components/movies/rowlist.xml
Normal file
104
components/movies/rowlist.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MovieRow" extends="RowList">
|
||||
<interface>
|
||||
<field id="rowSize" type="int" />
|
||||
<field id="movieData" type="associativearray" onChange="setData" />
|
||||
<field id="library" type="associativearray" />
|
||||
</interface>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub init()
|
||||
m.top.itemComponentName = "ListPoster"
|
||||
m.top.content = getData()
|
||||
|
||||
m.top.rowFocusAnimationStyle = "floatingFocus"
|
||||
'm.top.vertFocusAnimationStyle = "floatingFocus"
|
||||
|
||||
m.top.showRowLabel = [false]
|
||||
|
||||
updateSize()
|
||||
|
||||
m.top.setfocus(true)
|
||||
end sub
|
||||
|
||||
sub updateSize()
|
||||
m.top.numrows = 1
|
||||
m.top.rowSize = 5
|
||||
|
||||
dimensions = m.top.getScene().currentDesignResolution
|
||||
|
||||
border = 75
|
||||
m.top.translation = [border, border + 115]
|
||||
|
||||
textHeight = 50
|
||||
' Do we decide width by rowSize, or rowSize by width...
|
||||
itemWidth = (dimensions["width"] - border*2) / m.top.rowSize
|
||||
itemHeight = itemWidth * 1.5 + textHeight
|
||||
|
||||
m.top.visible = true
|
||||
|
||||
' size of the whole row
|
||||
m.top.itemSize = [dimensions["width"] - border*2, itemHeight]
|
||||
' spacing between rows
|
||||
m.top.itemSpacing = [ 0, 10 ]
|
||||
|
||||
' size of the item in the row
|
||||
m.top.rowItemSize = [ itemWidth, itemHeight ]
|
||||
' spacing between items in a row
|
||||
m.top.rowItemSpacing = [ 0, 0 ]
|
||||
end sub
|
||||
|
||||
function setData()
|
||||
movieData = m.top.movieData
|
||||
rowsize = m.top.rowSize
|
||||
|
||||
n = movieData.items.count()
|
||||
|
||||
' Test for no remainder
|
||||
if int(n/rowsize) = n/rowsize then
|
||||
m.top.numRows = n/rowsize
|
||||
else
|
||||
m.top.numRows = n/rowsize + 1
|
||||
end if
|
||||
|
||||
m.top.content = getData()
|
||||
end function
|
||||
|
||||
function getData()
|
||||
if m.top.movieData = invalid then
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
return data
|
||||
end if
|
||||
|
||||
movieData = m.top.movieData
|
||||
rowsize = m.top.rowSize
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
for rownum=1 to m.top.numRows
|
||||
row = data.CreateChild("ContentNode")
|
||||
for i=1 to rowsize
|
||||
index = (rownum - 1) * rowsize + i
|
||||
if index > movieData.items.count() then
|
||||
exit for
|
||||
end if
|
||||
datum = movieData.Items[index-1]
|
||||
item = row.CreateChild("MovieData")
|
||||
item.full_data = datum
|
||||
end for
|
||||
end for
|
||||
return data
|
||||
end function
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
if key = "down" and (m.top.itemFocused + 1) = m.top.content.getChildCount()
|
||||
m.top.getScene().findNode("pager").setFocus(true)
|
||||
m.top.getScene().findNode("pager").getChild(0).setFocus(true)
|
||||
return true
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
15
components/movies/scene.xml
Normal file
15
components/movies/scene.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="Movies" extends="Scene">
|
||||
<children>
|
||||
<MovieRow
|
||||
id="MovieSelect"
|
||||
visible="true"
|
||||
/>
|
||||
<Overhang
|
||||
id="overhang"
|
||||
title="Movies"
|
||||
/>
|
||||
<Rectangle id="footerBackdrop" />
|
||||
<Pager id="pager" />
|
||||
</children>
|
||||
</component>
|
19
components/search.xml
Normal file
19
components/search.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="SearchBox" extends="LayoutGroup">
|
||||
<children>
|
||||
<Label text="Search" />
|
||||
<TextEditBox id="search-input" />
|
||||
</children>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub init()
|
||||
m.top.layoutDirection = "vert"
|
||||
dimensions = m.top.getScene().currentDesignResolution
|
||||
m.top.translation = [dimensions.width / 2, 880]
|
||||
m.top.horizAlignment = "center"
|
||||
m.top.vertAlignment = "top"
|
||||
end sub
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
26
components/tvshows/data-season.xml
Normal file
26
components/tvshows/data-season.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="TVSeasonData" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="title" type="string" />
|
||||
<field id="posterUrl" type="string" />
|
||||
<field id="showID" type="string" />
|
||||
<field id="description" type="string" />
|
||||
<field id="full_data" type="associativearray" onChange="setFields" />
|
||||
<function name="getPoster" />
|
||||
</interface>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub setFields()
|
||||
datum = m.top.full_data
|
||||
m.top.title = datum.name
|
||||
m.top.showID = datum.id
|
||||
if datum.posterURL <> invalid
|
||||
m.top.posterURL = datum.posterURL
|
||||
else
|
||||
m.top.posterURL = ""
|
||||
end if
|
||||
m.top.description = datum.overview
|
||||
end sub
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
30
components/tvshows/data-show.xml
Normal file
30
components/tvshows/data-show.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="TVShowData" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="title" type="string" />
|
||||
<field id="posterUrl" type="string" />
|
||||
<field id="showID" type="string" />
|
||||
<field id="description" type="string" />
|
||||
<field id="seasons" type="associativearray" />
|
||||
<field id="nextup" type="associativearray" />
|
||||
<field id="full_data" type="associativearray" onChange="setFields" />
|
||||
<function name="loadSeasons" />
|
||||
</interface>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub setFields()
|
||||
datum = m.top.full_data
|
||||
m.top.title = datum.name
|
||||
m.top.showID = datum.id
|
||||
if datum.posterURL <> invalid
|
||||
m.top.posterURL = datum.posterURL
|
||||
else
|
||||
m.top.posterURL = ""
|
||||
end if
|
||||
m.top.description = datum.overview
|
||||
'm.top.seasons = TVSeasons(datum.id)
|
||||
'm.top.nextup = TVNext(datum.id)
|
||||
end sub
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
121
components/tvshows/details.brs
Normal file
121
components/tvshows/details.brs
Normal file
@ -0,0 +1,121 @@
|
||||
sub itemContentChanged()
|
||||
itemData = m.top.itemContent.full_data
|
||||
|
||||
m.top.findNode("tvshowPoster").uri = m.top.itemContent.posterURL
|
||||
|
||||
' Handle all "As Is" fields
|
||||
setFieldText("title", itemData.name)
|
||||
setFieldText("releaseYear", itemData.productionYear)
|
||||
setFieldText("officialRating", itemData.officialRating)
|
||||
setFieldText("communityRating", str(itemData.communityRating))
|
||||
setFieldText("overview", itemData.overview)
|
||||
|
||||
setFieldText("runtime", stri(getRuntime()) + " mins")
|
||||
|
||||
setFieldText("history", getHistory())
|
||||
|
||||
if itemData.genres.count() > 0
|
||||
setFieldText("genres", itemData.genres.join(", "))
|
||||
end if
|
||||
director = invalid
|
||||
for each person in itemData.people
|
||||
if person.type = "Director"
|
||||
director = person.name
|
||||
exit for
|
||||
end if
|
||||
end for
|
||||
if itemData.taglines.count() > 0
|
||||
setFieldText("tagline", itemData.taglines[0])
|
||||
end if
|
||||
m.top.findNode("TVSeasonSelect").TVSeasonData = m.top.itemContent.seasons
|
||||
end sub
|
||||
|
||||
sub setFieldText(field as string, value)
|
||||
node = m.top.findNode(field)
|
||||
if node = invalid then return
|
||||
|
||||
node.text = value
|
||||
end sub
|
||||
|
||||
function getRuntime() as Integer
|
||||
itemData = m.top.itemContent.full_data
|
||||
|
||||
' A tick is .1ms, so 1/10,000,000 for ticks to seconds,
|
||||
' then 1/60 for seconds to minutess... 1/600,000,000
|
||||
return round(itemData.RunTimeTicks / 600000000.0)
|
||||
end function
|
||||
|
||||
function getEndTime() as string
|
||||
itemData = m.top.itemContent.full_data
|
||||
|
||||
date = CreateObject("roDateTime")
|
||||
duration_s = int(itemData.RunTimeTicks / 10000000.0)
|
||||
date.fromSeconds(date.asSeconds() + duration_s)
|
||||
date.toLocalTime()
|
||||
hours = date.getHours()
|
||||
meridian = "AM"
|
||||
if hours = 0
|
||||
hours = 12
|
||||
meridian = "AM"
|
||||
else if hours = 12
|
||||
hours = 12
|
||||
meridian = "PM"
|
||||
else if hours > 12
|
||||
hours = hours - 12
|
||||
meridian = "PM"
|
||||
end if
|
||||
|
||||
return Substitute("{0}:{1} {2}", stri(hours).trim(), stri(date.getMinutes()).trim(), meridian)
|
||||
end function
|
||||
|
||||
function getHistory() as string
|
||||
itemData = m.top.itemContent.full_data
|
||||
' Aired Fridays at 9:30 PM on ABC (US)
|
||||
|
||||
airwords = invalid
|
||||
studio = invalid
|
||||
if itemData.status = "Ended"
|
||||
verb = "Aired"
|
||||
else
|
||||
verb = "Airs"
|
||||
end if
|
||||
|
||||
airdays = itemData.airdays
|
||||
airtime = itemData.airtime
|
||||
if airtime <> invalid and airdays.count() = 1
|
||||
airwords = airdays[0] + " at " + airtime
|
||||
endif
|
||||
|
||||
if itemData.studios.count() > 0
|
||||
studio = itemData.studios[0].name
|
||||
end if
|
||||
|
||||
if studio = invalid and airwords = invalid
|
||||
return ""
|
||||
end if
|
||||
|
||||
words = verb
|
||||
if airwords <> invalid
|
||||
words = words + " " + airwords
|
||||
end if
|
||||
if studio <> invalid
|
||||
words = words + " on " + studio
|
||||
end if
|
||||
|
||||
return words
|
||||
end function
|
||||
|
||||
function round(f as Float) as Integer
|
||||
' BrightScript only has a "floor" round
|
||||
' This compares floor to floor + 1 to find which is closer
|
||||
m = int(f)
|
||||
n = m + 1
|
||||
x = abs(f - m)
|
||||
y = abs(f - n)
|
||||
if y > x
|
||||
return m
|
||||
else
|
||||
return n
|
||||
end if
|
||||
end function
|
||||
|
47
components/tvshows/details.xml
Normal file
47
components/tvshows/details.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="TVShowItemDetailScene" extends="Scene">
|
||||
<children>
|
||||
<LayoutGroup id="main_group" layoutDirection="horiz" >
|
||||
<Poster id="tvshowPoster"
|
||||
translation="[150,150]"
|
||||
width="400" height="600" />
|
||||
<LayoutGroup layoutDirection="vert" translation="[355, 150]" itemSpacings="[25]">
|
||||
<Label id="title" font="font:LargeBoldSystemFont" />
|
||||
<LayoutGroup layoutDirection="horiz" itemSpacings="[150]">
|
||||
<Label id="releaseYear" />
|
||||
<Label id="officialRating" />
|
||||
<Label id="communityRating" />
|
||||
</LayoutGroup>
|
||||
<Label id="genres" />
|
||||
<ButtonGroupHoriz id="buttons" itemSpacings="[10]">
|
||||
<Button text="Play" id="play-button" />
|
||||
<Button text="Shuffle" id="shuffle-button" />
|
||||
<Button text="Watched" id="watched-button" />
|
||||
<Button text="Favorite" id="favorite-button" />
|
||||
</ButtonGroupHoriz>
|
||||
<Label id="tagline" />
|
||||
<Label id="overview" />
|
||||
<Label id="history" />
|
||||
|
||||
</LayoutGroup>
|
||||
</LayoutGroup>
|
||||
<!-- Next Up -->
|
||||
<TVSeasonRow id="TVSeasonSelect" visible="true" translation="[150, 800]" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="pkg:/components/tvshows/details.brs" />
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub init()
|
||||
main = m.top.findNode("main_group")
|
||||
dimensions = m.top.getScene().currentDesignResolution
|
||||
|
||||
main.translation=[50, 50]
|
||||
|
||||
m.top.findNode("buttons").setFocus(true)
|
||||
end sub
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
92
components/tvshows/rowlist-season.xml
Normal file
92
components/tvshows/rowlist-season.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="TVSeasonRow" extends="RowList">
|
||||
<interface>
|
||||
<field id="rowSize" type="int" />
|
||||
<field id="TVSeasonData" type="associativearray" onChange="setData" />
|
||||
</interface>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
' TODO - make this not a "row" list
|
||||
sub init()
|
||||
m.top.itemComponentName = "ListPoster"
|
||||
m.top.content = getData()
|
||||
|
||||
'm.top.rowFocusAnimationStyle = "floatingFocus"
|
||||
'm.top.vertFocusAnimationStyle = "floatingFocus"
|
||||
|
||||
m.top.showRowLabel = [false]
|
||||
|
||||
updateSize()
|
||||
|
||||
m.top.setfocus(true)
|
||||
end sub
|
||||
|
||||
sub updateSize()
|
||||
m.top.numrows = 1
|
||||
m.top.rowSize = 5
|
||||
|
||||
dimensions = m.top.getScene().currentDesignResolution
|
||||
|
||||
border = 75
|
||||
m.top.translation = [border, border]
|
||||
|
||||
textHeight = 50
|
||||
' Do we decide width by rowSize, or rowSize by width...
|
||||
itemWidth = (dimensions["width"] - border*2) / m.top.rowSize
|
||||
itemHeight = itemWidth * 1.5 + textHeight
|
||||
|
||||
m.top.visible = true
|
||||
|
||||
' size of the whole row
|
||||
m.top.itemSize = [dimensions["width"] - border*2, itemHeight]
|
||||
' spacing between rows
|
||||
m.top.itemSpacing = [ 0, 10 ]
|
||||
|
||||
' size of the item in the row
|
||||
m.top.rowItemSize = [ itemWidth, itemHeight ]
|
||||
' spacing between items in a row
|
||||
m.top.rowItemSpacing = [ 0, 0 ]
|
||||
end sub
|
||||
|
||||
function setData()
|
||||
seasonData = m.top.TVSeasonData
|
||||
rowsize = m.top.rowSize
|
||||
|
||||
n = seasonData.items.count()
|
||||
|
||||
' Test for no remainder
|
||||
if int(n/rowsize) = n/rowsize then
|
||||
m.top.numRows = n/rowsize
|
||||
else
|
||||
m.top.numRows = n/rowsize + 1
|
||||
end if
|
||||
|
||||
m.top.content = getData()
|
||||
end function
|
||||
|
||||
function getData()
|
||||
if m.top.TVSeasonData = invalid then
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
return data
|
||||
end if
|
||||
|
||||
seasonData = m.top.TVSeasonData
|
||||
rowsize = m.top.rowSize
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
for rownum=1 to m.top.numRows
|
||||
row = data.CreateChild("ContentNode")
|
||||
for i=1 to rowsize
|
||||
index = (rownum - 1) * rowsize + i
|
||||
if index > seasonData.items.count() then
|
||||
exit for
|
||||
end if
|
||||
datum = seasonData.Items[index-1]
|
||||
item = row.CreateChild("TVSeasonData")
|
||||
item.full_data = datum
|
||||
end for
|
||||
end for
|
||||
return data
|
||||
end function
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
104
components/tvshows/rowlist-show.xml
Normal file
104
components/tvshows/rowlist-show.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="TVShowRow" extends="RowList">
|
||||
<interface>
|
||||
<field id="rowSize" type="int" />
|
||||
<field id="TVShowData" type="associativearray" onChange="setData" />
|
||||
</interface>
|
||||
<script type="text/brightscript">
|
||||
<![CDATA[
|
||||
sub init()
|
||||
m.top.itemComponentName = "ListPoster"
|
||||
m.top.content = getData()
|
||||
|
||||
|
||||
m.top.rowFocusAnimationStyle = "floatingFocus"
|
||||
'm.top.vertFocusAnimationStyle = "floatingFocus"
|
||||
|
||||
m.top.showRowLabel = [false]
|
||||
|
||||
updateSize()
|
||||
|
||||
m.top.setfocus(true)
|
||||
end sub
|
||||
|
||||
sub updateSize()
|
||||
m.top.numrows = 1
|
||||
m.top.rowSize = 5
|
||||
|
||||
dimensions = m.top.getScene().currentDesignResolution
|
||||
|
||||
border = 75
|
||||
m.top.translation = [border, border + 115]
|
||||
|
||||
textHeight = 50
|
||||
' Do we decide width by rowSize, or rowSize by width...
|
||||
itemWidth = (dimensions["width"] - border*2) / m.top.rowSize
|
||||
itemHeight = itemWidth * 1.5 + textHeight
|
||||
|
||||
m.top.visible = true
|
||||
|
||||
' size of the whole row
|
||||
m.top.itemSize = [dimensions["width"] - border*2, itemHeight]
|
||||
' spacing between rows
|
||||
m.top.itemSpacing = [ 0, 10 ]
|
||||
|
||||
' size of the item in the row
|
||||
m.top.rowItemSize = [ itemWidth, itemHeight ]
|
||||
' spacing between items in a row
|
||||
m.top.rowItemSpacing = [ 0, 0 ]
|
||||
end sub
|
||||
|
||||
function setData()
|
||||
tvshowData = m.top.TVShowData
|
||||
rowsize = m.top.rowSize
|
||||
|
||||
n = tvshowData.items.count()
|
||||
|
||||
' Test for no remainder
|
||||
if int(n/rowsize) = n/rowsize then
|
||||
m.top.numRows = n/rowsize
|
||||
else
|
||||
m.top.numRows = n/rowsize + 1
|
||||
end if
|
||||
|
||||
m.top.content = getData()
|
||||
end function
|
||||
|
||||
function getData()
|
||||
if m.top.TVShowData = invalid then
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
return data
|
||||
end if
|
||||
|
||||
TVShowData = m.top.TVShowData
|
||||
rowsize = m.top.rowSize
|
||||
data = CreateObject("roSGNode", "ContentNode")
|
||||
for rownum=1 to m.top.numRows
|
||||
row = data.CreateChild("ContentNode")
|
||||
for i=1 to rowsize
|
||||
index = (rownum - 1) * rowsize + i
|
||||
if index > tvshowData.items.count() then
|
||||
exit for
|
||||
end if
|
||||
datum = tvshowData.Items[index-1]
|
||||
item = row.CreateChild("TVShowData")
|
||||
item.full_data = datum
|
||||
end for
|
||||
end for
|
||||
return data
|
||||
end function
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
if key = "down" and (m.top.itemFocused + 1) = m.top.content.getChildCount()
|
||||
m.top.getScene().findNode("pager").setFocus(true)
|
||||
m.top.getScene().findNode("pager").getChild(0).setFocus(true)
|
||||
return true
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
||||
]]>
|
||||
</script>
|
||||
</component>
|
15
components/tvshows/scene.xml
Normal file
15
components/tvshows/scene.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="TVShows" extends="Scene">
|
||||
<children>
|
||||
<TVShowRow
|
||||
id="TVShowSelect"
|
||||
visible="true"
|
||||
/>
|
||||
<Overhang
|
||||
id="overhang"
|
||||
title="TV Shows"
|
||||
/>
|
||||
<Rectangle id="footerBackdrop" />
|
||||
<Pager id="pager" />
|
||||
</children>
|
||||
</component>
|
Loading…
Reference in New Issue
Block a user