diff --git a/android.html b/android.html
new file mode 100644
index 000000000..93999008f
--- /dev/null
+++ b/android.html
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bangle.js App Loader
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sort by:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/alarm/app.js b/apps/alarm/app.js
index 46efe37bf..8e2e2b0a6 100644
--- a/apps/alarm/app.js
+++ b/apps/alarm/app.js
@@ -217,7 +217,12 @@ function showEditRepeatMenu(repeat, dow, dowChangeCallback) {
function showCustomDaysMenu(dow, dowChangeCallback, originalRepeat, originalDow) {
const menu = {
"": { "title": /*LANG*/"Custom Days" },
- "< Back": () => dowChangeCallback(true, dow),
+ "< Back": () => {
+ // If the user unchecks all the days then we assume repeat = once
+ // and we force the dow to every day.
+ var repeat = dow > 0;
+ dowChangeCallback(repeat, repeat ? dow : EVERY_DAY)
+ }
};
require("date_utils").dows(firstDayOfWeek).forEach((day, i) => {
@@ -315,12 +320,12 @@ function showAdvancedMenu() {
function enableAll(on) {
if (alarms.filter(e => e.on == !on).length == 0) {
- E.showPrompt(on ? /*LANG*/"Nothing to Enable" : /*LANG*/"Nothing to Disable", {
- title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All",
- buttons: { /*LANG*/"Ok": true }
- }).then(() => showAdvancedMenu());
+ E.showAlert(
+ on ? /*LANG*/"Nothing to Enable" : /*LANG*/"Nothing to Disable",
+ on ? /*LANG*/"Enable All" : /*LANG*/"Disable All"
+ ).then(() => showAdvancedMenu());
} else {
- E.showPrompt(/*LANG*/"Are you sure?", { title: on ? "/*LANG*/Enable All" : /*LANG*/"Disable All" }).then((confirm) => {
+ E.showPrompt(/*LANG*/"Are you sure?", { title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" }).then((confirm) => {
if (confirm) {
alarms.forEach(alarm => alarm.on = on);
saveAndReload();
@@ -334,7 +339,7 @@ function enableAll(on) {
function deleteAll() {
if (alarms.length == 0) {
- E.showPrompt(/*LANG*/"Nothing to delete", { title: /*LANG*/"Delete All", buttons: { /*LANG*/"Ok": true } }).then(() => showAdvancedMenu());
+ E.showAlert(/*LANG*/"Nothing to delete", /*LANG*/"Delete All").then(() => showAdvancedMenu());
} else {
E.showPrompt(/*LANG*/"Are you sure?", {
title: /*LANG*/"Delete All"
diff --git a/apps/bowserWF/metadata.json b/apps/bowserWF/metadata.json
index 22df2dea4..a0bdfb8e9 100644
--- a/apps/bowserWF/metadata.json
+++ b/apps/bowserWF/metadata.json
@@ -1,14 +1,18 @@
-{ "id": "bowserWF",
+{
+ "id": "bowserWF",
"name": "Bowser Watchface",
"shortName":"Bowser Watchface",
- "version":"0.01",
+ "version":"0.02",
"description": "Let bowser show you the time",
"icon": "app.png",
- "tags": "",
- "supports" : ["BANGLEJS2"],
+ "type": "clock",
+ "tags": "clock",
+ "supports" : ["BANGLEJS2"],
+ "allow_emulator": true,
"readme": "README.md",
"storage": [
{"name":"bowserWF.app.js","url":"app.js"},
{"name":"bowserWF.img","url":"app-icon.js","evaluate":true}
- ]
+ ],
+ "data": [{"name":"bowserWF.json"}]
}
diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog
index 41eec666a..7ca8319b6 100644
--- a/apps/bthrm/ChangeLog
+++ b/apps/bthrm/ChangeLog
@@ -21,3 +21,4 @@
Adds some preset modes and a custom one
Restructure the settings menu
0.08: Allow scanning for devices in settings
+0.09: Misc Fixes and improvements (https://github.com/espruino/BangleApps/pull/1655)
diff --git a/apps/bthrm/README.md b/apps/bthrm/README.md
index 42ad619bd..8d5872670 100644
--- a/apps/bthrm/README.md
+++ b/apps/bthrm/README.md
@@ -2,7 +2,7 @@
When this app is installed it overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.
-HRM is requested it searches on Bluetooth for a heart rate monitor, connects, and sends data back using the `Bangle.on('HRM'` event as if it came from the on board monitor.
+HRM is requested it searches on Bluetooth for a heart rate monitor, connects, and sends data back using the `Bangle.on('HRM')` event as if it came from the on board monitor.
This means it's compatible with many Bangle.js apps including:
@@ -16,19 +16,23 @@ as that requires live sensor data (rather than just BPM readings).
Just install the app, then install an app that uses the heart rate monitor.
-Once installed it'll automatically try and connect to the first bluetooth
-heart rate monitor it finds.
+Once installed you will have to go into this app's settings while your heart rate monitor
+ is available for bluetooth pairing and scan for devices.
**To disable this and return to normal HRM, uninstall the app**
## Compatible Heart Rate Monitors
This works with any heart rate monitor providing the standard Bluetooth
-Heart Rate Service (`180D`) and characteristic (`2A37`).
+Heart Rate Service (`180D`) and characteristic (`2A37`). It additionally supports
+the location (`2A38`) characteristic and the Battery Service (`180F`), reporting
+that information in the `BTHRM` event when they are available.
So far it has been tested on:
* CooSpo Bluetooth Heart Rate Monitor
+* Polar H10
+* Polar OH1
* Wahoo TICKR X 2
## Internals
@@ -38,7 +42,6 @@ This replaces `Bangle.setHRMPower` with its own implementation.
## TODO
* A widget to show connection state?
-* Specify a specific device by address?
## Creator
diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js
index 3a1f1cc4c..e9e640563 100644
--- a/apps/bthrm/boot.js
+++ b/apps/bthrm/boot.js
@@ -3,7 +3,7 @@
require('Storage').readJSON("bthrm.default.json", true) || {},
require('Storage').readJSON("bthrm.json", true) || {}
);
-
+
var log = function(text, param){
if (settings.debuglog){
var logline = new Date().toISOString() + " - " + text;
@@ -13,39 +13,38 @@
print(logline);
}
};
-
+
log("Settings: ", settings);
-
+
if (settings.enabled){
- function clearCache(){
+ var clearCache = function() {
return require('Storage').erase("bthrm.cache.json");
- }
+ };
- function getCache(){
+ var getCache = function() {
var cache = require('Storage').readJSON("bthrm.cache.json", true) || {};
- if (settings.btname && settings.btname == cache.name) return cache;
+ if (settings.btid && settings.btid === cache.id) return cache;
clearCache();
return {};
- }
-
- function addNotificationHandler(characteristic){
+ };
+
+ var addNotificationHandler = function(characteristic) {
log("Setting notification handler: " + supportedCharacteristics[characteristic.uuid].handler);
- characteristic.on('characteristicvaluechanged', supportedCharacteristics[characteristic.uuid].handler);
- }
-
- function writeCache(cache){
+ characteristic.on('characteristicvaluechanged', (ev) => supportedCharacteristics[characteristic.uuid].handler(ev.target.value));
+ };
+
+ var writeCache = function(cache) {
var oldCache = getCache();
- if (oldCache != cache) {
+ if (oldCache !== cache) {
log("Writing cache");
- require('Storage').writeJSON("bthrm.cache.json", cache)
+ require('Storage').writeJSON("bthrm.cache.json", cache);
} else {
log("No changes, don't write cache");
}
-
- }
+ };
- function characteristicsToCache(characteristics){
+ var characteristicsToCache = function(characteristics) {
log("Cache characteristics");
var cache = getCache();
if (!cache.characteristics) cache.characteristics = {};
@@ -60,9 +59,9 @@
};
}
writeCache(cache);
- }
+ };
- function characteristicsFromCache(){
+ var characteristicsFromCache = function() {
log("Read cached characteristics");
var cache = getCache();
if (!cache.characteristics) return [];
@@ -81,38 +80,34 @@
restored.push(r);
}
return restored;
- }
+ };
log("Start");
var lastReceivedData={
};
- var serviceFilters = [{
- services: [ "180d" ]
- }];
-
- supportedServices = [
- "0x180d", "0x180f"
+ var supportedServices = [
+ "0x180d", // Heart Rate
+ "0x180f", // Battery
];
var supportedCharacteristics = {
"0x2a37": {
//Heart rate measurement
- handler: function (event){
- var dv = event.target.value;
+ handler: function (dv){
var flags = dv.getUint8(0);
-
+
var bpm = (flags & 1) ? (dv.getUint16(1) / 100 /* ? */ ) : dv.getUint8(1); // 8 or 16 bit
-
+
var sensorContact;
-
+
if (flags & 2){
- sensorContact = (flags & 4) ? true : false;
+ sensorContact = !!(flags & 4);
}
-
+
var idx = 2 + (flags&1);
-
+
var energyExpended;
if (flags & 8){
energyExpended = dv.getUint16(idx,1);
@@ -121,11 +116,11 @@
var interval;
if (flags & 16) {
interval = [];
- maxIntervalBytes = (dv.byteLength - idx);
+ var maxIntervalBytes = (dv.byteLength - idx);
log("Found " + (maxIntervalBytes / 2) + " rr data fields");
for(var i = 0 ; i < maxIntervalBytes / 2; i++){
interval[i] = dv.getUint16(idx,1); // in milliseconds
- idx += 2
+ idx += 2;
}
}
@@ -140,45 +135,44 @@
}
if (settings.replace){
- var newEvent = {
+ var repEvent = {
bpm: bpm,
confidence: (sensorContact || sensorContact === undefined)? 100 : 0,
src: "bthrm"
};
-
- log("Emitting HRM: ", newEvent);
- Bangle.emit("HRM", newEvent);
+
+ log("Emitting HRM: ", repEvent);
+ Bangle.emit("HRM", repEvent);
}
var newEvent = {
bpm: bpm
};
-
+
if (location) newEvent.location = location;
if (interval) newEvent.rr = interval;
if (energyExpended) newEvent.energy = energyExpended;
if (battery) newEvent.battery = battery;
if (sensorContact) newEvent.contact = sensorContact;
-
+
log("Emitting BTHRM: ", newEvent);
Bangle.emit("BTHRM", newEvent);
}
},
"0x2a38": {
//Body sensor location
- handler: function(data){
+ handler: function(dv){
if (!lastReceivedData["0x180d"]) lastReceivedData["0x180d"] = {};
- if (!lastReceivedData["0x180d"]["0x2a38"]) lastReceivedData["0x180d"]["0x2a38"] = data.target.value;
+ lastReceivedData["0x180d"]["0x2a38"] = parseInt(dv.buffer, 10);
}
},
"0x2a19": {
//Battery
- handler: function (event){
+ handler: function (dv){
if (!lastReceivedData["0x180f"]) lastReceivedData["0x180f"] = {};
- if (!lastReceivedData["0x180f"]["0x2a19"]) lastReceivedData["0x180f"]["0x2a19"] = event.target.value.getUint8(0);
+ lastReceivedData["0x180f"]["0x2a19"] = dv.getUint8(0);
}
}
-
};
var device;
@@ -195,7 +189,7 @@
maxInterval: 1500
};
- function waitingPromise(timeout) {
+ var waitingPromise = function(timeout) {
return new Promise(function(resolve){
log("Start waiting for " + timeout);
setTimeout(()=>{
@@ -203,7 +197,7 @@
resolve();
}, timeout);
});
- }
+ };
if (settings.enabled){
Bangle.isBTHRMOn = function(){
@@ -215,7 +209,6 @@
};
}
-
if (settings.replace){
var origIsHRMOn = Bangle.isHRMOn;
@@ -229,15 +222,15 @@
};
}
- function clearRetryTimeout(){
+ var clearRetryTimeout = function() {
if (currentRetryTimeout){
log("Clearing timeout " + currentRetryTimeout);
clearTimeout(currentRetryTimeout);
currentRetryTimeout = undefined;
}
- }
+ };
- function retry(){
+ var retry = function() {
log("Retry");
if (!currentRetryTimeout){
@@ -252,17 +245,17 @@
initBt();
}, clampedTime);
- retryTime = Math.pow(retryTime, 1.1);
+ retryTime = Math.pow(clampedTime, 1.1);
if (retryTime > maxRetryTime){
retryTime = maxRetryTime;
}
} else {
log("Already in retry...");
}
- }
+ };
var buzzing = false;
- function onDisconnect(reason) {
+ var onDisconnect = function(reason) {
log("Disconnect: " + reason);
log("GATT: ", gatt);
log("Characteristics: ", characteristics);
@@ -277,11 +270,23 @@
if (Bangle.isBTHRMOn()){
retry();
}
- }
+ };
- function createCharacteristicPromise(newCharacteristic){
+ var createCharacteristicPromise = function(newCharacteristic) {
log("Create characteristic promise: ", newCharacteristic);
var result = Promise.resolve();
+ // For values that can be read, go ahead and read them, even if we might be notified in the future
+ // Allows for getting initial state of infrequently updating characteristics, like battery
+ if (newCharacteristic.readValue){
+ result = result.then(()=>{
+ log("Reading data for " + JSON.stringify(newCharacteristic));
+ return newCharacteristic.readValue().then((data)=>{
+ if (supportedCharacteristics[newCharacteristic.uuid] && supportedCharacteristics[newCharacteristic.uuid].handler) {
+ supportedCharacteristics[newCharacteristic.uuid].handler(data);
+ }
+ });
+ });
+ }
if (newCharacteristic.properties.notify){
result = result.then(()=>{
log("Starting notifications for: ", newCharacteristic);
@@ -290,31 +295,23 @@
log("Add " + settings.gracePeriodNotification + "ms grace period after starting notifications");
startPromise = startPromise.then(()=>{
log("Wait after connect");
- waitingPromise(settings.gracePeriodNotification)
+ return waitingPromise(settings.gracePeriodNotification);
});
}
return startPromise;
});
- } else if (newCharacteristic.read){
- result = result.then(()=>{
- readData(newCharacteristic);
- log("Reading data for " + newCharacteristic);
- return newCharacteristic.read().then((data)=>{
- supportedCharacteristics[newCharacteristic.uuid].handler(data);
- });
- });
}
return result.then(()=>log("Handled characteristic: ", newCharacteristic));
- }
-
- function attachCharacteristicPromise(promise, characteristic){
+ };
+
+ var attachCharacteristicPromise = function(promise, characteristic) {
return promise.then(()=>{
log("Handling characteristic:", characteristic);
return createCharacteristicPromise(characteristic);
});
- }
-
- function createCharacteristicsPromise(newCharacteristics){
+ };
+
+ var createCharacteristicsPromise = function(newCharacteristics) {
log("Create characteristics promise: ", newCharacteristics);
var result = Promise.resolve();
for (var c of newCharacteristics){
@@ -324,13 +321,13 @@
if (c.properties.notify){
addNotificationHandler(c);
}
-
+
result = attachCharacteristicPromise(result, c);
}
return result.then(()=>log("Handled characteristics"));
- }
-
- function createServicePromise(service){
+ };
+
+ var createServicePromise = function(service) {
log("Create service promise: ", service);
var result = Promise.resolve();
result = result.then(()=>{
@@ -338,15 +335,13 @@
return service.getCharacteristics().then((c)=>createCharacteristicsPromise(c));
});
return result.then(()=>log("Handled service" + service.uuid));
- }
-
- function attachServicePromise(promise, service){
- return promise.then(()=>createServicePromise(service));
- }
-
- var reUseCounter = 0;
+ };
- function initBt() {
+ var attachServicePromise = function(promise, service) {
+ return promise.then(()=>createServicePromise(service));
+ };
+
+ var initBt = function () {
log("initBt with blockInit: " + blockInit);
if (blockInit){
retry();
@@ -355,63 +350,58 @@
blockInit = true;
- if (reUseCounter > 10){
- log("Reuse counter to high");
- gatt=undefined;
- reUseCounter = 0;
- }
-
var promise;
-
+ var filters;
+
if (!device){
- var filters = serviceFilters;
- if (settings.btname){
- log("Configured device name", settings.btname);
- filters = [{name: settings.btname}];
+ if (settings.btid){
+ log("Configured device id", settings.btid);
+ filters = [{ id: settings.btid }];
+ } else {
+ return;
}
log("Requesting device with filters", filters);
- promise = NRF.requestDevice({ filters: filters });
-
+ promise = NRF.requestDevice({ filters: filters, active: true });
+
if (settings.gracePeriodRequest){
log("Add " + settings.gracePeriodRequest + "ms grace period after request");
}
-
+
promise = promise.then((d)=>{
log("Got device: ", d);
d.on('gattserverdisconnected', onDisconnect);
device = d;
});
-
+
promise = promise.then(()=>{
log("Wait after request");
return waitingPromise(settings.gracePeriodRequest);
});
-
} else {
promise = Promise.resolve();
log("Reuse device: ", device);
}
-
+
promise = promise.then(()=>{
if (gatt){
log("Reuse GATT: ", gatt);
} else {
log("GATT is new: ", gatt);
characteristics = [];
- var cachedName = getCache().name;
- if (device.name != cachedName){
- log("Device name changed from " + cachedName + " to " + device.name + ", clearing cache");
+ var cachedId = getCache().id;
+ if (device.id !== cachedId){
+ log("Device ID changed from " + cachedId + " to " + device.id + ", clearing cache");
clearCache();
}
var newCache = getCache();
- newCache.name = device.name;
+ newCache.id = device.id;
writeCache(newCache);
gatt = device.gatt;
}
-
+
return Promise.resolve(gatt);
});
-
+
promise = promise.then((gatt)=>{
if (!gatt.connected){
var connectPromise = gatt.connect(connectSettings);
@@ -427,16 +417,28 @@
return Promise.resolve();
}
});
-
+
+/* promise = promise.then(() => {
+ log(JSON.stringify(gatt.getSecurityStatus()));
+ if (gatt.getSecurityStatus()['bonded']) {
+ log("Already bonded");
+ return Promise.resolve();
+ } else {
+ log("Start bonding");
+ return gatt.startBonding()
+ .then(() => console.log(gatt.getSecurityStatus()));
+ }
+ });*/
+
promise = promise.then(()=>{
- if (!characteristics || characteristics.length == 0){
+ if (!characteristics || characteristics.length === 0){
characteristics = characteristicsFromCache();
}
});
promise = promise.then(()=>{
var characteristicsPromise = Promise.resolve();
- if (characteristics.length == 0){
+ if (characteristics.length === 0){
characteristicsPromise = characteristicsPromise.then(()=>{
log("Getting services");
return gatt.getPrimaryServices();
@@ -454,24 +456,22 @@
log("Add " + settings.gracePeriodService + "ms grace period after services");
result = result.then(()=>{
log("Wait after services");
- return waitingPromise(settings.gracePeriodService)
+ return waitingPromise(settings.gracePeriodService);
});
}
return result;
});
-
} else {
for (var characteristic of characteristics){
characteristicsPromise = attachCharacteristicPromise(characteristicsPromise, characteristic, true);
}
}
-
+
return characteristicsPromise;
});
-
- promise = promise.then(()=>{
+
+ return promise.then(()=>{
log("Connection established, waiting for notifications");
- reUseCounter = 0;
characteristicsToCache(characteristics);
clearRetryTimeout();
}).catch((e) => {
@@ -479,7 +479,7 @@
log("Error:", e);
onDisconnect(e);
});
- }
+ };
Bangle.setBTHRMPower = function(isOn, app) {
// Do app power handling
@@ -487,7 +487,7 @@
if (Bangle._PWR===undefined) Bangle._PWR={};
if (Bangle._PWR.BTHRM===undefined) Bangle._PWR.BTHRM=[];
if (isOn && !Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM.push(app);
- if (!isOn && Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM = Bangle._PWR.BTHRM.filter(a=>a!=app);
+ if (!isOn && Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM = Bangle._PWR.BTHRM.filter(a=>a!==app);
isOn = Bangle._PWR.BTHRM.length;
// so now we know if we're really on
if (isOn) {
@@ -510,7 +510,7 @@
}
}
};
-
+
var origSetHRMPower = Bangle.setHRMPower;
if (settings.startWithHrm){
@@ -525,11 +525,10 @@
}
};
}
-
-
+
var fallbackInterval;
-
- function switchInternalHrm(){
+
+ var switchInternalHrm = function() {
if (settings.allowFallback && !fallbackInterval){
log("Fallback to HRM enabled");
origSetHRMPower(1, "bthrm_fallback");
@@ -542,7 +541,7 @@
}
}, settings.fallbackTimeout);
}
- }
+ };
if (settings.replace){
log("Replace HRM event");
@@ -557,11 +556,11 @@
}
switchInternalHrm();
}
-
+
E.on("kill", ()=>{
if (gatt && gatt.connected){
log("Got killed, trying to disconnect");
- var promise = gatt.disconnect().then(()=>log("Disconnected on kill")).catch((e)=>log("Error during disconnnect on kill", e));
+ gatt.disconnect().then(()=>log("Disconnected on kill")).catch((e)=>log("Error during disconnnect on kill", e));
}
});
}
diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js
index cc533eedd..dd9230386 100644
--- a/apps/bthrm/bthrm.js
+++ b/apps/bthrm/bthrm.js
@@ -1,7 +1,16 @@
-var btm = g.getHeight()-1;
var intervalInt;
var intervalBt;
+var BODY_LOCS = {
+ 0: 'Other',
+ 1: 'Chest',
+ 2: 'Wrist',
+ 3: 'Finger',
+ 4: 'Hand',
+ 5: 'Ear Lobe',
+ 6: 'Foot',
+}
+
function clear(y){
g.reset();
g.clearRect(0,y,g.getWidth(),y+75);
@@ -15,17 +24,17 @@ function draw(y, type, event) {
g.setFontAlign(0,0);
g.setFontVector(40).drawString(str,px,y+20);
str = "Event: " + type;
- if (type == "HRM") {
+ if (type === "HRM") {
str += " Confidence: " + event.confidence;
g.setFontVector(12).drawString(str,px,y+40);
str = " Source: " + (event.src ? event.src : "internal");
g.setFontVector(12).drawString(str,px,y+50);
}
- if (type == "BTHRM"){
+ if (type === "BTHRM"){
if (event.battery) str += " Bat: " + (event.battery ? event.battery : "");
g.setFontVector(12).drawString(str,px,y+40);
str= "";
- if (event.location) str += "Loc: " + event.location.toFixed(0) + "ms";
+ if (event.location) str += "Loc: " + BODY_LOCS[event.location];
if (event.rr && event.rr.length > 0) str += " RR: " + event.rr.join(",");
g.setFontVector(12).drawString(str,px,y+50);
str= "";
@@ -45,7 +54,7 @@ function onBtHrm(e) {
firstEventBt = false;
}
draw(100, "BTHRM", e);
- if (e.bpm == 0){
+ if (e.bpm === 0){
Bangle.buzz(100,0.2);
}
if (intervalBt){
diff --git a/apps/bthrm/default.json b/apps/bthrm/default.json
index 64e638b8a..fb284bcd2 100644
--- a/apps/bthrm/default.json
+++ b/apps/bthrm/default.json
@@ -7,10 +7,10 @@
"allowFallback": true,
"warnDisconnect": false,
"fallbackTimeout": 10,
- "custom_replace": false,
+ "custom_replace": true,
"custom_debuglog": false,
- "custom_startWithHrm": false,
- "custom_allowFallback": false,
+ "custom_startWithHrm": true,
+ "custom_allowFallback": true,
"custom_warnDisconnect": false,
"custom_fallbackTimeout": 10,
"gracePeriodNotification": 0,
diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json
index b35ebd6af..39c1ff8bb 100644
--- a/apps/bthrm/metadata.json
+++ b/apps/bthrm/metadata.json
@@ -2,11 +2,11 @@
"id": "bthrm",
"name": "Bluetooth Heart Rate Monitor",
"shortName": "BT HRM",
- "version": "0.08",
+ "version": "0.09",
"description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.",
"icon": "app.png",
"type": "app",
- "tags": "health,bluetooth",
+ "tags": "health,bluetooth,hrm,bthrm",
"supports": ["BANGLEJS","BANGLEJS2"],
"readme": "README.md",
"storage": [
diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js
index 4b564d670..b376d6a2d 100644
--- a/apps/bthrm/settings.js
+++ b/apps/bthrm/settings.js
@@ -5,14 +5,14 @@
require('Storage').writeJSON(FILE, s);
readSettings();
}
-
+
function readSettings(){
settings = Object.assign(
require('Storage').readJSON("bthrm.default.json", true) || {},
require('Storage').readJSON(FILE, true) || {}
);
}
-
+
var FILE="bthrm.json";
var settings;
readSettings();
@@ -61,12 +61,13 @@
}
};
- if (settings.btname){
- var name = "Clear " + settings.btname;
+ if (settings.btname || settings.btid){
+ var name = "Clear " + (settings.btname || settings.btid);
mainmenu[name] = function() {
- E.showPrompt("Clear current device name?").then((r)=>{
+ E.showPrompt("Clear current device?").then((r)=>{
if (r) {
writeSettings("btname",undefined);
+ writeSettings("btid",undefined);
}
E.showMenu(buildMainMenu());
});
@@ -78,9 +79,7 @@
mainmenu.Debug = function() { E.showMenu(submenu_debug); };
return mainmenu;
}
-
-
var submenu_debug = {
'' : { title: "Debug"},
'< Back': function() { E.showMenu(buildMainMenu()); },
@@ -103,35 +102,39 @@
function createMenuFromScan(){
E.showMenu();
- E.showMessage("Scanning");
+ E.showMessage("Scanning for 4 seconds");
var submenu_scan = {
- '' : { title: "Scan"},
'< Back': function() { E.showMenu(buildMainMenu()); }
};
- var packets=10;
- var scanStart=Date.now();
- NRF.setScan(function(d) {
- packets--;
- if (packets<=0 || Date.now() - scanStart > 5000){
- NRF.setScan();
- E.showMenu(submenu_scan);
- } else if (d.name){
- print("Found device", d);
- submenu_scan[d.name] = function(){
- E.showPrompt("Set "+d.name+"?").then((r)=>{
- if (r) {
- writeSettings("btname",d.name);
- }
- E.showMenu(buildMainMenu());
+ NRF.findDevices(function(devices) {
+ submenu_scan[''] = { title: `Scan (${devices.length} found)`};
+ if (devices.length === 0) {
+ E.showAlert("No devices found")
+ .then(() => E.showMenu(buildMainMenu()));
+ return;
+ } else {
+ devices.forEach((d) => {
+ print("Found device", d);
+ var shown = (d.name || d.id.substr(0, 17));
+ submenu_scan[shown] = function () {
+ E.showPrompt("Set " + shown + "?").then((r) => {
+ if (r) {
+ writeSettings("btid", d.id);
+ // Store the name for displaying later. Will connect by ID
+ if (d.name) {
+ writeSettings("btname", d.name);
+ }
+ }
+ E.showMenu(buildMainMenu());
+ });
+ };
});
- };
}
- }, { filters: [{services: [ "180d" ]}]});
+ E.showMenu(submenu_scan);
+ }, { timeout: 4000, active: true, filters: [{services: [ "180d" ]}]});
}
-
-
var submenu_custom = {
'' : { title: "Custom mode"},
'< Back': function() { E.showMenu(buildMainMenu()); },
@@ -167,7 +170,7 @@
}
},
};
-
+
var submenu_grace = {
'' : { title: "Grace periods"},
'< Back': function() { E.showMenu(submenu_debug); },
@@ -212,51 +215,6 @@
}
}
};
-
- var submenu = {
- '' : { title: "Grace periods"},
- '< Back': function() { E.showMenu(buildMainMenu()); },
- 'Request': {
- value: settings.gracePeriodRequest,
- min: 0,
- max: 3000,
- step: 100,
- format: v=>v+"ms",
- onchange: v => {
- writeSettings("gracePeriodRequest",v);
- }
- },
- 'Connect': {
- value: settings.gracePeriodConnect,
- min: 0,
- max: 3000,
- step: 100,
- format: v=>v+"ms",
- onchange: v => {
- writeSettings("gracePeriodConnect",v);
- }
- },
- 'Notification': {
- value: settings.gracePeriodNotification,
- min: 0,
- max: 3000,
- step: 100,
- format: v=>v+"ms",
- onchange: v => {
- writeSettings("gracePeriodNotification",v);
- }
- },
- 'Service': {
- value: settings.gracePeriodService,
- min: 0,
- max: 3000,
- step: 100,
- format: v=>v+"ms",
- onchange: v => {
- writeSettings("gracePeriodService",v);
- }
- }
- };
-
+
E.showMenu(buildMainMenu());
-})
+});
diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog
index ecf441925..ecd0c355f 100644
--- a/apps/bwclk/ChangeLog
+++ b/apps/bwclk/ChangeLog
@@ -5,4 +5,5 @@
0.05: Included icons for information.
0.06: Design and usability improvements.
0.07: Improved positioning.
-0.08: Select the color of widgets correctly. Additional settings to hide colon.
\ No newline at end of file
+0.08: Select the color of widgets correctly. Additional settings to hide colon.
+0.09: Larger font size if colon is hidden to improve readability further.
\ No newline at end of file
diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js
index c22ec050f..5bfec4097 100644
--- a/apps/bwclk/app.js
+++ b/apps/bwclk/app.js
@@ -44,6 +44,16 @@ Graphics.prototype.setLargeFont = function(scale) {
return this;
};
+Graphics.prototype.setXLargeFont = function(scale) {
+ // Actual height 53 (55 - 3)
+ this.setFontCustom(
+ E.toString(require('heatshrink').decompress(atob('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'))),
+ 46,
+ atob("FR4uHyopKyksJSssGA=="),
+ 70+(scale<<8)+(1<<16)
+ );
+};
+
Graphics.prototype.setMediumFont = function(scale) {
// Actual height 41 (42 - 2)
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAB/AAAAAAAP/AAAAAAD//AAAAAA///AAAAAP///AAAAB///8AAAAf///AAAAH///wAAAB///+AAAAH///gAAAAH//4AAAAAH/+AAAAAAH/wAAAAAAH8AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAH////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gAAH+AAD+AAAD/AAH8AAAB/AAH4AAAA/gAH4AAAAfgAH4AAAAfgAPwAAAAfgAPwAAAAfgAPwAAAAfgAHwAAAAfgAH4AAAAfgAH4AAAA/gAH8AAAA/AAD+AAAD/AAD/gAAH/AAB/////+AAB/////8AAA/////4AAAf////wAAAH////gAAAB///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAfwAAAAAAA/gAAAAAAA/AAAAAAAB/AAAAAAAD+AAAAAAAD8AAAAAAAH8AAAAAAAH//////AAH//////AAH//////AAH//////AAH//////AAH//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAA/AAAP4AAB/AAAf4AAD/AAA/4AAD/AAB/4AAH/AAD/4AAP/AAH/AAAf/AAH8AAA//AAH4AAB//AAP4AAD//AAPwAAH+/AAPwAAP8/AAPwAAf4/AAPwAA/4/AAPwAA/w/AAPwAB/g/AAPwAD/A/AAP4AH+A/AAH8AP8A/AAH/A/4A/AAD///wA/AAD///gA/AAB///AA/AAA//+AA/AAAP/8AA/AAAD/wAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAH4AAAHwAAH4AAAH4AAH4AAAH8AAH4AAAP+AAH4AAAH+AAH4A4AB/AAH4A+AA/AAH4B/AA/gAH4D/AAfgAH4H+AAfgAH4P+AAfgAH4f+AAfgAH4/+AAfgAH5/+AAfgAH5//AAfgAH7+/AA/gAH/8/gB/AAH/4f4H/AAH/wf//+AAH/gP//8AAH/AH//8AAH+AD//wAAH8AB//gAAD4AAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAD/AAAAAAAP/AAAAAAB//AAAAAAH//AAAAAAf//AAAAAB///AAAAAH///AAAAAf/8/AAAAB//w/AAAAH/+A/AAAA//4A/AAAD//gA/AAAH/+AA/AAAH/4AA/AAAH/gAA/AAAH+AAA/AAAHwAAA/AAAHAAf///AAEAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAP/AHgAAH///AP4AAH///gP8AAH///gP8AAH///gP+AAH///gD/AAH/A/AB/AAH4A/AA/gAH4A+AAfgAH4B+AAfgAH4B+AAfgAH4B8AAfgAH4B8AAfgAH4B+AAfgAH4B+AAfgAH4B+AA/gAH4B/AA/AAH4A/gD/AAH4A/4H+AAH4Af//+AAH4AP//8AAH4AP//4AAHwAD//wAAAAAB//AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAD////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gP4H+AAD/AfgD/AAH8A/AB/AAH8A/AA/gAH4B+AAfgAH4B+AAfgAPwB8AAfgAPwB8AAfgAPwB+AAfgAPwB+AAfgAH4B+AAfgAH4B/AA/gAH8B/AB/AAH+A/wD/AAD+A/8P+AAB8Af//+AAB4AP//8AAAwAH//4AAAAAD//gAAAAAA//AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAHAAPwAAAA/AAPwAAAD/AAPwAAAf/AAPwAAB//AAPwAAP//AAPwAA//8AAPwAH//wAAPwAf/+AAAPwB//4AAAPwP//AAAAPw//8AAAAP3//gAAAAP//+AAAAAP//wAAAAAP//AAAAAAP/4AAAAAAP/gAAAAAAP+AAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAH+A//gAAAf/h//4AAA//z//8AAB/////+AAD/////+AAD///+H/AAH+H/4B/AAH8B/wA/gAH4A/gAfgAH4A/gAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAH4A/gAfgAH4A/gAfgAH8B/wA/gAH/H/4B/AAD///+H/AAD/////+AAB/////+AAA//z//8AAAf/h//4AAAH+A//gAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD/8AAAAAAP/+AAAAAAf//AAcAAA///gA8AAB///wB+AAD/x/4B/AAD+AP4B/AAH8AH8A/gAH4AH8A/gAH4AD8AfgAP4AD8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAH4AD8AfgAH4AD4A/gAH8AH4B/AAD+APwD/AAD/g/wP+AAB/////+AAA/////8AAAf////4AAAP////wAAAH////AAAAA///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DxcjFyAfISAiHCAiEg=="), 54+(scale<<8)+(1<<16));
@@ -304,17 +314,13 @@ function drawTime(){
g.setColor(g.theme.bg);
g.setFontAlign(0,0);
- var timeStr;
- if(settings.hideColon){
- var hours = date.getHours();
- hours -= hours >=12 ? 12 : 0;
- var minutes = date.getMinutes();
- minutes = minutes < 10 ? String("0") + minutes : minutes;
- timeStr = String(hours) + minutes;
- } else {
- timeStr = locale.time(date,1);
- }
+ var hours = String(date.getHours());
+ var minutes = date.getMinutes();
+ minutes = minutes < 10 ? String("0") + minutes : minutes;
+ var colon = settings.hideColon ? "" : ":";
+ var timeStr = hours + colon + minutes;
+ // Set y coordinates correctly
y += parseInt((H - y)/2) + 5;
var infoEntry = getInfoEntry();
@@ -324,7 +330,11 @@ function drawTime(){
// Show large or small time depending on info entry
if(infoStr == null){
- g.setLargeFont();
+ if(settings.hideColon){
+ g.setXLargeFont();
+ } else {
+ g.setLargeFont();
+ }
} else {
y -= 15;
g.setMediumFont();
diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json
index 60634e26c..eba1449a6 100644
--- a/apps/bwclk/metadata.json
+++ b/apps/bwclk/metadata.json
@@ -1,7 +1,7 @@
{
"id": "bwclk",
"name": "BW Clock",
- "version": "0.08",
+ "version": "0.09",
"description": "BW Clock.",
"readme": "README.md",
"icon": "app.png",
diff --git a/apps/bwclk/screenshot.png b/apps/bwclk/screenshot.png
index 302117ea9..550913422 100644
Binary files a/apps/bwclk/screenshot.png and b/apps/bwclk/screenshot.png differ
diff --git a/apps/bwclk/screenshot_2.png b/apps/bwclk/screenshot_2.png
index 9614131ec..ccbc9aae1 100644
Binary files a/apps/bwclk/screenshot_2.png and b/apps/bwclk/screenshot_2.png differ
diff --git a/apps/bwclk/screenshot_3.png b/apps/bwclk/screenshot_3.png
index 148f005e6..5bf7083f0 100644
Binary files a/apps/bwclk/screenshot_3.png and b/apps/bwclk/screenshot_3.png differ
diff --git a/apps/ffcniftya/ChangeLog b/apps/ffcniftya/ChangeLog
index 420c553f5..cb520193b 100644
--- a/apps/ffcniftya/ChangeLog
+++ b/apps/ffcniftya/ChangeLog
@@ -1,2 +1,4 @@
0.01: New Clock Nifty A
-0.02: Shows the current week number (ISO8601), can be disabled via settings ""
+0.02: Shows the current week number (ISO8601), can be disabled via settings
+0.03: Call setUI before loading widgets
+ Improve settings page
diff --git a/apps/ffcniftya/README.md b/apps/ffcniftya/README.md
index 86f1f5c2d..80005fd3c 100644
--- a/apps/ffcniftya/README.md
+++ b/apps/ffcniftya/README.md
@@ -1,13 +1,12 @@
# Nifty-A Clock
-Colors are black/white - photos have non correct camera color "blue"
+Colors are black/white - photos have non correct camera color "blue".
-## This is the clock
+This is the clock:

-## The week number (ISO8601) can be turned of in settings
-(default is **"On"**)
+The week number (ISO8601) can be turned off in settings (default is `On`)

diff --git a/apps/ffcniftya/app.js b/apps/ffcniftya/app.js
index 5da1ec48e..4000a1578 100644
--- a/apps/ffcniftya/app.js
+++ b/apps/ffcniftya/app.js
@@ -1,6 +1,6 @@
const locale = require("locale");
-const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"];
-const CFG = require('Storage').readJSON("ffcniftya.json", 1) || {showWeekNum: true};
+const is12Hour = Object.assign({ "12hour": false }, require("Storage").readJSON("setting.json", true))["12hour"];
+const showWeekNum = Object.assign({ showWeekNum: true }, require('Storage').readJSON("ffcniftya.json", true))["showWeekNum"];
/* Clock *********************************************/
const scale = g.getWidth() / 176;
@@ -17,16 +17,17 @@ const center = {
y: Math.round(((viewport.height - widget) / 2) + widget),
}
-function ISO8601_week_no(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480
- var tdt = new Date(date.valueOf());
- var dayn = (date.getDay() + 6) % 7;
- tdt.setDate(tdt.getDate() - dayn + 3);
- var firstThursday = tdt.valueOf();
- tdt.setMonth(0, 1);
- if (tdt.getDay() !== 4) {
- tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7);
- }
- return 1 + Math.ceil((firstThursday - tdt) / 604800000);
+// copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480
+function ISO8601_week_no(date) {
+ var tdt = new Date(date.valueOf());
+ var dayn = (date.getDay() + 6) % 7;
+ tdt.setDate(tdt.getDate() - dayn + 3);
+ var firstThursday = tdt.valueOf();
+ tdt.setMonth(0, 1);
+ if (tdt.getDay() !== 4) {
+ tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7);
+ }
+ return 1 + Math.ceil((firstThursday - tdt) / 604800000);
}
function d02(value) {
@@ -59,7 +60,7 @@ function draw() {
g.drawString(year, centerDatesScaleX, center.y - 62 * scale);
g.drawString(month, centerDatesScaleX, center.y - 44 * scale);
g.drawString(day, centerDatesScaleX, center.y - 26 * scale);
- if (CFG.showWeekNum) g.drawString(d02(ISO8601_week_no(now)), centerDatesScaleX, center.y + 15 * scale);
+ if (showWeekNum) g.drawString(weekNum, centerDatesScaleX, center.y + 15 * scale);
g.drawString(monthName, centerDatesScaleX, center.y + 48 * scale);
g.drawString(dayName, centerDatesScaleX, center.y + 66 * scale);
}
@@ -79,7 +80,6 @@ function clearTickTimer() {
function queueNextTick() {
clearTickTimer();
tickTimer = setTimeout(tick, 60000 - (Date.now() % 60000));
- // tickTimer = setTimeout(tick, 3000);
}
function tick() {
@@ -91,21 +91,16 @@ function tick() {
// Clear the screen once, at startup
g.clear();
-// Start ticking
tick();
-// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower', (on) => {
if (on) {
- tick(); // Start ticking
+ tick();
} else {
- clearTickTimer(); // stop ticking
+ clearTickTimer();
}
});
-// Load widgets
+Bangle.setUI("clock");
Bangle.loadWidgets();
Bangle.drawWidgets();
-
-// Show launcher when middle button pressed
-Bangle.setUI("clock");
\ No newline at end of file
diff --git a/apps/ffcniftya/metadata.json b/apps/ffcniftya/metadata.json
index ce91cc225..91b426cd0 100644
--- a/apps/ffcniftya/metadata.json
+++ b/apps/ffcniftya/metadata.json
@@ -1,7 +1,7 @@
{
"id": "ffcniftya",
"name": "Nifty-A Clock",
- "version": "0.02",
+ "version": "0.03",
"description": "A nifty clock with time and date",
"icon": "app.png",
"screenshots": [{"url":"screenshot_nifty.png"}],
diff --git a/apps/ffcniftya/settings.js b/apps/ffcniftya/settings.js
index 46e4ef5aa..aec1d680a 100644
--- a/apps/ffcniftya/settings.js
+++ b/apps/ffcniftya/settings.js
@@ -1,23 +1,15 @@
-(function(back) {
- var FILE = "ffcniftya.json";
- // Load settings
- var cfg = require('Storage').readJSON(FILE, 1) || { showWeekNum: true };
+(function (back) {
+ const settings = Object.assign({ showWeekNum: true }, require("Storage").readJSON("ffcniftya.json", true));
- function writeSettings() {
- require('Storage').writeJSON(FILE, cfg);
- }
-
- // Show the menu
E.showMenu({
- "" : { "title" : "Nifty-A Clock" },
- "< Back" : () => back(),
- 'week number?': {
- value: cfg.showWeekNum,
- format: v => v?"On":"Off",
+ "": { "title": "Nifty-A Clock" },
+ "< Back": () => back(),
+ /*LANG*/"Show Week Number": {
+ value: settings.showWeekNum,
onchange: v => {
- cfg.showWeekNum = v;
- writeSettings();
+ settings.showWeekNum = v;
+ require("Storage").writeJSON("ffcniftya.json", settings);
}
}
});
-})
\ No newline at end of file
+})
diff --git a/apps/ffcniftyb/ChangeLog b/apps/ffcniftyb/ChangeLog
index dedd31452..9fc7e3c5c 100644
--- a/apps/ffcniftyb/ChangeLog
+++ b/apps/ffcniftyb/ChangeLog
@@ -1,2 +1,5 @@
0.01: New Clock Nifty B
-0.02: Added configuration
\ No newline at end of file
+0.02: Added configuration
+0.03: Call setUI before loading widgets
+ Fix bug with black being unselectable
+ Improve settings page
diff --git a/apps/ffcniftyb/README.md b/apps/ffcniftyb/README.md
index e04243a0b..072f71cce 100644
--- a/apps/ffcniftyb/README.md
+++ b/apps/ffcniftyb/README.md
@@ -1,9 +1,6 @@
# Nifty Series B Clock
- Display Time and Date
-- Color Configuration
-
-##
+- Colour Configuration

-
diff --git a/apps/ffcniftyb/app.js b/apps/ffcniftyb/app.js
index 75d217ab4..65c74dbd7 100644
--- a/apps/ffcniftyb/app.js
+++ b/apps/ffcniftyb/app.js
@@ -1,9 +1,5 @@
-const locale = require("locale");
-const storage = require('Storage');
-
-const is12Hour = (storage.readJSON("setting.json", 1) || {})["12hour"];
-const color = (storage.readJSON("ffcniftyb.json", 1) || {})["color"] || 63488 /* red */;
-
+const is12Hour = Object.assign({ "12hour": false }, require("Storage").readJSON("setting.json", true))["12hour"];
+const color = Object.assign({ color: 63488 }, require("Storage").readJSON("ffcniftyb.json", true)).color; // Default to RED
/* Clock *********************************************/
const scale = g.getWidth() / 176;
@@ -19,7 +15,7 @@ const center = {
};
function d02(value) {
- return ('0' + value).substr(-2);
+ return ("0" + value).substr(-2);
}
function renderEllipse(g) {
@@ -35,8 +31,8 @@ function renderText(g) {
const month = d02(now.getMonth() + 1);
const year = now.getFullYear();
- const month2 = locale.month(now, 3);
- const day2 = locale.dow(now, 3);
+ const month2 = require("locale").month(now, 3);
+ const day2 = require("locale").dow(now, 3);
g.setFontAlign(1, 0).setFont("Vector", 90 * scale);
g.drawString(hour, center.x + 32 * scale, center.y - 31 * scale);
@@ -96,7 +92,6 @@ function startTick(run) {
stopTick();
run();
ticker = setTimeout(() => startTick(run), 60000 - (Date.now() % 60000));
- // ticker = setTimeout(() => startTick(run), 3000);
}
/* Init **********************************************/
@@ -104,7 +99,7 @@ function startTick(run) {
g.clear();
startTick(draw);
-Bangle.on('lcdPower', (on) => {
+Bangle.on("lcdPower", (on) => {
if (on) {
startTick(draw);
} else {
@@ -112,7 +107,6 @@ Bangle.on('lcdPower', (on) => {
}
});
+Bangle.setUI("clock");
Bangle.loadWidgets();
Bangle.drawWidgets();
-
-Bangle.setUI("clock");
diff --git a/apps/ffcniftyb/metadata.json b/apps/ffcniftyb/metadata.json
index 73f93ed36..3d26c27ea 100644
--- a/apps/ffcniftyb/metadata.json
+++ b/apps/ffcniftyb/metadata.json
@@ -1,8 +1,8 @@
{
"id": "ffcniftyb",
"name": "Nifty-B Clock",
- "version": "0.02",
- "description": "A nifty clock (series B) with time, date and color configuration",
+ "version": "0.03",
+ "description": "A nifty clock (series B) with time, date and colour configuration",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clock",
diff --git a/apps/ffcniftyb/settings.js b/apps/ffcniftyb/settings.js
index 00abf80b5..da350edd8 100644
--- a/apps/ffcniftyb/settings.js
+++ b/apps/ffcniftyb/settings.js
@@ -1,49 +1,31 @@
(function (back) {
- const storage = require('Storage');
- const SETTINGS_FILE = "ffcniftyb.json";
+ const settings = Object.assign({ color: 63488 }, require("Storage").readJSON("ffcniftyb.json", true));
const colors = {
- 65535: 'White',
- 63488: 'Red',
- 65504: 'Yellow',
- 2047: 'Cyan',
- 2016: 'Green',
- 31: 'Blue',
- 0: 'Black',
+ 65535: /*LANG*/"White",
+ 63488: /*LANG*/"Red",
+ 65504: /*LANG*/"Yellow",
+ 2047: /*LANG*/"Cyan",
+ 2016: /*LANG*/"Green",
+ 31: /*LANG*/"Blue",
+ 0: /*LANG*/"Black"
}
- function load(settings) {
- return Object.assign(settings, storage.readJSON(SETTINGS_FILE, 1) || {});
- }
+ const menu = {};
+ menu[""] = { title: "Nifty-B Clock" };
+ menu["< Back"] = back;
- function save(settings) {
- storage.write(SETTINGS_FILE, settings)
- }
-
- const settings = load({
- color: 63488 /* red */,
+ Object.keys(colors).forEach(color => {
+ var label = colors[color];
+ menu[label] = {
+ value: settings.color == color,
+ onchange: () => {
+ settings.color = color;
+ require("Storage").write("ffcniftyb.json", settings);
+ setTimeout(load, 10);
+ }
+ };
});
- const saveColor = (color) => () => {
- settings.color = color;
- save(settings);
- back();
- };
-
- function showMenu(items, opt) {
- items[''] = opt || {};
- items['< Back'] = back;
- E.showMenu(items);
- }
-
- showMenu(
- Object.keys(colors).reduce((menu, color) => {
- menu[colors[color]] = saveColor(color);
- return menu;
- }, {}),
- {
- title: 'Color',
- selected: Object.keys(colors).indexOf(settings.color)
- }
- );
+ E.showMenu(menu);
});
diff --git a/apps/health/README.md b/apps/health/README.md
index c6b379c0a..3cc234a3f 100644
--- a/apps/health/README.md
+++ b/apps/health/README.md
@@ -2,7 +2,7 @@
Logs health data to a file every 10 minutes, and provides an app to view it
-**BETA - requires firmware 2v11**
+**BETA - requires firmware 2v11 or later**
## Usage
diff --git a/apps/iconlaunch/ChangeLog b/apps/iconlaunch/ChangeLog
new file mode 100644
index 000000000..4a72a9f28
--- /dev/null
+++ b/apps/iconlaunch/ChangeLog
@@ -0,0 +1,2 @@
+0.01: Initial release
+0.02: implemented "direct launch" and "one click exit" settings
\ No newline at end of file
diff --git a/apps/iconlaunch/README.md b/apps/iconlaunch/README.md
new file mode 100644
index 000000000..0d36fdeb4
--- /dev/null
+++ b/apps/iconlaunch/README.md
@@ -0,0 +1,12 @@
+# Icon launcher
+
+A launcher inspired by smartphones, with an icon-only scrollable menu.
+
+This launcher shows 9 apps per screen, making it much faster to navigate versus the default launcher.
+
+
+
+
+## Technical note
+
+The app uses `E.showScroller`'s code in the app but not the function itself because `E.showScroller` doesn't report the position of a press to the select function.
diff --git a/apps/iconlaunch/app.js b/apps/iconlaunch/app.js
new file mode 100644
index 000000000..4eeaff589
--- /dev/null
+++ b/apps/iconlaunch/app.js
@@ -0,0 +1,209 @@
+const s = require("Storage");
+const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,oneClickExit:false };
+
+if( settings.oneClickExit)
+ setWatch(_=> load(), BTN1);
+
+if (!settings.fullscreen) {
+ Bangle.loadWidgets();
+ Bangle.drawWidgets();
+}
+
+var apps = s
+ .list(/\.info$/)
+ .map((app) => {
+ var a = s.readJSON(app, 1);
+ return (
+ a && {
+ name: a.name,
+ type: a.type,
+ icon: a.icon,
+ sortorder: a.sortorder,
+ src: a.src,
+ }
+ );
+ })
+ .filter(
+ (app) =>
+ app &&
+ (app.type == "app" ||
+ (app.type == "clock" && settings.showClocks) ||
+ !app.type)
+ );
+apps.sort((a, b) => {
+ var n = (0 | a.sortorder) - (0 | b.sortorder);
+ if (n) return n; // do sortorder first
+ if (a.name < b.name) return -1;
+ if (a.name > b.name) return 1;
+ return 0;
+});
+apps.forEach((app) => {
+ if (app.icon) app.icon = s.read(app.icon); // should just be a link to a memory area
+});
+
+let scroll = 0;
+let selectedItem = -1;
+const R = Bangle.appRect;
+
+const iconSize = 48;
+
+const appsN = Math.floor(R.w / iconSize);
+const whitespace = (R.w - appsN * iconSize) / (appsN + 1);
+
+const itemSize = iconSize + whitespace;
+
+function drawItem(itemI, r) {
+ g.clearRect(r.x, r.y, r.x + r.w - 1, r.y + r.h - 1);
+ let x = 0;
+ for (let i = itemI * appsN; i < appsN * (itemI + 1); i++) {
+ if (!apps[i]) break;
+ x += whitespace;
+ if (!apps[i].icon) {
+ g.setFontAlign(0,0,0).setFont("12x20:2").drawString("?", x + r.x+iconSize/2, r.y + iconSize/2);
+ } else {
+ g.drawImage(apps[i].icon, x + r.x, r.y);
+ }
+ if (selectedItem == i) {
+ g.drawRect(
+ x + r.x - 1,
+ r.y - 1,
+ x + r.x + iconSize + 1,
+ r.y + iconSize + 1
+ );
+ }
+ x += iconSize;
+ }
+ drawText(itemI);
+}
+
+function drawItemAuto(i) {
+ var y = idxToY(i);
+ g.reset().setClipRect(R.x, y, R.x2, y + itemSize);
+ drawItem(i, {
+ x: R.x,
+ y: y,
+ w: R.w,
+ h: itemSize
+ });
+ g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
+}
+
+let lastIsDown = false;
+
+function drawText(i) {
+ const selectedApp = apps[selectedItem];
+ const idy = (selectedItem - (selectedItem % 3)) / 3;
+ if (!selectedApp || i != idy) return;
+ const appY = idxToY(idy) + iconSize / 2;
+ g.setFontAlign(0, 0, 0);
+ g.setFont("12x20");
+ const rect = g.stringMetrics(selectedApp.name);
+ g.clearRect(
+ R.w / 2 - rect.width / 2,
+ appY - rect.height / 2,
+ R.w / 2 + rect.width / 2,
+ appY + rect.height / 2
+ );
+ g.drawString(selectedApp.name, R.w / 2, appY);
+}
+
+function selectItem(id, e) {
+ const iconN = E.clip(Math.floor((e.x - R.x) / itemSize), 0, appsN - 1);
+ const appId = id * appsN + iconN;
+ if( settings.direct && apps[appId])
+ {
+ load(apps[appId].src);
+ return;
+ }
+ if (appId == selectedItem && apps[appId]) {
+ const app = apps[appId];
+ if (!app.src || s.read(app.src) === undefined) {
+ E.showMessage( /*LANG*/ "App Source\nNot found");
+ } else {
+ load(app.src);
+ }
+ }
+ selectedItem = appId;
+ drawItems();
+}
+
+function idxToY(i) {
+ return i * itemSize + R.y - (scroll & ~1);
+}
+
+function YtoIdx(y) {
+ return Math.floor((y + (scroll & ~1) - R.y) / itemSize);
+}
+
+function drawItems() {
+ g.reset().clearRect(R.x, R.y, R.x2, R.y2);
+ g.setClipRect(R.x, R.y, R.x2, R.y2);
+ var a = YtoIdx(R.y);
+ var b = Math.min(YtoIdx(R.y2), 99);
+ for (var i = a; i <= b; i++)
+ drawItem(i, {
+ x: R.x,
+ y: idxToY(i),
+ w: R.w,
+ h: itemSize,
+ });
+ g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
+}
+
+drawItems();
+g.flip();
+
+const itemsN = Math.ceil(apps.length / appsN);
+
+Bangle.setUI({
+ mode: "custom",
+ drag: (e) => {
+ let dy = e.dy;
+ if (scroll + R.h - dy > itemsN * itemSize) {
+ dy = scroll + R.h - itemsN * itemSize;
+ }
+ if (scroll - dy < 0) {
+ dy = scroll;
+ }
+ scroll -= dy;
+ scroll = E.clip(scroll, 0, itemSize * (itemsN - 1));
+ g.setClipRect(R.x, R.y, R.x2, R.y2);
+ g.scroll(0, dy);
+ if (dy < 0) {
+ g.setClipRect(R.x, R.y2 - (1 - dy), R.x2, R.y2);
+ let i = YtoIdx(R.y2 - (1 - dy));
+ let y = idxToY(i);
+ while (y < R.y2) {
+ drawItem(i, {
+ x: R.x,
+ y: y,
+ w: R.w,
+ h: itemSize,
+ });
+ i++;
+ y += itemSize;
+ }
+ } else {
+ // d>0
+ g.setClipRect(R.x, R.y, R.x2, R.y + dy);
+ let i = YtoIdx(R.y + dy);
+ let y = idxToY(i);
+ while (y > R.y - itemSize) {
+ drawItem(i, {
+ x: R.x,
+ y: y,
+ w: R.w,
+ h: itemSize,
+ });
+ y -= itemSize;
+ i--;
+ }
+ }
+ g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1);
+ },
+ touch: (_, e) => {
+ if (e.y < R.y - 4) return;
+ var i = YtoIdx(e.y);
+ selectItem(i, e);
+ },
+});
diff --git a/apps/iconlaunch/app.png b/apps/iconlaunch/app.png
new file mode 100644
index 000000000..1c8068c50
Binary files /dev/null and b/apps/iconlaunch/app.png differ
diff --git a/apps/iconlaunch/metadata.json b/apps/iconlaunch/metadata.json
new file mode 100644
index 000000000..01e447672
--- /dev/null
+++ b/apps/iconlaunch/metadata.json
@@ -0,0 +1,18 @@
+{
+ "id": "iconlaunch",
+ "name": "Icon Launcher",
+ "shortName" : "Icon launcher",
+ "version": "0.02",
+ "icon": "app.png",
+ "description": "A launcher inspired by smartphones, with an icon-only scrollable menu.",
+ "tags": "tool,system,launcher",
+ "type": "launch",
+ "supports": ["BANGLEJS2"],
+ "storage": [
+ { "name": "iconlaunch.app.js", "url": "app.js" },
+ { "name": "iconlaunch.settings.js", "url": "settings.js" }
+ ],
+ "screenshots": [{ "url": "screenshot1.png" }, { "url": "screenshot2.png" }],
+ "readme": "README.md",
+ "sortorder": -10
+}
diff --git a/apps/iconlaunch/screenshot1.png b/apps/iconlaunch/screenshot1.png
new file mode 100644
index 000000000..8695ead7a
Binary files /dev/null and b/apps/iconlaunch/screenshot1.png differ
diff --git a/apps/iconlaunch/screenshot2.png b/apps/iconlaunch/screenshot2.png
new file mode 100644
index 000000000..b17efa78b
Binary files /dev/null and b/apps/iconlaunch/screenshot2.png differ
diff --git a/apps/iconlaunch/settings.js b/apps/iconlaunch/settings.js
new file mode 100644
index 000000000..e9667047c
--- /dev/null
+++ b/apps/iconlaunch/settings.js
@@ -0,0 +1,38 @@
+// make sure to enclose the function in parentheses
+(function(back) {
+ let settings = Object.assign({
+ showClocks: true,
+ fullscreen: false
+ }, require("Storage").readJSON("launch.json", true) || {});
+
+ let fonts = g.getFonts();
+ function save(key, value) {
+ settings[key] = value;
+ require("Storage").write("launch.json",settings);
+ }
+ const appMenu = {
+ "": { "title": /*LANG*/"Launcher" },
+ /*LANG*/"< Back": back,
+ /*LANG*/"Show Clocks": {
+ value: settings.showClocks == true,
+ format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
+ onchange: (m) => { save("showClocks", m) }
+ },
+ /*LANG*/"Fullscreen": {
+ value: settings.fullscreen == true,
+ format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
+ onchange: (m) => { save("fullscreen", m) }
+ },
+ /*LANG*/"Direct launch": {
+ value: settings.direct == true,
+ format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
+ onchange: (m) => { save("direct", m) }
+ },
+ /*LANG*/"One click exit": {
+ value: settings.oneClickExit == true,
+ format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
+ onchange: (m) => { save("oneClickExit", m) }
+ }
+ };
+ E.showMenu(appMenu);
+});
diff --git a/apps/multitimer/ChangeLog b/apps/multitimer/ChangeLog
index 624f1b0fb..9b60f403a 100644
--- a/apps/multitimer/ChangeLog
+++ b/apps/multitimer/ChangeLog
@@ -1 +1,2 @@
-0.01: Initial version
\ No newline at end of file
+0.01: Initial version
+0.02: Update for time_utils module
diff --git a/apps/multitimer/alarm.js b/apps/multitimer/alarm.js
index fc0195455..97cbaa5fa 100644
--- a/apps/multitimer/alarm.js
+++ b/apps/multitimer/alarm.js
@@ -73,7 +73,7 @@ function showAlarm(alarm) {
const settings = require("sched").getSettings();
let msg = "";
- msg += require("sched").formatTime(alarm.timer);
+ if (alarm.timer) msg += require("time_utils").formatTime(alarm.timer);
if (alarm.msg) {
msg += "\n"+alarm.msg;
}
@@ -86,7 +86,7 @@ function showAlarm(alarm) {
if (alarm.data.hm && alarm.data.hm == true) {
//hard mode extends auto-snooze time
- buzzCount = buzzCount * 2;
+ buzzCount = buzzCount * 3;
startHM();
}
diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js
index becaf6169..e5d77d860 100644
--- a/apps/multitimer/app.js
+++ b/apps/multitimer/app.js
@@ -258,7 +258,7 @@ function editTimer(idx, a) {
a.last = 0;
a.data.ot = a.timer;
a.appid = "multitimer";
- a.js = "load('multitimer.alarm.js')";
+ a.js = "(require('Storage').read('multitimer.alarm.js') !== undefined) ? load('multitimer.alarm.js') : load('sched.js')";
if (idx < 0) alarms.push(a);
else alarms[timerIdx[idx]] = a;
require("sched").setAlarms(alarms);
@@ -585,7 +585,7 @@ function editAlarm(idx, a) {
var menu = {
"": { "title": "Alarm" },
"< Back": () => {
- if (a.data.hm == true) a.js = "load('multitimer.alarm.js')";
+ if (a.data.hm == true) a.js = "(require('Storage').read('multitimer.alarm.js') !== undefined) ? load('multitimer.alarm.js') : load('sched.js')";
if (a.data.hm == false && a.js) delete a.js;
if (idx >= 0) alarms[alarmIdx[idx]] = a;
else alarms.push(a);
diff --git a/apps/multitimer/metadata.json b/apps/multitimer/metadata.json
index 6e53e2c8c..abb958b90 100644
--- a/apps/multitimer/metadata.json
+++ b/apps/multitimer/metadata.json
@@ -1,7 +1,7 @@
{
"id": "multitimer",
"name": "Multi Timer",
- "version": "0.01",
+ "version": "0.02",
"description": "Set timers and chronographs (stopwatches) and watch them count down in real time. Pause, create, edit, and delete timers and chronos, and add custom labels/messages. Also sets alarms.",
"icon": "app.png",
"screenshots": [
@@ -19,4 +19,4 @@
],
"data": [{"name":"multitimer.json"}],
"dependencies": {"scheduler":"type"}
-}
\ No newline at end of file
+}
diff --git a/apps/rebble/ChangeLog b/apps/rebble/ChangeLog
index 5dd28453e..4b415c1c5 100644
--- a/apps/rebble/ChangeLog
+++ b/apps/rebble/ChangeLog
@@ -4,4 +4,5 @@
0.04: Fixed icon and png to 48x48 pixels
0.05: added charging icon
0.06: Add 12h support and autocycle control
-0.07: added localization; removed deprecated code
\ No newline at end of file
+0.07: added localization, removed deprecated code
+0.08: removed unused font, fix autocycle, imported suncalc and trimmed, removed pedometer dependency, "tap to cycle" setting
diff --git a/apps/rebble/KdamThmor.ttf b/apps/rebble/KdamThmor.ttf
new file mode 100644
index 000000000..ca484ccbd
Binary files /dev/null and b/apps/rebble/KdamThmor.ttf differ
diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json
index e1f18ea55..e28c67784 100644
--- a/apps/rebble/metadata.json
+++ b/apps/rebble/metadata.json
@@ -2,11 +2,11 @@
"id": "rebble",
"name": "Rebble Clock",
"shortName": "Rebble",
- "version": "0.07",
+ "version": "0.08",
"description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion",
"readme": "README.md",
"icon": "rebble.png",
- "dependencies": {"mylocation":"app", "widpedom":"app"},
+ "dependencies": {"mylocation":"app"},
"screenshots": [{"url":"screenshot_rebble.png"}],
"type": "clock",
"tags": "clock",
@@ -14,6 +14,7 @@
"storage": [
{"name":"rebble.app.js","url":"rebble.app.js"},
{"name":"rebble.settings.js","url":"rebble.settings.js"},
- {"name":"rebble.img","url":"rebble.icon.js","evaluate":true}
+ {"name":"rebble.img","url":"rebble.icon.js","evaluate":true},
+ {"name":"suncalc","url":"suncalc.js"}
]
}
diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js
index bdc7ed1a3..8ba61f818 100644
--- a/apps/rebble/rebble.app.js
+++ b/apps/rebble/rebble.app.js
@@ -1,4 +1,4 @@
-var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js");
+var SunCalc = require("suncalc");
const SETTINGS_FILE = "rebble.json";
const LOCATION_FILE = "mylocation.json";
const GLOBAL_SETTINGS = "setting.json";
@@ -6,14 +6,15 @@ let settings;
let location;
let is12Hour;
-Graphics.prototype.setFontLECO1976Regular22 = function(scale) {
- // Actual height 22 (21 - 0)
- g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/nA/+cD/5wP/nAAAAAAAAPwAA/gAD+AAPwAAAAAD+AAP4AA/gAAAAAAAAAAAAAcOAP//A//8D//wP//AHDgAcOAP//A//8D//wP//AHDgAAAAAAAAH/jgf+OB/44H/jj8OP/w4//Dj/8OPxw/4HD/gcP+Bw/4AAAAAAAP+AA/8AD/wQOHHA4c8D//wP/8A//gAD4AAfAAH/8A//wP//A84cDjhwIP/AA/8AB/wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8ABwAAAAAAAAD8AAP4AA/gAD8AAAAAAAAAAAEAAD+AB//A///v/D//gB/wABwAAAAAADgAA/wAf/4P8///wf/4AP8AAOAAAAAAAAAyAAHcAAPwAD/gAP/AA/8AA/AAH8AAMwAAAAAAAAAAAAADgAAOAAA4AAf8AD/wAP/AA/8AAOAAA4AADgAAAAAAAAAAD8AAfwAB/AAD8AAAAAAAADgAAOAAA4AADgAAOAAA4AADgAAAAAAAAAADgAAOAAA4AADgAAAAAAAAABwAB/AA/8A//gP/gA/wADwAAIAAAAAAD//wP//A//8D//wOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA4AcDgBwOAHA//8D//wP//A//8AABwAAHAAAcAAAAAAAA+f8D5/wPn/A+f8DhxwOHHA4ccDhxwP/HA/8cD/xwP/HAAAAAAAAOAHA4AcDhxwOHHA4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/wAP/AA/8AD/wAAHAAAcAABwAAHAA//8D//wP//A//8AAAAAAAA/98D/3wP/fA/98DhxwOHHA4ccDhxwOH/A4f8Dh/wOH/AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccDh/wOH/A4f8Dh/wAAAAAAAD4AAPgAA+AADgAAOAAA4AADgAAP//A//8D//wP//AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA//8D//wP//A//8AAAAAAAAOA4A4DgDgOAOA4AAAAAAAAOA/A4H8DgfwOA/AAAAAAAAB4AAPwAA/AAD8AAf4ABzgAPPAA8cAHh4AAAAAAAAAAAAHHAAccABxwAHHAAccABxwAHHAAccABxwAHHAAAAAAAAAOHAA4cADzwAPPAAf4AB/gAD8AAPwAAeAAB4AAAAAAAAA+AAD4AAPgAA+ecDh9wOH3A4fcDhwAP/AA/8AD/wAP/AAAAAAAAAP//4///j//+P//44ADjn/OOf845/zjnHOP8c4//zj//OP/84AAAAAAAP//A//8D//wP//A4cADhwAOHAA4cAD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA//8D//wP9/A/j8AAAAAAAA//8D//wP//A//8DgBwOAHA4AcDgBwOAHA4AcDgBwOAHAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA8A8D//wH/+AP/wAf+AAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4ccDhxwOAHA4AcAAAAAAAA//8D//wP//A//8DhwAOHAA4cADhwAOHAA4cADgAAOAAAAAAD//wP//A//8D//wOAHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA//8D//wP//A//8ABwAAHAAAcAABwAP//A//8D//wP//AAAAAAAAP//A//8D//wP//AAAAAAAAOAHA4AcDgBwOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA//8D//wP//A//8AHwAA/AAP8AB/wAPn/A8f8DB/wIH/AAAAAAAAP//A//8D//wP//AAAcAABwAAHAAAcAABwAAHAAAAAAAAP//A//8D//wP//Af8AAP+AAH/AAD8AAHwAD/AB/wAf8AP+AA//8D//wP//AAAAAAAAP//A//8D//wP//AfwAAfwAAfwAAfwAAfwP//A//8D//wAAAAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHAA4cADhwAOHAA/8AD/wAP/AA/8AAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//+P//4///j//+AAA4AADgAAAP//A//8D//wP//A4eADh+AOH8A4f4D/3wP/HA/8MD/wQAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA4AADgAAOAAA//8D//wP//A//8DgAAOAAA4AADgAAAAAA//8D//wP//A//8AABwAAHAAAcAABwP//A//8D//wP//AAAADAAAPgAA/wAD/4AB/8AA/8AAfwAB/AA/8Af+AP/AA/wAD4AAMAAA4AAD+AAP/gA//8AH/wAB/AAf8Af/wP/4A/4AD/gAP/4AH/8AB/wAB/AB/8D//wP/gA/gADgAAIABA4AcDwDwPw/Afn4Af+AA/wAD/AA//AH5+A/D8DwDwOAHAgAEAAAAP/AA/8AD/wAP/AAAf8AB/wAH/AAf8D/wAP/AA/8AD/wAAAAAAAADh/wOH/A4f8Dh/wOHHA4ccDhxwOHHA/8cD/xwP/HA/8cAAAAAAAAf//9///3///f//9wAA3AADcAAMAAAOAAA/gAD/wAH/8AB/8AA/wAAPAAAEAAAAHAADcAANwAB3///f//9///wAA"), 32, atob("BwYLDg4UDwYJCQwMBgkGCQ4MDg4ODg4NDg4GBgwMDA4PDg4ODg4NDg4GDQ4MEg8ODQ8ODgwODhQODg4ICQg="), 22+(scale<<8)+(1<<16));
-}
-
Graphics.prototype.setFontKdamThmor = function(scale) {
- // Actual height 72 (71 - 0)
- g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAAAAAAAAAAAAH+AAAAAAAAAAAAAP/AAAAAAAAAAAAAf/gAAAAAAAAAAAA//gAAAAAAAAAAAA//wAAAAAAAAAAAA//wAAAAAAAAAAAA//wAAAAAAAAAAAA//wAAAAAAAAAAAA//gAAAAAAAAAAAAf/gAAAAAAAAAAAAf/AAAAAAAAAAAAAP+AAAAAAAAAAAAAD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAAAAAAAAAAAAB/AAAAAAAAAAAAAP/AAAAAAAAAAAAA//AAAAAAAAAAAAH/+AAAAAAAAAAAAf/+AAAAAAAAAAAD//+AAAAAAAAAAAf//8AAAAAAAAAAB///4AAAAAAAAAAP///wAAAAAAAAAA////AAAAAAAAAAH///4AAAAAAAAAAf///gAAAAAAAAAD///8AAAAAAAAAAf///wAAAAAAAAAB///+AAAAAAAAAAP///4AAAAAAAAAA////AAAAAAAAAAH///4AAAAAAAAAAf///gAAAAAAAAAD///8AAAAAAAAAAP///wAAAAAAAAAB///+AAAAAAAAAAP///4AAAAAAAAAA////AAAAAAAAAAD///4AAAAAAAAAAP///gAAAAAAAAAAf//8AAAAAAAAAAA///wAAAAAAAAAAA//+AAAAAAAAAAAA//4AAAAAAAAAAAA//AAAAAAAAAAAAA/4AAAAAAAAAAAAA/gAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//AAAAAAAAAAAP///+AAAAAAAAAD/////wAAAAAAAAP/////+AAAAAAAA///////gAAAAAAD///////4AAAAAAH///////8AAAAAAf///////+AAAAAA/////////gAAAAB/////////wAAAAB/////////wAAAAD/////////4AAAAH///AAA///8AAAAH//wAAAB//8AAAAP/+AAAAAP/+AAAAP/4AAAAAD/+AAAAf/gAAAAAA//AAAAf/AAAAAAAf/AAAAf+AAAAAAAP/AAAA/+AAAAAAAP/gAAA/8AAAAAAAH/gAAA/8AAAAAAAH/gAAA/8AAAAAAAH/gAAA/8AAAAAAAH/gAAA/8AAAAAAAH/gAAA/8AAAAAAAH/gAAA/8AAAAAAAH/gAAA/8AAAAAAAH/gAAA/+AAAAAAAP/gAAAf+AAAAAAAP/AAAAf/AAAAAAAf/AAAAf/gAAAAAA//AAAAP/4AAAAAD/+AAAAP/+AAAAAP/+AAAAH//gAAAA//8AAAAH///AAAf//8AAAAD/////////4AAAAD/////////wAAAAB/////////wAAAAA/////////gAAAAAf////////AAAAAAH///////8AAAAAAD///////4AAAAAAA///////gAAAAAAAP/////+AAAAAAAAD/////4AAAAAAAAAf////AAAAAAAAAAA///gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAADwAAAAAAAAAAAAAD4AAAAAAAAAAAAAH8AAAAAAAAAAAAAP+AAAAAAAAAAAAAf/AAAAAH/AAAAAA//AAAAAH/AAAAAB//AAAAAH/AAAAAB//AAAAAH/AAAAAD/+AAAAAH/AAAAAH/8AAAAAH/AAAAAP/4AAAAAH/AAAAAf/wAAAAAH/AAAAA//gAAAAAH/AAAAB//gAAAAAH/AAAAB//AAAAAAH/AAAAD/+AAAAAAH/AAAAH/8AAAAAAH/AAAAP//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/AAAAAAHgAAAAAD/AAAAAA/wAAAAAH/AAAAAD/wAAAAAP/AAAAAH/wAAAAAf/AAAAAP/wAAAAA//AAAAA//wAAAAB//AAAAB//wAAAAD//AAAAB//wAAAAH//AAAAD//wAAAAP//AAAAH//wAAAAf//AAAAH//gAAAA///AAAAP/+AAAAB///AAAAP/4AAAAD///AAAAf/gAAAAH///AAAAf/AAAAAP///AAAAf+AAAAAf///AAAAf+AAAAA//v/AAAA/8AAAAB//P/AAAA/8AAAAD/+P/AAAA/8AAAAH/8P/AAAA/8AAAAP/4P/AAAA/8AAAAf/wf/AAAA/8AAAA//gf/AAAA/8AAAD//Af/AAAA/8AAAH/+Af/AAAA/+AAAP/8Af/AAAA/+AAAf/4Af/AAAAf/AAB//wAf/AAAAf/gAD//gAf/AAAAf/wAf//AAf/AAAAf/+D//+AAf/AAAAP/////8AAf/AAAAP/////4AAf/AAAAH/////wAAf/AAAAH/////gAAf/AAAAD/////AAAf/AAAAB////8AAAf/AAAAA////4AAAf/AAAAAf///wAAAf/AAAAAP///AAAAf/AAAAAD//8AAAAf/AAAAAA//gAAAAP/AAAAAABwAAAAAH/AAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAfAAAAAAAAHgAAAA/wAAAAAAA/wAAAA/8AAAAAAD/wAAAB/+AAAAAAH/wAAAB//AAAAAAP/wAAAB//gAAAAA//wAAAB//wAAAAB//wAAAB//4AAAAB//wAAAB//8AAAAD//wAAAA//8AAAAH//wAAAAf/+AAAAH//gAAAAH/+AAAAP/+AAAAAB//AAAAP/4AAAAAA//AAAAf/gAAAAAAf/AAAAf/AAAAAAAf/AAAAf/AAAAAAAP/gAAAf+AAAAAAAP/gAAA/+AAD/gAAH/gAAA/8AAD/gAAH/gAAA/8AAD/gAAH/gAAA/8AAD/gAAH/gAAA/8AAD/gAAH/gAAA/8AAD/gAAH/gAAA/8AAD/gAAH/gAAA/8AAH/wAAH/gAAA/8AAH/wAAP/gAAA/+AAH/wAAP/AAAAf/AAP/4AAf/AAAAf/AAf/4AA//AAAAf/wA//8AB//AAAAf/+H//+AD/+AAAAP//////4f/+AAAAP////v////8AAAAH////v////8AAAAH////H////4AAAAD////H////wAAAAB///+D////wAAAAA///8D////gAAAAAf//4B////AAAAAAP//wA///+AAAAAAD//AAf//4AAAAAAAf4AAH//gAAAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAAAAAAAAAAAD/gAAAAAAAAAAAAP/wAAAAAAAAAAAAf/wAAAAAAAAAAAA//wAAAAAAAAAAAD//wAAAAAAAAAAAH//wAAAAAAAAAAAP//wAAAAAAAAAAA///wAAAAAAAAAAB///wAAAAAAAAAAD///wAAAAAAAAAAP///wAAAAAAAAAAf///wAAAAAAAAAA//9/wAAAAAAAAAD//x/wAAAAAAAAAH//h/wAAAAAAAAAP/+B/wAAAAAAAAA//8B/wAAAAAAAAB//4B/wAAAAAAAAD//gB/wAAAAAAAAP//AB/wAAAAAAAAf/+AB/wAAAAAAAA//4AB/wAAAAAAAD//wAB/wAAAAAAAH//AAB/wAAAAAAAP/+AAB/wAAAAAAA//8AAB/wAAAAAAB//wAAB/wAAAAAAD//gAAB/wAAAAAAP/+AAAB/wAAAAAAf/8AAAB/wAAAAAAf/5////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAf//////////AAAAAAAAAAB/wAAAAAAAAAAAAB/wAAAAAAAAAAAAB/wAAAAAAAAAAAAB/wAAAAAAAAAAAAB/wAAAAAAAAAAAAB/wAAAAAAAAAAAAB/wAAAAAAAAAAAAB/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAPgAAAAAAAAAAAAA/wAAAAAAAAD4AAB/4AAAAAAAD/4AAB/4AAAAAAD//4AAB/8AAAAAD///8AAB/8AAAAD////8AAB/+AAAAf////8AAA/+AAAAf////+AAA/+AAAAf////+AAAf/AAAAf////8AAAf/AAAAf////8AAAP/AAAAf////8AAAP/AAAAf//4/4AAAH/gAAAf/8A/4AAAH/gAAAf+AA/4AAAH/gAAAf+AA/4AAAH/gAAAf+AA/4AAAH/gAAAf+AA/4AAAH/gAAAf+AA/4AAAH/gAAAf+AB/4AAAH/gAAAf+AB/4AAAH/gAAAf+AA/8AAAP/gAAAf+AA/8AAAP/AAAAf+AA/8AAAP/AAAAf+AA/+AAAf/AAAAf+AA/+AAA//AAAAf+AA//AAB/+AAAAf+AAf/gAD/+AAAAf+AAf/4Af/8AAAAf+AAf/////8AAAAf+AAP/////4AAAAf+AAP/////wAAAAf+AAH/////wAAAAf+AAD/////gAAAAf+AAD/////AAAAAf+AAB////+AAAAAf8AAA////8AAAAAf4AAAP///wAAAAAfgAAAH///AAAAAAAAAAAA//8AAAAAAAAAAAAH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AAAAAAAAAAAB///AAAAAAAAAAAP///wAAAAAAAAAA////8AAAAAAAAAB////+AAAAAAAAAH/////AAAAAAAAAP/////gAAAAAAAA//////wAAAAAAAB//////4AAAAAAAH//////8AAAAAAAP//////8AAAAAAAf//+AP/+AAAAAAB///4AB/+AAAAAAD///wAA/+AAAAAAH///gAAf/AAAAAAf///AAAP/AAAAAA///+AAAP/AAAAAB///+AAAH/gAAAAH//3+AAAH/gAAAAP//v8AAAH/gAAAAf//P8AAAH/gAAAB//+P8AAAH/gAAAD//4f8AAAH/gAAAH//wf8AAAH/gAAAP//gf8AAAH/gAAAf//Af8AAAH/gAAAf/8Af+AAAH/gAAAf/4Af+AAAP/AAAAf/wAf+AAAP/AAAAf/gAf/AAAf/AAAAf/AAP/gAA//AAAAf8AAP/wAB/+AAAAf4AAP/4AD/+AAAAfwAAP//Af/8AAAAfgAAH/////8AAAAeAAAH/////4AAAAcAAAD/////4AAAAYAAAD/////wAAAAQAAAB/////gAAAAAAAAA/////AAAAAAAAAAf///+AAAAAAAAAAP///8AAAAAAAAAAD///wAAAAAAAAAAB///AAAAAAAAAAAAP/8AAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAAAAAAf+AAAAAAAAAAAAAf+AAAAAAAAAAAAAf+AAAAAAAAAAAAAf+AAAAAAAAAAAAAf+AAAAAAAABAAAAf+AAAAAAAAHAAAAf+AAAAAAAAfAAAAf+AAAAAAAB/AAAAf+AAAAAAAH/AAAAf+AAAAAAAf/AAAAf+AAAAAAB//AAAAf+AAAAAAH//AAAAf+AAAAAAf//AAAAf+AAAAAB///AAAAf+AAAAAH///AAAAf+AAAAAf///AAAAf+AAAAB///+AAAAf+AAAAH///8AAAAf+AAAAf///wAAAAf+AAAA////AAAAAf+AAAD///8AAAAAf+AAAP///wAAAAAf+AAA////AAAAAAf+AAD///8AAAAAAf+AAP///wAAAAAAf+AA////AAAAAAAf+AD///8AAAAAAAf+AP///wAAAAAAAf+A////AAAAAAAAf+D///8AAAAAAAAf+P///wAAAAAAAAf+f//+AAAAAAAAAf////4AAAAAAAAAf////gAAAAAAAAAf///+AAAAAAAAAAf///4AAAAAAAAAAf///gAAAAAAAAAAf//+AAAAAAAAAAAf//4AAAAAAAAAAAf//gAAAAAAAAAAAf/+AAAAAAAAAAAAf/4AAAAAAAAAAAAf/gAAAAAAAAAAAAf+AAAAAAAAAAAAAfgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4AAAAAAAAAAAAB//gAAAAAAADwAAH//4AAAAAAA//AAf//8AAAAAAD//wA////AAAAAAP//4B////gAAAAAf//+B////wAAAAA////D////wAAAAB////H////4AAAAD////n////8AAAAH/////////8AAAAH/////////+AAAAP//////wP/+AAAAP//////AB/+AAAAf/wD//8AA//AAAAf/AA//4AAf/AAAAf+AAf/4AAP/AAAAf8AAP/wAAH/AAAA/8AAH/wAAH/gAAA/4AAH/gAAH/gAAA/4AAH/gAAD/gAAA/4AAD/gAAD/gAAA/4AAD/gAAD/gAAA/4AAD/gAAD/gAAA/4AAD/gAAD/gAAA/4AAD/gAAD/gAAA/4AAH/gAAH/gAAA/8AAH/wAAH/gAAAf8AAP/wAAH/gAAAf+AAP/wAAP/AAAAf/AAf/4AAf/AAAAf/wB//8AAf/AAAAP/////+AB//AAAAP//////wH/+AAAAH/////////+AAAAH/////////8AAAAD////n////8AAAAB////H////4AAAAA////D////wAAAAAf//+B////wAAAAAP//8B////gAAAAAH//wA////AAAAAAB//AAf//8AAAAAAAH4AAH//4AAAAAAAAAAAB//gAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AAAAAAAAAAAAf//AAAAAAAAAAAB///wAAAAAAAAAAH///4AAAAAAAAAAP///+AAAAAAAAAAf////AAAAAAAAAA/////AAAADAAAAB/////gAAAHAAAAD/////wAAAPAAAAH/////wAAAfAAAAH/////4AAB/AAAAP//A//4AAD/AAAAP/4AH/8AAH/AAAAf/gAD/8AAP/AAAAf/AAB/8AA//AAAAf+AAA/8AB//AAAAf+AAA/8AD//AAAA/8AAAf8AH//AAAA/8AAAf8Af//AAAA/8AAAf8A//+AAAA/8AAAf8B//+AAAA/8AAAf8D//8AAAA/8AAAf8P//wAAAA/8AAAf8f//gAAAA/8AAAf4//+AAAAA/8AAAf5//8AAAAA/8AAAf3//4AAAAAf+AAA////gAAAAAf+AAB////AAAAAAf/AAB///8AAAAAAf/gAD///4AAAAAAP/4AP///gAAAAAAP//B////AAAAAAAH//////+AAAAAAAH//////4AAAAAAAD//////wAAAAAAAB//////AAAAAAAAA/////+AAAAAAAAAf////4AAAAAAAAAP////wAAAAAAAAAH////AAAAAAAAAAB///8AAAAAAAAAAAf//gAAAAAAAAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAD8AAAAAAAA/4AAAP+AAAAAAAB/8AAAf/AAAAAAAB/+AAAf/gAAAAAAD/+AAA//gAAAAAAD//AAA//wAAAAAAD//AAA//wAAAAAAD//AAA//wAAAAAAD//AAA//wAAAAAAD/+AAA//gAAAAAAB/+AAAf/gAAAAAAA/8AAAP/AAAAAAAAf4AAAH+AAAAAAAAHgAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("FCM0NDQ0NDQ0NDQ0GA=="), 90+(scale<<8)+(1<<16));
+ // Actual height 70 (69 - 0)
+ this.setFontCustom(
+ E.toString(require('heatshrink').decompress(atob('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'))),
+ 46,
+ atob("GBo2NjY2NjY2NjY2Gg=="),
+ 94+(scale<<8)+(1<<16)
+ );
+ return this;
}
var boot_img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4A/AE8AAAoeXoAfeDQUBmcyD7A+Dh///8QD649CiAfaHwUvD4sEHy0DDYIfEICg+Cn4fHICY+DD4nxcgojOHwgfEIAYfRCIQaDD4ZAFD5r7DH4//kAfRCIZ/GAAnwD5p9DX44fTHgYSBf4ofVDAQEBl4fFUAgfOXoQzBgIfFBAIfPP4RAEAoYAB+cRiK/SG4h/WIBAfXIA7CBAAswD55AHn6fUIBMCD65AHl4gCmcziAfQQJqfQQJpiDgk0IDXxQLRAEECaBM+QgRYRYgUIA0CD4ggSQJiDCiAKBICszAAswD55AHABKBVD7BAFABIqBD5pAFABPxD55AOD6BADiIAJQAyxLABwf/gaAPAH4A/AH4ARA=="));
@@ -27,6 +28,7 @@ var sunSet = "00:00";
function log_debug(o) {
//console.log(o);
+
}
// requires the myLocation app
@@ -35,7 +37,16 @@ function loadLocation() {
}
function loadSettings() {
- settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'bg': '#0f0', 'color': 'Green', 'autoCycle': true};
+ settings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true,'sideTap':0};
+ //sideTap 0 = on | 1 = sidebar1...
+
+ let tmp = require('Storage').readJSON(SETTINGS_FILE, 1) || settings;
+ for (const key in tmp) {
+ settings[key] = tmp[key]
+ }
+
+ if(settings.sideTap!=0)
+ sideBar=parseInt(settings.sideTap)-1; //tab to show
is12Hour = (require("Storage").readJSON(GLOBAL_SETTINGS, 1) || {})["12hour"] || false;
}
@@ -236,20 +247,11 @@ function drawBattery(x,y,wi,hi) {
}
-function getSteps() {
- if (WIDGETS.wpedom !== undefined) {
- return WIDGETS.wpedom.getSteps();
- }
- return '????';
-}
-
// format steps so they fit in the place
function formatSteps() {
- var s = getSteps();
+ var s = Bangle.getHealthStatus("day").steps;
- if ( s == '????') {
- return s;
- } else if (s < 1000) {
+ if (s < 1000) {
return s + '';
} else if (s < 10000) {
return '' + (s/1000).toFixed(1) + 'K';
@@ -258,20 +260,19 @@ function formatSteps() {
}
function nextSidebar() {
+
if (++sideBar > 2) sideBar = 0;
log_debug("next: " + sideBar);
+
}
function prevSidebar() {
+
if (--sideBar < 0) sideBar = 2;
log_debug("prev: " + sideBar);
+
}
-Bangle.setUI("clockupdown", btn=> {
- if (btn<0) prevSidebar();
- if (btn>0) nextSidebar();
- draw();
-});
// timeout used to update every minute
@@ -282,7 +283,7 @@ function queueDraw() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
- if (!settings.autoCycle) {
+ if (settings.autoCycle) {
nextSidebar();
}
draw();
@@ -301,6 +302,24 @@ Bangle.loadWidgets();
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
loadSettings();
loadLocation();
+
+
+
+if(settings.autoCycle || settings.sideTap==0)
+{
+ Bangle.setUI("clockupdown", btn=> {
+ if (btn<0) prevSidebar();
+ if (btn>0) nextSidebar();
+ draw();
+ });
+}
+else{
+ Bangle.setUI("clock");
+}
+
+
+
+
draw(); // queues the next draw for a minutes time
Bangle.on('charging', function(charging) {
//redraw the sidebar ( with the battery )
diff --git a/apps/rebble/rebble.settings.js b/apps/rebble/rebble.settings.js
index 91142d72d..37b7be3a1 100644
--- a/apps/rebble/rebble.settings.js
+++ b/apps/rebble/rebble.settings.js
@@ -2,12 +2,14 @@
const SETTINGS_FILE = "rebble.json";
// initialize with default settings...
- let localSettings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true}
+ let localSettings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true, 'sideTap':0};
+ //sideTap 0 = on| 1= sideBar1 | 2 = ...
// ...and overwrite them with any saved values
// This way saved values are preserved if a new version adds more settings
const storage = require('Storage')
let settings = storage.readJSON(SETTINGS_FILE, 1) || localSettings;
+
const saved = settings || {}
for (const key in saved) {
localSettings[key] = saved[key]
@@ -21,26 +23,55 @@
var color_options = ['Green','Orange','Cyan','Purple','Red','Blue'];
var bg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f'];
- E.showMenu({
- '': { 'title': 'Rebble Clock' },
- '< Back': back,
- 'Colour': {
- value: 0 | color_options.indexOf(localSettings.color),
- min: 0, max: 5,
- format: v => color_options[v],
- onchange: v => {
- localSettings.color = color_options[v];
- localSettings.bg = bg_code[v];
- save();
+ function showMenu()
+ {
+ const menu={
+ '': { 'title': 'Rebble Clock' },
+ '< Back': back,
+ 'Colour': {
+ value: 0 | color_options.indexOf(localSettings.color),
+ min: 0, max: 5,
+ format: v => color_options[v],
+ onchange: v => {
+ localSettings.color = color_options[v];
+ localSettings.bg = bg_code[v];
+ save();
+ },
},
- },
- 'Auto Cycle': {
- value: "autoCycle" in localSettings ? localSettings.autoCycle : true,
- format: () => (localSettings.autoCycle ? 'Yes' : 'No'),
- onchange: () => {
- localSettings.autoCycle = !localSettings.autoCycle;
- save();
+ 'Auto Cycle': {
+ value: localSettings.autoCycle,
+ onchange: (v) => {
+ localSettings.autoCycle = v;
+ save();
+ showMenu();
+ }
}
+ };
+
+ if( !localSettings.autoCycle)
+ {
+ menu['Tap to Cycle']= {
+ value: localSettings.sideTap,
+ min: 0,
+ max: 3,
+ step: 1,
+ format: v => NumberToSideTap(v),
+ onchange: v => {
+ localSettings.sideTap=v
+ save();
+ setTimeout(showMenu, 10);
+ }
+ };
}
- });
-})
+ E.showMenu(menu);
+ }
+
+ function NumberToSideTap(Number)
+ {
+ if(Number==0)
+ return 'on';
+ return Number+"";
+ }
+
+ showMenu();
+})
\ No newline at end of file
diff --git a/apps/rebble/suncalc.js b/apps/rebble/suncalc.js
new file mode 100644
index 000000000..d86f039c5
--- /dev/null
+++ b/apps/rebble/suncalc.js
@@ -0,0 +1,143 @@
+/*
+ (c) 2011-2015, Vladimir Agafonkin
+ SunCalc is a JavaScript library for calculating sun/moon position and light phases.
+ https://github.com/mourner/suncalc
+
+ edit for banglejs
+*/
+
+(function () { 'use strict';
+
+// shortcuts for easier to read formulas
+
+var PI = Math.PI,
+ sin = Math.sin,
+ cos = Math.cos,
+ tan = Math.tan,
+ asin = Math.asin,
+ atan = Math.atan2,
+ acos = Math.acos,
+ rad = PI / 180;
+
+// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
+
+
+// date/time constants and conversions
+
+var dayMs = 1000 * 60 * 60 * 24,
+ J1970 = 2440588,
+ J2000 = 2451545;
+
+function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
+function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); }
+function toDays(date) { return toJulian(date) - J2000; }
+
+
+// general calculations for position
+
+var e = rad * 23.4397; // obliquity of the Earth
+
+function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
+
+
+// general sun calculations
+
+function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
+
+function eclipticLongitude(M) {
+
+ var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
+ P = rad * 102.9372; // perihelion of the Earth
+
+ return M + C + P + PI;
+}
+
+var SunCalc = {};
+
+
+// sun times configuration (angle, morning name, evening name)
+
+var times = SunCalc.times = [
+ [-0.833, 'sunrise', 'sunset' ],
+ [ -0.3, 'sunriseEnd', 'sunsetStart' ],
+ [ -6, 'dawn', 'dusk' ],
+ [ -12, 'nauticalDawn', 'nauticalDusk'],
+ [ -18, 'nightEnd', 'night' ],
+ [ 6, 'goldenHourEnd', 'goldenHour' ]
+];
+
+
+
+// calculations for sun times
+
+var J0 = 0.0009;
+
+function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); }
+
+function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; }
+function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); }
+
+function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); }
+function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; }
+
+// returns set time for the given sun altitude
+function getSetJ(h, lw, phi, dec, n, M, L) {
+
+ var w = hourAngle(h, phi, dec),
+ a = approxTransit(w, lw, n);
+ return solarTransitJ(a, M, L);
+}
+
+
+// calculates sun times for a given date, latitude/longitude, and, optionally,
+// the observer height (in meters) relative to the horizon
+
+SunCalc.getTimes = function (date, lat, lng, height) {
+
+ height = height || 0;
+
+ var lw = rad * -lng,
+ phi = rad * lat,
+
+ dh = observerAngle(height),
+
+ d = toDays(date),
+ n = julianCycle(d, lw),
+ ds = approxTransit(0, lw, n),
+
+ M = solarMeanAnomaly(ds),
+ L = eclipticLongitude(M),
+ dec = declination(L, 0),
+
+ Jnoon = solarTransitJ(ds, M, L),
+
+ i, len, time, h0, Jset, Jrise;
+
+
+ var result = {
+ solarNoon: fromJulian(Jnoon),
+ nadir: fromJulian(Jnoon - 0.5)
+ };
+
+ for (i = 0, len = times.length; i < len; i += 1) {
+ time = times[i];
+ h0 = (time[0] + dh) * rad;
+
+ Jset = getSetJ(h0, lw, phi, dec, n, M, L);
+ Jrise = Jnoon - (Jset - Jnoon);
+
+ result[time[1]] = fromJulian(Jrise);
+ result[time[2]] = fromJulian(Jset);
+ }
+
+ return result;
+};
+
+
+// export as Node module / AMD module / browser variable
+if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc;
+else if (typeof define === 'function' && define.amd) define(SunCalc);
+else window.SunCalc = SunCalc;
+
+
+}());
\ No newline at end of file
diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog
index de070dbd8..95945be78 100644
--- a/apps/run/ChangeLog
+++ b/apps/run/ChangeLog
@@ -12,3 +12,4 @@
0.11: Notifications fixes
0.12: Fix for recorder not stopping at end of run. Bug introduced in 0.11
0.13: Revert #1578 (stop duplicate entries) as with 2v12 menus it causes other boxes to be wiped (fix #1643)
+0.14: Fix Bangle.js 1 issue where after the 'overwrite track' menu, the start/stop button stopped working
diff --git a/apps/run/app.js b/apps/run/app.js
index 19dcd7e88..4038b8c1a 100644
--- a/apps/run/app.js
+++ b/apps/run/app.js
@@ -55,6 +55,7 @@ function onStartStop() {
prepPromises.push(
WIDGETS["recorder"].setRecording(true).then(() => {
isMenuDisplayed = false;
+ layout.setUI(); // grab our input handling again
layout.forgetLazyState();
layout.render();
})
diff --git a/apps/run/metadata.json b/apps/run/metadata.json
index afa52b2f7..933576a5d 100644
--- a/apps/run/metadata.json
+++ b/apps/run/metadata.json
@@ -1,6 +1,6 @@
{ "id": "run",
"name": "Run",
- "version":"0.13",
+ "version":"0.14",
"description": "Displays distance, time, steps, cadence, pace and more for runners.",
"icon": "app.png",
"tags": "run,running,fitness,outdoors,gps",
diff --git a/apps/sched/boot.js b/apps/sched/boot.js
index 3020f4945..98bb0ff7d 100644
--- a/apps/sched/boot.js
+++ b/apps/sched/boot.js
@@ -24,7 +24,7 @@
will then clearInterval() to get rid of this call so it can proceed
normally.
If active[0].js is defined, just run that code as-is and not alarm.js */
- Bangle.SCHED = setTimeout(require("Storage").read(active[0].js)!==undefined ? active[0].js : 'load("sched.js")',t);
+ Bangle.SCHED = setTimeout(active[0].js||'load("sched.js")',t);
} else { // check for new alarms at midnight (so day of week works)
Bangle.SCHED = setTimeout('eval(require("Storage").read("sched.boot.js"))', 86400000 - (Date.now()%86400000));
}
diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog
index bfd32a130..6d3bbb468 100644
--- a/apps/setting/ChangeLog
+++ b/apps/setting/ChangeLog
@@ -48,3 +48,4 @@
0.43: Add some Bangle 1 colours to theme customizer
0.44: Add "Start Week On X" option (#1780)
UI improvements to Locale and Date & Time menu
+0.45: Add calibrate battery option
diff --git a/apps/setting/README.md b/apps/setting/README.md
index 451b48c06..657b96f71 100644
--- a/apps/setting/README.md
+++ b/apps/setting/README.md
@@ -13,7 +13,6 @@ This is Bangle.js's settings menu
* **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below.
* **Theme** Adjust the colour scheme
* **Utils** Utilities - including resetting settings (see below)
-* **Turn Off** Turn Bangle.js off
## BLE - Bluetooth Settings
@@ -61,5 +60,7 @@ The exact effects depend on the app. In general the watch will not wake up by i
* **Compact Storage** Removes deleted/old files from Storage - this will speed up your Bangle.js
* **Rewrite Settings** Should not normally be required, but if `.boot0` has been deleted/corrupted (and so no settings are being loaded) this will fix it.
* **Flatten Battery** Turns on all devices and draws as much power as possible, attempting to flatten the Bangle.js battery. This can still take 5+ hours.
+* **Calibrate Battery** If you're finding your battery percentage meter isn't accurate, leave your Bangle.js on charge for at least 3 hours, and then choose this menu option. It will measure the battery voltage when full and will allow Bangle.js to report a more accurate battery percentage.
* **Reset Settings** Reset the settings (as set in this app) to defaults. Does not reset settings for other apps.
* **Factory Reset** (not available on Bangle.js 1) - wipe **everything** and return to a factory state
+* **Turn Off** Turn Bangle.js off
diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json
index 85dddf9db..c5c368fae 100644
--- a/apps/setting/metadata.json
+++ b/apps/setting/metadata.json
@@ -1,7 +1,7 @@
{
"id": "setting",
"name": "Settings",
- "version": "0.44",
+ "version": "0.45",
"description": "A menu for setting up Bangle.js",
"icon": "settings.png",
"tags": "tool,system",
diff --git a/apps/setting/settings.js b/apps/setting/settings.js
index 9b5bdae68..5c14e914d 100644
--- a/apps/setting/settings.js
+++ b/apps/setting/settings.js
@@ -546,6 +546,18 @@ function showUtilMenu() {
var i=1000;while (i--);
}, 1);
},
+ /*LANG*/'Calibrate Battery': () => {
+ E.showPrompt(/*LANG*/"Is the battery fully charged?",{title:/*LANG*/"Calibrate"}).then(ok => {
+ if (ok) {
+ var s=require("Storage").readJSON("setting.json");
+ s.batFullVoltage = (analogRead(D3)+analogRead(D3)+analogRead(D3)+analogRead(D3))/4;
+ require("Storage").writeJSON("setting.json",s);
+ E.showAlert(/*LANG*/"Calibrated!").then(() => load("settings.app.js"));
+ } else {
+ E.showAlert(/*LANG*/"Please charge Bangle.js for 3 hours and try again").then(() => load("settings.app.js"));
+ }
+ });
+ },
/*LANG*/'Reset Settings': () => {
E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings"}).then((v) => {
if (v) {
diff --git a/apps/speedalt2/ChangeLog b/apps/speedalt2/ChangeLog
index 73e9bfc40..9e2abb4ef 100644
--- a/apps/speedalt2/ChangeLog
+++ b/apps/speedalt2/ChangeLog
@@ -13,3 +13,4 @@
1.14: Add VMG and coordinates screens
1.43: Adds mirroring of the watch face to an Android device. See README.md
1.49: Droidscript mirroring prog automatically uses last connection address. Auto connects when run.
+1.50: Add configuration item Wpt File Suffix. A one character suffix to append to the waypoints.json file. A number of other apps also use this file name. Using the file name suffix allows the speedalt2 waypoints to be retained if one of these other apps is installed for a different use.
diff --git a/apps/speedalt2/README.md b/apps/speedalt2/README.md
index e1c6b0a5a..c124e0c00 100644
--- a/apps/speedalt2/README.md
+++ b/apps/speedalt2/README.md
@@ -78,6 +78,10 @@ Waypoints are used in Distance and VMG modes. Create a file waypoints.json and w
The [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app in the App Loader has a really nice waypoints file editor. (Must be connected to your Bangle.JS and then click on the Download icon.)
+By default the waypoints file is called waypoints.json
+
+**Note** : The waypoints.json file is used by a number of different gps apps. The setting 'Wpt File Suffix' allows one of waypoints1.json, waypoints2.json or waypoints3.json to be used instead. This allows the other apps to be used with a different set of waypoints without losing the speedalt2 waypoint set.
+
Sample waypoints.json (My sailing waypoints)
diff --git a/apps/speedalt2/app.js b/apps/speedalt2/app.js
index ed16131a4..4cdf71913 100644
--- a/apps/speedalt2/app.js
+++ b/apps/speedalt2/app.js
@@ -5,8 +5,9 @@ Mike Bennett mike[at]kereru.com
1.14 : Add VMG screen
1.34 : Add bluetooth data stream for Droidscript
1.43 : Keep GPS in SuperE mode while using Droiscript screen mirroring
+1.50 : Add cfg.wptSfx one char suffix to append to waypoints.json filename. Protects speedalt2 waypoints from other apps that use the same file name for waypoints.
*/
-var v = '1.49';
+var v = '1.50';
var vDroid = '1.50'; // Required DroidScript program version
/*kalmanjs, Wouter Bulten, MIT, https://github.com/wouterbulten/kalmanjs */
@@ -209,7 +210,7 @@ function nxtWp(){
}
function loadWp() {
- var w = require("Storage").readJSON('waypoints.json')||[{name:"NONE"}];
+ var w = require("Storage").readJSON('waypoints'+cfg.wptSfx+'.json')||[{name:"NONE"}];
if (cfg.wp>=w.length) cfg.wp=0;
if (cfg.wp<0) cfg.wp = w.length-1;
savSettings();
@@ -718,6 +719,7 @@ cfg.primSpd = cfg.primSpd||0; // 1 = Spd in primary, 0 = Spd in secondary
cfg.spdFilt = cfg.spdFilt==undefined?true:cfg.spdFilt;
cfg.altFilt = cfg.altFilt==undefined?true:cfg.altFilt;
cfg.touch = cfg.touch==undefined?true:cfg.touch;
+cfg.wptSfx = cfg.wptSfx==undefined?'':cfg.wptSfx;
if ( cfg.spdFilt ) var spdFilter = new KalmanFilter({R: 0.1 , Q: 1 });
if ( cfg.altFilt ) var altFilter = new KalmanFilter({R: 0.01, Q: 2 });
diff --git a/apps/speedalt2/metadata.json b/apps/speedalt2/metadata.json
index 4ace46854..2a111af28 100644
--- a/apps/speedalt2/metadata.json
+++ b/apps/speedalt2/metadata.json
@@ -2,7 +2,7 @@
"id": "speedalt2",
"name": "GPS Adventure Sports II",
"shortName":"GPS Adv Sport II",
- "version":"1.49",
+ "version":"1.50",
"description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.",
"icon": "app.png",
"type": "app",
@@ -15,5 +15,11 @@
{"name":"speedalt2.img","url":"app-icon.js","evaluate":true},
{"name":"speedalt2.settings.js","url":"settings.js"}
],
- "data": [{"name":"speedalt2.json"}]
+ "data": [
+ {"name":"speedalt2.json"},
+ {"name":"waypoints.json"},
+ {"name":"waypoints1.json"},
+ {"name":"waypoints2.json"},
+ {"name":"waypoints3.json"}
+ ]
}
diff --git a/apps/speedalt2/settings.js b/apps/speedalt2/settings.js
index babb03061..1bdb58f9d 100644
--- a/apps/speedalt2/settings.js
+++ b/apps/speedalt2/settings.js
@@ -30,6 +30,11 @@
writeSettings();
}
+ function setSfx(s) {
+ settings.wptSfx = s;
+ writeSettings();
+ }
+
const appMenu = {
'': {'title': 'GPS Adv Sprt II'},
@@ -38,6 +43,7 @@
'Units' : function() { E.showMenu(unitsMenu); },
'Colours' : function() { E.showMenu(colMenu); },
'Kalman Filter' : function() { E.showMenu(kalMenu); },
+ 'Wpt File Suffix' : function() { E.showMenu(sfxMenu); },
'Touch' : {
value : settings.touch,
format : v => v?"On":"Off",
@@ -69,6 +75,15 @@
'Inverted' : function() { setColour(3); }
};
+ const sfxMenu = {
+ '': {'title': 'Wpt File Suffix'},
+ '< Back': function() { E.showMenu(appMenu); },
+ 'Default' : function() { setSfx(''); },
+ '1' : function() { setSfx('1'); },
+ '2' : function() { setSfx('2'); },
+ '3' : function() { setSfx('3'); }
+ };
+
const kalMenu = {
'': {'title': 'Kalman Filter'},
'< Back': function() { E.showMenu(appMenu); },
diff --git a/core b/core
index 147892754..404e98183 160000
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit 147892754eaf50c8581ebfb4d8651b9ec24aa44e
+Subproject commit 404e981834f2e8df9c505a8fab12ae12fe3bd562
diff --git a/lang/it_IT.json b/lang/it_IT.json
index 4bc36ee48..310af8580 100644
--- a/lang/it_IT.json
+++ b/lang/it_IT.json
@@ -192,7 +192,15 @@
"Notifications": "Notifiche",
"Scheduler": "Schedulatore",
"Stop": "Stop",
- "Min Font": "Dimensione minima del font"
+ "Min Font": "Dimensione minima del font",
+ "White": "Bianco",
+ "Red": "Rosso",
+ "Yellow": "Giallo",
+ "Cyan": "Ciano",
+ "Green": "Verde",
+ "Blue": "Blu",
+ "Black": "Nero",
+ "Show Week Number": "Mostra numero settimana"
},
"//2": "App-specific overrides",
"alarm": {
diff --git a/modules/ClockFace.js b/modules/ClockFace.js
index 25e2430bf..d6c3a2e66 100644
--- a/modules/ClockFace.js
+++ b/modules/ClockFace.js
@@ -66,6 +66,10 @@ ClockFace.prototype.tick = function() {
};
ClockFace.prototype.start = function() {
+ /* Some widgets want to know if we're in a clock or not (like chrono, widget clock, etc). Normally
+ .CLOCK is set by Bangle.setUI('clock') but we want to load widgets so we can check appRect and *then*
+ call setUI. see #1864 */
+ Bangle.CLOCK = 1;
Bangle.loadWidgets();
if (this.init) this.init.apply(this);
if (this._upDown) Bangle.setUI("clockupdown", d=>this._upDown.apply(this,[d]));
@@ -103,4 +107,4 @@ ClockFace.prototype.redraw = function() {
this.tick();
};
-exports = ClockFace;
\ No newline at end of file
+exports = ClockFace;
diff --git a/modules/Layout.js b/modules/Layout.js
index 019d63815..43419a397 100644
--- a/modules/Layout.js
+++ b/modules/Layout.js
@@ -65,6 +65,8 @@ Other functions:
* `layout.debug(obj)` - draw outlines for objects on screen
* `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render)
* `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render
+* `layout.setUI()` - (called when module initialised) This sets up input (buttons, touch, etc) with Bangle._setUI
+ This can be useful if you called E.showMenu/showPrompt/etc and those grabbed input away from layour
*/
@@ -73,11 +75,10 @@ function Layout(layout, options) {
// Do we have >1 physical buttons?
this.physBtns = (process.env.HWVERSION==2) ? 1 : 3;
- options = options || {};
- this.lazy = options.lazy || false;
+ this.options = options || {};
+ this.lazy = this.options.lazy || false;
- var btnList, uiSet;
- Bangle.setUI(); // remove all existing input handlers
+ var btnList;
if (process.env.HWVERSION!=2) {
// no touchscreen, find any buttons in 'layout'
btnList = [];
@@ -91,48 +92,19 @@ function Layout(layout, options) {
this.physBtns = 0;
this.buttons = btnList;
this.selectedButton = -1;
- Bangle.setUI({mode:"updown", back:options.back}, dir=>{
- var s = this.selectedButton, l=this.buttons.length;
- if (dir===undefined && this.buttons[s])
- return this.buttons[s].cb();
- if (this.buttons[s]) {
- delete this.buttons[s].selected;
- this.render(this.buttons[s]);
- }
- s = (s+l+dir) % l;
- if (this.buttons[s]) {
- this.buttons[s].selected = 1;
- this.render(this.buttons[s]);
- }
- this.selectedButton = s;
- });
- uiSet = true;
}
}
- if (options.back && !uiSet) Bangle.setUI({mode: "custom", back: options.back});
- if (options.btns) {
- var buttons = options.btns;
+ if (this.options.btns) {
+ var buttons = this.options.btns;
this.b = buttons;
if (this.physBtns >= buttons.length) {
- // Handler for button watch events
- function pressHandler(btn,e) {
- if (e.time-e.lastTime > 0.75 && this.b[btn].cbl)
- this.b[btn].cbl(e);
- else
- if (this.b[btn].cb) this.b[btn].cb(e);
- }
// enough physical buttons
let btnHeight = Math.floor(Bangle.appRect.h / this.physBtns);
- if (Bangle.btnWatches) Bangle.btnWatches.forEach(clearWatch);
- Bangle.btnWatches = [];
if (this.physBtns > 2 && buttons.length==1)
buttons.unshift({label:""}); // pad so if we have a button in the middle
while (this.physBtns > buttons.length)
buttons.push({label:""});
- if (buttons[0]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,0), BTN1, {repeat:true,edge:-1}));
- if (buttons[1]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,1), BTN2, {repeat:true,edge:-1}));
- if (buttons[2]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,2), BTN3, {repeat:true,edge:-1}));
this._l.width = g.getWidth()-8; // text width
this._l = {type:"h", filly:1, c: [
this._l,
@@ -149,19 +121,8 @@ function Layout(layout, options) {
if (btnList) btnList.push.apply(btnList, this._l.c[1].c);
}
}
- if (process.env.HWVERSION==2) {
-
- // Handler for touch events
- function touchHandler(l,e) {
- if (l.cb && e.x>=l.x && e.y>=l.y && e.x<=l.x+l.w && e.y<=l.y+l.h) {
- if (e.type==2 && l.cbl) l.cbl(e); else if (l.cb) l.cb(e);
- }
- if (l.c) l.c.forEach(n => touchHandler(n,e));
- }
- Bangle.touchHandler = (_,e)=>touchHandler(this._l,e);
- Bangle.on('touch',Bangle.touchHandler);
- }
-
+ // Link in all buttons/touchscreen/etc
+ this.setUI();
// recurse over layout doing some fixing up if needed
var ll = this;
function recurser(l) {
@@ -175,16 +136,57 @@ function Layout(layout, options) {
this.updateNeeded = true;
}
-Layout.prototype.remove = function (l) {
- if (Bangle.btnWatches) {
- Bangle.btnWatches.forEach(clearWatch);
- delete Bangle.btnWatches;
+Layout.prototype.setUI = function() {
+ Bangle.setUI(); // remove all existing input handlers
+
+ var uiSet;
+ if (this.buttons) {
+ // multiple buttons so we'll jus use back/next/select
+ Bangle.setUI({mode:"updown", back:this.options.back}, dir=>{
+ var s = this.selectedButton, l=this.buttons.length;
+ if (dir===undefined && this.buttons[s])
+ return this.buttons[s].cb();
+ if (this.buttons[s]) {
+ delete this.buttons[s].selected;
+ this.render(this.buttons[s]);
+ }
+ s = (s+l+dir) % l;
+ if (this.buttons[s]) {
+ this.buttons[s].selected = 1;
+ this.render(this.buttons[s]);
+ }
+ this.selectedButton = s;
+ });
+ uiSet = true;
}
- if (Bangle.touchHandler) {
- Bangle.removeListener("touch",Bangle.touchHandler);
- delete Bangle.touchHandler;
+ if (this.options.back && !uiSet) Bangle.setUI({mode: "custom", back: this.options.back});
+ // physical buttons -> actual applications
+ if (this.b) {
+ // Handler for button watch events
+ function pressHandler(btn,e) {
+ if (e.time-e.lastTime > 0.75 && this.b[btn].cbl)
+ this.b[btn].cbl(e);
+ else
+ if (this.b[btn].cb) this.b[btn].cb(e);
+ }
+ if (Bangle.btnWatches) Bangle.btnWatches.forEach(clearWatch);
+ Bangle.btnWatches = [];
+ if (this.b[0]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,0), BTN1, {repeat:true,edge:-1}));
+ if (this.b[1]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,1), BTN2, {repeat:true,edge:-1}));
+ if (this.b[2]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,2), BTN3, {repeat:true,edge:-1}));
}
-};
+ // Handle touch events on new Bangle.js
+ if (process.env.HWVERSION==2) {
+ function touchHandler(l,e) {
+ if (l.cb && e.x>=l.x && e.y>=l.y && e.x<=l.x+l.w && e.y<=l.y+l.h) {
+ if (e.type==2 && l.cbl) l.cbl(e); else if (l.cb) l.cb(e);
+ }
+ if (l.c) l.c.forEach(n => touchHandler(n,e));
+ }
+ Bangle.touchHandler = (_,e)=>touchHandler(this._l,e);
+ Bangle.on('touch',Bangle.touchHandler);
+ }
+}
function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
var bgCol = l.bgCol == null ? parentBg : g.toColor(l.bgCol);
diff --git a/typescript/types/globals.d.ts b/typescript/types/globals.d.ts
index 2ef52dcdf..e82c3da3d 100644
--- a/typescript/types/globals.d.ts
+++ b/typescript/types/globals.d.ts
@@ -140,7 +140,7 @@ declare const require: ((module: 'heatshrink') => {
declare const Bangle: {
// functions
- buzz: () => void;
+ buzz: (duration?: number, intensity?: number) => Promise;
drawWidgets: () => void;
isCharging: () => boolean;
// events
@@ -158,9 +158,9 @@ declare type Image = {
};
declare type GraphicsApi = {
- reset: () => void;
+ reset: () => GraphicsApi;
flip: () => void;
- setColor: (color: string) => void; // TODO we can most likely type color more usefully than this
+ setColor: (color: string) => GraphicsApi; // TODO we can most likely type color more usefully than this
drawImage: (
image: string | Image | ArrayBuffer,
xOffset: number,
@@ -169,7 +169,7 @@ declare type GraphicsApi = {
rotate?: number;
scale?: number;
}
- ) => void;
+ ) => GraphicsApi;
// TODO add more
};