Finished with initial flow
This commit is contained in:
parent
44bf6d2b12
commit
ebd49cefb3
21
components/JFButton.brs
Normal file
21
components/JFButton.brs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
sub init()
|
||||||
|
m.top.observeFieldScoped("text", "onTextChanged")
|
||||||
|
m.top.iconUri = ""
|
||||||
|
m.top.focusedIconUri = ""
|
||||||
|
m.top.showFocusFootprint = true
|
||||||
|
m.top.minWidth = 0
|
||||||
|
end sub
|
||||||
|
|
||||||
|
sub onTextChanged()
|
||||||
|
addSpaceAfter = true
|
||||||
|
minChars = m.top.minChars
|
||||||
|
if minChars = invalid then minChars = 50
|
||||||
|
while m.top.text.Len() < minChars
|
||||||
|
if addSpaceAfter then
|
||||||
|
m.top.text = m.top.text + Chr(160)
|
||||||
|
else
|
||||||
|
m.top.text = Chr(160) + m.top.text
|
||||||
|
end if
|
||||||
|
addSpaceAfter = addSpaceAfter = false
|
||||||
|
end while
|
||||||
|
end sub
|
7
components/JFButton.xml
Normal file
7
components/JFButton.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<component name="JFButton" extends="Button">
|
||||||
|
<interface>
|
||||||
|
<field id="minChars" type="int" />
|
||||||
|
</interface>
|
||||||
|
<script type="text/brightscript" uri="JFButton.brs" />
|
||||||
|
</component>
|
|
@ -4,15 +4,13 @@ sub init()
|
||||||
|
|
||||||
m.spinner = m.top.findNode("spinner")
|
m.spinner = m.top.findNode("spinner")
|
||||||
m.serverPicker = m.top.findNode("serverPicker")
|
m.serverPicker = m.top.findNode("serverPicker")
|
||||||
m.serverUrl = m.top.findNode("serverUrl")
|
m.serverUrlTextbox = m.top.findNode("serverUrlTextbox")
|
||||||
m.serverUrlContainer = m.top.findNode("serverUrlContainer")
|
m.serverUrlContainer = m.top.findNode("serverUrlContainer")
|
||||||
m.serverUrlOutline = m.top.findNode("serverUrlOutline")
|
m.serverUrlOutline = m.top.findNode("serverUrlOutline")
|
||||||
m.submit = m.top.findNode("submit")
|
m.submit = m.top.findNode("submit")
|
||||||
|
|
||||||
m.serverUrl.focusable = true
|
|
||||||
m.serverPicker.setFocus(true)
|
m.serverPicker.setFocus(true)
|
||||||
ScanForServers()
|
ScanForServers()
|
||||||
m.serverPicker.ObserveField("itemSelected", "onclick")
|
|
||||||
|
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
|
@ -22,8 +20,11 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
||||||
if not press then return true
|
if not press then return true
|
||||||
handled = 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 = "OK" and m.serverPicker.hasFocus() then
|
||||||
if key = "down" and m.serverPicker.hasFocus() and m.serverPicker.itemFocused = m.serverPicker.content.getChildCount() - 1
|
m.top.serverUrl = m.serverPicker.content.getChild(m.serverPicker.itemFocused).baseUrl
|
||||||
|
m.submit.setFocus(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
|
||||||
|
else if key = "down" and m.serverPicker.hasFocus() and m.serverPicker.itemFocused = m.serverPicker.content.getChildCount() - 1
|
||||||
m.serverUrlContainer.setFocus(true)
|
m.serverUrlContainer.setFocus(true)
|
||||||
else if key = "up" and m.serverUrlContainer.hasFocus()
|
else if key = "up" and m.serverUrlContainer.hasFocus()
|
||||||
m.serverPicker.setFocus(true)
|
m.serverPicker.setFocus(true)
|
||||||
|
@ -51,15 +52,11 @@ function ScanForServers()
|
||||||
end function
|
end function
|
||||||
|
|
||||||
sub ScanForServersComplete(event)
|
sub ScanForServersComplete(event)
|
||||||
' m.scanOrManual.visible = false
|
|
||||||
|
|
||||||
' m.serverPicker.visible = true
|
|
||||||
' m.serverPicker.SetFocus(true)
|
|
||||||
servers = event.getData()
|
servers = event.getData()
|
||||||
servers = [servers[0], servers[0]]
|
|
||||||
items = CreateObject("roSGNode", "ContentNode")
|
items = CreateObject("roSGNode", "ContentNode")
|
||||||
for each server in servers
|
for each server in servers
|
||||||
server.subtype = "ContentNode"
|
server.subtype = "ContentNode"
|
||||||
|
'add new fields for every server property onto the ContentNode (rather than making a dedicated component just to hold data...)
|
||||||
items.update([server], true)
|
items.update([server], true)
|
||||||
end for
|
end for
|
||||||
m.serverPicker.content = items
|
m.serverPicker.content = items
|
||||||
|
@ -70,7 +67,7 @@ function ShowKeyboard()
|
||||||
dialog = createObject("roSGNode", "KeyboardDialog")
|
dialog = createObject("roSGNode", "KeyboardDialog")
|
||||||
dialog.title = "Enter the server name or ip address"
|
dialog.title = "Enter the server name or ip address"
|
||||||
dialog.buttons = [tr("OK"), tr("Cancel")]
|
dialog.buttons = [tr("OK"), tr("Cancel")]
|
||||||
dialog.text = m.serverUrl.text
|
dialog.text = m.serverUrlTextbox.text
|
||||||
|
|
||||||
m.top.getscene().dialog = dialog
|
m.top.getscene().dialog = dialog
|
||||||
m.dialog = dialog
|
m.dialog = dialog
|
||||||
|
@ -83,7 +80,7 @@ function onDialogButton()
|
||||||
button_text = d.buttons[d.buttonSelected]
|
button_text = d.buttons[d.buttonSelected]
|
||||||
|
|
||||||
if button_text = tr("OK")
|
if button_text = tr("OK")
|
||||||
m.serverUrl.text = d.text
|
m.serverUrlTextbox.text = d.text
|
||||||
m.dialog.close = true
|
m.dialog.close = true
|
||||||
return true
|
return true
|
||||||
else if button_text = tr("Cancel")
|
else if button_text = tr("Cancel")
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<component name="SetServerScreen" extends="JFGroup">
|
<component name="SetServerScreen" extends="JFGroup">
|
||||||
<interface>
|
<interface>
|
||||||
<field id="serverUrl" type="string" />
|
<field id="serverUrl" type="string" alias="serverUrlTextbox.text" />
|
||||||
<field id="serverWidth" alias="serverUrlOutline.width,serverUrl.width,serverUrlContainer.width" value="1570" />
|
<field id="serverWidth" alias="serverUrlOutline.width,serverUrlTextbox.width,serverUrlContainer.width" value="1570" />
|
||||||
<field id="serverHeight" alias="serverUrlOutline.height,serverUrl.height,serverUrlContainer.height" value="60" />
|
<field id="serverHeight" alias="serverUrlOutline.height,serverUrlTextbox.height,serverUrlContainer.height" value="60" />
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<children>
|
<children>
|
||||||
|
@ -17,23 +17,24 @@
|
||||||
<MarkupList id="serverPicker" translation="[50, 20]" itemComponentName="JFServer" itemSpacing="[0, 10]" itemSize="[1590, 100]" numRows="3" vertFocusAnimationStyle="fixedFocus" />
|
<MarkupList id="serverPicker" translation="[50, 20]" itemComponentName="JFServer" itemSpacing="[0, 10]" itemSize="[1590, 100]" numRows="3" vertFocusAnimationStyle="fixedFocus" />
|
||||||
</Rectangle>
|
</Rectangle>
|
||||||
|
|
||||||
<label text="...or enter server information manually" translation="[0, 670]" />
|
<label text="...or enter server URL manually" translation="[0, 690]" />
|
||||||
|
|
||||||
<Rectangle color="0x00000020" width="1690" height="400" translation="[0, 730]">
|
<Group width="1690" height="140" translation="[0, 730]">
|
||||||
|
<LayoutGroup layoutDirection="horiz" vertAlignment="center" translation="[10, 70]">
|
||||||
<LayoutGroup layoutDirection="horiz" vertAlignment="center" translation="[10, 50]">
|
|
||||||
<Label text="URL: " font="font:MediumSystemFont" translation="[0, 25]" />
|
<Label text="URL: " font="font:MediumSystemFont" translation="[0, 25]" />
|
||||||
<Rectangle id="serverUrlContainer" color="0x00000000">
|
<Rectangle id="serverUrlContainer" color="0x00000000">
|
||||||
<TextEditBox id="serverUrl" hintText="e.g. 192.168.1.100:8096 or https://example.com/jellyfin"></TextEditBox>
|
<TextEditBox id="serverUrlTextbox" 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" />
|
<Poster id="serverUrlOutline" visible="false" uri="pkg:/images/hd_focus.9.png" />
|
||||||
</Rectangle>
|
</Rectangle>
|
||||||
</LayoutGroup>
|
</LayoutGroup>
|
||||||
|
</Group>
|
||||||
<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]" />
|
<label text="" id="alert" font="font:MediumSystemFont" translation="[0, 555]" />
|
||||||
</Group>
|
</Group>
|
||||||
|
<LayoutGroup layoutDirection="vert" horizAlignment="center" vertAlignment="top" translation="[960, 930]">
|
||||||
|
<JFButton id="submit" minChars="30" text="Submit" translation="[120, 930]"></JFButton>
|
||||||
|
<!--add a known width invisibile element to allow the button to be centered-->
|
||||||
|
<Rectangle width="1920" height="12" color="#00000000" />
|
||||||
|
</LayoutGroup>
|
||||||
</children>
|
</children>
|
||||||
|
|
||||||
<script type="text/brightscript" uri="SetServerScreen.brs" />
|
<script type="text/brightscript" uri="SetServerScreen.brs" />
|
||||||
|
|
|
@ -21,7 +21,7 @@ sub Main()
|
||||||
|
|
||||||
m.overhang = CreateObject("roSGNode", "JFOverhang")
|
m.overhang = CreateObject("roSGNode", "JFOverhang")
|
||||||
m.scene.insertChild(m.overhang, 0)
|
m.scene.insertChild(m.overhang, 0)
|
||||||
|
|
||||||
m.page_size = 48
|
m.page_size = 48
|
||||||
|
|
||||||
app_start:
|
app_start:
|
||||||
|
@ -116,7 +116,7 @@ sub Main()
|
||||||
group = CreateItemGrid(selectedItem)
|
group = CreateItemGrid(selectedItem)
|
||||||
group.overhangTitle = selectedItem.title
|
group.overhangTitle = selectedItem.title
|
||||||
m.scene.appendChild(group)
|
m.scene.appendChild(group)
|
||||||
else if selectedItem.type = "Folder"
|
else if selectedItem.type = "Folder"
|
||||||
group.lastFocus = group.focusedChild
|
group.lastFocus = group.focusedChild
|
||||||
group.setFocus(false)
|
group.setFocus(false)
|
||||||
group.visible = false
|
group.visible = false
|
||||||
|
@ -187,7 +187,7 @@ sub Main()
|
||||||
group.control = "play"
|
group.control = "play"
|
||||||
ReportPlayback(group, "start")
|
ReportPlayback(group, "start")
|
||||||
m.overhang.visible = false
|
m.overhang.visible = false
|
||||||
else
|
else
|
||||||
dialog = createObject("roSGNode", "Dialog")
|
dialog = createObject("roSGNode", "Dialog")
|
||||||
dialog.title = tr("Error loading Channel Data")
|
dialog.title = tr("Error loading Channel Data")
|
||||||
dialog.message = tr("Unable to load Channel Data from the server")
|
dialog.message = tr("Unable to load Channel Data from the server")
|
||||||
|
@ -438,7 +438,7 @@ function LoginFlow(startOver = false as boolean)
|
||||||
end if
|
end if
|
||||||
'Collect Jellyfin server and user information
|
'Collect Jellyfin server and user information
|
||||||
start_login:
|
start_login:
|
||||||
if get_setting("server") = invalid or ServerInfo() = invalid or startOver = true then
|
if invalid = invalid or get_setting("server") = invalid or ServerInfo() = invalid or startOver = true then
|
||||||
print "Get server details"
|
print "Get server details"
|
||||||
SendPerformanceBeacon("AppDialogInitiate") ' Roku Performance monitoring - Dialog Starting
|
SendPerformanceBeacon("AppDialogInitiate") ' Roku Performance monitoring - Dialog Starting
|
||||||
serverSelection = CreateServerGroup()
|
serverSelection = CreateServerGroup()
|
||||||
|
@ -573,4 +573,4 @@ sub SendPerformanceBeacon(signalName as string)
|
||||||
if m.global.app_loaded = false then
|
if m.global.app_loaded = false then
|
||||||
m.scene.signalBeacon(signalName)
|
m.scene.signalBeacon(signalName)
|
||||||
end if
|
end if
|
||||||
end sub
|
end sub
|
||||||
|
|
|
@ -10,11 +10,11 @@ function CreateServerGroup()
|
||||||
m.viewModel = {}
|
m.viewModel = {}
|
||||||
button = screen.findNode("submit")
|
button = screen.findNode("submit")
|
||||||
button.observeField("buttonSelected", port)
|
button.observeField("buttonSelected", port)
|
||||||
server_hostname = screen.serverUrl
|
|
||||||
screen.observeField("backPressed", port)
|
screen.observeField("backPressed", port)
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
msg = wait(0, port)
|
msg = wait(0, port)
|
||||||
|
print type(msg), msg
|
||||||
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed()
|
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed()
|
||||||
return "false"
|
return "false"
|
||||||
else if isNodeEvent(msg, "backPressed")
|
else if isNodeEvent(msg, "backPressed")
|
||||||
|
@ -22,27 +22,13 @@ function CreateServerGroup()
|
||||||
else if type(msg) = "roSGNodeEvent"
|
else if type(msg) = "roSGNodeEvent"
|
||||||
node = msg.getNode()
|
node = msg.getNode()
|
||||||
if node = "submit"
|
if node = "submit"
|
||||||
'Append default ports
|
serverUrl = standardize_jellyfin_url(screen.serverUrl)
|
||||||
maxSlashes = 0
|
|
||||||
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
|
|
||||||
server_hostname.value = server_hostname.value + ":8920"
|
|
||||||
else
|
|
||||||
server_hostname.value = server_hostname.value + ":8096"
|
|
||||||
end if
|
|
||||||
end if
|
|
||||||
end if
|
|
||||||
'Append http:// to server
|
|
||||||
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 this is a different server from what we know, reset username/password setting
|
||||||
if get_setting("server") <> server_hostname.value then
|
if get_setting("server") <> serverUrl then
|
||||||
set_setting("username", "")
|
set_setting("username", "")
|
||||||
set_setting("password", "")
|
set_setting("password", "")
|
||||||
end if
|
end if
|
||||||
set_setting("server", server_hostname.value)
|
set_setting("server", serverUrl)
|
||||||
if ServerInfo() = invalid then
|
if ServerInfo() = invalid then
|
||||||
' Maybe don't unset setting, but offer as a prompt
|
' Maybe don't unset setting, but offer as a prompt
|
||||||
' Server not found, is it online? New values / Retry
|
' Server not found, is it online? New values / Retry
|
||||||
|
|
|
@ -83,7 +83,7 @@ function get_dialog_result(dialog, port)
|
||||||
if isNodeEvent(msg, "backPressed") then
|
if isNodeEvent(msg, "backPressed") then
|
||||||
return -1
|
return -1
|
||||||
elseif isNodeEvent(msg, "itemSelected")
|
elseif isNodeEvent(msg, "itemSelected")
|
||||||
return dialog.findNode("optionList").itemSelected
|
return dialog.findNode("optionList").itemSelected
|
||||||
end if
|
end if
|
||||||
end while
|
end while
|
||||||
'Dialog has closed outside of this loop, return -1 for failure
|
'Dialog has closed outside of this loop, return -1 for failure
|
||||||
|
@ -95,8 +95,8 @@ function lastFocusedChild(obj as object) as object
|
||||||
for i = 0 to obj.getChildCount()
|
for i = 0 to obj.getChildCount()
|
||||||
if obj.focusedChild <> invalid then
|
if obj.focusedChild <> invalid then
|
||||||
child = child.focusedChild
|
child = child.focusedChild
|
||||||
end if
|
end if
|
||||||
end for
|
end for
|
||||||
return child
|
return child
|
||||||
end function
|
end function
|
||||||
|
|
||||||
|
@ -144,3 +144,30 @@ end function
|
||||||
function option_dialog(options, message = "", defaultSelection = 0) as integer
|
function option_dialog(options, message = "", defaultSelection = 0) as integer
|
||||||
return show_dialog(message, options, defaultSelection)
|
return show_dialog(message, options, defaultSelection)
|
||||||
end function
|
end function
|
||||||
|
|
||||||
|
'
|
||||||
|
' Take a jellyfin hostname and ensure it's a full url.
|
||||||
|
' prepend http or https and append default ports, and remove excess slashes
|
||||||
|
'
|
||||||
|
function standardize_jellyfin_url(url as string)
|
||||||
|
'Append default ports
|
||||||
|
maxSlashes = 0
|
||||||
|
if left(url, 8) = "https://" or left(url, 7) = "http://" then
|
||||||
|
maxSlashes = 2
|
||||||
|
end if
|
||||||
|
'Check to make sure entry has no extra slashes before adding default ports.
|
||||||
|
if Instr(0, url, "/") = maxSlashes then
|
||||||
|
if url.len() > 5 and mid(url, url.len() - 4, 1) <> ":" and mid(url, url.len() - 5, 1) <> ":" then
|
||||||
|
if left(url, 5) = "https" then
|
||||||
|
url = url + ":8920"
|
||||||
|
else
|
||||||
|
url = url + ":8096"
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
'Append http:// to server
|
||||||
|
if left(url, 4) <> "http" then
|
||||||
|
url = "http://" + url
|
||||||
|
end if
|
||||||
|
return url
|
||||||
|
end function
|
||||||
|
|
Loading…
Reference in New Issue
Block a user