Add scrub function to audio trickplay bar
This commit is contained in:
parent
9e5bdd4979
commit
39c73755b4
|
@ -5,6 +5,7 @@ import "pkg:/source/utils/config.bs"
|
|||
|
||||
sub init()
|
||||
m.top.optionsAvailable = false
|
||||
m.inScrubMode = false
|
||||
|
||||
setupAudioNode()
|
||||
setupAnimationTasks()
|
||||
|
@ -32,6 +33,8 @@ sub init()
|
|||
pageContentChanged()
|
||||
setShuffleIconState()
|
||||
setLoopButtonImage()
|
||||
|
||||
m.buttons.setFocus(true)
|
||||
end sub
|
||||
|
||||
sub onScreensaverTimeoutLoaded()
|
||||
|
@ -117,6 +120,7 @@ sub setupInfoNodes()
|
|||
m.playPosition = m.top.findNode("playPosition")
|
||||
m.bufferPosition = m.top.findNode("bufferPosition")
|
||||
m.seekBar = m.top.findNode("seekBar")
|
||||
m.thumb = m.top.findNode("thumb")
|
||||
m.shuffleIndicator = m.top.findNode("shuffleIndicator")
|
||||
m.loopIndicator = m.top.findNode("loopIndicator")
|
||||
m.positionTimestamp = m.top.findNode("positionTimestamp")
|
||||
|
@ -124,6 +128,8 @@ sub setupInfoNodes()
|
|||
end sub
|
||||
|
||||
sub bufferPositionChanged()
|
||||
if m.inScrubMode then return
|
||||
|
||||
if not isValid(m.global.audioPlayer.bufferingStatus)
|
||||
bufferPositionBarWidth = m.seekBar.width
|
||||
else
|
||||
|
@ -141,6 +147,10 @@ sub bufferPositionChanged()
|
|||
end sub
|
||||
|
||||
sub audioPositionChanged()
|
||||
if m.inScrubMode then return
|
||||
|
||||
stopLoadingSpinner()
|
||||
|
||||
if m.global.audioPlayer.position = 0
|
||||
m.playPosition.width = 0
|
||||
end if
|
||||
|
@ -159,6 +169,8 @@ sub audioPositionChanged()
|
|||
playPositionBarWidth = m.seekBar.width
|
||||
end if
|
||||
|
||||
moveSeekbarThumb(playPositionBarWidth)
|
||||
|
||||
' Use animation to make the display smooth
|
||||
m.playPositionAnimationWidth.keyValue = [m.playPosition.width, playPositionBarWidth]
|
||||
m.playPositionAnimation.control = "start"
|
||||
|
@ -217,6 +229,7 @@ sub audioStateChanged()
|
|||
if m.global.audioPlayer.state = "finished"
|
||||
' User has enabled single song loop, play current song again
|
||||
if m.global.audioPlayer.loopMode = "one"
|
||||
m.global.audioPlayer.content.playStart = 0
|
||||
playAction()
|
||||
return
|
||||
end if
|
||||
|
@ -255,6 +268,13 @@ function playAction() as boolean
|
|||
' Write screen tracker for screensaver
|
||||
WriteAsciiFile("tmp:/scene.temp", "nowplaying")
|
||||
MoveFile("tmp:/scene.temp", "tmp:/scene")
|
||||
else if m.global.audioPlayer.state = "buffering"
|
||||
m.inScrubMode = false
|
||||
startLoadingSpinner()
|
||||
m.global.audioPlayer.control = "play"
|
||||
' Write screen tracker for screensaver
|
||||
WriteAsciiFile("tmp:/scene.temp", "nowplaying")
|
||||
MoveFile("tmp:/scene.temp", "tmp:/scene")
|
||||
end if
|
||||
|
||||
return true
|
||||
|
@ -540,6 +560,72 @@ sub setBackdropImage(data)
|
|||
end if
|
||||
end sub
|
||||
|
||||
' setSelectedButtonState: Changes the icon state url for the currently selected button
|
||||
'
|
||||
' @param {string} oldState - current state to replace in icon url
|
||||
' @param {string} newState - state to replace {oldState} with in icon url
|
||||
sub setSelectedButtonState(oldState as string, newState as string)
|
||||
selectedButton = m.buttons.getChild(m.top.selectedButtonIndex)
|
||||
selectedButton.uri = selectedButton.uri.Replace(oldState, newState)
|
||||
end sub
|
||||
|
||||
' processScrubAction: Handles +/- seeking for the audio trickplay bar
|
||||
'
|
||||
' @param {integer} seekStep - seconds to move the trickplay position (negative values allowed)
|
||||
sub processScrubAction(seekStep as integer)
|
||||
m.inScrubMode = true
|
||||
' Change audio player control method
|
||||
m.global.audioPlayer.control = "prebuffer"
|
||||
|
||||
' Prepare starting playStart property value
|
||||
if m.global.audioPlayer.position <> 0
|
||||
m.global.audioPlayer.content.playStart = m.global.audioPlayer.position
|
||||
end if
|
||||
|
||||
' Don't let seek to go past the end of the song
|
||||
if m.global.audioPlayer.content.playStart + seekStep > m.songDuration
|
||||
return
|
||||
end if
|
||||
|
||||
if seekStep > 0
|
||||
' Move seek forward
|
||||
m.global.audioPlayer.content.playStart += seekStep
|
||||
else if m.global.audioPlayer.content.playStart >= Abs(seekStep)
|
||||
' If back seek won't go below 0, move seek back
|
||||
m.global.audioPlayer.content.playStart += seekStep
|
||||
else
|
||||
' Back seek would go below 0, set to 0 directly
|
||||
m.global.audioPlayer.content.playStart = 0
|
||||
end if
|
||||
|
||||
' Move the seedbar thumb forward
|
||||
songPercentComplete = m.global.audioPlayer.content.playStart / m.songDuration
|
||||
playPositionBarWidth = m.seekBar.width * songPercentComplete
|
||||
|
||||
moveSeekbarThumb(playPositionBarWidth)
|
||||
|
||||
' Change the displayed position timestamp
|
||||
m.positionTimestamp.text = secondsToHuman(m.global.audioPlayer.content.playStart, false)
|
||||
end sub
|
||||
|
||||
' moveSeekbarThumb: Positions the thumb on the seekbar
|
||||
'
|
||||
' @param {float} playPositionBarWidth - width of the play position bar
|
||||
sub moveSeekbarThumb(playPositionBarWidth as float)
|
||||
' Center the thumb on the play position bar
|
||||
thumbPostionLeft = playPositionBarWidth - 10
|
||||
|
||||
' Don't let thumb go below 0
|
||||
if thumbPostionLeft < 0 then thumbPostionLeft = 0
|
||||
|
||||
' Don't let thumb go past end of seekbar
|
||||
if thumbPostionLeft > m.seekBar.width - 25
|
||||
thumbPostionLeft = m.seekBar.width - 25
|
||||
end if
|
||||
|
||||
m.thumb.translation = [thumbPostionLeft, m.thumb.translation[1]]
|
||||
end sub
|
||||
|
||||
' Process key press events
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
|
||||
|
@ -551,9 +637,55 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
return true
|
||||
end if
|
||||
|
||||
' Key Event handler when m.thumb is in focus
|
||||
if m.thumb.hasFocus()
|
||||
if key = "right"
|
||||
processScrubAction(10)
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "left"
|
||||
processScrubAction(-10)
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "OK" or key = "play"
|
||||
if m.inScrubMode
|
||||
startLoadingSpinner()
|
||||
m.inScrubMode = false
|
||||
m.global.audioPlayer.control = "play"
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
if key = "play"
|
||||
return playAction()
|
||||
else if key = "back"
|
||||
end if
|
||||
|
||||
if key = "up"
|
||||
if not m.thumb.visible
|
||||
m.thumb.visible = true
|
||||
setSelectedButtonState("-selected", "-default")
|
||||
end if
|
||||
|
||||
m.thumb.setFocus(true)
|
||||
m.buttons.setFocus(false)
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "down"
|
||||
if m.thumb.visible
|
||||
m.thumb.visible = false
|
||||
setSelectedButtonState("-default", "-selected")
|
||||
end if
|
||||
|
||||
m.buttons.setFocus(true)
|
||||
m.thumb.setFocus(false)
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "back"
|
||||
m.global.audioPlayer.control = "stop"
|
||||
m.global.audioPlayer.loopMode = ""
|
||||
else if key = "rewind"
|
||||
|
@ -561,6 +693,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
else if key = "fastforward"
|
||||
return nextClicked()
|
||||
else if key = "left"
|
||||
if m.buttons.hasFocus()
|
||||
if m.global.queueManager.callFunc("getCount") = 1 then return false
|
||||
|
||||
if m.top.selectedButtonIndex > 0
|
||||
|
@ -568,13 +701,17 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.top.selectedButtonIndex = m.top.selectedButtonIndex - 1
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
else if key = "right"
|
||||
if m.buttons.hasFocus()
|
||||
if m.global.queueManager.callFunc("getCount") = 1 then return false
|
||||
|
||||
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
|
||||
if m.top.selectedButtonIndex < m.buttonCount - 1 then m.top.selectedButtonIndex = m.top.selectedButtonIndex + 1
|
||||
return true
|
||||
end if
|
||||
else if key = "OK"
|
||||
if m.buttons.hasFocus()
|
||||
if m.buttons.getChild(m.top.selectedButtonIndex).id = "play"
|
||||
return playAction()
|
||||
else if m.buttons.getChild(m.top.selectedButtonIndex).id = "previous"
|
||||
|
@ -588,6 +725,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<Poster id="backdrop" opacity=".5" loadDisplayMode="scaleToZoom" width="1920" height="1200" blendColor="#3f3f3f" />
|
||||
<Poster id="shuffleIndicator" width="64" height="64" uri="pkg:/images/icons/shuffleIndicator-off.png" translation="[1150,775]" opacity="0" />
|
||||
<Poster id="loopIndicator" width="64" height="64" uri="pkg:/images/icons/loopIndicator-off.png" translation="[700,775]" opacity="0" />
|
||||
<Label id="positionTimestamp" width="100" height="25" horizAlign="right" font="font:SmallestSystemFont" translation="[590,825]" color="#999999" text="0:00" />
|
||||
<Label id="totalLengthTimestamp" width="100" height="25" horizAlign="left" font="font:SmallestSystemFont" translation="[1230,825]" color="#999999" />
|
||||
<Label id="positionTimestamp" width="100" height="25" horizAlign="right" font="font:SmallestSystemFont" translation="[590,838]" color="#999999" text="0:00" />
|
||||
<Label id="totalLengthTimestamp" width="100" height="25" horizAlign="left" font="font:SmallestSystemFont" translation="[1230,838]" color="#999999" />
|
||||
<LayoutGroup id="toplevel" layoutDirection="vert" horizAlignment="center" translation="[960,175]" itemSpacings="[40]">
|
||||
<LayoutGroup id="main_group" layoutDirection="vert" horizAlignment="center" itemSpacings="[15]">
|
||||
<Poster id="albumCover" width="500" height="500" />
|
||||
|
@ -16,6 +16,7 @@
|
|||
<Rectangle id="seekBar" color="0x00000099" width="500" height="10">
|
||||
<Rectangle id="bufferPosition" color="0xFFFFFF44" height="10"></Rectangle>
|
||||
<Rectangle id="playPosition" color="#00a4dcFF" height="10"></Rectangle>
|
||||
<Poster id="thumb" width="25" height="25" uri="pkg:/images/icons/circle.png" visible="false" translation="[0, -10]" />
|
||||
</Rectangle>
|
||||
<LayoutGroup id="buttons" layoutDirection="horiz" horizAlignment="center" itemSpacings="[45]">
|
||||
<Poster id="loop" width="64" height="64" uri="pkg:/images/icons/loop-default.png" opacity="0" />
|
||||
|
|
BIN
images/icons/circle.png
Normal file
BIN
images/icons/circle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Loading…
Reference in New Issue
Block a user