Add ui components and focus handling

This commit is contained in:
Bronley 2021-07-09 06:12:19 -04:00
parent c303250ffa
commit 44bf6d2b12
7 changed files with 219 additions and 38 deletions

View File

@ -0,0 +1,35 @@
function init() as void
m.poster = m.top.findNode("poster")
m.name = m.top.findNode("name")
m.baseUrl = m.top.findNode("baseUrl")
m.labels = m.top.findNode("labels")
setTextColor(0)
end function
function itemContentChanged() as void
server = m.top.itemContent
m.poster.uri = server.iconUrl
m.name.text = server.name
m.baseUrl.text = server.baseUrl
end function
function onFocusPercentChange(event)
'print "focusPercentChange: " ; event.getData()
setTextColor(event.getData())
end function
function setTextColor(percentFocused)
white = "0xffffffff"
black = "0x00000099"
if percentFocused > .4 then
color = black
else
color = white
end if
children = m.labels.getChildren(-1, 0)
for each child in children
child.color = color
end for
end function

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="JFServer" extends="Group">
<interface>
<field id="itemContent" type="node" onchange="itemContentChanged" />
<field id="focusPercent" type="float" onchange="onFocusPercentChange" />
</interface>
<script type="text/brightscript" uri="JFServer.brs" />
<children>
<Poster id="poster" translation="[0,5]" width="90" height="90" />
<Group id="labels" translation="[100,0]">
<Label text="Name:" horizAlign="left" font="font:MediumBoldSystemFont" width="130" height="65" translation="[0,5]" />
<Label text="URL:" horizAlign="left" font="font:MediumBoldSystemFont" width="130" height="65" translation="[0,55]" />
<Label id="name" horizAlign="left" font="font:MediumSystemFont" height="65" translation="[125,5]" />
<Label id="baseUrl" horizAlign="left" font="font:MediumSystemFont" height="65" translation="[125,55]" />
</Group>
</children>
</component>

View File

@ -0,0 +1,93 @@
sub init()
m.top.setFocus(true)
m.top.optionsAvailable = false
m.spinner = m.top.findNode("spinner")
m.serverPicker = m.top.findNode("serverPicker")
m.serverUrl = m.top.findNode("serverUrl")
m.serverUrlContainer = m.top.findNode("serverUrlContainer")
m.serverUrlOutline = m.top.findNode("serverUrlOutline")
m.submit = m.top.findNode("submit")
m.serverUrl.focusable = true
m.serverPicker.setFocus(true)
ScanForServers()
m.serverPicker.ObserveField("itemSelected", "onclick")
end sub
function onKeyEvent(key as string, press as boolean) as boolean
print "onKeyEvent", key, press
if not press then return true
handled = true
'if the user pressed the down key and we are already at the last child of server picker, then change focus to the url textbox
if key = "down" and m.serverPicker.hasFocus() and m.serverPicker.itemFocused = m.serverPicker.content.getChildCount() - 1
m.serverUrlContainer.setFocus(true)
else if key = "up" and m.serverUrlContainer.hasFocus()
m.serverPicker.setFocus(true)
else if key = "OK" and m.serverUrlContainer.hasFocus()
ShowKeyboard()
'focus the serverUrl input from submit button
else if key = "up" and m.submit.hasFocus()
m.serverUrlContainer.setFocus(true)
'focus the submit button from serverUrl
else if key = "down" and m.serverUrlContainer.hasFocus()
m.submit.setFocus(true)
else
handled = false
end if
'show/hide input box outline
m.serverUrlOutline.visible = m.serverUrlContainer.isInFocusChain()
return handled
end function
function ScanForServers()
m.ssdpScanner = CreateObject("roSGNode", "SSDPTask")
'run the task
m.ssdpScanner.observeField("content", "ScanForServersComplete")
m.ssdpScanner.control = "RUN"
end function
sub ScanForServersComplete(event)
' m.scanOrManual.visible = false
' m.serverPicker.visible = true
' m.serverPicker.SetFocus(true)
servers = event.getData()
servers = [servers[0], servers[0]]
items = CreateObject("roSGNode", "ContentNode")
for each server in servers
server.subtype = "ContentNode"
items.update([server], true)
end for
m.serverPicker.content = items
m.spinner.visible = false
end sub
function ShowKeyboard()
dialog = createObject("roSGNode", "KeyboardDialog")
dialog.title = "Enter the server name or ip address"
dialog.buttons = [tr("OK"), tr("Cancel")]
dialog.text = m.serverUrl.text
m.top.getscene().dialog = dialog
m.dialog = dialog
dialog.observeField("buttonSelected", "onDialogButton")
end function
function onDialogButton()
d = m.dialog
button_text = d.buttons[d.buttonSelected]
if button_text = tr("OK")
m.serverUrl.text = d.text
m.dialog.close = true
return true
else if button_text = tr("Cancel")
m.dialog.close = true
return true
end if
end function

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="SetServerScreen" extends="JFGroup">
<interface>
<field id="serverUrl" type="string" />
<field id="serverWidth" alias="serverUrlOutline.width,serverUrl.width,serverUrlContainer.width" value="1570" />
<field id="serverHeight" alias="serverUrlOutline.height,serverUrl.height,serverUrlContainer.height" value="60" />
</interface>
<children>
<Group translation="[150,0]">
<label text="Connect to Server" id="prompt" font="font:LargeBoldSystemFont" translation="[0, 150]" />
<label text="Pick a Jellyfin server from the local network" translation="[0, 200]" />
<!--background for server picker-->
<Rectangle color="0x00000020" width="1690" height="400" translation="[0, 250]">
<Spinner id="spinner" translation="[717, 136]" />
<MarkupList id="serverPicker" translation="[50, 20]" itemComponentName="JFServer" itemSpacing="[0, 10]" itemSize="[1590, 100]" numRows="3" vertFocusAnimationStyle="fixedFocus" />
</Rectangle>
<label text="...or enter server information manually" translation="[0, 670]" />
<Rectangle color="0x00000020" width="1690" height="400" translation="[0, 730]">
<LayoutGroup layoutDirection="horiz" vertAlignment="center" translation="[10, 50]">
<Label text="URL: " font="font:MediumSystemFont" translation="[0, 25]" />
<Rectangle id="serverUrlContainer" color="0x00000000">
<TextEditBox id="serverUrl" hintText="e.g. 192.168.1.100:8096 or https://example.com/jellyfin"></TextEditBox>
<Poster id="serverUrlOutline" visible="false" uri="pkg:/images/hd_focus.9.png" />
</Rectangle>
</LayoutGroup>
<Button id="submit" text="Submit" translation="[10, 100]" focusable="true" showFocusFootprint="false" iconUri="" focusedIconUri=""></Button>
</Rectangle>
<label text="" id="alert" font="font:MediumSystemFont" translation="[0, 555]" />
</Group>
</children>
<script type="text/brightscript" uri="SetServerScreen.brs" />
</component>

