Merge pull request #811 from 1hitsong/music-appears-on
Add appears on music artist section
This commit is contained in:
commit
b5293c5773
|
@ -69,17 +69,11 @@ end sub
|
|||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
if key = "OK" and m.top.hasFocus()
|
||||
' Simply toggle the selected field to trigger the next event
|
||||
m.top.selected = not m.top.selected
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "right" and m.top.hasFocus()
|
||||
if key = "right" and m.top.focus
|
||||
m.top.escape = "right"
|
||||
end if
|
||||
|
||||
if key = "left" and m.top.hasFocus()
|
||||
if key = "left" and m.top.focus
|
||||
m.top.escape = "left"
|
||||
end if
|
||||
|
||||
|
|
|
@ -80,6 +80,20 @@ sub itemContentChanged()
|
|||
m.backdrop.height = 290
|
||||
m.backdrop.width = 290
|
||||
|
||||
m.posterText.height = 200
|
||||
m.posterText.width = 280
|
||||
else if itemData.json.type = "MusicAlbum"
|
||||
m.itemPoster.uri = itemData.PosterUrl
|
||||
m.itemText.text = itemData.Title
|
||||
|
||||
m.itemPoster.height = 290
|
||||
m.itemPoster.width = 290
|
||||
|
||||
m.itemText.translation = [0, m.itemPoster.height + 7]
|
||||
|
||||
m.backdrop.height = 290
|
||||
m.backdrop.width = 290
|
||||
|
||||
m.posterText.height = 200
|
||||
m.posterText.width = 280
|
||||
else
|
||||
|
|
|
@ -163,25 +163,16 @@ sub loadInitialItems()
|
|||
m.loadItemsTask.itemId = m.top.parentItem.Id
|
||||
else if getCollectionType() = "music"
|
||||
' Default Settings
|
||||
m.loadItemsTask.recursive = true
|
||||
m.itemGrid.itemSize = "[290, 290]"
|
||||
|
||||
if m.voiceBox.text <> ""
|
||||
m.loadItemsTask.recursive = true
|
||||
else
|
||||
m.loadItemsTask.recursive = false
|
||||
m.itemGrid.itemSize = "[290, 290]"
|
||||
end if
|
||||
|
||||
m.loadItemsTask.itemType = "MusicArtist,MusicAlbum"
|
||||
m.loadItemsTask.itemType = "MusicArtist"
|
||||
m.loadItemsTask.itemId = m.top.parentItem.Id
|
||||
|
||||
m.view = get_user_setting("display.music.view")
|
||||
|
||||
if m.view = "music-artist"
|
||||
m.loadItemsTask.recursive = true
|
||||
m.loadItemsTask.itemType = "MusicArtist"
|
||||
else if m.view = "music-album"
|
||||
if m.view = "music-album"
|
||||
m.loadItemsTask.itemType = "MusicAlbum"
|
||||
m.loadItemsTask.recursive = true
|
||||
end if
|
||||
else if m.top.parentItem.collectionType = "livetv"
|
||||
m.loadItemsTask.itemType = "TvChannel"
|
||||
|
@ -312,7 +303,6 @@ end sub
|
|||
' Set Music view, sort, and filter options
|
||||
sub setMusicOptions(options)
|
||||
options.views = [
|
||||
{ "Title": tr("Default"), "Name": "music-default" },
|
||||
{ "Title": tr("Artists"), "Name": "music-artist" },
|
||||
{ "Title": tr("Albums"), "Name": "music-album" },
|
||||
]
|
||||
|
@ -599,13 +589,7 @@ sub optionsClosed()
|
|||
|
||||
if m.top.parentItem.collectionType = "music"
|
||||
if m.options.view <> m.view
|
||||
if m.options.view = "music-artist"
|
||||
m.view = "music-artist"
|
||||
else if m.options.view = "music-album"
|
||||
m.view = "music-album"
|
||||
else
|
||||
m.view = "music-default"
|
||||
end if
|
||||
m.view = m.options.view
|
||||
set_user_setting("display.music.view", m.view)
|
||||
reload = true
|
||||
end if
|
||||
|
@ -796,6 +780,12 @@ sub updateTitle()
|
|||
m.top.overhangTitle = m.top.parentItem.title + tr(" (Filtered by ") + m.loadItemsTask.nameStartsWith + ")"
|
||||
end if
|
||||
|
||||
if m.view = "music-artist"
|
||||
m.top.overhangTitle = "%s (%s)".Format(m.top.parentItem.title, tr("Artists"))
|
||||
else if m.view = "music-album"
|
||||
m.top.overhangTitle = "%s (%s)".Format(m.top.parentItem.title, tr("Albums"))
|
||||
end if
|
||||
|
||||
if m.options.view = "Networks" or m.view = "Networks"
|
||||
m.top.overhangTitle = "%s (%s)".Format(m.top.parentItem.title, tr("Networks"))
|
||||
end if
|
||||
|
|
|
@ -77,6 +77,16 @@ sub loadItems()
|
|||
else if m.top.view = "Genres"
|
||||
url = "Genres"
|
||||
params.append({ UserId: get_setting("active_user") })
|
||||
else if m.top.ItemType = "MusicArtist"
|
||||
url = "Artists"
|
||||
params.append({
|
||||
UserId: get_setting("active_user")
|
||||
})
|
||||
params.IncludeItemTypes = ""
|
||||
else if m.top.ItemType = "MusicAlbum"
|
||||
url = Substitute("Users/{0}/Items/", get_setting("active_user"))
|
||||
params.append({ ImageTypeLimit: 1 })
|
||||
params.append({ EnableImageTypes: "Primary,Backdrop,Banner,Thumb" })
|
||||
else
|
||||
url = Substitute("Users/{0}/Items/", get_setting("active_user"))
|
||||
end if
|
||||
|
@ -110,7 +120,15 @@ sub loadItems()
|
|||
tmp = CreateObject("roSGNode", "FolderData")
|
||||
else if item.Type = "Studio"
|
||||
tmp = CreateObject("roSGNode", "FolderData")
|
||||
else if item.Type = "MusicArtist" or item.Type = "MusicAlbum"
|
||||
else if item.Type = "MusicAlbum"
|
||||
tmp = CreateObject("roSGNode", "MusicAlbumData")
|
||||
tmp.type = "MusicAlbum"
|
||||
if api_API().items.headimageurlbyname(item.id, "primary")
|
||||
tmp.posterURL = ImageURL(item.id, "Primary")
|
||||
else
|
||||
tmp.posterURL = ImageURL(item.id, "backdrop")
|
||||
end if
|
||||
else if item.Type = "MusicArtist"
|
||||
tmp = CreateObject("roSGNode", "MusicArtistData")
|
||||
else if item.Type = "Audio"
|
||||
tmp = CreateObject("roSGNode", "MusicSongData")
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
</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/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/api/Image.brs" />
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MusicAlbumData" extends="ContentNode">
|
||||
<component name="MusicAlbumData" extends="JFContentItem">
|
||||
<interface>
|
||||
<field id="id" type="string" />
|
||||
<field id="title" type="string" />
|
||||
<field id="image" type="node" onChange="setPoster" />
|
||||
<field id="posterURL" type="string" />
|
||||
<field id="overview" type="string" />
|
||||
<field id="type" type="string" value="Episode" />
|
||||
<field id="json" type="assocarray" onChange="setFields" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="MusicAlbumData.brs" />
|
||||
</component>
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="MusicSongData" extends="ContentNode">
|
||||
<component name="MusicSongData" extends="JFContentItem">
|
||||
<interface>
|
||||
<field id="id" type="string" />
|
||||
<field id="title" type="string" />
|
||||
<field id="trackNumber" type="integer" />
|
||||
<field id="image" type="node" onChange="setPoster" />
|
||||
<field id="posterURL" type="string" />
|
||||
<field id="overview" type="string" />
|
||||
<field id="type" type="string" value="Song" />
|
||||
<field id="json" type="assocarray" onChange="setFields" />
|
||||
<field id="favorite" type="boolean" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="MusicSongData.brs" />
|
||||
</component>
|
||||
|
|
|
@ -15,10 +15,15 @@ function getData()
|
|||
|
||||
for each album in albumData.items
|
||||
gridAlbum = CreateObject("roSGNode", "ContentNode")
|
||||
|
||||
if not isValid(album.posterURL) or album.posterURL = ""
|
||||
album.posterURL = "pkg:/images/icons/album.png"
|
||||
end if
|
||||
|
||||
gridAlbum.shortdescriptionline1 = album.title
|
||||
gridAlbum.HDGRIDPOSTERURL = album.posterURL
|
||||
gridAlbum.hdposterurl = album.posterURL
|
||||
gridAlbum.SDGRIDPOSTERURL = album.SDGRIDPOSTERURL
|
||||
gridAlbum.SDGRIDPOSTERURL = album.posterURL
|
||||
gridAlbum.sdposterurl = album.posterURL
|
||||
|
||||
data.appendChild(gridAlbum)
|
||||
|
@ -47,6 +52,15 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.top.escape = key
|
||||
return true
|
||||
end if
|
||||
else if key = "down"
|
||||
totalCount = m.top.MusicArtistAlbumData.items.count()
|
||||
totalRows = div_ceiling(totalCount, 5)
|
||||
currentRow = div_ceiling(m.top.itemFocused + 1, 5)
|
||||
|
||||
if currentRow = totalRows
|
||||
m.top.escape = key
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
return false
|
||||
|
|
|
@ -5,4 +5,5 @@
|
|||
<field id="escape" type="string" alwaysNotify="true" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="AlbumGrid.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
</component>
|
||||
|
|
|
@ -8,8 +8,16 @@ sub init()
|
|||
m.albumHeader = m.top.findNode("albumHeader")
|
||||
m.albumHeader.text = tr("Albums")
|
||||
|
||||
m.appearsOnHeader = m.top.findNode("appearsOnHeader")
|
||||
m.appearsOnHeader.text = tr("AppearsOn")
|
||||
|
||||
m.appearsOn = m.top.findNode("appearsOn")
|
||||
m.appearsOn.observeField("escape", "onAppearsOnEscape")
|
||||
m.appearsOn.observeField("MusicArtistAlbumData", "onAppearsOnData")
|
||||
|
||||
m.albums = m.top.findNode("albums")
|
||||
m.albums.observeField("escape", "onAlbumsEscape")
|
||||
m.albums.observeField("MusicArtistAlbumData", "onAlbumsData")
|
||||
|
||||
m.pageLoadAnimation = m.top.findNode("pageLoad")
|
||||
m.pageLoadAnimation.control = "start"
|
||||
|
@ -33,15 +41,47 @@ sub init()
|
|||
createDialogPallete()
|
||||
end sub
|
||||
|
||||
sub onAlbumsData()
|
||||
' We have no album data
|
||||
if m.albums.MusicArtistAlbumData.TotalRecordCount = 0
|
||||
m.sectionScroller.removeChild(m.top.findNode("albumsSlide"))
|
||||
m.sectionNavigation.removeChild(m.top.findNode("albumsLink"))
|
||||
m.top.findNode("appearsOnSlide").callFunc("scrollUpToOnDeck")
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub onAppearsOnData()
|
||||
' We have no appears on data
|
||||
if m.appearsOn.MusicArtistAlbumData.TotalRecordCount = 0
|
||||
m.sectionScroller.removeChild(m.top.findNode("appearsOnSlide"))
|
||||
m.sectionNavigation.removeChild(m.top.findNode("appearsOnLink"))
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub onSectionScrollerChange()
|
||||
m.overhang.isVisible = (m.sectionScroller.displayedIndex = 0)
|
||||
end sub
|
||||
|
||||
sub OnScreenShown()
|
||||
m.sectionScroller.focus = true
|
||||
|
||||
if m.sectionScroller.displayedIndex = 0
|
||||
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
|
||||
m.top.selectedButtonIndex = 0
|
||||
m.buttonGrp.setFocus(true)
|
||||
else
|
||||
m.overhang.opacity = "0"
|
||||
m.overhang.isVisible = false
|
||||
m.overhang.opacity = "1"
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub OnScreenHidden()
|
||||
if not m.overhang.isVisible
|
||||
m.overhang.disableMoveAnimation = true
|
||||
m.overhang.isVisible = true
|
||||
m.overhang.disableMoveAnimation = false
|
||||
m.overhang.opacity = "1"
|
||||
end if
|
||||
end sub
|
||||
|
||||
|
@ -50,6 +90,18 @@ sub onAlbumsEscape()
|
|||
m.sectionNavigation.selected = m.sectionScroller.displayedIndex - 1
|
||||
else if m.albums.escape = "left"
|
||||
m.sectionNavigation.setFocus(true)
|
||||
else if m.albums.escape = "down"
|
||||
if m.sectionScroller.displayedIndex + 1 < m.sectionNavigation.getChildCount()
|
||||
m.sectionNavigation.selected = m.sectionScroller.displayedIndex + 1
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub onAppearsOnEscape()
|
||||
if m.appearsOn.escape = "up"
|
||||
m.sectionNavigation.selected = m.sectionScroller.displayedIndex - 1
|
||||
else if m.appearsOn.escape = "left"
|
||||
m.sectionNavigation.setFocus(true)
|
||||
end if
|
||||
end sub
|
||||
|
||||
|
@ -95,7 +147,6 @@ sub pageContentChanged()
|
|||
' Populate scene data
|
||||
setScreenTitle(item.json)
|
||||
setPosterImage(item.posterURL)
|
||||
setOnScreenTextValues(item.json)
|
||||
end sub
|
||||
|
||||
sub setScreenTitle(json)
|
||||
|
@ -129,10 +180,12 @@ sub setBackdropImage(data)
|
|||
end if
|
||||
end sub
|
||||
|
||||
' Populate on screen text variables
|
||||
sub setOnScreenTextValues(json)
|
||||
if isValid(json)
|
||||
setFieldTextValue("overview", json.overview)
|
||||
' Event fired when page data is loaded
|
||||
sub artistOverviewChanged()
|
||||
overviewContent = m.top.artistOverview
|
||||
|
||||
if isValid(overviewContent)
|
||||
setFieldTextValue("overview", overviewContent)
|
||||
end if
|
||||
end sub
|
||||
|
||||
|
@ -194,19 +247,17 @@ sub createDialogPallete()
|
|||
}
|
||||
end sub
|
||||
|
||||
sub OnScreenShown()
|
||||
m.sectionScroller.focus = true
|
||||
|
||||
if m.sectionScroller.displayedIndex = 0
|
||||
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
|
||||
m.top.selectedButtonIndex = 0
|
||||
m.buttonGrp.setFocus(true)
|
||||
end if
|
||||
end sub
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
|
||||
if m.buttonGrp.isInFocusChain()
|
||||
if key = "OK"
|
||||
if press
|
||||
selectedButton = m.buttonGrp.getChild(m.top.selectedButtonIndex)
|
||||
selectedButton.selected = not selectedButton.selected
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
if key = "left"
|
||||
if m.top.selectedButtonIndex > 0
|
||||
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
|
||||
|
@ -241,11 +292,13 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
end if
|
||||
|
||||
if key = "down"
|
||||
selectedButton = m.buttonGrp.getChild(m.top.selectedButtonIndex)
|
||||
selectedButton.focus = false
|
||||
if m.sectionNavigation.getChildCount() > 1
|
||||
selectedButton = m.buttonGrp.getChild(m.top.selectedButtonIndex)
|
||||
selectedButton.focus = false
|
||||
|
||||
m.top.selectedButtonIndex = 0
|
||||
m.sectionNavigation.selected = m.sectionScroller.displayedIndex + 1
|
||||
m.top.selectedButtonIndex = 0
|
||||
m.sectionNavigation.selected = m.sectionScroller.displayedIndex + 1
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
|
@ -19,20 +19,27 @@
|
|||
</LayoutGroup>
|
||||
</Section>
|
||||
|
||||
<Section id="slide-2" translation="[0, 1050]" defaultFocusID="albums">
|
||||
<Section id="albumsSlide" translation="[0, 950]" defaultFocusID="albums">
|
||||
<Rectangle id='albumRect' translation="[0, 0]" width="1920" height="1080" color="#000000" opacity=".75" />
|
||||
<Label id="albumHeader" translation="[120, 50]" font="font:LargeSystemFont" />
|
||||
<AlbumGrid id="albums" translation="[120, 150]" vertFocusAnimationStyle="fixedFocus" basePosterSize="[300, 300]" numColumns="5" numRows="99" caption1NumLines="1" itemSpacing="[50, 50]" />
|
||||
</Section>
|
||||
|
||||
<Section id="appearsOnSlide" translation="[0, 1100]" defaultFocusID="appearsOn">
|
||||
<Rectangle id='appearsOnRect' translation="[0, 0]" width="1920" height="1080" color="#000000" opacity=".75" />
|
||||
<Label id="appearsOnHeader" translation="[120, 50]" font="font:LargeSystemFont" />
|
||||
<AlbumGrid id="appearsOn" translation="[120, 150]" vertFocusAnimationStyle="fixedFocus" basePosterSize="[300, 300]" numColumns="5" numRows="99" caption1NumLines="1" itemSpacing="[50, 50]" />
|
||||
</Section>
|
||||
|
||||
</SectionScroller>
|
||||
|
||||
<bgv_ButtonGroupVert id="sectionNavigation" translation="[-100, 175]" itemSpacings="[10]">
|
||||
<sob_SlideOutButton background="#070707" focusBackground="#00a4dc" highlightBackground="#555555" padding="20" icon="pkg:/images/icons/details.png" text="Details" height="50" width="60" />
|
||||
<sob_SlideOutButton background="#070707" focusBackground="#00a4dc" highlightBackground="#555555" padding="20" icon="pkg:/images/icons/cd.png" text="Albums" height="50" width="60" />
|
||||
<sob_SlideOutButton id="albumsLink" background="#070707" focusBackground="#00a4dc" highlightBackground="#555555" padding="20" icon="pkg:/images/icons/cd.png" text="Albums" height="50" width="60" />
|
||||
<sob_SlideOutButton id="appearsOnLink" background="#070707" focusBackground="#00a4dc" highlightBackground="#555555" padding="20" icon="pkg:/images/icons/cassette.png" text="Appears On" height="50" width="60" />
|
||||
</bgv_ButtonGroupVert>
|
||||
|
||||
<Animation id="pageLoad" duration=".5" repeat="false">
|
||||
<Vector2DFieldInterpolator key="[0.0, .5]" keyValue="[[0, 1050], [0, 750]]" fieldToInterp="slide-2.translation" />
|
||||
<Animation id="pageLoad" duration="1" repeat="false">
|
||||
<Vector2DFieldInterpolator key="[0.5, 1.0]" keyValue="[[-100, 175], [40, 175]]" fieldToInterp="sectionNavigation.translation" />
|
||||
</Animation>
|
||||
|
||||
|
@ -40,7 +47,10 @@
|
|||
<interface>
|
||||
<field id="pageContent" type="node" onChange="pageContentChanged" />
|
||||
<field id="musicArtistAlbumData" type="assocarray" alias="albums.MusicArtistAlbumData" />
|
||||
<field id="musicArtistAppearsOnData" type="assocarray" alias="appearsOn.MusicArtistAlbumData" />
|
||||
<field id="artistOverview" type="string" onChange="artistOverviewChanged" />
|
||||
<field id="musicAlbumSelected" alias="albums.itemSelected" />
|
||||
<field id="appearsOnSelected" alias="appearsOn.itemSelected" />
|
||||
<field id="playArtistSelected" alias="play.selected" />
|
||||
<field id="instantMixSelected" alias="instantMix.selected" />
|
||||
<field id="selectedButtonIndex" type="integer" value="-1" />
|
||||
|
|
|
@ -15,6 +15,16 @@ sub init()
|
|||
m.scrollOffBottomPosition = m.top.findNode("scrollOffBottomPosition")
|
||||
m.scrollOffBottomOpacity = m.top.findNode("scrollOffBottomOpacity")
|
||||
|
||||
m.scrollUpToOnDeckAnimation = m.top.findNode("scrollUpToOnDeckAnimation")
|
||||
m.scrollUpToOnDeckPosition = m.top.findNode("scrollUpToOnDeckPosition")
|
||||
|
||||
m.scrollDownToOnDeckAnimation = m.top.findNode("scrollDownToOnDeckAnimation")
|
||||
m.scrollDownToOnDeckPosition = m.top.findNode("scrollDownToOnDeckPosition")
|
||||
|
||||
m.scrollOffOnDeckAnimation = m.top.findNode("scrollOffOnDeckAnimation")
|
||||
m.scrollOffOnDeckPosition = m.top.findNode("scrollOffOnDeckPosition")
|
||||
|
||||
m.top.observeField("translation", "onTranslationChange")
|
||||
m.top.observeField("id", "onIDChange")
|
||||
m.top.observeField("focusedChild", "onFocusChange")
|
||||
end sub
|
||||
|
@ -31,6 +41,18 @@ sub onIDChange()
|
|||
|
||||
m.scrollOffBottomPosition.fieldToInterp = m.top.id + ".translation"
|
||||
m.scrollOffBottomOpacity.fieldToInterp = m.top.id + ".opacity"
|
||||
|
||||
m.scrollUpToOnDeckPosition.fieldToInterp = m.top.id + ".translation"
|
||||
|
||||
m.scrollDownToOnDeckPosition.fieldToInterp = m.top.id + ".translation"
|
||||
|
||||
m.scrollOffOnDeckPosition.fieldToInterp = m.top.id + ".translation"
|
||||
end sub
|
||||
|
||||
sub onTranslationChange()
|
||||
m.startingPosition = m.top.translation
|
||||
m.scrollOffBottomPosition.keyValue = "[[0, 0], [" + str(m.startingPosition[0]) + ", " + str(m.startingPosition[1]) + "]]"
|
||||
m.top.unobserveField("translation")
|
||||
end sub
|
||||
|
||||
sub showFromTop()
|
||||
|
@ -49,6 +71,18 @@ sub scrollOffTop()
|
|||
m.scrollOffTopAnimation.control = "start"
|
||||
end sub
|
||||
|
||||
sub scrollUpToOnDeck()
|
||||
m.scrollUpToOnDeckAnimation.control = "start"
|
||||
end sub
|
||||
|
||||
sub scrollDownToOnDeck()
|
||||
m.scrollDownToOnDeckAnimation.control = "start"
|
||||
end sub
|
||||
|
||||
sub scrollOffOnDeck()
|
||||
m.scrollOffOnDeckAnimation.control = "start"
|
||||
end sub
|
||||
|
||||
sub onFocusChange()
|
||||
defaultFocusElement = m.top.findNode(m.top.defaultFocusID)
|
||||
|
||||
|
|
|
@ -3,19 +3,28 @@
|
|||
<children>
|
||||
<Animation id="showFromBottomAnimation" duration="0.5" repeat="false">
|
||||
<Vector2DFieldInterpolator id="showFromBottomPosition" key="[0.0, 1.0]" keyValue="[[0, 750], [0, 0]]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="showFromBottomOpacity" key="[0.0, 1.0]" keyValue="[0.75, 0.95]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="showFromBottomOpacity" key="[0.0, 1.0]" keyValue="[0.55, 0.95]" fieldToInterp="" />
|
||||
</Animation>
|
||||
<Animation id="showFromTopAnimation" duration="0.5" repeat="false">
|
||||
<Vector2DFieldInterpolator id="showFromTopPosition" key="[0.0, 1.0]" keyValue="[[0, -1080], [0, 0]]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="showFromTopOpacity" key="[0.0, 1.0]" keyValue="[0.75, 0.95]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="showFromTopOpacity" key="[0.0, 1.0]" keyValue="[0.55, 0.95]" fieldToInterp="" />
|
||||
</Animation>
|
||||
<Animation id="scrollOffBottomAnimation" duration="0.5" repeat="false">
|
||||
<Vector2DFieldInterpolator id="scrollOffBottomPosition" key="[0.0, 1.0]" keyValue="[[0, 0], [0, 750]]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="scrollOffBottomOpacity" key="[0.0, 1.0]" keyValue="[0.95, 0.75]" fieldToInterp="" />
|
||||
<Vector2DFieldInterpolator id="scrollOffBottomPosition" key="[0.0, 1.0]" keyValue="[]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="scrollOffBottomOpacity" key="[0.0, 1.0]" keyValue="[0.95, 0.55]" fieldToInterp="" />
|
||||
</Animation>
|
||||
<Animation id="scrollOffTopAnimation" duration="0.5" repeat="false">
|
||||
<Vector2DFieldInterpolator id="scrollOffTopPosition" key="[0.0, 1.0]" keyValue="[[0, 0], [0, -1080]]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="scrollOffTopOpacity" key="[0.0, 1.0]" keyValue="[0.95, 0.75]" fieldToInterp="" />
|
||||
<FloatFieldInterpolator id="scrollOffTopOpacity" key="[0.0, 1.0]" keyValue="[0.95, 0.55]" fieldToInterp="" />
|
||||
</Animation>
|
||||
<Animation id="scrollUpToOnDeckAnimation" duration="0.5" repeat="false">
|
||||
<Vector2DFieldInterpolator id="scrollUpToOnDeckPosition" key="[0.0, 1.0]" keyValue="[[0, 1100], [0, 950]]" fieldToInterp="" />
|
||||
</Animation>
|
||||
<Animation id="scrollDownToOnDeckAnimation" duration="0.5" repeat="false">
|
||||
<Vector2DFieldInterpolator id="scrollDownToOnDeckPosition" key="[0.0, 1.0]" keyValue="[[0, 0], [0, 950]]" fieldToInterp="" />
|
||||
</Animation>
|
||||
<Animation id="scrollOffOnDeckAnimation" duration="0.5" repeat="false">
|
||||
<Vector2DFieldInterpolator id="scrollOffOnDeckPosition" key="[0.0, 1.0]" keyValue="[[0, 950], [0, 1080]]" fieldToInterp="" />
|
||||
</Animation>
|
||||
</children>
|
||||
<interface>
|
||||
|
@ -24,6 +33,9 @@
|
|||
<function name="showFromBottom" />
|
||||
<function name="scrollOffTop" />
|
||||
<function name="scrollOffBottom" />
|
||||
<function name="scrollUpToOnDeck" />
|
||||
<function name="scrollDownToOnDeck" />
|
||||
<function name="scrollOffOnDeck" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
<script type="text/brightscript" uri="section.brs" />
|
||||
|
|
|
@ -24,13 +24,34 @@ sub displayedIndexChanged()
|
|||
displayedSection = m.top.getChild(m.top.displayedIndex)
|
||||
displayedSection.setFocus(true)
|
||||
|
||||
onDeckSection = invalid
|
||||
previouslyOnDeckSection = invalid
|
||||
|
||||
if m.top.displayedIndex + 1 <= (m.top.getChildCount() - 1)
|
||||
onDeckSection = m.top.getChild(m.top.displayedIndex + 1)
|
||||
end if
|
||||
|
||||
if m.top.displayedIndex + 2 <= (m.top.getChildCount() - 1)
|
||||
previouslyOnDeckSection = m.top.getChild(m.top.displayedIndex + 2)
|
||||
end if
|
||||
|
||||
' Move sections either up or down depending on what index we're moving to
|
||||
if m.top.displayedIndex > m.previouslyDisplayedSection
|
||||
m.top.getChild(m.previouslyDisplayedSection).callFunc("scrollOffTop")
|
||||
for i = m.previouslyDisplayedSection to m.top.displayedIndex - 1
|
||||
m.top.getChild(i).callFunc("scrollOffTop")
|
||||
end for
|
||||
|
||||
displayedSection.callFunc("showFromBottom")
|
||||
if isValid(onDeckSection)
|
||||
onDeckSection.callFunc("scrollUpToOnDeck")
|
||||
end if
|
||||
else if m.top.displayedIndex < m.previouslyDisplayedSection
|
||||
m.top.getChild(m.previouslyDisplayedSection).callFunc("scrollOffBottom")
|
||||
m.top.getChild(m.top.displayedIndex + 1).callFunc("scrollDownToOnDeck")
|
||||
displayedSection.callFunc("showFromTop")
|
||||
|
||||
if isValid(previouslyOnDeckSection)
|
||||
previouslyOnDeckSection.callFunc("scrollOffOnDeck")
|
||||
end if
|
||||
end if
|
||||
|
||||
m.previouslyDisplayedSection = m.top.displayedIndex
|
||||
|
|
BIN
images/icons/album.png
Normal file
BIN
images/icons/album.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
images/icons/cassette.png
Normal file
BIN
images/icons/cassette.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
|
@ -812,5 +812,10 @@
|
|||
<translation>WxH</translation>
|
||||
<extracomment>Video width x height</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to find any albums or songs belonging to this artist</source>
|
||||
<translation>Unable to find any albums or songs belonging to this artist</translation>
|
||||
<extracomment>Popup message when we find no audio data for an artist</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -159,6 +159,9 @@ sub Main (args as dynamic) as void
|
|||
' Nothing to do here, handled in ItemGrid
|
||||
else if selectedItem.type = "MusicArtist"
|
||||
group = CreateArtistView(selectedItem.json)
|
||||
if not isValid(group)
|
||||
message_dialog(tr("Unable to find any albums or songs belonging to this artist"))
|
||||
end if
|
||||
else if selectedItem.type = "MusicAlbum"
|
||||
group = CreateAlbumView(selectedItem.json)
|
||||
else if selectedItem.type = "Audio"
|
||||
|
@ -188,6 +191,12 @@ sub Main (args as dynamic) as void
|
|||
albums = msg.getRoSGNode()
|
||||
node = albums.musicArtistAlbumData.items[ptr]
|
||||
group = CreateAlbumView(node)
|
||||
else if isNodeEvent(msg, "appearsOnSelected")
|
||||
' If you select a Music Album from ANYWHERE, follow this flow
|
||||
ptr = msg.getData()
|
||||
albums = msg.getRoSGNode()
|
||||
node = albums.musicArtistAppearsOnData.items[ptr]
|
||||
group = CreateAlbumView(node)
|
||||
else if isNodeEvent(msg, "playSong")
|
||||
' User has selected audio they want us to play
|
||||
selectedIndex = msg.getData()
|
||||
|
|
|
@ -377,13 +377,26 @@ end function
|
|||
' Shows details on selected artist. Bio, image, and list of available albums
|
||||
function CreateArtistView(musicartist)
|
||||
musicData = MusicAlbumList(musicartist.id)
|
||||
appearsOnData = AppearsOnList(musicartist.id)
|
||||
|
||||
' User only has songs under artists
|
||||
if musicData = invalid or musicData.Items.Count() = 0
|
||||
if (musicData = invalid or musicData.Items.Count() = 0) and (appearsOnData = invalid or appearsOnData.Items.Count() = 0)
|
||||
' Just songs under artists...
|
||||
group = CreateObject("roSGNode", "AlbumView")
|
||||
group.pageContent = ItemMetaData(musicartist.id)
|
||||
group.albumData = MusicSongList(musicartist.id)
|
||||
|
||||
' Lookup songs based on artist id
|
||||
songList = GetSongsByArtist(musicartist.id)
|
||||
|
||||
if not isValid(songList)
|
||||
' Lookup songs based on folder parent / child relationship
|
||||
songList = MusicSongList(musicartist.id)
|
||||
end if
|
||||
|
||||
if not isValid(songList)
|
||||
return invalid
|
||||
end if
|
||||
|
||||
group.albumData = songList
|
||||
group.observeField("playSong", m.port)
|
||||
group.observeField("playAllSelected", m.port)
|
||||
group.observeField("instantMixSelected", m.port)
|
||||
|
@ -392,9 +405,13 @@ function CreateArtistView(musicartist)
|
|||
group = CreateObject("roSGNode", "ArtistView")
|
||||
group.pageContent = ItemMetaData(musicartist.id)
|
||||
group.musicArtistAlbumData = musicData
|
||||
group.musicArtistAppearsOnData = appearsOnData
|
||||
group.artistOverview = ArtistOverview(musicartist.name)
|
||||
|
||||
group.observeField("musicAlbumSelected", m.port)
|
||||
group.observeField("playArtistSelected", m.port)
|
||||
group.observeField("instantMixSelected", m.port)
|
||||
group.observeField("appearsOnSelected", m.port)
|
||||
end if
|
||||
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
|
@ -531,8 +548,6 @@ function CreateArtistMixGroup(artistID)
|
|||
songIDArray.push(song.id)
|
||||
end for
|
||||
|
||||
songIDArray.shift()
|
||||
|
||||
group.pageContent = songIDArray
|
||||
group.musicArtistAlbumData = songList.items
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ function ItemMetaData(id as string)
|
|||
if data = invalid then return invalid
|
||||
imgParams = {}
|
||||
if data.type <> "Audio"
|
||||
if data.UserData.PlayedPercentage <> invalid
|
||||
if data?.UserData?.PlayedPercentage <> invalid
|
||||
param = { "PercentPlayed": data.UserData.PlayedPercentage }
|
||||
imgParams.Append(param)
|
||||
end if
|
||||
|
@ -163,21 +163,82 @@ function ItemMetaData(id as string)
|
|||
end if
|
||||
end function
|
||||
|
||||
' Music Artist Data
|
||||
function ArtistOverview(name as string)
|
||||
req = createObject("roUrlTransfer")
|
||||
url = Substitute("Artists/{0}", req.escape(name))
|
||||
resp = APIRequest(url)
|
||||
data = getJson(resp)
|
||||
if data = invalid then return invalid
|
||||
return data.overview
|
||||
end function
|
||||
|
||||
' Get list of albums belonging to an artist
|
||||
function MusicAlbumList(id as string)
|
||||
url = Substitute("Users/{0}/Items", get_setting("active_user"), id)
|
||||
url = Substitute("Users/{0}/Items", get_setting("active_user"))
|
||||
resp = APIRequest(url, {
|
||||
"UserId": get_setting("active_user"),
|
||||
"parentId": id,
|
||||
"AlbumArtistIds": id,
|
||||
"includeitemtypes": "MusicAlbum",
|
||||
"sortBy": "SortName"
|
||||
"sortBy": "SortName",
|
||||
"Recursive": true
|
||||
})
|
||||
|
||||
data = getJson(resp)
|
||||
results = []
|
||||
for each item in data.Items
|
||||
tmp = CreateObject("roSGNode", "MusicAlbumData")
|
||||
tmp.image = PosterImage(item.id, { "maxHeight": "500", "maxWidth": "500" })
|
||||
tmp.image = PosterImage(item.id)
|
||||
tmp.json = item
|
||||
results.push(tmp)
|
||||
end for
|
||||
data.Items = results
|
||||
return data
|
||||
end function
|
||||
|
||||
' Get list of albums an artist appears on
|
||||
function AppearsOnList(id as string)
|
||||
url = Substitute("Users/{0}/Items", get_setting("active_user"))
|
||||
resp = APIRequest(url, {
|
||||
"ContributingArtistIds": id,
|
||||
"ExcludeItemIds": id,
|
||||
"includeitemtypes": "MusicAlbum",
|
||||
"sortBy": "PremiereDate,ProductionYear,SortName",
|
||||
"SortOrder": "Descending",
|
||||
"Recursive": true
|
||||
})
|
||||
|
||||
data = getJson(resp)
|
||||
results = []
|
||||
for each item in data.Items
|
||||
tmp = CreateObject("roSGNode", "MusicAlbumData")
|
||||
tmp.image = PosterImage(item.id)
|
||||
tmp.json = item
|
||||
results.push(tmp)
|
||||
end for
|
||||
data.Items = results
|
||||
return data
|
||||
end function
|
||||
|
||||
' Get list of songs belonging to an artist
|
||||
function GetSongsByArtist(id as string)
|
||||
url = Substitute("Users/{0}/Items", get_setting("active_user"))
|
||||
resp = APIRequest(url, {
|
||||
"AlbumArtistIds": id,
|
||||
"includeitemtypes": "Audio",
|
||||
"sortBy": "SortName",
|
||||
"Recursive": true
|
||||
})
|
||||
|
||||
data = getJson(resp)
|
||||
results = []
|
||||
|
||||
if data = invalid then return invalid
|
||||
if data.Items = invalid then return invalid
|
||||
if data.Items.Count() = 0 then return invalid
|
||||
|
||||
for each item in data.Items
|
||||
tmp = CreateObject("roSGNode", "MusicAlbumData")
|
||||
tmp.image = PosterImage(item.id)
|
||||
tmp.json = item
|
||||
results.push(tmp)
|
||||
end for
|
||||
|
@ -195,8 +256,13 @@ function MusicSongList(id as string)
|
|||
"sortBy": "SortName"
|
||||
})
|
||||
|
||||
data = getJson(resp)
|
||||
results = []
|
||||
data = getJson(resp)
|
||||
|
||||
if data = invalid then return invalid
|
||||
if data.Items = invalid then return invalid
|
||||
if data.Items.Count() = 0 then return invalid
|
||||
|
||||
for each item in data.Items
|
||||
tmp = CreateObject("roSGNode", "MusicSongData")
|
||||
tmp.image = PosterImage(item.id)
|
||||
|
@ -232,15 +298,18 @@ end function
|
|||
|
||||
' Get Instant Mix based on item
|
||||
function CreateArtistMix(id as string)
|
||||
url = Substitute("Users/{0}/Items", get_setting("active_user"), id)
|
||||
url = Substitute("Users/{0}/Items", get_setting("active_user"))
|
||||
resp = APIRequest(url, {
|
||||
"UserId": get_setting("active_user"),
|
||||
"parentId": id,
|
||||
"Filters": "IsNotFolder",
|
||||
"Recursive": true,
|
||||
"SortBy": "SortName",
|
||||
"ArtistIds": id,
|
||||
"Recursive": "true",
|
||||
"MediaTypes": "Audio",
|
||||
"Limit": 300
|
||||
"Filters": "IsNotFolder",
|
||||
"SortBy": "SortName",
|
||||
"Limit": 300,
|
||||
"Fields": "Chapters",
|
||||
"ExcludeLocationTypes": "Virtual",
|
||||
"EnableTotalRecordCount": false,
|
||||
"CollapseBoxSetItems": false
|
||||
})
|
||||
|
||||
return getJson(resp)
|
||||
|
|
Loading…
Reference in New Issue
Block a user