Improved interface for TV episodes
This commit is contained in:
parent
76fc41c23b
commit
fb757570c3
54
components/tvshows/details-list.brs
Normal file
54
components/tvshows/details-list.brs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
sub init()
|
||||||
|
m.title = m.top.findNode("title")
|
||||||
|
m.title.text = "Loading..."
|
||||||
|
end sub
|
||||||
|
|
||||||
|
function itemContentChanged() as void
|
||||||
|
item = m.top.itemContent
|
||||||
|
itemData = item.json
|
||||||
|
m.top.findNode("title").text = item.title
|
||||||
|
m.top.findNode("poster").uri = item.posterURL
|
||||||
|
m.top.findNode("overview").text = item.overview
|
||||||
|
|
||||||
|
if type(itemData.RunTimeTicks) = "LongInteger"
|
||||||
|
m.top.findNode("runtime").text = stri(getRuntime()) + " mins"
|
||||||
|
m.top.findNode("endtime").text = "Ends at " + getEndTime()
|
||||||
|
end if
|
||||||
|
if itemData.communityRating <> invalid then
|
||||||
|
m.top.findNode("communityRating").text = str(int(itemData.communityRating*10)/10)
|
||||||
|
end if
|
||||||
|
end function
|
||||||
|
|
||||||
|
function getRuntime() as integer
|
||||||
|
itemData = m.top.itemContent.json
|
||||||
|
|
||||||
|
' 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 int(itemData.RunTimeTicks / 600000000.0)
|
||||||
|
end function
|
||||||
|
|
||||||
|
function getEndTime() as string
|
||||||
|
itemData = m.top.itemContent.json
|
||||||
|
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
|
||||||
|
minutes = stri(date.getMinutes()).trim()
|
||||||
|
if val(minutes) > 10
|
||||||
|
minutes= "0" + minutes
|
||||||
|
end if
|
||||||
|
|
||||||
|
return Substitute("{0}:{1} {2}", stri(hours).trim(), stri(date.getMinutes()).trim(), meridian)
|
||||||
|
end function
|
25
components/tvshows/details-list.xml
Normal file
25
components/tvshows/details-list.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<component name="TVListDetails" extends="Group">
|
||||||
|
<children>
|
||||||
|
<LayoutGroup id="toplevel" layoutDirection="vert" itemSpacings="[40]">
|
||||||
|
<LayoutGroup id="main_group" layoutDirection="horiz" itemSpacings="[30]">
|
||||||
|
<Poster id="poster" width="534" height="300" />
|
||||||
|
<LayoutGroup id="text" layoutDirection="vert" itemSpacings="[15]">
|
||||||
|
<!-- Using poster of 1 length to get spacing. Not successful with adding translation to title -->
|
||||||
|
<Poster id="null" height="1" />
|
||||||
|
<ScrollingLabel id="title" font="font:LargeBoldSystemFont" maxWidth="1200" />
|
||||||
|
<LayoutGroup layoutDirection="horiz" itemSpacings="[20]">
|
||||||
|
<Label id="runtime" font="font:SmallestSystemFont" />
|
||||||
|
<Label id="communityRating" font="font:SmallestSystemFont" />
|
||||||
|
<Label id="endtime" font="font:SmallestSystemFont" />
|
||||||
|
</LayoutGroup>
|
||||||
|
<Label id="overview" wrap="true" height="170" width="1200" maxLines="4" ellipsizeOnBoundary="true"/>
|
||||||
|
</LayoutGroup>
|
||||||
|
</LayoutGroup>
|
||||||
|
</LayoutGroup>
|
||||||
|
</children>
|
||||||
|
<interface>
|
||||||
|
<field id="itemContent" type="node" onChange="itemContentChanged"/>
|
||||||
|
</interface>
|
||||||
|
<script type="text/brightscript" uri="details-list.brs" />
|
||||||
|
</component>
|
|
@ -1,7 +0,0 @@
|
||||||
sub init()
|
|
||||||
m.top.overhangTitle = "Season"
|
|
||||||
end sub
|
|
||||||
|
|
||||||
sub setSeason()
|
|
||||||
m.top.overhangTitle = m.top.seasonData.name
|
|
||||||
end sub
|
|
7
components/tvshows/episodes.brs
Normal file
7
components/tvshows/episodes.brs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
sub init()
|
||||||
|
m.top.overhangTitle = "Season"
|
||||||
|
end sub
|
||||||
|
|
||||||
|
sub setSeason()
|
||||||
|
m.top.overhangTitle = m.top.seasonData.SeriesName + " - " + m.top.seasonData.name
|
||||||
|
end sub
|
|
@ -1,12 +1,12 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<component name="TVEpisodes" extends="JFGroup">
|
<component name="TVEpisodes" extends="JFGroup">
|
||||||
<children>
|
<children>
|
||||||
<ItemGrid id="picker" visible="true" itemsPerRow="10" />
|
<TVEpisodeRow id="picker" visible="true" />
|
||||||
</children>
|
</children>
|
||||||
<interface>
|
<interface>
|
||||||
<field id="episodeSelected" alias="picker.itemSelected" />
|
<field id="episodeSelected" alias="picker.itemSelected" />
|
||||||
<field id="seasonData" type="node" onChange="setSeason" />
|
<field id="seasonData" type="associativearray" onChange="setSeason" />
|
||||||
<field id="objects" alias="picker.objects" />
|
<field id="objects" alias="picker.objects" />
|
||||||
</interface>
|
</interface>
|
||||||
<script type="text/brightscript" uri="episode.brs" />
|
<script type="text/brightscript" uri="episodes.brs" />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -1,67 +1,66 @@
|
||||||
sub init()
|
sub init()
|
||||||
m.top.itemComponentName = "ListPoster"
|
m.top.itemComponentName = "TVListDetails"
|
||||||
|
m.top.content = setData()
|
||||||
|
|
||||||
m.top.rowFocusAnimationStyle = "floatingFocus"
|
m.top.rowFocusAnimationStyle = "floatingFocus"
|
||||||
|
|
||||||
updateSize()
|
m.top.showRowLabel = [false]
|
||||||
|
|
||||||
m.top.setFocus(true)
|
updateSize()
|
||||||
|
|
||||||
|
m.top.setFocus(true)
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub updateSize()
|
sub updateSize()
|
||||||
m.top.numRows = 1
|
m.top.numRows = 1
|
||||||
m.top.rowSize = 3
|
m.top.itemsPerRow = 1
|
||||||
|
|
||||||
dimensions = m.top.getScene().currentDesignResolution
|
dimensions = m.top.getScene().currentDesignResolution
|
||||||
|
|
||||||
border = 75
|
border = 75
|
||||||
m.top.translation = [border, border + 115]
|
m.top.translation = [border, border + 115]
|
||||||
|
|
||||||
textHeight = 80
|
textHeight = 80
|
||||||
itemWidth = (dimensions["width"] - border*2) / m.top.rowSize
|
itemWidth = (dimensions["width"] - border*2)
|
||||||
itemHeight = itemWidth * dimensions["height"]/ dimensions["width"] + textHeight
|
itemHeight = 300
|
||||||
|
|
||||||
m.top.visible = true
|
m.top.visible = true
|
||||||
|
|
||||||
m.top.itemSize = [dimensions["width"] - border*2, itemHeight]
|
' Size of the individual rows
|
||||||
m.top.itemSpacing = [ 0, 10 ]
|
m.top.itemSize = [dimensions["width"] - border*2, itemHeight]
|
||||||
|
' Spacing between Rows
|
||||||
|
m.top.itemSpacing = [ 0, 40]
|
||||||
|
|
||||||
m.top.rowItemSize = [ itemWidth, itemHeight ]
|
' Size of items in the row
|
||||||
m.top.rowItemSpacing = [ 0, 0 ]
|
m.top.rowItemSize = [ itemWidth, itemHeight ]
|
||||||
|
' Spacing between items in the row
|
||||||
|
m.top.rowItemSpacing = [ 20, 0 ]
|
||||||
episodeData = m.top.TVEpisodeData
|
|
||||||
|
|
||||||
if episodeData = invalid then return
|
|
||||||
|
|
||||||
rowsize = m.top.rowSize
|
|
||||||
|
|
||||||
n = episodeData.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
|
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
function getData()
|
function setupRows()
|
||||||
if m.top.TVEpisodeData = invalid then
|
updateSize()
|
||||||
data = CreateObject("roSGNode", "ContentNode")
|
objects = m.top.objects
|
||||||
return data
|
m.top.numRows = objects.items.count()
|
||||||
end if
|
m.top.content = setData()
|
||||||
|
end function
|
||||||
updateSize()
|
|
||||||
|
function setData()
|
||||||
episodeData = m.top.TVEpisodeData
|
data = CreateObject("roSGNode", "ContentNode")
|
||||||
rowsize = m.top.rowSize
|
if m.top.objects = invalid then
|
||||||
data = CreateObject("roSGNode", "ContentNode")
|
' Return an empty node just to return something; we'll update once we have data
|
||||||
row = data.CreateChild("ContentNode")
|
return data
|
||||||
row.title = "Episodes"
|
end if
|
||||||
for each item in episodeData.items
|
|
||||||
row.appendChild(item)
|
for each item in m.top.objects.items
|
||||||
end for
|
row = data.CreateChild("ContentNode")
|
||||||
m.top.content = data
|
row.appendChild(item)
|
||||||
return data
|
end for
|
||||||
|
|
||||||
|
return data
|
||||||
|
end function
|
||||||
|
|
||||||
|
function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
|
if not press then return false
|
||||||
|
|
||||||
|
return false
|
||||||
end function
|
end function
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<component name="TVEpisodeRow" extends="RowList">
|
<component name="TVEpisodeRow" extends="RowList">
|
||||||
<interface>
|
<interface>
|
||||||
<field id="rowSize" type="int" />
|
<field id="itemsPerRow" type="int" />
|
||||||
<field id="TVEpisodeData" type="associativearray" onChange="getData" />
|
<field id="objects" type="associativearray" onChange="setupRows" />
|
||||||
|
<field id="escapeButton" type="string" alwaysNotify="true" />
|
||||||
</interface>
|
</interface>
|
||||||
<script type="text/brightscript" uri="rowlist-episode.brs" />
|
<script type="text/brightscript" uri="rowlist-episode.brs" />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -198,7 +198,6 @@ end function
|
||||||
function CreateMovieDetailsGroup(movie)
|
function CreateMovieDetailsGroup(movie)
|
||||||
group = CreateObject("roSGNode", "MovieDetails")
|
group = CreateObject("roSGNode", "MovieDetails")
|
||||||
|
|
||||||
|
|
||||||
movie = ItemMetaData(movie.id)
|
movie = ItemMetaData(movie.id)
|
||||||
group.itemContent = movie
|
group.itemContent = movie
|
||||||
|
|
||||||
|
@ -243,7 +242,7 @@ end function
|
||||||
function CreateSeasonDetailsGroup(series, season)
|
function CreateSeasonDetailsGroup(series, season)
|
||||||
group = CreateObject("roSGNode", "TVEpisodes")
|
group = CreateObject("roSGNode", "TVEpisodes")
|
||||||
|
|
||||||
group.seasonData = TVSeasons(series.id)
|
group.seasonData = ItemMetaData(season.id)
|
||||||
group.objects = TVEpisodes(series.id, season.id)
|
group.objects = TVEpisodes(series.id, season.id)
|
||||||
|
|
||||||
group.observeField("episodeSelected", m.port)
|
group.observeField("episodeSelected", m.port)
|
||||||
|
|
|
@ -131,7 +131,7 @@ function ItemList(library_id = invalid as string, params = {})
|
||||||
tmp.json = item
|
tmp.json = item
|
||||||
results.push(tmp)
|
results.push(tmp)
|
||||||
else
|
else
|
||||||
print item.type
|
print "Items.brs::ItemList received unhandled type: " item.type
|
||||||
' Otherwise we just stick with the JSON
|
' Otherwise we just stick with the JSON
|
||||||
results.push(item)
|
results.push(item)
|
||||||
end if
|
end if
|
||||||
|
@ -165,8 +165,13 @@ function ItemMetaData(id as string)
|
||||||
tmp.image = PosterImage(data.id)
|
tmp.image = PosterImage(data.id)
|
||||||
tmp.json = item
|
tmp.json = item
|
||||||
return tmp
|
return tmp
|
||||||
|
else if data.type = "Season"
|
||||||
|
tmp = CreateObject("roSGNode", "TVSeasonData")
|
||||||
|
tmp.image = PosterImage(data.id)
|
||||||
|
tmp.json = data
|
||||||
|
return tmp
|
||||||
else
|
else
|
||||||
print data.type
|
print "Items.brs::ItemMetaData processed unhandled type: " data.type
|
||||||
' Return json if we don't know what it is
|
' Return json if we don't know what it is
|
||||||
return data
|
return data
|
||||||
end if
|
end if
|
||||||
|
@ -202,13 +207,14 @@ function TVEpisodes(show_id as string, season_id as string)
|
||||||
data = getJson(resp)
|
data = getJson(resp)
|
||||||
results = []
|
results = []
|
||||||
for each item in data.Items
|
for each item in data.Items
|
||||||
imgParams = { "AddPlayedIndicator": item.UserData.Played }
|
imgParams = { "AddPlayedIndicator": item.UserData.Played, "maxWidth": 712, "maxheight": 400 }
|
||||||
tmp = CreateObject("roSGNode", "TVEpisodeData")
|
tmp = CreateObject("roSGNode", "TVEpisodeData")
|
||||||
tmp.image = PosterImage(item.id, imgParams)
|
tmp.image = PosterImage(item.id, imgParams)
|
||||||
if tmp.image <> invalid
|
if tmp.image <> invalid
|
||||||
tmp.image.posterDisplayMode = "scaleToFit"
|
tmp.image.posterDisplayMode = "scaleToFit"
|
||||||
end if
|
end if
|
||||||
tmp.json = item
|
tmp.json = item
|
||||||
|
tmp.overview = ItemMetaData(item.id).overview
|
||||||
results.push(tmp)
|
results.push(tmp)
|
||||||
end for
|
end for
|
||||||
data.Items = results
|
data.Items = results
|
||||||
|
|
Loading…
Reference in New Issue
Block a user