Merge branch 'espruino:master' into master
|
@ -1,4 +1,5 @@
|
|||
(() => {
|
||||
BANGLEJS2 = process.env.HWVERSION==2;
|
||||
Bangle.setLCDTimeout(0);
|
||||
let intervalID;
|
||||
let settings = require("Storage").readJSON("ballmaze.json",true) || {};
|
||||
|
@ -6,7 +7,9 @@
|
|||
// density, elasticity of bounces, "drag coefficient"
|
||||
const rho = 100, e = 0.3, C = 0.01;
|
||||
// screen width & height in pixels
|
||||
const sW = 240, sH = 160;
|
||||
const sW = g.getWidth();
|
||||
const sH = g.getHeight()*2/3;
|
||||
const bgColour ="#f00"; // only for Bangle.js 2
|
||||
// gravity constant (lowercase was already taken)
|
||||
const G = 9.80665;
|
||||
|
||||
|
@ -17,14 +20,16 @@
|
|||
// The play area is 240x160, sizes are the ball radius, so we can use common
|
||||
// denominators of 120x80 to get square rooms
|
||||
// Reverse the order to show the easiest on top of the menu
|
||||
const sizes = [1, 2, 4, 5, 8, 10, 16, 20, 40].reverse(),
|
||||
// even size 1 actually works, but larger mazes take forever to generate
|
||||
minSize = 4, defaultSize = 10;
|
||||
const sizeNames = {
|
||||
1: "Insane", 2: "Gigantic", 4: "Enormous", 5: "Huge", 8: "Large",
|
||||
10: "Medium", 16: "Small", 20: "Tiny", 40: "Trivial",
|
||||
};
|
||||
|
||||
// even size 1 actually works, but larger mazes take forever to generate
|
||||
if (!BANGLEJS2) {
|
||||
const sizes = [1, 2, 4, 5, 8, 10, 16, 20, 40].reverse(), minSize = 4, defaultSize = 10;
|
||||
} else {
|
||||
const sizes = [1, 2, 4, 5, 8, 10, 16, 20 ].reverse(), minSize = 4, defaultSize = 10;
|
||||
}
|
||||
/**
|
||||
* Draw something to all screen buffers
|
||||
* @param draw {function} Callback which performs the drawing
|
||||
|
@ -45,17 +50,17 @@
|
|||
|
||||
// use unbuffered graphics for UI stuff
|
||||
function showMessage(message, title) {
|
||||
Bangle.setLCDMode();
|
||||
if (!BANGLEJS2) Bangle.setLCDMode();
|
||||
return E.showMessage(message, title);
|
||||
}
|
||||
|
||||
function showPrompt(prompt, options) {
|
||||
Bangle.setLCDMode();
|
||||
if (!BANGLEJS2) Bangle.setLCDMode();
|
||||
return E.showPrompt(prompt, options);
|
||||
}
|
||||
|
||||
function showMenu(menu) {
|
||||
Bangle.setLCDMode();
|
||||
if (!BANGLEJS2) Bangle.setLCDMode();
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
|
@ -105,7 +110,7 @@
|
|||
generateMaze(); // this shows unbuffered progress messages
|
||||
if (settings.cheat && r>1) findRoute(); // not enough memory for r==1 :-(
|
||||
|
||||
Bangle.setLCDMode("doublebuffered");
|
||||
if (!BANGLEJS2) Bangle.setLCDMode("doublebuffered");
|
||||
clearAll();
|
||||
drawAll(drawMaze);
|
||||
intervalID = setInterval(tick, 100);
|
||||
|
@ -307,6 +312,7 @@
|
|||
const range = {top: 0, left: 0, bottom: rows, right: cols};
|
||||
const w = sW/cols, h = sH/rows;
|
||||
g.clear();
|
||||
if (BANGLEJS2) g.setBgColor(bgColour);
|
||||
g.setColor(0.76, 0.60, 0.42);
|
||||
for(let row = range.top; row<=range.bottom; row++) {
|
||||
for(let col = range.left; col<=range.right; col++) {
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: Initial version of Balltastic released! Happy!
|
||||
0.02: Set LCD timeout for Espruino 2v10 compatibility
|
||||
0.03: Now also works on Bangle.js 2
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
BANGLEJS2 = process.env.HWVERSION==2;
|
||||
Bangle.setLCDBrightness(1);
|
||||
Bangle.setLCDMode("doublebuffered");
|
||||
if (!BANGLEJS2) Bangle.setLCDMode("doublebuffered");
|
||||
Bangle.setLCDTimeout(0);
|
||||
|
||||
let points = 0;
|
||||
let level = 1;
|
||||
let levelSpeedStart = 0.8;
|
||||
let nextLevelPoints = 20;
|
||||
let nextLevelPoints = 10;
|
||||
let levelSpeedFactor = 0.2;
|
||||
let counterWidth = 10;
|
||||
let gWidth = g.getWidth() - counterWidth;
|
||||
|
@ -81,12 +82,23 @@ function drawLevelText() {
|
|||
g.setColor("#26b6c7");
|
||||
g.setFontAlign(0, 0);
|
||||
g.setFont("4x6", 5);
|
||||
g.drawString("Level " + level, 120, 80);
|
||||
g.drawString("Level " + level, g.getWidth()/2, g.getHeight()/2);
|
||||
}
|
||||
|
||||
function drawPointsText() {
|
||||
g.setColor("#26b6c7");
|
||||
g.setFontAlign(0, 0);
|
||||
g.setFont("4x6", 2);
|
||||
g.drawString("Points " + points, g.getWidth()/2, g.getHeight()-20);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
//bg
|
||||
if (!BANGLEJS2) {
|
||||
g.setColor("#71c6cf");
|
||||
} else {
|
||||
g.setColor("#002000");
|
||||
}
|
||||
g.fillRect(0, 0, g.getWidth(), g.getHeight());
|
||||
|
||||
//counter
|
||||
|
@ -94,6 +106,7 @@ function draw() {
|
|||
|
||||
//draw level
|
||||
drawLevelText();
|
||||
drawPointsText();
|
||||
|
||||
//dot
|
||||
g.setColor("#ff0000");
|
||||
|
@ -152,7 +165,7 @@ function count() {
|
|||
if (counter <= 0) {
|
||||
running = false;
|
||||
clearInterval(drawInterval);
|
||||
setTimeout(function(){ E.showMessage("Press Button 1\nto restart.", "Gameover!");},50);
|
||||
setTimeout(function(){ E.showMessage("Press Button 1\nto restart.", "Game over!");},50);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"id": "balltastic",
|
||||
"name": "Balltastic",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Simple but fun ball eats dots game.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"bangle2-balltastic-screenshot.png"}],
|
||||
"type": "app",
|
||||
"tags": "game,fun",
|
||||
"supports": ["BANGLEJS"],
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"balltastic.app.js","url":"app.js"},
|
||||
{"name":"balltastic.img","url":"app-icon.js","evaluate":true}
|
||||
|
|
|
@ -11,3 +11,4 @@
|
|||
Support to choose between humidity and wind speed for weather circle progress
|
||||
Support to show time and progress until next sunrise or sunset
|
||||
Load daily steps from Bangle health if available
|
||||
0.07: Allow configuration of minimal heart rate confidence
|
||||
|
|
|
@ -29,6 +29,7 @@ function loadSettings() {
|
|||
settings = storage.readJSON("circlesclock.json", 1) || {
|
||||
'minHR': 40,
|
||||
'maxHR': 200,
|
||||
'confidence': 0,
|
||||
'stepGoal': 10000,
|
||||
'stepDistanceGoal': 8000,
|
||||
'stepLength': 0.8,
|
||||
|
@ -599,10 +600,12 @@ Bangle.on('lock', function(isLocked) {
|
|||
|
||||
Bangle.on('HRM', function(hrm) {
|
||||
if (isCircleEnabled("hr")) {
|
||||
if (hrm.confidence >= (settings.confidence || 0)) {
|
||||
hrtValue = hrm.bpm;
|
||||
if (Bangle.isLCDOn())
|
||||
drawHeartRate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "circlesclock",
|
||||
"name": "Circles clock",
|
||||
"shortName":"Circles clock",
|
||||
"version":"0.06",
|
||||
"version":"0.07",
|
||||
"description": "A clock with circles for different data at the bottom in a probably familiar style",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}],
|
||||
|
|
|
@ -35,6 +35,16 @@
|
|||
},
|
||||
onchange: x => save('maxHR', x),
|
||||
},
|
||||
'hr confidence': {
|
||||
value: "confidence" in settings ? settings.confidence : 0,
|
||||
min: 0,
|
||||
max : 100,
|
||||
step: 10,
|
||||
format: x => {
|
||||
return x;
|
||||
},
|
||||
onchange: x => save('confidence', x),
|
||||
},
|
||||
'step goal': {
|
||||
value: "stepGoal" in settings ? settings.stepGoal : 10000,
|
||||
min: 2000,
|
||||
|
|
|
@ -24,12 +24,7 @@ if (!settings) resetSettings();
|
|||
function showMenu() {
|
||||
const datemenu = {
|
||||
'': {
|
||||
'title': 'Set Date',
|
||||
'predraw': function() {
|
||||
datemenu.Day.value = settings.day;
|
||||
datemenu.Month.value = settings.month;
|
||||
datemenu.Year.value = settings.year;
|
||||
}
|
||||
'title': 'Set Date'
|
||||
},
|
||||
'Day': {
|
||||
value: settings.day,
|
||||
|
@ -65,4 +60,3 @@ function showMenu() {
|
|||
}
|
||||
|
||||
showMenu();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"description": "Simple file manager, allows user to examine watch storage and display, load or delete individual files",
|
||||
"icon": "icons8-filing-cabinet-48.png",
|
||||
"tags": "tools",
|
||||
"supports": ["BANGLEJS"],
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"fileman.app.js","url":"fileman.app.js"},
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
0.06: Move the next strike time to the first row of display
|
||||
0.07: Change the boot function to avoid reloading the entire watch
|
||||
0.08: Default to no strikes. Fix file-not-found issue during the first boot. Add data file.
|
||||
0.09: Add some customisation options
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const storage = require('Storage');
|
||||
var settings = storage.readJSON('hourstrike.json', 1);
|
||||
const chimes = ["Buzz", "Beep"];
|
||||
|
||||
function updateSettings() {
|
||||
storage.write('hourstrike.json', settings);
|
||||
|
@ -26,6 +27,12 @@ function showMainMenu() {
|
|||
mainmenu.Strength = {
|
||||
value: settings.vlevel*10, min: 1, max: 10, format: v=>v/10,
|
||||
onchange: v=> {settings.vlevel = v/10; updateSettings();}};
|
||||
mainmenu.Strikecount = {
|
||||
value: settings.scount, min: 1, max: 2, format: v=>v,
|
||||
onchange: v=> {settings.scount = v; updateSettings();}};
|
||||
mainmenu.Chimetype = {
|
||||
value: settings.buzzOrBeep, min: 0, max: 1, format: v => chimes[v],
|
||||
onchange: v=> {settings.buzzOrBeep = v; updateSettings();}};
|
||||
mainmenu['< Back'] = ()=>load();
|
||||
return E.showMenu(mainmenu);
|
||||
}
|
||||
|
|
|
@ -30,9 +30,23 @@
|
|||
}
|
||||
function strike_func () {
|
||||
var setting = require('Storage').readJSON('hourstrike.json',1)||[];
|
||||
if (0 == setting.buzzOrBeep) {
|
||||
if (2 == setting.scount) {
|
||||
Bangle.buzz(200, setting.vlevel||0.5)
|
||||
.then(() => new Promise(resolve => setTimeout(resolve,200)))
|
||||
.then(() => Bangle.buzz(200, setting.vlevel||0.5));
|
||||
} else {
|
||||
Bangle.buzz(200, setting.vlevel||0.5);
|
||||
}
|
||||
} else {
|
||||
if (2 == setting.scount) {
|
||||
Bangle.beep(200)
|
||||
.then(() => new Promise(resolve => setTimeout(resolve,100)))
|
||||
.then(() => Bangle.beep(300));
|
||||
} else {
|
||||
Bangle.beep(200);
|
||||
}
|
||||
}
|
||||
setup();
|
||||
}
|
||||
setup();
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"interval":-1,"start":9,"end":21,"vlevel":0.5,"next_hour":-1,"next_minute":-1}
|
||||
{"interval":-1,"start":9,"end":21,"vlevel":0.5,"scount":2,"buzzOrBeep":0,"next_hour":-1,"next_minute":-1}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "hourstrike",
|
||||
"name": "Hour Strike",
|
||||
"shortName": "Hour Strike",
|
||||
"version": "0.08",
|
||||
"version": "0.09",
|
||||
"description": "Strike the clock on the hour. A great tool to remind you an hour has passed!",
|
||||
"icon": "app-icon.png",
|
||||
"tags": "tool,alarm",
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Add the option to enable touching the widget only on clock and settings.
|
|
@ -0,0 +1,102 @@
|
|||
# Light Switch Widget
|
||||
|
||||
Whis this widget I wanted to create a solution to quickly en-/disable the LCD backlight and even change the brightness.
|
||||
In addition it shows the lock status with the option to personalize the lock icon with a tiny image.
|
||||
|
||||
---
|
||||
### Control
|
||||
---
|
||||
* __On / off__
|
||||
Single touch the widget to en-/disable the backlight.
|
||||
* __Change brightness__ _(can be disabled)_
|
||||
First touch the widget, then quickly touch the screen again and drag up/down until you reach your wished brigthness.
|
||||
* __Double tap to flash backlight__ _(can be disabled)_
|
||||
By defaut you can double tap on the right side of your bangle to flash the backlight for a short duration.
|
||||
(While the backlight is active your bangle will be unlocked.)
|
||||
* __Double tap to unlock__ _(disabled by default)_
|
||||
If a side is defined in the app settings, your bangle will be unlocked if you double tap on that side.
|
||||
|
||||
---
|
||||
### Settings
|
||||
---
|
||||
#### Widget - Change the apperance of the widget:
|
||||
* __Bulb col__
|
||||
_red_ / _yellow_ / _green_ / __cyan__ / _blue_ / _magenta_
|
||||
Define the color used for the lightbulbs inner circle.
|
||||
The selected color will be dimmed depending on the actual brightness value.
|
||||
* __Image__
|
||||
__default__ / _random_ / _..._
|
||||
Set your favourite lock icon image. (If no image file is found _no image_ will be displayed.)
|
||||
* _random_ -> Select a random image on each time the widget is drawn.
|
||||
|
||||
#### Control - Change when and how to use the widget:
|
||||
* __Touch__
|
||||
_on def clk_ / _on all clk_ / _clk+setting_ / _clk+launch_ / _except apps_ / __always on__
|
||||
Select when touching the widget is active to en-/disable the backlight.
|
||||
* _on def clk_ -> only on your selected main clock face
|
||||
* _on all clk_ -> on all apps of the type _clock_
|
||||
* _clk+setting_ -> on all apps of the type _clock_ and in the settings
|
||||
* _clk+launch_ -> on all apps of the types _clock_ and _launch_
|
||||
* _except apps_ -> on all apps of the types _clock_ and _launch_ and in the settings
|
||||
* _always on_ -> always enabled when the widget is displayed
|
||||
* __Drag Delay__
|
||||
_off_ / _50ms_ / _100ms_ / _..._ / __500ms__ / _..._ / _1000ms_
|
||||
Change the maximum delay between first touch and re-touch/drag to change the brightness or disable changing the brightness completely.
|
||||
* __Min Value__
|
||||
_1%_ / _2%_ / _..._ / __10%__ / _..._ / _100%_
|
||||
Set the minimal level of brightness you can change to.
|
||||
|
||||
#### Unlock - Set double tap side to unlock:
|
||||
* __TapSide__
|
||||
__off__ / _left_ / _right_ / _top_ / _bottom_ / _front_ / _back_
|
||||
|
||||
#### Flash - Change if and how to flash the backlight:
|
||||
* __TapSide__
|
||||
_off_ / _left_ / __right__ / _top_ / _bottom_ / _front_ / _back_
|
||||
Set double tap side to flash the backlight or disable completely.
|
||||
* __Tap__
|
||||
_on locked_ / _on unlocked_ / __always on__
|
||||
Select when a double tap is recognised.
|
||||
* __Timeout__
|
||||
_0.5s_ / _1s_ / _..._ / __2s__ / _..._ / _10s_
|
||||
Change how long the backlight will be activated on a flash.
|
||||
* __Min Value__
|
||||
_1%_ / _2%_ / _..._ / __20%__ / _..._ / _100%_
|
||||
Set the minimal level of brightness for the backlight on a flash.
|
||||
|
||||
---
|
||||
### Images
|
||||
---
|
||||
|
||||
| Lightbulb | Default lock icon |
|
||||
|:-----------------------------:|:-----------------------:|
|
||||
|  |  |
|
||||
| ( _full_ / _dimmed_ / _off_ ) | ( _on_ / _off_ ) |
|
||||
|
||||
Examples in default light and dark theme.
|
||||
|
||||
| Lock | Heart | Invader | JS | Smiley | Skull | Storm |
|
||||
|:----:|:-----:|:-------:|:--:|:------:|:-----:|:-----:|
|
||||
|  |  |  |  |  |  |  |
|
||||
|
||||
This images are stored in a seperate file _(lightswitch.images.json)_.
|
||||
|
||||
---
|
||||
### Worth Mentioning
|
||||
---
|
||||
#### To do list
|
||||
* Catch the touch and draw input related to this widget to prevent actions in the active app.
|
||||
_(For now I have no idea how to achieve this, help is appreciated)_
|
||||
* Manage images for the lock icon through a _Customize and Upload App_ page.
|
||||
|
||||
#### Requests, Bugs and Feedback
|
||||
Please leave requests and bug reports by raising an issue at [github.com/storm64/BangleApps](https://github.com/storm64/BangleApps) or send me a [mail](mailto:banglejs@storm64.de).
|
||||
|
||||
#### Thanks
|
||||
Huge thanks to Gordon Williams and all the motivated developers.
|
||||
|
||||
#### Creator
|
||||
Storm64 ([Mail](mailto:banglejs@storm64.de), [github](https://github.com/storm64))
|
||||
|
||||
#### License
|
||||
[MIT License](LICENSE)
|
|
@ -0,0 +1,17 @@
|
|||
// load settings
|
||||
var settings = Object.assign({
|
||||
value: 1,
|
||||
isOn: true
|
||||
}, require("Storage").readJSON("lightswitch.json", true) || {});
|
||||
|
||||
// set brightness
|
||||
Bangle.setLCDBrightness(settings.isOn ? settings.value : 0);
|
||||
|
||||
// remove tap listener to prevent uncertainties
|
||||
Bangle.removeListener("tap", require("lightswitch.js").tapListener);
|
||||
|
||||
// add tap listener to unlock and/or flash backlight
|
||||
if (settings.unlockSide || settings.tapSide) Bangle.on("tap", require("lightswitch.js").tapListener);
|
||||
|
||||
// clear variable
|
||||
settings = undefined;
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"lock": {
|
||||
"str": "BQcBAAEYxiA=",
|
||||
"x": 9,
|
||||
"y": 15,
|
||||
},
|
||||
"heart": {
|
||||
"str": "CQjBAQD4//+chAAACA4Pj+8=",
|
||||
"x": 7,
|
||||
"y": 14,
|
||||
},
|
||||
"invader": {
|
||||
"str": "DQqDASQASQASSEAAECSQEAEASQEkkkAQEgkgkAEkkkkkAgkkkggEEAAEEAAEgkAASQAAASQ=",
|
||||
"x": 5,
|
||||
"y": 13,
|
||||
},
|
||||
"js": {
|
||||
"str": "CAqBAd//2NfZ3tHfX78=",
|
||||
"x": 7,
|
||||
"y": 13,
|
||||
},
|
||||
"skull": {
|
||||
"str": "CQqBAcHAZTKcH/+OfMGfAA==",
|
||||
"x": 7,
|
||||
"y": 13,
|
||||
},
|
||||
"smiley": {
|
||||
"str": "CwqDASQAAASQNtsAQNttsANgMBsBsBgNgNtttsBsNsNgBsANgCBttgCSAAACQA==",
|
||||
"x": 6,
|
||||
"y": 13,
|
||||
},
|
||||
"storm": {
|
||||
"str": "CQmDASAAACBttgBgABgBttgCMAACQNsASRgASSBgCSSACSA=",
|
||||
"x": 7,
|
||||
"y": 13,
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
# Light Switch Images
|
After Width: | Height: | Size: 944 B |
After Width: | Height: | Size: 936 B |
After Width: | Height: | Size: 773 B |
After Width: | Height: | Size: 803 B |
After Width: | Height: | Size: 776 B |
After Width: | Height: | Size: 923 B |
After Width: | Height: | Size: 777 B |
After Width: | Height: | Size: 789 B |
After Width: | Height: | Size: 773 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,124 @@
|
|||
// from boot accassible functions
|
||||
exports = {
|
||||
// listener function //
|
||||
// tap listener to flash backlight
|
||||
tapListener: function(data) {
|
||||
// check for double tap and direction
|
||||
if (data.double) {
|
||||
// setup shortcut to this widget or load from storage
|
||||
var w = global.WIDGETS ? WIDGETS.lightswitch : Object.assign({
|
||||
unlockSide: "",
|
||||
tapSide: "right",
|
||||
tapOn: "always",
|
||||
}, require("Storage").readJSON("lightswitch.json", true) || {});
|
||||
|
||||
// cache lock status
|
||||
var locked = Bangle.isLocked();
|
||||
|
||||
// check to unlock
|
||||
if (locked && data.dir === w.unlockSide) Bangle.setLocked();
|
||||
|
||||
// check to flash
|
||||
if (data.dir === w.tapSide && (w.tapOn === "always" || locked === (w.tapOn === "locked"))) require("lightswitch.js").flash();
|
||||
|
||||
// clear variables
|
||||
w = undefined;
|
||||
locked = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
// external function //
|
||||
// function to flash backlight
|
||||
flash: function(tOut) {
|
||||
// setup shortcut to this widget or load from storage
|
||||
var w = global.WIDGETS ? WIDGETS.lightswitch : Object.assign({
|
||||
tOut: 3000,
|
||||
minFlash: 0.2,
|
||||
value: 1,
|
||||
isOn: true
|
||||
}, require("Storage").readJSON("lightswitch.json", true) || {});
|
||||
|
||||
// chack if locked, backlight off or actual value lower then minimal flash value
|
||||
if (Bangle.isLocked() || !w.isOn || w.value < w.minFlash) {
|
||||
|
||||
// set inner bulb and brightness
|
||||
var setBrightness = function(w, value) {
|
||||
if (w.drawInnerBulb) w.drawInnerBulb(value);
|
||||
Bangle.setLCDBrightness(value);
|
||||
};
|
||||
|
||||
// override timeout if defined
|
||||
if (!tOut) tOut = w.tOut;
|
||||
|
||||
// check lock state
|
||||
if (Bangle.isLocked()) {
|
||||
// cache options
|
||||
var options = Bangle.getOptions();
|
||||
// set shortened lock and backlight timeout
|
||||
Bangle.setOptions({
|
||||
lockTimeout: tOut,
|
||||
backlightTimeout: tOut
|
||||
});
|
||||
// unlock
|
||||
Bangle.setLocked(false);
|
||||
// set timeout to reset options
|
||||
setTimeout(Bangle.setOptions, tOut + 100, options);
|
||||
|
||||
// clear variable
|
||||
options = undefined;
|
||||
} else {
|
||||
// set timeout to reset backlight
|
||||
setTimeout((w, funct) => {
|
||||
if (!Bangle.isLocked()) funct(w, w.isOn ? w.value : 0);
|
||||
}, tOut, w, setBrightness);
|
||||
}
|
||||
|
||||
// enable backlight
|
||||
setTimeout((w, funct) => {
|
||||
funct(w, w.value < w.minFlash ? w.minFlash : w.value);
|
||||
}, 10, w, setBrightness);
|
||||
|
||||
// clear variable
|
||||
setBrightness = undefined;
|
||||
}
|
||||
|
||||
// clear variable
|
||||
w = undefined;
|
||||
},
|
||||
|
||||
// external access to internal function //
|
||||
// refference to widget function or set backlight and write to storage if not skipped
|
||||
changeValue: function(value, skipWrite) {
|
||||
// check if widgets are loaded
|
||||
if (global.WIDGETS) {
|
||||
// execute inside widget
|
||||
WIDGETS.lightswitch.changeValue(value, skipWrite);
|
||||
} else {
|
||||
// load settings from storage
|
||||
var filename = "lightswitch.json";
|
||||
var storage = require("Storage");
|
||||
var settings = Object.assign({
|
||||
value: 1,
|
||||
isOn: true
|
||||
}, storage.readJSON(filename, true) || {});
|
||||
|
||||
// check value
|
||||
if (value) {
|
||||
// set new value
|
||||
settings.value = value;
|
||||
} else {
|
||||
// switch backlight status
|
||||
settings.isOn = !settings.isOn;
|
||||
}
|
||||
// set brightness
|
||||
Bangle.setLCDBrightness(settings.isOn ? settings.value : 0);
|
||||
// write changes to storage if not skipped
|
||||
if (!skipWrite) storage.writeJSON(filename, settings);
|
||||
|
||||
// clear variables
|
||||
filename = undefined;
|
||||
storage = undefined;
|
||||
settings = undefined;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"id": "lightswitch",
|
||||
"name": "Light Switch Widget",
|
||||
"shortName": "Light Switch",
|
||||
"version": "0.02",
|
||||
"description": "A fast way to switch LCD backlight on/off, change the brightness and show the lock status. All in one widget.",
|
||||
"icon": "images/app.png",
|
||||
"screenshots": [
|
||||
{"url": "images/screenshot_1.png"},
|
||||
{"url": "images/screenshot_2.png"},
|
||||
{"url": "images/screenshot_3.png"},
|
||||
{"url": "images/screenshot_4.png"}
|
||||
],
|
||||
"type": "widget",
|
||||
"tags": "tool,widget,brightness,lock",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name": "lightswitch.boot.js", "url": "boot.js"},
|
||||
{"name": "lightswitch.js", "url": "lib.js"},
|
||||
{"name": "lightswitch.settings.js", "url": "settings.js"},
|
||||
{"name": "lightswitch.wid.js", "url": "widget.js"}
|
||||
],
|
||||
"data": [
|
||||
{"name": "lightswitch.json"},
|
||||
{"name": "lightswitch.images.json", "url": "images.json"}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
(function(back) {
|
||||
var filename = "lightswitch.json";
|
||||
|
||||
// set Storage and load settings
|
||||
var storage = require("Storage");
|
||||
var settings = Object.assign({
|
||||
colors: "011",
|
||||
image: "default",
|
||||
touchOn: "clock,launch",
|
||||
dragDelay: 500,
|
||||
minValue: 0.1,
|
||||
unlockSide: "",
|
||||
tapSide: "right",
|
||||
tapOn: "always",
|
||||
tOut: 2000,
|
||||
minFlash: 0.2
|
||||
}, storage.readJSON(filename, true) || {});
|
||||
var images = storage.readJSON(filename.replace(".", ".images."), true) || false;
|
||||
|
||||
// write change to storage and widget
|
||||
function writeSetting(key, value, drawWidgets) {
|
||||
// reread settings to only change key
|
||||
settings = Object.assign(settings, storage.readJSON(filename, true) || {});
|
||||
// change the value of key
|
||||
settings[key] = value;
|
||||
// write to storage
|
||||
storage.writeJSON(filename, settings);
|
||||
// check if widgets are loaded
|
||||
if (global.WIDGETS) {
|
||||
// setup shortcut to the widget
|
||||
var w = WIDGETS.lightswitch;
|
||||
// assign changes to widget
|
||||
w = Object.assign(w, settings);
|
||||
// redraw widgets if neccessary
|
||||
if (drawWidgets) Bangle.drawWidgets();
|
||||
}
|
||||
}
|
||||
|
||||
// generate entry for circulating values
|
||||
function getEntry(key) {
|
||||
var entry = entries[key];
|
||||
// check for existing titles to decide value type
|
||||
if (entry.value) {
|
||||
// return entry for string value
|
||||
return {
|
||||
value: entry.value.indexOf(settings[key]),
|
||||
format: v => entry.title ? entry.title[v] : entry.value[v],
|
||||
onchange: function(v) {
|
||||
this.value = v = v >= entry.value.length ? 0 : v < 0 ? entry.value.length - 1 : v;
|
||||
writeSetting(key, entry.value[v], entry.drawWidgets);
|
||||
if (entry.exec) entry.exec(entry.value[v]);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// return entry for numerical value
|
||||
return {
|
||||
value: settings[key] * entry.factor,
|
||||
step: entry.step,
|
||||
format: v => v > 0 ? v + entry.unit : "off",
|
||||
onchange: function(v) {
|
||||
this.value = v = v > entry.max ? entry.min : v < entry.min ? entry.max : v;
|
||||
writeSetting(key, v / entry.factor, entry.drawWidgets);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// define menu entries with circulating values
|
||||
var entries = {
|
||||
colors: {
|
||||
title: ["red", "yellow", "green", "cyan", "blue", "magenta"],
|
||||
value: ["100", "110", "010", "011", "001", "101"],
|
||||
drawWidgets: true
|
||||
},
|
||||
image: {
|
||||
title: images ? undefined : ["no found"],
|
||||
value: images ? ["default", "random"].concat(Object.keys(images)) : ["default"],
|
||||
exec: function(value) {
|
||||
// draw selected image in upper right corner
|
||||
var x = 152,
|
||||
y = 26,
|
||||
i = images ? images[value] : false;
|
||||
g.reset();
|
||||
if (!i) g.setColor(g.theme.bg);
|
||||
g.drawImage(atob("Dw+BADAYYDDAY//v////////////////////////3/8A"), x + 4, y);
|
||||
if (i) g.drawImage(atob(i.str), x + i.x, y - 9 + i.y);
|
||||
i = undefined;
|
||||
}
|
||||
},
|
||||
touchOn: {
|
||||
title: ["on def clk", "on all clk", "clk+launch", "clk+setting", "except apps", "always on"],
|
||||
value: ["", "clock", "clock,setting.app.js", "clock,launch", "clock,setting.app.js,launch", "always"],
|
||||
drawWidgets: true
|
||||
},
|
||||
dragDelay: {
|
||||
factor: 1,
|
||||
unit: "ms",
|
||||
min: 0,
|
||||
max: 1000,
|
||||
step: 50
|
||||
},
|
||||
minValue: {
|
||||
factor: 100,
|
||||
unit: "%",
|
||||
min: 1,
|
||||
max: 100,
|
||||
step: 1
|
||||
},
|
||||
unlockSide: {
|
||||
title: ["off", "left", "right", "top", "bottom", "front", "back"],
|
||||
value: ["", "left", "right", "top", "bottom", "front", "back"]
|
||||
},
|
||||
tapOn: {
|
||||
title: ["on locked", "on unlocked", "always on"],
|
||||
value: ["locked", "unlocked", "always"]
|
||||
},
|
||||
tOut: {
|
||||
factor: 0.001,
|
||||
unit: "s",
|
||||
min: 0.5,
|
||||
max: 10,
|
||||
step: 0.5
|
||||
}
|
||||
};
|
||||
// copy duplicated entries
|
||||
entries.tapSide = entries.unlockSide;
|
||||
entries.minFlash = entries.minValue;
|
||||
|
||||
// show main menu
|
||||
function showMain() {
|
||||
var mainMenu = E.showMenu({
|
||||
"": {
|
||||
title: "Light Switch"
|
||||
},
|
||||
"< Back": () => back(),
|
||||
"-- Widget --------": 0,
|
||||
"Bulb col": getEntry("colors"),
|
||||
"Image": getEntry("image"),
|
||||
"-- Control -------": 0,
|
||||
"Touch": getEntry("touchOn"),
|
||||
"Drag Delay": getEntry("dragDelay"),
|
||||
"Min Value": getEntry("minValue"),
|
||||
"-- Unlock --------": 0,
|
||||
"TapSide": getEntry("unlockSide"),
|
||||
"-- Flash ---------": 0,
|
||||
"TapSide ": getEntry("tapSide"),
|
||||
"Tap": getEntry("tapOn"),
|
||||
"Timeout": getEntry("tOut"),
|
||||
"Min Value ": getEntry("minFlash")
|
||||
});
|
||||
}
|
||||
|
||||
// draw main menu
|
||||
showMain();
|
||||
})
|
|
@ -0,0 +1,72 @@
|
|||
/*** Available settings for lightswitch ***
|
||||
|
||||
* colors: string // colors used for the bulb
|
||||
// set with g.setColor(val*col[0], val*col[1], val*col[2])
|
||||
"100" -> red
|
||||
"110" -> yellow
|
||||
"010" -> green
|
||||
"011" -> cyan (default)
|
||||
"001" -> blue
|
||||
"101" -> magenta
|
||||
|
||||
* image: string //
|
||||
"default" ->
|
||||
"random" ->
|
||||
|
||||
* touchOn: string // select when widget touch is active
|
||||
"" -> only on default clock
|
||||
"clock" -> on all clocks
|
||||
"clock,launch" -> on all clocks and lanchers (default)
|
||||
"always" -> always
|
||||
|
||||
* dragDelay: int // drag listener reset time in ms
|
||||
// time until a drag is needed to activate backlight changing mode
|
||||
0 -> disabled
|
||||
500 -> (default)
|
||||
|
||||
* minValue: float // minimal brightness level that can be set by dragging
|
||||
0.05 to 1, 0.1 as default
|
||||
|
||||
* unlockSide: string // side of the watch to double tap on to flash backlight
|
||||
0/false/undefined -> backlight flash disabled
|
||||
right/left/up/down/front/back -> side to tap on (default: right)
|
||||
|
||||
* tapSide: string // side of the watch to double tap on to flash backlight
|
||||
0/false/undefined -> backlight flash disabled
|
||||
right/left/up/down/front/back -> side to tap on (default: right)
|
||||
|
||||
* tapOn: string // select when tap to flash backlight is active
|
||||
"locked" -> only when locked
|
||||
"unlocked" -> only when unlocked (default)
|
||||
"always" -> always
|
||||
|
||||
* tOut: int // backlight flash timeout in ms
|
||||
3000 (default)
|
||||
|
||||
* minFlash: float // minimal brightness level when
|
||||
0.05 to 1, 0.2 as default
|
||||
|
||||
*** Cached values ***
|
||||
|
||||
* value: float // active brightness value (0-1)
|
||||
1 (default)
|
||||
* isOn: bool // active backlight status
|
||||
true (default)
|
||||
|
||||
*/
|
||||
{
|
||||
// settings
|
||||
"colors": "011",
|
||||
"image": "default",
|
||||
"touchOn": "clock,launch",
|
||||
"dragDelay": 500,
|
||||
"minValue": 0.1,
|
||||
"unlockSide": "",
|
||||
"tapSide": "right",
|
||||
"tapOn": "always",
|
||||
"tOut": 2000,
|
||||
"minFlash": 0.2,
|
||||
// cached values
|
||||
"value": 1,
|
||||
"isOn": true
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
(function() {
|
||||
// load settings
|
||||
var settings = Object.assign({
|
||||
colors: "011",
|
||||
image: "default",
|
||||
touchOn: "clock,launch",
|
||||
dragDelay: 500,
|
||||
minValue: 0.1,
|
||||
unlockSide: "",
|
||||
tapSide: "right",
|
||||
tapOn: "always",
|
||||
tOut: 3000,
|
||||
value: 1,
|
||||
isOn: true
|
||||
}, require("Storage").readJSON("lightswitch.json", true) || {});
|
||||
|
||||
// write widget with loaded settings
|
||||
WIDGETS.lightswitch = Object.assign(settings, {
|
||||
|
||||
// set area, sortorder, width and dragStatus
|
||||
area: "tr",
|
||||
sortorder: 10,
|
||||
width: 23,
|
||||
dragStatus: "off",
|
||||
|
||||
// internal function //
|
||||
// write settings to storage
|
||||
writeSettings: function(changes) {
|
||||
// define variables
|
||||
var filename = "lightswitch.json";
|
||||
var storage = require("Storage");
|
||||
|
||||
// write changes into json file
|
||||
storage.writeJSON(filename, Object.assign(
|
||||
storage.readJSON(filename, true) || {}, changes
|
||||
));
|
||||
|
||||
// clear variables
|
||||
filename = undefined;
|
||||
storage = undefined;
|
||||
},
|
||||
|
||||
// internal function //
|
||||
// draw inner bulb circle
|
||||
drawInnerBulb: function(value) {
|
||||
// check if active or value is set
|
||||
if (value || this.isOn) {
|
||||
// use set value or load from widget
|
||||
value = value || this.value;
|
||||
// calculate color
|
||||
g.setColor(
|
||||
value * this.colors[0],
|
||||
value * this.colors[1],
|
||||
value * this.colors[2]
|
||||
);
|
||||
} else {
|
||||
// backlight off
|
||||
g.setColor(0);
|
||||
}
|
||||
// draw circle
|
||||
g.drawImage(atob("CwuBAB8H8f9/////////f8fwfAA="), this.x + 6, this.y + 6);
|
||||
},
|
||||
|
||||
// internal function //
|
||||
// draw widget icon
|
||||
drawIcon: function(locked) {
|
||||
// define icons
|
||||
var icons = {
|
||||
bulb: "DxSBAAAAD4BgwYDCAIgAkAEgAkAEgAiAIYDBgwH8A/gH8A/gH8AfABwA",
|
||||
shine: "FxeBAAgQIAgggBBBABAECAAALAABhAAEAAAAAAAAAAAAAAAHAABwAAAAAAAAAAAAAAAQABDAABoAAAgQBABABACACAIACAA=",
|
||||
lock: "DxCBAAAAH8B/wMGBgwMGBgwf/H/8+Pnx8/fn78/fn/8f/A==",
|
||||
image: "DxSBAA/gP+Dg4YDDAYYDDAYYDH/9////////////////////////+//g"
|
||||
};
|
||||
// read images
|
||||
var images = require("Storage").readJSON("lightswitch.images.json", true) || false;
|
||||
|
||||
// select image if images are found
|
||||
var image = (!images || image === "default") ? false :
|
||||
(function(i) {
|
||||
if (i === "random") {
|
||||
i = Object.keys(images);
|
||||
i = i[parseInt(Math.random() * i.length)];
|
||||
}
|
||||
return images[i];
|
||||
})(this.image);
|
||||
|
||||
// clear widget area
|
||||
g.reset().clearRect(this.x, this.y, this.x + this.width, this.y + 24);
|
||||
|
||||
// draw shine if backlight is active
|
||||
if (this.isOn) g.drawImage(atob(icons.shine), this.x, this.y);
|
||||
|
||||
// draw icon depending on lock status and image
|
||||
g.drawImage(atob(!locked ? icons.bulb : image ? icons.image : icons.lock), this.x + 4, this.y + 4);
|
||||
|
||||
// draw image on lock
|
||||
if (locked && image) g.drawImage(atob(image.str), this.x + image.x, this.y + image.y);
|
||||
|
||||
// draw bulb color depending on backlight status
|
||||
if (!locked) this.drawInnerBulb();
|
||||
|
||||
// clear variables
|
||||
icons = undefined;
|
||||
images = undefined;
|
||||
image = undefined;
|
||||
},
|
||||
|
||||
// internal function //
|
||||
// change or switch backlight and icon and write to storage if not skipped
|
||||
changeValue: function(value, skipWrite) {
|
||||
// check value
|
||||
if (value) {
|
||||
// set new value
|
||||
this.value = value;
|
||||
// check backlight status
|
||||
if (this.isOn) {
|
||||
// redraw only inner bulb circle
|
||||
this.drawInnerBulb();
|
||||
} else {
|
||||
// activate backlight
|
||||
this.isOn = true;
|
||||
// redraw complete widget icon
|
||||
this.drawIcon(false);
|
||||
}
|
||||
} else {
|
||||
// switch backlight status
|
||||
this.isOn = !this.isOn;
|
||||
// redraw widget icon
|
||||
this.drawIcon(false);
|
||||
}
|
||||
// set brightness
|
||||
Bangle.setLCDBrightness(this.isOn ? this.value : 0);
|
||||
// write changes to storage if not skipped
|
||||
if (!skipWrite) this.writeSettings({
|
||||
isOn: this.isOn,
|
||||
value: this.value
|
||||
});
|
||||
},
|
||||
|
||||
// listener function //
|
||||
// drag listener for brightness change mode
|
||||
dragListener: function(event) {
|
||||
// setup shortcut to this widget
|
||||
var w = WIDGETS.lightswitch;
|
||||
|
||||
// first drag recognised
|
||||
if (event.b && typeof w.dragStatus === "number") {
|
||||
// reset drag timeout
|
||||
clearTimeout(w.dragStatus);
|
||||
// change drag status to indicate ongoing drag action
|
||||
w.dragStatus = "ongoing";
|
||||
// feedback for brightness change mode
|
||||
Bangle.buzz(50);
|
||||
}
|
||||
|
||||
// read y position, pleasant usable area 20-170
|
||||
var y = event.y;
|
||||
y = y < 20 ? 0 : y > 170 ? 150 : y - 20;
|
||||
// calculate brightness respecting minimal value in settings
|
||||
var value = (1 - Math.round(y / 1.5) / 100) * (1 - w.minValue) + w.minValue;
|
||||
|
||||
// change brigthness value, skip write to storage while still touching
|
||||
w.changeValue(value, event.b);
|
||||
|
||||
// on touch release remove drag listener and reset drag status to indicate stopped drag action
|
||||
if (!event.b) {
|
||||
Bangle.removeListener("drag", w.dragListener);
|
||||
w.dragStatus = "off";
|
||||
}
|
||||
|
||||
// clear variables
|
||||
w = undefined;
|
||||
y = undefined;
|
||||
value = undefined;
|
||||
},
|
||||
|
||||
// listener function //
|
||||
// touch listener for light control
|
||||
touchListener: function(button, cursor) {
|
||||
// setup shortcut to this widget
|
||||
var w = WIDGETS.lightswitch;
|
||||
|
||||
// skip all if drag action ongoing
|
||||
if (w.dragStatus === "off") {
|
||||
|
||||
// check if inside widget area
|
||||
if (!(!w || cursor.x < w.x || cursor.x > w.x + w.width ||
|
||||
cursor.y < w.y || cursor.y > w.y + 23)) {
|
||||
// first touch feedback
|
||||
Bangle.buzz(25);
|
||||
// check if drag is disabled
|
||||
if (w.dragDelay) {
|
||||
// add drag listener
|
||||
Bangle.on("drag", w.dragListener);
|
||||
// set drag timeout
|
||||
w.dragStatus = setTimeout((w) => {
|
||||
// remove drag listener
|
||||
Bangle.removeListener("drag", w.dragListener);
|
||||
// clear drag timeout
|
||||
if (typeof w.dragStatus === "number") clearTimeout(w.dragStatus);
|
||||
// reset drag status to indicate stopped drag action
|
||||
w.dragStatus = "off";
|
||||
}, w.dragDelay, w);
|
||||
}
|
||||
// switch backlight
|
||||
w.changeValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// clear variable
|
||||
w = undefined;
|
||||
},
|
||||
|
||||
// main widget function //
|
||||
// display and setup/reset function
|
||||
draw: function(locked) {
|
||||
// setup shortcut to this widget
|
||||
var w = WIDGETS.lightswitch;
|
||||
|
||||
// set lcd brightness on unlocking
|
||||
// all other cases are catched by the boot file
|
||||
if (locked === false) Bangle.setLCDBrightness(w.isOn ? w.value : 0);
|
||||
|
||||
// read lock status
|
||||
locked = Bangle.isLocked();
|
||||
|
||||
// remove listeners to prevent uncertainties
|
||||
Bangle.removeListener("lock", w.draw);
|
||||
Bangle.removeListener("touch", w.touchListener);
|
||||
Bangle.removeListener("tap", require("lightswitch.js").tapListener);
|
||||
|
||||
// draw widget icon
|
||||
w.drawIcon(locked);
|
||||
|
||||
// add lock listener
|
||||
Bangle.on("lock", w.draw);
|
||||
|
||||
// add touch listener to control the light depending on settings
|
||||
if (w.touchOn === "always" || !global.__FILE__ ||
|
||||
w.touchOn.includes(__FILE__) ||
|
||||
w.touchOn.includes(require("Storage").readJSON(__FILE__.replace("app.js", "info")).type))
|
||||
Bangle.on("touch", w.touchListener);
|
||||
|
||||
// add tap listener to unlock and/or flash backlight
|
||||
if (w.unlockSide || w.tapSide) Bangle.on("tap", require("lightswitch.js").tapListener);
|
||||
|
||||
// clear variables
|
||||
w = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
// clear variable
|
||||
settings = undefined;
|
||||
})()
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Set pace format to mm:ss, time format to h:mm:ss,
|
||||
added settings to opt out of GPS and HRM
|
||||
0.03: Fixed distance calculation, tested against Garmin Etrex, Amazfit GTS 2
|
||||
|
|
|
@ -5,6 +5,7 @@ var fontHeading = "6x8:2";
|
|||
var fontValue = B2 ? "6x15:2" : "6x8:3";
|
||||
var headingCol = "#888";
|
||||
var running = false;
|
||||
var fixCount = 0;
|
||||
var startTime;
|
||||
var startSteps;
|
||||
// This & previous GPS readings
|
||||
|
@ -102,8 +103,6 @@ var layout = new Layout( {
|
|||
clearState();
|
||||
layout.render();
|
||||
|
||||
|
||||
|
||||
function onTimer() {
|
||||
layout.clock.label = locale.time(new Date(),1);
|
||||
if (!running) {
|
||||
|
@ -125,21 +124,36 @@ function onTimer() {
|
|||
stepHistory[0]=0;
|
||||
}
|
||||
|
||||
function radians(a) {
|
||||
return a*Math.PI/180;
|
||||
}
|
||||
|
||||
// distance between 2 lat and lons, in meters, Mean Earth Radius = 6371km
|
||||
// https://www.movable-type.co.uk/scripts/latlong.html
|
||||
function calcDistance(a,b) {
|
||||
var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
|
||||
var y = radians(b.lat-a.lat);
|
||||
return Math.round(Math.sqrt(x*x + y*y) * 6371000);
|
||||
}
|
||||
|
||||
Bangle.on("GPS", function(fix) {
|
||||
layout.gps.bgCol = fix.fix ? "#0f0" : "#f00";
|
||||
lastGPS = thisGPS;
|
||||
if (!fix.fix) { return; } // only process actual fixes
|
||||
if (fixCount++ == 0) {
|
||||
Bangle.buzz(); // first fix, does not need to respect quiet mode
|
||||
lastGPS = fix; // initialise on first fix
|
||||
}
|
||||
|
||||
thisGPS = fix;
|
||||
if (running && fix.fix && lastGPS.fix) {
|
||||
// work out distance - moving from a to b
|
||||
var a = Bangle.project(lastGPS);
|
||||
var b = Bangle.project(thisGPS);
|
||||
var dx = a.x-b.x, dy = a.y-b.y;
|
||||
var d = Math.sqrt(dx*dx+dy*dy); // this should be the distance in meters
|
||||
|
||||
if (running) {
|
||||
var d = calcDistance(lastGPS, thisGPS);
|
||||
distance += d;
|
||||
layout.dist.label=locale.distance(distance);
|
||||
var duration = Date.now() - startTime; // in ms
|
||||
var speed = distance * 1000 / duration; // meters/sec
|
||||
layout.pace.label = formatPace(speed);
|
||||
lastGPS = fix;
|
||||
}
|
||||
});
|
||||
Bangle.on("HRM", function(h) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "run",
|
||||
"name": "Run",
|
||||
"version":"0.02",
|
||||
"version":"0.03",
|
||||
"description": "Displays distance, time, steps, cadence, pace and more for runners.",
|
||||
"icon": "app.png",
|
||||
"tags": "run,running,fitness,outdoors,gps",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
{ "url": "screenshot-mag.png" }
|
||||
],
|
||||
"type": "app",
|
||||
"tags": "tool,sensors",
|
||||
"tags": "tool,sensors,bluetooth",
|
||||
"supports" : [ "BANGLEJS2" ],
|
||||
"allow_emulator": true,
|
||||
"readme": "README.md",
|
||||
|
|