mirror of
https://github.com/SEPPDROID/JellyCAT.git
synced 2025-10-21 23:44:20 +00:00
finishing touches & getting ready for the big MAIN :)
This commit is contained in:
@@ -24,7 +24,7 @@ atv.onAppExit = function() {
|
||||
// Help I'm even worse at JS
|
||||
|
||||
function jcatMain(){
|
||||
atvutils.loadURL("https://" + atv.jcathost.SigHost + "/xml/devtools.xml");
|
||||
atvutils.loadURL("https://" + atv.jcathost.SigHost + "/xml/home.xml");
|
||||
}
|
||||
|
||||
// ***************************************************
|
||||
|
BIN
app/assets/img/jcat.png
Normal file
BIN
app/assets/img/jcat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 132 KiB |
BIN
app/assets/img/jcprev.png
Normal file
BIN
app/assets/img/jcprev.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
app/assets/img/jcsettings.png
Normal file
BIN
app/assets/img/jcsettings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
@@ -34,8 +34,6 @@
|
||||
|
||||
</dict>
|
||||
<key>javascript-url</key>
|
||||
<string>./js/application.js</string>
|
||||
|
||||
|
||||
<string>./application.js</string>
|
||||
</dict>
|
||||
</plist>
|
302
app/js/jcathostinfo.js
Normal file
302
app/js/jcathostinfo.js
Normal file
@@ -0,0 +1,302 @@
|
||||
// /\_/|
|
||||
// { ' ' } JellyCAT
|
||||
// \____\
|
||||
|
||||
//----------------------------DOMView--------------------------------------------
|
||||
|
||||
var JCATHOSTInfoXML = '<?xml version="1.0" encoding="UTF-8"?>\n' +
|
||||
'<atv>\n' +
|
||||
' <head>\n' +
|
||||
' </head>\n' +
|
||||
' <body>\n' +
|
||||
' <scrollingText id="com.jellycat.jcathostinfo" initialSelection="1">\n' +
|
||||
' <title>JCATHOST Information</title>\n' +
|
||||
' <text><![CDATA[\n' +
|
||||
'// /\\_/ |\n' +
|
||||
'// { \' \' } JellyCAT\n' +
|
||||
'// \\____\\\n' +
|
||||
'\n' +
|
||||
'ENGLISH\n' +
|
||||
'\n' +
|
||||
'-=JellyCAT Server (JCHOST) Information=-\n' +
|
||||
'\n' +
|
||||
'JellyCAT Server Host (fallback):\n' +
|
||||
'http://jcathost.dns\n' +
|
||||
'\n' +
|
||||
'ATVCSETTINGS pick-up location:\n' +
|
||||
'http://jcathost.dns/atvcsettings\n' +
|
||||
'\n' +
|
||||
'ATVCSETTINGS Hello:\n' +
|
||||
'$atvcsettings.hello\n' +
|
||||
'\n' +
|
||||
'ATVCSETTINGS System Information:\n' +
|
||||
'$atvcsettings.system\n' +
|
||||
'\n' +
|
||||
'JellyCat Version:\n' +
|
||||
'$atvcsettings.version\n' +
|
||||
'\n' +
|
||||
'Hijacked Host App domain\n' +
|
||||
'$atvcsettings.sighost\n' +
|
||||
'\n' +
|
||||
'JellyCAT Server Host IP\n' +
|
||||
'$atvcsettings.hostip\n' +
|
||||
']]></text>\n' +
|
||||
' <buttons>\n' +
|
||||
' <actionButton onSelect="atvutils.loadURL(\'https://\'+ atv.jcathost.SigHost +\'/xml/about.xml\');" id="help">\n' +
|
||||
' <title>About</title>\n' +
|
||||
' </actionButton>\n' +
|
||||
' <actionButton onSelect="DomViewManager.unloadView(\'JcathostInfoView\');" id="close">\n' +
|
||||
' <title>Close</title>\n' +
|
||||
' </actionButton>\n' +
|
||||
' </buttons>\n' +
|
||||
' </scrollingText>\n' +
|
||||
' </body>\n' +
|
||||
'</atv>';
|
||||
|
||||
JCATHOSTInfoXML = JCATHOSTInfoXML
|
||||
.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 generateJCATHOSTInfoXML() {
|
||||
var doc = atv.parseXML( JCATHOSTInfoXML );
|
||||
|
||||
console.log( "Creating the view --> " );
|
||||
DomViewManager.createView( "JcathostInfoView" );
|
||||
|
||||
console.log( "Loading the view --> " );
|
||||
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 --------
|
||||
|
159
app/js/jcm.js
159
app/js/jcm.js
@@ -558,5 +558,164 @@ String.prototype.xmlEncode = function()
|
||||
return string;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an XHR handler. It handles most of tediousness of the XHR request
|
||||
* and keeps track of onRefresh XHR calls so that we don't end up with multiple
|
||||
* page refresh calls.
|
||||
*
|
||||
* You can see how I call it on the handleRefresh function below.
|
||||
*
|
||||
*
|
||||
* @params object (hash) $options
|
||||
* @params string $options.url - url to be loaded
|
||||
* @params string $options.method - "GET", "POST", "PUT", "DELTE"
|
||||
* @params bool $options.type - false = "Sync" or true = "Async" (You should always use true)
|
||||
* @params func $options.success - Gets called on readyState 4 & status 200
|
||||
* @params func $options.failure - Gets called on readyState 4 & status != 200
|
||||
* @params func $options.callback - Gets called after the success and failure on readyState 4
|
||||
* @params string $options.data - data to be sent to the server
|
||||
* @params bool $options.refresh - Is this a call from the onRefresh event.
|
||||
*/
|
||||
ATVUtils.Ajax = function($options) {
|
||||
var me = this;
|
||||
$options = $options || {}
|
||||
|
||||
/* Setup properties */
|
||||
this.url = $options.url || false;
|
||||
this.method = $options.method || "GET";
|
||||
this.type = ($options.type === false) ? false : true;
|
||||
this.success = $options.success || null;
|
||||
this.failure = $options.failure || null;
|
||||
this.data = $options.data || null;
|
||||
this.complete = $options.complete || null;
|
||||
this.refresh = $options.refresh || false;
|
||||
|
||||
if(!this.url) {
|
||||
console.error('\nAjax Object requires a url to be passed in: e.g. { "url": "some string" }\n')
|
||||
return undefined;
|
||||
};
|
||||
|
||||
this.id = Date.now();
|
||||
|
||||
this.createRequest();
|
||||
|
||||
this.req.onreadystatechange = this.stateChange;
|
||||
|
||||
this.req.object = this;
|
||||
|
||||
this.open();
|
||||
|
||||
this.send();
|
||||
|
||||
};
|
||||
|
||||
ATVUtils.Ajax.currentlyRefreshing = false;
|
||||
ATVUtils.Ajax.activeRequests = {};
|
||||
|
||||
ATVUtils.Ajax.prototype = {
|
||||
stateChange: function() {
|
||||
var me = this.object;
|
||||
switch(this.readyState) {
|
||||
case 1:
|
||||
if(typeof(me.connection) === "function") me.connection(this, me);
|
||||
break;
|
||||
case 2:
|
||||
if(typeof(me.received) === "function") me.received(this, me);
|
||||
break;
|
||||
case 3:
|
||||
if(typeof(me.processing) === "function") me.processing(this, me);
|
||||
break;
|
||||
case 4:
|
||||
if(this.status == "200") {
|
||||
if(typeof(me.success) === "function") me.success(this, me);
|
||||
} else {
|
||||
if(typeof(me.failure) === "function") me.failure(this.status, this, me);
|
||||
}
|
||||
if(typeof(me.complete) === "function") me.complete(this, me);
|
||||
if(me.refresh) Ajax.currentlyRefreshing = false;
|
||||
break;
|
||||
default:
|
||||
console.log("I don't think I should be here.");
|
||||
break;
|
||||
}
|
||||
},
|
||||
cancelRequest: function() {
|
||||
this.req.abort();
|
||||
delete ATVUtils.Ajax.activeRequests[ this.id ];
|
||||
},
|
||||
cancelAllActiveRequests: function() {
|
||||
for ( var p in ATVUtils.Ajax.activeRequests ) {
|
||||
if( ATVUtils.Ajax.activeRequests.hasOwnProperty( p ) ) {
|
||||
var obj = ATVUtils.Ajax.activeRequests[ p ];
|
||||
if( ATVUtils.Ajax.prototype.isPrototypeOf( obj ) ) {
|
||||
obj.req.abort();
|
||||
};
|
||||
};
|
||||
};
|
||||
ATVUtils.Ajax.activeRequests = {};
|
||||
},
|
||||
createRequest: function() {
|
||||
try {
|
||||
this.req = new XMLHttpRequest();
|
||||
ATVUtils.Ajax.activeRequests[ this.id ] = this;
|
||||
if(this.refresh) ATVUtils.Ajax.currentlyRefreshing = true;
|
||||
} catch (error) {
|
||||
alert("The request could not be created: </br>" + error);
|
||||
console.error("failed to create request: " +error);
|
||||
}
|
||||
},
|
||||
open: function() {
|
||||
try {
|
||||
this.req.open(this.method, this.url, this.type);
|
||||
} catch(error) {
|
||||
console.log("failed to open request: " + error);
|
||||
}
|
||||
},
|
||||
send: function() {
|
||||
var data = this.data || null;
|
||||
try {
|
||||
this.req.send(data);
|
||||
} catch(error) {
|
||||
console.log("failed to send request: " + error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function handleNavbarNavigate( event ) {
|
||||
console.log( "Handling the navigation event."+ JSON.stringify( event ) );
|
||||
|
||||
// The navigation item ID is passed in through the event parameter.
|
||||
var navId = event.navigationItemId,
|
||||
|
||||
// Use the event.navigationItemId to retrieve the appropriate URL information this can
|
||||
// retrieved from the document navigation item.
|
||||
docUrl = document.getElementById( navId ).getElementByTagName( 'url' ).textContent,
|
||||
|
||||
// Request the XML document via URL and send any headers you need to here.
|
||||
ajax = new ATVUtils.Ajax({
|
||||
"url": docUrl,
|
||||
"success": function( xhr ){
|
||||
console.log( "successfully loaded the XHR" );
|
||||
|
||||
// After successfully retrieving the document you can manipulate the document
|
||||
// before sending it to the navigation bar.
|
||||
var doc = xhr.responseXML
|
||||
|
||||
// Once the document is ready to load pass it to the event.success function
|
||||
event.success( doc );
|
||||
},
|
||||
"failure": function( status, xhr ){
|
||||
// If the document fails to load pass an error message to the event.failure button
|
||||
event.failure( "Navigation failed to load." );
|
||||
}
|
||||
});
|
||||
|
||||
event.onCancel = function() {
|
||||
console.log("nav bar nagivation was cancelled");
|
||||
// declare an onCancel handler to handle cleanup if the user presses the menu button before the page loads.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
console.log('Reached EOF!');
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
<atv>
|
||||
<head>
|
||||
<script src="http://jcathost.dns/js/jcm.js"/>
|
||||
<script src="http://jcathost.dns/js/jcathostinfo.js"/>
|
||||
</head>
|
||||
<body>
|
||||
<optionDialog id="com.jellycat.devtools">
|
||||
@@ -14,7 +15,7 @@
|
||||
<description>These options are intended for testing your development environment only. It is crucial to refrain from utilizing these test functions on server hosts that are not under your management, as doing so may inadvertently expose sensitive data to the server's administrator.</description>
|
||||
<menu>
|
||||
<initialSelection>
|
||||
<row>4</row>
|
||||
<row>5</row>
|
||||
</initialSelection>
|
||||
<sections>
|
||||
<menuSection>
|
||||
@@ -31,7 +32,10 @@
|
||||
<oneLineMenuItem id="list_3" accessibilityLabel="Option 4" onSelect="console.log('loading storage-test-page'); atvutils.loadURL('https://'+ atv.jcathost.SigHost +'/xml/dvt/storagetest.xml');">
|
||||
<label>Load Storage Testing</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_4" accessibilityLabel="Option 5" onSelect="console.log('Unloading page'); atv.unloadPage();">
|
||||
<oneLineMenuItem id="list_4" accessibilityLabel="Option 5" onSelect="console.log('loading jcathostinfo-page'); generateJCATHOSTInfoXML();">
|
||||
<label>JCATHOST Information</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_5" accessibilityLabel="Option 6" onSelect="console.log('Unloading page'); atv.unloadPage();">
|
||||
<label>Unload Page (go back)</label>
|
||||
</oneLineMenuItem>
|
||||
</items>
|
@@ -6,7 +6,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<optionList id="com.jellycat.storagetestpage" autoSelectSingleItem="false">
|
||||
<footnote>atv.localstorage || storage data elements || JellyCAT</footnote>
|
||||
<footnote>atv.localstorage | atv.sessionstorage | storage data elements | JellyCAT</footnote>
|
||||
<items>
|
||||
<oneLineMenuItem id="list_0" accessibilityLabel="Set test session storage key" onSelect="setTestSessionStorageItem();">
|
||||
<label>Set ATV APP session storage key (test)</label>
|
||||
|
9
app/xml/help.xml
Normal file
9
app/xml/help.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<atv>
|
||||
<body>
|
||||
<dialog id="com.jellycat.help-page">
|
||||
<title>Help</title>
|
||||
<description>For assistance, please visit the JellyCAT documentation at https://github.com/SEPPDROID/JellyCAT/. If you encounter any issues, kindly raise them on the GitHub repository at https://github.com/SEPPDROID/JellyCAT/issues.</description>
|
||||
</dialog>
|
||||
</body>
|
||||
</atv>
|
36
app/xml/home.xml
Normal file
36
app/xml/home.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<atv>
|
||||
<head>
|
||||
<script src="http://jcathost.dns/js/jcm.js"/>
|
||||
</head>
|
||||
<body>
|
||||
<viewWithNavigationBar id="com.jellycat.homenav" onNavigate="handleNavbarNavigate( event )">
|
||||
<navigation currentIndex="0">
|
||||
<navigationItem id="nav1">
|
||||
<title>Home</title>
|
||||
<url></url>
|
||||
</navigationItem>
|
||||
<navigationItem id="nav2">
|
||||
<title>Favorites</title>
|
||||
<url></url>
|
||||
</navigationItem>
|
||||
<navigationItem id="nav3">
|
||||
<title>Movies</title>
|
||||
<url></url>
|
||||
</navigationItem>
|
||||
<navigationItem id="nav4">
|
||||
<title>TV-Shows</title>
|
||||
<url></url>
|
||||
</navigationItem>
|
||||
<navigationItem id="nav5">
|
||||
<title>Search</title>
|
||||
<url></url>
|
||||
</navigationItem>
|
||||
<navigationItem id="nav6">
|
||||
<title>Settings</title>
|
||||
<url>http://jcathost.dns/xml/settings.xml</url>
|
||||
</navigationItem>
|
||||
</navigation>
|
||||
</viewWithNavigationBar>
|
||||
</body>
|
||||
</atv>
|
63
app/xml/settings.xml
Normal file
63
app/xml/settings.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<atv>
|
||||
<head>
|
||||
<script src="http://jcathost.dns/js/jcm.js"/>
|
||||
</head>
|
||||
<body>
|
||||
<listWithPreview id="com.jellycat.settings">
|
||||
<header>
|
||||
<simpleHeader accessibilityLabel="Simple menu items">
|
||||
<image required="true">http://jcathost.dns/assets/img/jcsettings.png</image>
|
||||
</simpleHeader>
|
||||
</header>
|
||||
<preview>
|
||||
<crossFadePreview>
|
||||
<image>http://jcathost.dns/assets/img/jcprev.png</image>
|
||||
</crossFadePreview>
|
||||
</preview>
|
||||
<menu>
|
||||
<sections>
|
||||
<menuSection>
|
||||
<header>
|
||||
<horizontalDivider alignment="center" accessibilityLabel="Centered section">
|
||||
<title>JellyfinAPI Settings</title>
|
||||
</horizontalDivider>
|
||||
</header>
|
||||
<items>
|
||||
<oneLineMenuItem id="list_center_1" accessibilityLabel="Menu Item 1">
|
||||
<label>Menu item title</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_center_2" accessibilityLabel="Menu Item 2">
|
||||
<label>Menu item title</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_center_3" accessibilityLabel="Menu Item 3">
|
||||
<label>Menu item title</label>
|
||||
</oneLineMenuItem>
|
||||
</items>
|
||||
</menuSection>
|
||||
<menuSection>
|
||||
<header>
|
||||
<horizontalDivider alignment="center" accessibilityLabel="Centered section">
|
||||
<title>JellyCAT APP Settings</title>
|
||||
</horizontalDivider>
|
||||
</header>
|
||||
<items>
|
||||
<oneLineMenuItem id="list_center_1" accessibilityLabel="tools" onSelect="atvutils.loadURL('https://' + atv.jcathost.SigHost + '/xml/dvt/devtools.xml');">
|
||||
<label>Tools</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_center_1" accessibilityLabel="about" onSelect="atvutils.loadURL('https://' + atv.jcathost.SigHost + '/xml/about.xml');">
|
||||
<label>About</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_center_1" accessibilityLabel="about" onSelect="atvutils.loadURL('https://' + atv.jcathost.SigHost + '/xml/help.xml');">
|
||||
<label>Help</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_center_2" accessibilityLabel="exit app" onSelect="atv.exitApp();">
|
||||
<label>Exit App</label>
|
||||
</oneLineMenuItem>
|
||||
</items>
|
||||
</menuSection>
|
||||
</sections>
|
||||
</menu>
|
||||
</listWithPreview>
|
||||
</body>
|
||||
</atv>
|
1
assets/certificates/readme.txt
Normal file
1
assets/certificates/readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
The certificate files generated by CERTGEN will be stored in this directory. The JellyCAT web server will serve the "certificate.cer" for your Apple TV's profile.
|
Reference in New Issue
Block a user