Add play/pause, auto-hide, subtitle, video info, adjust pause logic

This commit is contained in:
1hitsong 2023-11-06 14:05:21 -05:00
parent 4c394dc7e7
commit 7fdac1b489
12 changed files with 357 additions and 95 deletions

39
components/Clock.bs Normal file
View File

@ -0,0 +1,39 @@
import "pkg:/source/utils/misc.brs"
sub init()
' If hideclick setting is checked, exit without setting any variables
if m.global.session.user.settings["ui.design.hideclock"]
return
end if
m.clockTime = m.top.findNode("clockTime")
m.currentTimeTimer = m.top.findNode("currentTimeTimer")
m.dateTimeObject = CreateObject("roDateTime")
m.currentTimeTimer.observeField("fire", "onCurrentTimeTimerFire")
m.currentTimeTimer.control = "start"
' Default to 12 hour clock
m.format = "short-h12"
' If user has selected a 24 hour clock, update date display format
if LCase(m.global.device.clockFormat) = "24h"
m.format = "short-h24"
end if
end sub
' onCurrentTimeTimerFire: Code that runs every time the currentTimeTimer fires
'
sub onCurrentTimeTimerFire()
' Refresh time variable
m.dateTimeObject.Mark()
' Convert to local time zone
m.dateTimeObject.ToLocalTime()
' Format time as requested
m.clockTime.text = m.dateTimeObject.asTimeStringLoc(m.format)
end sub

9
components/Clock.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="Clock" extends="Group" initialFocus="chapterNext">
<children>
<Label id="clockTime" font="font:SmallSystemFont" horizAlign="right" vertAlign="center" height="64" width="200" />
<Timer id="currentTimeTimer" repeat="true" duration="1" />
</children>
<interface>
</interface>
</component>

View File

@ -1,63 +0,0 @@
import "pkg:/source/utils/misc.brs"
sub init()
m.chapterNavigation = m.top.findNode("chapterNavigation")
m.selectedButtonIndex = 0
m.chapterNavigation.getChild(m.selectedButtonIndex).focus = true
end sub
sub onButtonSelected()
selectedButton = m.chapterNavigation.getChild(m.selectedButtonIndex)
if LCase(selectedButton.id) = "chapterlist"
m.top.showChapterList = not m.top.showChapterList
end if
m.top.action = selectedButton.id
end sub
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false
if key = "OK"
onButtonSelected()
return true
end if
if key = "right"
if m.selectedButtonIndex + 1 >= m.chapterNavigation.getChildCount()
return true
end if
selectedButton = m.chapterNavigation.getChild(m.selectedButtonIndex)
selectedButton.focus = false
m.selectedButtonIndex++
selectedButton = m.chapterNavigation.getChild(m.selectedButtonIndex)
selectedButton.focus = true
return true
end if
if key = "left"
if m.selectedButtonIndex = 0
return true
end if
selectedButton = m.chapterNavigation.getChild(m.selectedButtonIndex)
selectedButton.focus = false
m.selectedButtonIndex--
selectedButton = m.chapterNavigation.getChild(m.selectedButtonIndex)
selectedButton.focus = true
return true
end if
' All other keys hide the menu
m.top.action = "hide"
return true
end function

View File

