Updated design and functionality of ItemGrid for Movies
This commit is contained in:
parent
ba05444f44
commit
68e322b1ca
40
components/ItemGrid2/GridItem.brs
Normal file
40
components/ItemGrid2/GridItem.brs
Normal file
|
@ -0,0 +1,40 @@
|
|||
sub init()
|
||||
m.itemPoster = m.top.findNode("itemPoster")
|
||||
m.itemText = m.top.findNode("itemText")
|
||||
end sub
|
||||
|
||||
sub itemContentChanged()
|
||||
|
||||
itemData = m.top.itemContent
|
||||
|
||||
if itemData = invalid then return
|
||||
|
||||
itemPoster = m.top.findNode("itemPoster")
|
||||
|
||||
if itemData.type = "Movie" then
|
||||
itemPoster.uri = itemData.PosterUrl
|
||||
m.itemText.text = itemData.Title
|
||||
return
|
||||
end if
|
||||
|
||||
print "Unhandled Item Type: " + itemData.type
|
||||
|
||||
end sub
|
||||
|
||||
'
|
||||
'Resize Poster and Title Vivbility on focus change
|
||||
sub focusChanged()
|
||||
|
||||
if m.top.itemHasFocus = true then
|
||||
m.itemPoster.width = 295
|
||||
m.itemPoster.height = 440
|
||||
m.itemPoster.translation = [0,0]
|
||||
m.itemText.visible = true
|
||||
else
|
||||
m.itemPoster.width = 250
|
||||
m.itemPoster.height = 375
|
||||
m.itemPoster.translation = [21,35]
|
||||
m.itemText.visible = false
|
||||
end if
|
||||
|
||||
end sub
|
12
components/ItemGrid2/GridItem.xml
Normal file
12
components/ItemGrid2/GridItem.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="GridItem" extends="Group">
|
||||
<children>
|
||||
<Poster id="itemPoster" width="250" height="375" translation="[21,35]" loadDisplayMode="scaleToZoom" loadingBitmapUri="pkg:/images/PosterLoading.png" failedBitmapUri="pkg:/images/PosterFailed.png" />
|
||||
<ScrollingLabel id="itemText" horizAlign="center" font="font:SmallSystemFont" maxWidth="295" translation="[0,442]" repeatCount="-1" visible="false" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemContent" type="node" onChange="itemContentChanged" />
|
||||
<field id="itemHasFocus" type="boolean" onChange="focusChanged" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="GridItem.brs" />
|
||||
</component>
|
133
components/ItemGrid2/ItemGrid2.brs
Normal file
133
components/ItemGrid2/ItemGrid2.brs
Normal file
|
@ -0,0 +1,133 @@
|
|||
sub init()
|
||||
|
||||
m.itemGrid = m.top.findNode("itemGrid")
|
||||
m.backdrop = m.top.findNode("backdrop")
|
||||
m.newBackdrop = m.top.findNode("backdropTransition")
|
||||
|
||||
m.swapAnimation = m.top.findNode("backroundSwapAnimation")
|
||||
m.swapAnimation.observeField("state", "swapDone")
|
||||
|
||||
m.loadedRows = 0
|
||||
m.loadedItems = 0
|
||||
|
||||
m.data = CreateObject("roSGNode", "ContentNode")
|
||||
|
||||
m.itemGrid.content = m.data
|
||||
m.itemGrid.setFocus(true)
|
||||
|
||||
m.itemGrid.observeField("itemFocused", "onItemFocused")
|
||||
m.itemGrid.observeField("itemSelected", "onItemSelected")
|
||||
m.newBackdrop.observeField("loadStatus", "newBGLoaded")
|
||||
|
||||
'Background Image Queued for loading
|
||||
m.queuedBGUri = ""
|
||||
|
||||
m.loadItemsTask = createObject("roSGNode", "LoadItemsTask2")
|
||||
|
||||
end sub
|
||||
|
||||
'
|
||||
'Load initial set of Data
|
||||
sub loadInitialItems()
|
||||
m.loadItemsTask.itemId = m.top.itemId
|
||||
m.loadItemsTask.observeField("content", "ItemDataLoaded")
|
||||
m.loadItemsTask.itemType = "Movie"
|
||||
m.loadItemsTask.control = "RUN"
|
||||
end sub
|
||||
|
||||
'
|
||||
'Handle loaded data, and add to Grid
|
||||
sub ItemDataLoaded(msg)
|
||||
|
||||
itemData = msg.GetData()
|
||||
data = msg.getField()
|
||||
|
||||
if itemData = invalid then
|
||||
m.Loading = false
|
||||
return
|
||||
end if
|
||||
|
||||
for each item in itemData
|
||||
m.data.appendChild(item)
|
||||
end for
|
||||
|
||||
'Update the stored counts
|
||||
m.loadedItems = m.itemGrid.content.getChildCount()
|
||||
m.loadedRows = m.loadedItems / m.itemGrid.numColumns
|
||||
m.Loading = false
|
||||
end sub
|
||||
|
||||
'
|
||||
'Set Background Image
|
||||
sub SetBackground(backgroundUri as string)
|
||||
|
||||
'If a new image is being loaded, or transitioned to, store URL to load next
|
||||
if m.swapAnimation.state <> "stopped" or m.newBackdrop.loadStatus = "loading" then
|
||||
m.queuedBGUri = backgroundUri
|
||||
return
|
||||
end if
|
||||
|
||||
m.newBackdrop.uri = backgroundUri
|
||||
end sub
|
||||
|
||||
'
|
||||
'Handle new item being focused
|
||||
sub onItemFocused()
|
||||
|
||||
focusedRow = CInt(m.itemGrid.itemFocused / m.itemGrid.numColumns) + 1
|
||||
|
||||
' Set Background
|
||||
itemInt = m.itemGrid.itemFocused
|
||||
|
||||
SetBackground(m.itemGrid.content.getChild(m.itemGrid.itemFocused).backdropUrl)
|
||||
|
||||
' Load more data if focus is within last 3 rows, and there are more items to load
|
||||
if focusedRow >= m.loadedRows - 3 and m.loadeditems < m.loadItemsTask.totalRecordCount then
|
||||
loadMoreData()
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'When Image Loading Status changes
|
||||
sub newBGLoaded()
|
||||
'If image load was sucessful, start the fade swap
|
||||
if m.newBackdrop.loadStatus = "ready"
|
||||
m.swapAnimation.control = "start"
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'Swap Complete
|
||||
sub swapDone()
|
||||
|
||||
if m.swapAnimation.state = "stopped" then
|
||||
|
||||
'Set main BG node image and hide transitioning node
|
||||
m.backdrop.uri = m.newBackdrop.uri
|
||||
m.backdrop.opacity = 0.25
|
||||
m.newBackdrop.opacity = 0
|
||||
|
||||
'If there is another one to load
|
||||
if m.newBackdrop.uri <> m.queuedBGUri and m.queuedBGUri <> "" then
|
||||
SetBackground(m.queuedBGUri)
|
||||
m.queuedBGUri = ""
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
'
|
||||
'Load next set of items
|
||||
sub loadMoreData()
|
||||
|
||||
if m.Loading = true then return
|
||||
|
||||
m.Loading = true
|
||||
m.loadItemsTask.startIndex = m.loadedItems
|
||||
m.loadItemsTask.control = "RUN"
|
||||
end sub
|
||||
|
||||
'
|
||||
'Item Selected
|
||||
sub onItemSelected()
|
||||
m.top.selectedItem = m.itemGrid.content.getChild(m.itemGrid.itemSelected)
|
||||
end sub
|
37
components/ItemGrid2/ItemGrid2.xml
Normal file
37
components/ItemGrid2/ItemGrid2.xml
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="ItemGrid2" extends="JFGroup">
|
||||
<children>
|
||||
<poster id="backdrop"
|
||||
loadDisplayMode="scaleToFill"
|
||||
width="1920"
|
||||
height="1080"
|
||||
opacity="0.25"
|
||||
/>
|
||||
<poster id="backdropTransition"
|
||||
loadDisplayMode="scaleToFill"
|
||||
width="1920"
|
||||
height="1080"
|
||||
opacity="0.25"
|
||||
/>
|
||||
<MarkupGrid
|
||||
id = "itemGrid"
|
||||
translation = "[ 96, 160 ]"
|
||||
itemComponentName = "GridItem"
|
||||
numColumns = "6"
|
||||
numRows = "5"
|
||||
vertFocusAnimationStyle = "fixed"
|
||||
itemSize = "[ 290, 425 ]"
|
||||
itemSpacing = "[ 0, 45 ]"
|
||||
drawFocusFeedback = "false" />
|
||||
<OptionsSlider id="options" />
|
||||
<Animation id="backroundSwapAnimation" duration="1" repeat="false" easeFunction="linear" >
|
||||
<FloatFieldInterpolator id = "fadeinLoading" key="[0.0, 1.0]" keyValue="[ 0.00, 0.25 ]" fieldToInterp="backdropTransition.opacity" />
|
||||
<FloatFieldInterpolator id = "fadeoutLoaded" key="[0.0, 1.0]" keyValue="[ 0.25, 0.00 ]" fieldToInterp="backdrop.opacity" />
|
||||
</Animation>
|
||||
</children>
|
||||
<interface>
|
||||
<field id="itemId" type="string" onChange="loadInitialItems" />
|
||||
<field id="selectedItem" type="node" alwaysNotify="true" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="ItemGrid2.brs" />
|
||||
</component>
|
54
components/ItemGrid2/LoadItemsTask2.brs
Normal file
54
components/ItemGrid2/LoadItemsTask2.brs
Normal file
|
@ -0,0 +1,54 @@
|
|||
sub init()
|
||||
m.top.functionName = "loadItems"
|
||||
end sub
|
||||
|
||||
sub loadItems()
|
||||
|
||||
results = []
|
||||
|
||||
sort_order = get_user_setting("movie_sort_order", "Ascending")
|
||||
sort_field = get_user_setting("movie_sort_field", "SortName")
|
||||
|
||||
|
||||
params = {
|
||||
limit: m.top.limit,
|
||||
StartIndex: m.top.startIndex,
|
||||
parentid: m.top.itemId,
|
||||
SortBy: sort_field,
|
||||
SortOrder: sort_order,
|
||||
recursive: false
|
||||
}
|
||||
|
||||
if m.top.ItemType <> "" then
|
||||
params.append({ IncludeItemTypes: m.top.ItemType})
|
||||
end if
|
||||
|
||||
url = Substitute("Users/{0}/Items/", get_setting("active_user"))
|
||||
resp = APIRequest(url, params)
|
||||
data = getJson(resp)
|
||||
|
||||
if data.TotalRecordCount <> invalid then
|
||||
m.top.totalRecordCount = data.TotalRecordCount
|
||||
end if
|
||||
|
||||
for each item in data.Items
|
||||
|
||||
tmp = invalid
|
||||
if item.Type = "Movie" then
|
||||
tmp = CreateObject("roSGNode", "MovieData")
|
||||
else
|
||||
print "Unknown Type: " item.Type
|
||||
|
||||
end if
|
||||
|
||||
if tmp <> invalid then
|
||||
|
||||
tmp.json = item
|
||||
results.push(tmp)
|
||||
|
||||
end if
|
||||
end for
|
||||
|
||||
m.top.content = results
|
||||
|
||||
end sub
|
20
components/ItemGrid2/LoadItemsTask2.xml
Normal file
20
components/ItemGrid2/LoadItemsTask2.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<component name="LoadItemsTask2" extends="Task">
|
||||
<interface>
|
||||
<field id="itemId" type="string" />
|
||||
<field id="startIndex" type="integer" value="0" />
|
||||
<field id="itemType" type="string" value="" />
|
||||
<field id="limit" type="integer" value="36" />
|
||||
<field id="metadata" type="associativearray" />
|
||||
|
||||
<!-- Total records available from server-->
|
||||
<field id="totalRecordCount" type="int" value="-1" />
|
||||
<field id="content" type="array" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="LoadItemsTask2.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/Items.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/baserequest.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />
|
||||
</component>
|
12
components/data/JFContentItem.xml
Normal file
12
components/data/JFContentItem.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="JFContentItem" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="favorite" type="boolean" />
|
||||
<field id="watched" type="boolean" />
|
||||
<field id="posterUrl" type="string" />
|
||||
<field id="backdropUrl" type="string" />
|
||||
<field id="SubTitle" type="string" value="" />
|
||||
<field id="Type" type="string" value="" />
|
||||
<field id="json" type="associativearray" onChange="setFields" />
|
||||
</interface>
|
||||
</component>
|
|
@ -1,11 +1,27 @@
|
|||
sub setFields()
|
||||
|
||||
' print "Setting Fields in MovieData - " m.top.json.name
|
||||
json = m.top.json
|
||||
|
||||
m.top.id = json.id
|
||||
m.top.title = json.name
|
||||
m.top.overview = json.overview
|
||||
m.top.Title = json.name
|
||||
m.top.Description = json.overview
|
||||
m.top.favorite = json.UserData.isFavorite
|
||||
m.top.watched = json.UserData.played
|
||||
m.top.Type = "Movie"
|
||||
|
||||
if json.ProductionYear <> invalid then
|
||||
m.top.SubTitle = json.ProductionYear
|
||||
end if
|
||||
|
||||
if json.OfficialRating <> invalid and json.OfficialRating <> "" then
|
||||
m.top.Rating = json.OfficialRating
|
||||
if m.top.SubTitle <> "" then
|
||||
m.top.SubTitle = m.top.SubTitle + " - " + m.top.Rating
|
||||
else
|
||||
m.top.SubTitle = m.top.Rating
|
||||
end if
|
||||
end if
|
||||
|
||||
setPoster()
|
||||
setContainer()
|
||||
|
@ -15,9 +31,23 @@ sub setPoster()
|
|||
if m.top.image <> invalid
|
||||
m.top.posterURL = m.top.image.url
|
||||
else
|
||||
m.top.posterURL = ""
|
||||
end if
|
||||
|
||||
if m.top.json.ImageTags.Primary <> invalid then
|
||||
|
||||
imgParams = { "maxHeight": 440, "maxWidth": 295, "Tag" : m.top.json.ImageTags.Primary }
|
||||
m.top.posterURL = ImageURL(m.top.json.id, "Primary", imgParams)
|
||||
else if m.top.json.BackdropImageTags <> invalid then
|
||||
imgParams = { "maxHeight": 440, "Tag" : m.top.json.BackdropImageTags[0] }
|
||||
m.top.posterURL = ImageURL(m.top.json.id, "Backdrop", imgParams)
|
||||
end if
|
||||
|
||||
' Add Backdrop Image
|
||||
if m.top.json.BackdropImageTags <> invalid then
|
||||
imgParams = { "maxHeight": 720, "maxWidth": 1280, "Tag" : m.top.json.BackdropImageTags[0] }
|
||||
m.top.backdropURL = ImageURL(m.top.json.id, "Backdrop", imgParams)
|
||||
end if
|
||||
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub setContainer()
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MovieData" extends="ContentNode">
|
||||
<component name="MovieData" extends="JFContentItem">
|
||||
<interface>
|
||||
<field id="title" type="string" />
|
||||
<field id="image" type="node" onChange="setPoster" />
|
||||
<field id="posterUrl" type="string" />
|
||||
<field id="movieID" type="string" />
|
||||
<field id="overview" type="string" />
|
||||
<field id="favorite" type="boolean" />
|
||||
<field id="watched" type="boolean" />
|
||||
<field id="seasons" type="associativearray" />
|
||||
<field id="container" type="string" />
|
||||
<field id="json" type="associativearray" onChange="setFields" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="MovieData.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/baserequest.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
</component>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
sub init()
|
||||
|
||||
end sub
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
if key = "down"
|
||||
m.top.lastFocus = m.top.focusedChild
|
||||
m.top.findNode("paginator").setFocus(true)
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="Movies" extends="JFGroup">
|
||||
<children>
|
||||
<ItemGrid id="picker" visible="true" itemsPerRow="6" />
|
||||
<OptionsSlider id="options" />
|
||||
<Rectangle translation="[0,981]" width="1920" height="100" color="#101010" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="movieSelected" alias="picker.itemSelected" />
|
||||
<field id="objects" alias="picker.objects" />
|
||||
<field id="pageNumber" type="integer" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="Movies.brs" />
|
||||
</component>
|
BIN
images/PosterFailed.png
Normal file
BIN
images/PosterFailed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
images/PosterLoading.png
Normal file
BIN
images/PosterLoading.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
|
@ -235,9 +235,7 @@ sub Main()
|
|||
else if isNodeEvent(msg, "pageSelected")
|
||||
group.pageNumber = msg.getRoSGNode().pageSelected
|
||||
collectionType = group.subType()
|
||||
if collectionType = "Movies"
|
||||
MovieLister(group, m.page_size)
|
||||
else if collectionType = "Collections"
|
||||
if collectionType = "Collections"
|
||||
CollectionLister(group, m.page_size)
|
||||
else if collectionType = "TVShows"
|
||||
SeriesLister(group, m.page_size)
|
||||
|
|
|
@ -196,10 +196,10 @@ function CreateHomeGroup()
|
|||
end function
|
||||
|
||||
function CreateMovieListGroup(libraryId)
|
||||
group = CreateObject("roSGNode", "Movies")
|
||||
group.id = libraryId
|
||||
group = CreateObject("roSGNode", "ItemGrid2")
|
||||
group.itemId = libraryId
|
||||
|
||||
group.observeField("movieSelected", m.port)
|
||||
group.observeField("selectedItem", m.port)
|
||||
|
||||
sidepanel = group.findNode("options")
|
||||
movie_options = [
|
||||
|
@ -235,15 +235,7 @@ function CreateMovieListGroup(libraryId)
|
|||
sidepanel.options = new_options
|
||||
sidepanel.observeField("closeSidePanel", m.port)
|
||||
|
||||
p = CreatePaginator()
|
||||
group.appendChild(p)
|
||||
|
||||
group.pageNumber = 1
|
||||
p.currentPage = group.pageNumber
|
||||
|
||||
MovieLister(group, m.page_size)
|
||||
|
||||
return group
|
||||
return group
|
||||
end function
|
||||
|
||||
function CreateMovieDetailsGroup(movie)
|
||||
|
@ -397,22 +389,6 @@ function CreateVideoPlayerGroup(video_id)
|
|||
return video
|
||||
end function
|
||||
|
||||
function MovieLister(group, page_size)
|
||||
sort_order = get_user_setting("movie_sort_order", "Ascending")
|
||||
sort_field = get_user_setting("movie_sort_field", "SortName")
|
||||
|
||||
item_list = ItemList(group.id, {"limit": page_size,
|
||||
"StartIndex": page_size * (group.pageNumber - 1),
|
||||
"SortBy": sort_field,
|
||||
"SortOrder": sort_order,
|
||||
"IncludeItemTypes": "Movie"
|
||||
})
|
||||
group.objects = item_list
|
||||
|
||||
p = group.findNode("paginator")
|
||||
p.maxPages = div_ceiling(group.objects.TotalRecordCount, page_size)
|
||||
end function
|
||||
|
||||
function SeriesLister(group, page_size)
|
||||
sort_order = get_user_setting("series_sort_order", "Ascending")
|
||||
sort_field = get_user_setting("series_sort_field", "SortName")
|
||||
|
|
Loading…
Reference in New Issue
Block a user