Add "Continue Watching" row on home screen
This commit is contained in:
parent
855ad0b8a2
commit
513f9b9618
|
@ -5,5 +5,9 @@ sub setData()
|
||||||
|
|
||||||
m.top.id = datum.id
|
m.top.id = datum.id
|
||||||
m.top.name = datum.name
|
m.top.name = datum.name
|
||||||
|
if datum.CollectionType = invalid then
|
||||||
|
m.top.type = datum.type
|
||||||
|
else
|
||||||
m.top.type = datum.CollectionType
|
m.top.type = datum.CollectionType
|
||||||
|
end if
|
||||||
end sub
|
end sub
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<component name="LibraryData" extends="ContentNode">
|
<component name="HomeData" extends="ContentNode">
|
||||||
<interface>
|
<interface>
|
||||||
<field id="id" type="string" />
|
<field id="id" type="string" />
|
||||||
<field id="name" type="string" />
|
<field id="name" type="string" />
|
||||||
|
@ -7,5 +7,5 @@
|
||||||
<field id="type" type="string" />
|
<field id="type" type="string" />
|
||||||
<field id="json" type="associativearray" onChange="setData" />
|
<field id="json" type="associativearray" onChange="setData" />
|
||||||
</interface>
|
</interface>
|
||||||
<script type="text/brightscript" uri="library.brs" />
|
<script type="text/brightscript" uri="HomeData.brs" />
|
||||||
</component>
|
</component>
|
4
components/home/Home.brs
Normal file
4
components/home/Home.brs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
sub init()
|
||||||
|
m.tracker=m.top.createChild("TrackerTask")
|
||||||
|
m.top.overhangTitle = "Home"
|
||||||
|
end sub
|
13
components/home/Home.xml
Normal file
13
components/home/Home.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<component name="Home" extends="JFGroup">
|
||||||
|
<children>
|
||||||
|
<HomeRows id="homeRows" />
|
||||||
|
<OptionsSlider id="options" />
|
||||||
|
</children>
|
||||||
|
<interface>
|
||||||
|
<field id="libraries" alias="homeRows.libList" />
|
||||||
|
<field id="continueWatching" alias="homeRows.continueList" />
|
||||||
|
<field id="homeSelection" alias="homeRows.itemSelected" />
|
||||||
|
</interface>
|
||||||
|
<script type="text/brightscript" uri="Home.brs" />
|
||||||
|
</component>
|
|
@ -1,6 +1,5 @@
|
||||||
sub init()
|
sub init()
|
||||||
itemText = m.top.findNode("itemText")
|
|
||||||
itemText.text = "Loading..."
|
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
function itemContentChanged() as void
|
function itemContentChanged() as void
|
||||||
|
@ -9,6 +8,7 @@ function itemContentChanged() as void
|
||||||
|
|
||||||
itemText = m.top.findNode("itemText")
|
itemText = m.top.findNode("itemText")
|
||||||
itemText.text = itemData.name
|
itemText.text = itemData.name
|
||||||
|
|
||||||
itemPoster = m.top.findNode("itemPoster")
|
itemPoster = m.top.findNode("itemPoster")
|
||||||
if itemData.type = "livetv" then
|
if itemData.type = "livetv" then
|
||||||
itemPoster.width = "96"
|
itemPoster.width = "96"
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<component name="LibItem" extends="Group">
|
<component name="HomeItem" extends="Group">
|
||||||
<children>
|
<children>
|
||||||
<Poster id="itemPoster" width="464" height="261" translation="[8,5]" />
|
<Poster id="itemPoster" width="464" height="261" translation="[8,5]" />
|
||||||
<Label id="itemText" horizAlign="center" vertAlign="center" font="font:MediumSystemFont" height="64" width="480" translation="[0,266]" />
|
<Label id="itemText" horizAlign="center" vertAlign="center" font="font:MediumSystemFont" height="64" width="480" translation="[0,266]" />
|
||||||
|
@ -7,5 +7,5 @@
|
||||||
<interface>
|
<interface>
|
||||||
<field id="itemContent" type="node" onChange="itemContentChanged"/>
|
<field id="itemContent" type="node" onChange="itemContentChanged"/>
|
||||||
</interface>
|
</interface>
|
||||||
<script type="text/brightscript" uri="item.brs" />
|
<script type="text/brightscript" uri="HomeItem.brs" />
|
||||||
</component>
|
</component>
|
73
components/home/HomeRows.brs
Normal file
73
components/home/HomeRows.brs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
sub init()
|
||||||
|
m.top.itemComponentName = "HomeItem"
|
||||||
|
' My media row should always exist
|
||||||
|
m.top.numRows = 1
|
||||||
|
m.top.content = CreateObject("roSGNode", "ContentNode")
|
||||||
|
|
||||||
|
m.top.rowFocusAnimationStyle = "fixedFocusWrap"
|
||||||
|
m.top.vertFocusAnimationStyle = "floatingFocus"
|
||||||
|
|
||||||
|
m.top.showRowLabel = [true]
|
||||||
|
m.top.rowLabelOffset = [0, 20]
|
||||||
|
m.top.showRowCounter = [true]
|
||||||
|
|
||||||
|
updateSize()
|
||||||
|
|
||||||
|
m.top.setfocus(true)
|
||||||
|
end sub
|
||||||
|
|
||||||
|
sub updateSize()
|
||||||
|
sideborder = 100
|
||||||
|
m.top.translation = [111, 155]
|
||||||
|
|
||||||
|
itemWidth = 480
|
||||||
|
itemHeight = 330
|
||||||
|
|
||||||
|
m.top.itemSize = [1920 - 111 - 27, itemHeight]
|
||||||
|
' spacing between rows
|
||||||
|
m.top.itemSpacing = [0, 105]
|
||||||
|
|
||||||
|
' size of the item in the row
|
||||||
|
m.top.rowItemSize = [itemWidth, itemHeight]
|
||||||
|
' spacing between items in a row
|
||||||
|
m.top.rowItemSpacing = [20, 0]
|
||||||
|
|
||||||
|
m.top.visible = true
|
||||||
|
end sub
|
||||||
|
|
||||||
|
sub showLibraryRow()
|
||||||
|
libs = m.top.libList
|
||||||
|
|
||||||
|
libraryRow = CreateObject("roSGNode", "ContentNode")
|
||||||
|
libraryRow.title = "My Media"
|
||||||
|
|
||||||
|
for i = 1 to libs.TotalRecordCount
|
||||||
|
item = libs.Items[i - 1]
|
||||||
|
libraryRow.appendChild(item)
|
||||||
|
end for
|
||||||
|
|
||||||
|
m.top.content.appendChild(libraryRow)
|
||||||
|
end sub
|
||||||
|
|
||||||
|
sub showContinueRow()
|
||||||
|
continueItems = m.top.continueList
|
||||||
|
|
||||||
|
if continueItems.TotalRecordCount > 0 then
|
||||||
|
continueRow = CreateObject("roSGNode", "ContentNode")
|
||||||
|
continueRow.title = "Continue Watching"
|
||||||
|
|
||||||
|
for i = 1 to continueItems.TotalRecordCount
|
||||||
|
item = continueItems.Items[i - 1]
|
||||||
|
continueRow.appendChild(item)
|
||||||
|
end for
|
||||||
|
|
||||||
|
m.top.numRows++
|
||||||
|
m.top.content.appendChild(continueRow)
|
||||||
|
end if
|
||||||
|
end sub
|
||||||
|
|
||||||
|
function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
|
if not press then return false
|
||||||
|
|
||||||
|
return false
|
||||||
|
end function
|
8
components/home/HomeRows.xml
Normal file
8
components/home/HomeRows.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<component name="HomeRows" extends="RowList">
|
||||||
|
<interface>
|
||||||
|
<field id="libList" type="associativearray" onChange="showLibraryRow" />
|
||||||
|
<field id="continueList" type="associativearray" onChange="showContinueRow" />
|
||||||
|
</interface>
|
||||||
|
<script type="text/brightscript" uri="HomeRows.brs"/>
|
||||||
|
</component>
|
|
@ -1,64 +0,0 @@
|
||||||
sub init()
|
|
||||||
m.top.itemComponentName = "LibItem"
|
|
||||||
m.top.content = getData()
|
|
||||||
|
|
||||||
m.top.rowFocusAnimationStyle = "fixedFocusWrap"
|
|
||||||
m.top.vertFocusAnimationStyle = "fixedFocusWrap"
|
|
||||||
|
|
||||||
m.top.showRowLabel = [true]
|
|
||||||
m.top.rowLabelOffset = [0, 20]
|
|
||||||
m.top.showRowCounter = [true]
|
|
||||||
|
|
||||||
updateSize()
|
|
||||||
|
|
||||||
m.top.setfocus(true)
|
|
||||||
end sub
|
|
||||||
|
|
||||||
sub updateSize()
|
|
||||||
' real border is border - rowlist title and rowlist padding
|
|
||||||
topborder = 40
|
|
||||||
sideborder = 119
|
|
||||||
' 115 is the overhang height
|
|
||||||
m.top.translation = [sideborder, topborder + 115]
|
|
||||||
|
|
||||||
itemWidth = 480
|
|
||||||
itemHeight = 330
|
|
||||||
|
|
||||||
m.top.visible = true
|
|
||||||
|
|
||||||
' size of the whole row
|
|
||||||
m.top.itemSize = [1920 - sideborder * 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 = [20, 0]
|
|
||||||
end sub
|
|
||||||
|
|
||||||
function getData()
|
|
||||||
if m.top.libList = invalid then
|
|
||||||
data = CreateObject("roSGNode", "ContentNode")
|
|
||||||
m.top.content = data
|
|
||||||
return data
|
|
||||||
end if
|
|
||||||
|
|
||||||
libs = m.top.libList
|
|
||||||
data = CreateObject("roSGNode", "ContentNode")
|
|
||||||
|
|
||||||
row = data.CreateChild("ContentNode")
|
|
||||||
row.title = "My Media"
|
|
||||||
for i = 1 to libs.TotalRecordCount
|
|
||||||
item = libs.Items[i - 1]
|
|
||||||
row.appendChild(item)
|
|
||||||
end for
|
|
||||||
m.top.content = data
|
|
||||||
return data
|
|
||||||
end function
|
|
||||||
|
|
||||||
function onKeyEvent(key as string, press as boolean) as boolean
|
|
||||||
if not press then return false
|
|
||||||
|
|
||||||
return false
|
|
||||||
end function
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<component name="LibraryRow" extends="RowList">
|
|
||||||
<interface>
|
|
||||||
<field id="libList" type="associativearray" onChange="getData" />
|
|
||||||
</interface>
|
|
||||||
<script type="text/brightscript" uri="rowlist.brs"/>
|
|
||||||
</component>
|
|
|
@ -1,4 +0,0 @@
|
||||||
sub init()
|
|
||||||
m.tracker=m.top.createChild("TrackerTask")
|
|
||||||
m.top.overhangTitle = "Home"
|
|
||||||
end sub
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<component name="Library" extends="JFGroup">
|
|
||||||
<children>
|
|
||||||
<LibraryRow id="LibrarySelect" />
|
|
||||||
|
|
||||||
<OptionsSlider id="options" />
|
|
||||||
</children>
|
|
||||||
<interface>
|
|
||||||
<field id="libraries" alias="LibrarySelect.libList" />
|
|
||||||
<field id="librarySelected" alias="LibrarySelect.itemSelected" />
|
|
||||||
</interface>
|
|
||||||
<script type="text/brightscript" uri="scene.brs" />
|
|
||||||
</component>
|
|
|
@ -20,11 +20,10 @@ sub Main()
|
||||||
' First thing to do is validate the ability to use the API
|
' First thing to do is validate the ability to use the API
|
||||||
LoginFlow()
|
LoginFlow()
|
||||||
|
|
||||||
|
' load home page
|
||||||
' Confirm the configured server and user work
|
m.overhang.title = "Home"
|
||||||
group = CreateLibraryGroup()
|
|
||||||
m.overhang.title = group.overhangTitle
|
|
||||||
m.overhang.currentUser = m.user.Name
|
m.overhang.currentUser = m.user.Name
|
||||||
|
group = CreateHomeGroup()
|
||||||
m.scene.appendChild(group)
|
m.scene.appendChild(group)
|
||||||
|
|
||||||
m.scene.observeField("backPressed", m.port)
|
m.scene.observeField("backPressed", m.port)
|
||||||
|
@ -71,9 +70,9 @@ sub Main()
|
||||||
else
|
else
|
||||||
group.setFocus(true)
|
group.setFocus(true)
|
||||||
end if
|
end if
|
||||||
else if isNodeEvent(msg, "librarySelected")
|
else if isNodeEvent(msg, "homeSelection")
|
||||||
' If you select a library from ANYWHERE, follow this flow
|
' If you select a library from ANYWHERE, follow this flow
|
||||||
node = getMsgPicker(msg, "LibrarySelect")
|
node = getMsgPicker(msg, "homeRows")
|
||||||
if node.type = "movies"
|
if node.type = "movies"
|
||||||
group.lastFocus = group.focusedChild
|
group.lastFocus = group.focusedChild
|
||||||
group.setFocus(false)
|
group.setFocus(false)
|
||||||
|
@ -100,6 +99,31 @@ sub Main()
|
||||||
group = CreateCollectionsList(node)
|
group = CreateCollectionsList(node)
|
||||||
group.overhangTitle = node.name
|
group.overhangTitle = node.name
|
||||||
m.scene.appendChild(group)
|
m.scene.appendChild(group)
|
||||||
|
else if node.type = "Episode" then
|
||||||
|
' play episode
|
||||||
|
' todo: create an episode page to link here
|
||||||
|
group.lastFocus = group.focusedChild
|
||||||
|
group.setFocus(false)
|
||||||
|
group.visible = false
|
||||||
|
video_id = node.id
|
||||||
|
|
||||||
|
group = CreateVideoPlayerGroup(video_id)
|
||||||
|
m.scene.appendChild(group)
|
||||||
|
group.setFocus(true)
|
||||||
|
group.control = "play"
|
||||||
|
ReportPlayback(group, "start")
|
||||||
|
m.overhang.visible = false
|
||||||
|
else if node.type = "Movie" then
|
||||||
|
' open movie detail page
|
||||||
|
group.lastFocus = group.focusedChild
|
||||||
|
group.setFocus(false)
|
||||||
|
group.visible = false
|
||||||
|
|
||||||
|
m.overhang.title = node.name
|
||||||
|
m.overhang.showOptions = false
|
||||||
|
group = CreateMovieDetailsGroup(node)
|
||||||
|
group.overhangTitle = node.name
|
||||||
|
m.scene.appendChild(group)
|
||||||
else
|
else
|
||||||
' TODO - switch on more node types
|
' TODO - switch on more node types
|
||||||
message_dialog("This library type is not yet implemented: " + node.type + ".")
|
message_dialog("This library type is not yet implemented: " + node.type + ".")
|
||||||
|
|
|
@ -97,16 +97,16 @@ sub CreateSigninGroup()
|
||||||
group.visible = false
|
group.visible = false
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
function CreateLibraryGroup()
|
function CreateHomeGroup()
|
||||||
' Main screen after logging in. Shows the user's libraries
|
' Main screen after logging in. Shows the user's libraries
|
||||||
group = CreateObject("roSGNode", "Library")
|
group = CreateObject("roSGNode", "Home")
|
||||||
|
|
||||||
libs = LibraryList()
|
libs = LibraryList()
|
||||||
|
|
||||||
group.libraries = libs
|
group.libraries = libs
|
||||||
group.observeField("librarySelected", m.port)
|
con = HomeItemList("continue")
|
||||||
|
group.continueWatching = con
|
||||||
|
|
||||||
library = group.findNode("LibrarySelect")
|
group.observeField("homeSelection", m.port)
|
||||||
|
|
||||||
sidepanel = group.findNode("options")
|
sidepanel = group.findNode("options")
|
||||||
sidepanel.observeField("closeSidePanel", m.port)
|
sidepanel.observeField("closeSidePanel", m.port)
|
||||||
|
|
|
@ -42,7 +42,7 @@ function LibraryList()
|
||||||
data = getJson(resp)
|
data = getJson(resp)
|
||||||
results = []
|
results = []
|
||||||
for each item in data.Items
|
for each item in data.Items
|
||||||
tmp = CreateObject("roSGNode", "LibraryData")
|
tmp = CreateObject("roSGNode", "HomeData")
|
||||||
tmp.json = item
|
tmp.json = item
|
||||||
params = { "Tag" : tmp.json.ImageTags.Primary, "maxHeight" : 261, "maxWidth" : 464 }
|
params = { "Tag" : tmp.json.ImageTags.Primary, "maxHeight" : 261, "maxWidth" : 464 }
|
||||||
tmp.imageURL = ImageURL(tmp.json.id, "Primary", params)
|
tmp.imageURL = ImageURL(tmp.json.id, "Primary", params)
|
||||||
|
@ -140,6 +140,64 @@ function ItemList(library_id = invalid as string, params = {})
|
||||||
return data
|
return data
|
||||||
end function
|
end function
|
||||||
|
|
||||||
|
' Return items for use on home screen (homeRows)
|
||||||
|
function HomeItemList(row = "" as string, params = {})
|
||||||
|
if params["limit"] = invalid
|
||||||
|
params["limit"] = 20
|
||||||
|
end if
|
||||||
|
if row = "continue" then
|
||||||
|
params["recursive"] = true
|
||||||
|
params["SortBy"] = "DatePlayed"
|
||||||
|
params["SortOrder"] = "Descending"
|
||||||
|
params["Filters"] = "IsResumable"
|
||||||
|
end if
|
||||||
|
|
||||||
|
url = Substitute("Users/{0}/Items/", get_setting("active_user"))
|
||||||
|
resp = APIRequest(url, params)
|
||||||
|
data = getJson(resp)
|
||||||
|
results = []
|
||||||
|
for each item in data.Items
|
||||||
|
tmp = CreateObject("roSGNode", "HomeData")
|
||||||
|
imgParams = {}
|
||||||
|
|
||||||
|
param = { "AddPlayedIndicator": item.UserData.Played }
|
||||||
|
imgParams.Append(param)
|
||||||
|
|
||||||
|
if item.UserData.PlayedPercentage <> invalid then
|
||||||
|
param = { "PercentPlayed": item.UserData.PlayedPercentage }
|
||||||
|
imgParams.Append(param)
|
||||||
|
end if
|
||||||
|
|
||||||
|
param = { "maxHeight": 261 }
|
||||||
|
imgParams.Append(param)
|
||||||
|
param = { "maxWidth": 464 }
|
||||||
|
imgParams.Append(param)
|
||||||
|
|
||||||
|
if item.type = "Movie"
|
||||||
|
if item.ImageTags.Thumb <> invalid then
|
||||||
|
param = { "Tag" : item.ImageTags.Thumb }
|
||||||
|
imgParams.Append(param)
|
||||||
|
tmp.imageURL = ImageURL(item.id, "Thumb", imgParams)
|
||||||
|
else
|
||||||
|
param = { "Tag" : item.ImageTags.Primary }
|
||||||
|
imgParams.Append(param)
|
||||||
|
tmp.imageURL = ImageURL(item.id, "Primary", imgParams)
|
||||||
|
end if
|
||||||
|
else if item.type = "Episode"
|
||||||
|
if item.ImageTags.Primary <> invalid then
|
||||||
|
param = { "Tag" : item.ImageTags.Primary }
|
||||||
|
imgParams.Append(param)
|
||||||
|
end if
|
||||||
|
tmp.imageURL = ImageURL(item.id, "Primary", imgParams)
|
||||||
|
end if
|
||||||
|
|
||||||
|
tmp.json = item
|
||||||
|
results.push(tmp)
|
||||||
|
end for
|
||||||
|
data.items = results
|
||||||
|
return data
|
||||||
|
end function
|
||||||
|
|
||||||
' MetaData about an item
|
' MetaData about an item
|
||||||
function ItemMetaData(id as string)
|
function ItemMetaData(id as string)
|
||||||
url = Substitute("Users/{0}/Items/{1}", get_setting("active_user"), id)
|
url = Substitute("Users/{0}/Items/{1}", get_setting("active_user"), id)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user