@ -0,0 +1,206 @@
import "pkg:/source/utils/misc.brs"
sub init()
m.videoControls = m.top.findNode("videoControls")
m.optionControls = m.top.findNode("optionControls")
m.inactivityTimer = m.top.findNode("inactivityTimer")
m.itemTitle = m.top.findNode("itemTitle")
m.videoPlayPause = m.top.findNode("videoPlayPause")
m.top.observeField("visible", "onVisibleChanged")
m.top.observeField("playbackState", "onPlaybackStateChanged")
m.top.observeField("itemTitleText", "onItemTitleTextChanged")
m.defaultButtonIndex = 1
m.focusedButtonIndex = 1
m.videoControls.getChild(m.defaultButtonIndex).focus = true
m.deviceInfo = CreateObject("roDeviceInfo")
end sub
' onPlaybackStateChanged: Handler for changes to m.top.playbackState param
'
sub onPlaybackStateChanged()
if LCase(m.top.playbackState) = "playing"
m.videoPlayPause.icon = "pkg:/images/icons/pause.png"
return
end if
m.videoPlayPause.icon = "pkg:/images/icons/play.png"
end sub
' onItemTitleTextChanged: Handler for changes to m.top.itemTitleText param.
'
sub onItemTitleTextChanged()
m.itemTitle.text = m.top.itemTitleText
end sub
' resetFocusToDefaultButton: Reset focus back to the default button
'
sub resetFocusToDefaultButton()
' Remove focus from previously selected button
for each child in m.videoControls.getChildren(-1, 0)
if isValid(child.focus)
child.focus = false
end if
end for
for each child in m.optionControls.getChildren(-1, 0)
if isValid(child.focus)
child.focus = false
end if
end for
m.optionControls.setFocus(false)
' Set focus back to the default button
m.videoControls.setFocus(true)
m.focusedButtonIndex = m.defaultButtonIndex
m.videoControls.getChild(m.defaultButtonIndex).focus = true
end sub
' onVisibleChanged: Handler for changes to the visibility of this pause menu.
'
sub onVisibleChanged()
if m.top.visible
resetFocusToDefaultButton()
m.inactivityTimer.observeField("fire", "inactiveCheck")
m.inactivityTimer.control = "start"
return
end if
m.inactivityTimer.unobserveField("fire")
m.inactivityTimer.control = "stop"
end sub
' inactiveCheck: Checks if the time since last keypress is greater than or equal to the allowed inactive time of the pause menu.
'
sub inactiveCheck()
if LCase(m.top.playbackState) <> "playing" then return
if m.deviceInfo.timeSinceLastKeypress() >= m.top.inactiveTimeout
m.top.action = "hide"
end if
end sub
' onButtonSelected: Handler for selection of buttons from the pause menu.
'
sub onButtonSelected()
if m.optionControls.isInFocusChain()
buttonGroup = m.optionControls
else
buttonGroup = m.videoControls
end if
selectedButton = buttonGroup.getChild(m.focusedButtonIndex)
if LCase(selectedButton.id) = "chapterlist"
m.top.showChapterList = not m.top.showChapterList
end if
m.top.action = selectedButton.id
end sub
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false
if key = "OK"
onButtonSelected()
return true
end if
if key = "play"
m.top.action = "videoplaypause"
return true
end if
if key = "right"
if m.optionControls.isInFocusChain()
buttonGroup = m.optionControls
else
buttonGroup = m.videoControls
end if
if m.focusedButtonIndex + 1 >= buttonGroup.getChildCount()
return true
end if
focusedButton = buttonGroup.getChild(m.focusedButtonIndex)
focusedButton.focus = false
' Skip spacer elements until next button is found
for i = m.focusedButtonIndex + 1 to buttonGroup.getChildCount()
m.focusedButtonIndex = i
focusedButton = buttonGroup.getChild(m.focusedButtonIndex)
if isValid(focusedButton.focus)
focusedButton.focus = true
exit for
end if
end for
return true
end if
if key = "left"
if m.focusedButtonIndex = 0
return true
end if
if m.optionControls.isInFocusChain()
buttonGroup = m.optionControls
else
buttonGroup = m.videoControls
end if
focusedButton = buttonGroup.getChild(m.focusedButtonIndex)
focusedButton.focus = false
' Skip spacer elements until next button is found
for i = m.focusedButtonIndex - 1 to 0 step -1
m.focusedButtonIndex = i
focusedButton = buttonGroup.getChild(m.focusedButtonIndex)
if isValid(focusedButton.focus)
focusedButton.focus = true
exit for
end if
end for
return true
end if
if key = "up"
if m.videoControls.isInFocusChain()
focusedButton = m.videoControls.getChild(m.focusedButtonIndex)
focusedButton.focus = false
m.videoControls.setFocus(false)
m.focusedButtonIndex = 2
focusedButton = m.optionControls.getChild(m.focusedButtonIndex)
focusedButton.focus = true
m.optionControls.setFocus(true)
end if
return true
end if
if key = "down"
if m.optionControls.isInFocusChain()
focusedButton = m.optionControls.getChild(m.focusedButtonIndex)
focusedButton.focus = false
m.optionControls.setFocus(false)
m.focusedButtonIndex = m.defaultButtonIndex
focusedButton = m.videoControls.getChild(m.defaultButtonIndex)
focusedButton.focus = true
m.videoControls.setFocus(true)
end if
return true
end if
' All other keys hide the menu
m.top.action = "hide"
return true
end function