BIN
images/fhd_focus.9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

BIN
images/hd_focus.9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View File

@ -1,27 +1,17 @@
function CreateServerGroup()
' Get and Save Jellyfin Server Information
group = CreateObject("roSGNode", "ConfigScene")
m.scene.appendChild(group)
port = CreateObject("roMessagePort")
group.findNode("prompt").text = tr("Connect to Server")
screen = CreateObject("roSGNode", "SetServerScreen")
m.scene.appendChild(screen)
port = CreateObject("roMessagePort")
m.colors = {}
config = group.findNode("configOptions")
server_field = CreateObject("roSGNode", "ConfigData")
server_field.label = tr("Server")
server_field.field = "server"
server_field.type = "string"
if get_setting("server") <> invalid
server_field.value = get_setting("server")
screen.serverUrl = get_setting("server")
end if
group.findNode("example").text = tr("192.168.1.100:8096 or https://example.com/jellyfin")
items = [ server_field ]
config.configItems = items
button = group.findNode("submit")
m.viewModel = {}
button = screen.findNode("submit")
button.observeField("buttonSelected", port)
server_hostname = config.content.getChild(0)
group.observeField("backPressed", port)
server_hostname = screen.serverUrl
screen.observeField("backPressed", port)
while(true)
msg = wait(0, port)
@ -34,11 +24,11 @@ function CreateServerGroup()
if node = "submit"
'Append default ports
maxSlashes = 0
if left(server_hostname.value,8) = "https://" or left(server_hostname.value,7) = "http://" then maxSlashes = 2
if left(server_hostname.value, 8) = "https://" or left(server_hostname.value, 7) = "http://" then maxSlashes = 2
'Check to make sure entry has no extra slashes before adding default ports.
if Instr(0, server_hostname.value, "/") = maxSlashes then
if server_hostname.value.len() > 5 and mid(server_hostname.value, server_hostname.value.len()-4,1) <> ":" and mid(server_hostname.value, server_hostname.value.len()-5,1) <> ":" then
if left(server_hostname.value ,5) = "https" then
if server_hostname.value.len() > 5 and mid(server_hostname.value, server_hostname.value.len() - 4, 1) <> ":" and mid(server_hostname.value, server_hostname.value.len() - 5, 1) <> ":" then
if left(server_hostname.value, 5) = "https" then
server_hostname.value = server_hostname.value + ":8920"
else
server_hostname.value = server_hostname.value + ":8096"
@ -46,29 +36,29 @@ function CreateServerGroup()
end if
end if
'Append http:// to server
if left(server_hostname.value,4) <> "http" then server_hostname.value = "http://" + server_hostname.value
if left(server_hostname.value, 4) <> "http" then server_hostname.value = "http://" + server_hostname.value
'If this is a different server from what we know, reset username/password setting
if get_setting("server") <> server_hostname.value then
set_setting("username", "")
set_setting("password", "")
endif
end if
set_setting("server", server_hostname.value)
if ServerInfo() = invalid then
' Maybe don't unset setting, but offer as a prompt
' Server not found, is it online? New values / Retry
print "Server not found, is it online? New values / Retry"
group.findNode("alert").text = tr("Server not found, is it online?")
screen.findNode("alert").text = tr("Server not found, is it online?")
SignOut()
else
group.visible = false
screen.visible = false
return "true"
endif
end if
end if
end if
end while
' Just hide it when done, in case we need to come back
group.visible = false
screen.visible = false
end function
function CreateUserSelectGroup(users = [])
@ -77,7 +67,7 @@ function CreateUserSelectGroup(users = [])
end if
group = CreateObject("roSGNode", "UserSelect")
m.scene.appendChild(group)
port = CreateObject("roMessagePort")
port = CreateObject("roMessagePort")
group.itemContent = users
group.findNode("userRow").observeField("userSelected", port)
@ -107,7 +97,7 @@ function CreateSigninGroup(user = "")
' Get and Save Jellyfin user login credentials
group = CreateObject("roSGNode", "ConfigScene")
m.scene.appendChild(group)
port = CreateObject("roMessagePort")
port = CreateObject("roMessagePort")
group.findNode("prompt").text = tr("Sign In")
@ -128,7 +118,7 @@ function CreateSigninGroup(user = "")
if get_setting("password") <> invalid
password_field.value = get_setting("password")
end if
items = [ username_field, password_field ]
items = [username_field, password_field]
config.configItems = items
button = group.findNode("submit")
@ -181,9 +171,9 @@ function CreateHomeGroup()
sidepanel.observeField("closeSidePanel", m.port)
new_options = []
options_buttons = [
{"title": "Search", "id": "goto_search"},
{"title": "Change server", "id": "change_server"},
{"title": "Sign out", "id": "sign_out"}
{ "title": "Search", "id": "goto_search" },
{ "title": "Change server", "id": "change_server" },
{ "title": "Sign out", "id": "sign_out" }
]
for each opt in options_buttons
o = CreateObject("roSGNode", "OptionsButton")
@ -200,7 +190,7 @@ function CreateHomeGroup()
user_node.base_title = tr("Profile")
user_options = []
for each user in AvailableUsers()
user_options.push({display: user.username + "@" + user.server, value: user.id})
user_options.push({ display: user.username + "@" + user.server, value: user.id })
end for
user_node.choices = user_options
user_node.value = get_setting("active_user")
@ -303,7 +293,7 @@ function SeriesLister(group, page_size)
sort_order = get_user_setting("series_sort_order", "Ascending")
sort_field = get_user_setting("series_sort_field", "SortName")
item_list = ItemList(group.id, {"limit": page_size,
item_list = ItemList(group.id, { "limit": page_size,
"StartIndex": page_size * (group.pageNumber - 1),
"SortBy": sort_field,
"SortOrder": sort_order,
@ -319,7 +309,7 @@ function CollectionLister(group, page_size)
sort_order = get_user_setting("boxsets_sort_order", "Ascending")
sort_field = get_user_setting("boxsets_sort_field", "SortName")
item_list = ItemList(group.id, {"limit": page_size,
item_list = ItemList(group.id, { "limit": page_size,
"StartIndex": page_size * (group.pageNumber - 1),
"SortBy": sort_field,
"SortOrder": sort_order,
@ -333,7 +323,7 @@ end function
function ChannelLister(group, page_size)
sort_order = get_user_setting("channel_sort_order", "Ascending")
sort_field = get_user_setting("channel_sort_field", "SortName")
group.objects = Channels({"limit": page_size,
group.objects = Channels({ "limit": page_size,
"StartIndex": page_size * (group.pageNumber - 1),
"SortBy": sort_field,
"SortOrder": sort_order,