diff --git a/.eslintignore b/.eslintignore index 7bbe41136..fcbea07f9 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,5 @@ apps/animclk/V29.LBM.js apps/banglerun/rollup.config.js apps/schoolCalendar/fullcalendar/main.js apps/authentiwatch/qr_packed.js +apps/qrcode/qr-scanner.umd.min.js *.test.js diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 000000000..1eb009153 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,34 @@ +name: Node CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v2 + with: + submodules: recursive + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: install testing dependencies + run: npm i + - name: test all apps and widgets + run: npm run test + - name: install typescript dependencies + working-directory: ./typescript + run: npm ci + - name: build types + working-directory: ./typescript + run: npm run build:types + - name: build all TS apps and widgets + working-directory: ./typescript + run: npm run build \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f3d0d2159..000000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: node_js -node_js: - - "node" diff --git a/apps/authentiwatch/ChangeLog b/apps/authentiwatch/ChangeLog index 7d6f96026..bb2945db4 100644 --- a/apps/authentiwatch/ChangeLog +++ b/apps/authentiwatch/ChangeLog @@ -3,3 +3,4 @@ 0.03: Add "Calculating" placeholder, update JSON save format 0.04: Fix tapping at very bottom of list, exit on inactivity 0.05: Add support for bulk importing and exporting tokens +0.06: Add spaces to codes for improved readability (thanks @BartS23) diff --git a/apps/authentiwatch/README.md b/apps/authentiwatch/README.md index cc25e9604..a957cf93a 100644 --- a/apps/authentiwatch/README.md +++ b/apps/authentiwatch/README.md @@ -33,7 +33,7 @@ Keep those copies safe and secure. * Swipe right to exit to the app launcher. * Swipe left on selected counter token to advance the counter to the next value. - +    ## Creator diff --git a/apps/authentiwatch/app.js b/apps/authentiwatch/app.js index 640183230..73b8bdeea 100644 --- a/apps/authentiwatch/app.js +++ b/apps/authentiwatch/app.js @@ -1,5 +1,6 @@ const tokenextraheight = 16; var tokendigitsheight = 30; +var tokenheight = tokendigitsheight + tokenextraheight; // Hash functions const crypto = require("crypto"); const algos = { @@ -93,6 +94,9 @@ function hotp(d, token, dohmac) { while (ret.length < token.digits) { ret = "0" + ret; } + // add a space after every 3rd or 4th digit + var re = (token.digits % 3 == 0 || (token.digits % 3 >= token.digits % 4 && token.digits % 4 != 0)) ? "" : "."; + ret = ret.replace(new RegExp("(..." + re + ")", "g"), "$1 ").trim(); } catch(err) { ret = notsupported; } @@ -121,15 +125,15 @@ function drawToken(id, r) { lbl = tokens[id].label.substr(0, 10); if (id == state.curtoken) { // current token - g.setColor(g.theme.fgH); - g.setBgColor(g.theme.bgH); - g.setFont("Vector", tokenextraheight); + g.setColor(g.theme.fgH) + .setBgColor(g.theme.bgH) + .setFont("Vector", tokenextraheight) // center just below top line - g.setFontAlign(0, -1, 0); + .setFontAlign(0, -1, 0); adj = y1; } else { - g.setColor(g.theme.fg); - g.setBgColor(g.theme.bg); + g.setColor(g.theme.fg) + .setBgColor(g.theme.bg); sz = tokendigitsheight; do { g.setFont("Vector", sz--); @@ -138,8 +142,8 @@ function drawToken(id, r) { g.setFontAlign(0, 0, 0); adj = (y1 + y2) / 2; } - g.clearRect(x1, y1, x2, y2); - g.drawString(lbl, (x1 + x2) / 2, adj, false); + g.clearRect(x1, y1, x2, y2) + .drawString(lbl, (x1 + x2) / 2, adj, false); if (id == state.curtoken) { if (tokens[id].period > 0) { // timed - draw progress bar @@ -160,10 +164,10 @@ function drawToken(id, r) { g.drawString(state.otp, (x1 + adj + x2) / 2, y1 + tokenextraheight, false); } // shaded lines top and bottom - g.setColor(0.5, 0.5, 0.5); - g.drawLine(x1, y1, x2, y1); - g.drawLine(x1, y2, x2, y2); - g.setClipRect(0, 0, g.getWidth(), g.getHeight()); + g.setColor(0.5, 0.5, 0.5) + .drawLine(x1, y1, x2, y1) + .drawLine(x1, y2, x2, y2) + .setClipRect(0, 0, g.getWidth(), g.getHeight()); } function draw() { @@ -198,15 +202,15 @@ function draw() { } if (tokens.length > 0) { var drewcur = false; - var id = Math.floor(state.listy / (tokendigitsheight + tokenextraheight)); - var y = id * (tokendigitsheight + tokenextraheight) + Bangle.appRect.y - state.listy; + var id = Math.floor(state.listy / tokenheight); + var y = id * tokenheight + Bangle.appRect.y - state.listy; while (id < tokens.length && y < Bangle.appRect.y2) { - drawToken(id, {x:Bangle.appRect.x, y:y, w:Bangle.appRect.w, h:(tokendigitsheight + tokenextraheight)}); + drawToken(id, {x:Bangle.appRect.x, y:y, w:Bangle.appRect.w, h:tokenheight}); if (id == state.curtoken && (tokens[id].period <= 0 || state.nextTime != 0)) { drewcur = true; } id += 1; - y += (tokendigitsheight + tokenextraheight); + y += tokenheight; } if (drewcur) { // the current token has been drawn - schedule a redraw @@ -228,9 +232,9 @@ function draw() { state.nexttime = 0; } } else { - g.setFont("Vector", tokendigitsheight); - g.setFontAlign(0, 0, 0); - g.drawString(notokens, Bangle.appRect.x + Bangle.appRect.w / 2, Bangle.appRect.y + Bangle.appRect.h / 2, false); + g.setFont("Vector", tokendigitsheight) + .setFontAlign(0, 0, 0) + .drawString(notokens, Bangle.appRect.x + Bangle.appRect.w / 2, Bangle.appRect.y + Bangle.appRect.h / 2, false); } if (state.drawtimer) { clearTimeout(state.drawtimer); @@ -240,18 +244,18 @@ function draw() { function onTouch(zone, e) { if (e) { - var id = Math.floor((state.listy + (e.y - Bangle.appRect.y)) / (tokendigitsheight + tokenextraheight)); + var id = Math.floor((state.listy + (e.y - Bangle.appRect.y)) / tokenheight); if (id == state.curtoken || tokens.length == 0 || id >= tokens.length) { id = -1; } if (state.curtoken != id) { if (id != -1) { - var y = id * (tokendigitsheight + tokenextraheight) - state.listy; + var y = id * tokenheight - state.listy; if (y < 0) { state.listy += y; y = 0; } - y += (tokendigitsheight + tokenextraheight); + y += tokenheight; if (y > Bangle.appRect.h) { state.listy += (y - Bangle.appRect.h); } @@ -268,7 +272,7 @@ function onTouch(zone, e) { function onDrag(e) { if (e.x > g.getWidth() || e.y > g.getHeight()) return; if (e.dx == 0 && e.dy == 0) return; - var newy = Math.min(state.listy - e.dy, tokens.length * (tokendigitsheight + tokenextraheight) - Bangle.appRect.h); + var newy = Math.min(state.listy - e.dy, tokens.length * tokenheight - Bangle.appRect.h); state.listy = Math.max(0, newy); draw(); } @@ -300,8 +304,12 @@ function bangle1Btn(e) { } state.curtoken = Math.max(state.curtoken, 0); state.curtoken = Math.min(state.curtoken, tokens.length - 1); + state.listy = state.curtoken * tokenheight; + state.listy -= (Bangle.appRect.h - tokenheight) / 2; + state.listy = Math.min(state.listy, tokens.length * tokenheight - Bangle.appRect.h); + state.listy = Math.max(state.listy, 0); var fakee = {}; - fakee.y = state.curtoken * (tokendigitsheight + tokenextraheight) - state.listy + Bangle.appRect.y; + fakee.y = state.curtoken * tokenheight - state.listy + Bangle.appRect.y; state.curtoken = -1; state.nextTime = 0; onTouch(0, fakee); @@ -318,9 +326,9 @@ Bangle.on('touch', onTouch); Bangle.on('drag' , onDrag ); Bangle.on('swipe', onSwipe); if (typeof BTN2 == 'number') { - setWatch(function(){bangle1Btn(-1);}, BTN1, {edge:"rising", debounce:50, repeat:true}); - setWatch(function(){exitApp(); }, BTN2, {edge:"rising", debounce:50, repeat:true}); - setWatch(function(){bangle1Btn( 1);}, BTN3, {edge:"rising", debounce:50, repeat:true}); + setWatch(function(){bangle1Btn(-1);}, BTN1, {edge:"rising" , debounce:50, repeat:true}); + setWatch(function(){exitApp(); }, BTN2, {edge:"falling", debounce:50}); + setWatch(function(){bangle1Btn( 1);}, BTN3, {edge:"rising" , debounce:50, repeat:true}); } Bangle.loadWidgets(); diff --git a/apps/authentiwatch/interface.html b/apps/authentiwatch/interface.html index d2213b819..5ee32fd8e 100644 --- a/apps/authentiwatch/interface.html +++ b/apps/authentiwatch/interface.html @@ -56,6 +56,7 @@ function base32clean(val, nows) { var ret = val.replaceAll(/\s+/g, ' '); ret = ret.replaceAll(/0/g, 'O'); ret = ret.replaceAll(/1/g, 'I'); + ret = ret.replaceAll(/8/g, 'B'); ret = ret.replaceAll(/[^A-Za-z2-7 ]/g, ''); if (nows) { ret = ret.replaceAll(/\s+/g, ''); diff --git a/apps/authentiwatch/metadata.json b/apps/authentiwatch/metadata.json index 676d8da9f..b4ed34a12 100644 --- a/apps/authentiwatch/metadata.json +++ b/apps/authentiwatch/metadata.json @@ -3,8 +3,8 @@ "name": "2FA Authenticator", "shortName": "AuthWatch", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "version": "0.05", + "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot4.png"}], + "version": "0.06", "description": "Google Authenticator compatible tool.", "tags": "tool", "interface": "interface.html", diff --git a/apps/authentiwatch/screenshot.png b/apps/authentiwatch/screenshot.png deleted file mode 100644 index 2a7bcbd9a..000000000 Binary files a/apps/authentiwatch/screenshot.png and /dev/null differ diff --git a/apps/authentiwatch/screenshot1.png b/apps/authentiwatch/screenshot1.png new file mode 100644 index 000000000..c7ca744b4 Binary files /dev/null and b/apps/authentiwatch/screenshot1.png differ diff --git a/apps/authentiwatch/screenshot2.png b/apps/authentiwatch/screenshot2.png new file mode 100644 index 000000000..8156dd3e8 Binary files /dev/null and b/apps/authentiwatch/screenshot2.png differ diff --git a/apps/authentiwatch/screenshot3.png b/apps/authentiwatch/screenshot3.png new file mode 100644 index 000000000..6d14e0b96 Binary files /dev/null and b/apps/authentiwatch/screenshot3.png differ diff --git a/apps/authentiwatch/screenshot4.png b/apps/authentiwatch/screenshot4.png new file mode 100644 index 000000000..7576e1aff Binary files /dev/null and b/apps/authentiwatch/screenshot4.png differ diff --git a/apps/banglerun/.gitignore b/apps/banglerun/.gitignore deleted file mode 100644 index c2658d7d1..000000000 --- a/apps/banglerun/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/apps/banglerun/ChangeLog b/apps/banglerun/ChangeLog deleted file mode 100644 index c778588cc..000000000 --- a/apps/banglerun/ChangeLog +++ /dev/null @@ -1,13 +0,0 @@ -0.01: First release -0.02: Bugfix time: Reset minutes to 0 when hitting 60 -0.03: Fix distance >=10 km (fix #529) -0.04: Use offscreen buffer for flickerless updates -0.05: Complete rewrite. New UI, GPS & HRM Kalman filters, activity logging -0.06: Reading HDOP directly from the GPS event (needs Espruino 2v07 or above) -0.07: Fixed GPS update, added guards against NaN values -0.08: Fix issue with GPS coordinates being wrong after the first one -0.09: Another GPS fix (log raw coordinates - not filtered ones) -0.10: Removed kalman filtering to allow distance log to work - Only log data every 5 seconds (not 1 sec) - Don't create a file until the first log entry is ready - Add labels for buttons diff --git a/apps/banglerun/README.md b/apps/banglerun/README.md deleted file mode 100644 index 80e984bfa..000000000 --- a/apps/banglerun/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# BangleRun - -An app for running sessions. Displays info and logs your run for later viewing. - -## Compilation - -The app is written in Typescript, and needs to be transpiled in order to be -run on the BangleJS. The easiest way to perform this step is by using the -ubiquitous [NPM package manager](https://www.npmjs.com/get-npm). - -After having installed NPM for your platform, checkout the `BangleApps` repo, -open a terminal, and navigate into the `apps/banglerun` folder. Then issue: - -``` -npm i -``` - -to install the project's build tools, and: - -``` -npm run build -``` - -To build the app. The last command will generate the `app.js` file, containing -the transpiled code for the BangleJS. diff --git a/apps/banglerun/app-icon.js b/apps/banglerun/app-icon.js deleted file mode 100644 index 9eeaced6e..000000000 --- a/apps/banglerun/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("mEwwIHEuAEDgP8ApMDAqAXBjAGD/E8AgUcgF8CAX/BgIFBn//wAFCv//8PwAoP///5Aon/8AcB+IFB4AFB8P/34FBgfj/8fwAFB4f+g4cBg/H/w/Cg+HKQcPx4FEh4/CAoMfAocOj4/CKYRwELIIFDLII6BAoZSBLIYeCgP+v4FD/k/GAQFBHgcD/ABBIIX4gIFBSYPwAoUPAog/B8AFEwAFDDQQCBQoQFCZYYFigCKEgFwgAA==")) diff --git a/apps/banglerun/app.js b/apps/banglerun/app.js deleted file mode 100644 index b79255171..000000000 --- a/apps/banglerun/app.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";var t;!function(t){t.Stopped="STOP",t.Paused="PAUSE",t.Running="RUN"}(t||(t={}));const n={STOP:63488,PAUSE:65504,RUN:2016};function e(t,n,e){g.setColor(0),g.fillRect(n-60,e,n+60,e+30),g.setColor(65535),g.drawString(t,n,e)}function i(i){var s;g.setFontVector(30),g.setFontAlign(0,-1,0),e((i.distance/1e3).toFixed(2),60,55),e(function(t){const n=Math.round(t),e=Math.floor(n/3600),i=Math.floor(n/60)%60,s=n%60;return(e?e+":":"")+("0"+i).substr(-2)+":"+("0"+s).substr(-2)}(i.duration),172,55),e(function(t){if(t<.1667)return"__'__\"";const n=Math.round(1e3/t),e=Math.floor(n/60),i=n%60;return("0"+e).substr(-2)+"'"+("0"+i).substr(-2)+'"'}(i.speed),60,115),e(i.hr.toFixed(0),172,115),e(i.steps.toFixed(0),60,175),e(i.cadence.toFixed(0),172,175),g.setFont("6x8",2),g.setColor(i.gpsValid?2016:63488),g.fillRect(0,216,80,240),g.setColor(0),g.drawString("GPS",40,220),g.setColor(65535),g.fillRect(80,216,160,240),g.setColor(0),g.drawString(("0"+(s=new Date).getHours()).substr(-2)+":"+("0"+s.getMinutes()).substr(-2),120,220),g.setColor(n[i.status]),g.fillRect(160,216,230,240),g.setColor(0),g.drawString(i.status,200,220),g.setFont("6x8").setFontAlign(0,0,1).setColor(-1),i.status===t.Paused?g.drawString("START",236,60,1).drawString(" CLEAR ",236,180,1):i.status===t.Running?g.drawString(" PAUSE ",236,60,1).drawString(" PAUSE ",236,180,1):g.drawString("START",236,60,1).drawString(" ",236,180,1)}function s(t){g.clear(),g.setColor(50712),g.setFont("6x8",2),g.setFontAlign(0,-1,0),g.drawString("DIST (KM)",60,32),g.drawString("TIME",180,32),g.drawString("PACE",60,92),g.drawString("HEART",180,92),g.drawString("STEPS",60,152),g.drawString("CADENCE",180,152),i(t),Bangle.drawWidgets()}function a(n){n.status===t.Stopped&&function(t){const n=(new Date).toISOString().replace(/[-:]/g,""),e=`banglerun_${n.substr(2,6)}_${n.substr(9,6)}`;t.file=require("Storage").open(e,"w"),t.fileWritten=!1}(n),n.status===t.Running?n.status=t.Paused:n.status=t.Running,i(n)}const r={fix:NaN,lat:NaN,lon:NaN,alt:NaN,vel:NaN,dop:NaN,gpsValid:!1,x:NaN,y:NaN,z:NaN,t:NaN,timeSinceLog:0,hr:60,hrError:100,file:null,fileWritten:!1,drawing:!1,status:t.Stopped,duration:0,distance:0,speed:0,steps:0,cadence:0};var o;o=r,Bangle.on("GPS",n=>function(n,e){n.lat=e.lat,n.lon=e.lon,n.alt=e.alt,n.vel=e.speed/3.6,n.fix=e.fix,n.dop=e.hdop,n.gpsValid=n.fix>0,function(n){const e=Date.now();let i=(e-n.t)/1e3;if(isFinite(i)||(i=0),n.t=e,n.timeSinceLog+=i,n.status===t.Running&&(n.duration+=i),!n.gpsValid)return;const s=6371008.8+n.alt,a=n.lat*Math.PI/180,r=n.lon*Math.PI/180,o=s*Math.cos(a)*Math.cos(r),g=s*Math.cos(a)*Math.sin(r),d=s*Math.sin(a);if(!n.x)return n.x=o,n.y=g,void(n.z=d);const u=o-n.x,l=g-n.y,c=d-n.z,f=Math.sqrt(u*u+l*l+c*c);n.x=o,n.y=g,n.z=d,n.status===t.Running&&(n.distance+=f,n.speed=n.distance/n.duration||0,n.cadence=60*n.steps/n.duration||0)}(n),i(n),n.gpsValid&&n.status===t.Running&&n.timeSinceLog>5&&(n.timeSinceLog=0,function(t){t.fileWritten||(t.file.write(["timestamp","latitude","longitude","altitude","duration","distance","heartrate","steps"].join(",")+"\n"),t.fileWritten=!0),t.file.write([Date.now().toFixed(0),t.lat.toFixed(6),t.lon.toFixed(6),t.alt.toFixed(2),t.duration.toFixed(0),t.distance.toFixed(2),t.hr.toFixed(0),t.steps.toFixed(0)].join(",")+"\n")}(n))}(o,n)),Bangle.setGPSPower(1),function(t){Bangle.on("HRM",n=>function(t,n){if(0===n.confidence)return;const e=n.bpm-t.hr,i=Math.abs(e)+101-n.confidence,s=t.hrError/(t.hrError+i)||0;t.hr+=e*s,t.hrError+=(i-t.hrError)*s}(t,n)),Bangle.setHRMPower(1)}(r),function(n){Bangle.on("step",()=>function(n){n.status===t.Running&&(n.steps+=1)}(n))}(r),function(t){Bangle.loadWidgets(),Bangle.on("lcdPower",n=>{t.drawing=n,n&&s(t)}),s(t)}(r),setWatch(()=>a(r),BTN1,{repeat:!0,edge:"falling"}),setWatch(()=>function(n){n.status===t.Paused&&function(t){t.duration=0,t.distance=0,t.speed=0,t.steps=0,t.cadence=0}(n),n.status===t.Running?n.status=t.Paused:n.status=t.Stopped,i(n)}(r),BTN3,{repeat:!0,edge:"falling"})}(); diff --git a/apps/banglerun/banglerun.png b/apps/banglerun/banglerun.png deleted file mode 100644 index bf2cd8af3..000000000 Binary files a/apps/banglerun/banglerun.png and /dev/null differ diff --git a/apps/banglerun/interface.html b/apps/banglerun/interface.html deleted file mode 100644 index 6388d3b65..000000000 --- a/apps/banglerun/interface.html +++ /dev/null @@ -1,217 +0,0 @@ - -
- - - - - - - - - diff --git a/apps/banglerun/jasmine.json b/apps/banglerun/jasmine.json deleted file mode 100644 index 813363b27..000000000 --- a/apps/banglerun/jasmine.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "spec_dir": "test", - "spec_files": [ - "**/*.spec.ts" - ] -} \ No newline at end of file diff --git a/apps/banglerun/metadata.json b/apps/banglerun/metadata.json deleted file mode 100644 index d66441c8d..000000000 --- a/apps/banglerun/metadata.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "banglerun", - "name": "BangleRun", - "shortName": "BangleRun", - "version": "0.10", - "description": "An app for running sessions. Displays info and logs your run for later viewing.", - "icon": "banglerun.png", - "tags": "run,running,fitness,outdoors", - "supports": ["BANGLEJS"], - "interface": "interface.html", - "allow_emulator": false, - "storage": [ - {"name":"banglerun.app.js","url":"app.js"}, - {"name":"banglerun.img","url":"app-icon.js","evaluate":true} - ] -} diff --git a/apps/banglerun/package.json b/apps/banglerun/package.json deleted file mode 100644 index 1f5cc677b..000000000 --- a/apps/banglerun/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "banglerun", - "version": "0.5.0", - "description": "Bangle.js app for running sessions", - "main": "app.js", - "types": "app.d.ts", - "scripts": { - "build": "rollup -c", - "test": "ts-node -P tsconfig.spec.json node_modules/jasmine/bin/jasmine --config=jasmine.json" - }, - "author": { - "name": "Stefano Baldan", - "email": "singintime@gmail.com" - }, - "license": "ISC", - "devDependencies": { - "@rollup/plugin-typescript": "^4.1.1", - "@types/jasmine": "^3.5.10", - "jasmine": "^3.5.0", - "rollup": "^2.10.2", - "rollup-plugin-terser": "^5.3.0", - "terser": "^4.7.0", - "ts-node": "^8.10.2", - "tslib": "^2.0.0", - "typescript": "^3.9.2" - } -} diff --git a/apps/banglerun/rollup.config.js b/apps/banglerun/rollup.config.js deleted file mode 100644 index f7027eb2b..000000000 --- a/apps/banglerun/rollup.config.js +++ /dev/null @@ -1,15 +0,0 @@ -import typescript from '@rollup/plugin-typescript'; -import { terser } from 'rollup-plugin-terser'; - -export default { - input: './src/app.ts', - output: { - dir: '.', - format: 'iife', - name: 'banglerun' - }, - plugins: [ - typescript(), - terser(), - ] -}; diff --git a/apps/banglerun/src/activity.ts b/apps/banglerun/src/activity.ts deleted file mode 100644 index c1a01f30b..000000000 --- a/apps/banglerun/src/activity.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { draw } from './display'; -import { initLog } from './log'; -import { ActivityStatus, AppState } from './state'; - -function startActivity(state: AppState): void { - if (state.status === ActivityStatus.Stopped) { - initLog(state); - } - - if (state.status === ActivityStatus.Running) { - state.status = ActivityStatus.Paused; - } else { - state.status = ActivityStatus.Running; - } - - draw(state); -} - -function stopActivity(state: AppState): void { - if (state.status === ActivityStatus.Paused) { - clearActivity(state); - } - - if (state.status === ActivityStatus.Running) { - state.status = ActivityStatus.Paused; - } else { - state.status = ActivityStatus.Stopped; - } - - draw(state); -} - -function clearActivity(state: AppState): void { - state.duration = 0; - state.distance = 0; - state.speed = 0; - state.steps = 0; - state.cadence = 0; -} - -export { clearActivity, startActivity, stopActivity }; diff --git a/apps/banglerun/src/app.ts b/apps/banglerun/src/app.ts deleted file mode 100644 index 7093e24e0..000000000 --- a/apps/banglerun/src/app.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { startActivity, stopActivity } from './activity'; -import { initDisplay } from './display'; -import { initGps } from './gps'; -import { initHrm } from './hrm'; -import { initState } from './state'; -import { initStep } from './step'; - -declare var BTN1: any; -declare var BTN3: any; -declare var setWatch: any; - -const appState = initState(); - -initGps(appState); -initHrm(appState); -initStep(appState); -initDisplay(appState); - -setWatch(() => startActivity(appState), BTN1, { repeat: true, edge: 'falling' }); -setWatch(() => stopActivity(appState), BTN3, { repeat: true, edge: 'falling' }); diff --git a/apps/banglerun/src/display.ts b/apps/banglerun/src/display.ts deleted file mode 100644 index 528890c35..000000000 --- a/apps/banglerun/src/display.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { ActivityStatus, AppState } from './state'; - -declare var Bangle: any; -declare var g: any; - -const STATUS_COLORS = { - 'STOP': 0xF800, - 'PAUSE': 0xFFE0, - 'RUN': 0x07E0, -} - -function initDisplay(state: AppState): void { - Bangle.loadWidgets(); - Bangle.on('lcdPower', (on: boolean) => { - state.drawing = on; - if (on) { - drawAll(state); - } - }); - drawAll(state); -} - -function drawBackground(): void { - g.clear(); - g.setColor(0xC618); - g.setFont('6x8', 2); - g.setFontAlign(0, -1, 0); - g.drawString('DIST (KM)', 60, 32); - g.drawString('TIME', 172, 32); - g.drawString('PACE', 60, 92); - g.drawString('HEART', 172, 92); - g.drawString('STEPS', 60, 152); - g.drawString('CADENCE', 172, 152); -} - -function drawValue(value: string, x: number, y: number) { - g.setColor(0x0000); - g.fillRect(x - 60, y, x + 60, y + 30); - g.setColor(0xFFFF); - g.drawString(value, x, y); -} - -function draw(state: AppState): void { - g.setFontVector(30); - g.setFontAlign(0, -1, 0); - - drawValue(formatDistance(state.distance), 60, 55); - drawValue(formatTime(state.duration), 172, 55); - drawValue(formatPace(state.speed), 60, 115); - drawValue(state.hr.toFixed(0), 172, 115); - drawValue(state.steps.toFixed(0), 60, 175); - drawValue(state.cadence.toFixed(0), 172, 175); - - g.setFont('6x8', 2); - - g.setColor(state.gpsValid ? 0x07E0 : 0xF800); - g.fillRect(0, 216, 80, 240); - g.setColor(0x0000); - g.drawString('GPS', 40, 220); - - g.setColor(0xFFFF); - g.fillRect(80, 216, 160, 240); - g.setColor(0x0000); - g.drawString(formatClock(new Date()), 120, 220); - - g.setColor(STATUS_COLORS[state.status]); - g.fillRect(160, 216, 230, 240); - g.setColor(0x0000); - g.drawString(state.status, 200, 220); - - g.setFont("6x8").setFontAlign(0,0,1).setColor(-1); - if (state.status === ActivityStatus.Paused) { - g.drawString("START",236,60,1).drawString(" CLEAR ",236,180,1); - } else if (state.status === ActivityStatus.Running) { - g.drawString(" PAUSE ",236,60,1).drawString(" PAUSE ",236,180,1); - } else { - g.drawString("START",236,60,1).drawString(" ",236,180,1); - } -} - -function drawAll(state: AppState) { - drawBackground(); - draw(state); - Bangle.drawWidgets(); -} - -function formatClock(date: Date): string { - return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2); -} - -function formatDistance(meters: number): string { - return (meters / 1000).toFixed(2); -} - -function formatPace(speed: number): string { - if (speed < 0.1667) { - return `__'__"`; - } - const pace = Math.round(1000 / speed); - const min = Math.floor(pace / 60); - const sec = pace % 60; - return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`; -} - -function formatTime(time: number): string { - const seconds = Math.round(time); - const hrs = Math.floor(seconds / 3600); - const min = Math.floor(seconds / 60) % 60; - const sec = seconds % 60; - return (hrs ? hrs + ':' : '') + ('0' + min).substr(-2) + `:` + ('0' + sec).substr(-2); -} - -export { - draw, - drawAll, - drawBackground, - drawValue, - formatClock, - formatDistance, - formatPace, - formatTime, - initDisplay, -}; diff --git a/apps/banglerun/src/gps.ts b/apps/banglerun/src/gps.ts deleted file mode 100644 index 1886ecfb2..000000000 --- a/apps/banglerun/src/gps.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { draw } from './display'; -import { updateLog } from './log'; -import { ActivityStatus, AppState } from './state'; - -declare var Bangle: any; - -interface GpsEvent { - lat: number; - lon: number; - alt: number; - speed: number; - hdop: number; - fix: number; -} - -const EARTH_RADIUS = 6371008.8; - -function initGps(state: AppState): void { - Bangle.on('GPS', (gps: GpsEvent) => readGps(state, gps)); - Bangle.setGPSPower(1); -} - -function readGps(state: AppState, gps: GpsEvent): void { - state.lat = gps.lat; - state.lon = gps.lon; - state.alt = gps.alt; - state.vel = gps.speed / 3.6; - state.fix = gps.fix; - state.dop = gps.hdop; - state.gpsValid = state.fix > 0; - - updateGps(state); - draw(state); - - /* Only log GPS data every 5 secs if we - have a fix and we're running. */ - if (state.gpsValid && - state.status === ActivityStatus.Running && - state.timeSinceLog > 5) { - state.timeSinceLog = 0; - updateLog(state); - } -} - -function updateGps(state: AppState): void { - const t = Date.now(); - let dt = (t - state.t) / 1000; - if (!isFinite(dt)) dt=0; - state.t = t; - state.timeSinceLog += dt; - - if (state.status === ActivityStatus.Running) { - state.duration += dt; - } - - if (!state.gpsValid) { - return; - } - - const r = EARTH_RADIUS + state.alt; - const lat = state.lat * Math.PI / 180; - const lon = state.lon * Math.PI / 180; - const x = r * Math.cos(lat) * Math.cos(lon); - const y = r * Math.cos(lat) * Math.sin(lon); - const z = r * Math.sin(lat); - - if (!state.x) { - state.x = x; - state.y = y; - state.z = z; - return; - } - - const dx = x - state.x; - const dy = y - state.y; - const dz = z - state.z; - const dpMag = Math.sqrt(dx * dx + dy * dy + dz * dz); - - state.x = x; - state.y = y; - state.z = z; - - if (state.status === ActivityStatus.Running) { - state.distance += dpMag; - state.speed = (state.distance / state.duration) || 0; - state.cadence = (60 * state.steps / state.duration) || 0; - } -} - -export { initGps, readGps, updateGps }; diff --git a/apps/banglerun/src/hrm.ts b/apps/banglerun/src/hrm.ts deleted file mode 100644 index 08dd237a7..000000000 --- a/apps/banglerun/src/hrm.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { AppState } from './state'; - -interface HrmData { - bpm: number; - confidence: number; - raw: string; -} - -declare var Bangle: any; - -function initHrm(state: AppState) { - Bangle.on('HRM', (hrm: HrmData) => updateHrm(state, hrm)); - Bangle.setHRMPower(1); -} - -function updateHrm(state: AppState, hrm: HrmData) { - if (hrm.confidence === 0) { - return; - } - - const dHr = hrm.bpm - state.hr; - const hrError = Math.abs(dHr) + 101 - hrm.confidence; - const hrGain = (state.hrError / (state.hrError + hrError)) || 0; - - state.hr += dHr * hrGain; - state.hrError += (hrError - state.hrError) * hrGain; -} - -export { initHrm, updateHrm }; diff --git a/apps/banglerun/src/log.ts b/apps/banglerun/src/log.ts deleted file mode 100644 index b6714e407..000000000 --- a/apps/banglerun/src/log.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { AppState } from './state'; - -declare var require: any; - -function initLog(state: AppState): void { - const datetime = new Date().toISOString().replace(/[-:]/g, ''); - const date = datetime.substr(2, 6); - const time = datetime.substr(9, 6); - const filename = `banglerun_${date}_${time}`; - state.file = require('Storage').open(filename, 'w'); - state.fileWritten = false; -} - -function updateLog(state: AppState): void { - if (!state.fileWritten) { - state.file.write([ - 'timestamp', - 'latitude', - 'longitude', - 'altitude', - 'duration', - 'distance', - 'heartrate', - 'steps', - ].join(',') + '\n'); - state.fileWritten = true; - } - state.file.write([ - Date.now().toFixed(0), - state.lat.toFixed(6), - state.lon.toFixed(6), - state.alt.toFixed(2), - state.duration.toFixed(0), - state.distance.toFixed(2), - state.hr.toFixed(0), - state.steps.toFixed(0), - ].join(',') + '\n'); -} - -export { initLog, updateLog }; diff --git a/apps/banglerun/src/state.ts b/apps/banglerun/src/state.ts deleted file mode 100644 index 14ef2dc5d..000000000 --- a/apps/banglerun/src/state.ts +++ /dev/null @@ -1,85 +0,0 @@ -enum ActivityStatus { - Stopped = 'STOP', - Paused = 'PAUSE', - Running = 'RUN', -} - -interface AppState { - // GPS NMEA data - fix: number; - lat: number; - lon: number; - alt: number; - vel: number; - dop: number; - gpsValid: boolean; - - // Absolute position data - x: number; - y: number; - z: number; - // Last fix time - t: number; - // Last time we saved log info - timeSinceLog : number; - - // HRM data - hr: number, - hrError: number, - - // Logger data - file: File; - fileWritten: boolean; - - // Drawing data - drawing: boolean; - - // Activity data - status: ActivityStatus; - duration: number; - distance: number; - speed: number; - steps: number; - cadence: number; -} - -interface File { - read: Function; - write: Function; - erase: Function; -} - -function initState(): AppState { - return { - fix: NaN, - lat: NaN, - lon: NaN, - alt: NaN, - vel: NaN, - dop: NaN, - gpsValid: false, - - x: NaN, - y: NaN, - z: NaN, - t: NaN, - timeSinceLog : 0, - - hr: 60, - hrError: 100, - - file: null, - fileWritten: false, - - drawing: false, - - status: ActivityStatus.Stopped, - duration: 0, - distance: 0, - speed: 0, - steps: 0, - cadence: 0, - } -} - -export { ActivityStatus, AppState, File, initState }; diff --git a/apps/banglerun/src/step.ts b/apps/banglerun/src/step.ts deleted file mode 100644 index c7fcb61ea..000000000 --- a/apps/banglerun/src/step.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ActivityStatus, AppState } from './state'; - -declare var Bangle: any; - -function initStep(state: AppState) { - Bangle.on('step', () => updateStep(state)); -} - -function updateStep(state: AppState) { - if (state.status === ActivityStatus.Running) { - state.steps += 1; - } -} - -export { initStep, updateStep }; diff --git a/apps/banglerun/tsconfig.json b/apps/banglerun/tsconfig.json deleted file mode 100644 index a341a5a5e..000000000 --- a/apps/banglerun/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "module": "es2015", - "noImplicitAny": true, - "target": "es2015" - }, - "include": [ - "src" - ] -} diff --git a/apps/banglerun/tsconfig.spec.json b/apps/banglerun/tsconfig.spec.json deleted file mode 100644 index 136ae137b..000000000 --- a/apps/banglerun/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "noImplicitAny": true, - "target": "es2015" - }, - "include": [ - "test" - ] -} diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index 254124d4e..115c8f2ff 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -1,3 +1,4 @@ 0.01: first release 0.02: added settings menu to change color 0.03: fix metadata.json to allow setting as clock +0.04: added heart rate which is switched on when cycled to it through up/down touch on rhs diff --git a/apps/daisy/README.md b/apps/daisy/README.md index 3f22f5dd9..12a55ddfd 100644 --- a/apps/daisy/README.md +++ b/apps/daisy/README.md @@ -1,4 +1,4 @@ -# Daisy +# Daisy  *A beautiful digital clock with large ring guage, idle timer and a cyclic information line that includes, day, date, steps, battery, @@ -8,15 +8,20 @@ Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) -* Derived from `The Ring` proof of concept and the [Pastel clock](https://banglejs.com/apps/?q=pastel) +* Derived from [The Ring](https://banglejs.com/apps/?id=thering) proof of concept and the [Pastel clock](https://banglejs.com/apps/?q=pastel) * Includes the [Lazybones](https://banglejs.com/apps/?q=lazybones) Idle warning timer -* Touch the top right/top left to cycle through the info display (Day, Date, Steps, Sunrise, Sunset) +* Touch the top right/top left to cycle through the info display (Day, Date, Steps, Sunrise, Sunset, Heart Rate) +* The heart rate monitor is turned on only when Heart rate is selected and will take a few seconds to settle +* The heart value is displayed in RED if the confidence value is less than 50% +* NOTE: The heart rate monitor of Bangle JS 2 is not very accurate when moving about. +See [#1248](https://github.com/espruino/BangleApps/issues/1248) * Uses mylocation.json from MyLocation app to calculate sunrise and sunset times for your location +* If your Sunrise, Sunset times look odd make sure you have setup your location using +[MyLocation](https://banglejs.com/apps/?id=mylocation) * The screen is updated every minute to save battery power * Uses the [BloggerSansLight](https://www.1001fonts.com/rounded-fonts.html?page=3) font, which if free for commercial use ## Future Development -* Add a heart rate option in the information line that turns on when selected * Use mini icons in the information line rather that text * Add weather icons as per Pastel clock * Add a lock icon to the screen @@ -25,5 +30,3 @@ Forum](http://forum.espruino.com/microcosms/1424/)  It is worth looking at the real thing though as the screenshot does not do it justice. -(Though I need to redo this photo at some point) - diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 2717f94db..01d177a32 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -14,16 +14,19 @@ let warned = 0; let idle = false; let IDLE_MINUTES = 26; -var pal1; // palette for 0-40% -var pal2; // palette for 50-100% -const infoWidth = 50; -const infoHeight = 14; +let pal1; // palette for 0-40% +let pal2; // palette for 50-100% +const infoLine = (3*h/4) - 6; +const infoWidth = 56; +const infoHeight = 11; var drawingSteps = false; function log_debug(o) { //print(o); } +var hrmImg = require("heatshrink").decompress(atob("i0WgIKHgPh8Ef5/g///44CBz///1///5A4PnBQk///wA4PBA4MDA4MH/+Ah/8gEP4EAjw0GA")); + // https://www.1001fonts.com/rounded-fonts.html?page=3 Graphics.prototype.setFontBloggerSansLight46 = function(scale) { // Actual height 46 (45 - 0) @@ -109,7 +112,8 @@ const infoData = { ID_SR: { calc: () => 'Sunrise: ' + sunRise }, ID_SS: { calc: () => 'Sunset: ' + sunSet }, ID_STEP: { calc: () => 'Steps: ' + getSteps() }, - ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' } + ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' }, + ID_HRM: { calc: () => hrmCurrent } }; const infoList = Object.keys(infoData).sort(); @@ -121,6 +125,9 @@ function nextInfo() { if (idx === infoList.length - 1) infoMode = infoList[0]; else infoMode = infoList[idx + 1]; } + // power HRM on/off accordingly + Bangle.setHRMPower(infoMode == "ID_HRM" ? 1 : 0); + resetHrm(); } function prevInfo() { @@ -129,8 +136,125 @@ function prevInfo() { if (idx === 0) infoMode = infoList[infoList.length - 1]; else infoMode = infoList[idx - 1]; } + // power HRM on/off accordingly + Bangle.setHRMPower(infoMode == "ID_HRM" ? 1 : 0); + resetHrm(); } +function clearInfo() { + g.setColor(g.theme.bg); + //g.setColor(g.theme.fg); + g.fillRect((w/2) - infoWidth, infoLine - infoHeight, (w/2) + infoWidth, infoLine + infoHeight); +} + +function drawInfo() { + clearInfo(); + g.setColor(g.theme.fg); + setSmallFont(); + g.setFontAlign(0,0); + + if (infoMode == "ID_HRM") { + clearInfo(); + g.setColor('#f00'); // red + drawHeartIcon(); + } else { + g.drawString((infoData[infoMode].calc()), w/2, infoLine); + } +} + +function drawHeartIcon() { + g.drawImage(hrmImg, (w/2) - infoHeight - 20, infoLine - infoHeight); +} + +function drawHrm() { + if (idle) return; // dont draw while prompting + var d = new Date(); + clearInfo(); + g.setColor(d.getSeconds()&1 ? '#f00' : g.theme.bg); + drawHeartIcon(); + setSmallFont(); + g.setFontAlign(-1,0); // left + g.setColor(hrmConfidence >= 50 ? g.theme.fg : '#f00'); + g.drawString(hrmCurrent, (w/2) + 10, infoLine); +} + +function draw() { + if (!idle) + drawClock(); + else + drawIdle(); + queueDraw(); +} + +function drawClock() { + var date = new Date(); + var timeStr = require("locale").time(date,1); + var da = date.toString().split(" "); + var time = da[4].substr(0,5); + var hh = da[4].substr(0,2); + var mm = da[4].substr(3,2); + var steps = getSteps(); + var p_steps = Math.round(100*(steps/10000)); + + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(0, 0, w, h); + g.drawImage(getGaugeImage(p_steps), 0, 0); + setLargeFont(); + + g.setColor(settings.fg); + g.setFontAlign(1,0); // right aligned + g.drawString(hh, (w/2) - 1, h/2); + + g.setColor(g.theme.fg); + g.setFontAlign(-1,0); // left aligned + g.drawString(mm, (w/2) + 1, h/2); + + drawInfo(); + + // recalc sunrise / sunset every hour + if (drawCount % 60 == 0) + updateSunRiseSunSet(new Date(), location.lat, location.lon); + drawCount++; +} + +function drawSteps() { + if (drawingSteps) return; + drawingSteps = true; + clearInfo(); + setSmallFont(); + g.setFontAlign(0,0); + g.setColor(g.theme.fg); + g.drawString('Steps ' + getSteps(), w/2, (3*h/4) - 4); + drawingSteps = false; +} + +///////////////// GAUGE images ///////////////////////////////////// + +var hrmCurrent = "--"; +var hrmConfidence = 0; + +function resetHrm() { + hrmCurrent = "--"; + hrmConfidence = 0; + if (infoMode == "ID_HRM") { + clearInfo(); + g.setColor('#f00'); // red + drawHeartIcon(); + } +} + +Bangle.on('HRM', function(hrm) { + hrmCurrent = hrm.bpm; + hrmConfidence = hrm.confidence; + log_debug("HRM=" + hrm.bpm + " (" + hrm.confidence + ")"); + if (infoMode == "ID_HRM" ) drawHrm(); +}); + + +///////////////// GAUGE images ///////////////////////////////////// + + // putting into 1 function like this, rather than individual variables // reduces ram usage from 70%-13% function getGaugeImage(p) { @@ -247,68 +371,6 @@ function getGaugeImage(p) { }; } -function draw() { - if (!idle) - drawClock(); - else - drawIdle(); - queueDraw(); -} - -function drawClock() { - var date = new Date(); - var timeStr = require("locale").time(date,1); - var da = date.toString().split(" "); - var time = da[4].substr(0,5); - var hh = da[4].substr(0,2); - var mm = da[4].substr(3,2); - var steps = getSteps(); - var p_steps = Math.round(100*(steps/10000)); - - g.reset(); - g.setColor(g.theme.bg); - g.fillRect(0, 0, w, h); - g.drawImage(getGaugeImage(p_steps), 0, 0); - setLargeFont(); - - g.setColor(settings.fg); - g.setFontAlign(1,0); // right aligned - g.drawString(hh, (w/2) - 1, h/2); - - g.setColor(g.theme.fg); - g.setFontAlign(-1,0); // left aligned - g.drawString(mm, (w/2) + 1, h/2); - - setSmallFont(); - g.setFontAlign(0,0); // left aligned - g.drawString((infoData[infoMode].calc()), w/2, (3*h/4) - 4); - - // recalc sunrise / sunset every hour - if (drawCount % 60 == 0) - updateSunRiseSunSet(new Date(), location.lat, location.lon); - drawCount++; -} - -function drawSteps() { - if (drawingSteps) return; - drawingSteps = true; - setSmallFont(); - g.setFontAlign(0,0); - var steps = getSteps(); - g.setColor(g.theme.bg); - g.fillRect((w/2) - infoWidth, (3*h/4) - infoHeight, (w/2) + infoWidth, (3*h/4) + infoHeight); - g.setColor(g.theme.fg); - g.drawString('Steps ' + steps, w/2, (3*h/4) - 4); - drawingSteps = false; -} - -/* -Bangle.on('step', s => { - drawSteps(); -}); -*/ - - ///////////////// IDLE TIMER ///////////////////////////////////// function drawIdle() { @@ -392,6 +454,8 @@ Bangle.on('step', s => { } idle = false; warned = 0; + + if (infoMode == "ID_STEP") drawSteps(); }); function checkIdle() { diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index f4a9fcbbe..5e53f2d5e 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.03", + "version":"0.04", "dependencies": {"mylocation":"app"}, "description": "A clock based on the Pastel clock with large ring guage for steps", "icon": "app.png", diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index 556472eaa..811784b39 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -6,3 +6,5 @@ 0.06: Adds settings page (hide clocks or launchers) 0.07: Adds setting for directly launching app on touch for Bangle 2 0.08: Optimize line wrapping for Bangle 2 +0.09: fix the trasparent widget bar if there are no widgets for Bangle 2 +0.10: added "one click exit" setting for Bangle 2 diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index 96e562add..e0f7f825f 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -6,8 +6,12 @@ var settings = Object.assign({ showClocks: true, showLaunchers: true, direct: false, + oneClickExit:false }, require('Storage').readJSON("dtlaunch.json", true) || {}); +if( settings.oneClickExit) + setWatch(_=> load(), BTN1); + var s = require("Storage"); var apps = s.list(/\.info$/).map(app=>{ var a=s.readJSON(app,1); @@ -125,5 +129,6 @@ Bangle.on("touch",(_,p)=>{ }); Bangle.loadWidgets(); +g.clear(); Bangle.drawWidgets(); drawPage(0); diff --git a/apps/dtlaunch/metadata.json b/apps/dtlaunch/metadata.json index 6cd1dbe73..7a4094e54 100644 --- a/apps/dtlaunch/metadata.json +++ b/apps/dtlaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.08", + "version": "0.10", "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "icon": "icon.png", diff --git a/apps/dtlaunch/settings-b2.js b/apps/dtlaunch/settings-b2.js index 7f667d213..8eca46a7e 100644 --- a/apps/dtlaunch/settings-b2.js +++ b/apps/dtlaunch/settings-b2.js @@ -4,7 +4,8 @@ var settings = Object.assign({ showClocks: true, showLaunchers: true, - direct: false + direct: false, + oneClickExit:false }, require('Storage').readJSON(FILE, true) || {}); function writeSettings() { @@ -37,6 +38,14 @@ settings.direct = v; writeSettings(); } + }, + 'One click exit': { + value: settings.oneClickExit, + format: v => v?"On":"Off", + onchange: v => { + settings.oneClickExit = v; + writeSettings(); + } } }); }) diff --git a/apps/gpsautotime/ChangeLog b/apps/gpsautotime/ChangeLog index 5560f00bc..2827c9e5c 100644 --- a/apps/gpsautotime/ChangeLog +++ b/apps/gpsautotime/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Set Bangle.js 2 compatible diff --git a/apps/gpsautotime/metadata.json b/apps/gpsautotime/metadata.json index a64a45f6d..766961276 100644 --- a/apps/gpsautotime/metadata.json +++ b/apps/gpsautotime/metadata.json @@ -2,12 +2,12 @@ "id": "gpsautotime", "name": "GPS auto time", "shortName": "GPS auto time", - "version": "0.01", + "version": "0.02", "description": "A widget that automatically updates the Bangle.js time to the GPS time whenever there is a valid GPS fix.", "icon": "widget.png", "type": "widget", "tags": "widget,gps", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"gpsautotime.wid.js","url":"widget.js"} ] diff --git a/apps/pooqroman/app.js b/apps/pooqroman/app.js index bed8ef3d2..fcb2437e1 100644 --- a/apps/pooqroman/app.js +++ b/apps/pooqroman/app.js @@ -353,13 +353,15 @@ const events = { let c, p, i, l = from - o, h = to - o; for (i = 0; (c = this.wall[i]).time < l; i++) ; for (; (c = this.wall[i]).time < h; i++) { - if ((p = c.time < t) ? c.past : c.future) + p = c.time < t; + if (p ? c.past : c.future) result = Math.min(result, f(c, new Date(c.time + o), p)); } l += o; h += o; t += o; for (i = 0; (c = this.fixed[i]).time < l; i++) ; for (; (c = this.fixed[i]).time < h; i++) { - if ((p = c.time < t) ? c.past : c.future) + p = c.time < t; + if (p ? c.past : c.future) result = Math.min(f(c, new Date(c.time), p)); } return result; diff --git a/apps/pooqroman/resourcer.js b/apps/pooqroman/resourcer.js index 69365018e..8b95dc834 100644 --- a/apps/pooqroman/resourcer.js +++ b/apps/pooqroman/resourcer.js @@ -60,7 +60,8 @@ const prepFont = (name, data) => { let width = m[2] == '*' ? null : +m[2]; let c = null, o = 0; lines.forEach((line, l) => { - if (m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line)) { + m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line); + if (m) { const h = m[2] == '='; if (m[1].length > desc || h && m[1].length != desc) throw new Error('Invalid descender height at ' + l); diff --git a/apps/pooqround/resourcer.js b/apps/pooqround/resourcer.js index 17c35a40d..6b969a102 100644 --- a/apps/pooqround/resourcer.js +++ b/apps/pooqround/resourcer.js @@ -60,7 +60,8 @@ const prepFont = (name, data) => { let width = m[2] == '*' ? null : +m[2]; let c = null, o = 0; lines.forEach((line, l) => { - if (m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line)) { + m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line); + if (m) { const h = m[2] == '='; if (m[1].length > desc || h && m[1].length != desc) throw new Error('Invalid descender height at ' + l); diff --git a/apps/run/README.md b/apps/run/README.md index 17975f92c..5b3bb635a 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -46,8 +46,8 @@ record GPS/HRM/etc data every time you start a run? ## Development -This app uses the [`exstats` module](/modules/exstats.js). When uploaded via the +This app uses the [`exstats` module](https://github.com/espruino/BangleApps/blob/master/modules/exstats.js). When uploaded via the app loader, the module is automatically included in the app's source. However when developing via the IDE the module won't get pulled in by default. -There are some options to fix this easily - please check out the [modules README.md file](/modules/README.md) +There are some options to fix this easily - please check out the [modules README.md file](https://github.com/espruino/BangleApps/blob/master/modules/README.md) diff --git a/apps/smclock/ChangeLog b/apps/smclock/ChangeLog index b029d805d..0300d5ceb 100644 --- a/apps/smclock/ChangeLog +++ b/apps/smclock/ChangeLog @@ -1,2 +1,4 @@ 0.01: Initial version 0.02: Add battery level +0.03: Fix battery display when full +0.04: Add support for settings diff --git a/apps/smclock/README.md b/apps/smclock/README.md index 7b5613147..635292d0c 100644 --- a/apps/smclock/README.md +++ b/apps/smclock/README.md @@ -3,3 +3,21 @@ Just a simple watch face for the Banglejs2. It shows battery level in the upper left corner, date information in the upper right, and time information in the bottom. + + + +## Settings + +**Analog Clock:** + +**Human Readable Date:** When the setting is on, the date is shown in a more human-friendly format (e.g. "Oct 2"), otherwise the date is shown in a standard format (e.g. "02/10"). Default is off. + +**Show Week Info:** When the setting is on, the weekday and week number are shown in the upper right box. When the setting is off, the full year is shown instead. Default is off. + +**Vector Font:** When the setting is on, the app uses Espruino's vector font, otherwise it uses the default font. Default is off. + +## Using the app + +Monogram Watch Face can be selected as the default clock or it can be run manually from the launcher. Its settings can be accessed and changed via the relevant menu. + +Tapping on the "Alerts" area will replace the current time display with the time of the most immediate alert. diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 6aff72a46..350c0dd07 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -1,48 +1,81 @@ +const SETTINGSFILE = "smclock.json"; const background = { - width : 176, height : 176, bpp : 3, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4A/AH4ACUb8H9MkyVJAThB/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/INP/AH4A/AAX8Yz4Afn5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/INI=")) + width: 176, + height: 176, + bpp: 3, + transparent: 1, + buffer: require("heatshrink").decompress( + atob( + "/4A/AH4ACUb8H9MkyVJAThB/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/INP/AH4A/AAX8Yz4Afn5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/IP5B/INI=" + ) + ), }; +const monthName = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; +const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; -const weekday = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]; -var level = -1; +// dynamic variables +var batLevel = -1; +var batColor = [0, 0, 0]; -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); +// settings variables +var dateFormat; +var drawInterval; +var pollInterval; +var showAnalogFace; +var showWeekInfo; +var useVectorFont; + +// load settings +function loadSettings() { + // Helper function default setting + function def(value, def) {return value !== undefined ? value : def;} + var settings = require("Storage").readJSON(SETTINGSFILE, true) || {}; + + dateFormat = def(settings.dateFormat, "Short"); + drawInterval = def(settings.drawInterval, 10); + pollInterval = def(settings.pollInterval, 60); + showAnalogFace = def(settings.showAnalogFace, false); + showWeekInfo = def(settings.showWeekInfo, false); + useVectorFont = def(settings.useVectorFont, false); +} + +// 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) { - return ('0' + value).substr(-2); + return ("0" + value).substr(-2); } function pollBattery() { - level = E.getBattery(); - return level; + batLevel = E.getBattery(); } function getBatteryColor(level) { var color; if (level < 0) { - level = pollBattery(); + pollBattery(); + level = batLevel; } - if(level>80) { - color = [0,0,1]; - } else if(level>60) { - color = [0,1,1]; - } else if(level>40) { - color = [0,1,0]; - } else if(level>20) { - color = [1,1,0]; + if (level > 80) { + color = [0, 0, 1]; + } else if (level > 60) { + color = [0, 1, 1]; + } else if (level > 40) { + color = [0, 1, 0]; + } else if (level > 20) { + color = [1, 1, 0]; } else { - color = [1,0,0]; + color = [1, 0, 0]; } return color; } @@ -50,57 +83,110 @@ function getBatteryColor(level) { function draw() { g.drawImage(background); - const color = getBatteryColor(); - const bat = d02(E.getBattery()) + "%"; + const color = getBatteryColor(batLevel); + var bat = ""; const d = new Date(); const day = d.getDate(); - const month = (d.getMonth() + 1); + const month = d.getMonth() + 1; const week = d02(ISO8601_week_no(d)); - const date1 = d02(day) + "/" + d02(month); - const date2 = weekday[d.getDay()] + " " + d02(week); + var date1 = ""; + var date2 = ""; const h = d.getHours(); const m = d.getMinutes(); const time = d02(h) + ":" + d02(m); + if (E.getBattery() < 100) { + bat = d02(E.getBattery()) + "%"; + } else { + bat = E.getBattery() + "%"; + } + g.reset(); - g.setColor(0, 0, 0); - g.setFont("Vector", 20); - g.drawString(date1, 105, 20, false); - g.setFont("Vector", 16); - g.drawString(date2, 105, 55, false); - + // draw battery info g.setColor(1, 1, 1); - g.setFont("Vector", 60); - g.drawString(time, 10, 108, false); - - g.setColor(1, 1, 1); - g.setFont("Vector", 16); - g.drawString("Bat:", 12, 22, false); + if (useVectorFont == true) { + g.setFont("Vector", 16); + g.drawString("Bat:", 12, 22, false); + } else { + g.setFont("4x6", 2); + g.drawString("Bat:", 10, 22, false); + } g.setColor(color[0], color[1], color[2]); - g.drawString(bat, 52, 22, false); + if (batLevel < 100) { + g.drawString(bat, 52, 22, false); + } else { + g.drawString(bat, 46, 22, false); + } + + // draw date info + g.setColor(0, 0, 0); + if (useVectorFont == true) { + g.setFont("Vector", 20); + } else { + g.setFont("6x8", 2); + } + if (dateFormat == "Short") { + date1 = d02(day) + "/" + d02(month); + g.drawString(date1, 105, 20, false); + } else { + date1 = monthName[month - 1] + d02(day); + g.drawString(date1, 104, 20, false); + } + + // draw week info + if (showWeekInfo == true) { + date2 = weekday[d.getDay()] + " " + d02(week) + if (useVectorFont == true) { + g.setFont("Vector", 18); + } else { + g.setFont("6x8", 2); + } + g.drawString(date2, 105, 55, false); + } else { + date2 = d.getFullYear(); + if (useVectorFont == true) { + g.setFont("Vector", 22); + g.drawString(date2, 105, 55, false); + } else { + g.setFont("4x6", 3); + g.drawString(date2, 108, 55, false); + } + } + + // draw time + g.setColor(1, 1, 1); + if (useVectorFont == true) { + g.setFont("Vector", 60); + g.drawString(time, 10, 108, false); + } else { + g.setFont("6x8", 5); + g.drawString(time, 14, 112, false); + } } +loadSettings(); + g.clear(); pollBattery(); draw(); -var batInterval = setInterval(pollBattery, 60000); -var drawInterval = setInterval(draw, 10000); +var batInterval = setInterval(pollBattery, pollInterval * 1000); +var actualDrawInterval = setInterval(draw, drawInterval * 1000); // Stop updates when LCD is off, restart when on -Bangle.on('lcdPower',on=>{ +Bangle.on("lcdPower", (on) => { if (batInterval) clearInterval(batInterval); batInterval = undefined; - if (drawInterval) clearInterval(drawInterval); - drawInterval = undefined; + if (actualDrawInterval) clearInterval(actualDrawInterval); + actualDrawInterval = undefined; if (on) { - batInterval = setInterval(pollBattery, 60000); - drawInterval = setInterval(draw, 10000); - + batInterval = setInterval(pollBattery, pollInterval * 1000); + actualDrawInterval = setInterval(draw, drawInterval * 1000); + pollBattery(); - draw(); // draw immediately + draw(); } }); diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 1783ca7bf..cc995d587 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -1,16 +1,20 @@ { - "id":"smclock", - "name":"Monogram Watch Face", - "shortName":"MonoClock", - "icon":"app.png", - "version":"0.02", + "id": "smclock", + "name": "Monogram Watch Face", + "shortName": "MonoClock", + "icon": "app.png", + "screenshots": [{ "url": "screenshot.png" }], + "version": "0.04", "description": "A simple watchface based on my stylised monogram.", - "tags":"clock", - "readme":"README.md", - "supports" : ["BANGLEJS2"], + "type": "clock", + "tags": "clock", + "readme": "README.md", + "supports": ["BANGLEJS", "BANGLEJS2"], "allow_emulator": true, "storage": [ - {"name":"smclock.app.js","url":"app.js"}, - {"name":"smclock.img","url":"app-icon.js","evaluate":true} - ] + { "name": "smclock.app.js", "url": "app.js" }, + { "name": "smclock.settings.js", "url": "settings.js" }, + { "name": "smclock.img", "url": "app-icon.js", "evaluate": true } + ], + "data": [{ "name": "smclock.json" }] } diff --git a/apps/smclock/screenshot.png b/apps/smclock/screenshot.png new file mode 100644 index 000000000..c0e0bd0ee Binary files /dev/null and b/apps/smclock/screenshot.png differ diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js new file mode 100644 index 000000000..a6c7d1b98 --- /dev/null +++ b/apps/smclock/settings.js @@ -0,0 +1,94 @@ +// settings menu for Monogram Watch Face +// Anton Clock settings were used as template +// helper functions taken from Anton Clock + +(function (back) { + var FILE = "smclock.json"; + // load settings from the file + // assign default values if it doesn't exist + var settings = Object.assign({ + dateFormat: "Short", + drawInterval: 10, + pollInterval: 60, + showAnalogFace: false, + showWeekInfo: false, + useVectorFont: false, + }, require("Storage").readJSON(FILE, true) || {}); + + // write the new settings to the file + function writeSettings() {require("Storage").writeJSON(FILE, settings);} + + // helper method which uses int-based menu item for set of string values + function stringItems(startvalue, writer, values) { + return { + value: startvalue === undefined ? 0 : values.indexOf(startvalue), + format: v => values[v], + min: 0, + max: values.length - 1, + wrap: true, + step: 1, + onchange: v => { + writer(values[v]); + writeSettings(); + }, + }; + } + + // helper method which breaks string set settings down to local settings object + function stringInSettings(name, values) { + return stringItems(settings[name], (v) => (settings[name] = v), values); + } + + // settings menu + var mainmenu = { + "": {title: "Monogram Clock",}, + "< Back": () => back(), + "Analog Face": { + value: + settings.showAnalogFace !== undefined ? settings.showAnalogFace : false, + format: v => v ? "On" : "Off", + onchange: v => { + settings.showAnalogFace = v; + writeSettings(); + }, + }, + Date: stringInSettings("dateFormat", ["Long", "Short"]), + "Draw Interval": { + value: settings.drawInterval, + onchange: v => { + settings.drawInterval = v; + writeSettings(); + }, + }, + "Poll Interval": { + value: settings.pollInterval, + onchange: v => { + settings.pollInterval = v; + writeSettings(); + }, + }, + "Week Info": { + value: + settings.showWeekInfo !== undefined ? settings.showWeekInfo : false, + format: v => v ? "On" : "Off", + onchange: v => { + settings.showWeekInfo = v; + writeSettings(); + }, + }, + "Vector Font": { + value: + settings.useVectorFont !== undefined ? settings.useVectorFont : false, + format: v => v ? "On" : "Off", + onchange: v => { + settings.useVectorFont = v; + writeSettings(); + }, + }, + }; + + // Actually display the menu + E.showMenu(mainmenu); +}); + +// end of file diff --git a/apps/snek/snek.icon.js b/apps/snek/snek.icon.js index b820ffcf7..c9a17eee3 100644 --- a/apps/snek/snek.icon.js +++ b/apps/snek/snek.icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("oFA4X/AAOJksvr2rmokYgWqB7sq/2AB5krgYPMgW8ioPc1X9i/oLplVqv+1BdK1OV//q9QPMv4PL1eqy/q1SRK3tVu+AgWCFxP96t+Vhn9qoPLgWr/+//wFBSBEq3/qlW+JwJ/I3eXDQIOBB5OrB5sC3xMD1WAH4+r6xsOtSpKLoYPN1fV1bpKTYf+RJAeDytXFxoPOdQYPNPpkCy1VtQPc6wvO62Vu+CbhfVN4P//+q//uMgwPH9QPH3tqqtpqoABv4wHfoOpBoP/6tVUg7uBFwIvB3xlIB4v+OpJsC1WA1fVQpiGCB52+uzlMB58A31XB5sqy4PNlYPfH50rywPN3++BxgPPgW9V5kCZ4L/HBwmq/tX1APM/4PMBwNVvxuKgW/tP/HxUq1X+1eqFxQPRAAKsLB4KqNAFY=")) +require("heatshrink").decompress(atob("mEwwcBkmSpICZqVECJ+SCJ+UxIRP0lIggRNlckxFICJlKrYGCsmJNBfZsmSpdkyIRL7YRBAwIRLAYQyLNAQRPkoGDCJlLBwQmBAoZ6HBYI4Cy3ZCJVZCITpLymSCIhWMF4IRMlMky3JkTRMAYTjNqREBCJ4DCX5gRD2IRO5MlCKAjQRgOSkslBIRrMUoO2fZVSpdkyQ4BBIWRUJNtBIzpHWYYCCpYRJa4RWDEZQCH0oR0yuyCJ+UCKI1QEaOkCKI1PAYQgMyQDDNBwDBxIRLdgOydgQRKqVJloROyVLthWOpQONAUIA=")) diff --git a/apps/speedalt2/app.js b/apps/speedalt2/app.js index 73fa3bacb..ed16131a4 100644 --- a/apps/speedalt2/app.js +++ b/apps/speedalt2/app.js @@ -179,7 +179,8 @@ var buf = Graphics.createArrayBuffer(240,160,2,{msb:true}); let LED = // LED as minimal and only definition (as instance / singleton) { isOn: false // status on / off, not needed if you don't need to ask for it , set: function(v) { // turn on w/ no arg or truey, else off - g.setColor((this.isOn=(v===undefined||!!v))?1:0,0,0).fillCircle(120,10,10); } + this.isOn = v===undefined||!!v; + g.setColor(this.isOn?1:0,0,0).fillCircle(120,10,10); } , reset: function() { this.set(false); } // turn off , write: function(v) { this.set(v); } // turn on w/ no arg or truey, else off , toggle: function() { this.set( ! this.isOn); } // toggle the LED diff --git a/apps/weatherClock/app.js b/apps/weatherClock/app.js index 1a7f53f05..91d0ab36f 100644 --- a/apps/weatherClock/app.js +++ b/apps/weatherClock/app.js @@ -71,7 +71,6 @@ function chooseIconByCode(code) { case 801: return partSunIcon; default: return cloudIcon; } - break; default: return cloudIcon; } } diff --git a/apps/widChargingStatus/ChangeLog b/apps/widChargingStatus/ChangeLog index 1033c0cd3..5a6db5cb7 100644 --- a/apps/widChargingStatus/ChangeLog +++ b/apps/widChargingStatus/ChangeLog @@ -1 +1,2 @@ 0.01: First release. +0.02: No functional changes, just moved codebase to Typescript. diff --git a/apps/widChargingStatus/metadata.json b/apps/widChargingStatus/metadata.json index f68ccf5b4..573c594e7 100644 --- a/apps/widChargingStatus/metadata.json +++ b/apps/widChargingStatus/metadata.json @@ -2,7 +2,7 @@ "name": "Charging Status", "shortName":"ChargingStatus", "icon": "widget.png", - "version":"0.01", + "version":"0.02", "type": "widget", "description": "A simple widget that shows a yellow lightning icon to indicate whenever the watch is charging. This way one can see the charging status at a glance, no matter which battery widget is being used.", "tags": "widget", diff --git a/apps/widChargingStatus/widget.js b/apps/widChargingStatus/widget.js index 90f9199fa..5d9ea3837 100644 --- a/apps/widChargingStatus/widget.js +++ b/apps/widChargingStatus/widget.js @@ -1,31 +1,33 @@ -(() => { - const icon = require("heatshrink").decompress(atob("ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA")); - const iconWidth = 18; - - function draw() { - g.reset(); - if (Bangle.isCharging()) { - g.setColor("#FD0"); - g.drawImage(icon, this.x + 1, this.y + 1, { - scale: 0.6875 - }); - } - } - - WIDGETS.chargingStatus = { - area: 'tr', - width: Bangle.isCharging() ? iconWidth : 0, - draw: draw, - }; - - Bangle.on('charging', (charging) => { - if (charging) { - Bangle.buzz(); - WIDGETS.chargingStatus.width = iconWidth; - } else { - WIDGETS.chargingStatus.width = 0; - } - Bangle.drawWidgets(); // re-layout widgets - g.flip(); - }); -})(); \ No newline at end of file +"use strict"; +(() => { + const icon = require('heatshrink').decompress(atob('ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA')); + const iconWidth = 18; + function draw() { + g.reset(); + if (Bangle.isCharging()) { + g.setColor('#FD0'); + g.drawImage(icon, this.x + 1, this.y + 1, { + scale: 0.6875, + }); + } + } + WIDGETS.chargingStatus = { + area: 'tr', + width: Bangle.isCharging() ? iconWidth : 0, + draw: draw, + }; + Bangle.on('charging', (charging) => { + const widget = WIDGETS.chargingStatus; + if (widget) { + if (charging) { + Bangle.buzz(); + widget.width = iconWidth; + } + else { + widget.width = 0; + } + Bangle.drawWidgets(); // re-layout widgets + g.flip(); + } + }); +})(); diff --git a/apps/widChargingStatus/widget.ts b/apps/widChargingStatus/widget.ts new file mode 100644 index 000000000..14b4df4a4 --- /dev/null +++ b/apps/widChargingStatus/widget.ts @@ -0,0 +1,38 @@ +(() => { + const icon = require('heatshrink').decompress( + atob( + 'ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA' + ) + ); + const iconWidth = 18; + + function draw(this: { x: number; y: number }) { + g.reset(); + if (Bangle.isCharging()) { + g.setColor('#FD0'); + g.drawImage(icon, this.x + 1, this.y + 1, { + scale: 0.6875, + }); + } + } + + WIDGETS.chargingStatus = { + area: 'tr', + width: Bangle.isCharging() ? iconWidth : 0, + draw: draw, + }; + + Bangle.on('charging', (charging) => { + const widget = WIDGETS.chargingStatus; + if (widget) { + if (charging) { + Bangle.buzz(); + widget.width = iconWidth; + } else { + widget.width = 0; + } + Bangle.drawWidgets(); // re-layout widgets + g.flip(); + } + }); +})(); diff --git a/lang/nl_NL.json b/lang/nl_NL.json index 0a39fefb2..117d4feeb 100644 --- a/lang/nl_NL.json +++ b/lang/nl_NL.json @@ -11,10 +11,10 @@ "Back": "Terug", "Repeat": "Herhalen", "Delete": "Verwijderen", - "ALARM!": "ALARV.", - "Sleep": "Stand-by", + "ALARM!": "ALARM!", + "Sleep": "Standby", "New Timer": "Nieuwe Timer", - "(repeat)": "(herhaling)", + "(repeat)": "(herhaal)", "music": "muziek", "week": "week", "Auto snooze": "Auto snooze", @@ -31,7 +31,7 @@ "minimum": "minimum", "valid period": "geldige periode", "heartrate": "hartslag", - "battery warn": "batterijwaarschuwing", + "battery warn": "batterijwaarsch.", "data": "gegevens", "step length": "staplengte", "min. confidence": "min. vertrouwen", @@ -47,7 +47,7 @@ "Yes\ndefinitely": "Ja\nzeker", "STEPS": "STAPPEN", "Show clocks": "Toon klokken", - "Record Run": "Record run", + "Record Run": "Rondje opnemen", "No Messages": "Geen berichten.", "View Message": "Bekijk bericht", "Piezo": "Piƫzo", @@ -63,7 +63,7 @@ "Make Connectable": "Maak Verbindbaar", "Quiet Mode": "Rustige modus", "BLE": "BLE", - "Dark BW": "Donker BW", + "Dark BW": "Donkere modus", "Apps": "Apps", "Programmable": "Programmeerbaar", "Vibration": "Trilling", @@ -82,32 +82,32 @@ "Remove": "Verwijder", "Add Device": "Apparaat toevoegen", "Connect device\nto add to\nwhitelist": "Apparaat aansluiten\ntoe te voegen aan\nwhitelist", - "Wake on Twist": "Wake on Twist", - "Wake on BTN2": "Wake op BTN2", - "Wake on BTN1": "Wake op BTN1", - "Wake on FaceUp": "Wakker worden op FaceUp", + "Wake on Twist": "Aangaan bij draaien", + "Wake on BTN2": "Aangaan bij BTN2", + "Wake on BTN1": "Aangaan bij BTN1", + "Wake on FaceUp": "Aangaan bij FaceUp", "Log": "Log", "Debug Info": "Debug info", - "Wake on BTN3": "Wake op BTN3", - "Flatten Battery": "Batterij plat maken", + "Wake on BTN3": "Aangaan bij BTN3", + "Flatten Battery": "Batterij leegmaken", "Rewrite Settings": "Instellingen herschrijven", - "Compact Storage": "Compacte opslag", - "Utilities": "Nutsbedrijven", + "Compact Storage": "Comprimeer opslag", + "Utilities": "Gereedschap", "Clock Style": "Klok Stijl", "Time Zone": "Tijdzone", - "Twist Timeout": "Time-out draaien", - "Twist Max Y": "Twist Max Y", - "Twist Threshold": "Twist Drempel", - "Wake on Touch": "Wakker worden bij aanraking", - "Compacting...\nTakes approx\n1 minute": "Verdichten...\nDuurt ongeveer\n1 minuut", - "Reset to Defaults": "Terugzetten op standaardwaarden", + "Twist Timeout": "Draaien time-out", + "Twist Max Y": "Draaien Max Y", + "Twist Threshold": "Draaien vanaf", + "Wake on Touch": "Aangaan bij aanraking", + "Compacting...\nTakes approx\n1 minute": "Comprimeren...\nDuurt ongeveer\n1 minuut", + "Reset to Defaults": "Terug naar standaardwaarden", "No Clocks Found": "Geen klokken gevonden", "Month": "Maand", - "Minute": "Minuutje", + "Minute": "Minuut", "Flattening battery - this can take hours.\nLong-press button to cancel": "Batterij leegmaken - dit kan uren duren.\nDruk lang op de knop om te annuleren", "Sleep Phase Alarm": "Slaapfase alarm", "Second": "Tweede", - "Turn Off": "Zet uit.", + "Turn Off": "Uitzetten", "Hour": "Uur", "Storage": "Opslag", "Date": "Datum", @@ -144,7 +144,7 @@ "Hide": "Verberg", "Messages": "Berichten", "Error in settings": "Fout in instellingen", - "BACK": "ACHTER", + "BACK": "TERUG", "Whitelist": "Whitelist", "Set Time": "Tijd instellen", "Disable": "Uitschakelen", @@ -162,7 +162,7 @@ "Loading": "Laden", "Music": "Muziek", "color": "kleur", - "off": "van", + "off": "uit", "Off": "Uit", "Theme": "Thema" }, diff --git a/typescript/.gitignore b/typescript/.gitignore new file mode 100644 index 000000000..630f61ee5 --- /dev/null +++ b/typescript/.gitignore @@ -0,0 +1,2 @@ +./node_modules +!package-lock.json diff --git a/typescript/README.md b/typescript/README.md new file mode 100644 index 000000000..13800aeec --- /dev/null +++ b/typescript/README.md @@ -0,0 +1,29 @@ +# BangleTS + +A generic project setup for compiling apps from Typescript to Bangle.js ready, readable Javascript. +It includes types for _some_ of the modules and globals that are exposed for apps to use. +The goal is to have types for everything, but that will take some time. Feel free to help out by contributing! + +## Using the types + +All currently typed modules can be found in `/typescript/types.globals.d.ts`. +The typing is an ongoing process. If anything is still missing, you can add it! It will automatically be available in your TS files. + +## Compilation + +Install [npm](https://www.npmjs.com/get-npm) and node.js if you haven't already. We recommend using a version manager like nvm, which is also referenced in the linked documentation. +Make sure you are using node version 16 by running `nvm use 16` and npm version ^8 by running `npm -v`. If the latter version is incorrect, run `npm i -g npm@^8`. + +After having installed npm for your platform, open a terminal, and navigate into the `/typescript` folder. Then run: + +``` +npm ci +``` + +to install the project's build tools, and: + +``` +npm run build +``` + +To build all Typescript apps and widgets. The last command will generate the `app.js` files containing the transpiled code for the BangleJS. diff --git a/typescript/package-lock.json b/typescript/package-lock.json new file mode 100644 index 000000000..52be5f98a --- /dev/null +++ b/typescript/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "Bangle.ts", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "Bangle.ts", + "version": "0.0.1", + "devDependencies": { + "typescript": "4.5.2" + } + }, + "node_modules/typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true + } + } +} diff --git a/typescript/package.json b/typescript/package.json new file mode 100644 index 000000000..8cd38ce63 --- /dev/null +++ b/typescript/package.json @@ -0,0 +1,13 @@ +{ + "name": "Bangle.ts", + "description": "Bangle.js Typescript Project Setup and Types", + "author": "Sebastian Di Luzio