BangleApps/android.html

451 lines
19 KiB
HTML
Raw Normal View History

2022-05-23 15:54:00 +00:00
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.8">
2022-05-23 15:54:00 +00:00
<link rel="stylesheet" href="css/spectre.min.css">
<link rel="stylesheet" href="css/spectre-exp.min.css">
<link rel="stylesheet" href="css/spectre-icons.min.css">
<link rel="stylesheet" href="css/pwa.css">
<link rel="stylesheet" href="css/main.css">
<link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
<link rel="manifest" href="site.webmanifest">
<link rel="mask-icon" href="img/safari-pinned-tab.svg" color="#5755d9">
<meta name="apple-mobile-web-app-title" content="BangleApps">
<meta name="application-name" content="BangleApps">
<meta name="msapplication-TileColor" content="#5755d9">
<meta name="theme-color" content="#5755d9">
<title>Bangle.js App Loader</title>
</head>
<body>
<header class="navbar-primary navbar">
<section class="navbar-section" >
2024-02-22 21:35:10 +00:00
<a href="https://banglejs.com" target="_blank" class="navbar-brand mr-2"><img src="img/banglejs-logo-small.svg" alt="Bangle.js">
2022-05-23 15:54:00 +00:00
<div>App Loader</div></a>
<!-- <a href="#" class="btn btn-link">...</a> -->
</section>
<section class="navbar-section">
<button class="btn" id="connectmydevice">Connect</button>
</section>
<!--<section class="navbar-section">
<div class="input-group input-inline">
<input class="form-input" type="text" placeholder="search">
<button class="btn btn-primary input-group-btn">Search</button>
</div>
</section>-->
</header>
<div class="container" style="padding-top:4px">
<p id="requireHTTPS" class="hidden">
<b>STOP!</b> This page <b>must</b> be served over HTTPS. Please <a>reload this page via HTTPS</a>.
</p>
</div>
<ul class="tab tab-block" id="tab-navigate">
<li class="tab-item active" id="tab-librarycontainer">
<a href="javascript:showTab('librarycontainer')">Library</a>
</li>
<li class="tab-item" id="tab-myappscontainer">
<a href="javascript:showTab('myappscontainer')">My Apps</a>
</li>
<li class="tab-item" id="tab-morecontainer">
<a href="javascript:showTab('morecontainer')">More...</a>
</li>
</ul>
<div class="container" id="toastcontainer">
</div>
<div class="container apploader-tab" id="librarycontainer">
<div class="dropdown-container">
<div class="dropdown devicetype-nav">
<a href="#" class="btn btn-link dropdown-toggle" tabindex="0">
<span>All apps</span><i class="icon icon-caret"></i>
</a>
<!-- menu component -->
<ul class="menu">
<li class="menu-item"><a>All apps</a></li>
<li class="menu-item"><a dt="BANGLEJS">Bangle.js 1</a></li>
<li class="menu-item"><a dt="BANGLEJS2">Bangle.js 2</a></li>
</ul>
</div>
<div class="filter-nav">
<label class="chip active" filterid="" data-tooltip="Show all apps">All</label>
<label class="chip tooltip" filterid="clock" data-tooltip="To tell the time!">Clocks</label>
<label class="chip tooltip" filterid="launch" data-tooltip="Choose which apps to launch">Launchers</label>
<label class="chip tooltip" filterid="game" data-tooltip="Have fun!">Games</label>
<label class="chip tooltip" filterid="tool" data-tooltip="Useful applications">Tools</label>
<label class="chip tooltip" filterid="textinput" data-tooltip="To allow you to enter text">Keyboards</label>
<label class="chip tooltip" filterid="widget" data-tooltip="Appear in the top bar of Bangle.js apps">Widgets</label>
<label class="chip tooltip" filterid="bluetooth" data-tooltip="Using Bluetooth Functionality">Bluetooth</label>
<label class="chip tooltip" filterid="outdoors" data-tooltip="For outdoor use">Outdoors</label>
<label class="chip tooltip" filterid="ram" data-tooltip="Apps that don't save anything to flash memory">Online</label>
<label class="chip tooltip" filterid="clkinfo" data-tooltip="Info displayed on clocks, or clocks with info">Clock Info</label>
2023-11-13 08:54:01 +00:00
<label class="chip tooltip" filterid="health" data-tooltip="Apps for your health">Health</label>
<label class="chip tooltip" filterid="favourites" data-tooltip="Apps that you've liked ❤️">Favourites</label>
2022-05-23 15:54:00 +00:00
</div>
<div class="sort-nav hidden">
<span>Sort by:</span>
<label class="chip active" sortid="">None</label>
<label class="chip hidden tooltip" sortid="created" data-tooltip="Most recent apps">New</label>
<label class="chip hidden tooltip" sortid="modified" data-tooltip="Most recently changed">Updated</label>
<label class="chip hidden tooltip" sortid="installs" data-tooltip="Most installed by users">Installed</label>
<label class="chip hidden tooltip" sortid="favourites" data-tooltip="Most liked by users">Favourited</label>
2022-05-23 15:54:00 +00:00
</div>
</div>
<div class="panel" style="clear:both">
<div class="panel-header">
<div class="input-group" id="searchform">
<input class="form-input" type="text" placeholder="Keywords...">
<button class="btn btn-primary input-group-btn">Search</button>
</div>
</div>
<div class="panel-body columns"><!-- apps go here --></div>
</div>
</div>
<div class="container apploader-tab" id="myappscontainer" style="display:none">
<div class="panel">
<div class="panel-header" style="text-align:right">
<button class="btn refresh">Refresh...</button>
<button class="btn btn-primary updateapps hidden">Update X apps</button>
</div>
<div class="panel-body columns"><!-- apps go here --></div>
</div>
</div>
<div class="container apploader-tab" id="morecontainer" style="display:none">
<div class="hero bg-gray">
<div class="hero-body">
<a href="https://banglejs.com" target="_blank"><img src="img/banglejs-logo-mid.png" alt="Bangle.js"></a>
<h2>App Loader</h2>
<p>A tool for uploading and removing apps from <a href="https://banglejs.com" target="_blank">Bangle.js Smart Watches</a></p>
</div>
</div>
<div class="container" style="padding-top: 8px;">
<p><b>Can't connect?</b> Check out the <a href="https://www.espruino.com/Troubleshooting+Bangle.js" target="_blank">Bangle.js Troubleshooting page</a>
<p id="apploaderlinks"></p>
<p>Check out <a href="https://github.com/espruino/BangleApps" target="_blank">the Source on GitHub</a>, or
find out <a href="https://www.espruino.com/Bangle.js+App+Loader" target="_blank">how to add your own app</a></p>
<p>Using <a href="https://espruino.com/" target="_blank">Espruino</a>, Icons from <a href="https://icons8.com/" target="_blank">icons8.com</a></p>
<h3>Utilities</h3>
<p>
<button class="btn tooltip" id="settime" data-tooltip="Set the Bangle's time to your Browser's time">Set Bangle.js Time</button>
<button class="btn tooltip" id="screenshot" data-tooltip="Create screenshot">Screenshot</button>
<button class="btn tooltip" id="downloadallapps" data-tooltip="Download all Bangle.js files to a ZIP file">Backup</button>
<button class="btn tooltip" id="uploadallapps" data-tooltip="Restore Bangle.js from a ZIP file">Restore</button>
</p><p>
<button class="btn tooltip" id="removeall" data-tooltip="Delete everything, leave it blank">Remove all Apps</button>
<button class="btn tooltip" id="reinstallall" data-tooltip="Re-install every app, leave all data">Reinstall apps</button>
<button class="btn tooltip" id="installdefault" data-tooltip="Delete everything, install default apps">Install default apps</button>
<button class="btn tooltip" id="installfavourite" data-tooltip="Delete everything, install your favourites">Install favourite apps</button>
<button class="btn tooltip" id="defaultbanglesettings" data-tooltip="Reset your Bangle's settings to the defaults">Reset Settings</button>
</p><p>
<button class="btn tooltip" id="newGithubIssue" data-tooltip="Create a new issue on GitHub">New issue on GitHub</button>
<button class="btn tooltip" id="webideremote" data-tooltip="Enable the Web IDE remote server">Web IDE Remote</button>
</p>
2022-05-23 15:54:00 +00:00
<h3>Settings</h3>
<div class="form-group">
<label class="form-switch">
<input type="checkbox" id="settings-pretokenise">
<i class="form-icon"></i> Pretokenise apps before upload (smaller, faster apps)
</label>
<label class="form-switch">
<input type="checkbox" id="settings-settime">
<i class="form-icon"></i> Always update time when we connect
</label>
2023-04-28 07:17:15 +00:00
<label class="form-switch">
<input type="checkbox" id="settings-usage-stats">
<i class="form-icon"></i> Send app analytics to banglejs.com (apps installed, favourites, firmware version).<br/>
<small>Used for 'Sort by Installed/Favourited' functionality. See the <a href="http://www.espruino.com/Privacy">privacy policy</a></small>.
</label>
2022-05-23 15:54:00 +00:00
<div class="form-group">
<select class="form-select form-inline" id="settings-lang" style="width: 10em">
<option value="">None (English)</option>
</select>&nbsp;&nbsp;<span>Translations (<a href="https://github.com/espruino/BangleApps/issues/1311" target="_blank">BETA - more info</a>). Any apps that are uploaded to Bangle.js after changing this will have any text automatically translated.</span>
</div>
2023-04-28 07:17:15 +00:00
<details>
<summary>Advanced Options</summary>
<label class="form-switch">
<input type="checkbox" id="settings-minify">
<i class="form-icon"></i> Minify apps before upload (⚠DANGER⚠: Not recommended. Uploads smaller, faster apps but this <b>will</b> break many apps)
2023-04-28 07:17:15 +00:00
</label>
<label class="form-switch">
<input type="checkbox" id="settings-alwaysAllowUpdate">
<i class="form-icon"></i> Always show "reinstall app" button <i class="icon icon-refresh"></i> regardless of the version
</label>
<label class="form-switch">
<input type="checkbox" id="settings-autoReload">
<i class="form-icon"></i> Automatically reload watch after app App Loader actions (removes "Hold button" prompt)
</label>
<button class="btn" id="defaultsettings">Reset App Loader settings to defaults</button>
2023-04-28 07:17:15 +00:00
</details>
2022-05-23 15:54:00 +00:00
</div>
<div id="more-deviceinfo" style="display:none">
<h3>Device info</h3>
<div id="more-deviceinfo-content"></div>
<div class="editor--terminal">
<div class="editor__canvas" style="position:relative;height:20rem;display:none;"></div>
<button class="btn" id="terminalEnable">Enable Terminal</button>
</div>
2022-05-23 15:54:00 +00:00
</div>
</div>
</div>
<footer class="floating hidden">
<!-- PWA Install button, hidden by default -->
2022-05-23 15:54:00 +00:00
<div id="installContainer" class="hidden">
<button id="butInstall" type="button">
Install
</button>
</div>
</footer>
<script src="webtools/puck.js"></script>
<script src="webtools/heatshrink.js"></script>
2022-05-23 15:54:00 +00:00
<script src="core/lib/marked.min.js"></script>
<script src="core/lib/espruinotools.js"></script>
<script src="core/js/utils.js"></script>
<script src="loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script> <!-- for backup.js -->
<script src="backup.js"></script>
<script src="core/js/ui.js"></script>
<script src="core/js/comms.js"></script>
<script src="core/js/appinfo.js"></script>
<script src="core/js/index.js"></script>
<script src="core/js/pwa.js" defer></script>
<!-- FIXME - use espruino.com/ide, github -->
<script src="https://espruino.github.io/EspruinoWebIDE/js/libs/peerjs.min.js"></script>
<script src="https://espruino.github.io/EspruinoWebIDE/EspruinoTools/libs/webrtc-connection.js"></script>
2022-05-23 15:54:00 +00:00
<script>
/*Android = {
bangleTx : function(data) {
console.log("TX : "+JSON.stringify(data));
}
};*/
/*document.getElementById("test").addEventListener("click", function() {
console.log("Pressed");
Android.bangleTx("LED1.toggle();\n");
});*/
if (typeof Android!=="undefined") {
console.log("Running in Android, overwrite Puck library");
var isBusy = false;
var queue = [];
var connection = {
cb : function(data) {},
write : function(data, writecb) {
Android.bangleTx(data);
Puck.writeProgress(data.length, data.length);
if (writecb) setTimeout(writecb,10);
},
close : function() {},
2023-05-05 11:52:45 +00:00
on : function(evt,cb) { connection.handlers[evt] = cb; },
2022-05-23 15:54:00 +00:00
received : "",
hadData : false,
handlers : []
2022-05-23 15:54:00 +00:00
}
connection.on("data", function(d) {
connection.received += d;
connection.hadData = true;
if (connection.cb) connection.cb(d);
});
2022-05-23 15:54:00 +00:00
function bangleRx(data) {
// document.getElementById("status").innerText = "RX:"+data;
// call data event
if (connection.handlers["data"])
connection.handlers["data"](data);
2022-05-23 15:54:00 +00:00
}
function log(level, s) {
if (Puck.log) Puck.log(level, s);
}
function handleQueue() {
if (!queue.length) return;
var q = queue.shift();
log(3,"Executing "+JSON.stringify(q)+" from queue");
if (q.type == "write") Puck.write(q.data, q.callback, q.callbackNewline);
else log(1,"Unknown queue item "+JSON.stringify(q));
}
/* convenience function... Write data, call the callback with data:
callbackNewline = false => if no new data received for ~0.2 sec
callbackNewline = true => after a newline */
function write(data, callback, callbackNewline) {
let result;
/// If there wasn't a callback function, then promisify
if (typeof callback !== 'function') {
callbackNewline = callback;
result = new Promise((resolve, reject) => callback = (value, err) => {
if (err) reject(err);
else resolve(value);
});
}
if (isBusy) {
log(3, "Busy - adding Puck.write to queue");
queue.push({type:"write", data:data, callback:callback, callbackNewline:callbackNewline});
return result;
}
var cbTimeout;
function onWritten() {
if (callbackNewline) {
connection.cb = function(d) {
var newLineIdx = connection.received.indexOf("\n");
if (newLineIdx>=0) {
var l = connection.received.substr(0,newLineIdx);
connection.received = connection.received.substr(newLineIdx+1);
connection.cb = undefined;
if (cbTimeout) clearTimeout(cbTimeout);
cbTimeout = undefined;
if (callback)
callback(l);
isBusy = false;
handleQueue();
}
};
}
// wait for any received data if we have a callback...
var maxTime = 300; // 30 sec - Max time we wait in total, even if getting data
var dataWaitTime = callbackNewline ? 100/*10 sec if waiting for newline*/ : 3/*300ms*/;
var maxDataTime = dataWaitTime; // max time we wait after having received data
cbTimeout = setTimeout(function timeout() {
cbTimeout = undefined;
if (maxTime) maxTime--;
if (maxDataTime) maxDataTime--;
if (connection.hadData) maxDataTime=dataWaitTime;
if (maxDataTime && maxTime) {
cbTimeout = setTimeout(timeout, 100);
} else {
connection.cb = undefined;
if (callback)
callback(connection.received);
isBusy = false;
handleQueue();
connection.received = "";
}
connection.hadData = false;
}, 100);
}
if (!connection.txInProgress) connection.received = "";
isBusy = true;
connection.write(data, onWritten);
return result
}
// ----------------------------------------------------------
2022-05-23 15:54:00 +00:00
Puck = {
/// Are we writing debug information? 0 is no, 1 is some, 2 is more, 3 is all.
debug : Puck.debug,
/// Should we use flow control? Default is true
flowControl : true,
/// Used internally to write log information - you can replace this with your own function
log : function(level, s) { if (level <= this.debug) console.log("<BLE> "+s)},
/// Called with the current send progress or undefined when done - you can replace this with your own function
writeProgress : Puck.writeProgress,
connect : function(callback) {
setTimeout(callback, 10, connection);
return connection;
2022-05-23 15:54:00 +00:00
},
write : write,
eval : function(expr, cb) {
const response = write('\x10Bluetooth.println(JSON.stringify(' + expr + '))\n', true)
.then(function (d) {
try {
return JSON.parse(d);
} catch (e) {
log(1, "Unable to decode " + JSON.stringify(d) + ", got " + e.toString());
return Promise.reject(d);
}
});
if (cb) {
return void response.then(cb, (err) => cb(null, err));
} else {
return response;
}
},
isConnected : function() { return true; },
getConnection : function() { return connection; },
close : function() {
if (connection)
connection.close();
},
};
// no need for header
document.getElementsByTagName("header")[0].style="display:none";
// force connection attempt automatically
setTimeout(function() {
getInstalledApps(true).catch(err => {
showToast("Device connection failed, "+err,"error");
if ("object"==typeof err) console.log(err.stack);
});
}, 500);
} else {
showToast("You're running the App Loader version for Gadgetbridge, but you don't seem to be in Gadgetbridge!","error");
}
function showWebRTCID(id) {
showToast("Bridge's Peer ID: "+id);
showPrompt("Web IDE Remote Access",`
Remote access enabled. Peer ID:
<br/><br/>
<b>${id}</b>
<br/><br/>
Go to <b>espruino.com/ide</b> on your
desktop and enter this code under
<b>Remote Connection Bridge Peer ID</b> in Settings.
Then connect to the <b>Android</b> device.
`,{ok:1},false/*shouldEscapeHtml*/).then(() => {
}, function() { /* cancelled */ });
2022-05-23 15:54:00 +00:00
}
// Button to Enable Remote Web IDE
var el = document.getElementById("webideremote");
var webrtc;
if (el) el.addEventListener("click", event=>{
if (webrtc) showWebRTCID(webrtc.peerId);
else {
webrtc = webrtcInit({
bridge:true,
onStatus : function(s) {
showToast(s);
},
onPeerID : function(id) {
showWebRTCID(id);
},
onGetPorts : function(cb) {
cb([{path:"Android",description:"Remote Device Connection",type:"socket"}]);
},
onPortConnect : function(serialPort, cb) {
cb(); // we're already connected...
},
onPortDisconnect : function(serialPort) {
},
onPortWrite : function(data, cb) {
Puck.write(data, cb);
}
});
connection.on("data", function(d) {
webrtc.onPortReceived(d);
});
}
});
2022-05-23 15:54:00 +00:00
</script>
</body>
</html>