Merge pull request #583 from neilsb/user-setting-screen
This commit is contained in:
commit
bdb296a870
1
app.mk
1
app.mk
|
@ -108,6 +108,7 @@ prep_staging:
|
|||
cp -r $(SOURCEREL)/source $(STAGINGREL)
|
||||
cp -r $(SOURCEREL)/components $(STAGINGREL)
|
||||
cp -r $(SOURCEREL)/images $(STAGINGREL)
|
||||
cp -r $(SOURCEREL)/settings $(STAGINGREL)
|
||||
|
||||
# Copy only supported languages over to staging
|
||||
mkdir $(STAGINGREL)/locale
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
"components/**/*.*",
|
||||
"images/**/*.*",
|
||||
"resources/**/*.*",
|
||||
"locale/**/*.*"
|
||||
"locale/**/*.*",
|
||||
"settings/*.*"
|
||||
],
|
||||
"plugins": [ "@rokucommunity/bslint" ]
|
||||
}
|
|
@ -114,6 +114,12 @@ sub clearScenes()
|
|||
m.groups = []
|
||||
end sub
|
||||
|
||||
'
|
||||
' Display user/device settings screen
|
||||
sub settings()
|
||||
settingsScreen = createObject("roSGNode", "Settings")
|
||||
pushScene(settingsScreen)
|
||||
end sub
|
||||
|
||||
'
|
||||
' Register observers for overhang data
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<interface>
|
||||
<function name="pushScene" />
|
||||
<function name="popScene" />
|
||||
<function name="settings" />
|
||||
<function name="getActiveScene" />
|
||||
<function name="clearScenes" />
|
||||
<function name="resetTime" />
|
||||
|
|
5
components/settings/setting.xml
Normal file
5
components/settings/setting.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<component name="Setting" extends="ContentNode">
|
||||
<interface>
|
||||
<field id="type" type="string" />
|
||||
</interface>
|
||||
</component>
|
141
components/settings/settings.brs
Normal file
141
components/settings/settings.brs
Normal file
|
@ -0,0 +1,141 @@
|
|||
sub init()
|
||||
|
||||
m.top.overhangTitle = tr("Settings")
|
||||
m.top.optionsAvailable = false
|
||||
|
||||
m.userLocation = []
|
||||
|
||||
m.settingsMenu = m.top.findNode("settingsMenu")
|
||||
m.settingDetail = m.top.findNode("settingDetail")
|
||||
m.settingDesc = m.top.findNode("settingDesc")
|
||||
m.settingTitle = m.top.findNode("settingTitle")
|
||||
m.path = m.top.findNode("path")
|
||||
|
||||
m.boolSetting = m.top.findNode("boolSetting")
|
||||
|
||||
m.settingsMenu.setFocus(true)
|
||||
m.settingsMenu.observeField("itemFocused", "settingFocused")
|
||||
m.settingsMenu.observeField("itemSelected", "settingSelected")
|
||||
|
||||
m.boolSetting.observeField("checkedItem", "boolSettingChanged")
|
||||
|
||||
' Load Configuration Tree
|
||||
m.configTree = GetConfigTree()
|
||||
LoadMenu({ children: m.configTree })
|
||||
end sub
|
||||
|
||||
|
||||
sub LoadMenu(configSection)
|
||||
|
||||
if configSection.children = invalid
|
||||
' Load parent menu
|
||||
m.userLocation.pop()
|
||||
configSection = m.userLocation.peek()
|
||||
else
|
||||
if m.userLocation.Count() > 0 then m.userLocation.peek().selectedIndex = m.settingsMenu.itemFocused
|
||||
m.userLocation.push(configSection)
|
||||
end if
|
||||
|
||||
result = CreateObject("roSGNode", "ContentNode")
|
||||
|
||||
for each item in configSection.children
|
||||
listItem = result.CreateChild("ContentNode")
|
||||
listItem.title = tr(item.title)
|
||||
listItem.Description = tr(item.description)
|
||||
listItem.id = item.id
|
||||
end for
|
||||
|
||||
m.settingsMenu.content = result
|
||||
|
||||
if configSection.selectedIndex <> invalid and configSection.selectedIndex > -1
|
||||
m.settingsMenu.jumpToItem = configSection.selectedIndex
|
||||
end if
|
||||
|
||||
' Set Path display
|
||||
m.path.text = ""
|
||||
for each level in m.userLocation
|
||||
if level.title <> invalid then m.path.text += " / " + tr(level.title)
|
||||
end for
|
||||
end sub
|
||||
|
||||
|
||||
|
||||
sub settingFocused()
|
||||
|
||||
selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused]
|
||||
m.settingDesc.text = tr(selectedSetting.Description)
|
||||
m.settingTitle.text = tr(selectedSetting.Title)
|
||||
|
||||
' Hide Settings
|
||||
m.boolSetting.visible = false
|
||||
|
||||
if selectedSetting.type = invalid
|
||||
return
|
||||
else if selectedSetting.type = "bool"
|
||||
|
||||
m.boolSetting.visible = true
|
||||
|
||||
if get_user_setting(selectedSetting.settingName) = "true"
|
||||
m.boolSetting.checkedItem = 1
|
||||
else
|
||||
m.boolSetting.checkedItem = 0
|
||||
end if
|
||||
else
|
||||
print "Unknown setting type " + selectedSetting.type
|
||||
end if
|
||||
|
||||
end sub
|
||||
|
||||
|
||||
sub settingSelected()
|
||||
|
||||
selectedItem = m.userLocation.peek().children[m.settingsMenu.itemFocused]
|
||||
|
||||
|
||||
if selectedItem.type <> invalid ' Show setting
|
||||
if selectedItem.type = "bool"
|
||||
m.boolSetting.setFocus(true)
|
||||
end if
|
||||
else if selectedItem.children <> invalid and selectedItem.children.Count() > 0 ' Show sub menu
|
||||
LoadMenu(selectedItem)
|
||||
m.settingsMenu.setFocus(true)
|
||||
else
|
||||
return
|
||||
end if
|
||||
|
||||
m.settingDesc.text = m.settingsMenu.content.GetChild(m.settingsMenu.itemFocused).Description
|
||||
|
||||
end sub
|
||||
|
||||
|
||||
sub boolSettingChanged()
|
||||
|
||||
if m.boolSetting.focusedChild = invalid then return
|
||||
selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused]
|
||||
|
||||
if m.boolSetting.checkedItem
|
||||
set_user_setting(selectedSetting.settingName, "true")
|
||||
else
|
||||
set_user_setting(selectedSetting.settingName, "false")
|
||||
end if
|
||||
|
||||
end sub
|
||||
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
if (key = "back" or key = "left") and m.settingsMenu.focusedChild <> invalid and m.userLocation.Count() > 1
|
||||
LoadMenu({})
|
||||
return true
|
||||
else if (key = "back" or key = "left") and m.settingDetail.focusedChild <> invalid
|
||||
m.settingsMenu.setFocus(true)
|
||||
return true
|
||||
end if
|
||||
|
||||
if key = "right"
|
||||
settingSelected()
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
51
components/settings/settings.xml
Normal file
51
components/settings/settings.xml
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="Settings" extends="JFGroup">
|
||||
<children>
|
||||
|
||||
<Label id="path" translation = "[95,175]" font="font:SmallestBoldSystemFont" />
|
||||
|
||||
<LabelList
|
||||
translation = "[120,250]"
|
||||
id = "settingsMenu"
|
||||
itemSize = "[440,48]"
|
||||
vertFocusAnimationStyle = "floatingFocus"
|
||||
focusBitmapBlendColor = "#006fab"
|
||||
focusedColor = "#ffffff"
|
||||
itemSpacing = "[0,5]"
|
||||
/>
|
||||
|
||||
<Poster
|
||||
translation = "[710,250]"
|
||||
id="testRectangle"
|
||||
width="880"
|
||||
height="700"
|
||||
uri="pkg:/images/white.9.png"
|
||||
blendColor = "#3f3f3f"
|
||||
/>
|
||||
|
||||
<LayoutGroup
|
||||
translation = "[1150,275]"
|
||||
id="settingDetail"
|
||||
vertAlignment="top"
|
||||
horizAlignment="center"
|
||||
itemSpacings="[50]"
|
||||
>
|
||||
|
||||
<ScrollingLabel font="font:LargeSystemFont" id="settingTitle" maxWidth="750" />
|
||||
|
||||
<Label id="settingDesc" width="750" wrap = "true" />
|
||||
|
||||
<RadioButtonList id="boolSetting" vertFocusAnimationStyle="floatingFocus">
|
||||
<ContentNode role="content">
|
||||
<ContentNode title="Disabled" />
|
||||
<ContentNode title="Enabled" />
|
||||
</ContentNode>
|
||||
</RadioButtonList>
|
||||
|
||||
</LayoutGroup>
|
||||
|
||||
|
||||
</children>
|
||||
<script type="text/brightscript" uri="settings.brs" />
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
|
||||
</component>
|
|
@ -470,5 +470,28 @@
|
|||
<source>Version</source>
|
||||
<translation>Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playback</source>
|
||||
<translation>Playback</translation>
|
||||
<extracomment>Title for Playback section in user setting screen.</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>MPEG 2 Support</source>
|
||||
<translation>MPEG 2 Support</translation>
|
||||
<extracomment>Settings Menu - Title for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Support direct play of MPEG 2 content (e.g. Live TV). This will prevent transcoding of MPEG 2 content, but uses significantly more bandwidth</source>
|
||||
<translation>Support direct play of MPEG 2 content (e.g. Live TV). This will prevent transcoding of MPEG 2 content, but uses significantly more bandwidth</translation>
|
||||
<extracomment>Settings Menu - Description for option</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enabled</source>
|
||||
<translation>Enabled</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabled</source>
|
||||
<translation>Disabled</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
15
settings/settings.json
Normal file
15
settings/settings.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
[
|
||||
{
|
||||
"title": "Playback",
|
||||
"description": "Settings related to playback and supported codec and media types",
|
||||
"children": [
|
||||
{
|
||||
"title": "MPEG 2 Support",
|
||||
"description": "Support direct play of MPEG 2 content (e.g. Live TV). This will prevent transcoding of MPEG 2 content, but uses significantly more bandwidth",
|
||||
"settingName": "playback.mpeg2",
|
||||
"type": "bool",
|
||||
"default": "false"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -10,6 +10,13 @@ sub Main (args as dynamic) as void
|
|||
' Set global constants
|
||||
setConstants()
|
||||
|
||||
' Temporary code to migrate MPEG2 setting from device setting to user setting
|
||||
' Added for 1.4.13 release and should probably be removed for 1.4.15
|
||||
if get_setting("playback.mpeg2") <> invalid and registry_read("playback.mpeg2", get_setting("active_user")) = invalid
|
||||
set_user_setting("playback.mpeg2", get_setting("playback.mpeg2"))
|
||||
end if
|
||||
' End Temporary code
|
||||
|
||||
m.port = CreateObject("roMessagePort")
|
||||
m.screen.setMessagePort(m.port)
|
||||
m.scene = m.screen.CreateScene("JFScene")
|
||||
|
@ -274,16 +281,16 @@ sub Main (args as dynamic) as void
|
|||
SignOut()
|
||||
sceneManager.callFunc("clearScenes")
|
||||
goto app_start
|
||||
else if button.id = "play_mpeg2"
|
||||
playMpeg2 = get_setting("playback.mpeg2")
|
||||
if playMpeg2 = "true"
|
||||
playMpeg2 = "false"
|
||||
button.title = tr("MPEG2 Support: Off")
|
||||
else if button.id = "settings"
|
||||
' Exit out of the side panel
|
||||
panel = group.findNode("options")
|
||||
panel.visible = false
|
||||
if group.lastFocus <> invalid
|
||||
group.lastFocus.setFocus(true)
|
||||
else
|
||||
playMpeg2 = "true"
|
||||
button.title = tr("MPEG2 Support: On")
|
||||
group.setFocus(true)
|
||||
end if
|
||||
set_setting("playback.mpeg2", playMpeg2)
|
||||
sceneManager.callFunc("settings")
|
||||
end if
|
||||
else if isNodeEvent(msg, "selectSubtitlePressed")
|
||||
node = m.scene.focusedChild
|
||||
|
|
|
@ -258,19 +258,10 @@ function CreateHomeGroup()
|
|||
new_options.push(o)
|
||||
end for
|
||||
|
||||
' Add option for mpeg-2 playback
|
||||
playMpeg2 = get_setting("playback.mpeg2")
|
||||
if playMpeg2 = invalid
|
||||
playMpeg2 = "true"
|
||||
set_setting("playback.mpeg2", playMpeg2)
|
||||
end if
|
||||
' Add settings option to menu
|
||||
o = CreateObject("roSGNode", "OptionsButton")
|
||||
if playMpeg2 = "true"
|
||||
o.title = tr("MPEG2 Support: On")
|
||||
else
|
||||
o.title = tr("MPEG2 Support: Off")
|
||||
end if
|
||||
o.id = "play_mpeg2"
|
||||
o.title = "Settings"
|
||||
o.id = "settings"
|
||||
o.observeField("optionSelected", m.port)
|
||||
new_options.push(o)
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
' "Registry" is where Roku stores config
|
||||
|
||||
' Read config tree from json config file and return
|
||||
function GetConfigTree()
|
||||
return ParseJSON(ReadAsciiFile("pkg:/settings/settings.json"))
|
||||
end function
|
||||
|
||||
|
||||
' Generic registry accessors
|
||||
function registry_read(key, section = invalid)
|
||||
|
@ -44,7 +49,19 @@ end sub
|
|||
function get_user_setting(key, default = invalid)
|
||||
if get_setting("active_user") = invalid then return default
|
||||
value = registry_read(key, get_setting("active_user"))
|
||||
if value = invalid then return default
|
||||
if value = invalid
|
||||
|
||||
' Check for default in Config Tree
|
||||
configTree = GetConfigTree()
|
||||
configKey = findConfigTreeKey(key, configTree)
|
||||
|
||||
if configKey <> invalid and configKey.default <> invalid
|
||||
set_user_setting(key, configKey.default) ' Set user setting to default
|
||||
return configKey.default
|
||||
end if
|
||||
|
||||
return default
|
||||
end if
|
||||
return value
|
||||
end function
|
||||
|
||||
|
@ -57,3 +74,20 @@ sub unset_user_setting(key)
|
|||
if get_setting("active_user") = invalid then return
|
||||
registry_delete(key, get_setting("active_user"))
|
||||
end sub
|
||||
|
||||
|
||||
' Recursivly search the config tree for entry with settingname equal to key
|
||||
function findConfigTreeKey(key as string, tree)
|
||||
for each item in tree
|
||||
if item.settingName <> invalid and item.settingName = key then return item
|
||||
|
||||
if item.children <> invalid and item.children.Count() > 0
|
||||
result = findConfigTreeKey(key, item.children)
|
||||
if result <> invalid then return result
|
||||
end if
|
||||
end for
|
||||
|
||||
return invalid
|
||||
end function
|
||||
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ end function
|
|||
|
||||
|
||||
function getDeviceProfile() as object
|
||||
playMpeg2 = get_setting("playback.mpeg2") = "true"
|
||||
playMpeg2 = get_user_setting("playback.mpeg2") = "true"
|
||||
|
||||
'Check if 5.1 Audio Output connected
|
||||
maxAudioChannels = 2
|
||||
|
@ -165,7 +165,7 @@ function GetDirectPlayProfiles() as object
|
|||
mkvAudio = "mp3,pcm,lpcm,wav"
|
||||
audio = "mp3,pcm,lpcm,wav"
|
||||
|
||||
playMpeg2 = get_setting("playback.mpeg2") = "true"
|
||||
playMpeg2 = get_user_setting("playback.mpeg2") = "true"
|
||||
|
||||
di = CreateObject("roDeviceInfo")
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user