diff --git a/components/ItemGrid.brs b/components/ItemGrid.brs
index 12a7e187..5fc0c362 100644
--- a/components/ItemGrid.brs
+++ b/components/ItemGrid.brs
@@ -87,9 +87,6 @@ function onKeyEvent(key as string, press as boolean) as boolean
if key = "down" and (m.top.itemFocused + 1) = m.top.content.getChildCount()
m.top.escapeButton = "down"
return true
- else if key = "options"
- m.top.escapeButton = "options"
- return true
end if
return false
diff --git a/components/JFGroup.brs b/components/JFGroup.brs
index 8b96ba51..080f7151 100644
--- a/components/JFGroup.brs
+++ b/components/JFGroup.brs
@@ -4,10 +4,5 @@ end sub
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false
- if key = "back"
- m.top.backPressed = true
- return true
- end if
-
return false
end function
diff --git a/components/JFMessageDialog.brs b/components/JFMessageDialog.brs
new file mode 100644
index 00000000..bdf525ee
--- /dev/null
+++ b/components/JFMessageDialog.brs
@@ -0,0 +1,11 @@
+sub init()
+end sub
+
+function onKeyEvent(key as string, press as boolean) as boolean
+ if key = "OK"
+ m.top.close = true
+ return true
+ end if
+
+ return false
+end function
diff --git a/components/JFMessageDialog.xml b/components/JFMessageDialog.xml
new file mode 100644
index 00000000..c58efc52
--- /dev/null
+++ b/components/JFMessageDialog.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/components/JFScene.brs b/components/JFScene.brs
new file mode 100644
index 00000000..5f3bf227
--- /dev/null
+++ b/components/JFScene.brs
@@ -0,0 +1,16 @@
+sub init()
+end sub
+
+function onKeyEvent(key as string, press as boolean) as boolean
+ if not press then return false
+
+ if key = "back"
+ m.top.backPressed = true
+ return true
+ else if key = "options"
+ m.top.optionsPressed = true
+ return true
+ end if
+
+ return false
+end function
diff --git a/components/JFScene.xml b/components/JFScene.xml
new file mode 100644
index 00000000..1b252cbc
--- /dev/null
+++ b/components/JFScene.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/components/JFVideo.brs b/components/JFVideo.brs
index 8b96ba51..e317bb6b 100644
--- a/components/JFVideo.brs
+++ b/components/JFVideo.brs
@@ -1,13 +1,2 @@
sub init()
end sub
-
-function onKeyEvent(key as string, press as boolean) as boolean
- if not press then return false
-
- if key = "back"
- m.top.backPressed = true
- return true
- end if
-
- return false
-end function
diff --git a/components/config/list.brs b/components/config/list.brs
index 87fadcc2..ea92f350 100644
--- a/components/config/list.brs
+++ b/components/config/list.brs
@@ -23,6 +23,7 @@ function setData()
end function
function onItemSelected()
+ print "HI"
i = m.top.itemSelected
itemField = m.top.content.getchild(i)
@@ -59,7 +60,7 @@ sub show_dialog(configField)
dialog.text = configField.value
end if
- m.top.getparent().dialog = dialog
+ m.top.getscene().dialog = dialog
m.dialog = dialog
dialog.observeField("buttonSelected", "onDialogButton")
diff --git a/components/config/scene.brs b/components/config/scene.brs
index 4700eb30..ea7540ea 100644
--- a/components/config/scene.brs
+++ b/components/config/scene.brs
@@ -1,6 +1,4 @@
sub init()
- m.top.backgroundColor = "#000b35ff"
- m.top.backgroundURI = ""
m.tracker=m.top.createChild("TrackerTask")
m.top.setFocus(true)
end sub
@@ -8,6 +6,7 @@ end sub
function onKeyEvent(key as String, press as Boolean) as Boolean
' Returns true if user navigates to a new focusable element
if not press then return false
+
list = m.top.findNode("configOptions")
button = m.top.findNode("submit")
if key = "down" and button.focusedChild = invalid
diff --git a/components/config/scene.xml b/components/config/scene.xml
index ca7d9fb2..771d01de 100644
--- a/components/config/scene.xml
+++ b/components/config/scene.xml
@@ -1,10 +1,6 @@
-
+
-
-
-
+
diff --git a/components/library/scene.xml b/components/library/scene.xml
index 7ecc04f9..e26c7b4e 100644
--- a/components/library/scene.xml
+++ b/components/library/scene.xml
@@ -3,7 +3,6 @@
-
diff --git a/components/movies/details.brs b/components/movies/details.brs
index cebb4e97..dc6dc04a 100644
--- a/components/movies/details.brs
+++ b/components/movies/details.brs
@@ -134,14 +134,3 @@ function round(f as float) as integer
return n
end if
end function
-
-function onKeyEvent(key as string, press as boolean) as boolean
- if not press then return false
-
- if key = "back"
- m.top.backPressed = true
- return true
- end if
-
- return false
-end function
diff --git a/components/movies/scene.brs b/components/movies/scene.brs
index 31940de7..15badda8 100644
--- a/components/movies/scene.brs
+++ b/components/movies/scene.brs
@@ -1,14 +1,3 @@
sub init()
m.top.overhangTitle = "Movies"
-end sub
-
-function onKeyEvent(key as string, press as boolean) as boolean
- if not press then return false
-
- if key = "back"
- m.top.backPressed = true
- return true
- end if
-
- return false
-end function
\ No newline at end of file
+end sub
\ No newline at end of file
diff --git a/components/movies/scene.xml b/components/movies/scene.xml
index 92d4b4cf..16c98d24 100644
--- a/components/movies/scene.xml
+++ b/components/movies/scene.xml
@@ -2,6 +2,7 @@
+
diff --git a/components/options/panel.brs b/components/options/panel.brs
index 7d92691e..245cdd8f 100644
--- a/components/options/panel.brs
+++ b/components/options/panel.brs
@@ -11,13 +11,6 @@ sub init()
list = m.top.findNode("panelList")
panel.list = list
-
- bd = m.top.findNode("backdrop")
- bd.color = "#101010DD"
- bd.translation = [0, 0]
- dimensions = m.top.getScene().currentDesignResolution
- bd.width = 575
- bd.height = dimensions.height
end sub
sub setFields()
@@ -35,12 +28,12 @@ function onKeyEvent(key as string, press as boolean) as boolean
if key = "options" or key = "back"
m.top.visible = false
- m.top.escape = true
+ m.top.closeSidePanel = true
return true
else if key = "OK"
list = m.top.findNode("panelList")
data = list.content.getChild(list.itemFocused)
- data.callFunc("press")
+ data.optionSelected = true
return true
end if
diff --git a/components/options/panel.xml b/components/options/panel.xml
index 50c4d96f..7f341f03 100644
--- a/components/options/panel.xml
+++ b/components/options/panel.xml
@@ -2,7 +2,11 @@
-
+
@@ -11,7 +15,7 @@
-
+
diff --git a/source/Main.brs b/source/Main.brs
index ae594daf..a00277f5 100644
--- a/source/Main.brs
+++ b/source/Main.brs
@@ -7,7 +7,7 @@ sub Main()
m.screen = CreateObject("roSGScreen")
m.port = CreateObject("roMessagePort")
m.screen.setMessagePort(m.port)
- m.scene = m.screen.CreateScene("Scene")
+ m.scene = m.screen.CreateScene("JFScene")
m.screen.show()
m.overhang = CreateObject("roSGNode", "JFOverhang")
@@ -20,10 +20,17 @@ sub Main()
' Confirm the configured server and user work
- group = CreateLibraryScene()
+ group = CreateLibraryGroup()
m.overhang.title = group.overhangTitle
m.scene.appendChild(group)
+ m.scene.observeField("backPressed", m.port)
+ m.scene.observeField("optionsPressed", m.port)
+
+ ' This is the core logic loop. Mostly for transitioning between scenes
+ ' This now only references m. fields so could be placed anywhere, in theory
+ ' "group" is always "whats on the screen"
+ ' m.scene's children is the "previous view" stack
while(true)
msg = wait(0, m.port)
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed() then
@@ -46,6 +53,17 @@ sub Main()
group.setFocus(true)
end if
group.visible = true
+ else if isNodeEvent(msg, "optionsPressed")
+ group.lastFocus = group.focusedChild
+ panel = group.findNode("options")
+ panel.visible = true
+ panel.findNode("panelList").setFocus(true)
+ else if isNodeEvent(msg, "closeSidePanel")
+ if group.lastFocus <> invalid
+ group.lastFocus.setFocus(true)
+ else
+ group.setFocus(true)
+ end if
else if isNodeEvent(msg, "librarySelected")
' If you select a library from ANYWHERE, follow this flow
node = getMsgPicker(msg, "LibrarySelect")
@@ -54,11 +72,12 @@ sub Main()
group.setFocus(false)
group.visible = false
- group = CreateMovieScene(node)
+ group = CreateMovieListGroup(node)
m.overhang.title = group.overhangTitle
m.scene.appendChild(group)
else
- print node.type
+ ' TODO - switch on more node types
+ message_dialog("This library type is not yet implemented: " + node.type)
end if
else if isNodeEvent(msg, "movieSelected")
' If you select a movie from ANYWHERE, follow this flow
@@ -68,25 +87,46 @@ sub Main()
group.setFocus(false)
group.visible = false
- group = CreateMovieDetails(node)
+ group = CreateMovieDetailsGroup(node)
m.scene.appendChild(group)
m.overhang.title = group.overhangTitle
else if isNodeEvent(msg, "buttonSelected")
' If a button is selected, we have some determining to do
btn = getButton(msg)
if btn.id = "play-button"
- ' TODO - Do a better job of picking the focusedChild
+ ' TODO - Do a better job of picking the last focus
group.lastFocus = group.focusedChild
group.setFocus(false)
group.visible = false
video_id = group.id
- group = CreateVideoPlayer(video_id)
+ group = CreateVideoPlayerGroup(video_id)
m.scene.appendChild(group)
group.setFocus(true)
group.control = "play"
m.overhang.visible = false
end if
+ else if isNodeEvent(msg, "optionSelected")
+ button = msg.getRoSGNode()
+ if button.id = "goto_search"
+ print "Search goes here"
+ else if button.id = "change_server"
+ unset_setting("server")
+ unset_setting("port")
+ SignOut()
+ wipe_groups()
+ goto app_start
+ else if button.id = "sign_out"
+ SignOut()
+ wipe_groups()
+ goto app_start
+ else if button.id = "add_user"
+ unset_setting("active_user")
+ unset_setting("server")
+ unset_setting("port")
+ wipe_groups()
+ goto app_start
+ end if
else
print type(msg)
print msg
@@ -100,12 +140,12 @@ sub LoginFlow()
start_login:
if get_setting("server") = invalid or ServerInfo() = invalid then
print "Get server details"
- ShowServerSelect()
+ CreateServerGroup()
end if
if get_setting("active_user") = invalid then
print "Get user login"
- ShowSigninSelect()
+ CreateSigninGroup()
end if
m.user = AboutMe()
@@ -114,6 +154,8 @@ sub LoginFlow()
unset_setting("active_user")
goto start_login
end if
+
+ wipe_groups()
end sub
sub RunScreenSaver()
@@ -135,4 +177,11 @@ sub RunScreenSaver()
end if
end while
+end sub
+
+sub wipe_groups()
+ ' The 1 remaining child should be the overhang
+ while(m.scene.getChildCount() > 1)
+ m.scene.removeChildIndex(1)
+ end while
end sub
\ No newline at end of file
diff --git a/source/ShowScenes.brs b/source/ShowScenes.brs
index 4fbf8c91..82863fef 100644
--- a/source/ShowScenes.brs
+++ b/source/ShowScenes.brs
@@ -1,15 +1,12 @@
-sub ShowServerSelect()
+sub CreateServerGroup()
' Get and Save Jellyfin Server Information
- port = CreateObject("roMessagePort")
- screen = CreateObject("roSGScreen")
- screen.setMessagePort(port)
- scene = screen.CreateScene("ConfigScene")
- screen.show()
+ group = CreateObject("roSGNode", "ConfigScene")
+ m.scene.appendChild(group)
- themeScene(scene)
- scene.findNode("prompt").text = "Connect to Server"
+ group.findNode("prompt").text = "Connect to Server"
- config = scene.findNode("configOptions")
+
+ config = group.findNode("configOptions")
server_field = CreateObject("roSGNode", "ConfigData")
server_field.label = "Server"
server_field.field = "server"
@@ -27,14 +24,14 @@ sub ShowServerSelect()
items = [ server_field, port_field ]
config.configItems = items
- button = scene.findNode("submit")
- button.observeField("buttonSelected", port)
+ button = group.findNode("submit")
+ button.observeField("buttonSelected", m.port)
server_hostname = config.content.getChild(0)
server_port = config.content.getChild(1)
while(true)
- msg = wait(0, port)
+ msg = wait(0, m.port)
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed()
return
else if type(msg) = "roSGNodeEvent"
@@ -46,28 +43,28 @@ sub ShowServerSelect()
' 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"
- scene.findNode("alert").text = "Server not found, is it online?"
+ group.findNode("alert").text = "Server not found, is it online?"
SignOut()
else
+ group.visible = false
return
endif
end if
end if
end while
+
+ ' Just hide it when done, in case we need to come back
+ group.visible = false
end sub
-sub ShowSignInSelect()
+sub CreateSigninGroup()
' Get and Save Jellyfin user login credentials
- port = CreateObject("roMessagePort")
- screen = CreateObject("roSGScreen")
- screen.setMessagePort(port)
- scene = screen.CreateScene("ConfigScene")
- screen.show()
+ group = CreateObject("roSGNode", "ConfigScene")
+ m.scene.appendChild(group)
- themeScene(scene)
- scene.findNode("prompt").text = "Sign In"
+ group.findNode("prompt").text = "Sign In"
- config = scene.findNode("configOptions")
+ config = group.findNode("configOptions")
username_field = CreateObject("roSGNode", "ConfigData")
username_field.label = "Username"
username_field.field = "username"
@@ -79,17 +76,18 @@ sub ShowSignInSelect()
items = [ username_field, password_field ]
config.configItems = items
- button = scene.findNode("submit")
- button.observeField("buttonSelected", port)
+ button = group.findNode("submit")
+ button.observeField("buttonSelected", m.port)
- config = scene.findNode("configOptions")
+ config = group.findNode("configOptions")
username = config.content.getChild(0)
password = config.content.getChild(1)
while(true)
- msg = wait(0, port)
+ msg = wait(0, m.port)
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed()
+ group.visible = false
return
else if type(msg) = "roSGNodeEvent"
node = msg.getNode()
@@ -98,13 +96,16 @@ sub ShowSignInSelect()
get_token(username.value, password.value)
if get_setting("active_user") <> invalid then return
print "Login attempt failed..."
- scene.findNode("alert").text = "Login attempt failed."
+ group.findNode("alert").text = "Login attempt failed."
end if
end if
end while
+
+ ' Just hide it when done, in case we need to come back
+ group.visible = false
end sub
-function CreateLibraryScene()
+function CreateLibraryGroup()
' Main screen after logging in. Shows the user's libraries
group = CreateObject("roSGNode", "Library")
@@ -112,15 +113,14 @@ function CreateLibraryScene()
group.libraries = libs
group.observeField("librarySelected", m.port)
- group.observeField("backPressed", m.port)
library = group.findNode("LibrarySelect")
- search = group.findNode("search")
-
sidepanel = group.findNode("options")
+ 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": "Add User", "id": "add_user"}
@@ -129,6 +129,7 @@ function CreateLibraryScene()
o = CreateObject("roSGNode", "OptionsButton")
o.title = opt.title
o.id = opt.id
+ o.observeField("optionSelected", m.port)
new_options.push(o)
end for
@@ -150,16 +151,49 @@ function CreateLibraryScene()
return group
end function
-function CreateMovieScene(library)
+function CreateMovieListGroup(library)
group = CreateObject("roSGNode", "Movies")
- group.observeField("backPressed", m.port)
group.observeField("movieSelected", m.port)
+ sidepanel = group.findNode("options")
+ movie_options = [
+ {"title": "Sort Field",
+ "base_title": "Sort Field",
+ "key": "movie_sort_field",
+ "default": "DateCreated",
+ "values": [
+ {display: "Date Added", value: "DateCreated"},
+ {display: "Release Date", value: "PremiereDate"},
+ {display: "Name", value: "SortName"}
+ ]},
+ {"title": "Sort Order",
+ "base_title": "Sort Order",
+ "key": "movie_sort_order",
+ "default": "Ascending",
+ "values": [
+ {display: "Descending", value: "Descending"},
+ {display: "Ascending", value: "Ascending"}
+ ]}
+ ]
+ new_options = []
+ for each opt in movie_options
+ o = CreateObject("roSGNode", "OptionsData")
+ o.title = opt.title
+ o.choices = opt.values
+ o.base_title = opt.base_title
+ o.config_key = opt.key
+ o.value = get_user_setting(opt.key, opt.default)
+ new_options.append([o])
+ end for
+
+ sidepanel.options = new_options
+ sidepanel.observeField("closeSidePanel", m.port)
+
page_num = 1
page_size = 20
- sort_order = "Ascending"
- sort_field = "SortName"
+ sort_order = get_user_setting("movie_sort_order", "Ascending")
+ sort_field = get_user_setting("movie_sort_field", "SortName")
item_list = ItemList(library.id, {"limit": page_size,
"StartIndex": page_size * (page_num - 1),
@@ -172,10 +206,9 @@ function CreateMovieScene(library)
return group
end function
-function CreateMovieDetails(movie)
+function CreateMovieDetailsGroup(movie)
group = CreateObject("roSGNode", "MovieDetails")
- group.observeField("backPressed", m.port)
movie = ItemMetaData(movie.id)
group.itemContent = movie
@@ -509,7 +542,14 @@ sub ShowSearchOptions(query)
end while
end sub
-function CreateVideoPlayer(video_id)
+function CreateSidePanel(buttons, options)
+ group = CreateObject("roSGNode", "OptionsSlider")
+ group.buttons = buttons
+ group.options = options
+
+end function
+
+function CreateVideoPlayerGroup(video_id)
' Video is Playing
video = VideoPlayer(video_id)
diff --git a/source/utils/misc.brs b/source/utils/misc.brs
index 0ef82334..cd2f1ee2 100644
--- a/source/utils/misc.brs
+++ b/source/utils/misc.brs
@@ -35,12 +35,19 @@ function leftPad(base as string, fill as string, length as integer) as string
return base
end function
-function make_dialog(message="" as string)
+function message_dialog(message="" as string)
' Takes a string and returns an object for dialog popup
- dialog = createObject("roSGNode", "Dialog")
+ dialog = createObject("roSGNode", "JFMessageDialog")
dialog.id = "popup"
dialog.buttons = ["OK"]
dialog.message = message
- return dialog
+ m.scene.dialog = dialog
+ m.scene.dialog.observeField("buttonSelected", handle_dialog)
+ m.scene.dialog.setFocus(true)
+end function
+
+function handle_dialog(msg)
+ print("THERE")
+ m.scene.dialog.close = true
end function