Merge branch 'master' of https://github.com/espruino/BangleApps
commit
fdf6ee24c1
|
|
@ -9,3 +9,4 @@ Changed for individual apps are listed in `apps/appname/ChangeLog`
|
|||
* Fix issue removing an app that was just installed (fix #253)
|
||||
* Add `Favourite` functionality
|
||||
* Version number now clickable even when you're at the latest version (fix #291)
|
||||
* Rewrite 'getInstalledApps' to minimize RAM usage
|
||||
|
|
|
|||
36
apps.json
36
apps.json
|
|
@ -78,7 +78,7 @@
|
|||
{ "id": "welcome",
|
||||
"name": "Welcome",
|
||||
"icon": "app.png",
|
||||
"version":"0.06",
|
||||
"version":"0.07",
|
||||
"description": "Appears at first boot and explains how to use Bangle.js",
|
||||
"tags": "start,welcome",
|
||||
"allow_emulator":true,
|
||||
|
|
@ -86,13 +86,14 @@
|
|||
{"name":"welcome.boot.js","url":"boot.js"},
|
||||
{"name":"welcome.app.js","url":"app.js"},
|
||||
{"name":"welcome.settings.js","url":"settings.js"},
|
||||
{"name":"welcome.settings.json","url":"settings-default.json","evaluate":true},
|
||||
{"name":"welcome.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "gbridge",
|
||||
"name": "Gadgetbridge",
|
||||
"icon": "app.png",
|
||||
"version":"0.08",
|
||||
"version":"0.09",
|
||||
"description": "The default notification handler for Gadgetbridge notifications from Android",
|
||||
"tags": "tool,system,android,widget",
|
||||
"type":"widget",
|
||||
|
|
@ -119,7 +120,7 @@
|
|||
{ "id": "setting",
|
||||
"name": "Settings",
|
||||
"icon": "settings.png",
|
||||
"version":"0.14",
|
||||
"version":"0.15",
|
||||
"description": "A menu for setting up Bangle.js",
|
||||
"tags": "tool,system",
|
||||
"storage": [
|
||||
|
|
@ -279,7 +280,7 @@
|
|||
{ "id": "gpsrec",
|
||||
"name": "GPS Recorder",
|
||||
"icon": "app.png",
|
||||
"version":"0.06",
|
||||
"version":"0.07",
|
||||
"interface": "interface.html",
|
||||
"description": "Application that allows you to record a GPS track. Can run in background",
|
||||
"tags": "tool,outdoors,gps,widget",
|
||||
|
|
@ -329,7 +330,7 @@
|
|||
{ "id": "widbat",
|
||||
"name": "Battery Level Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"description": "Show the current battery level and charging status in the top right of the clock",
|
||||
"tags": "widget,battery",
|
||||
"type":"widget",
|
||||
|
|
@ -341,7 +342,7 @@
|
|||
"name": "Battery Level Widget (with percentage)",
|
||||
"shortName": "Battery Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.08",
|
||||
"version":"0.09",
|
||||
"description": "Show the current battery level and charging status in the top right of the clock, with charge percentage",
|
||||
"tags": "widget,battery",
|
||||
"type":"widget",
|
||||
|
|
@ -354,7 +355,7 @@
|
|||
{ "id": "widbt",
|
||||
"name": "Bluetooth Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.03",
|
||||
"version":"0.04",
|
||||
"description": "Show the current Bluetooth connection status in the top right of the clock",
|
||||
"tags": "widget,bluetooth",
|
||||
"type":"widget",
|
||||
|
|
@ -362,6 +363,18 @@
|
|||
{"name":"widbt.wid.js","url":"widget.js"}
|
||||
]
|
||||
},
|
||||
{ "id": "widram",
|
||||
"name": "RAM Widget",
|
||||
"shortName":"RAM Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.01",
|
||||
"description": "Display your Bangle's available RAM percentage in a widget",
|
||||
"tags": "widget",
|
||||
"type": "widget",
|
||||
"storage": [
|
||||
{"name":"widram.wid.js","url":"widget.js"}
|
||||
]
|
||||
},
|
||||
{ "id": "hrm",
|
||||
"name": "Heart Rate Monitor",
|
||||
"icon": "heartrate.png",
|
||||
|
|
@ -504,13 +517,14 @@
|
|||
"id": "ncstart",
|
||||
"name": "NCEU Startup",
|
||||
"icon": "start.png",
|
||||
"version":"0.03",
|
||||
"version":"0.04",
|
||||
"description": "NodeConfEU 2019 'First Start' Sequence",
|
||||
"tags": "start,welcome",
|
||||
"storage": [
|
||||
{"name":"ncstart.app.js","url":"start.js"},
|
||||
{"name":"ncstart.boot.js","url":"boot.js"},
|
||||
{"name":"ncstart.settings.js","url":"settings.js"},
|
||||
{"name":"ncstart.settings.json","url":"settings-default.json","evaluate":true},
|
||||
{"name":"ncstart.img","url":"start-icon.js","evaluate":true},
|
||||
{"name":"nc-bangle.img","url":"start-bangle.js","evaluate":true},
|
||||
{"name":"nc-nceu.img","url":"start-nceu.js","evaluate":true},
|
||||
|
|
@ -775,7 +789,7 @@
|
|||
{ "id": "widclk",
|
||||
"name": "Digital clock widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.03",
|
||||
"version":"0.04",
|
||||
"description": "A simple digital clock widget",
|
||||
"tags": "widget,clock",
|
||||
"type":"widget",
|
||||
|
|
@ -1219,8 +1233,8 @@
|
|||
"name": "Snake",
|
||||
"shortName":"Snake",
|
||||
"icon": "snake.png",
|
||||
"version":"0.01",
|
||||
"description": "The classic snake game. Eat apples and don't bite your tail:",
|
||||
"version":"0.02",
|
||||
"description": "The classic snake game. Eat apples and don't bite your tail.",
|
||||
"tags": "game,fun",
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@
|
|||
0.06: Gadgetbridge App 'Connected' state is no longer toggleable
|
||||
0.07: Move configuration to settings menu
|
||||
0.08: Don't turn on LCD at start of every song
|
||||
0.09: Update Bluetooth connection state automatically
|
||||
|
|
|
|||
|
|
@ -189,8 +189,8 @@
|
|||
g.flip(); // turns screen on
|
||||
}
|
||||
|
||||
NRF.on("connected", changedConnectionState);
|
||||
NRF.on("disconnected", changedConnectionState);
|
||||
NRF.on("connect", changedConnectionState);
|
||||
NRF.on("disconnect", changedConnectionState);
|
||||
|
||||
WIDGETS["gbridgew"] = { area: "tl", width: 24, draw: draw };
|
||||
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@
|
|||
0.04: Properly Fix GPS time display in gpsrec app
|
||||
0.05: Tweaks for variable size widget system
|
||||
0.06: Ensure widget update itself (fix #118) and change to using icons
|
||||
0.07: Added @jeffmer's awesome track viewer
|
||||
|
|
|
|||
|
|
@ -70,27 +70,65 @@ function viewTracks() {
|
|||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
function getTrackInfo(fn) {
|
||||
var filename = getFN(fn);
|
||||
var minLat = 90;
|
||||
var maxLat = -90;
|
||||
var minLong = 180;
|
||||
var maxLong = -180;
|
||||
var starttime, duration=0;
|
||||
var f = require("Storage").open(filename,"r");
|
||||
if (f===undefined) return;
|
||||
var l = f.readLine(f);
|
||||
var nl = 0, c, n;
|
||||
if (l!==undefined) {
|
||||
c = l.split(",");
|
||||
starttime = parseInt(c[0]);
|
||||
}
|
||||
// pushed this loop together to try and bump loading speed a little
|
||||
while(l!==undefined) {
|
||||
++nl;c=l.split(",");
|
||||
n = parseFloat(c[1]);if(n>maxLat)maxLat=n;if(n<minLat)minLat=n;
|
||||
n = parseFloat(c[2]);if(n>maxLong)maxLong=n;if(n<minLong)minLong=n;
|
||||
l = f.readLine(f);
|
||||
}
|
||||
if (c) duration = parseInt(c[0]) - starttime;
|
||||
var lfactor = Math.cos(minLat*Math.PI/180);
|
||||
var ylen = (maxLat-minLat);
|
||||
var xlen = (maxLong-minLong)* lfactor;
|
||||
var scale = xlen>ylen ? 200/xlen : 200/ylen;
|
||||
return {
|
||||
fn : fn,
|
||||
filename : filename,
|
||||
time : new Date(starttime),
|
||||
records : nl,
|
||||
minLat : minLat, maxLat : maxLat,
|
||||
minLong : minLong, maxLong : maxLong,
|
||||
lfactor : lfactor,
|
||||
scale : scale,
|
||||
duration : Math.round(duration/1000)
|
||||
};
|
||||
}
|
||||
|
||||
function asTime(v){
|
||||
var mins = Math.floor(v/60);
|
||||
var secs = v-mins*60;
|
||||
return ""+mins.toString()+"m "+secs.toString()+"s";
|
||||
}
|
||||
|
||||
function viewTrack(n) {
|
||||
E.showMessage("Loading...","GPS Track "+n);
|
||||
var info = getTrackInfo(n);
|
||||
const menu = {
|
||||
'': { 'title': 'GPS Track '+n }
|
||||
};
|
||||
var trackCount = 0;
|
||||
var trackTime;
|
||||
var f = require("Storage").open(getFN(n),"r");
|
||||
var l = f.readLine();
|
||||
if (l!==undefined) {
|
||||
var c = l.split(",");
|
||||
trackTime = new Date(parseInt(c[0]));
|
||||
}
|
||||
while (l!==undefined) {
|
||||
trackCount++;
|
||||
// TODO: min/max/length of track?
|
||||
l = f.readLine();
|
||||
}
|
||||
if (trackTime)
|
||||
menu[" "+trackTime.toISOString().substr(0,16).replace("T"," ")] = function(){};
|
||||
menu[trackCount+" records"] = function(){};
|
||||
// TODO: option to draw it? Just scan through, project using min/max
|
||||
if (info.time)
|
||||
menu[info.time.toISOString().substr(0,16).replace("T"," ")] = function(){};
|
||||
menu["Duration"] = { value : asTime(info.duration)};
|
||||
menu["Records"] = { value : ""+info.records };
|
||||
menu['Plot'] = function() {
|
||||
plotTrack(info);
|
||||
};
|
||||
menu['Erase'] = function() {
|
||||
E.showPrompt("Delete Track?").then(function(v) {
|
||||
if (v) {
|
||||
|
|
@ -107,4 +145,80 @@ function viewTrack(n) {
|
|||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
function plotTrack(info) {
|
||||
function xcoord(long){
|
||||
return 30 + Math.round((long-info.minLong)*info.lfactor*info.scale);
|
||||
}
|
||||
|
||||
function ycoord(lat){
|
||||
return 210 - Math.round((lat - info.minLat)*info.scale);
|
||||
}
|
||||
|
||||
function radians(a) {
|
||||
return a*Math.PI/180;
|
||||
}
|
||||
|
||||
function distance(lat1,long1,lat2,long2){
|
||||
var x = radians(long1-long2) * Math.cos(radians((lat1+lat2)/2));
|
||||
var y = radians(lat2-lat1);
|
||||
return Math.sqrt(x*x + y*y) * 6371000;
|
||||
}
|
||||
|
||||
E.showMenu(); // remove menu
|
||||
g.setColor(1,0.5,0.5);
|
||||
g.setFont("Vector",16);
|
||||
g.fillRect(9,80,11,120);
|
||||
g.fillPoly([9,60,19,80,0,80]);
|
||||
g.setColor(1,1,1);
|
||||
g.drawString("N",2,40);
|
||||
g.drawString("Track"+info.fn.toString()+" - Loading",10,220);
|
||||
g.setColor(0,0,0);
|
||||
g.fillRect(0,220,239,239);
|
||||
g.setColor(1,1,1);
|
||||
g.drawString(asTime(info.duration),10,220);
|
||||
var f = require("Storage").open(info.filename,"r");
|
||||
if (f===undefined) return;
|
||||
var l = f.readLine(f);
|
||||
var ox=0;
|
||||
var oy=0;
|
||||
var olat,olong,dist=0;
|
||||
var first = true;
|
||||
var i=0;
|
||||
while(l!==undefined) {
|
||||
var c = l.split(",");
|
||||
var lat = parseFloat(c[1]);
|
||||
var long = parseFloat(c[2]);
|
||||
var x = xcoord(long);
|
||||
var y = ycoord(lat);
|
||||
if (first) {
|
||||
g.moveTo(x,y);
|
||||
g.setColor(0,1,0);
|
||||
g.fillCircle(x,y,5);
|
||||
g.setColor(1,1,1);
|
||||
first = false;
|
||||
} else if (x!=ox || y!=oy) {
|
||||
g.lineTo(x,y);
|
||||
}
|
||||
if (!first) {
|
||||
var d = distance(olat,olong,lat,long);
|
||||
if (!isNaN(d)) dist+=d;
|
||||
}
|
||||
olat = lat;
|
||||
olong = long;
|
||||
ox = x;
|
||||
oy = y;
|
||||
l = f.readLine(f);
|
||||
}
|
||||
g.setColor(1,0,0);
|
||||
g.fillCircle(ox,oy,5);
|
||||
g.setColor(1,1,1);
|
||||
g.drawString(require("locale").distance(dist),120,220);
|
||||
g.setFont("6x8",2);
|
||||
g.setFontAlign(0,0,3);
|
||||
g.drawString("Back",230,200);
|
||||
setWatch(function() {
|
||||
viewTrack(info.fn);
|
||||
}, BTN3);
|
||||
}
|
||||
|
||||
showMainMenu();
|
||||
|
|
|
|||
|
|
@ -2,3 +2,6 @@
|
|||
Renamed as nodeconf-specific
|
||||
0.03: Move configuration into App/widget settings
|
||||
Move loader into welcome.boot.js
|
||||
0.04: Run again when updated
|
||||
Don't run again when settings app is updated (or absent)
|
||||
Add "Run Now" option to settings
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
(function() {
|
||||
let s = require('Storage').readJSON('setting.json', 1) || {}
|
||||
let s = require('Storage').readJSON('ncstart.settings.json', 1)
|
||||
|| require('Storage').readJSON('setting.json', 1)
|
||||
|| {welcomed: true} // do NOT run if global settings are also absent
|
||||
if (!s.welcomed && require('Storage').read('ncstart.app.js')) {
|
||||
setTimeout(() => {
|
||||
s.welcomed = true
|
||||
require('Storage').write('setting.json', s)
|
||||
require('Storage').write('ncstart.settings.json', s)
|
||||
load('ncstart.app.js')
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"welcomed": false
|
||||
}
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
// The welcome app is special, and gets to use global settings
|
||||
(function(back) {
|
||||
let settings = require('Storage').readJSON('setting.json', 1) || {}
|
||||
let settings = require('Storage').readJSON('ncstart.settings.json', 1)
|
||||
|| require('Storage').readJSON('setting.json', 1) || {}
|
||||
E.showMenu({
|
||||
'': { 'title': 'NCEU Startup' },
|
||||
'Run again': {
|
||||
'Run on Next Boot': {
|
||||
value: !settings.welcomed,
|
||||
format: v => v ? 'Yes' : 'No',
|
||||
onchange: v => {
|
||||
settings.welcomed = v ? undefined : true
|
||||
require('Storage').write('setting.json', settings)
|
||||
},
|
||||
format: v => v ? 'OK' : 'No',
|
||||
onchange: v => require('Storage').write('ncstart.settings.json', {welcomed: !v}),
|
||||
},
|
||||
'Run Now': () => load('ncstart.app.js'),
|
||||
'< Back': back,
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,3 +16,4 @@
|
|||
Make capitalization more consistent
|
||||
Move LCD Brightness menu into more general LCD menu
|
||||
0.14: Reduce memory usage when running app settings page
|
||||
0.15: Reduce memory usage when running default clock chooser (#294)
|
||||
|
|
|
|||
|
|
@ -296,10 +296,10 @@ function makeConnectable() {
|
|||
});
|
||||
}
|
||||
function showClockMenu() {
|
||||
var clockApps = require("Storage").list(/\.info$/).map(app => {
|
||||
try { return require("Storage").readJSON(app); }
|
||||
catch (e) { }
|
||||
}).filter(app => app.type == "clock").sort((a, b) => a.sortorder - b.sortorder);
|
||||
var clockApps = require("Storage").list(/\.info$/)
|
||||
.map(app => {var a=storage.readJSON(app, 1);return (a&&a.type == "clock")?a:undefined})
|
||||
.filter(app => app) // filter out any undefined apps
|
||||
.sort((a, b) => a.sortorder - b.sortorder);
|
||||
const clockMenu = {
|
||||
'': {
|
||||
'title': 'Select Clock',
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
0.01: New App!
|
||||
0.01: New App!
|
||||
0.02: Performance and graphic improvements, game pause, beep and buzz
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Snake
|
||||
|
||||

|
||||

|
||||
|
||||
The legentary classic game is now available on Bangle.js!
|
||||
Eat apples and don't bite your tail.
|
||||
|
|
@ -11,3 +11,4 @@ Eat apples and don't bite your tail.
|
|||
- DOWN: BTN3
|
||||
- LEFT: BTN4
|
||||
- RIGHT: BTN5
|
||||
- PAUSE: BTN2
|
||||
|
|
|
|||
|
|
@ -1,37 +1,61 @@
|
|||
Bangle.setLCDMode("120x120");
|
||||
|
||||
const H = g.getWidth();
|
||||
const W = g.getHeight();
|
||||
let running = true;
|
||||
let score = 0;
|
||||
let d;
|
||||
|
||||
// game world
|
||||
const gridSize = 40;
|
||||
const gridSize = 20;
|
||||
const tileSize = 6;
|
||||
let nextX = 0;
|
||||
let nextY = 0;
|
||||
|
||||
// snake
|
||||
const defaultTailSize = 3;
|
||||
let tailSize = defaultTailSize;
|
||||
const snakeTrail = [];
|
||||
let snakeX = 10;
|
||||
let snakeY = 10;
|
||||
const snake = { x: 10, y: 10 };
|
||||
const apple = { x: Math.floor(Math.random() * gridSize), y: Math.floor(Math.random() * gridSize) };
|
||||
|
||||
// apple
|
||||
let appleX = Math.floor(Math.random() * gridSize);
|
||||
let appleY = Math.floor(Math.random() * gridSize);
|
||||
function drawBackground(){
|
||||
g.setColor("#000000");
|
||||
g.fillRect(0, 0, H, W);
|
||||
}
|
||||
|
||||
function drawApple(){
|
||||
g.setColor("#FF0000");
|
||||
g.fillCircle((apple.x * tileSize) + tileSize/2, (apple.y * tileSize) + tileSize/2, tileSize/2);
|
||||
}
|
||||
|
||||
function drawSnake(){
|
||||
g.setColor("#008000");
|
||||
for (let i = 0; i < snakeTrail.length; i++) {
|
||||
g.fillRect(snakeTrail[i].x * tileSize, snakeTrail[i].y * tileSize, snakeTrail[i].x * tileSize + tileSize, snakeTrail[i].y * tileSize + tileSize);
|
||||
|
||||
//snake bites it's tail
|
||||
if (snakeTrail[i].x === snake.x && snakeTrail[i].y === snake.y && tailSize > defaultTailSize) {
|
||||
Bangle.buzz(1000);
|
||||
gameOver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawScore(){
|
||||
g.setColor("#FFFFFF");
|
||||
g.setFont("6x8");
|
||||
g.setFontAlign(0, 0);
|
||||
g.drawString("Score:" + score, W / 2, 10);
|
||||
}
|
||||
|
||||
function gameStart() {
|
||||
running = true;
|
||||
score = 0;
|
||||
}
|
||||
|
||||
function gameStop() {
|
||||
function gameOver() {
|
||||
g.clear();
|
||||
g.setColor("#FFFFFF");
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString("GAME OVER!", W / 2, H / 2 - 20);
|
||||
g.drawString("Tap to Restart", W / 2, H / 2 + 20);
|
||||
g.setFont("6x8");
|
||||
g.drawString("GAME OVER!", W / 2, H / 2 - 10);
|
||||
g.drawString("Tap to Restart", W / 2, H / 2 + 10);
|
||||
running = false;
|
||||
tailSize = defaultTailSize;
|
||||
}
|
||||
|
|
@ -41,66 +65,50 @@ function draw() {
|
|||
return;
|
||||
}
|
||||
|
||||
g.clear();
|
||||
|
||||
// move snake in next pos
|
||||
snakeX += nextX;
|
||||
snakeY += nextY;
|
||||
snake.x += nextX;
|
||||
snake.y += nextY;
|
||||
|
||||
// snake over game world?
|
||||
if (snakeX < 0) {
|
||||
snakeX = gridSize - 1;
|
||||
// snake over game world
|
||||
if (snake.x < 0) {
|
||||
snake.x = gridSize - 1;
|
||||
}
|
||||
if (snake.x > gridSize - 1) {
|
||||
snake.x = 0;
|
||||
}
|
||||
|
||||
if (snakeX > gridSize - 1) {
|
||||
snakeX = 0;
|
||||
if (snake.y < 0) {
|
||||
snake.y = gridSize - 1;
|
||||
}
|
||||
if (snake.y > gridSize - 1) {
|
||||
snake.y = 0;
|
||||
}
|
||||
|
||||
if (snakeY < 0) {
|
||||
snakeY = gridSize - 1;
|
||||
}
|
||||
if (snakeY > gridSize - 1) {
|
||||
snakeY = 0;
|
||||
}
|
||||
|
||||
//snake bite apple?
|
||||
if (snakeX === appleX && snakeY === appleY) {
|
||||
//snake bite apple
|
||||
if (snake.x === apple.x && snake.y === apple.y) {
|
||||
Bangle.beep(20);
|
||||
tailSize++;
|
||||
score++;
|
||||
|
||||
appleX = Math.floor(Math.random() * gridSize);
|
||||
appleY = Math.floor(Math.random() * gridSize);
|
||||
apple.x = Math.floor(Math.random() * gridSize);
|
||||
apple.y = Math.floor(Math.random() * gridSize);
|
||||
drawApple();
|
||||
}
|
||||
|
||||
//paint background
|
||||
g.setColor("#000000");
|
||||
g.fillRect(0, 0, H, W);
|
||||
|
||||
// paint snake
|
||||
g.setColor("#008000");
|
||||
|
||||
for (let i = 0; i < snakeTrail.length; i++) {
|
||||
g.fillRect(snakeTrail[i].x * tileSize, snakeTrail[i].y * tileSize, snakeTrail[i].x * tileSize + tileSize, snakeTrail[i].y * tileSize + tileSize);
|
||||
|
||||
//snake bites it's tail?
|
||||
if (snakeTrail[i].x === snakeX && snakeTrail[i].y === snakeY && tailSize > defaultTailSize) {
|
||||
gameStop();
|
||||
}
|
||||
}
|
||||
|
||||
// paint apple
|
||||
g.setColor("#FF0000");
|
||||
g.fillRect(appleX * tileSize, appleY * tileSize, appleX * tileSize + tileSize, appleY * tileSize + tileSize);
|
||||
|
||||
// paint score
|
||||
g.setColor("#FFFFFF");
|
||||
g.setFont("6x8");
|
||||
g.setFontAlign(0, 0);
|
||||
g.drawString("Score:" + score, W / 2, 10);
|
||||
drawBackground();
|
||||
drawApple();
|
||||
drawSnake();
|
||||
drawScore();
|
||||
|
||||
//set snake trail
|
||||
snakeTrail.push({ x: snakeX, y: snakeY });
|
||||
snakeTrail.push({ x: snake.x, y: snake.y });
|
||||
while (snakeTrail.length > tailSize) {
|
||||
snakeTrail.shift();
|
||||
}
|
||||
|
||||
g.flip();
|
||||
}
|
||||
|
||||
// input
|
||||
|
|
@ -132,6 +140,9 @@ setWatch(() => {// Right
|
|||
d = 'r';
|
||||
}
|
||||
}, BTN5, { repeat: true });
|
||||
setWatch(() => {// Pause
|
||||
running = !running;
|
||||
}, BTN2, { repeat: true });
|
||||
|
||||
Bangle.on('touch', button => {
|
||||
if (!running) {
|
||||
|
|
@ -140,5 +151,5 @@ Bangle.on('touch', button => {
|
|||
});
|
||||
|
||||
// render X times per second
|
||||
var x = 5;
|
||||
const x = 5;
|
||||
setInterval(draw, 1000 / x);
|
||||
|
|
@ -4,3 +4,6 @@
|
|||
0.04: Fix regression after tweaks to Storage.readJSON
|
||||
0.05: Move configuration into App/widget settings
|
||||
0.06: Move loader into welcome.boot.js
|
||||
0.07: Run again when updated
|
||||
Don't run again when settings app is updated (or absent)
|
||||
Add "Run Now" option to settings
|
||||
|
|
|
|||
|
|
@ -288,6 +288,13 @@ setWatch(()=>{
|
|||
}, BTN2, {repeat:true,edge:"rising"});
|
||||
setWatch(()=>move(-1), BTN1, {repeat:true});
|
||||
|
||||
(function migrateSettings(){
|
||||
let global_settings = require('Storage').readJSON('setting.json', 1)
|
||||
if (global_settings) {
|
||||
delete global_settings.welcomed
|
||||
require('Storage').write('setting.json', global_settings)
|
||||
}
|
||||
})()
|
||||
|
||||
Bangle.setLCDTimeout(0);
|
||||
Bangle.setLCDPower(1);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
(function() {
|
||||
let s = require('Storage').readJSON('setting.json', 1) || {}
|
||||
let s = require('Storage').readJSON('welcome.settings.json', 1)
|
||||
|| require('Storage').readJSON('setting.json', 1)
|
||||
|| {welcomed: true} // do NOT run if global settings are also absent
|
||||
if (!s.welcomed && require('Storage').read('welcome.app.js')) {
|
||||
setTimeout(() => {
|
||||
s.welcomed = true
|
||||
require('Storage').write('setting.json', s)
|
||||
require('Storage').write('welcome.settings.json', {welcomed: "yes"})
|
||||
load('welcome.app.js')
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"welcomed": false
|
||||
}
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
// The welcome app is special, and gets to use global settings
|
||||
(function(back) {
|
||||
let settings = require('Storage').readJSON('setting.json', 1) || {}
|
||||
let settings = require('Storage').readJSON('welcome.settings.json', 1)
|
||||
|| require('Storage').readJSON('setting.json', 1) || {}
|
||||
E.showMenu({
|
||||
'': { 'title': 'Welcome App' },
|
||||
'Run again': {
|
||||
'Run on Next Boot': {
|
||||
value: !settings.welcomed,
|
||||
format: v => v ? 'Yes' : 'No',
|
||||
onchange: v => {
|
||||
settings.welcomed = v ? undefined : true
|
||||
require('Storage').write('setting.json', settings)
|
||||
},
|
||||
format: v => v ? 'OK' : 'No',
|
||||
onchange: v => require('Storage').write('welcome.settings.json', {welcomed: !v}),
|
||||
},
|
||||
'Run Now': () => load('welcome.app.js'),
|
||||
'< Back': back,
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.02: Now refresh battery monitor every minute if LCD on
|
||||
0.03: Tweaks for variable size widget system
|
||||
0.04: Ensure redrawing works with variable size widget system
|
||||
0.05: Fix regression stopping correct widget updates
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Bangle.on('lcdPower', function(on) {
|
|||
WIDGETS["bat"].draw();
|
||||
// refresh once a minute if LCD on
|
||||
if (!batteryInterval)
|
||||
batteryInterval = setInterval(draw, 60000);
|
||||
batteryInterval = setInterval(()=>WIDGETS["bat"].draw(), 60000);
|
||||
} else {
|
||||
if (batteryInterval) {
|
||||
clearInterval(batteryInterval);
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@
|
|||
0.06: Show battery percentage as text
|
||||
0.07: Add settings: percentage/color/charger icon
|
||||
0.08: Draw percentage as inverted on monochrome battery
|
||||
0.09: Fix regression stopping correct widget updates
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ Bangle.on('lcdPower', function(on) {
|
|||
WIDGETS["batpc"].draw();
|
||||
// refresh once a minute if LCD on
|
||||
if (!batteryInterval)
|
||||
batteryInterval = setInterval(draw, 60000);
|
||||
batteryInterval = setInterval(()=>WIDGETS["batpc"].draw(), 60000);
|
||||
} else {
|
||||
if (batteryInterval) {
|
||||
clearInterval(batteryInterval);
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.02: Tweaks for variable size widget system
|
||||
0.03: Ensure redrawing works with variable size widget system
|
||||
0.04: Fix automatic update of Bluetooth connection status
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function changed() {
|
|||
WIDGETS["bluetooth"].draw();
|
||||
g.flip();// turns screen on
|
||||
}
|
||||
NRF.on('connected',changed);
|
||||
NRF.on('disconnected',changed);
|
||||
NRF.on('connect',changed);
|
||||
NRF.on('disconnect',changed);
|
||||
WIDGETS["bluetooth"]={area:"tr",width:24,draw:draw};
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.02: Now refresh battery monitor every minute if LCD on
|
||||
0.03: Ensure redrawing works with variable size widget system
|
||||
0.04: Fix regression stopping correct widget updates
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
}
|
||||
function startTimers(){
|
||||
intervalRef = setInterval(draw, 60*1000);
|
||||
intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000);
|
||||
WIDGETS["wdclk"].draw();
|
||||
}
|
||||
Bangle.on('lcdPower', (on) => {
|
||||
|
|
@ -23,5 +23,5 @@
|
|||
});
|
||||
|
||||
WIDGETS["wdclk"]={area:"tr",width:width,draw:draw};
|
||||
if (Bangle.isLCDOn) intervalRef = setInterval(draw, 60*1000);
|
||||
if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000);
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New Widget!
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
(() => {
|
||||
function draw() {
|
||||
g.reset();
|
||||
var m = process.memory();
|
||||
var pc = Math.round(m.usage*100/m.total);
|
||||
g.drawImage(atob("BwgBqgP////AVQ=="), this.x+(24-7)/2, this.y+4);
|
||||
g.setColor(pc>70 ? "#ff0000" : (pc>50 ? "#ffff00" : "#ffffff"));
|
||||
g.setFont("6x8").setFontAlign(0,0).drawString(pc+"%", this.x+12, this.y+20, true/*solid*/);
|
||||
}
|
||||
var ramInterval;
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) {
|
||||
WIDGETS["ram"].draw();
|
||||
if (!ramInterval) ramInterval = setInterval(()=>WIDGETS["ram"].draw(), 10000);
|
||||
} else {
|
||||
if (ramInterval) {
|
||||
clearInterval(ramInterval);
|
||||
ramInterval = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
WIDGETS["ram"]={area:"tl",width: 24,draw:draw};
|
||||
})()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 403 B |
13
js/comms.js
13
js/comms.js
|
|
@ -75,12 +75,21 @@ getInstalledApps : () => {
|
|||
Progress.hide({sticky:true});
|
||||
return reject("");
|
||||
}
|
||||
Puck.eval('require("Storage").list(/\.info$/).map(f=>{var j=require("Storage").readJSON(f,1)||{};j.id=f.slice(0,-5);return j})', (appList,err) => {
|
||||
Puck.write('\x10Bluetooth.print("[");require("Storage").list(/\.info$/).forEach(f=>{var j=require("Storage").readJSON(f,1)||{};j.id=f.slice(0,-5);Bluetooth.print(JSON.stringify(j)+",")});Bluetooth.println("0]")\n', (appList,err) => {
|
||||
Progress.hide({sticky:true});
|
||||
try {
|
||||
appList = JSON.parse(appList);
|
||||
// remove last element since we added a final '0'
|
||||
// to make things easy on the Bangle.js side
|
||||
appList = appList.slice(0,-1);
|
||||
} catch (e) {
|
||||
appList = null;
|
||||
err = e.toString();
|
||||
}
|
||||
if (appList===null) return reject(err || "");
|
||||
console.log("getInstalledApps", appList);
|
||||
resolve(appList);
|
||||
});
|
||||
}, true /* callback on newline */);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue