Merge branch 'espruino:master' into nav_testing
commit
1dc18b40ad
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Uke Chords
|
||||
|
||||
An app that simply describes finger placements on a Ukulele to form common chords.
|
||||
|
||||
## Usage
|
||||
|
||||
Use the button to scroll through the available chords.
|
||||
|
||||
## Creator
|
||||
|
||||
NovaDawn999
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwgtqiAXWiMRDKsBolBCqcQilEoQwTiMUoMkkJGUiQwUFwVCGCcUoVEkJ5SgJ2CAQMROyIsBoVDoIXQgMSiJ2EPB4uBdwMieCMBCoIZCDoJdQAAMSUYUBLqIXBIhxCBCAJdDIZwPBTgIAEFxrOCAAIuTCwVELoQuToIuRgIuDCoUiFxjNCFwq7BC5YWBFoZdDAQIXLCwpdEogXKLYgWBXYZ9BC5SKDCwQYCkIHBC5IuFFQIYBiQhCC5JdFCoIYBBIYXJIwlEFwUUBIYXOLgIYDA4ReJC4i4BI4RODOxj/CAQIyBFwSOMoIYCagQ4BCxQXEigrBiS7CLpRHGAIMiMwYXMQoYwCSogXKU4gwCC6gwCC6ApEUoIFDRxR4Fd4QXReAgcEC5hIFLyAwJFxwwIiIWODATbDCyIYCAAQWSACY"))
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
const stringInterval = 30;
|
||||
const stringLength = 131;
|
||||
const fretHeight = 35;
|
||||
const fingerOffset = 17;
|
||||
const x = 44;
|
||||
const y = 32;
|
||||
|
||||
//chords
|
||||
const cc = [
|
||||
"C",
|
||||
"x",
|
||||
"x",
|
||||
"x",
|
||||
"33"
|
||||
];
|
||||
|
||||
const dd = [
|
||||
"D",
|
||||
"23",
|
||||
"22",
|
||||
"24",
|
||||
"x"
|
||||
];
|
||||
|
||||
const gg = [
|
||||
"G",
|
||||
"x",
|
||||
"21",
|
||||
"33",
|
||||
"22",
|
||||
];
|
||||
|
||||
const am = [
|
||||
"Am",
|
||||
"22",
|
||||
"x",
|
||||
"x",
|
||||
"x"
|
||||
];
|
||||
|
||||
const em = [
|
||||
"Em",
|
||||
"x",
|
||||
"43",
|
||||
"32",
|
||||
"21"
|
||||
];
|
||||
|
||||
const aa = [
|
||||
"A",
|
||||
"22",
|
||||
"11",
|
||||
"x",
|
||||
"x"
|
||||
];
|
||||
|
||||
const ff = [
|
||||
"F",
|
||||
"22",
|
||||
"x",
|
||||
"11",
|
||||
"x"
|
||||
];
|
||||
|
||||
var ee = [
|
||||
"E",
|
||||
"33",
|
||||
"32",
|
||||
"34",
|
||||
"11"
|
||||
];
|
||||
|
||||
var index = 0;
|
||||
var chords = [];
|
||||
|
||||
function init() {
|
||||
g.setFontAlign(0,0); // center font
|
||||
g.setFont("6x8",2); // bitmap font, 8x magnified
|
||||
chords.push(cc, dd, gg, am, em, aa, ff, ee);
|
||||
}
|
||||
|
||||
function drawBase() {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
g.drawLine(x + i * stringInterval, y, x + i * stringInterval, y + stringLength);
|
||||
g.fillRect(x- 1, y + i * fretHeight - 1, x + stringInterval * 3 + 1, y + i * fretHeight + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function drawChord(chord) {
|
||||
g.drawString(chord[0], g.getWidth() * 0.5 + 2, 18);
|
||||
for (let i = 0; i < chord.length; i++) {
|
||||
if (i === 0 || chord[i][0] === "x") {
|
||||
continue;
|
||||
}
|
||||
if (chord[i][0] === "0") {
|
||||
g.drawString(chord[i][1], x + (i - 1) * stringInterval + 1, y + fretHeight * chord[i][0], true);
|
||||
g.drawCircle(x + (i - 1) * stringInterval -1, y + fretHeight * chord[i][0], 8);
|
||||
}
|
||||
else {
|
||||
g.drawString(chord[i][1], x + (i - 1) * stringInterval + 1, y -fingerOffset + fretHeight * chord[i][0], true);
|
||||
g.drawCircle(x + (i - 1) * stringInterval -1, y -fingerOffset + fretHeight * chord[i][0], 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buttonPress() {
|
||||
setWatch(() => {
|
||||
buttonPress();
|
||||
}, BTN);
|
||||
index++;
|
||||
if (index >= chords.length) { index = 0; }
|
||||
draw();
|
||||
}
|
||||
|
||||
function draw() {
|
||||
g.clear();
|
||||
drawBase();
|
||||
drawChord(chords[index]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function main() {
|
||||
init();
|
||||
draw();
|
||||
setWatch(() => {
|
||||
buttonPress();
|
||||
}, BTN);
|
||||
}
|
||||
|
||||
main();
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
{ "id": "Uke",
|
||||
"name": "Uke Chords",
|
||||
"shortName":"Uke",
|
||||
"version":"0.01",
|
||||
"description": "Wrist mounted ukulele chords",
|
||||
"icon": "app.png",
|
||||
"tags": "uke, chords",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"Uke.app.js","url":"app.js"},
|
||||
{"name":"Uke.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Remove un-needed fonts to improve memory usage
|
||||
0.03: Tell clock widgets to hide.
|
||||
0.04: Swipe down to see widgets, step counter now just uses getHealthStatus
|
||||
0.05: Report latest HRM rather than HRM 10 minutes ago (fix #2395)
|
||||
|
|
@ -122,7 +122,7 @@ function draw() {
|
|||
g.setFontAlign(0,-1);
|
||||
g.setFont("8x12", 2);
|
||||
g.drawString(getTemperature(), 155, 132);
|
||||
g.drawString(Math.round(Bangle.getHealthStatus("last").bpm), 109, 98);
|
||||
g.drawString(Math.round(Bangle.getHealthStatus().bpm||Bangle.getHealthStatus("last").bpm), 109, 98);
|
||||
g.drawString(getSteps(), 158, 98);
|
||||
|
||||
g.setFontAlign(-1,-1);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "advcasio",
|
||||
"name": "Advanced Casio Clock",
|
||||
"shortName":"advcasio",
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.",
|
||||
"icon": "app.png",
|
||||
"tags": "clock",
|
||||
|
|
|
|||
|
|
@ -24,3 +24,5 @@
|
|||
0.23: Handle 'act' Gadgetbridge messages for realtime activity monitoring
|
||||
0.24: Handle new 'nav' event for navigation
|
||||
0.25: Added option to 'ignore' an app from the message
|
||||
0.26: Change handling of GPS status to depend on GPS events instead of connection events
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
var lastMsg; // for music messages - may not be needed now...
|
||||
var actInterval; // Realtime activity reporting interval when `act` is true
|
||||
var actHRMHandler; // For Realtime activity reporting
|
||||
var gpsState = {}; // keep information on GPS via Gadgetbridge
|
||||
|
||||
// this settings var is deleted after this executes to save memory
|
||||
var settings = require("Storage").readJSON("android.settings.json",1)||{};
|
||||
|
|
@ -137,16 +138,38 @@
|
|||
},
|
||||
// {t:"gps", lat, lon, alt, speed, course, time, satellites, hdop, externalSource:true }
|
||||
"gps": function() {
|
||||
const settings = require("Storage").readJSON("android.settings.json",1)||{};
|
||||
if (!settings.overwriteGps) return;
|
||||
// modify event for using it as Bangle GPS event
|
||||
delete event.t;
|
||||
event.satellites = NaN;
|
||||
if (!isFinite(event.satellites)) event.satellites = NaN;
|
||||
if (!isFinite(event.course)) event.course = NaN;
|
||||
event.fix = 1;
|
||||
if (event.long!==undefined) { // for earlier Gadgetbridge implementations
|
||||
event.lon = event.long;
|
||||
delete event.long;
|
||||
}
|
||||
if (event.time){
|
||||
event.time = new Date(event.time);
|
||||
}
|
||||
|
||||
if (!gpsState.lastGPSEvent) {
|
||||
// this is the first event, save time of arrival and deactivate internal GPS
|
||||
Bangle.moveGPSPower(0);
|
||||
} else {
|
||||
// this is the second event, store the intervall for expecting the next GPS event
|
||||
gpsState.interval = Date.now() - gpsState.lastGPSEvent;
|
||||
}
|
||||
gpsState.lastGPSEvent = Date.now();
|
||||
// in any case, cleanup the GPS state in case no new events arrive
|
||||
if (gpsState.timeoutGPS) clearTimeout(gpsState.timeoutGPS);
|
||||
gpsState.timeoutGPS = setTimeout(()=>{
|
||||
// reset state
|
||||
gpsState.lastGPSEvent = undefined;
|
||||
gpsState.timeoutGPS = undefined;
|
||||
gpsState.interval = undefined;
|
||||
// did not get an expected GPS event but have GPS clients, switch back to internal GPS
|
||||
if (Bangle.isGPSOn()) Bangle.moveGPSPower(1);
|
||||
}, (gpsState.interval || 10000) + 1000);
|
||||
Bangle.emit('GPS', event);
|
||||
},
|
||||
// {t:"is_gps_active"}
|
||||
|
|
@ -258,10 +281,9 @@
|
|||
if (isFinite(msg.id)) return gbSend({ t: "notify", n:"MUTE", id: msg.id });
|
||||
};
|
||||
// GPS overwrite logic
|
||||
if (settings.overwriteGps) { // if the overwrite option is set../
|
||||
if (settings.overwriteGps) { // if the overwrite option is set..
|
||||
const origSetGPSPower = Bangle.setGPSPower;
|
||||
// migrate all GPS clients to the other variant on connection events
|
||||
let handleConnection = (state) => {
|
||||
Bangle.moveGPSPower = (state) => {
|
||||
if (Bangle.isGPSOn()){
|
||||
let orig = Bangle._PWR.GPS;
|
||||
delete Bangle._PWR.GPS;
|
||||
|
|
@ -269,39 +291,45 @@
|
|||
Bangle._PWR.GPS = orig;
|
||||
}
|
||||
};
|
||||
NRF.on('connect', ()=>{handleConnection(0);});
|
||||
NRF.on('disconnect', ()=>{handleConnection(1);});
|
||||
|
||||
// Work around Serial1 for GPS not working when connected to something
|
||||
// work around Serial1 for GPS not working when connected to something
|
||||
let serialTimeout;
|
||||
let wrap = function(f){
|
||||
return (s)=>{
|
||||
if (serialTimeout) clearTimeout(serialTimeout);
|
||||
handleConnection(1);
|
||||
origSetGPSPower(1, "androidgpsserial");
|
||||
f(s);
|
||||
serialTimeout = setTimeout(()=>{
|
||||
serialTimeout = undefined;
|
||||
if (NRF.getSecurityStatus().connected) handleConnection(0);
|
||||
origSetGPSPower(0, "androidgpsserial");
|
||||
}, 10000);
|
||||
};
|
||||
};
|
||||
Serial1.println = wrap(Serial1.println);
|
||||
Serial1.write = wrap(Serial1.write);
|
||||
|
||||
// Replace set GPS power logic to suppress activation of gps (and instead request it from the phone)
|
||||
Bangle.setGPSPower = (isOn, appID) => {
|
||||
// if not connected use internal GPS power function
|
||||
if (!NRF.getSecurityStatus().connected) return origSetGPSPower(isOn, appID);
|
||||
// replace set GPS power logic to suppress activation of gps (and instead request it from the phone)
|
||||
Bangle.setGPSPower = ((isOn, appID) => {
|
||||
let pwr;
|
||||
if (!this.lastGPSEvent){
|
||||
// use internal GPS power function if no gps event has arrived from GadgetBridge
|
||||
pwr = origSetGPSPower(isOn, appID);
|
||||
} else {
|
||||
// we are currently expecting the next GPS event from GadgetBridge, keep track of GPS state per app
|
||||
if (!Bangle._PWR) Bangle._PWR={};
|
||||
if (!Bangle._PWR.GPS) Bangle._PWR.GPS=[];
|
||||
if (!appID) appID="?";
|
||||
if (isOn && !Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.push(appID);
|
||||
if (!isOn && Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.splice(Bangle._PWR.GPS.indexOf(appID),1);
|
||||
let pwr = Bangle._PWR.GPS.length>0;
|
||||
pwr = Bangle._PWR.GPS.length>0;
|
||||
// stop internal GPS, no clients left
|
||||
if (!pwr) origSetGPSPower(0);
|
||||
}
|
||||
// always update Gadgetbridge on current power state
|
||||
gbSend({ t: "gps_power", status: pwr });
|
||||
return pwr;
|
||||
};
|
||||
// Allow checking for GPS via GadgetBridge
|
||||
}).bind(gpsState);
|
||||
// allow checking for GPS via GadgetBridge
|
||||
Bangle.isGPSOn = () => {
|
||||
return !!(Bangle._PWR && Bangle._PWR.GPS && Bangle._PWR.GPS.length>0);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "android",
|
||||
"name": "Android Integration",
|
||||
"shortName": "Android",
|
||||
"version": "0.25",
|
||||
"version": "0.26",
|
||||
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||
|
|
|
|||
|
|
@ -28,11 +28,12 @@ let sec = {
|
|||
};
|
||||
|
||||
NRF.getSecurityStatus = () => sec;
|
||||
// add an empty starting point to make the asserts work
|
||||
Bangle._PWR={};
|
||||
|
||||
setTimeout(() => {
|
||||
// add an empty starting point to make the asserts work
|
||||
Bangle._PWR={};
|
||||
let teststeps = [];
|
||||
|
||||
teststeps.push(()=>{
|
||||
print("Not connected, should use internal GPS");
|
||||
assertTrue(!NRF.getSecurityStatus().connected, "Not connected");
|
||||
|
||||
|
|
@ -51,6 +52,9 @@ setTimeout(() => {
|
|||
assertFalse(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
|
||||
});
|
||||
|
||||
teststeps.push(()=>{
|
||||
print("Connected, should use GB GPS");
|
||||
sec.connected = true;
|
||||
|
||||
|
|
@ -60,67 +64,90 @@ setTimeout(() => {
|
|||
assertFalse(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
|
||||
|
||||
print("Internal GPS stays on until the first GadgetBridge event arrives");
|
||||
assertTrue(Bangle.setGPSPower(1, "test"), "Switch GPS on");
|
||||
|
||||
assertNotEmpty(Bangle._PWR.GPS, "GPS");
|
||||
assertTrue(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
|
||||
assertFalse(Bangle.setGPSPower(0, "test"), "Switch GPS off");
|
||||
|
||||
assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS");
|
||||
assertFalse(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
|
||||
print("Connected, then reconnect cycle");
|
||||
sec.connected = true;
|
||||
|
||||
assertTrue(NRF.getSecurityStatus().connected, "Connected");
|
||||
|
||||
assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS");
|
||||
assertFalse(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
|
||||
assertTrue(Bangle.setGPSPower(1, "test"), "Switch GPS on");
|
||||
|
||||
assertNotEmpty(Bangle._PWR.GPS, "GPS");
|
||||
assertTrue(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
|
||||
NRF.emit("disconnect", {});
|
||||
print("disconnect");
|
||||
sec.connected = false;
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
assertNotEmpty(Bangle._PWR.GPS, "GPS");
|
||||
assertTrue(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertTrue(internalOn(), "Internal GPS on");
|
||||
|
||||
print("connect");
|
||||
sec.connected = true;
|
||||
NRF.emit("connect", {});
|
||||
print("Send minimal GadgetBridge GPS event to trigger switch");
|
||||
GB({t:"gps"});
|
||||
});
|
||||
|
||||
teststeps.push(()=>{
|
||||
print("GPS should be on, internal off");
|
||||
|
||||
setTimeout(() => {
|
||||
assertNotEmpty(Bangle._PWR.GPS, "GPS");
|
||||
assertTrue(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
});
|
||||
|
||||
teststeps.push(()=>{
|
||||
print("Switching GPS off turns both GadgetBridge as well as internal off");
|
||||
assertFalse(Bangle.setGPSPower(0, "test"), "Switch GPS off");
|
||||
|
||||
assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS");
|
||||
assertFalse(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
print("Test disconnect without gps on");
|
||||
teststeps.push(()=>{
|
||||
print("Wait for all timeouts to run out");
|
||||
return 12000;
|
||||
});
|
||||
|
||||
assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS");
|
||||
assertFalse(Bangle.isGPSOn(), "isGPSOn");
|
||||
teststeps.push(()=>{
|
||||
print("Check auto switch when no GPS event arrives");
|
||||
|
||||
assertTrue(Bangle.setGPSPower(1, "test"), "Switch GPS on");
|
||||
|
||||
assertNotEmpty(Bangle._PWR.GPS, "GPS");
|
||||
assertTrue(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertTrue(internalOn(), "Internal GPS on");
|
||||
|
||||
print("Send minimal GadgetBridge GPS event to trigger switch");
|
||||
GB({t:"gps"});
|
||||
|
||||
print("Internal should be switched off now");
|
||||
|
||||
assertNotEmpty(Bangle._PWR.GPS, "GPS");
|
||||
assertTrue(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertFalse(internalOn(), "Internal GPS off");
|
||||
|
||||
//wait on next test
|
||||
return 12000;
|
||||
});
|
||||
|
||||
teststeps.push(()=>{
|
||||
print("Check state and disable GPS, internal should be on");
|
||||
|
||||
assertNotEmpty(Bangle._PWR.GPS, "GPS");
|
||||
assertTrue(Bangle.isGPSOn(), "isGPSOn");
|
||||
assertTrue(internalOn(), "Internal GPS on");
|
||||
|
||||
assertFalse(Bangle.setGPSPower(0, "test"), "Switch GPS off");
|
||||
});
|
||||
|
||||
teststeps.push(()=>{
|
||||
print("Result Overall is " + (result ? "OK" : "FAIL"));
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
let wrap = (functions) => {
|
||||
if (functions.length > 0) {
|
||||
setTimeout(()=>{
|
||||
let waitingTime = functions.shift()();
|
||||
if (waitingTime){
|
||||
print("WAITING: ", waitingTime);
|
||||
setTimeout(()=>{wrap(functions);}, waitingTime);
|
||||
} else
|
||||
wrap(functions);
|
||||
},0);
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(()=>{
|
||||
wrap(teststeps);
|
||||
}, 5000);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@
|
|||
0.10: Show daily steps, heartrate and the temperature if weather information is available.
|
||||
0.11: Tell clock widgets to hide.
|
||||
0.12: Swipe down to see widgets, step counter now just uses getHealthStatus
|
||||
0.13: Report latest HRM rather than HRM 10 minutes ago (fix #2395)
|
||||
|
|
@ -121,7 +121,7 @@ function draw() {
|
|||
g.setFontAlign(0,-1);
|
||||
g.setFont("8x12", 2);
|
||||
g.drawString(getTemperature(), 155, 132);
|
||||
g.drawString(Math.round(Bangle.getHealthStatus("last").bpm), 109, 98);
|
||||
g.drawString(Math.round(Bangle.getHealthStatus().bpm||Bangle.getHealthStatus("last").bpm), 109, 98);
|
||||
g.drawString(getSteps(), 158, 98);
|
||||
|
||||
g.setFontAlign(-1,-1);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"description": "Animated Clock with Space Cassio Watch Style",
|
||||
"screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }],
|
||||
"icon": "app.png",
|
||||
"version": "0.12",
|
||||
"version": "0.13",
|
||||
"type": "clock",
|
||||
"tags": "clock, weather, cassio, retro",
|
||||
"supports": ["BANGLEJS2"],
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# Charge LCD rotation
|
||||
|
||||
This simple app is for handling all types of charging cradles i.e.:
|
||||
- [Official Bangle.js 2 dock](https://shop.espruino.com/banglejs2-dock)
|
||||
- [Many more you can 3d print](https://www.thingiverse.com/search?q=banglejs+dock&page=1&type=things&sort=relevant)
|
||||
|
||||
## Setup
|
||||
In app settings set desired rotation.
|
||||
App will swap screen rotation when charged and return to default one (you can change this in settings app) when undocked.
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
(() => {
|
||||
const chargingRotation = 0 | require('Storage').readJSON("chargerot.settings.json").rotate;
|
||||
const defaultRotation = 0 | require('Storage').readJSON("setting.json").rotate;
|
||||
if (Bangle.isCharging()) g.setRotation(chargingRotation&3,chargingRotation>>2).clear();
|
||||
Bangle.on('charging', (charging) => {
|
||||
if (charging) {
|
||||
g.setRotation(chargingRotation&3,chargingRotation>>2).clear();
|
||||
Bangle.showClock();
|
||||
} else {
|
||||
g.setRotation(defaultRotation&3,defaultRotation>>2).clear();
|
||||
Bangle.showClock();
|
||||
}
|
||||
});
|
||||
})();
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"id": "chargerot",
|
||||
"name": "Charge LCD rotation",
|
||||
"version": "0.01",
|
||||
"description": "When charging, this app can rotate your screen and revert it when unplugged. Made for all sort of cradles.",
|
||||
"icon": "icon.png",
|
||||
"tags": "battery",
|
||||
"readme": "README.md",
|
||||
"type": "bootloader",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"chargerot.boot.js","url":"boot.js"},
|
||||
{"name":"chargerot.settings.js","url":"settings.js"}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
(function(back) {
|
||||
var rotNames = [/*LANG*/"No",/*LANG*/"Rotate CW",/*LANG*/"Left Handed",/*LANG*/"Rotate CCW",/*LANG*/"Mirror"];
|
||||
var FILE = "chargerot.settings.json";
|
||||
var appSettings = Object.assign({
|
||||
rotate: 0,
|
||||
}, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, appSettings);
|
||||
}
|
||||
|
||||
|
||||
E.showMenu({
|
||||
"" : { "title" : "Charging rotation" },
|
||||
"< Back" : () => back(),
|
||||
'Rotate': {
|
||||
value: 0|appSettings.rotate,
|
||||
min: 0,
|
||||
max: rotNames.length-1,
|
||||
format: v=> rotNames[v],
|
||||
onchange: v => {
|
||||
appSettings.rotate = 0 | v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
});
|
||||
// If(true) big();
|
||||
})
|
||||
|
|
@ -100,6 +100,7 @@ function onInit(device) {
|
|||
if (crc==2560806221) version = "2v15";
|
||||
if (crc==2886730689) version = "2v16";
|
||||
if (crc==156320890) version = "2v17";
|
||||
if (crc==4012421318) version = "2v18";
|
||||
if (!ok) {
|
||||
version += `(⚠ update required)`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,3 +24,4 @@
|
|||
0.24: Add ability to disable alarm functionality.
|
||||
0.25: Add more colors to the settings and add the ability to disable the data charts+Markup.
|
||||
0.26: Use widget_utils.
|
||||
0.27: Report latest HRM rather than HRM 10 minutes ago (fix #2395)
|
||||
|
|
@ -240,7 +240,7 @@ function _drawData(key, y, c){
|
|||
value = E.getAnalogVRef().toFixed(2) + "V";
|
||||
|
||||
} else if(key == "HRM"){
|
||||
value = Math.round(Bangle.getHealthStatus("last").bpm);
|
||||
value = Math.round(Bangle.getHealthStatus().bpm||Bangle.getHealthStatus("last").bpm);
|
||||
|
||||
} else if (key == "TEMP"){
|
||||
var weather = getWeather();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"name": "LCARS Clock",
|
||||
"shortName":"LCARS",
|
||||
"icon": "lcars.png",
|
||||
"version":"0.26",
|
||||
"version":"0.27",
|
||||
"readme": "README.md",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"description": "Library Computer Access Retrieval System (LCARS) clock.",
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Tell clock widgets to hide.
|
||||
0.03: Swipe down to see widgets
|
||||
Support for fast loading
|
||||
0.04: Localisation request: added Miles and AM/PM
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "pebbled",
|
||||
"name": "Pebble Clock with distance",
|
||||
"shortName": "Pebble + distance",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).",
|
||||
"readme": "README.md",
|
||||
"icon": "pebbled.png",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,15 @@ let loadSettings = function() {
|
|||
settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'bg': '#0f0', 'color': 'Green', 'avStep': 0.75};
|
||||
};
|
||||
|
||||
let tConv24 = function(time24) {
|
||||
var ts = time24;
|
||||
var H = +ts.substr(0, 2);
|
||||
var h = (H % 12) || 12;
|
||||
h = (h < 10)?("0"+h):h;
|
||||
ts = h + ts.substr(2, 3);
|
||||
return ts;
|
||||
}
|
||||
|
||||
const img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4A/AE8AAAoeXoAfeDQUBmcyD7A+Dh///8QD649CiAfaHwUvD4sEHy0DDYIfEICg+Cn4fHICY+DD4nxcgojOHwgfEIAYfRCIQaDD4ZAFD5r7DH4//kAfRCIZ/GAAnwD5p9DX44fTHgYSBf4ofVDAQEBl4fFUAgfOXoQzBgIfFBAIfPP4RAEAoYAB+cRiK/SG4h/WIBAfXIA7CBAAswD55AHn6fUIBMCD65AHl4gCmcziAfQQJqfQQJpiDgk0IDXxQLRAEECaBM+QgRYRYgUIA0CD4ggSQJiDCiAKBICszAAswD55AHABKBVD7BAFABIqBD5pAFABPxD55AOD6BADiIAJQAyxLABwf/gaAPAH4A/AH4ARA=="));
|
||||
|
||||
const h = g.getHeight();
|
||||
|
|
@ -30,16 +39,19 @@ let batteryWarning = false;
|
|||
let draw = function() {
|
||||
let date = new Date();
|
||||
let da = date.toString().split(" ");
|
||||
let timeStr = da[4].substr(0,5);
|
||||
let timeStr = settings.localization === "US" ? tConv24(da[4].substr(0,5)) : da[4].substr(0,5);
|
||||
const t = 6;
|
||||
let stps = Bangle.getHealthStatus("day").steps;
|
||||
const distInKm = (stps / 1000 * settings.avStep).toFixed(2);
|
||||
const distance = settings.localization === "US" ? (distInKm / 1.609).toFixed(2) : distInKm;
|
||||
const distanceStr = settings.localization === "US" ? distance + ' MI' : distance + ' KM';
|
||||
|
||||
// turn the warning on once we have dipped below 15%
|
||||
if (E.getBattery() < 15)
|
||||
// turn the warning on once we have dipped below 25%
|
||||
if (E.getBattery() < 25)
|
||||
batteryWarning = true;
|
||||
|
||||
// turn the warning off once we have dipped above 20%
|
||||
if (E.getBattery() > 20)
|
||||
// turn the warning off once we have dipped above 30%
|
||||
if (E.getBattery() > 30)
|
||||
batteryWarning = false;
|
||||
|
||||
g.reset();
|
||||
|
|
@ -88,7 +100,7 @@ let draw = function() {
|
|||
g.setColor('#fff'); // white on blue or red best contrast
|
||||
else
|
||||
g.setColor('#000'); // otherwise black regardless of theme
|
||||
g.drawString((stps / 1000 * settings.avStep).toFixed(2) + ' KM', w/2, ha + 107);
|
||||
g.drawString(distanceStr, w/2, ha + 107);
|
||||
|
||||
// queue next draw
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
const SETTINGS_FILE = "pebbleDistance.json";
|
||||
|
||||
// initialize with default settings...
|
||||
let s = {'bg': '#0f0', 'color': 'Green', 'avStep': 0.75};
|
||||
let s = {'bg': '#0f0', 'color': 'Green', 'avStep': 0.75, 'localization': 'World'};
|
||||
|
||||
// ...and overwrite them with any saved values
|
||||
// This way saved values are preserved if a new version adds more settings
|
||||
|
|
@ -20,9 +20,10 @@
|
|||
|
||||
var color_options = ['Green','Orange','Cyan','Purple','Red','Blue'];
|
||||
var bg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f'];
|
||||
var local_options = ['World', 'US'];
|
||||
|
||||
E.showMenu({
|
||||
'': { 'title': 'Pebble Clock' },
|
||||
'': { 'title': 'PebbleD Clock' },
|
||||
'< Back': back,
|
||||
'Color': {
|
||||
value: 0 | color_options.indexOf(s.color),
|
||||
|
|
@ -43,6 +44,15 @@
|
|||
s.avStep = v;
|
||||
save();
|
||||
}
|
||||
},
|
||||
'Localization': {
|
||||
value: 0 | local_options.indexOf(s.localization),
|
||||
min: 0, max: 1,
|
||||
format: v => local_options[v],
|
||||
onchange: v => {
|
||||
s.localization = local_options[v];
|
||||
save();
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Trim old entries from the popcon app cache
|
||||
0.03: Avoid polluting global scope
|
||||
0.04: Add settings app for resetting popcon
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@
|
|||
trimCache(cache);
|
||||
require("Storage").writeJSON("popcon.cache.json", cache);
|
||||
if (orderChanged) {
|
||||
var info = oldRead("popcon.info", true);
|
||||
var info = oldRead("popconlaunch.info", true);
|
||||
info.cacheBuster = !info.cacheBuster;
|
||||
require("Storage").writeJSON("popcon.info", info);
|
||||
require("Storage").writeJSON("popconlaunch.info", info);
|
||||
}
|
||||
};
|
||||
var sortCache = function () {
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ const saveCache = (cache: Cache, orderChanged: boolean) => {
|
|||
require("Storage").writeJSON("popcon.cache.json", cache);
|
||||
if(orderChanged){
|
||||
// ensure launchers reload their caches:
|
||||
const info: AppInfo & { cacheBuster?: boolean } = oldRead("popcon.info", true);
|
||||
const info: AppInfo & { cacheBuster?: boolean } = oldRead("popconlaunch.info", true);
|
||||
info.cacheBuster = !info.cacheBuster;
|
||||
require("Storage").writeJSON("popcon.info", info);
|
||||
require("Storage").writeJSON("popconlaunch.info", info);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,16 +2,17 @@
|
|||
"id": "popconlaunch",
|
||||
"name": "Popcon Launcher",
|
||||
"shortName": "Popcon",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Launcher modification - your launchers will display your favourite (popular) apps first. Overrides `readJSON`, may slow down your watch",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
"type": "bootloader",
|
||||
"tags": "tool,system,launcher",
|
||||
"tags": "tool,system",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"popcon.boot.js","url":"boot.js"},
|
||||
{"name":"popcon.img","url":"icon.js","evaluate":true}
|
||||
{"name":"popcon.img","url":"icon.js","evaluate":true},
|
||||
{"name":"popcon.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name":"popcon.cache.json"}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
(function (back) {
|
||||
var menu = {
|
||||
'': { 'title': 'Popcon' },
|
||||
'< Back': back,
|
||||
'Reset app popularities': function () {
|
||||
var S = require("Storage");
|
||||
S.erase("popcon.cache.json");
|
||||
var info = S.readJSON("popconlaunch.info", true);
|
||||
info.cacheBuster = !info.cacheBuster;
|
||||
S.writeJSON("popconlaunch.info", info);
|
||||
E.showMessage("Popcon reset", "Done");
|
||||
},
|
||||
};
|
||||
E.showMenu(menu);
|
||||
});
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
(function(back) {
|
||||
const menu = {
|
||||
'': {'title': 'Popcon'},
|
||||
'< Back': back,
|
||||
'Reset app popularities': () => {
|
||||
const S = require("Storage");
|
||||
S.erase("popcon.cache.json");
|
||||
|
||||
const info: AppInfo & { cacheBuster?: boolean } = S.readJSON("popconlaunch.info", true);
|
||||
info.cacheBuster = !info.cacheBuster;
|
||||
S.writeJSON("popconlaunch.info", info);
|
||||
|
||||
E.showMessage("Popcon reset", "Done");
|
||||
},
|
||||
};
|
||||
|
||||
E.showMenu(menu);
|
||||
}) satisfies SettingsFunc
|
||||
Loading…
Reference in New Issue