View File

@ -1,13 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="PauseMenu" extends="Group" initialFocus="chapterNext">
<children>
<ButtonGroup id="chapterNavigation" itemSpacings="[20]" layoutDirection="horiz">
<IconButton id="chapterList" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/numberList.png" height="65" width="100" />
<IconButton id="chapterBack" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/previous.png" height="65" width="100" />
<IconButton id="chapterNext" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/next.png" height="65" width="100" />
<Label id="itemTitle" font="font:LargeBoldSystemFont" translation="[103,61]" />
<Clock id="clock" translation="[1618, 46]" />
<ButtonGroup id="optionControls" itemSpacings="[20]" layoutDirection="horiz" horizAlignment="left" translation="[103,120]">
<IconButton id="showVideoInfoPopup" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/videoInfo.png" height="65" width="100" />
<IconButton id="chapterList" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/numberList.png" height="65" width="100" />
<IconButton id="showSubtitleMenu" background="#070707" focusBackground="#00a4dc" padding="0" icon="pkg:/images/icons/subtitle.png" height="65" width="100" />
</ButtonGroup>
<ButtonGroup id="videoControls" itemSpacings="[20]" layoutDirection="horiz" horizAlignment="center" translation="[960,950]">
<IconButton id="chapterBack" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/previousChapter.png" height="65" width="100" />
<IconButton id="videoPlayPause" background="#070707" focusBackground="#00a4dc" padding="35" icon="pkg:/images/icons/play.png" height="65" width="100" />
<IconButton id="chapterNext" background="#070707" focusBackground="#00a4dc" padding="16" icon="pkg:/images/icons/nextChapter.png" height="65" width="100" />
</ButtonGroup>
<Timer id="inactivityTimer" duration="1" repeat="true" />
</children>
<interface>
<field id="itemTitleText" type="string" />
<field id="inactiveTimeout" type="integer" />
<field id="playbackState" type="string" alwaysNotify="true" />
<field id="action" type="string" alwaysNotify="true" />
<field id="showChapterList" type="boolean" alwaysNotify="true" />
</interface>

View File

