Add Genres, Parental Ratings, and Years as Movie Filters (#928)
* Add Movie Filters * Add filter names to translations file. * Only jump up if content is reloaded
This commit is contained in:
parent
a33ce8bd57
commit
2eff1401d8
|
@ -16,6 +16,11 @@ sub init()
|
|||
m.menus.push(m.top.findNode("sortMenu"))
|
||||
m.menus.push(m.top.findNode("filterMenu"))
|
||||
|
||||
m.filterOptions = m.top.findNode("filterOptions")
|
||||
|
||||
m.filterMenu = m.top.findNode("filterMenu")
|
||||
m.filterMenu.observeField("itemFocused", "onFilterFocusChange")
|
||||
|
||||
m.viewNames = []
|
||||
m.sortNames = []
|
||||
m.filterNames = []
|
||||
|
@ -24,14 +29,46 @@ sub init()
|
|||
m.fadeAnim = m.top.findNode("fadeAnim")
|
||||
m.fadeOutAnimOpacity = m.top.findNode("outOpacity")
|
||||
m.fadeInAnimOpacity = m.top.findNode("inOpacity")
|
||||
m.showChecklistAnimation = m.top.findNode("showChecklistAnimation")
|
||||
m.hideChecklistAnimation = m.top.findNode("hideChecklistAnimation")
|
||||
|
||||
m.buttons.observeField("focusedIndex", "buttonFocusChanged")
|
||||
m.favoriteMenu.observeField("buttonSelected", "toggleFavorite")
|
||||
end sub
|
||||
|
||||
sub showChecklist()
|
||||
if m.filterOptions.opacity = 0
|
||||
if m.showChecklistAnimation.state = "stopped"
|
||||
m.showChecklistAnimation.control = "start"
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub hideChecklist()
|
||||
if m.filterOptions.opacity = 1
|
||||
if m.hideChecklistAnimation.state = "stopped"
|
||||
m.hideChecklistAnimation.control = "start"
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub onFilterFocusChange()
|
||||
if m.filterMenu.content.getChild(m.filterMenu.itemFocused).getChildCount() > 0
|
||||
showChecklist()
|
||||
else
|
||||
hideChecklist()
|
||||
end if
|
||||
|
||||
m.filterOptions.content = m.filterMenu.content.getChild(m.filterMenu.itemFocused)
|
||||
if isValid(m.filterMenu.content.getChild(m.filterMenu.itemFocused).checkedState)
|
||||
m.filterOptions.checkedState = m.filterMenu.content.getChild(m.filterMenu.itemFocused).checkedState
|
||||
else
|
||||
m.filterOptions.checkedState = []
|
||||
end if
|
||||
end sub
|
||||
|
||||
|
||||
sub optionsSet()
|
||||
|
||||
' Views Tab
|
||||
if m.top.options.views <> invalid
|
||||
viewContent = CreateObject("roSGNode", "ContentNode")
|
||||
|
@ -90,8 +127,19 @@ sub optionsSet()
|
|||
m.selectedFilterIndex = 0
|
||||
|
||||
for each filterItem in m.top.options.filter
|
||||
entry = filterContent.CreateChild("ContentNode")
|
||||
entry = filterContent.CreateChild("OptionNode")
|
||||
entry.title = filterItem.Title
|
||||
entry.name = filterItem.Name
|
||||
entry.delimiter = filterItem.Delimiter
|
||||
|
||||
if isValid(filterItem.options)
|
||||
for each filterItemOption in filterItem.options
|
||||
entryOption = entry.CreateChild("ContentNode")
|
||||
entryOption.title = toString(filterItemOption)
|
||||
end for
|
||||
entry.checkedState = filterItem.checkedState
|
||||
end if
|
||||
|
||||
m.filterNames.push(filterItem.Name)
|
||||
if filterItem.selected <> invalid and filterItem.selected = true
|
||||
m.selectedFilterIndex = index
|
||||
|
@ -193,12 +241,31 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
end if
|
||||
|
||||
return true
|
||||
else if key = "right"
|
||||
if m.menus[m.selectedItem].isInFocusChain()
|
||||
' Handle Filter screen
|
||||
if m.selectedItem = 2
|
||||
' Selected filter has options, move cursor to it
|
||||
if m.filterMenu.content.getChild(m.filterMenu.itemFocused).getChildCount() > 0
|
||||
m.menus[m.selectedItem].setFocus(false)
|
||||
m.filterOptions.setFocus(true)
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
else if key = "left"
|
||||
if m.favoriteMenu.hasFocus()
|
||||
m.favoriteMenu.setFocus(false)
|
||||
m.menus[m.selectedItem].visible = true
|
||||
m.buttons.setFocus(true)
|
||||
end if
|
||||
|
||||
' User wants to escape filter options
|
||||
if m.filterOptions.isInFocusChain()
|
||||
m.filterOptions.setFocus(false)
|
||||
m.menus[m.selectedItem].setFocus(true)
|
||||
return true
|
||||
end if
|
||||
else if key = "OK"
|
||||
if m.menus[m.selectedItem].isInFocusChain()
|
||||
' Handle View Screen
|
||||
|
@ -229,14 +296,58 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
' Handle Filter screen
|
||||
if m.selectedItem = 2
|
||||
m.selectedFilterIndex = m.menus[2].itemSelected
|
||||
m.top.filter = m.filterNames[m.selectedFilterIndex]
|
||||
' If filter has no options, select it
|
||||
if m.filterMenu.content.getChild(m.filterMenu.itemFocused).getChildCount() = 0
|
||||
m.menus[2].checkedItem = m.menus[2].itemSelected
|
||||
m.selectedFilterIndex = m.menus[2].itemSelected
|
||||
m.top.filter = m.filterNames[m.selectedFilterIndex]
|
||||
m.top.filterOptions = {}
|
||||
return true
|
||||
end if
|
||||
|
||||
' Selected filter has options, move cursor to it
|
||||
m.filterOptions.setFocus(true)
|
||||
m.menus[m.selectedItem].setFocus(false)
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
' User pressed OK from inside the filter's options
|
||||
if m.filterOptions.isInFocusChain()
|
||||
selectedOptions = []
|
||||
for i = 0 to m.filterOptions.checkedState.count() - 1
|
||||
if m.filterOptions.checkedState[i]
|
||||
selectedValue = toString(m.filterOptions.content.getChild(i).title)
|
||||
selectedOptions.push(selectedValue)
|
||||
end if
|
||||
end for
|
||||
|
||||
if selectedOptions.Count() > 0
|
||||
m.menus[2].checkedItem = m.menus[2].itemFocused
|
||||
m.selectedFilterIndex = m.menus[2].itemFocused
|
||||
m.top.filter = m.filterMenu.content.getChild(m.filterMenu.itemFocused).Name
|
||||
|
||||
newFilter = {}
|
||||
newFilter[m.top.filter] = selectedOptions.join(m.filterMenu.content.getChild(m.filterMenu.itemFocused).delimiter)
|
||||
m.top.filterOptions = newFilter
|
||||
else
|
||||
m.menus[2].checkedItem = 0
|
||||
m.selectedFilterIndex = 0
|
||||
m.top.filter = m.filterNames[0]
|
||||
m.top.filterOptions = {}
|
||||
end if
|
||||
|
||||
m.filterMenu.content.getChild(m.filterMenu.itemFocused).checkedState = m.filterOptions.checkedState
|
||||
|
||||
return true
|
||||
end if
|
||||
return true
|
||||
else if key = "back" or key = "up"
|
||||
if key = "back" then hideChecklist()
|
||||
|
||||
m.menus[2].visible = true ' Show Filter contents in case hidden by favorite button
|
||||
if m.menus[m.selectedItem].isInFocusChain()
|
||||
m.buttons.setFocus(true)
|
||||
|
@ -244,6 +355,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
return true
|
||||
end if
|
||||
else if key = "options"
|
||||
hideChecklist()
|
||||
m.menus[2].visible = true ' Show Filter contents in case hidden by favorite button
|
||||
m.menus[m.selectedItem].drawFocusFeedback = false
|
||||
return false
|
||||
|
|
|
@ -6,15 +6,18 @@
|
|||
<Poster width="1720" height="880" uri="pkg:/images/dialog.9.png" />
|
||||
<LayoutGroup horizAlignment="center" translation="[860,50]" itemSpacings="[50]">
|
||||
<JFButtons id="buttons" />
|
||||
</LayoutGroup>
|
||||
<LayoutGroup id="menuOptions" horizAlignment="center" translation="[860,200]" itemSpacings="[50]">
|
||||
<Group>
|
||||
<RadiobuttonList id="viewMenu" itemspacing="[0,10]" vertFocusAnimationStyle="floatingFocus" opacity="0" drawFocusFeedback="false">
|
||||
</RadiobuttonList>
|
||||
<RadiobuttonList id="sortMenu" itemspacing="[0,10]" vertFocusAnimationStyle="floatingFocus" opacity="1" numRows="8" drawFocusFeedback="false">
|
||||
</RadiobuttonList>
|
||||
<RadiobuttonList id="filterMenu" itemspacing="[0,10]" vertFocusAnimationStyle="floatingFocus" opacity="0" drawFocusFeedback="false">
|
||||
<RadiobuttonList id="filterMenu" checkOnSelect="false" itemspacing="[0,10]" vertFocusAnimationStyle="floatingFocus" opacity="0" drawFocusFeedback="false">
|
||||
</RadiobuttonList>
|
||||
</Group>
|
||||
</LayoutGroup>
|
||||
<CheckList opacity="0" translation="[900, 200]" id="filterOptions" numRows="8" itemSize="[250, 70]" />
|
||||
<ButtonGroup translation="[1250,50]">
|
||||
<Button id="favoriteMenu" iconUri="pkg:/images/icons/favorite.png" focusedIconUri="pkg:/images/icons/favorite.png" focusBitmapUri="" focusFootprintBitmapUri="" text="Favorite" showFocusFootprint="false"></Button>
|
||||
</ButtonGroup>
|
||||
|
@ -25,6 +28,16 @@
|
|||
<FloatFieldInterpolator id="inOpacity" key="[0.0, 0.5, 1.0]" keyValue="[ 0, 0, 1 ]" fieldToInterp="focus.opacity" />
|
||||
</Animation>
|
||||
|
||||
<Animation id="showChecklistAnimation" duration="0.5" repeat="false">
|
||||
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0, 1]" fieldToInterp="filterOptions.opacity" />
|
||||
<Vector2DFieldInterpolator key="[0.0, 1.0]" keyValue="[[860, 200], [560, 200]]" fieldToInterp="menuOptions.translation" />
|
||||
</Animation>
|
||||
|
||||
<Animation id="hideChecklistAnimation" duration="0.5" repeat="false">
|
||||
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[1, 0]" fieldToInterp="filterOptions.opacity" />
|
||||
<Vector2DFieldInterpolator key="[0.0, 1.0]" keyValue="[[560, 200], [860, 200]]" fieldToInterp="menuOptions.translation" />
|
||||
</Animation>
|
||||
|
||||
</children>
|
||||
<interface>
|
||||
<field id="buttons" type="nodearray" />
|
||||
|
@ -35,8 +48,10 @@
|
|||
<field id="sortField" type="string" value="SortName" />
|
||||
<field id="sortAscending" type="boolean" value="false" />
|
||||
<field id="filter" type="string" value="All" />
|
||||
<field id="filterOptions" type="assocarray" value="" />
|
||||
<field id="favorite" type="string" value="Favorite" />
|
||||
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="ItemGridOptions.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
</component>
|
||||
|
|
|
@ -83,6 +83,12 @@ sub loadItems()
|
|||
params.append({ Filters: "IsResumable" })
|
||||
end if
|
||||
|
||||
if isValid(m.top.filterOptions)
|
||||
if m.top.filterOptions.count() > 0
|
||||
params.append(m.top.filterOptions)
|
||||
end if
|
||||
end if
|
||||
|
||||
if m.top.ItemType <> ""
|
||||
params.append({ IncludeItemTypes: m.top.ItemType })
|
||||
end if
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<field id="nameStartsWith" type="string" value="" />
|
||||
<field id="recursive" type="boolean" value="true" />
|
||||
<field id="filter" type="string" value="All" />
|
||||
<field id="filterOptions" type="assocarray" value="" />
|
||||
<field id="searchTerm" type="string" value="" />
|
||||
<field id="studioIds" type="string" value="" />
|
||||
<field id="genreIds" type="string" value="" />
|
||||
|
@ -25,6 +26,7 @@
|
|||
<script type="text/brightscript" uri="pkg:/source/roku_modules/api/api.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/utils/misc.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/deviceCapabilities.brs" />
|
||||
</component>
|
|
@ -67,10 +67,12 @@ sub init()
|
|||
m.sortAscending = true
|
||||
|
||||
m.filter = "All"
|
||||
m.filterOptions = {}
|
||||
m.favorite = "Favorite"
|
||||
|
||||
m.loadItemsTask = createObject("roSGNode", "LoadItemsTask2")
|
||||
m.loadLogoTask = createObject("roSGNode", "LoadItemsTask2")
|
||||
m.getFiltersTask = createObject("roSGNode", "GetFiltersTask")
|
||||
|
||||
'set inital counts for overhang before content is loaded.
|
||||
m.loadItemsTask.totalRecordCount = 0
|
||||
|
@ -126,6 +128,7 @@ sub loadInitialItems()
|
|||
|
||||
m.sortField = get_user_setting("display." + m.top.parentItem.Id + ".sortField")
|
||||
m.filter = get_user_setting("display." + m.top.parentItem.Id + ".filter")
|
||||
m.filterOptions = get_user_setting("display." + m.top.parentItem.Id + ".filterOptions")
|
||||
m.view = get_user_setting("display." + m.top.parentItem.Id + ".landing")
|
||||
sortAscendingStr = get_user_setting("display." + m.top.parentItem.Id + ".sortAscending")
|
||||
|
||||
|
@ -136,8 +139,11 @@ sub loadInitialItems()
|
|||
|
||||
if not isValid(m.sortField) then m.sortField = "SortName"
|
||||
if not isValid(m.filter) then m.filter = "All"
|
||||
if not isValid(m.filterOptions) then m.filterOptions = "{}"
|
||||
if not isValid(m.view) then m.view = "Movies"
|
||||
|
||||
m.filterOptions = ParseJson(m.filterOptions)
|
||||
|
||||
if sortAscendingStr = invalid or sortAscendingStr = "true"
|
||||
m.sortAscending = true
|
||||
else
|
||||
|
@ -165,6 +171,7 @@ sub loadInitialItems()
|
|||
m.loadItemsTask.sortField = m.sortField
|
||||
m.loadItemsTask.sortAscending = m.sortAscending
|
||||
m.loadItemsTask.filter = m.filter
|
||||
m.loadItemsTask.filterOptions = m.filterOptions
|
||||
m.loadItemsTask.startIndex = 0
|
||||
|
||||
' Load Item Types
|
||||
|
@ -216,7 +223,14 @@ sub loadInitialItems()
|
|||
m.loadItemsTask.observeField("content", "ItemDataLoaded")
|
||||
m.spinner.visible = true
|
||||
m.loadItemsTask.control = "RUN"
|
||||
SetUpOptions()
|
||||
|
||||
m.getFiltersTask.observeField("filters", "FilterDataLoaded")
|
||||
m.getFiltersTask.params = {
|
||||
userid: get_setting("active_user"),
|
||||
parentid: m.top.parentItem.Id,
|
||||
includeitemtypes: "Movie"
|
||||
}
|
||||
m.getFiltersTask.control = "RUN"
|
||||
end sub
|
||||
|
||||
' Set Movies view, sort, and filter options
|
||||
|
@ -291,12 +305,7 @@ function inStringArray(array, searchValue) as boolean
|
|||
end function
|
||||
|
||||
' Data to display when options button selected
|
||||
sub SetUpOptions()
|
||||
options = {}
|
||||
options.filter = []
|
||||
options.favorite = []
|
||||
|
||||
setMoviesOptions(options)
|
||||
sub setSelectedOptions(options)
|
||||
|
||||
' Set selected view option
|
||||
for each o in options.views
|
||||
|
@ -316,17 +325,76 @@ sub SetUpOptions()
|
|||
end if
|
||||
end for
|
||||
|
||||
' Set selected filter option
|
||||
' Set selected filter
|
||||
for each o in options.filter
|
||||
if o.Name = m.filter
|
||||
o.Selected = true
|
||||
m.options.filter = o.Name
|
||||
end if
|
||||
|
||||
' Select selected filter options
|
||||
if isValid(o.options) and isValid(m.filterOptions)
|
||||
if o.options.Count() > 0 and m.filterOptions.Count() > 0
|
||||
if LCase(o.Name) = LCase(m.filterOptions.keys()[0])
|
||||
selectedFilterOptions = m.filterOptions[m.filterOptions.keys()[0]].split(o.delimiter)
|
||||
checkedState = []
|
||||
|
||||
for each availableFilterOption in o.options
|
||||
matchFound = false
|
||||
|
||||
for each selectedFilterOption in selectedFilterOptions
|
||||
if LCase(toString(availableFilterOption).trim()) = LCase(selectedFilterOption.trim())
|
||||
matchFound = true
|
||||
end if
|
||||
end for
|
||||
|
||||
checkedState.push(matchFound)
|
||||
end for
|
||||
|
||||
o.checkedState = checkedState
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
|
||||
m.options.options = options
|
||||
end sub
|
||||
|
||||
'
|
||||
' Logo Image Loaded Event Handler
|
||||
sub FilterDataLoaded(msg)
|
||||
options = {}
|
||||
options.filter = []
|
||||
options.favorite = []
|
||||
|
||||
setMoviesOptions(options)
|
||||
|
||||
data = msg.GetData()
|
||||
m.getFiltersTask.unobserveField("filters")
|
||||
|
||||
if not isValid(data) then return
|
||||
|
||||
' Add Movie filters from the API data
|
||||
if LCase(m.loadItemsTask.view) = "movies"
|
||||
if isValid(data.genres)
|
||||
options.filter.push({ "Title": tr("Genres"), "Name": "Genres", "Options": data.genres, "Delimiter": "|", "CheckedState": [] })
|
||||
end if
|
||||
|
||||
if isValid(data.OfficialRatings)
|
||||
options.filter.push({ "Title": tr("Parental Ratings"), "Name": "OfficialRatings", "Options": data.OfficialRatings, "Delimiter": "|", "CheckedState": [] })
|
||||
end if
|
||||
|
||||
if isValid(data.Years)
|
||||
options.filter.push({ "Title": tr("Years"), "Name": "Years", "Options": data.Years, "Delimiter": ",", "CheckedState": [] })
|
||||
end if
|
||||
end if
|
||||
|
||||
setSelectedOptions(options)
|
||||
|
||||
m.options.options = options
|
||||
end sub
|
||||
|
||||
|
||||
'
|
||||
' Logo Image Loaded Event Handler
|
||||
sub LogoImageLoaded(msg)
|
||||
|
@ -384,6 +452,10 @@ sub ItemDataLoaded(msg)
|
|||
m.itemGrid.setFocus(true)
|
||||
m.genreList.setFocus(false)
|
||||
|
||||
if m.data.getChildCount() = 0
|
||||
m.itemGrid.jumpToItem = 0
|
||||
end if
|
||||
|
||||
for each item in itemData
|
||||
m.data.appendChild(item)
|
||||
end for
|
||||
|
@ -709,6 +781,16 @@ sub optionsClosed()
|
|||
set_user_setting("display." + m.top.parentItem.Id + ".filter", m.options.filter)
|
||||
end if
|
||||
|
||||
if not isValid(m.options.filterOptions)
|
||||
m.filterOptions = {}
|
||||
end if
|
||||
|
||||
if not AssocArrayEqual(m.options.filterOptions, m.filterOptions)
|
||||
m.filterOptions = m.options.filterOptions
|
||||
reload = true
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".filterOptions", FormatJson(m.options.filterOptions))
|
||||
end if
|
||||
|
||||
m.view = get_user_setting("display." + m.top.parentItem.Id + ".landing")
|
||||
|
||||
if m.options.view <> m.view
|
||||
|
@ -720,6 +802,7 @@ sub optionsClosed()
|
|||
m.loadItemsTask.NameStartsWith = " "
|
||||
m.loadItemsTask.searchTerm = ""
|
||||
m.filter = "All"
|
||||
m.filterOptions = {}
|
||||
m.sortField = "SortName"
|
||||
m.sortAscending = true
|
||||
|
||||
|
@ -727,6 +810,7 @@ sub optionsClosed()
|
|||
set_user_setting("display." + m.top.parentItem.Id + ".sortField", m.sortField)
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".sortAscending", "true")
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".filter", m.filter)
|
||||
set_user_setting("display." + m.top.parentItem.Id + ".filterOptions", FormatJson(m.filterOptions))
|
||||
|
||||
reload = true
|
||||
end if
|
||||
|
@ -845,6 +929,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.top.alphaSelected = ""
|
||||
m.loadItemsTask.filter = "All"
|
||||
m.filter = "All"
|
||||
m.filterOptions = {}
|
||||
m.data = CreateObject("roSGNode", "ContentNode")
|
||||
m.itemGrid.content = m.data
|
||||
loadInitialItems()
|
||||
|
|
|
@ -63,4 +63,5 @@
|
|||
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/deviceCapabilities.brs" />
|
||||
<script type="text/brightscript" uri="MovieLibraryView.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/roku_modules/api/api.brs" />
|
||||
</component>
|
||||
|
|
8
components/data/GetFiltersTask.brs
Normal file
8
components/data/GetFiltersTask.brs
Normal file
|
@ -0,0 +1,8 @@
|
|||
sub init()
|
||||
m.top.functionName = "getFiltersTask"
|
||||
end sub
|
||||
|
||||
sub getFiltersTask()
|
||||
m.filters = api_API().items.getFilters(m.top.params)
|
||||
m.top.filters = m.filters
|
||||
end sub
|
11
components/data/GetFiltersTask.xml
Normal file
11
components/data/GetFiltersTask.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<component name="GetFiltersTask" extends="Task">
|
||||
<interface>
|
||||
<field id="params" type="assocarray" />
|
||||
<field id="filters" type="assocarray" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="GetFiltersTask.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/roku_modules/api/api.brs" />
|
||||
</component>
|
2
components/options/OptionNode.brs
Normal file
2
components/options/OptionNode.brs
Normal file
|
@ -0,0 +1,2 @@
|
|||
sub init()
|
||||
end sub
|
9
components/options/OptionNode.xml
Normal file
9
components/options/OptionNode.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="OptionNode" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="name" type="string" />
|
||||
<field id="delimiter" type="string" />
|
||||
<field id="checkedState" type="array" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="OptionNode.brs" />
|
||||
</component>
|
|
@ -933,6 +933,16 @@
|
|||
<translation>Support Direct Play of MPEG-4 content. This may need to be disabled for playback of DIVX encoded video files.</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Parental Ratings</source>
|
||||
<translation>Parental Ratings</translation>
|
||||
<extracomment>Used in Filter menu</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Years</source>
|
||||
<translation>Years</translation>
|
||||
<extracomment>Used in Filter menu</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show What's New Popup</source>
|
||||
<translation>Show What's New Popup</translation>
|
||||
|
|
|
@ -282,14 +282,53 @@ function findNodeBySubtype(node, subtype)
|
|||
return foundNodes
|
||||
end function
|
||||
|
||||
' Search string array for search value. Return if it's found
|
||||
function inArray(array, searchValue) as boolean
|
||||
for each item in array
|
||||
if lcase(item) = lcase(searchValue) then return true
|
||||
function AssocArrayEqual(Array1 as object, Array2 as object) as boolean
|
||||
if not isValid(Array1) or not isValid(Array2)
|
||||
return false
|
||||
end if
|
||||
|
||||
if not Array1.Count() = Array2.Count()
|
||||
return false
|
||||
end if
|
||||
|
||||
for each key in Array1
|
||||
if not Array2.DoesExist(key)
|
||||
return false
|
||||
end if
|
||||
|
||||
if Array1[key] <> Array2[key]
|
||||
return false
|
||||
end if
|
||||
end for
|
||||
|
||||
return true
|
||||
end function
|
||||
|
||||
' Search string array for search value. Return if it's found
|
||||
function inArray(haystack, needle) as boolean
|
||||
valueToFind = needle
|
||||
|
||||
if LCase(type(valueToFind)) <> "rostring" and LCase(type(valueToFind)) <> "string"
|
||||
valueToFind = str(needle)
|
||||
end if
|
||||
|
||||
valueToFind = lcase(valueToFind)
|
||||
|
||||
for each item in haystack
|
||||
if lcase(item) = valueToFind then return true
|
||||
end for
|
||||
|
||||
return false
|
||||
end function
|
||||
|
||||
function toString(input) as string
|
||||
if LCase(type(input)) = "rostring" or LCase(type(input)) = "string"
|
||||
return input
|
||||
end if
|
||||
|
||||
return str(input)
|
||||
end function
|
||||
|
||||
sub startLoadingSpinner()
|
||||
m.spinner = createObject("roSGNode", "Spinner")
|
||||
m.spinner.translation = "[900, 450]"
|
||||
|
|
Loading…
Reference in New Issue
Block a user