diff --git a/app/assets/img/jfserver.png b/app/assets/img/jfserver.png new file mode 100644 index 0000000..138b2b6 Binary files /dev/null and b/app/assets/img/jfserver.png differ diff --git a/app/js/about.js b/app/js/about.js new file mode 100644 index 0000000..5b8218d --- /dev/null +++ b/app/js/about.js @@ -0,0 +1,81 @@ +// /\_/| +// { ' ' } JellyCAT +// \____\ + +//----------------------------DOMView-------------------------------------------- + +var JCATAboutXML = '\n' + + '\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' JellyCAT About\n' + + ' \n' + + ' \n' + + ' \n' + + ' Close\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ''; + + +JCATAboutXML = JCATAboutXML + .replace(/\$atvcsettings\.hello/g, atv.jcathost.HelloMessage) + .replace(/\$atvcsettings\.system/g, atv.jcathost.System) + .replace(/\$atvcsettings\.version/g, atv.jcathost.Version) + .replace(/\$atvcsettings\.sighost/g, atv.jcathost.SigHost) + .replace(/\$atvcsettings\.hostip/g, atv.jcathost.HostIP); + + +function generateJCATAboutXML() { + var doc = atv.parseXML( JCATAboutXML ); + + console.log( "Creating the view --> " ); + DomViewManager.createView( "JcatAboutView" ); + + console.log( "Loading the view --> " ); + DomViewManager.loadView( "JcatAboutView", doc ); + + console.log( "View is loaded" ); +} \ No newline at end of file diff --git a/app/js/jcathostinfo.js b/app/js/jcathostinfo.js index 773b1d3..71d3511 100644 --- a/app/js/jcathostinfo.js +++ b/app/js/jcathostinfo.js @@ -42,7 +42,7 @@ var JCATHOSTInfoXML = '\n' + '$atvcsettings.hostip\n' + ']]>\n' + ' \n' + - ' \n' + + ' \n' + ' About\n' + ' \n' + ' \n' + @@ -71,232 +71,4 @@ function generateJCATHOSTInfoXML() { DomViewManager.loadView( "JcathostInfoView", doc ); console.log( "View is loaded" ); -} - -// *************************************************** -// DOMView | Wrapper -// https://github.com/wahlmanj/sample-aTV/blob/dba73806c21183fb35d6edca94b960691d8e5d66/js/views/DOMView/DOMView.js - -/** - * This wrapper makes it easier to handle the DOM View JS calls. - * The actual calls for DOMView are: - * view = new atv.DOMView() - * view.onUnload - similar to onPageUnload - * view.load ( XMLDOC, function(sucess) { ... } ) - pushes the view onto the stack the callback function is called back and gives you a success or fail call. - * view.unload - removes the view from the stack. - */ -var DomViewManager = ( function() { - var views = {}, - ViewNames = [], - config = {}, - callbackEvents = {}, - optionDialogXML = {}; - - - function _saveView( name, view ) { - if( name && view ) { - views[ name ] = view; - _addViewToList( name ); - - } else { - console.error( "When saving a view, both name and view are required" ); - }; - }; - - function _deleteView( name ) { - if( views[ name ] ) { - delete views[ name ]; - _removeViewFromList( name ); - }; - }; - - function _retrieveView( name ) { - if( name ) { - return views[ name ] || null; - } else { - console.error( "When attempting to retrieve a view name is required."); - }; - return null; - }; - - function _addViewToList( name ) { - var index = ViewNames.indexOf( name ); - if( index == -1 ) { - ViewNames.push( name ); - }; - }; - - function _removeViewFromList( name ) { - var index = ViewNames.indexOf( name ); - if( index > -1 ) { - ViewNames.splice( index, 1 ); - }; - }; - - function _createDialogXML( dialogOptions ) { - var doc = atv.parseXML( optionDialogXML ), - title = dialogOptions.title, - description = dialogOptions.description, - initialSelection = dialogOptions.initialSelection || 0, - options = dialogOptions.options || []; - - - // fill in the title, accessibility label - doc.rootElement.getElementByTagName( 'title' ).textContent = title; - doc.rootElement.getElementByTagName( 'simpleHeader' ).setAttribute( 'accessibilityLabel', title +". "+ description ); - - // fill in the description - doc.rootElement.getElementByTagName( 'description' ).textContent = description; - - // fill in the initial selection - doc.rootElement.getElementByTagName( 'row' ).textContent = initialSelection; - - // fill in the options - var items = doc.rootElement.getElementByTagName( 'items' ); - options.forEach( function ( option, index ) { - // save option callbacks - RegisterCallbackEvent( "DialogOption_"+index, option.callback ); - - // create the option - var newOptionButton = ATVUtils.createNode({ - "name": "oneLineMenuItem", - "attrs": [{ - "name": "id", - "value": "DialogOption_"+ index - }, { - "name": "accessibilityLabel", - "value": option.label - }, { - "name": "onSelect", - "value": "DomViewManager.fireCallback( 'DialogOption_"+ index +"' );" - }], - "children": [{ - "name": "label", - "text": option.label - }] - }, - doc ); - - // append it to the items. - items.appendChild( newOptionButton ); - }); - - return doc; - - } - - function ListSavedViews() { - return ViewNames; - }; - - function setConfig(property, value) { - console.log( " ===> Setting: "+ property +" = "+ value +" <=== " ); - config[ property ] = value; - }; - - function getConfig(property) { - var value = config[property]; - return (value) ? value: null; - }; - - // Create a new DomView - function CreateView( name, dialogOptions ) { - if( name ) { - var view = new atv.DOMView(); - - _saveView( name, view ); - - if( typeof( dialogOptions ) === "object" ) { - var doc = _createDialogXML( dialogOptions ); - }; - - setConfig( name+"_doc", doc ) - - view.onUnload = function() { - console.log(" == DOMView onUnload called == " ); - FireCallbackEvent("ONUNLOADVIEW", { - "name": name, - "view": this - }); - }; - - } else { - console.error("When attempting to create a DOM view, name is required."); - }; - }; - - function RemoveView( name ) { - // unload the view, remove the view from the view list, remove the view name - UnloadView( name ); - _deleteView( name ); - }; - - function LoadView( name, doc ) { - try { - var view = _retrieveView( name ), - doc = doc || getConfig( name+"_doc" ); - - if( !view ) - { - CreateView( name ); - view = _retrieveView( name ); - } - - console.log( "We load the view: "+ name +" : "+ view ); - view.load(doc, function(success) { - console.log("DOMView succeeded " + success); - if( success ) - { - console.log("=== Saving Document: "+ name +"_doc ==="); - view.doc = doc.serializeToString(); - FireCallbackEvent( "ONLOADSUCCESS", { "view": name } ) - } - else - { - var msg = "Unable to load view." - FireCallbackEvent( "ONLOADERROR", { "id": "LOADERROR", "view":name, "msg": msg } ); - } - }); - } catch ( error ) { - console.error( "LOAD ERROR: "+ error ); - }; - }; - - function UnloadView( name ) { - var view = _retrieveView( name ); - view.unload(); - }; - - function RegisterCallbackEvent( name, callback ) { - console.log(" ---- Registering Callback: " + name + " with callback type: " + typeof(callback)); - if (typeof callback === "function") { - callbackEvents[name] = callback; - } else { - console.error("When attempting to register a callback event, a callback function is required."); - }; - }; - - function FireCallbackEvent( name, parameters, scope ) { - var scope = scope || this, - parameters = parameters || {}; - - if (callbackEvents[name] && typeof callbackEvents[name] === "function") { - callbackEvents[name].call(scope, parameters) - }; - }; - - return { - "createView": CreateView, - "removeView": RemoveView, - "loadView": LoadView, - "unloadView": UnloadView, - "listViews": ListSavedViews, - "registerCallback": RegisterCallbackEvent, - "fireCallback": FireCallbackEvent - }; - -})(); - - -// ------ End DOM View Manager -------- - +} \ No newline at end of file diff --git a/app/js/jcm.js b/app/js/jcm.js index 1e30a41..6ac2ef2 100644 --- a/app/js/jcm.js +++ b/app/js/jcm.js @@ -717,5 +717,234 @@ function handleNavbarNavigate( event ) { } +// *************************************************** +// DOMView | Wrapper +// https://github.com/wahlmanj/sample-aTV/blob/dba73806c21183fb35d6edca94b960691d8e5d66/js/views/DOMView/DOMView.js + +/** + * This wrapper makes it easier to handle the DOM View JS calls. + * The actual calls for DOMView are: + * view = new atv.DOMView() + * view.onUnload - similar to onPageUnload + * view.load ( XMLDOC, function(sucess) { ... } ) - pushes the view onto the stack the callback function is called back and gives you a success or fail call. + * view.unload - removes the view from the stack. + */ +var DomViewManager = ( function() { + var views = {}, + ViewNames = [], + config = {}, + callbackEvents = {}, + optionDialogXML = {}; + + + function _saveView( name, view ) { + if( name && view ) { + views[ name ] = view; + _addViewToList( name ); + + } else { + console.error( "When saving a view, both name and view are required" ); + }; + }; + + function _deleteView( name ) { + if( views[ name ] ) { + delete views[ name ]; + _removeViewFromList( name ); + }; + }; + + function _retrieveView( name ) { + if( name ) { + return views[ name ] || null; + } else { + console.error( "When attempting to retrieve a view name is required."); + }; + return null; + }; + + function _addViewToList( name ) { + var index = ViewNames.indexOf( name ); + if( index == -1 ) { + ViewNames.push( name ); + }; + }; + + function _removeViewFromList( name ) { + var index = ViewNames.indexOf( name ); + if( index > -1 ) { + ViewNames.splice( index, 1 ); + }; + }; + + function _createDialogXML( dialogOptions ) { + var doc = atv.parseXML( optionDialogXML ), + title = dialogOptions.title, + description = dialogOptions.description, + initialSelection = dialogOptions.initialSelection || 0, + options = dialogOptions.options || []; + + + // fill in the title, accessibility label + doc.rootElement.getElementByTagName( 'title' ).textContent = title; + doc.rootElement.getElementByTagName( 'simpleHeader' ).setAttribute( 'accessibilityLabel', title +". "+ description ); + + // fill in the description + doc.rootElement.getElementByTagName( 'description' ).textContent = description; + + // fill in the initial selection + doc.rootElement.getElementByTagName( 'row' ).textContent = initialSelection; + + // fill in the options + var items = doc.rootElement.getElementByTagName( 'items' ); + options.forEach( function ( option, index ) { + // save option callbacks + RegisterCallbackEvent( "DialogOption_"+index, option.callback ); + + // create the option + var newOptionButton = ATVUtils.createNode({ + "name": "oneLineMenuItem", + "attrs": [{ + "name": "id", + "value": "DialogOption_"+ index + }, { + "name": "accessibilityLabel", + "value": option.label + }, { + "name": "onSelect", + "value": "DomViewManager.fireCallback( 'DialogOption_"+ index +"' );" + }], + "children": [{ + "name": "label", + "text": option.label + }] + }, + doc ); + + // append it to the items. + items.appendChild( newOptionButton ); + }); + + return doc; + + } + + function ListSavedViews() { + return ViewNames; + }; + + function setConfig(property, value) { + console.log( " ===> Setting: "+ property +" = "+ value +" <=== " ); + config[ property ] = value; + }; + + function getConfig(property) { + var value = config[property]; + return (value) ? value: null; + }; + + // Create a new DomView + function CreateView( name, dialogOptions ) { + if( name ) { + + var view = new atv.DOMView(); + // console.log("This log prevents occasional hanging for some reason...") + + _saveView( name, view ); + + if( typeof( dialogOptions ) === "object" ) { + var doc = _createDialogXML( dialogOptions ); + }; + + setConfig( name+"_doc", doc ) + + view.onUnload = function() { + console.log(" == DOMView onUnload called == " ); + FireCallbackEvent("ONUNLOADVIEW", { + "name": name, + "view": this + }); + }; + + } else { + console.error("When attempting to create a DOM view, name is required."); + }; + }; + + function RemoveView( name ) { + // unload the view, remove the view from the view list, remove the view name + UnloadView( name ); + _deleteView( name ); + }; + + function LoadView( name, doc ) { + try { + var view = _retrieveView( name ), + doc = doc || getConfig( name+"_doc" ); + + if( !view ) + { + CreateView( name ); + view = _retrieveView( name ); + } + + console.log( "We load the view: "+ name +" : "+ view ); + view.load(doc, function(success) { + console.log("DOMView succeeded " + success); + if( success ) + { + console.log("=== Saving Document: "+ name +"_doc ==="); + view.doc = doc.serializeToString(); + FireCallbackEvent( "ONLOADSUCCESS", { "view": name } ) + } + else + { + var msg = "Unable to load view." + FireCallbackEvent( "ONLOADERROR", { "id": "LOADERROR", "view":name, "msg": msg } ); + } + }); + } catch ( error ) { + console.error( "LOAD ERROR: "+ error ); + }; + }; + + function UnloadView( name ) { + var view = _retrieveView( name ); + view.unload(); + }; + + function RegisterCallbackEvent( name, callback ) { + console.log(" ---- Registering Callback: " + name + " with callback type: " + typeof(callback)); + if (typeof callback === "function") { + callbackEvents[name] = callback; + } else { + console.error("When attempting to register a callback event, a callback function is required."); + }; + }; + + function FireCallbackEvent( name, parameters, scope ) { + var scope = scope || this, + parameters = parameters || {}; + + if (callbackEvents[name] && typeof callbackEvents[name] === "function") { + callbackEvents[name].call(scope, parameters) + }; + }; + + return { + "createView": CreateView, + "removeView": RemoveView, + "loadView": LoadView, + "unloadView": UnloadView, + "listViews": ListSavedViews, + "registerCallback": RegisterCallbackEvent, + "fireCallback": FireCallbackEvent + }; + +})(); + + +// ------ End DOM View Manager -------- + console.log('Reached EOF!'); diff --git a/app/js/jellyfin-setup.js b/app/js/jellyfin-setup.js new file mode 100644 index 0000000..5713802 --- /dev/null +++ b/app/js/jellyfin-setup.js @@ -0,0 +1,70 @@ +// /\_/| +// { ' ' } JellyCAT +// \____\ + +// Function to show text entry page +showTextEntryPage = function(input_type, input_title, input_instructions, callback_submit, callback_cancel, defaultvalue) { + var textEntry = new atv.TextEntry(); + + textEntry.type = input_type; + textEntry.title = input_title; + textEntry.instructions = input_instructions; + textEntry.defaultValue = defaultvalue; + textEntry.defaultToAppleID = false; + // textEntry.image = + textEntry.onSubmit = callback_submit; + textEntry.onCancel = callback_cancel; + + textEntry.show(); +}; + +// Function to set server address +function setServerAddress() { + showTextEntryPage( + "emailAddress", + "Set Jellyfin Server Address", + "Enter the address of the Jellyfin server:", + function(value) { + // Save server address to localStorage + atv.localStorage['jellyfin_server_address'] = value; + }, + function() { + + }, + atv.localStorage['jellyfin_server_address'] || "" + ); +} + +// Function to set username +function setUsername() { + showTextEntryPage( + "emailAddress", + "Set Username", + "Enter your username:", + function(value) { + // Save username to localStorage + atv.localStorage['jellyfin_username'] = value; + }, + function() { + + }, + atv.localStorage['jellyfin_username'] || "" + ); +} + +// Function to set password +function setPassword() { + showTextEntryPage( + "password", + "Set Password", + "Enter your password:", + function(value) { + // Save password to localStorage + atv.localStorage['jellyfin_password'] = value; + }, + function() { + + }, + atv.localStorage['jellyfin_password'] || "" + ); +} diff --git a/app/js/storagetest.js b/app/js/storagetest.js index f948743..9359bb5 100644 --- a/app/js/storagetest.js +++ b/app/js/storagetest.js @@ -4,7 +4,7 @@ function printSessionStorage() { - var keys = ['test', 'exampleKey2', 'exampleKey3']; + var keys = ['test', 'exampleKey']; keys.forEach(function(key) { var value = atv.sessionStorage.getItem(key); @@ -18,7 +18,7 @@ function printSessionStorage() { function printLocalStorage() { - var keys = ['test', 'exampleKey2', 'exampleKey3']; + var keys = ['test', 'jellyfin_server_address', 'jellyfin_username', 'jellyfin_password', 'jellyfin_auth']; keys.forEach(function(key) { var value = atv.localStorage.getItem(key); diff --git a/app/xml/dvt/devtools.xml b/app/xml/dvt/devtools.xml index 8600583..49bc973 100644 --- a/app/xml/dvt/devtools.xml +++ b/app/xml/dvt/devtools.xml @@ -3,6 +3,7 @@