@ -92,16 +92,21 @@ end sub
' handleHideAction: Handles action to hide pause menu
'
sub handleHideAction()
' @param {boolean} resume - controls whether or not to resume video playback when sub is called
'
sub handleHideAction(resume as boolean)
m.pauseMenu.visible = false
m.chapterList.visible = false
m.pauseMenu.showChapterList = false
m.chapterList.setFocus(false)
m.pauseMenu.setFocus(false)
m.top.setFocus(true)
m.top.control = "resume"
if resume
m.top.control = "resume"
end if
end sub
' handleHideAction: Handles action to show chapter list
' handleChapterListAction: Handles action to show chapter list
'
sub handleChapterListAction()
m.chapterList.visible = m.pauseMenu.showChapterList
@ -136,13 +141,45 @@ function getCurrentChapterIndex() as integer
return currentChapter
end function
' handleVideoPlayPauseAction: Handles action to either play or pause the video content
'
sub handleVideoPlayPauseAction()
' If video is paused, resume it
if m.top.state = "paused"
m.top.control = "resume"
return
end if
' Pause video
m.top.control = "pause"
end sub
' handleShowSubtitleMenuAction: Handles action to show subtitle selection menu
'
sub handleShowSubtitleMenuAction()
m.top.selectSubtitlePressed = true
handleHideAction(false)
end sub
' handleShowVideoInfoPopupAction: Handles action to show video info popup
'
sub handleShowVideoInfoPopupAction()
m.top.selectPlaybackInfoPressed = true
handleHideAction(false)
end sub
' onPauseMenuAction: Process action events from pause menu to their respective handlers
'
sub onPauseMenuAction()
action = LCase(m.pauseMenu.action)
if action = "hide"
handleHideAction()
handleHideAction(false)
return
end if
if action = "play"
handleHideAction(true)
return
end if
@ -155,6 +192,21 @@ sub onPauseMenuAction()
handleChapterListAction()
return
end if
if action = "videoplaypause"
handleVideoPlayPauseAction()
return
end if
if action = "showsubtitlemenu"
handleShowSubtitleMenuAction()
return
end if
if action = "showvideoinfopopup"
handleShowVideoInfoPopupAction()
return
end if
end sub
' Only setup caption items if captions are allowed
@ -265,6 +317,8 @@ sub onVideoContentLoaded()
m.top.transcodeParams = videoContent[0].transcodeparams
m.chapters = videoContent[0].chapters
m.pauseMenu.itemTitleText = m.top.content.title
populateChapterMenu()
if m.LoadMetaDataTask.isIntro
@ -381,6 +435,9 @@ sub onState(msg)
m.captionTask.playerState = m.top.state + m.top.globalCaptionMode
end if
' Pass video state into pause menu
m.pauseMenu.playbackState = m.top.state
' When buffering, start timer to monitor buffering process
if m.top.state = "buffering" and m.bufferCheckTimer <> invalid
@ -488,7 +545,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
if m.chapterMenu.hasFocus()
if not press then return false
if key = "OK" or key = "play"
if key = "OK"
focusedChapter = m.chapterMenu.itemFocused
selectedChapter = m.chapterMenu.content.getChild(focusedChapter)
seekTime = selectedChapter.playstart
@ -508,6 +565,10 @@ function onKeyEvent(key as string, press as boolean) as boolean
return true
end if
if key = "play"
handleVideoPlayPauseAction()
end if
return true
end if
@ -543,31 +604,27 @@ function onKeyEvent(key as string, press as boolean) as boolean
return true
end if
else if key = "OK"
' OK will play/pause depending on current state
' return false to allow selection during seeking
if m.top.state = "paused"
m.top.control = "resume"
return false
else if m.top.state = "playing"
m.top.control = "pause"
' Disable pause menu for intro videos
if not m.LoadMetaDataTask.isIntro
' Show pause menu
m.top.control = "pause"
m.pauseMenu.visible = true
m.pauseMenu.setFocus(true)
return true
end if
return false
else if key = "OK" and not m.top.trickPlayBar.visible
if not m.LoadMetaDataTask.isIntro
' Show pause menu, but don't pause video
m.pauseMenu.visible = true
m.pauseMenu.setFocus(true)
return true
end if
return false
end if
' Disable pause menu for intro videos
if not m.LoadMetaDataTask.isIntro
if key = "play"
' Show pause menu
if key = "play" and not m.top.trickPlayBar.visible
' If video is paused, resume it and don't show pause menu
if m.top.state = "paused"
m.top.control = "resume"
return true
end if
' Pause video and show pause menu
m.top.control = "pause"
m.pauseMenu.visible = true
m.pauseMenu.setFocus(true)

View File

@ -30,10 +30,10 @@
<Group id="captionGroup" translation="[960,1020]" />
<timer id="playbackTimer" repeat="true" duration="30" />
<timer id="bufferCheckTimer" repeat="true" />
<PauseMenu id="pauseMenu" visible="false" translation="[50,950]" />
<PauseMenu id="pauseMenu" visible="false" inactiveTimeout="5" />
<Rectangle id="chapterList" visible="false" color="0x00000098" width="460" height="380" translation="[50,530]">
<LabelList id="chaptermenu" itemSpacing="[0,20]" numRows="5" font="font:SmallSystemFont" itemSize="[365,40]" translation="[50,20]">
<Rectangle id="chapterList" visible="false" color="0x00000098" width="400" height="380" translation="[103,210]">
<LabelList id="chaptermenu" itemSpacing="[0,20]" numRows="5" font="font:SmallSystemFont" itemSize="[315,40]" translation="[40,20]">
<ContentNode id="chapterContent" role="content" />
</LabelList>
</Rectangle>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
images/icons/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
images/icons/subtitle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
images/icons/videoInfo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB