From 39c3a11d9f65730baac527c5586799709aba9055 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Tue, 7 Dec 2021 21:38:09 +0100 Subject: [PATCH 001/447] first draft: does not export to correct path yet --- typescript/sharedLib/.gitignore | 2 ++ typescript/sharedLib/README.md | 27 +++++++++++++++++++ typescript/sharedLib/package-lock.json | 37 ++++++++++++++++++++++++++ typescript/sharedLib/package.json | 20 ++++++++++++++ typescript/sharedLib/src/app.ts | 2 ++ typescript/sharedLib/tsconfig.json | 8 ++++++ 6 files changed, 96 insertions(+) create mode 100644 typescript/sharedLib/.gitignore create mode 100644 typescript/sharedLib/README.md create mode 100644 typescript/sharedLib/package-lock.json create mode 100644 typescript/sharedLib/package.json create mode 100644 typescript/sharedLib/src/app.ts create mode 100644 typescript/sharedLib/tsconfig.json diff --git a/typescript/sharedLib/.gitignore b/typescript/sharedLib/.gitignore new file mode 100644 index 000000000..b2af6e004 --- /dev/null +++ b/typescript/sharedLib/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +!package-lock.json \ No newline at end of file diff --git a/typescript/sharedLib/README.md b/typescript/sharedLib/README.md new file mode 100644 index 000000000..78b07b332 --- /dev/null +++ b/typescript/sharedLib/README.md @@ -0,0 +1,27 @@ +# 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 +TODO + +## Compilation + +Install [npm](https://www.npmjs.com/get-npm) if you haven't already. +Make sure you are using version ^8 by running `npm -v`. If the version is incorrect, run `npm i -g npm@^8`. + +After having installed npm for your platform, open a terminal, and navigate into the `/typescript/sharedLib` folder. Then run: + +``` +npm ci +``` + +to install the project's build tools, and: + +``` +npm run build:app pathToYourApp.ts +``` + +To build your app. The last command will generate the `app.js` file containing the transpiled code for the BangleJS. diff --git a/typescript/sharedLib/package-lock.json b/typescript/sharedLib/package-lock.json new file mode 100644 index 000000000..9df411a91 --- /dev/null +++ b/typescript/sharedLib/package-lock.json @@ -0,0 +1,37 @@ +{ + "name": "banglets", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "banglets", + "version": "0.1.0", + "license": "MIT", + "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/sharedLib/package.json b/typescript/sharedLib/package.json new file mode 100644 index 000000000..2bf45de2e --- /dev/null +++ b/typescript/sharedLib/package.json @@ -0,0 +1,20 @@ +{ + "name": "bangle.ts", + "version": "0.1.0", + "description": "Typescript configuration and typings for Bangle.js", + "main": "app.js", + "types": "app.d.ts", + "scripts": { + "build:testapp": "tsc src/app.ts", + "build:types": "tsc src/bangle.d.ts", + "build:app": "tsc" + }, + "author": { + "name": "Sebastian Di Luzio", + "email": "sebastian@diluz.io" + }, + "license": "MIT", + "devDependencies": { + "typescript": "^4.5.2" + } +} diff --git a/typescript/sharedLib/src/app.ts b/typescript/sharedLib/src/app.ts new file mode 100644 index 000000000..6e5739557 --- /dev/null +++ b/typescript/sharedLib/src/app.ts @@ -0,0 +1,2 @@ +const testString = 'test hehe'; +console.log(testString); diff --git a/typescript/sharedLib/tsconfig.json b/typescript/sharedLib/tsconfig.json new file mode 100644 index 000000000..42b34ec65 --- /dev/null +++ b/typescript/sharedLib/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "es2015", + "noImplicitAny": true, + "target": "es2015", + "outDir": "../dist" + } +} From 3cd9c3952560dec0f7689de0cf2eb9302125afb6 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Tue, 7 Dec 2021 21:46:28 +0100 Subject: [PATCH 002/447] add build example to export to correct path --- typescript/sharedLib/README.md | 5 +++-- typescript/sharedLib/package.json | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/typescript/sharedLib/README.md b/typescript/sharedLib/README.md index 78b07b332..a54a4c75a 100644 --- a/typescript/sharedLib/README.md +++ b/typescript/sharedLib/README.md @@ -1,10 +1,11 @@ # 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. +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 + TODO ## Compilation @@ -21,7 +22,7 @@ npm ci to install the project's build tools, and: ``` -npm run build:app pathToYourApp.ts +npx tsc ./relativePathToYourApp/app.ts --outDir ./relativePathToYourApp/dist ``` To build your app. The last command will generate the `app.js` file containing the transpiled code for the BangleJS. diff --git a/typescript/sharedLib/package.json b/typescript/sharedLib/package.json index 2bf45de2e..814db8f3e 100644 --- a/typescript/sharedLib/package.json +++ b/typescript/sharedLib/package.json @@ -5,9 +5,8 @@ "main": "app.js", "types": "app.d.ts", "scripts": { - "build:testapp": "tsc src/app.ts", - "build:types": "tsc src/bangle.d.ts", - "build:app": "tsc" + "build:testapp": "tsc ./src/app.ts --outDir ./dist", + "build:types": "tsc ./src/bangle.d.ts" }, "author": { "name": "Sebastian Di Luzio", From 61cc93b0b6e461b25daa5225497466c00a099662 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Tue, 7 Dec 2021 22:27:09 +0100 Subject: [PATCH 003/447] prepare for using with widChargingStatus global types are not yet received correctly, but we're close! - use widChargerStatus as first example to make setup work - add github action to compile supplied types/globals on pushes --- .github/workflows/nodejs.yml | 25 +++ .../{widget.js => widget.ts} | 0 typescript/{sharedLib => }/.gitignore | 0 typescript/{sharedLib => }/README.md | 0 typescript/globals.d.ts | 145 ++++++++++++++++++ typescript/{sharedLib => }/package-lock.json | 0 typescript/{sharedLib => }/package.json | 4 +- typescript/sharedLib/src/app.ts | 2 - typescript/{sharedLib => }/tsconfig.json | 6 +- 9 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/nodejs.yml rename apps/widChargingStatus/{widget.js => widget.ts} (100%) rename typescript/{sharedLib => }/.gitignore (100%) rename typescript/{sharedLib => }/README.md (100%) create mode 100644 typescript/globals.d.ts rename typescript/{sharedLib => }/package-lock.json (100%) rename typescript/{sharedLib => }/package.json (70%) delete mode 100644 typescript/sharedLib/src/app.ts rename typescript/{sharedLib => }/tsconfig.json (52%) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 000000000..9503d8934 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,25 @@ +name: Node CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: go to typescript directory + run: cd typescript + - name: npm ci + run: npm ci + - name: build types + run: npm run build:types \ No newline at end of file diff --git a/apps/widChargingStatus/widget.js b/apps/widChargingStatus/widget.ts similarity index 100% rename from apps/widChargingStatus/widget.js rename to apps/widChargingStatus/widget.ts diff --git a/typescript/sharedLib/.gitignore b/typescript/.gitignore similarity index 100% rename from typescript/sharedLib/.gitignore rename to typescript/.gitignore diff --git a/typescript/sharedLib/README.md b/typescript/README.md similarity index 100% rename from typescript/sharedLib/README.md rename to typescript/README.md diff --git a/typescript/globals.d.ts b/typescript/globals.d.ts new file mode 100644 index 000000000..702ef26cb --- /dev/null +++ b/typescript/globals.d.ts @@ -0,0 +1,145 @@ +// TODO all of these globals (copied from eslintrc need to be typed at some point) +/* "globals": { + // Methods and Fields at https://banglejs.com/reference + "Array": "readonly", + "ArrayBuffer": "readonly", + "ArrayBufferView": "readonly", + "Bangle": "readonly", + "BluetoothDevice": "readonly", + "BluetoothRemoteGATTCharacteristic": "readonly", + "BluetoothRemoteGATTServer": "readonly", + "BluetoothRemoteGATTService": "readonly", + "Boolean": "readonly", + "console": "readonly", + "DataView": "readonly", + "Date": "readonly", + "E": "readonly", + "Error": "readonly", + "Flash": "readonly", + "Float32Array": "readonly", + "Float64Array": "readonly", + "fs": "readonly", + "Function": "readonly", + "Graphics": "readonly", + "heatshrink": "readonly", + "I2C": "readonly", + "Int16Array": "readonly", + "Int32Array": "readonly", + "Int8Array": "readonly", + "InternalError": "readonly", + "JSON": "readonly", + "Math": "readonly", + "Modules": "readonly", + "NRF": "readonly", + "Number": "readonly", + "Object": "readonly", + "OneWire": "readonly", + "Pin": "readonly", + "process": "readonly", + "Promise": "readonly", + "ReferenceError": "readonly", + "RegExp": "readonly", + "Serial": "readonly", + "SPI": "readonly", + "Storage": "readonly", + "StorageFile": "readonly", + "String": "readonly", + "SyntaxError": "readonly", + "tensorflow": "readonly", + "TFMicroInterpreter": "readonly", + "TypeError": "readonly", + "Uint16Array": "readonly", + "Uint24Array": "readonly", + "Uint32Array": "readonly", + "Uint8Array": "readonly", + "Uint8ClampedArray": "readonly", + "Waveform": "readonly", + // Methods and Fields at https://banglejs.com/reference + "analogRead": "readonly", + "analogWrite": "readonly", + "arguments": "readonly", + "atob": "readonly", + "Bluetooth": "readonly", + "BTN": "readonly", + "BTN1": "readonly", + "BTN2": "readonly", + "BTN3": "readonly", + "BTN4": "readonly", + "BTN5": "readonly", + "btoa": "readonly", + "changeInterval": "readonly", + "clearInterval": "readonly", + "clearTimeout": "readonly", + "clearWatch": "readonly", + "decodeURIComponent": "readonly", + "digitalPulse": "readonly", + "digitalRead": "readonly", + "digitalWrite": "readonly", + "dump": "readonly", + "echo": "readonly", + "edit": "readonly", + "encodeURIComponent": "readonly", + "eval": "readonly", + "getPinMode": "readonly", + "getSerial": "readonly", + "getTime": "readonly", + "global": "readonly", + "HIGH": "readonly", + "I2C1": "readonly", + "Infinity": "readonly", + "isFinite": "readonly", + "isNaN": "readonly", + "LED": "readonly", + "LED1": "readonly", + "LED2": "readonly", + "load": "readonly", + "LoopbackA": "readonly", + "LoopbackB": "readonly", + "LOW": "readonly", + "NaN": "readonly", + "parseFloat": "readonly", + "parseInt": "readonly", + "peek16": "readonly", + "peek32": "readonly", + "peek8": "readonly", + "pinMode": "readonly", + "poke16": "readonly", + "poke32": "readonly", + "poke8": "readonly", + "print": "readonly", + "require": "readonly", + "reset": "readonly", + "save": "readonly", + "Serial1": "readonly", + "setBusyIndicator": "readonly", + "setInterval": "readonly", + "setSleepIndicator": "readonly", + "setTime": "readonly", + "setTimeout": "readonly", + "setWatch": "readonly", + "shiftOut": "readonly", + "SPI1": "readonly", + "Terminal": "readonly", + "trace": "readonly", + "VIBRATE": "readonly", + // Aliases and not defined at https://banglejs.com/reference + "g": "readonly", + */ + +declare const Bangle: { + // functions + buzz: () => void; + drawWidgets: () => void; + isCharging: () => boolean; + // events + on(event: 'charging', listener: (charging: boolean) => void): void; + // TODO add more +}; + +type Widget = { + area: 'tr' | 'tl'; + width: number; + draw: () => void; +}; + +declare const WIDGETS: { [key: string]: Widget }; diff --git a/typescript/sharedLib/package-lock.json b/typescript/package-lock.json similarity index 100% rename from typescript/sharedLib/package-lock.json rename to typescript/package-lock.json diff --git a/typescript/sharedLib/package.json b/typescript/package.json similarity index 70% rename from typescript/sharedLib/package.json rename to typescript/package.json index 814db8f3e..513e7b7df 100644 --- a/typescript/sharedLib/package.json +++ b/typescript/package.json @@ -5,8 +5,8 @@ "main": "app.js", "types": "app.d.ts", "scripts": { - "build:testapp": "tsc ./src/app.ts --outDir ./dist", - "build:types": "tsc ./src/bangle.d.ts" + "build:example": "tsc ../apps/widChargingStatus/widget.ts --outDir ../apps/widChargingStatus/dist", + "build:types": "tsc ./globals.d.ts" }, "author": { "name": "Sebastian Di Luzio", diff --git a/typescript/sharedLib/src/app.ts b/typescript/sharedLib/src/app.ts deleted file mode 100644 index 6e5739557..000000000 --- a/typescript/sharedLib/src/app.ts +++ /dev/null @@ -1,2 +0,0 @@ -const testString = 'test hehe'; -console.log(testString); diff --git a/typescript/sharedLib/tsconfig.json b/typescript/tsconfig.json similarity index 52% rename from typescript/sharedLib/tsconfig.json rename to typescript/tsconfig.json index 42b34ec65..ce8e6278b 100644 --- a/typescript/sharedLib/tsconfig.json +++ b/typescript/tsconfig.json @@ -3,6 +3,8 @@ "module": "es2015", "noImplicitAny": true, "target": "es2015", - "outDir": "../dist" - } + "outDir": "../dist", + "isolatedModules": false + }, + "include": ["./globals.d.ts"] } From 63b26f5d1ffeb069c373d94eb9a9705004a1c1c1 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Wed, 8 Dec 2021 20:22:39 +0100 Subject: [PATCH 004/447] move dev dependencies to main package.json, get first compiling version of test widget - i still want to be able to get the types ambiently defined without any weird import needed - it would be nice to be able to have a separate package.json in ./typescirpt. not sure if it's possible, I would move working on that part to the end --- apps.json | 2 +- apps/widChargingStatus/dist/widget.js | 31 +++++++++++ apps/widChargingStatus/widget.ts | 60 +++++++++++---------- package.json | 8 ++- tsconfig.json | 7 +++ typescript/.gitignore | 2 - typescript/package-lock.json | 37 ------------- typescript/package.json | 19 ------- typescript/tsconfig.json | 10 ---- typescript/{ => types}/globals.d.ts | 77 ++++++++++++++++----------- 10 files changed, 124 insertions(+), 129 deletions(-) create mode 100644 apps/widChargingStatus/dist/widget.js create mode 100644 tsconfig.json delete mode 100644 typescript/.gitignore delete mode 100644 typescript/package-lock.json delete mode 100644 typescript/package.json delete mode 100644 typescript/tsconfig.json rename typescript/{ => types}/globals.d.ts (75%) diff --git a/apps.json b/apps.json index 13bb5892d..58a67d8c2 100644 --- a/apps.json +++ b/apps.json @@ -4763,7 +4763,7 @@ "tags": "widget", "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ - {"name":"widChargingStatus.wid.js","url":"widget.js"} + {"name":"widChargingStatus.wid.js","url":"./dist/widget.js"} ] }, { diff --git a/apps/widChargingStatus/dist/widget.js b/apps/widChargingStatus/dist/widget.js new file mode 100644 index 000000000..7772a5b87 --- /dev/null +++ b/apps/widChargingStatus/dist/widget.js @@ -0,0 +1,31 @@ +"use strict"; +exports.__esModule = true; +(function () { + var icon = require('heatshrink').decompress(atob('ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA')); + var 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', function (charging) { + if (charging) { + Bangle.buzz(); + WIDGETS.chargingStatus.width = iconWidth; + } + else { + WIDGETS.chargingStatus.width = 0; + } + Bangle.drawWidgets(); // re-layout widgets + g.flip(); + }); +})(); diff --git a/apps/widChargingStatus/widget.ts b/apps/widChargingStatus/widget.ts index 90f9199fa..e3ce2d7e2 100644 --- a/apps/widChargingStatus/widget.ts +++ b/apps/widChargingStatus/widget.ts @@ -1,31 +1,37 @@ +import { loadGlobals } from '../../typescript/types/globals'; // TODO find a nicer way to load ambient type definitions than this + (() => { - const icon = require("heatshrink").decompress(atob("ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA")); - const iconWidth = 18; + 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 - }); - } - } + 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, - }; + 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 + Bangle.on('charging', (charging) => { + if (charging) { + Bangle.buzz(); + WIDGETS.chargingStatus.width = iconWidth; + } else { + WIDGETS.chargingStatus.width = 0; + } + Bangle.drawWidgets(); // re-layout widgets + g.flip(); + }); +})(); diff --git a/package.json b/package.json index b796044c9..1ecfb6280 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,16 @@ "author": "Gordon Williams (http://espruino.com)", "version": "0.0.1", "devDependencies": { - "eslint": "7.1.0" + "eslint": "7.1.0", + "@types/node": "16.11.12", + "typescript": "4.5.2" }, "scripts": { "lint-apps": "eslint ./apps --ext .js", "test": "node bin/sanitycheck.js && eslint ./apps --ext .js", - "start": "npx http-server -c-1" + "start": "npx http-server -c-1", + "build:example": "tsc ./apps/widChargingStatus/widget.ts --outDir ./apps/widChargingStatus/dist", + "build:types": "tsc .typescript/types/globals.d.ts" }, "dependencies": { "acorn": "^7.2.0" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..46a557e89 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "es2015", + "noImplicitAny": true, + "target": "es2015" + } +} diff --git a/typescript/.gitignore b/typescript/.gitignore deleted file mode 100644 index b2af6e004..000000000 --- a/typescript/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -!package-lock.json \ No newline at end of file diff --git a/typescript/package-lock.json b/typescript/package-lock.json deleted file mode 100644 index 9df411a91..000000000 --- a/typescript/package-lock.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "banglets", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "banglets", - "version": "0.1.0", - "license": "MIT", - "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 deleted file mode 100644 index 513e7b7df..000000000 --- a/typescript/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "bangle.ts", - "version": "0.1.0", - "description": "Typescript configuration and typings for Bangle.js", - "main": "app.js", - "types": "app.d.ts", - "scripts": { - "build:example": "tsc ../apps/widChargingStatus/widget.ts --outDir ../apps/widChargingStatus/dist", - "build:types": "tsc ./globals.d.ts" - }, - "author": { - "name": "Sebastian Di Luzio", - "email": "sebastian@diluz.io" - }, - "license": "MIT", - "devDependencies": { - "typescript": "^4.5.2" - } -} diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json deleted file mode 100644 index ce8e6278b..000000000 --- a/typescript/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "module": "es2015", - "noImplicitAny": true, - "target": "es2015", - "outDir": "../dist", - "isolatedModules": false - }, - "include": ["./globals.d.ts"] -} diff --git a/typescript/globals.d.ts b/typescript/types/globals.d.ts similarity index 75% rename from typescript/globals.d.ts rename to typescript/types/globals.d.ts index 702ef26cb..97a40ae54 100644 --- a/typescript/globals.d.ts +++ b/typescript/types/globals.d.ts @@ -1,33 +1,19 @@ // TODO all of these globals (copied from eslintrc need to be typed at some point) /* "globals": { // Methods and Fields at https://banglejs.com/reference - "Array": "readonly", - "ArrayBuffer": "readonly", - "ArrayBufferView": "readonly", - "Bangle": "readonly", "BluetoothDevice": "readonly", "BluetoothRemoteGATTCharacteristic": "readonly", "BluetoothRemoteGATTServer": "readonly", "BluetoothRemoteGATTService": "readonly", - "Boolean": "readonly", - "console": "readonly", "DataView": "readonly", - "Date": "readonly", "E": "readonly", "Error": "readonly", "Flash": "readonly", - "Float32Array": "readonly", - "Float64Array": "readonly", "fs": "readonly", "Function": "readonly", - "Graphics": "readonly", "heatshrink": "readonly", "I2C": "readonly", - "Int16Array": "readonly", - "Int32Array": "readonly", - "Int8Array": "readonly", "InternalError": "readonly", - "JSON": "readonly", "Math": "readonly", "Modules": "readonly", "NRF": "readonly", @@ -122,24 +108,53 @@ "Terminal": "readonly", "trace": "readonly", "VIBRATE": "readonly", - // Aliases and not defined at https://banglejs.com/reference - "g": "readonly", */ -declare const Bangle: { - // functions - buzz: () => void; - drawWidgets: () => void; - isCharging: () => boolean; - // events - on(event: 'charging', listener: (charging: boolean) => void): void; - // TODO add more -}; +export type loadGlobals = {}; -type Widget = { - area: 'tr' | 'tl'; - width: number; - draw: () => void; -}; +declare global { + const Bangle: { + // functions + buzz: () => void; + drawWidgets: () => void; + isCharging: () => boolean; + // events + on(event: 'charging', listener: (charging: boolean) => void): void; + // TODO add more + }; -declare const WIDGETS: { [key: string]: Widget }; + type Image = { + width: number; + height: number; + bpp?: number; + buffer: ArrayBuffer | string; + transparent?: number; + palette?: Uint16Array; + }; + + type GraphicsApi = { + reset: () => void; + flip: () => void; + setColor: (color: string) => void; // TODO we can most likely type color more usefully than this + drawImage: ( + image: string | Image | ArrayBuffer, + xOffset: number, + yOffset: number, + options?: { + rotate?: number; + scale?: number; + } + ) => void; + // TODO add more + }; + + const Graphics: GraphicsApi; + const g: GraphicsApi; + + type Widget = { + area: 'tr' | 'tl'; + width: number; + draw: () => void; + }; + const WIDGETS: { [key: string]: Widget }; +} From d46736c01a4fa85888e78a8c8814ddcd26384908 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Wed, 8 Dec 2021 20:23:14 +0100 Subject: [PATCH 005/447] adjust github actions --- .github/workflows/nodejs.yml | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 9503d8934..e2a12cc51 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -4,7 +4,6 @@ on: [push] jobs: build: - runs-on: ubuntu-latest strategy: @@ -12,14 +11,12 @@ jobs: node-version: [16.x] steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: go to typescript directory - run: cd typescript - - name: npm ci - run: npm ci - - name: build types - run: npm run build:types \ No newline at end of file + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm i + run: npm i + - name: build types + run: npm run build:types From 0a2426a6dd9add940909a552663eb0b25ce86ade Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Wed, 8 Dec 2021 20:24:11 +0100 Subject: [PATCH 006/447] fix type build script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ecfb6280..f6426e7e2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "test": "node bin/sanitycheck.js && eslint ./apps --ext .js", "start": "npx http-server -c-1", "build:example": "tsc ./apps/widChargingStatus/widget.ts --outDir ./apps/widChargingStatus/dist", - "build:types": "tsc .typescript/types/globals.d.ts" + "build:types": "tsc ./typescript/types/globals.d.ts" }, "dependencies": { "acorn": "^7.2.0" From 83d445c1a28c7257cfd09b819a0b949ce439507e Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 20:52:17 +0100 Subject: [PATCH 007/447] move package back within typescript --- package.json | 8 +--- typescript/.gitignore | 2 + typescript/README.md | 4 +- typescript/package-lock.json | 49 +++++++++++++++++++++++ typescript/package.json | 14 +++++++ tsconfig.json => typescript/tsconfig.json | 0 6 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 typescript/.gitignore create mode 100644 typescript/package-lock.json create mode 100644 typescript/package.json rename tsconfig.json => typescript/tsconfig.json (100%) diff --git a/package.json b/package.json index f6426e7e2..b796044c9 100644 --- a/package.json +++ b/package.json @@ -4,16 +4,12 @@ "author": "Gordon Williams (http://espruino.com)", "version": "0.0.1", "devDependencies": { - "eslint": "7.1.0", - "@types/node": "16.11.12", - "typescript": "4.5.2" + "eslint": "7.1.0" }, "scripts": { "lint-apps": "eslint ./apps --ext .js", "test": "node bin/sanitycheck.js && eslint ./apps --ext .js", - "start": "npx http-server -c-1", - "build:example": "tsc ./apps/widChargingStatus/widget.ts --outDir ./apps/widChargingStatus/dist", - "build:types": "tsc ./typescript/types/globals.d.ts" + "start": "npx http-server -c-1" }, "dependencies": { "acorn": "^7.2.0" 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 index a54a4c75a..9b38459ae 100644 --- a/typescript/README.md +++ b/typescript/README.md @@ -13,7 +13,7 @@ TODO Install [npm](https://www.npmjs.com/get-npm) if you haven't already. Make sure you are using version ^8 by running `npm -v`. If the version is incorrect, run `npm i -g npm@^8`. -After having installed npm for your platform, open a terminal, and navigate into the `/typescript/sharedLib` folder. Then run: +After having installed npm for your platform, open a terminal, and navigate into the `/typescript` folder. Then run: ``` npm ci @@ -22,7 +22,7 @@ npm ci to install the project's build tools, and: ``` -npx tsc ./relativePathToYourApp/app.ts --outDir ./relativePathToYourApp/dist +npx tsc ../apps/relativePathToYourApp/app.ts --outDir ../apps/relativePathToYourApp/dist ``` To build your app. The last command will generate the `app.js` file 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..bd3cfc702 --- /dev/null +++ b/typescript/package-lock.json @@ -0,0 +1,49 @@ +{ + "name": "Bangle.ts", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "Bangle.ts", + "version": "0.0.1", + "devDependencies": { + "@types/node": "16.11.12", + "typescript": "4.5.2" + } + }, + "node_modules/@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", + "dev": true + }, + "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": { + "@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", + "dev": true + }, + "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..03f435497 --- /dev/null +++ b/typescript/package.json @@ -0,0 +1,14 @@ +{ + "name": "Bangle.ts", + "description": "Bangle.js Typescript Project Setup and Types", + "author": "Sebastian Di Luzio (https://diluz.io)", + "version": "0.0.1", + "devDependencies": { + "@types/node": "16.11.12", + "typescript": "4.5.2" + }, + "scripts": { + "build:example": "tsc ../apps/widChargingStatus/widget.ts --outDir ../apps/widChargingStatus/dist", + "build:types": "tsc ./types/globals.d.ts" + } +} diff --git a/tsconfig.json b/typescript/tsconfig.json similarity index 100% rename from tsconfig.json rename to typescript/tsconfig.json From 45bd654eca724a8cb15cddf1eab883978c38bd87 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 21:19:01 +0100 Subject: [PATCH 008/447] fix global vars inside IDE (only cli to go) --- apps/widChargingStatus/dist/widget.js | 2 - apps/widChargingStatus/widget.ts | 2 - typescript/package-lock.json | 13 - typescript/package.json | 1 - typescript/tsconfig.json | 3 +- typescript/types/globals.d.ts | 327 ++++++++++++++------------ 6 files changed, 177 insertions(+), 171 deletions(-) diff --git a/apps/widChargingStatus/dist/widget.js b/apps/widChargingStatus/dist/widget.js index 7772a5b87..eea96ce58 100644 --- a/apps/widChargingStatus/dist/widget.js +++ b/apps/widChargingStatus/dist/widget.js @@ -1,5 +1,3 @@ -"use strict"; -exports.__esModule = true; (function () { var icon = require('heatshrink').decompress(atob('ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA')); var iconWidth = 18; diff --git a/apps/widChargingStatus/widget.ts b/apps/widChargingStatus/widget.ts index e3ce2d7e2..a8cf2ed94 100644 --- a/apps/widChargingStatus/widget.ts +++ b/apps/widChargingStatus/widget.ts @@ -1,5 +1,3 @@ -import { loadGlobals } from '../../typescript/types/globals'; // TODO find a nicer way to load ambient type definitions than this - (() => { const icon = require('heatshrink').decompress( atob( diff --git a/typescript/package-lock.json b/typescript/package-lock.json index bd3cfc702..52be5f98a 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -8,16 +8,9 @@ "name": "Bangle.ts", "version": "0.0.1", "devDependencies": { - "@types/node": "16.11.12", "typescript": "4.5.2" } }, - "node_modules/@types/node": { - "version": "16.11.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", - "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", - "dev": true - }, "node_modules/typescript": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", @@ -33,12 +26,6 @@ } }, "dependencies": { - "@types/node": { - "version": "16.11.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", - "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==", - "dev": true - }, "typescript": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", diff --git a/typescript/package.json b/typescript/package.json index 03f435497..83ea7d82b 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -4,7 +4,6 @@ "author": "Sebastian Di Luzio (https://diluz.io)", "version": "0.0.1", "devDependencies": { - "@types/node": "16.11.12", "typescript": "4.5.2" }, "scripts": { diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index 46a557e89..8a7ab3342 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -3,5 +3,6 @@ "module": "es2015", "noImplicitAny": true, "target": "es2015" - } + }, + "include": ["../apps/**/*", "./**/*"] } diff --git a/typescript/types/globals.d.ts b/typescript/types/globals.d.ts index 97a40ae54..359d5d294 100644 --- a/typescript/types/globals.d.ts +++ b/typescript/types/globals.d.ts @@ -1,160 +1,183 @@ // TODO all of these globals (copied from eslintrc need to be typed at some point) -/* "globals": { - // Methods and Fields at https://banglejs.com/reference - "BluetoothDevice": "readonly", - "BluetoothRemoteGATTCharacteristic": "readonly", - "BluetoothRemoteGATTServer": "readonly", - "BluetoothRemoteGATTService": "readonly", - "DataView": "readonly", - "E": "readonly", - "Error": "readonly", - "Flash": "readonly", - "fs": "readonly", - "Function": "readonly", - "heatshrink": "readonly", - "I2C": "readonly", - "InternalError": "readonly", - "Math": "readonly", - "Modules": "readonly", - "NRF": "readonly", - "Number": "readonly", - "Object": "readonly", - "OneWire": "readonly", - "Pin": "readonly", - "process": "readonly", - "Promise": "readonly", - "ReferenceError": "readonly", - "RegExp": "readonly", - "Serial": "readonly", - "SPI": "readonly", - "Storage": "readonly", - "StorageFile": "readonly", - "String": "readonly", - "SyntaxError": "readonly", - "tensorflow": "readonly", - "TFMicroInterpreter": "readonly", - "TypeError": "readonly", - "Uint16Array": "readonly", - "Uint24Array": "readonly", - "Uint32Array": "readonly", - "Uint8Array": "readonly", - "Uint8ClampedArray": "readonly", - "Waveform": "readonly", - // Methods and Fields at https://banglejs.com/reference - "analogRead": "readonly", - "analogWrite": "readonly", - "arguments": "readonly", - "atob": "readonly", - "Bluetooth": "readonly", - "BTN": "readonly", - "BTN1": "readonly", - "BTN2": "readonly", - "BTN3": "readonly", - "BTN4": "readonly", - "BTN5": "readonly", - "btoa": "readonly", - "changeInterval": "readonly", - "clearInterval": "readonly", - "clearTimeout": "readonly", - "clearWatch": "readonly", - "decodeURIComponent": "readonly", - "digitalPulse": "readonly", - "digitalRead": "readonly", - "digitalWrite": "readonly", - "dump": "readonly", - "echo": "readonly", - "edit": "readonly", - "encodeURIComponent": "readonly", - "eval": "readonly", - "getPinMode": "readonly", - "getSerial": "readonly", - "getTime": "readonly", - "global": "readonly", - "HIGH": "readonly", - "I2C1": "readonly", - "Infinity": "readonly", - "isFinite": "readonly", - "isNaN": "readonly", - "LED": "readonly", - "LED1": "readonly", - "LED2": "readonly", - "load": "readonly", - "LoopbackA": "readonly", - "LoopbackB": "readonly", - "LOW": "readonly", - "NaN": "readonly", - "parseFloat": "readonly", - "parseInt": "readonly", - "peek16": "readonly", - "peek32": "readonly", - "peek8": "readonly", - "pinMode": "readonly", - "poke16": "readonly", - "poke32": "readonly", - "poke8": "readonly", - "print": "readonly", - "require": "readonly", - "reset": "readonly", - "save": "readonly", - "Serial1": "readonly", - "setBusyIndicator": "readonly", - "setInterval": "readonly", - "setSleepIndicator": "readonly", - "setTime": "readonly", - "setTimeout": "readonly", - "setWatch": "readonly", - "shiftOut": "readonly", - "SPI1": "readonly", - "Terminal": "readonly", - "trace": "readonly", - "VIBRATE": "readonly", +/* { + // Methods and Fields at https://banglejs.com/reference + "Array": "readonly", + "ArrayBuffer": "readonly", + "ArrayBufferView": "readonly", + "Bangle": "readonly", + "BluetoothDevice": "readonly", + "BluetoothRemoteGATTCharacteristic": "readonly", + "BluetoothRemoteGATTServer": "readonly", + "BluetoothRemoteGATTService": "readonly", + "Boolean": "readonly", + "console": "readonly", + "DataView": "readonly", + "Date": "readonly", + "E": "readonly", + "Error": "readonly", + "Flash": "readonly", + "Float32Array": "readonly", + "Float64Array": "readonly", + "fs": "readonly", + "Function": "readonly", + "Graphics": "readonly", // partly done + "heatshrink": "readonly", + "I2C": "readonly", + "Int16Array": "readonly", + "Int32Array": "readonly", + "Int8Array": "readonly", + "InternalError": "readonly", + "JSON": "readonly", + "Math": "readonly", + "Modules": "readonly", + "NRF": "readonly", + "Number": "readonly", + "Object": "readonly", + "OneWire": "readonly", + "Pin": "readonly", + "process": "readonly", + "Promise": "readonly", + "ReferenceError": "readonly", + "RegExp": "readonly", + "Serial": "readonly", + "SPI": "readonly", + "Storage": "readonly", + "StorageFile": "readonly", + "String": "readonly", + "SyntaxError": "readonly", + "tensorflow": "readonly", + "TFMicroInterpreter": "readonly", + "TypeError": "readonly", + "Uint16Array": "readonly", + "Uint24Array": "readonly", + "Uint32Array": "readonly", + "Uint8Array": "readonly", + "Uint8ClampedArray": "readonly", + "Waveform": "readonly", + // Methods and Fields at https://banglejs.com/reference + "analogRead": "readonly", + "analogWrite": "readonly", + "arguments": "readonly", + "atob": "readonly", + "Bluetooth": "readonly", + "BTN": "readonly", + "BTN1": "readonly", + "BTN2": "readonly", + "BTN3": "readonly", + "BTN4": "readonly", + "BTN5": "readonly", + "btoa": "readonly", + "changeInterval": "readonly", + "clearInterval": "readonly", + "clearTimeout": "readonly", + "clearWatch": "readonly", + "decodeURIComponent": "readonly", + "digitalPulse": "readonly", + "digitalRead": "readonly", + "digitalWrite": "readonly", + "dump": "readonly", + "echo": "readonly", + "edit": "readonly", + "encodeURIComponent": "readonly", + "eval": "readonly", + "getPinMode": "readonly", + "getSerial": "readonly", + "getTime": "readonly", + "global": "readonly", + "HIGH": "readonly", + "I2C1": "readonly", + "Infinity": "readonly", + "isFinite": "readonly", + "isNaN": "readonly", + "LED": "readonly", + "LED1": "readonly", + "LED2": "readonly", + "load": "readonly", + "LoopbackA": "readonly", + "LoopbackB": "readonly", + "LOW": "readonly", + "NaN": "readonly", + "parseFloat": "readonly", + "parseInt": "readonly", + "peek16": "readonly", + "peek32": "readonly", + "peek8": "readonly", + "pinMode": "readonly", + "poke16": "readonly", + "poke32": "readonly", + "poke8": "readonly", + "print": "readonly", + "require": "readonly", + "reset": "readonly", + "save": "readonly", + "Serial1": "readonly", + "setBusyIndicator": "readonly", + "setInterval": "readonly", + "setSleepIndicator": "readonly", + "setTime": "readonly", + "setTimeout": "readonly", + "setWatch": "readonly", + "shiftOut": "readonly", + "SPI1": "readonly", + "Terminal": "readonly", + "trace": "readonly", + "VIBRATE": "readonly", + // Aliases and not defined at https://banglejs.com/reference + "g": "readonly", // done + "WIDGETS": "readonly" // done + } */ -export type loadGlobals = {}; +// ambient JS definitions -declare global { - const Bangle: { - // functions - buzz: () => void; - drawWidgets: () => void; - isCharging: () => boolean; - // events - on(event: 'charging', listener: (charging: boolean) => void): void; - // TODO add more - }; +declare const require: ((module: 'heatshrink') => { + decompress: (compressedString: string) => string; +}) & // TODO add more + ((module: 'otherString') => {}); - type Image = { - width: number; - height: number; - bpp?: number; - buffer: ArrayBuffer | string; - transparent?: number; - palette?: Uint16Array; - }; +// ambient bangle.js definitions - type GraphicsApi = { - reset: () => void; - flip: () => void; - setColor: (color: string) => void; // TODO we can most likely type color more usefully than this - drawImage: ( - image: string | Image | ArrayBuffer, - xOffset: number, - yOffset: number, - options?: { - rotate?: number; - scale?: number; - } - ) => void; - // TODO add more - }; +declare const Bangle: { + // functions + buzz: () => void; + drawWidgets: () => void; + isCharging: () => boolean; + // events + on(event: 'charging', listener: (charging: boolean) => void): void; + // TODO add more +}; - const Graphics: GraphicsApi; - const g: GraphicsApi; +declare type Image = { + width: number; + height: number; + bpp?: number; + buffer: ArrayBuffer | string; + transparent?: number; + palette?: Uint16Array; +}; - type Widget = { - area: 'tr' | 'tl'; - width: number; - draw: () => void; - }; - const WIDGETS: { [key: string]: Widget }; -} +declare type GraphicsApi = { + reset: () => void; + flip: () => void; + setColor: (color: string) => void; // TODO we can most likely type color more usefully than this + drawImage: ( + image: string | Image | ArrayBuffer, + xOffset: number, + yOffset: number, + options?: { + rotate?: number; + scale?: number; + } + ) => void; + // TODO add more +}; + +declare const Graphics: GraphicsApi; +declare const g: GraphicsApi; + +declare type Widget = { + area: 'tr' | 'tl'; + width: number; + draw: () => void; +}; +declare const WIDGETS: { [key: string]: Widget }; From 15d24ac1b3f5a1412adda885b116894d47c749a2 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 21:36:42 +0100 Subject: [PATCH 009/447] update TS rules to make them stricter --- apps/widChargingStatus/dist/widget.js | 19 +++++++++++-------- apps/widChargingStatus/widget.ts | 21 ++++++++++++--------- typescript/tsconfig.json | 11 ++++++++++- typescript/types/globals.d.ts | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/apps/widChargingStatus/dist/widget.js b/apps/widChargingStatus/dist/widget.js index eea96ce58..6cac1931f 100644 --- a/apps/widChargingStatus/dist/widget.js +++ b/apps/widChargingStatus/dist/widget.js @@ -16,14 +16,17 @@ draw: draw }; Bangle.on('charging', function (charging) { - if (charging) { - Bangle.buzz(); - WIDGETS.chargingStatus.width = iconWidth; + var widget = WIDGETS.chargingStatus; + if (widget) { + if (charging) { + Bangle.buzz(); + widget.width = iconWidth; + } + else { + widget.width = 0; + } + Bangle.drawWidgets(); // re-layout widgets + g.flip(); } - else { - WIDGETS.chargingStatus.width = 0; - } - Bangle.drawWidgets(); // re-layout widgets - g.flip(); }); })(); diff --git a/apps/widChargingStatus/widget.ts b/apps/widChargingStatus/widget.ts index a8cf2ed94..712bf4f97 100644 --- a/apps/widChargingStatus/widget.ts +++ b/apps/widChargingStatus/widget.ts @@ -6,7 +6,7 @@ ); const iconWidth = 18; - function draw() { + function draw(this: { x: number; y: number }) { g.reset(); if (Bangle.isCharging()) { g.setColor('#FD0'); @@ -19,17 +19,20 @@ WIDGETS.chargingStatus = { area: 'tr', width: Bangle.isCharging() ? iconWidth : 0, - draw: draw, + draw, }; Bangle.on('charging', (charging) => { - if (charging) { - Bangle.buzz(); - WIDGETS.chargingStatus.width = iconWidth; - } else { - WIDGETS.chargingStatus.width = 0; + const widget = WIDGETS.chargingStatus; + if (widget) { + if (charging) { + Bangle.buzz(); + widget.width = iconWidth; + } else { + widget.width = 0; + } + Bangle.drawWidgets(); // re-layout widgets + g.flip(); } - Bangle.drawWidgets(); // re-layout widgets - g.flip(); }); })(); diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index 8a7ab3342..09101094b 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -2,7 +2,16 @@ "compilerOptions": { "module": "es2015", "noImplicitAny": true, - "target": "es2015" + "target": "es2015", + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true }, "include": ["../apps/**/*", "./**/*"] } diff --git a/typescript/types/globals.d.ts b/typescript/types/globals.d.ts index 359d5d294..46d1e3b0a 100644 --- a/typescript/types/globals.d.ts +++ b/typescript/types/globals.d.ts @@ -178,6 +178,6 @@ declare const g: GraphicsApi; declare type Widget = { area: 'tr' | 'tl'; width: number; - draw: () => void; + draw: (this: { x: number; y: number }) => void; }; declare const WIDGETS: { [key: string]: Widget }; From 96b099b10ac58143d15b0ea28e1476a81d573c57 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 21:51:35 +0100 Subject: [PATCH 010/447] make tsconfig work for all ts apps --- .github/workflows/nodejs.yml | 9 +++++++-- apps.json | 2 +- apps/widChargingStatus/{dist => }/widget.js | 15 ++++++++------- typescript/package.json | 2 +- typescript/tsconfig.json | 3 ++- 5 files changed, 19 insertions(+), 12 deletions(-) rename apps/widChargingStatus/{dist => }/widget.js (61%) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index e2a12cc51..8187fc890 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -16,7 +16,12 @@ jobs: uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - - name: npm i - run: npm i + - name: npm ci + working-directory: ./typescript + run: npm ci - name: build types + working-directory: ./typescript + run: npm run build:types + - name: build all TS apps + working-directory: ./typescript run: npm run build:types diff --git a/apps.json b/apps.json index 58a67d8c2..6e85c19d7 100644 --- a/apps.json +++ b/apps.json @@ -4763,7 +4763,7 @@ "tags": "widget", "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ - {"name":"widChargingStatus.wid.js","url":"./dist/widget.js"} + {"name":"widChargingStatus.wid.js","url":"./widget.js"} ] }, { diff --git a/apps/widChargingStatus/dist/widget.js b/apps/widChargingStatus/widget.js similarity index 61% rename from apps/widChargingStatus/dist/widget.js rename to apps/widChargingStatus/widget.js index 6cac1931f..68a7c0aca 100644 --- a/apps/widChargingStatus/dist/widget.js +++ b/apps/widChargingStatus/widget.js @@ -1,22 +1,23 @@ -(function () { - var icon = require('heatshrink').decompress(atob('ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA')); - var iconWidth = 18; +"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 + scale: 0.6875, }); } } WIDGETS.chargingStatus = { area: 'tr', width: Bangle.isCharging() ? iconWidth : 0, - draw: draw + draw, }; - Bangle.on('charging', function (charging) { - var widget = WIDGETS.chargingStatus; + Bangle.on('charging', (charging) => { + const widget = WIDGETS.chargingStatus; if (widget) { if (charging) { Bangle.buzz(); diff --git a/typescript/package.json b/typescript/package.json index 83ea7d82b..4bfb88d27 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -7,7 +7,7 @@ "typescript": "4.5.2" }, "scripts": { - "build:example": "tsc ../apps/widChargingStatus/widget.ts --outDir ../apps/widChargingStatus/dist", + "build:apps": "tsc", "build:types": "tsc ./types/globals.d.ts" } } diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index 09101094b..aff7a6d38 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -13,5 +13,6 @@ "noUnusedParameters": true, "strict": true }, - "include": ["../apps/**/*", "./**/*"] + "include": ["../apps/**/*", "./**/*"], + "exclude": ["../apps/banglerun", "../apps/hebrew_calendar"] } From a393d573d644993927b4155c0c5c6ca570cb88a0 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 21:52:26 +0100 Subject: [PATCH 011/447] Update nodejs.yml --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 8187fc890..a9ada5e5e 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -21,7 +21,7 @@ jobs: run: npm ci - name: build types working-directory: ./typescript - run: npm run build:types + run: npm run build:apps - name: build all TS apps working-directory: ./typescript run: npm run build:types From d7be82bcc71a2445993e7adcec8074142cfa6038 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:01:01 +0100 Subject: [PATCH 012/447] Update README.md --- typescript/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/typescript/README.md b/typescript/README.md index 9b38459ae..66506924e 100644 --- a/typescript/README.md +++ b/typescript/README.md @@ -22,7 +22,7 @@ npm ci to install the project's build tools, and: ``` -npx tsc ../apps/relativePathToYourApp/app.ts --outDir ../apps/relativePathToYourApp/dist +npm run build:apps ``` -To build your app. The last command will generate the `app.js` file containing the transpiled code for the BangleJS. +To build all Typescript apps. The last command will generate the `app.js` files containing the transpiled code for the BangleJS. From a86f2c108dfc119de10d8ac3b65e1bc21009649b Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:02:41 +0100 Subject: [PATCH 013/447] Update README.md --- typescript/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/typescript/README.md b/typescript/README.md index 66506924e..d1f60fd0b 100644 --- a/typescript/README.md +++ b/typescript/README.md @@ -6,7 +6,8 @@ The goal is to have types for everything, but that will take some time. Feel fre ## Using the types -TODO +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 From 4990c426752586600ebb08ae472d71cbe2ed22c4 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:04:43 +0100 Subject: [PATCH 014/447] Update tsconfig.json --- typescript/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index aff7a6d38..40537c680 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -14,5 +14,6 @@ "strict": true }, "include": ["../apps/**/*", "./**/*"], + // these apps have been excluded because they were built before this configuration was created and are using their own "exclude": ["../apps/banglerun", "../apps/hebrew_calendar"] } From 4511520c88c4f4e2174639c41bb24195f3a82d83 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:17:06 +0100 Subject: [PATCH 015/447] upgrade chargingStatus version --- apps.json | 2 +- apps/widChargingStatus/ChangeLog | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 3466ab0fb..0a6cebba7 100644 --- a/apps.json +++ b/apps.json @@ -4782,7 +4782,7 @@ "name": "Charging Status", "shortName":"ChargingStatus", "icon": "widget.png", - "version":"0.1", + "version":"0.2", "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/ChangeLog b/apps/widChargingStatus/ChangeLog index d3175e1ab..ceb7cb883 100644 --- a/apps/widChargingStatus/ChangeLog +++ b/apps/widChargingStatus/ChangeLog @@ -1 +1,2 @@ -0.1: First release. \ No newline at end of file +0.1: First release. +0.2: No functional changes, just moved codebase to Typescript. \ No newline at end of file From d255d42a8c34b70c762cd8f4f3197aedfcf78a21 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:27:25 +0100 Subject: [PATCH 016/447] disable strict to see if that fixes widget --- apps/widChargingStatus/widget.js | 1 - typescript/tsconfig.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/widChargingStatus/widget.js b/apps/widChargingStatus/widget.js index 68a7c0aca..042e225f7 100644 --- a/apps/widChargingStatus/widget.js +++ b/apps/widChargingStatus/widget.js @@ -1,4 +1,3 @@ -"use strict"; (() => { const icon = require('heatshrink').decompress(atob('ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA')); const iconWidth = 18; diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index 40537c680..114e01ac3 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -11,7 +11,7 @@ "noUncheckedIndexedAccess": true, "noUnusedLocals": true, "noUnusedParameters": true, - "strict": true + "noImplicitUseStrict": true }, "include": ["../apps/**/*", "./**/*"], // these apps have been excluded because they were built before this configuration was created and are using their own From 0ece5ccdb0d8f61b963c7473ef00c47466b86900 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:32:36 +0100 Subject: [PATCH 017/447] more testing to get app back running --- apps.json | 2 +- apps/widChargingStatus/widget.js | 2 +- apps/widChargingStatus/widget.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 0a6cebba7..6f53c0c48 100644 --- a/apps.json +++ b/apps.json @@ -4782,7 +4782,7 @@ "name": "Charging Status", "shortName":"ChargingStatus", "icon": "widget.png", - "version":"0.2", + "version":"0.3", "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 042e225f7..386b84947 100644 --- a/apps/widChargingStatus/widget.js +++ b/apps/widChargingStatus/widget.js @@ -13,7 +13,7 @@ WIDGETS.chargingStatus = { area: 'tr', width: Bangle.isCharging() ? iconWidth : 0, - draw, + draw: draw, }; Bangle.on('charging', (charging) => { const widget = WIDGETS.chargingStatus; diff --git a/apps/widChargingStatus/widget.ts b/apps/widChargingStatus/widget.ts index 712bf4f97..14b4df4a4 100644 --- a/apps/widChargingStatus/widget.ts +++ b/apps/widChargingStatus/widget.ts @@ -19,7 +19,7 @@ WIDGETS.chargingStatus = { area: 'tr', width: Bangle.isCharging() ? iconWidth : 0, - draw, + draw: draw, }; Bangle.on('charging', (charging) => { From 0499f04dc3de9c1d5725c325ad67ddb6d676b939 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:36:22 +0100 Subject: [PATCH 018/447] try to use strict again --- apps/widChargingStatus/widget.js | 1 + typescript/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/widChargingStatus/widget.js b/apps/widChargingStatus/widget.js index 386b84947..5d9ea3837 100644 --- a/apps/widChargingStatus/widget.js +++ b/apps/widChargingStatus/widget.js @@ -1,3 +1,4 @@ +"use strict"; (() => { const icon = require('heatshrink').decompress(atob('ikggMAiEAgYIBmEAg4EB+EAh0AgPggEeCAIEBnwQBAgP+gEP//x///j//8f//k///H//4BYOP/4lBv4bDvwEB4EAvAEBwEAuA7DCAI7BgAQBhEAA')); const iconWidth = 18; diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index 114e01ac3..40537c680 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -11,7 +11,7 @@ "noUncheckedIndexedAccess": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noImplicitUseStrict": true + "strict": true }, "include": ["../apps/**/*", "./**/*"], // these apps have been excluded because they were built before this configuration was created and are using their own From 8baa3eca7235085698f08c5c8b2501048da1aa44 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:38:26 +0100 Subject: [PATCH 019/447] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 6f53c0c48..3f2363a31 100644 --- a/apps.json +++ b/apps.json @@ -4782,7 +4782,7 @@ "name": "Charging Status", "shortName":"ChargingStatus", "icon": "widget.png", - "version":"0.3", + "version":"0.4", "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", From 5c851714ee17ad55ca6692a6e9ad49e717a16d11 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:43:33 +0100 Subject: [PATCH 020/447] revert chargingStatus version --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 3f2363a31..0a6cebba7 100644 --- a/apps.json +++ b/apps.json @@ -4782,7 +4782,7 @@ "name": "Charging Status", "shortName":"ChargingStatus", "icon": "widget.png", - "version":"0.4", + "version":"0.2", "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", From c462547a2bfe283e610ea093bfa34a9cc98faf75 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 22:45:10 +0100 Subject: [PATCH 021/447] fix github actions --- .github/workflows/nodejs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index a9ada5e5e..c268c884c 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -21,7 +21,7 @@ jobs: run: npm ci - name: build types working-directory: ./typescript - run: npm run build:apps + run: npm run build:types - name: build all TS apps working-directory: ./typescript - run: npm run build:types + run: npm run build:apps From fc2c3c86a4c9c68b9ec56f5731775955f710b4c3 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Fri, 10 Dec 2021 23:17:18 +0100 Subject: [PATCH 022/447] document typing progress --- typescript/types/globals.d.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/typescript/types/globals.d.ts b/typescript/types/globals.d.ts index 46d1e3b0a..2ef52dcdf 100644 --- a/typescript/types/globals.d.ts +++ b/typescript/types/globals.d.ts @@ -1,10 +1,12 @@ -// TODO all of these globals (copied from eslintrc need to be typed at some point) -/* { +// TODO all of these globals (copied from eslintrc) need to be typed at some point +/* The typing status is listed on the left of the attribute, e.g.: +status "Attribute" + // Methods and Fields at https://banglejs.com/reference "Array": "readonly", "ArrayBuffer": "readonly", "ArrayBufferView": "readonly", - "Bangle": "readonly", +started "Bangle": "readonly", "BluetoothDevice": "readonly", "BluetoothRemoteGATTCharacteristic": "readonly", "BluetoothRemoteGATTServer": "readonly", @@ -20,8 +22,8 @@ "Float64Array": "readonly", "fs": "readonly", "Function": "readonly", - "Graphics": "readonly", // partly done - "heatshrink": "readonly", +started "Graphics": "readonly", +done "heatshrink": "readonly", "I2C": "readonly", "Int16Array": "readonly", "Int32Array": "readonly", @@ -107,7 +109,7 @@ "poke32": "readonly", "poke8": "readonly", "print": "readonly", - "require": "readonly", +started "require": "readonly", "reset": "readonly", "save": "readonly", "Serial1": "readonly", @@ -123,9 +125,8 @@ "trace": "readonly", "VIBRATE": "readonly", // Aliases and not defined at https://banglejs.com/reference - "g": "readonly", // done - "WIDGETS": "readonly" // done - } +done "g": "readonly", +done "WIDGETS": "readonly" */ // ambient JS definitions From 92b6fc0ea000968a6d24dba03f386f2ef6f99f07 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 22:57:12 -0800 Subject: [PATCH 023/447] Create app.js --- apps/aptSciClock/app.js | 206 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 apps/aptSciClock/app.js diff --git a/apps/aptSciClock/app.js b/apps/aptSciClock/app.js new file mode 100644 index 000000000..cb1305c36 --- /dev/null +++ b/apps/aptSciClock/app.js @@ -0,0 +1,206 @@ +const big = g.getWidth()>200; +const timeFontSize = big?5:4; +const dateFontSize = big?3:2; +const gmtFontSize = 2; +const font = "6x8"; + +const xyCenter = g.getWidth() / 2; +const yposTime = xyCenter*0.73; +const yposDate = xyCenter*1.44; +const yposYear = xyCenter*1.8; + +const buttonTolerance = 20; +const buttonX = 88; +const buttonY = 104; + +function getImg(img){ + if (img == "w0"){//drink + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOZFIQOD4EABwnwgEDBwf8g/4h4ODwYQBv4OC+AbDAIP+j/HAQIOC4Hwj4RBBwP8o8B/+PBwWOkEP/l/BwP4+JCB44OCj+Ih/+n4OB+PEoP38YOB/0YkUXGgIOB8cBi9f+IOCkEI+XvBwXigFG64OEg0/t4OEuP7BwkHx/PBwWigF8voOC+Uwg/ig4OCkMgv8QsIOB+cfSoOGLIUR/E/4ljBwPxx/B/0kO4UI/0P+J3C/HHVQOISoWEn+D/iPBBwIwC8IOCwcP84IBBwU4TAMHBwfAv+AcARBBgD3CBwX8gDnBBwfwewIODAgIABBwYHDB3oAEBwIHFByyDBABg")) +} + } + else if (img == "w1"){//cube + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOI/3/+fvBwYEBnwO/By3APgN/O6IeBh4OF8AOcwADCBwX8g4dM/8fBwt774OE+/9Bwt/BxodH3oOcFgyVG8BhCBwX8hRwCBwXA0C6BBwc/w4OE41MBwtEo6VF84sE/1/54OLDo4sHHYxKHLIxoGO44AD/kAABo")) + } + } + else if (img == "w2"){//acid + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOF+IOGngOF8/D8YGD/wdBB4nv4fzAwf4BwOfGQd/4f7/+//+f74OB4PwHIJKDx8P/4BBBwP8BwIBBBwXvh+Hw5ZD+Pwnl/NAcegJOBBwfgj0fBwvhBxcPgYEBBwXw/F+FghIB84OC/BfBOYQOBk/w/0f4f4nkGgFgh0hwED4H4jOBuF8hk/v/Hzlnx/zFgQZBGYLCD4EHaIn8gAOF8EDBwn+dgQOK/8AN4IOD+EABww0BBwqGEBwIWBBwk8CwIODg/gv4OEv4OD+4OBBAIOBRYIFBh+PcAQdC+gOCDoN+h/vBwPP/wOB/wOBwJCBBwP2oa3BLALgBiA7BOwIvB/+DQoV/d4hPBBwQsB/wJB8ZoEAAZoDAAQOPRQIAM")) + } + } + else if (img == "w3"){//turret + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOi+IOGh4OF8AOF/UNBwthx4OE+0YBwtBh4OE6mQBwn7rEfBwl22IOE99gBwn99UzBwUc/+90YsC8HH+++n98n/+g0++2Z+4OB4Fz73T74OCg877d8/YdC+d7u/v3gsBjEvt/+O4X+gvtIgI7CwG934OD8E326kD/0A+yzEwEO74OD/EArYOEgEDv4OD+PAl4OEnkBaInz0EPBwk3iAdE+XwSIYDBj2Oj4OD/fYvIOEvdHz4OD99unIOD/vt44OE3u4Dou3h4OE+3x/IOE70/Bwn78/9Bwl4LAQ7Dx75DBwP4Awb+EBwgAEBz0AABo=")) + } + } + else if (img == "w4"){//cake + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOY/oOG94OF/1/Bwv3FgwKCBwfnFhn8HY0LAQPwvgOB8EP/5uBBwP2gF4j+PBwP+sEEj/x44OB90Ao/8Dodwg8/nkH4ZXBgHnx8ABwPv/k98+ABwZEB+EAJQPj/3+nkAv4OB5+fz0Aj4OB98Ag+Ah/nBwJXB4EDHYSTB/EA/wsCSoJfBwAODNIPgBwgcBHYQOCC4QODn8Ah4ODGgMH+47D8EB/A7KTYMf4A7Eg/wHYgcBHZx3DcAPggbRBFgQcBcAQOB/iUBBwgcBBwgcCd4V/HYL+D/YOBDgIOC8/+DgIOC/+HfwIOD/4cCBwYAEBwQADBz0AABoA=")) + } + } + else if (img == "butPress"){ + return { + width : 176, height : 176, bpp : 4, + transparent : 1, + buffer : require("heatshrink").decompress(atob("iIA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AFEVqsFqpD/ACVVAAJXBqtRI35WSK4ZY/AB8VK49VJP5WRK4pY/ABhQEK41RJn5X/AEMVK5dVJv6uPK46w/K/4AgipPFgEALAxP/K5tQAQhX/K6KsDWApP/AA6uHWA9RIWPd6ICPK46qFAohXxjvd7oCMCAJX/K7cAAAZXFBQkBK/6v/ABPd6ICPK/4AaKIlQAhCv2ACMVVRC0FK2MdAIRXXVYSuFK/5XOqsAgCuFK/4AJJwtVKw1RK+MR7vRK/4AripXMJv6wQK4qu/K/4AjipXKJf5YRK4hJ/ABxXHqJI/LCRXCK34ASipXCIf4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACI=")) + } + } + else if (img == "butUnpress"){ + return { + width : 176, height : 176, bpp : 4, + transparent : 1, + buffer : require("heatshrink").decompress(atob("iIA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AFEc5kM5hD/ACXMAAJXB5nBI35WSK4ZY/AB8cK4/MJP5WRK4pY/ABhQEK43BJn5X/AEMcK5fMJv6uPK46w/K/4AgjhPFgEALAxP/K5vAAQhX/K6KsDWApP/AA6uHWA/BIWOIwICPK46qFAohXxjGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwICPK/4AaKInAAhCv2ACMcVRC0FK2MYAIRXXVYSuFK/5XO5kAgCuFK/4AJJwvMKw3BK+MRxGBK/4ArjhXMJv6wQK4qu/K/4AjjhXKJf5YRK4hJ/ABxXH4JI/LCRXCK34ASjhXCIf4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACI=")) + } + } + + else if (img == "apetureLaboratories"){ + return { + width : 173, height : 43, bpp : 4, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AA+IAAeAIv5UTK34APhABBKwpeBJX5VLJgJWGAwKv/ABL8EKomABIYA/KpJWHAoRW/KpZQCfwJSCAgRW/KphWFBgZW/KphNCAgSxEKP4ADJAatFKwWAL4oA/KpALGXQhS/Ko4MIwAOMAHREOKv5ZVVgcAh///4LDAwQAB+AIHCQYHMDQQYBDwQEGDIoaGTx4MCwAiCJgYhFBIYIHLw4HFBARjGESJUDehZVFVhJNLRI5VGDIIdEAgwiL+DzDJAJVJB4IMBCoKsHAYpFCDgr2IApYEIBpJFCKpqsCHgQbFIhBVHBhJoGTwyBRKp5mBDoY6GKoYqEXYg7JApKeHQJysEKpRmBDoasHQBAACM4qMGEAr0JAgZjGFYhVPgGAEIpVEAAaAEA4oyEW4qyKFZBoFKoisDJIJWLfIp3IQBJeJfgysMERpVCwEIVpijFBA6ZJdA4JHJYgEKQIx1EVgRVBVhj5IEIyZHHYoUGNw4MCQIwIKAARVDxBVRQo6ZJHZZoGU4yBGBAiBGVgRZBVhYlIfJBoFHZZoHfJRwGBAQrEVISvCKpwrEUZAqFVhzYKB4yKGQIpVDAYJVKEoYFDBIpVIb4ysMIgoPHOgoRFhGAVwKsLAFzQHACBVCVhQA/KpawBCJa76IhRWDVxIODAwTaFAocP///dhALGBQYJBCIYQBDYgKEBBAEDVgeIAgKgFBYZVEEYY+CH4YDBBgYFBBYoFEOYhmEDYgFFLIwEDKw2AKwhTFBoSsHIgglFAQo/HKIoDECBBZGc46eEAYa2EKox2Ga5LjLDoq8FKAgVDBAv/EghWGVgRWJKoaOFD4IgCViAWFVjKTGJIZOFKpKOHAQj3JAogCFPApcGKQziGLopKCU4hWFKojsEHYrXFCAJFId45CEDYh4EB4Y1DCYSzFJQT+FgAGCKooA/AAZMBfopWDKv5WLVgxT/AB+AKopW/ACBU/ABwA==")) + } + } + + else if (img == "apetureWatch"){ + return { + width : 176, height : 176, bpp : 4, + transparent : 2, + buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0SkQASkIVViIrqK/5X/K/5X/CqPd6EAAA8BiAKIABUBiIVUFZMIxBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xal////yK/5XTKwIABK4URAA3/+Pd6ILHAG8YxADBj5XD+ISIBwRX/K4pWDAAIHBiS6CAAMvBYXd6DbTeJcRCqgrJhGIJIJXFkUhK4oLDK/5XSBYhX/K6MvBIQDBK/5XD+RXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+SuEK4yuCK/5XHWAZOCK4cvKwhX/K45MFK4YAGK/5XGLApX/K6X/K5svK/5XIWAZXJ/5X/K6svK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/yK44GDVwRX/K50fWAi9DK/5XGUYRQCkMSK4auDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYXyK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAhXBAoa/Cl5X/K4ZHCAAZXEAoZnCK/5XLVQRXFBgZX/K4igCLAnxK4RdBBohX/K5cikJXCAAxX/K4j5EK/5X/K9fyK/5X/K93/K/5X/KxQABK78vK4PyK/5XWWApXq+JXC+BXeKwRXPl5Xdh//K4Y1BK+H/K7n//GIK4g5BWR5XP+RXNl5Xch+IGQJXFA4JXeJwpXICAJXah/4x4fBKwURj5XBBIJXcVwpXBFoYwDK4XRBYwAR/CtFAAZXCBQ4AQjBXCCRxXcUoJLDjnMhnMBgTqCK7RzIiS3FkRXC6DbTAAf4UYIoB5gABK4PM4KBD+AcLFZUIK4JNGkUhK44ABK7EPQwZWCK4ZYCWARXY+RXrVwccK4/MWB5XMJhBXkVwJWEK4pYBK/4AGh+IVwJQEK43BWARX/VwmP+JXNWBpX5VwMcK5fMiKwBK9YAKCphXCJ4pXH4JXB+QrWCtUvxHxK58R///K/5XCx/xjhPFdAJYGK/5XN4ACEK/4AIIYMRK4qsDWAsRj//+RX/iIACVw6wH4ITCEJBXlxGCARxXIVQoFEK+MoxGIARgQBK/5XbgAADK4oKEgJX/V/4AJxGCARxX/Cq5XI4AEIV+wVO///iMcVRC0FiMf//yTNIADlABCCp0v//xK4qrCVwpXB/+PeNRXf5kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwQVQ///K58f/HyK94VSK4UcK5kRj+IK8I1BADhXE+KwGK4vBiP4x5XhEJQASl4DDWARXMj/4NwZX/WAkcK5UR/+IGgbeXK9awBLAhXEiKuBx40DHCYuEK9EvWAURK4/BVwSWEK/6wGLAZXCKwKuGK/6wIiMcK4QFBVw5X/WA2IwJSCAAYJBVwpX/WA2IJwJVDj///GPVwpX/A434K4PxVoYHBKwxX/AAynCK4ZWCGA5X/BI//V4itHK/4LKK4YtKK/4qJK4QOKK/5X/K8BYCBpZX/K/5XVfYQAWK6gedK/5XiBhchiINLK6grJK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xu/4AYV/4AXK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6v/ADCv/ABMhiKv/K/5X/K/5X/K/5X/K/5X6/4AdiIAYFzw=")) + } + } +} + + +function drawStart(){ + g.clear(); + g.reset(); + apSciLab = getImg("apetureLaboratories"); + g.drawImage(apSciLab, xyCenter-apSciLab.width/2, xyCenter-apSciLab.height/2); +} + +drawStart(); + +// Check settings for what type our clock should be +var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; + +// timeout used to update every minute +var drawTimeout; + +//warnings +var curWarning = -1; +var maxWarning = 4; + +function buttonPressed(){ + if (curWarning < maxWarning) curWarning += 1; + else curWarning = 0; + buttonImg = getImg("butPress"); + g.drawImage(buttonImg, 0, 0); + + warningImg = getImg("w"+String(curWarning)); + g.drawImage(warningImg, 1, g.getWidth()-61); + + setTimeout(buttonUnpressed, 500); +} +function buttonUnpressed(){ + buttonImg = getImg("butUnpress"); + g.drawImage(buttonImg, 0, 0); +} + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + + +function draw() { + // get date + var d = new Date(); + var da = d.toString().split(" "); + + g.reset(); // default draw styles + + //draw watchface + apSciWatch = getImg("apetureWatch"); + g.drawImage(apSciWatch, xyCenter-apSciWatch.width/2, xyCenter-apSciWatch.height/2); + + // drawSting centered + g.setFontAlign(0, 0); + + // draw time + var time = da[4].substr(0, 5).split(":"); + var hours = time[0], + minutes = time[1]; + var meridian = ""; + if (is12Hour) { + hours = parseInt(hours,10); + meridian = "AM"; + if (hours == 0) { + hours = 12; + meridian = "AM"; + } else if (hours >= 12) { + meridian = "PM"; + if (hours>12) hours -= 12; + } + hours = (" "+hours).substr(-2); + } + + g.setFont(font, timeFontSize); + g.drawString(`${hours}:${minutes}`, xyCenter, yposTime, false); + g.setFont(font, gmtFontSize); + g.drawString(meridian, xyCenter + 102, yposTime + 10, true); + + // draw Day, name of month, Date + var date = [da[0], da[1], da[2]].join(" "); + g.setFont(font, dateFontSize); + + g.drawString(String(da[0]), xyCenter*1.55, yposDate, true); + g.drawString(String(da[1]), xyCenter*1.55, yposDate+20*1, true); + g.drawString(String(da[2]), xyCenter*1.55, yposDate+20*2, true); + + + // draw year + g.setFont(font, dateFontSize); + g.drawString(d.getFullYear(), xyCenter+1, yposYear, true); + + queueDraw(); +} + + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + +Bangle.on('touch',(n,e)=>{ + //button is 88 104 + if (buttonX-buttonTolerance < e.x && e.x < buttonX+buttonTolerance && buttonY-buttonTolerance < e.y && e.y < buttonY+buttonTolerance){ + buttonPressed(); + } +}); + +// clean app screen +g.clear(); +// Show launcher when button pressed +Bangle.setUI("clock"); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +buttonPressed();//update warning image + +// draw now +draw(); From 4113dab20b004d974df743fc164f362086f44063 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:09:34 -0800 Subject: [PATCH 024/447] Add files via upload --- apps/aptSciClock/App.png | Bin 0 -> 714 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/aptSciClock/App.png diff --git a/apps/aptSciClock/App.png b/apps/aptSciClock/App.png new file mode 100644 index 0000000000000000000000000000000000000000..b37efdaf87f40701f3599655074d11a22bf2ff11 GIT binary patch literal 714 zcmV;*0yX`KP)L z17IEMg|K#r{J;RL^LnLPK*|`;7J!HWTAUY7FL9iYc~@j+`DRVteY zwLCHZ_W?#YpOq8>DDydyI0N)LPb8kJb%_?TZ|3gl8Ha$Z)OIB#PB3FT~o`pF_Pw8t!2*VeN>iwlrse+R13PgiuG`%lo+#{}%wVKOF(0bLq?oFwUPMz??~E zK`;QjzwZbH&El12GXNOp-2)AoG?x}3ba&*OOL8Z&t0RC`AKnY02_$sP;XfNHZ9B1n zJl{$n!}{vuQxQ>i^A}rQvX25`6>!*%+7(BWM3+x22(nRAfg`Q_-^?KySfl9uCp|0hAdt wJ4o$;{H8^Iroccu@ALzBhEWe`bk-a82X Date: Sun, 19 Dec 2021 23:10:52 -0800 Subject: [PATCH 025/447] Delete App.png --- apps/aptSciClock/App.png | Bin 714 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/aptSciClock/App.png diff --git a/apps/aptSciClock/App.png b/apps/aptSciClock/App.png deleted file mode 100644 index b37efdaf87f40701f3599655074d11a22bf2ff11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 714 zcmV;*0yX`KP)L z17IEMg|K#r{J;RL^LnLPK*|`;7J!HWTAUY7FL9iYc~@j+`DRVteY zwLCHZ_W?#YpOq8>DDydyI0N)LPb8kJb%_?TZ|3gl8Ha$Z)OIB#PB3FT~o`pF_Pw8t!2*VeN>iwlrse+R13PgiuG`%lo+#{}%wVKOF(0bLq?oFwUPMz??~E zK`;QjzwZbH&El12GXNOp-2)AoG?x}3ba&*OOL8Z&t0RC`AKnY02_$sP;XfNHZ9B1n zJl{$n!}{vuQxQ>i^A}rQvX25`6>!*%+7(BWM3+x22(nRAfg`Q_-^?KySfl9uCp|0hAdt wJ4o$;{H8^Iroccu@ALzBhEWe`bk-a82X Date: Sun, 19 Dec 2021 23:11:25 -0800 Subject: [PATCH 026/447] Renamed folder --- apps/{aptSciClock => aptsciclk}/app.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/{aptSciClock => aptsciclk}/app.js (100%) diff --git a/apps/aptSciClock/app.js b/apps/aptsciclk/app.js similarity index 100% rename from apps/aptSciClock/app.js rename to apps/aptsciclk/app.js From 498f0701599dcb26412ce19df3be79be27ae2bdb Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:11:45 -0800 Subject: [PATCH 027/447] Add files via upload --- apps/aptsciclk/App.png | Bin 0 -> 714 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/aptsciclk/App.png diff --git a/apps/aptsciclk/App.png b/apps/aptsciclk/App.png new file mode 100644 index 0000000000000000000000000000000000000000..b37efdaf87f40701f3599655074d11a22bf2ff11 GIT binary patch literal 714 zcmV;*0yX`KP)L z17IEMg|K#r{J;RL^LnLPK*|`;7J!HWTAUY7FL9iYc~@j+`DRVteY zwLCHZ_W?#YpOq8>DDydyI0N)LPb8kJb%_?TZ|3gl8Ha$Z)OIB#PB3FT~o`pF_Pw8t!2*VeN>iwlrse+R13PgiuG`%lo+#{}%wVKOF(0bLq?oFwUPMz??~E zK`;QjzwZbH&El12GXNOp-2)AoG?x}3ba&*OOL8Z&t0RC`AKnY02_$sP;XfNHZ9B1n zJl{$n!}{vuQxQ>i^A}rQvX25`6>!*%+7(BWM3+x22(nRAfg`Q_-^?KySfl9uCp|0hAdt wJ4o$;{H8^Iroccu@ALzBhEWe`bk-a82X Date: Sun, 19 Dec 2021 23:12:57 -0800 Subject: [PATCH 028/447] Create app-icon.js --- apps/aptsciclk/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/aptsciclk/app-icon.js diff --git a/apps/aptsciclk/app-icon.js b/apps/aptsciclk/app-icon.js new file mode 100644 index 000000000..d2a2dbbd6 --- /dev/null +++ b/apps/aptsciclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwgNKxAACEaIVDDKWAhAXGwAtODA4HBLR4YFD4QWICIhABGAoMBJRBZHC4wwHOQ4IFAgQwGUQ4YBAg4uMJIwDDGAjRLIgYLHc5gXJIwbKLC4hICb4gZKfAhgETJKHJLwwXRUooWKCImAJogXRMopGMNwkIC4oWLYYqtHC5rFJC5h0GIxwsGFyD8CC4wwOIxBIQFwoeBCxrwEFwYXTFgTXReI4uQC4apPC4xNERqBlGFx4XCeJ4nHD4kIIxY3KPoIxNBwYXEJRInEP44iGOgwXFBYYcDChCHHC4wMBC5BnJEoouMGAYXEJJCCJC4pOEcpYKBFIpJFZRQXGD4gWKXBUICxjdFIhwyJOJMAA=")) From 8ed719a73a072f4f6c123160324be653a553bd31 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:16:25 -0800 Subject: [PATCH 029/447] Delete App.png --- apps/aptsciclk/App.png | Bin 714 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/aptsciclk/App.png diff --git a/apps/aptsciclk/App.png b/apps/aptsciclk/App.png deleted file mode 100644 index b37efdaf87f40701f3599655074d11a22bf2ff11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 714 zcmV;*0yX`KP)L z17IEMg|K#r{J;RL^LnLPK*|`;7J!HWTAUY7FL9iYc~@j+`DRVteY zwLCHZ_W?#YpOq8>DDydyI0N)LPb8kJb%_?TZ|3gl8Ha$Z)OIB#PB3FT~o`pF_Pw8t!2*VeN>iwlrse+R13PgiuG`%lo+#{}%wVKOF(0bLq?oFwUPMz??~E zK`;QjzwZbH&El12GXNOp-2)AoG?x}3ba&*OOL8Z&t0RC`AKnY02_$sP;XfNHZ9B1n zJl{$n!}{vuQxQ>i^A}rQvX25`6>!*%+7(BWM3+x22(nRAfg`Q_-^?KySfl9uCp|0hAdt wJ4o$;{H8^Iroccu@ALzBhEWe`bk-a82X Date: Sun, 19 Dec 2021 23:16:36 -0800 Subject: [PATCH 030/447] Add files via upload --- apps/aptsciclk/app.png | Bin 0 -> 714 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/aptsciclk/app.png diff --git a/apps/aptsciclk/app.png b/apps/aptsciclk/app.png new file mode 100644 index 0000000000000000000000000000000000000000..b37efdaf87f40701f3599655074d11a22bf2ff11 GIT binary patch literal 714 zcmV;*0yX`KP)L z17IEMg|K#r{J;RL^LnLPK*|`;7J!HWTAUY7FL9iYc~@j+`DRVteY zwLCHZ_W?#YpOq8>DDydyI0N)LPb8kJb%_?TZ|3gl8Ha$Z)OIB#PB3FT~o`pF_Pw8t!2*VeN>iwlrse+R13PgiuG`%lo+#{}%wVKOF(0bLq?oFwUPMz??~E zK`;QjzwZbH&El12GXNOp-2)AoG?x}3ba&*OOL8Z&t0RC`AKnY02_$sP;XfNHZ9B1n zJl{$n!}{vuQxQ>i^A}rQvX25`6>!*%+7(BWM3+x22(nRAfg`Q_-^?KySfl9uCp|0hAdt wJ4o$;{H8^Iroccu@ALzBhEWe`bk-a82X Date: Sun, 19 Dec 2021 23:20:44 -0800 Subject: [PATCH 031/447] Added aptsciclk --- apps.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps.json b/apps.json index e5e9f8f02..f1d9c962f 100644 --- a/apps.json +++ b/apps.json @@ -5047,6 +5047,21 @@ {"name":"circlesclock.json"} ] }, + { "id": "aptsciclk", + "name": "Apeture Science clock", + "shortName":"AptSci clock", + "version":"0.01", + "description": "A clock based on the Portal series, + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator":true, + "storage": [ + {"name":"aptsciclk.app.js","url":"app.js"}, + {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true}, + ] + }, { "id": "ltherm", "name": "Localized Thermometer", From 3e090cd727ba2d929a7ba212fb0b6f360406c830 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:28:04 -0800 Subject: [PATCH 032/447] Update apps.json --- apps.json | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/apps.json b/apps.json index f1d9c962f..5abe84172 100644 --- a/apps.json +++ b/apps.json @@ -5047,21 +5047,6 @@ {"name":"circlesclock.json"} ] }, - { "id": "aptsciclk", - "name": "Apeture Science clock", - "shortName":"AptSci clock", - "version":"0.01", - "description": "A clock based on the Portal series, - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator":true, - "storage": [ - {"name":"aptsciclk.app.js","url":"app.js"}, - {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true}, - ] - }, { "id": "ltherm", "name": "Localized Thermometer", @@ -5077,5 +5062,19 @@ {"name":"ltherm.app.js","url":"app.js"}, {"name":"ltherm.img","url":"icon.js","evaluate":true} ] - } + }, + }, +{ "id": "aptsciclk", + "name": "Apeture Science Clock", + "shortName":"Apeture", + "icon": "app.png", + "version":"0.01", + "description": "A clock made in the style of the Portal series", + "tags": "clock", + "type":"clock", + "storage": [ + {"name":"aptsciclk.app.js","url":"app.js"}, + {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} + ] +} ] From d63a9975955aa65616b3bc3f078c22ee1c1fecdb Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:32:45 -0800 Subject: [PATCH 033/447] Update apps.json --- apps.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 5abe84172..0a9cd40f9 100644 --- a/apps.json +++ b/apps.json @@ -5070,8 +5070,9 @@ "icon": "app.png", "version":"0.01", "description": "A clock made in the style of the Portal series", - "tags": "clock", "type":"clock", + "tags": "clock", + "supports": ["BANGLEJS2"], "storage": [ {"name":"aptsciclk.app.js","url":"app.js"}, {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} From 8066e3d8ab82614edd2d0847160ebcf5299bc637 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:34:40 -0800 Subject: [PATCH 034/447] Update apps.json --- apps.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps.json b/apps.json index 0a9cd40f9..bc7c74703 100644 --- a/apps.json +++ b/apps.json @@ -5063,7 +5063,6 @@ {"name":"ltherm.img","url":"icon.js","evaluate":true} ] }, - }, { "id": "aptsciclk", "name": "Apeture Science Clock", "shortName":"Apeture", From 58ede020fa44bd2f8f8f907f3e0aa0556ecaefb5 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:36:57 -0800 Subject: [PATCH 035/447] Update apps.json --- apps.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index bc7c74703..c1d50ca6e 100644 --- a/apps.json +++ b/apps.json @@ -5065,11 +5065,11 @@ }, { "id": "aptsciclk", "name": "Apeture Science Clock", - "shortName":"Apeture", + "shortName": "Apeture", "icon": "app.png", - "version":"0.01", + "version": "0.01", "description": "A clock made in the style of the Portal series", - "type":"clock", + "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], "storage": [ From 6947bdf5fe7e36cb4bac83343efde84321c33d2f Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:40:55 -0800 Subject: [PATCH 036/447] Update apps.json --- apps.json | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/apps.json b/apps.json index c1d50ca6e..6e6f84426 100644 --- a/apps.json +++ b/apps.json @@ -5063,18 +5063,19 @@ {"name":"ltherm.img","url":"icon.js","evaluate":true} ] }, -{ "id": "aptsciclk", - "name": "Apeture Science Clock", - "shortName": "Apeture", - "icon": "app.png", - "version": "0.01", - "description": "A clock made in the style of the Portal series", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"aptsciclk.app.js","url":"app.js"}, - {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} - ] +{ + "id": "aptsciclk", + "name": "Apeture Science Clock", + "version": "0.1", + "description": "A clock based on the portal series", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"aptsciclk.app.js","url":"app.js"}, + {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} + ] } ] From 7f3864f310445fcc634e012ecebf4187e0a34445 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:43:37 -0800 Subject: [PATCH 037/447] Update apps.json --- apps.json | 5064 ----------------------------------------------------- 1 file changed, 5064 deletions(-) diff --git a/apps.json b/apps.json index 6e6f84426..1d792ecfc 100644 --- a/apps.json +++ b/apps.json @@ -1,5068 +1,4 @@ [ - { - "id": "fwupdate", - "name": "Firmware Update", - "version": "0.02", - "description": "[BETA] Uploads new Espruino firmwares to Bangle.js 2. For now, please use the instructions under https://www.espruino.com/Bangle.js2#firmware-updates", - "icon": "app.png", - "type": "RAM", - "tags": "tools,system", - "supports": ["BANGLEJS2"], - "custom": "custom.html", - "customConnect": true, - "storage": [], - "sortorder": 20 - }, - { - "id": "boot", - "name": "Bootloader", - "version": "0.39", - "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", - "icon": "bootloader.png", - "type": "bootloader", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":".boot0","url":"boot0.js"}, - {"name":".bootcde","url":"bootloader.js"}, - {"name":"bootupdate.js","url":"bootupdate.js"} - ], - "sortorder": -10 - }, - { - "id": "hebrew_calendar", - "name": "Hebrew Calendar", - "shortName": "HebCal", - "version": "0.04", - "description": "lists the date according to the hebrew calendar", - "icon": "app.png", - "allow_emulator": false, - "tags": "tool,locale", - "supports": [ - "BANGLEJS", - "BANGLEJS2" - ], - "readme": "README.md", - "storage": [ - { - "name": "hebrew_calendar.app.js", - "url": "app.js" - }, - { - "name": "hebrewDate", - "url": "hebrewDate.js" - }, - { - "name": "hebrew_calendar.img", - "url": "app-icon.js", - "evaluate": true - } - ] - }, - { "id": "golfscore", - "name": "Golf Score", - "shortName":"golfscore", - "version":"0.02", - "description": "keeps track of strokes during a golf game", - "icon": "app.png", - "tags": "outdoors", - "allow_emulator": true, - "supports" : ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"golfscore.app.js","url":"app.js"}, - {"name":"golfscore.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "messages", - "name": "Messages", - "version": "0.14", - "description": "App to display notifications from iOS and Gadgetbridge", - "icon": "app.png", - "type": "app", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"messages.app.js","url":"app.js"}, - {"name":"messages.settings.js","url":"settings.js"}, - {"name":"messages.img","url":"app-icon.js","evaluate":true}, - {"name":"messages.wid.js","url":"widget.js"}, - {"name":"messages","url":"lib.js"} - ], - "data": [{"name":"messages.json"},{"name":"messages.settings.json"}], - "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-notify.gif"}], - "sortorder": -9 - }, - { - "id": "android", - "name": "Android Integration", - "shortName": "Android", - "version": "0.05", - "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", - "icon": "app.png", - "tags": "tool,system,messages,notifications", - "dependencies": {"messages":"app"}, - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"android.app.js","url":"app.js"}, - {"name":"android.settings.js","url":"settings.js"}, - {"name":"android.img","url":"app-icon.js","evaluate":true}, - {"name":"android.boot.js","url":"boot.js"} - ], - "sortorder": -8 - }, - { - "id": "ios", - "name": "iOS Integration", - "version": "0.07", - "description": "Display notifications/music/etc from iOS devices", - "icon": "app.png", - "tags": "tool,system,ios,apple,messages,notifications", - "dependencies": {"messages":"app"}, - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"ios.app.js","url":"app.js"}, - {"name":"ios.img","url":"app-icon.js","evaluate":true}, - {"name":"ios.boot.js","url":"boot.js"} - ], - "sortorder": -8 - }, - { - "id": "health", - "name": "Health Tracking", - "version": "0.09", - "description": "Logs health data and provides an app to view it (requires firmware 2v10.100 or later)", - "icon": "app.png", - "tags": "tool,system,health", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"health.app.js","url":"app.js"}, - {"name":"health.img","url":"app-icon.js","evaluate":true}, - {"name":"health.boot.js","url":"boot.js"}, - {"name":"health","url":"lib.js"} - ] - }, - { - "id": "launch", - "name": "Launcher", - "shortName": "Launcher", - "version": "0.10", - "description": "This is needed to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", - "icon": "app.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"launch.app.js","url":"app-bangle1.js","supports":["BANGLEJS"]}, - {"name":"launch.app.js","url":"app-bangle2.js","supports":["BANGLEJS2"]}, - {"name":"launch.settings.js","url":"settings.js","supports":["BANGLEJS2"]} - ], - "data": [{"name":"launch.json"}], - "sortorder": -10 - }, - { - "id": "setting", - "name": "Settings", - "version": "0.38", - "description": "A menu for setting up Bangle.js", - "icon": "settings.png", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"setting.app.js","url":"settings.js"}, - {"name":"setting.img","url":"settings-icon.js","evaluate":true} - ], - "data": [{"name":"setting.json","url":"settings.min.json","evaluate":true}], - "sortorder": -5 - }, - { - "id": "about", - "name": "About", - "version": "0.12", - "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", - "icon": "app.png", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"bangle1-about-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"about.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, - {"name":"about.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, - {"name":"about.img","url":"app-icon.js","evaluate":true} - ], - "sortorder": -4 - }, - { - "id": "alarm", - "name": "Default Alarm & Timer", - "shortName": "Alarms", - "version": "0.14", - "description": "Set and respond to alarms and timers", - "icon": "app.png", - "tags": "tool,alarm,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"alarm.app.js","url":"app.js"}, - {"name":"alarm.boot.js","url":"boot.js"}, - {"name":"alarm.js","url":"alarm.js"}, - {"name":"alarm.img","url":"app-icon.js","evaluate":true}, - {"name":"alarm.wid.js","url":"widget.js"} - ], - "data": [{"name":"alarm.json"}] - }, - { - "id": "locale", - "name": "Languages", - "version": "0.14", - "description": "Translations for different countries", - "icon": "locale.png", - "type": "locale", - "tags": "tool,system,locale,translate", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "custom": "locale.html", - "storage": [ - {"name":"locale"} - ], - "sortorder": -10 - }, - { - "id": "notify", - "name": "Notifications (default)", - "shortName": "Notifications", - "version": "0.11", - "description": "Provides the default `notify` module used by applications to display notifications in a bar at the top of the screen. This module is installed by default by client applications such as the Gadgetbridge app. Installing `Fullscreen Notifications` replaces this module with a version that displays the notifications using the full screen", - "icon": "notify.png", - "type": "notify", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"notify","url":"notify.js"} - ] - }, - { - "id": "notifyfs", - "name": "Fullscreen Notifications", - "shortName": "Notifications", - "version": "0.12", - "description": "Provides a replacement for the `Notifications (default)` `notify` module. This version is used by applications to display notifications fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notify module.", - "icon": "notify.png", - "type": "notify", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"notify","url":"notify.js"} - ] - }, - { - "id": "welcome", - "name": "Welcome", - "shortName": "Welcome", - "version": "0.14", - "description": "Appears at first boot and explains how to use Bangle.js", - "icon": "app.png", - "screenshots": [{"url":"screenshot_welcome.png"}], - "tags": "start,welcome", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"welcome.boot.js","url":"boot.js"}, - {"name":"welcome.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, - {"name":"welcome.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, - {"name":"welcome.settings.js","url":"settings.js"}, - {"name":"welcome.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"welcome.json"}] - }, - { - "id": "mywelcome", - "name": "Customised Welcome", - "shortName": "My Welcome", - "version": "0.13", - "description": "Appears at first boot and explains how to use Bangle.js. Like 'Welcome', but can be customised with a greeting", - "icon": "app.png", - "tags": "start,welcome", - "supports": ["BANGLEJS","BANGLEJS2"], - "custom": "custom.html", - "screenshots": [{"url":"bangle1-customized-welcome-screenshot.png"}], - "storage": [ - {"name":"mywelcome.boot.js","url":"boot.js"}, - {"name":"mywelcome.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, - {"name":"mywelcome.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, - {"name":"mywelcome.settings.js","url":"settings.js"}, - {"name":"mywelcome.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"mywelcome.json"}] - }, - { - "id": "gbridge", - "name": "Gadgetbridge", - "version": "0.25", - "description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android' Bangle.js app instead.", - "icon": "app.png", - "type": "widget", - "tags": "tool,system,android,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "dependencies": {"notify":"type"}, - "readme": "README.md", - "storage": [ - {"name":"gbridge.settings.js","url":"settings.js"}, - {"name":"gbridge.img","url":"app-icon.js","evaluate":true}, - {"name":"gbridge.wid.js","url":"widget.js"} - ], - "data": [{"name":"gbridge.json"}] - }, - { "id": "gbdebug", - "name": "Gadgetbridge Debug", - "shortName":"GB Debug", - "version":"0.01", - "description": "Debug info for Gadgetbridge. Run this app and when Gadgetbridge messages arrive they are displayed on-screen.", - "icon": "app.png", - "tags": "", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"gbdebug.app.js","url":"app.js"}, - {"name":"gbdebug.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "mclock", - "name": "Morphing Clock", - "version": "0.07", - "description": "7 segment clock that morphs between minutes and hours", - "icon": "clock-morphing.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-morphing-clock-screenshot.png"}], - "storage": [ - {"name":"mclock.app.js","url":"clock-morphing.js"}, - {"name":"mclock.img","url":"clock-morphing-icon.js","evaluate":true} - ], - "sortorder": -9 - }, - { - "id": "moonphase", - "name": "Moonphase", - "version": "0.02", - "description": "Shows current moon phase. Now with GPS function.", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-moon-phase-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"moonphase.app.js","url":"app.js"}, - {"name":"moonphase.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "daysl", - "name": "Days left", - "version": "0.03", - "description": "Shows you the days left until a certain date. Date can be set with a settings app and is written to a file.", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "allow_emulator": false, - "storage": [ - {"name":"daysl.app.js","url":"app.js"}, - {"name":"daysl.img","url":"app-icon.js","evaluate":true}, - {"name":"daysl.wid.js","url":"widget.js"} - ] - }, - { - "id": "wclock", - "name": "Word Clock", - "version": "0.03", - "description": "Display Time as Text", - "icon": "clock-word.png", - "screenshots": [{"url":"screenshot_word.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"wclock.app.js","url":"clock-word.js"}, - {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} - ] - }, - { - "id": "fontclock", - "name": "Font Clock", - "version": "0.01", - "description": "Choose the font and design of clock face from a library of available designs", - "icon": "fontclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "allow_emulator": false, - "storage": [ - {"name":"fontclock.app.js","url":"fontclock.js"}, - {"name":"fontclock.img","url":"fontclock-icon.js","evaluate":true}, - {"name":"fontclock.hand.js","url":"fontclock.hand.js"}, - {"name":"fontclock.thinhand.js","url":"fontclock.thinhand.js"}, - {"name":"fontclock.thickhand.js","url":"fontclock.thickhand.js"}, - {"name":"fontclock.hourscriber.js","url":"fontclock.hourscriber.js"}, - {"name":"fontclock.font.js","url":"fontclock.font.js"}, - {"name":"fontclock.font.abril_ff50.js","url":"fontclock.font.abril_ff50.js"}, - {"name":"fontclock.font.cpstc58.js","url":"fontclock.font.cpstc58.js"}, - {"name":"fontclock.font.mntn25.js","url":"fontclock.font.mntn25.js"}, - {"name":"fontclock.font.mntn50.js","url":"fontclock.font.mntn50.js"}, - {"name":"fontclock.font.vector25.js","url":"fontclock.font.vector25.js"}, - {"name":"fontclock.font.vector50.js","url":"fontclock.font.vector50.js"} - ] - }, - { - "id": "slidingtext", - "name": "Sliding Clock", - "version": "0.07", - "description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported", - "icon": "slidingtext.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "custom": "custom.html", - "allow_emulator": false, - "storage": [ - {"name":"slidingtext.app.js","url":"slidingtext.js"}, - {"name":"slidingtext.img","url":"slidingtext-icon.js","evaluate":true}, - {"name":"slidingtext.locale.en.js","url":"slidingtext.locale.en.js"}, - {"name":"slidingtext.locale.en2.js","url":"slidingtext.locale.en2.js"}, - {"name":"slidingtext.utils.en.js","url":"slidingtext.utils.en.js"}, - {"name":"slidingtext.locale.es.js","url":"slidingtext.locale.es.js"}, - {"name":"slidingtext.locale.fr.js","url":"slidingtext.locale.fr.js"}, - {"name":"slidingtext.locale.jp.js","url":"slidingtext.locale.jp.js"}, - {"name":"slidingtext.locale.de.js","url":"slidingtext.locale.de.js"}, - {"name":"slidingtext.dtfmt.js","url":"slidingtext.dtfmt.js"} - ] - }, - { - "id": "solarclock", - "name": "Solar Clock", - "version": "0.02", - "description": "Using your current or chosen location the solar watch face shows the Sun's sky position, time and date. Also allows you to wind backwards and forwards in time to see the sun's position", - "icon": "solar_clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "allow_emulator": false, - "storage": [ - {"name":"solarclock.app.js","url":"solar_clock.js"}, - {"name":"solarclock.img","url":"solar_clock-icon.js","evaluate":true}, - {"name":"solar_colors.js","url":"solar_colors.js"}, - {"name":"solar_controller.js","url":"solar_controller.js"}, - {"name":"solar_date_utils.js","url":"solar_date_utils.js"}, - {"name":"solar_graphic_utils.js","url":"solar_graphic_utils.js"}, - {"name":"solar_location.js","url":"solar_location.js"}, - {"name":"solar_math_utils.js","url":"solar_math_utils.js"}, - {"name":"solar_loc.Reykjavik.json","url":"solar_loc.Reykjavik.json"}, - {"name":"solar_loc.Hong_Kong.json","url":"solar_loc.Hong_Kong.json"}, - {"name":"solar_loc.Honolulu.json","url":"solar_loc.Honolulu.json"}, - {"name":"solar_loc.Rio.json","url":"solar_loc.Rio.json"}, - {"name":"solar_loc.Tokyo.json","url":"solar_loc.Tokyo.json"}, - {"name":"solar_loc.Seoul.json","url":"solar_loc.Seoul.json"} - ] - }, - { - "id": "sweepclock", - "name": "Sweep Clock", - "version": "0.04", - "description": "Smooth sweep secondhand with single hour numeral. Use button 1 to toggle the numeral font, button 3 to change the colour theme and button 4 to change the date placement", - "icon": "sweepclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-sweep-clock-screenshot.png"}], - "storage": [ - {"name":"sweepclock.app.js","url":"sweepclock.js"}, - {"name":"sweepclock.img","url":"sweepclock-icon.js","evaluate":true} - ] - }, - { - "id": "matrixclock", - "name": "Matrix Clock", - "version": "0.02", - "description": "inspired by The Matrix, a clock of the same style", - "icon": "matrixclock.png", - "screenshots": [{"url":"screenshot_matrix.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"matrixclock.app.js","url":"matrixclock.js"}, - {"name":"matrixclock.img","url":"matrixclock-icon.js","evaluate":true} - ] - }, - { - "id": "mandelbrotclock", - "name": "Mandelbrot Clock", - "version": "0.01", - "description": "A mandelbrot set themed clock cool", - "icon": "mandelbrotclock.png", - "screenshots": [{ "url": "screenshot_mandelbrotclock.png" }], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - { "name": "mandelbrotclock.app.js", "url": "mandelbrotclock.js" }, - { - "name": "mandelbrotclock.img", - "url": "mandelbrotclock-icon.js", - "evaluate": true - } - ] - }, - { - "id": "imgclock", - "name": "Image background clock", - "shortName": "Image Clock", - "version": "0.08", - "description": "A clock with an image as a background", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [ - {"name":"imgclock.app.js","url":"app.js"}, - {"name":"imgclock.img","url":"app-icon.js","evaluate":true}, - {"name":"imgclock.face.img"}, - {"name":"imgclock.face.json"}, - {"name":"imgclock.face.bg","content":""} - ] - }, - { - "id": "impwclock", - "name": "Imprecise Word Clock", - "version": "0.04", - "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", - "icon": "clock-impword.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"bangle1-impercise-word-clock-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"impwclock.app.js","url":"clock-impword.js"}, - {"name":"impwclock.img","url":"clock-impword-icon.js","evaluate":true} - ] - }, - { - "id": "aclock", - "name": "Analog Clock", - "version": "0.15", - "description": "An Analog Clock", - "icon": "clock-analog.png", - "screenshots": [{"url":"screenshot_analog.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"aclock.app.js","url":"clock-analog.js"}, - {"name":"aclock.img","url":"clock-analog-icon.js","evaluate":true} - ] - }, - { - "id": "clock2x3", - "name": "2x3 Pixel Clock", - "version": "0.05", - "description": "This is a simple clock using minimalist 2x3 pixel numerical digits", - "icon": "clock2x3.png", - "screenshots": [{"url":"screenshot_pixel.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"clock2x3.app.js","url":"clock2x3-app.js"}, - {"name":"clock2x3.img","url":"clock2x3-icon.js","evaluate":true} - ] - }, - { - "id": "geissclk", - "name": "Geiss Clock", - "version": "0.03", - "description": "7 segment clock with animated background in the style of Ryan Geiss' music visualisation. NOTE: The first run will take ~1 minute to do some precalculation", - "icon": "clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"geissclk.app.js","url":"clock.js"}, - {"name":"geissclk.precompute.js","url":"precompute.js"}, - {"name":"geissclk.img","url":"clock-icon.js","evaluate":true} - ], - "data": [{"name":"geissclk.0.map"},{"name":"geissclk.1.map"},{"name":"geissclk.2.map"},{"name":"geissclk.3.map"},{"name":"geissclk.4.map"},{"name":"geissclk.5.map"},{"name":"geissclk.0.pal"},{"name":"geissclk.1.pal"},{"name":"geissclk.2.pal"}] - }, - { - "id": "trex", - "name": "T-Rex", - "version": "0.04", - "description": "T-Rex game in the style of Chrome's offline game", - "icon": "trex.png", - "screenshots": [{"url":"screenshot_trex.png"}], - "tags": "game", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"trex.app.js","url":"trex.js"}, - {"name":"trex.img","url":"trex-icon.js","evaluate":true}, - {"name":"trex.settings.js","url":"settings.js"} - ], - "data": [{"name":"trex.score","storageFile":true}] - }, - { - "id": "cubescramble", - "name": "Cube Scramble", - "version":"0.04", - "description": "A random scramble generator for the 3x3 Rubik's cube with a basic timer", - "icon": "cube-scramble.png", - "tags": "", - "supports" : ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle2-cube-scramble-screenshot.png"},{"url":"bangle1-cube-scramble-screenshot.png"}], - "storage": [ - {"name":"cubescramble.app.js","url":"cube-scramble.js"}, - {"name":"cubescramble.img","url":"cube-scramble-icon.js","evaluate":true} - ] - }, - { - "id": "astroid", - "name": "Asteroids!", - "version": "0.03", - "description": "Retro asteroids game", - "icon": "asteroids.png", - "screenshots": [{"url":"screenshot_asteroids.png"}], - "tags": "game", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"astroid.app.js","url":"asteroids.js"}, - {"name":"astroid.img","url":"asteroids-icon.js","evaluate":true} - ] - }, - { - "id": "clickms", - "name": "Click Master", - "version": "0.01", - "description": "Get several friends to start the game, then compete to see who can press BTN1 the most!", - "icon": "click-master.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"clickms.app.js","url":"click-master.js"}, - {"name":"clickms.img","url":"click-master-icon.js","evaluate":true} - ] - }, - { - "id": "horsey", - "name": "Horse Race!", - "version": "0.01", - "description": "Get several friends to start the game, then compete to see who can press BTN1 the most!", - "icon": "horse-race.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"horsey.app.js","url":"horse-race.js"}, - {"name":"horsey.img","url":"horse-race-icon.js","evaluate":true} - ] - }, - { - "id": "compass", - "name": "Compass", - "version": "0.05", - "description": "Simple compass that points North", - "icon": "compass.png", - "screenshots": [{"url":"screenshot_compass.png"}], - "tags": "tool,outdoors", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"compass.app.js","url":"compass.js"}, - {"name":"compass.img","url":"compass-icon.js","evaluate":true} - ] - }, - { - "id": "gpstime", - "name": "GPS Time", - "version": "0.05", - "description": "Update the Bangle.js's clock based on the time from the GPS receiver", - "icon": "gpstime.png", - "tags": "tool,gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"gpstime.app.js","url":"gpstime.js"}, - {"name":"gpstime.img","url":"gpstime-icon.js","evaluate":true} - ] - }, - { - "id": "openloc", - "name": "Open Location / Plus Codes", - "shortName": "Open Location", - "version": "0.01", - "description": "Convert your current GPS location to a series of characters", - "icon": "app.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"openloc.app.js","url":"app.js"}, - {"name":"openloc.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "speedo", - "name": "Speedo", - "version": "0.05", - "description": "Show the current speed according to the GPS", - "icon": "speedo.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"speedo.app.js","url":"speedo.js"}, - {"name":"speedo.img","url":"speedo-icon.js","evaluate":true} - ] - }, - { - "id": "gpsrec", - "name": "GPS Recorder", - "version": "0.27", - "description": "Application that allows you to record a GPS track. Can run in background", - "icon": "app.png", - "tags": "tool,outdoors,gps,widget", - "screenshots": [{"url":"screenshot.png"}], - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"gpsrec.app.js","url":"app.js"}, - {"name":"gpsrec.img","url":"app-icon.js","evaluate":true}, - {"name":"gpsrec.wid.js","url":"widget.js"}, - {"name":"gpsrec.settings.js","url":"settings.js"} - ], - "data": [{"name":"gpsrec.json"},{"wildcard":".gpsrc?","storageFile":true}] - }, - { - "id": "recorder", - "name": "Recorder (BETA)", - "shortName": "Recorder", - "version": "0.04", - "description": "Record GPS position, heart rate and more in the background, then download to your PC.", - "icon": "app.png", - "tags": "tool,outdoors,gps,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"recorder.app.js","url":"app.js"}, - {"name":"recorder.img","url":"app-icon.js","evaluate":true}, - {"name":"recorder.wid.js","url":"widget.js"}, - {"name":"recorder.settings.js","url":"settings.js"} - ], - "data": [{"name":"recorder.json"},{"wildcard":"recorder.log?.csv","storageFile":true}] - }, - { - "id": "gpsnav", - "name": "GPS Navigation", - "version": "0.05", - "description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording, now with waypoint editor", - "icon": "icon.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "waypoints.html", - "storage": [ - {"name":"gpsnav.app.js","url":"app.min.js"}, - {"name":"gpsnav.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"waypoints.json","url":"waypoints.json"}] - }, - { - "id": "heart", - "name": "Heart Rate Recorder", - "shortName": "HRM Record", - "version": "0.07", - "description": "Application that allows you to record your heart rate. Can run in background", - "icon": "app.png", - "tags": "tool,health,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "interface": "interface.html", - "storage": [ - {"name":"heart.app.js","url":"app.js"}, - {"name":"heart.img","url":"app-icon.js","evaluate":true}, - {"name":"heart.wid.js","url":"widget.js"} - ], - "data": [{"name":"heart.json"},{"wildcard":".heart?","storageFile":true}] - }, - { - "id": "slevel", - "name": "Spirit Level", - "version": "0.02", - "description": "Show the current angle of the watch, so you can use it to make sure something is absolutely flat", - "icon": "spiritlevel.png", - "tags": "tool", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"slevel.app.js","url":"spiritlevel.js"}, - {"name":"slevel.img","url":"spiritlevel-icon.js","evaluate":true} - ] - }, - { - "id": "files", - "name": "App Manager", - "version": "0.07", - "description": "Show currently installed apps, free space, and allow their deletion from the watch", - "icon": "files.png", - "tags": "tool,system,files", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"files.app.js","url":"files.js"}, - {"name":"files.img","url":"files-icon.js","evaluate":true} - ] - }, - { - "id": "weather", - "name": "Weather", - "version": "0.13", - "description": "Show Gadgetbridge weather report", - "icon": "icon.png", - "screenshots": [{"url":"screenshot.png"}], - "tags": "widget,outdoors", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "readme.md", - "storage": [ - {"name":"weather.app.js","url":"app.js"}, - {"name":"weather.wid.js","url":"widget.js"}, - {"name":"weather","url":"lib.js"}, - {"name":"weather.img","url":"icon.js","evaluate":true}, - {"name":"weather.settings.js","url":"settings.js"} - ], - "data": [{"name":"weather.json"}] - }, - { - "id": "chargeanim", - "name": "Charge Animation", - "version": "0.02", - "description": "When charging, show a sideways charging animation and keep the screen on. When removed from the charger load the clock again.", - "icon": "icon.png", - "tags": "battery", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-charge-animation-screenshot.png"},{"url":"bangle-charge-animation-screenshot.png"}], - "storage": [ - {"name":"chargeanim.app.js","url":"app.js"}, - {"name":"chargeanim.boot.js","url":"boot.js"}, - {"name":"chargeanim.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "bluetoothdock", - "name": "Bluetooth Dock", - "shortName": "Dock", - "version": "0.01", - "description": "When charging shows the time, scans Bluetooth for known devices (eg temperature) and shows them on the screen", - "icon": "app.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"bluetoothdock.app.js","url":"app.js"}, - {"name":"bluetoothdock.boot.js","url":"boot.js"}, - {"name":"bluetoothdock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widbat", - "name": "Battery Level Widget", - "version": "0.09", - "description": "Show the current battery level and charging status in the top right of the clock", - "icon": "widget.png", - "type": "widget", - "tags": "widget,battery", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbat.wid.js","url":"widget.js"} - ] - }, - { - "id": "widbatv", - "name": "Battery Level Widget (Vertical)", - "version": "0.01", - "description": "Slim, vertical battery widget that only takes up 14px", - "icon": "widget.png", - "type": "widget", - "tags": "widget,battery", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbatv.wid.js","url":"widget.js"} - ] - }, - { - "id": "widlock", - "name": "Lock Widget", - "version": "0.03", - "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", - "icon": "widget.png", - "type": "widget", - "tags": "widget,lock", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widlock.wid.js","url":"widget.js"} - ] - }, - { - "id": "widbatpc", - "name": "Battery Level Widget (with percentage)", - "shortName": "Battery Widget", - "version": "0.14", - "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", - "icon": "widget.png", - "type": "widget", - "tags": "widget,battery", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widbatpc.wid.js","url":"widget.js"}, - {"name":"widbatpc.settings.js","url":"settings.js"} - ], - "data": [{"name":"widbatpc.json"}] - }, - { - "id": "widbatwarn", - "name": "Battery Warning", - "shortName": "Battery Warning", - "version": "0.02", - "description": "Show a warning when the battery runs low.", - "icon": "widget.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "widget", - "tags": "tool,battery", - "supports": ["BANGLEJS"], - "dependencies": {"notify":"type"}, - "readme": "README.md", - "storage": [ - {"name":"widbatwarn.wid.js","url":"widget.js"}, - {"name":"widbatwarn.settings.js","url":"settings.js"} - ], - "data": [{"name":"widbatwarn.json"}] - }, - { - "id": "widbt", - "name": "Bluetooth Widget", - "version": "0.07", - "description": "Show the current Bluetooth connection status in the top right of the clock", - "icon": "widget.png", - "type": "widget", - "tags": "widget,bluetooth", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbt.wid.js","url":"widget.js"} - ] - }, - { - "id": "widchime", - "name": "Hour Chime", - "version": "0.02", - "description": "Buzz or beep on every whole hour.", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widchime.wid.js","url":"widget.js"}, - {"name":"widchime.settings.js","url":"settings.js"} - ], - "data": [{"name":"widchime.json"}] - }, - { - "id": "widram", - "name": "RAM Widget", - "shortName": "RAM Widget", - "version": "0.01", - "description": "Display your Bangle's available RAM percentage in a widget", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widram.wid.js","url":"widget.js"} - ] - }, - { - "id": "hrm", - "name": "Heart Rate Monitor", - "version": "0.06", - "description": "Measure your heart rate and see live sensor data", - "icon": "heartrate.png", - "tags": "health", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"hrm.app.js","url":"heartrate.js"}, - {"name":"hrm.img","url":"heartrate-icon.js","evaluate":true} - ] - }, - { - "id": "widhrm", - "name": "Simple Heart Rate widget", - "version": "0.05", - "description": "When the screen is on, the widget turns on the heart rate monitor and displays the current heart rate (or last known in grey). For this to work well you'll need at least a 15 second LCD Timeout.", - "icon": "widget.png", - "type": "widget", - "tags": "health,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widhrm.wid.js","url":"widget.js"} - ] - }, - { - "id": "bthrm", - "name": "Bluetooth Heart Rate Monitor", - "shortName": "BT HRM", - "version": "0.01", - "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", - "icon": "app.png", - "type": "boot", - "tags": "health,bluetooth", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"bthrm.boot.js","url":"boot.js"}, - {"name":"bthrm.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "stetho", - "name": "Stethoscope", - "version": "0.01", - "description": "Hear your heart rate", - "icon": "stetho.png", - "tags": "health", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"stetho.app.js","url":"stetho.js"}, - {"name":"stetho.img","url":"stetho-icon.js","evaluate":true} - ] - }, - { - "id": "swatch", - "name": "Stopwatch", - "version": "0.07", - "description": "Simple stopwatch with Lap Time logging to a JSON file", - "icon": "stopwatch.png", - "tags": "health", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-stopwatch-screenshot.png"}], - "storage": [ - {"name":"swatch.app.js","url":"stopwatch.js"}, - {"name":"swatch.img","url":"stopwatch-icon.js","evaluate":true} - ] - }, - { - "id": "hidmsic", - "name": "Bluetooth Music Controls", - "shortName": "Music Control", - "version": "0.02", - "description": "Enable HID in settings, pair with your phone, then use this app to control music from your watch!", - "icon": "hid-music.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidmsic.app.js","url":"hid-music.js"}, - {"name":"hidmsic.img","url":"hid-music-icon.js","evaluate":true} - ] - }, - { - "id": "hidkbd", - "name": "Bluetooth Keyboard", - "shortName": "Bluetooth Kbd", - "version": "0.02", - "description": "Enable HID in settings, pair with your phone/PC, then use this app to control other apps", - "icon": "hid-keyboard.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidkbd.app.js","url":"hid-keyboard.js"}, - {"name":"hidkbd.img","url":"hid-keyboard-icon.js","evaluate":true} - ] - }, - { - "id": "hidbkbd", - "name": "Binary Bluetooth Keyboard", - "shortName": "Binary BT Kbd", - "version": "0.02", - "description": "Enable HID in settings, pair with your phone/PC, then type messages using the onscreen keyboard by tapping repeatedly on the key you want", - "icon": "hid-binary-keyboard.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidbkbd.app.js","url":"hid-binary-keyboard.js"}, - {"name":"hidbkbd.img","url":"hid-binary-keyboard-icon.js","evaluate":true} - ] - }, - { - "id": "animals", - "name": "Animals Game", - "version": "0.01", - "description": "Simple toddler's game - displays a different number of animals each time the screen is pressed", - "icon": "animals.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"animals.app.js","url":"animals.js"}, - {"name":"animals.img","url":"animals-icon.js","evaluate":true}, - {"name":"animals-snake.img","url":"animals-snake.js","evaluate":true}, - {"name":"animals-duck.img","url":"animals-duck.js","evaluate":true}, - {"name":"animals-swan.img","url":"animals-swan.js","evaluate":true}, - {"name":"animals-fox.img","url":"animals-fox.js","evaluate":true}, - {"name":"animals-camel.img","url":"animals-camel.js","evaluate":true}, - {"name":"animals-pig.img","url":"animals-pig.js","evaluate":true}, - {"name":"animals-sheep.img","url":"animals-sheep.js","evaluate":true}, - {"name":"animals-mouse.img","url":"animals-mouse.js","evaluate":true} - ] - }, - { - "id": "qrcode", - "name": "Custom QR Code", - "version": "0.04", - "description": "Use this to upload a customised QR code to Bangle.js", - "icon": "app.png", - "tags": "qrcode", - "supports": ["BANGLEJS","BANGLEJS2"], - "custom": "custom.html", - "customConnect": true, - "storage": [ - {"name":"qrcode.app.js"}, - {"name":"qrcode.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "beer", - "name": "Beer Compass", - "version": "0.01", - "description": "Uploads all the pubs in an area onto your watch, so it can always point you at the nearest one", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [ - {"name":"beer.app.js"}, - {"name":"beer.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "route", - "name": "Route Viewer", - "version": "0.02", - "description": "Upload a KML file of a route, and have your watch display a map with how far around it you are", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [ - {"name":"route.app.js"}, - {"name":"route.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "ncstart", - "name": "NCEU Startup", - "version": "0.06", - "description": "NodeConfEU 2019 'First Start' Sequence", - "icon": "start.png", - "tags": "start,welcome", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"ncstart.app.js","url":"start.js"}, - {"name":"ncstart.boot.js","url":"boot.js"}, - {"name":"ncstart.settings.js","url":"settings.js"}, - {"name":"ncstart.img","url":"start-icon.js","evaluate":true}, - {"name":"nc-bangle.img","url":"start-bangle.js","evaluate":true}, - {"name":"nc-nceu.img","url":"start-nceu.js","evaluate":true}, - {"name":"nc-nfr.img","url":"start-nfr.js","evaluate":true}, - {"name":"nc-nodew.img","url":"start-nodew.js","evaluate":true}, - {"name":"nc-tf.img","url":"start-tf.js","evaluate":true} - ], - "data": [{"name":"ncstart.json"}] - }, - { - "id": "ncfrun", - "name": "NCEU 5K Fun Run", - "version": "0.01", - "description": "Display a map of the NodeConf EU 2019 5K Fun Run route and your location on it", - "icon": "nceu-funrun.png", - "tags": "health", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"ncfrun.app.js","url":"nceu-funrun.js"}, - {"name":"ncfrun.img","url":"nceu-funrun-icon.js","evaluate":true} - ] - }, - { - "id": "widnceu", - "name": "NCEU Logo Widget", - "version": "0.02", - "description": "Show the NodeConf EU logo in the top left", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"widnceu.wid.js","url":"widget.js"} - ] - }, - { - "id": "sclock", - "name": "Simple Clock", - "version": "0.07", - "description": "A Simple Digital Clock", - "icon": "clock-simple.png", - "screenshots": [{"url":"screenshot_simplec.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"sclock.app.js","url":"clock-simple.js"}, - {"name":"sclock.img","url":"clock-simple-icon.js","evaluate":true} - ] - }, - { - "id": "s7clk", - "name": "Simple 7 segment Clock", - "version": "0.03", - "description": "A simple 7 segment Clock with date", - "icon": "icon.png", - "screenshots": [{"url":"screenshot_s7segment.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"s7clk.app.js","url":"app.js"}, - {"name":"s7clk.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "vibrclock", - "name": "Vibrate Clock", - "version": "0.03", - "description": "When BTN1 is pressed, vibrate out the time as a series of buzzes, one digit at a time. Hours, then Minutes. Zero is signified by one long buzz. Otherwise a simple digital clock.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-vibrate-clock-screenshot.png"}], - "storage": [ - {"name":"vibrclock.app.js","url":"app.js"}, - {"name":"vibrclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "svclock", - "name": "Simple V-Clock", - "version": "0.04", - "description": "Modification of Simple Clock 0.04 to use Vectorfont", - "icon": "vclock-simple.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-simple-v-clock-screenshot.png"}], - "storage": [ - {"name":"svclock.app.js","url":"vclock-simple.js"}, - {"name":"svclock.img","url":"vclock-simple-icon.js","evaluate":true} - ] - }, - { - "id": "dclock", - "name": "Dev Clock", - "version": "0.10", - "description": "A Digital Clock including timestamp (tst), beats(@), days in current month (dm) and days since new moon (l)", - "icon": "clock-dev.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-dev-clock-screenshot.png"},{"url":"bangle1-dev-clock-screenshot.png"}], - "storage": [ - {"name":"dclock.app.js","url":"clock-dev.js"}, - {"name":"dclock.img","url":"clock-dev-icon.js","evaluate":true} - ] - }, - { - "id": "gesture", - "name": "Gesture Test", - "version": "0.01", - "description": "BETA! Uploads a basic Tensorflow Gesture model, and then outputs each gesture as a message", - "icon": "gesture.png", - "type": "app", - "tags": "gesture,ai", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"gesture.app.js","url":"gesture.js"}, - {"name":".tfnames","url":"gesture-tfnames.js","evaluate":true}, - {"name":".tfmodel","url":"gesture-tfmodel.js","evaluate":true}, - {"name":"gesture.img","url":"gesture-icon.js","evaluate":true} - ] - }, - { - "id": "pparrot", - "name": "Party Parrot", - "version": "0.01", - "description": "Party with a parrot on your wrist", - "icon": "party-parrot.png", - "type": "app", - "tags": "party,parrot,lol", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-party-parrot-screenshot.png"}], - "storage": [ - {"name":"pparrot.app.js","url":"party-parrot.js"}, - {"name":"pparrot.img","url":"party-parrot-icon.js","evaluate":true} - ] - }, - { - "id": "hrings", - "name": "Hypno Rings", - "version": "0.01", - "description": "Experiment with trippy rings, press buttons for change", - "icon": "hypno-rings.png", - "type": "app", - "tags": "rings,hypnosis,psychadelic", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-hypno-rings-screenshot.png"}], - "storage": [ - {"name":"hrings.app.js","url":"hypno-rings.js"}, - {"name":"hrings.img","url":"hypno-rings-icon.js","evaluate":true} - ] - }, - { - "id": "morse", - "name": "Morse Code", - "version": "0.01", - "description": "Learn morse code by hearing/seeing/feeling the code. Tap to toggle buzz!", - "icon": "morse-code.png", - "type": "app", - "tags": "morse,sound,visual,input", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"morse.app.js","url":"morse-code.js"}, - {"name":"morse.img","url":"morse-code-icon.js","evaluate":true} - ] - }, - { - "id": "blescan", - "name": "BLE Scanner", - "version": "0.01", - "description": "Scan for advertising BLE devices", - "icon": "blescan.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"blescan.app.js","url":"blescan.js"}, - {"name":"blescan.img","url":"blescan-icon.js","evaluate":true} - ] - }, - { - "id": "mmonday", - "name": "Manic Monday Tone", - "version": "0.02", - "description": "The Bangles make a comeback", - "icon": "manic-monday-icon.png", - "tags": "sound", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"mmonday.app.js","url":"manic-monday.js"}, - {"name":"mmonday.img","url":"manic-monday-icon.js","evaluate":true} - ] - }, - { - "id": "jbells", - "name": "Jingle Bells", - "version": "0.01", - "description": "Play Jingle Bells", - "icon": "jbells.png", - "type": "app", - "tags": "sound", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"jbells.app.js","url":"jbells.js"}, - {"name":"jbells.img","url":"jbells-icon.js","evaluate":true} - ] - }, - { - "id": "scolor", - "name": "Show Color", - "version": "0.01", - "description": "Display all available Colors and Names", - "icon": "show-color.png", - "type": "app", - "tags": "tool", - "screenshots": [{"url":"bangle1-view-color-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"scolor.app.js","url":"show-color.js"}, - {"name":"scolor.img","url":"show-color-icon.js","evaluate":true} - ] - }, - { - "id": "miclock", - "name": "Mixed Clock", - "version": "0.05", - "description": "A mix of analog and digital Clock", - "icon": "clock-mixed.png", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"bangle1-mixed-clock-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"miclock.app.js","url":"clock-mixed.js"}, - {"name":"miclock.img","url":"clock-mixed-icon.js","evaluate":true} - ] - }, - { - "id": "bclock", - "name": "Binary Clock", - "version": "0.03", - "description": "A simple binary clock watch face", - "icon": "clock-binary.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-binary-clock-screenshot.png"}], - "storage": [ - {"name":"bclock.app.js","url":"clock-binary.js"}, - {"name":"bclock.img","url":"clock-binary-icon.js","evaluate":true} - ] - }, - { - "id": "clotris", - "name": "Clock-Tris", - "version": "0.01", - "description": "A fully functional clone of a classic game of falling blocks", - "icon": "clock-tris.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-clock-tris-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"clotris.app.js","url":"clock-tris.js"}, - {"name":"clotris.img","url":"clock-tris-icon.js","evaluate":true}, - {"name":".trishig","url":"clock-tris-high"} - ] - }, - { - "id": "flappy", - "name": "Flappy Bird", - "version": "0.05", - "description": "A Flappy Bird game clone", - "icon": "app.png", - "screenshots": [{"url":"screenshot1_flappy.png"},{"url":"screenshot2_flappy.png"}], - "tags": "game", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"flappy.app.js","url":"app.js"}, - {"name":"flappy.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gpsinfo", - "name": "GPS Info", - "version": "0.05", - "description": "An application that displays information about altitude, lat/lon, satellites and time", - "icon": "gps-info.png", - "type": "app", - "tags": "gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"gpsinfo.app.js","url":"gps-info.js"}, - {"name":"gpsinfo.img","url":"gps-info-icon.js","evaluate":true} - ] - }, - { - "id": "assistedgps", - "name": "Assisted GPS Update (AGPS)", - "version": "0.01", - "description": "Downloads assisted GPS (AGPS) data to Bangle.js 1 for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", - "icon": "app.png", - "type": "RAM", - "tags": "tool,outdoors,agps", - "supports": ["BANGLEJS"], - "custom": "custom.html", - "storage": [] - }, - { - "id": "pomodo", - "name": "Pomodoro", - "version": "0.02", - "description": "A simple pomodoro timer.", - "icon": "pomodoro.png", - "type": "app", - "tags": "pomodoro,cooking,tools", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-pomodoro-screenshot.png"}], - "storage": [ - {"name":"pomodo.app.js","url":"pomodoro.js"}, - {"name":"pomodo.img","url":"pomodoro-icon.js","evaluate":true} - ] - }, - { - "id": "blobclk", - "name": "Large Digit Blob Clock", - "shortName": "Blob Clock", - "version": "0.06", - "description": "A clock with big digits", - "icon": "clock-blob.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-large-digit-blob-clock-screenshot.png"},{"url":"bangle1-large-digit-blob-clock-screenshot.png"}], - "storage": [ - {"name":"blobclk.app.js","url":"clock-blob.js"}, - {"name":"blobclk.img","url":"clock-blob-icon.js","evaluate":true} - ] - }, - { - "id": "boldclk", - "name": "Bold Clock", - "version": "0.05", - "description": "Simple, readable and practical clock", - "icon": "bold_clock.png", - "screenshots": [{"url":"screenshot_bold.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"boldclk.app.js","url":"bold_clock.js"}, - {"name":"boldclk.img","url":"bold_clock-icon.js","evaluate":true} - ] - }, - { - "id": "widclk", - "name": "Digital clock widget", - "version": "0.06", - "description": "A simple digital clock widget", - "icon": "widget.png", - "type": "widget", - "tags": "widget,clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widclk.wid.js","url":"widget.js"} - ] - }, - { - "id": "widpedom", - "name": "Pedometer widget", - "version": "0.20", - "description": "Daily pedometer widget", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widpedom.wid.js","url":"widget.js"}, - {"name":"widpedom.settings.js","url":"settings.js"} - ] - }, - { - "id": "berlinc", - "name": "Berlin Clock", - "version": "0.05", - "description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)", - "icon": "berlin-clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"berlin-clock-screenshot.png"}], - "storage": [ - {"name":"berlinc.app.js","url":"berlin-clock.js"}, - {"name":"berlinc.img","url":"berlin-clock-icon.js","evaluate":true} - ] - }, - { - "id": "ctrclk", - "name": "Centerclock", - "version": "0.03", - "description": "Watch-centered digital 24h clock with date in dd.mm.yyyy format.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-center-clock-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"ctrclk.app.js","url":"app.js"}, - {"name":"ctrclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "demoapp", - "name": "Demo Loop", - "version": "0.02", - "description": "Simple demo app - displays Bangle.js, JS logo, graphics, and Bangle.js information", - "icon": "app.png", - "type": "app", - "tags": "", - "screenshots": [{"url":"bangle1-demo-loop-screenshot1.png"},{"url":"bangle1-demo-loop-screenshot2.png"},{"url":"bangle1-demo-loop-screenshot3.png"},{"url":"bangle1-demo-loop-screenshot4.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"demoapp.app.js","url":"app.js"}, - {"name":"demoapp.img","url":"app-icon.js","evaluate":true} - ], - "sortorder": -9 - }, - { - "id": "flagrse", - "name": "Espruino Flag Raiser", - "version": "0.01", - "description": "App to send a command to another Espruino to cause it to raise a flag", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"flagrse.app.js","url":"app.js"}, - {"name":"flagrse.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pipboy", - "name": "Pipboy", - "version": "0.04", - "description": "Pipboy themed clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-pipboy-themed-clock-screenshot.png"}], - "storage": [ - {"name":"pipboy.app.js","url":"app.js"}, - {"name":"pipboy.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "torch", - "name": "Torch", - "shortName": "Torch", - "version": "0.02", - "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets", - "icon": "app.png", - "tags": "tool,torch", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"torch.app.js","url":"app.js"}, - {"name":"torch.wid.js","url":"widget.js"}, - {"name":"torch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "rtorch", - "name": "Red Torch", - "shortName": "RedTorch", - "version": "0.02", - "description": "Turns screen RED to help you see in the dark without breaking your night vision. Select from the launcher or on Bangle 1 press BTN3,BTN1,BTN3,BTN1 quickly to start when in any app that shows widgets", - "icon": "app.png", - "tags": "tool,torch", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"rtorch.app.js","url":"app.js"}, - {"name":"rtorch.wid.js","url":"widget.js", "supports": ["BANGLEJS"]}, - {"name":"rtorch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "wohrm", - "name": "Workout HRM", - "version": "0.08", - "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", - "icon": "app.png", - "type": "app", - "tags": "hrm,workout", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-workout-HRM-screenshot.png"}], - "storage": [ - {"name":"wohrm.app.js","url":"app.js"}, - {"name":"wohrm.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widid", - "name": "Bluetooth ID Widget", - "version": "0.03", - "description": "Display the last two tuple of your Bangle.js MAC address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!", - "icon": "widget.png", - "type": "widget", - "tags": "widget,address,mac", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widid.wid.js","url":"widget.js"} - ] - }, - { - "id": "grocery", - "name": "Grocery", - "version": "0.02", - "description": "Simple grocery (shopping) list - Display a list of product and track if you already put them in your cart.", - "icon": "grocery.png", - "type": "app", - "tags": "tool,outdoors,shopping,list", - "supports": ["BANGLEJS"], - "custom": "grocery.html", - "storage": [ - {"name":"grocery.app.js","url":"app.js"}, - {"name":"grocery.img","url":"grocery-icon.js","evaluate":true} - ] - }, - { - "id": "marioclock", - "name": "Mario Clock", - "version": "0.15", - "description": "Animated retro Mario clock, with Gameboy style 8-bit grey-scale graphics.", - "icon": "marioclock.png", - "type": "clock", - "tags": "clock,mario,retro", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": false, - "screenshots": [{"url":"bangle1-mario-clock-screenshot.png"}], - "storage": [ - {"name":"marioclock.app.js","url":"marioclock-app.js"}, - {"name":"marioclock.img","url":"marioclock-icon.js","evaluate":true} - ] - }, - { - "id": "cliock", - "name": "Commandline-Clock", - "shortName": "CLI-Clock", - "version": "0.15", - "description": "Simple CLI-Styled Clock", - "icon": "app.png", - "screenshots": [{"url":"screenshot_cli.png"}], - "type": "clock", - "tags": "clock,cli,command,bash,shell", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"cliock.app.js","url":"app.js"}, - {"name":"cliock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widver", - "name": "Firmware Version Widget", - "version": "0.03", - "description": "Display the version of the installed firmware in the top widget section.", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widver.wid.js","url":"widget.js"} - ] - }, - { - "id": "barclock", - "name": "Bar Clock", - "version": "0.09", - "description": "A simple digital clock showing seconds as a bar", - "icon": "clock-bar.png", - "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"barclock.app.js","url":"clock-bar.js"}, - {"name":"barclock.img","url":"clock-bar-icon.js","evaluate":true} - ] - }, - { - "id": "dotclock", - "name": "Dot Clock", - "version": "0.03", - "description": "A Minimal Dot Analog Clock", - "icon": "clock-dot.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle2-dot-clcok-screenshot.png"},{"url":"bangle1-dot-clock-screenshot.png"}], - "storage": [ - {"name":"dotclock.app.js","url":"clock-dot.js"}, - {"name":"dotclock.img","url":"clock-dot-icon.js","evaluate":true} - ] - }, - { - "id": "widtbat", - "name": "Tiny Battery Widget", - "version": "0.02", - "description": "Tiny blueish battery widget, vibs and changes level color when charging", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widtbat.wid.js","url":"widget.js"} - ] - }, - { - "id": "chrono", - "name": "Chrono", - "shortName": "Chrono", - "version": "0.01", - "description": "Single click BTN1 to add 5 minutes. Single click BTN2 to add 30 seconds. Single click BTN3 to add 5 seconds. Tap to pause or play to timer. Double click BTN1 to reset. When timer finishes the watch vibrates.", - "icon": "chrono.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"chrono.app.js","url":"chrono.js"}, - {"name":"chrono.img","url":"chrono-icon.js","evaluate":true} - ] - }, - { - "id": "astrocalc", - "name": "Astrocalc", - "version": "0.02", - "description": "Calculates interesting information on the sun and moon cycles for the current day based on your location.", - "icon": "astrocalc.png", - "tags": "app,sun,moon,cycles,tool,outdoors", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"astrocalc.app.js","url":"astrocalc-app.js"}, - {"name":"suncalc.js","url":"suncalc.js"}, - {"name":"astrocalc.img","url":"astrocalc-icon.js","evaluate":true}, - {"name":"first-quarter.img","url":"first-quarter-icon.js","evaluate":true}, - {"name":"last-quarter.img","url":"last-quarter-icon.js","evaluate":true}, - {"name":"waning-crescent.img","url":"waning-crescent-icon.js","evaluate":true}, - {"name":"waning-gibbous.img","url":"waning-gibbous-icon.js","evaluate":true}, - {"name":"full.img","url":"full-icon.js","evaluate":true}, - {"name":"new.img","url":"new-icon.js","evaluate":true}, - {"name":"waxing-gibbous.img","url":"waxing-gibbous-icon.js","evaluate":true}, - {"name":"waxing-crescent.img","url":"waxing-crescent-icon.js","evaluate":true} - ] - }, - { - "id": "widhwt", - "name": "Hand Wash Timer", - "version": "0.01", - "description": "Swipe your wrist over the watch face to start your personal Bangle.js hand wash timer for 35 sec. Start washing after the short buzz and stop after the long buzz.", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"widhwt.wid.js","url":"widget.js"} - ] - }, - { - "id": "toucher", - "name": "Touch Launcher", - "shortName": "Toucher", - "version": "0.07", - "description": "Touch enable left to right launcher.", - "icon": "app.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"toucher.app.js","url":"app.js"}, - {"name":"toucher.settings.js","url":"settings.js"} - ], - "data": [{"name":"toucher.json"}] - }, - { - "id": "balltastic", - "name": "Balltastic", - "version": "0.02", - "description": "Simple but fun ball eats dots game.", - "icon": "app.png", - "type": "app", - "tags": "game,fun", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"balltastic.app.js","url":"app.js"}, - {"name":"balltastic.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "rpgdice", - "name": "RPG dice", - "version": "0.02", - "description": "Simple RPG dice rolling app.", - "icon": "rpgdice.png", - "type": "app", - "tags": "game,fun", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-rpg-dice-screenshot.png"}], - "storage": [ - {"name":"rpgdice.app.js","url":"app.js"}, - {"name":"rpgdice.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widmp", - "name": "Moon Phase Widget", - "version": "0.02", - "description": "Display the current moon phase in blueish for the northern hemisphere in eight phases", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tools", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widmp.wid.js","url":"widget.js"} - ] - }, - { - "id": "widmpsh", - "name": "Moon Phase Widget Southern Hemisphere", - "version": "0.01", - "description": "Display the current moon phase in blueish for the southern hemisphere in eight phases", - "icon": "widget.png", - "type": "widget", - "tags": "widget,tools", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widmpsh.wid.js","url":"widget.js"} - ] - }, - { - "id": "minionclk", - "name": "Minion clock", - "version": "0.05", - "description": "Minion themed clock.", - "icon": "minionclk.png", - "type": "clock", - "tags": "clock,minion", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-minion-clock-screenshot.png"}], - "storage": [ - {"name":"minionclk.app.js","url":"app.js"}, - {"name":"minionclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "openstmap", - "name": "OpenStreetMap", - "shortName": "OpenStMap", - "version": "0.11", - "description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps", - "icon": "app.png", - "tags": "outdoors,gps,osm", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], - "custom": "custom.html", - "customConnect": true, - "storage": [ - {"name":"openstmap","url":"openstmap.js"}, - {"name":"openstmap.app.js","url":"app.js"}, - {"name":"openstmap.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "activepedom", - "name": "Active Pedometer", - "shortName": "Active Pedometer", - "version": "0.09", - "description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.", - "icon": "app.png", - "tags": "outdoors,widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"activepedom.wid.js","url":"widget.js"}, - {"name":"activepedom.settings.js","url":"settings.js"}, - {"name":"activepedom.img","url":"app-icon.js","evaluate":true}, - {"name":"activepedom.app.js","url":"app.js"} - ] - }, - { - "id": "chronowid", - "name": "Chrono Widget", - "shortName": "Chrono Widget", - "version": "0.04", - "description": "Chronometer (timer) which runs as widget.", - "icon": "app.png", - "tags": "tool,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], - "readme": "README.md", - "storage": [ - {"name":"chronowid.wid.js","url":"widget.js"}, - {"name":"chronowid.app.js","url":"app.js"}, - {"name":"chronowid.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "tabata", - "name": "Tabata", - "shortName": "Tabata - Control High-Intensity Interval Training", - "version": "0.01", - "description": "Control high-intensity interval training (according to tabata: https://en.wikipedia.org/wiki/Tabata_method).", - "icon": "tabata.png", - "tags": "workout,health", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"tabata.app.js","url":"tabata.js"}, - {"name":"tabata.img","url":"tabata-icon.js","evaluate":true} - ] - }, - { - "id": "custom", - "name": "Custom Boot Code ", - "version": "0.01", - "description": "Add code you want to run at boot time", - "icon": "custom.png", - "type": "bootloader", - "tags": "tool,system", - "supports": ["BANGLEJS","BANGLEJS2"], - "custom": "custom.html", - "storage": [ - {"name":"custom"} - ] - }, - { - "id": "devstopwatch", - "name": "Dev Stopwatch", - "shortName": "Dev Stopwatch", - "version": "0.03", - "description": "Stopwatch with 5 laps supported (cyclically replaced)", - "icon": "app.png", - "tags": "stopwatch,chrono,timer,chronometer", - "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"bangle1-dev-stopwatch-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"devstopwatch.app.js","url":"app.js"}, - {"name":"devstopwatch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "batchart", - "name": "Battery Chart", - "shortName": "Battery Chart", - "version": "0.10", - "description": "A widget and an app for recording and visualizing battery percentage over time.", - "icon": "app.png", - "tags": "app,widget,battery,time,record,chart,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"batchart.wid.js","url":"widget.js"}, - {"name":"batchart.app.js","url":"app.js"}, - {"name":"batchart.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "nato", - "name": "NATO Alphabet", - "shortName": "NATOAlphabet", - "version": "0.01", - "description": "Learn the NATO Phonetic alphabet plus some numbers.", - "icon": "nato.png", - "type": "app", - "tags": "app,learn,visual", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-NATO-alphabet-screenshot.png"},{"url":"bangle1-NATO-alphabet-screenshot2.png"}], - "storage": [ - {"name":"nato.app.js","url":"nato.js"}, - {"name":"nato.img","url":"nato-icon.js","evaluate":true} - ] - }, - { - "id": "numerals", - "name": "Numerals Clock", - "shortName": "Numerals Clock", - "version": "0.10", - "description": "A simple big numerals clock", - "icon": "numerals.png", - "type": "clock", - "tags": "numerals,clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-numerals-screenshot.png"}], - "storage": [ - {"name":"numerals.app.js","url":"numerals.app.js"}, - {"name":"numerals.img","url":"numerals-icon.js","evaluate":true}, - {"name":"numerals.settings.js","url":"numerals.settings.js"} - ], - "data": [{"name":"numerals.json"}] - }, - { - "id": "bledetect", - "name": "BLE Detector", - "shortName": "BLE Detector", - "version": "0.03", - "description": "Detect BLE devices and show some informations.", - "icon": "bledetect.png", - "tags": "app,bluetooth,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"bledetect.app.js","url":"bledetect.js"}, - {"name":"bledetect.img","url":"bledetect-icon.js","evaluate":true} - ] - }, - { - "id": "snake", - "name": "Snake", - "shortName": "Snake", - "version": "0.02", - "description": "The classic snake game. Eat apples and don't bite your tail.", - "icon": "snake.png", - "tags": "game,fun", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"snake.app.js","url":"snake.js"}, - {"name":"snake.img","url":"snake-icon.js","evaluate":true} - ] - }, - { "id": "snek", - "name": "The snek game", - "shortName":"Snek", - "version": "0.02", - "description": "A snek game where you control a snek to eat all the apples!", - "screenshots": [{"url":"screenshot_snek.png"}], - "icon": "snek.png", - "supports": ["BANGLEJS2"], - "tags": "game,fun", - "storage": [ - {"name":"snek.app.js","url":"snek.js"}, - {"name":"snek.img","url":"snek.icon.js","evaluate":true} - ] - }, - { - "id": "calculator", - "name": "Calculator", - "shortName": "Calculator", - "version": "0.04", - "description": "Basic calculator reminiscent of MacOs's one. Handy for small calculus.", - "icon": "calculator.png", - "screenshots": [{"url":"screenshot_calculator.png"}], - "tags": "app,tool", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"calculator.app.js","url":"app.js"}, - {"name":"calculator.img","url":"calculator-icon.js","evaluate":true} - ] - }, - { - "id": "dane", - "name": "Digital Assistant, not EDITH", - "shortName": "DANE", - "version": "0.16", - "description": "A Watchface inspired by Tony Stark's EDITH and based on https://arwes.dev/", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"dane.app.js","url":"app.js"}, - {"name":"dane.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "dane_tcr", - "name": "DANE Touch Launcher", - "shortName": "DANE Toucher", - "version": "0.07", - "description": "Touch enable left to right launcher in the style of the DANE Watchface", - "icon": "app.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"dane_tcr.app.js","url":"app.js"}, - {"name":"dane_tcr.settings.js","url":"settings.js"} - ], - "data": [{"name":"dane_tcr.json"}] - }, - { - "id": "buffgym", - "name": "BuffGym", - "version": "0.02", - "description": "BuffGym is the famous 5x5 workout program for the BangleJS", - "icon": "buffgym.png", - "type": "app", - "tags": "tool,outdoors,gym,exercise", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "buffgym.html", - "allow_emulator": false, - "storage": [ - {"name":"buffgym.app.js","url":"buffgym.app.js"}, - {"name":"buffgym-set.js","url":"buffgym-set.js"}, - {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, - {"name":"buffgym-workout.js","url":"buffgym-workout.js"}, - {"name":"buffgym-workout-a.json","url":"buffgym-workout-a.json"}, - {"name":"buffgym-workout-b.json","url":"buffgym-workout-b.json"}, - {"name":"buffgym-workout-index.json","url":"buffgym-workout-index.json"}, - {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} - ] - }, - { - "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} - ] - }, - { - "id": "metronome", - "name": "Metronome", - "version": "0.07", - "readme": "README.md", - "description": "Makes the watch blinking and vibrating with a given rate", - "icon": "metronome_icon.png", - "tags": "tool", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-metronome-screenshot.png"}], - "storage": [ - {"name":"metronome.app.js","url":"metronome.js"}, - {"name":"metronome.img","url":"metronome-icon.js","evaluate":true}, - {"name":"metronome.settings.js","url":"settings.js"} - ] - }, - { - "id": "blackjack", - "name": "Black Jack game", - "shortName": "Black Jack game", - "version": "0.02", - "description": "Simple implementation of card game Black Jack", - "icon": "blackjack.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-black-jack-game-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"blackjack.app.js","url":"blackjack.app.js"}, - {"name":"blackjack.img","url":"blackjack-icon.js","evaluate":true} - ] - }, - { - "id": "hidcam", - "name": "Camera shutter", - "shortName": "Cam shutter", - "version": "0.03", - "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle", - "icon": "app.png", - "tags": "bluetooth,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"hidcam.app.js","url":"app.js"}, - {"name":"hidcam.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "swlclk", - "name": "SWL Clock / Short Wave Listner Clock", - "shortName": "SWL Clock", - "version": "0.02", - "description": "Display Local, UTC time and some programs on the shorts waves along the day, with the frequencies", - "icon": "swlclk.png", - "type": "clock", - "tags": "tool,clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-SWL-clock-screenshot.png"}], - "storage": [ - {"name":"swlclk.app.js","url":"app.js"}, - {"name":"swlclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "rclock", - "name": "Round clock with seconds, minutes and date", - "shortName": "Round Clock", - "version": "0.06", - "description": "Designed round clock with ticks for minutes and seconds and heart rate indication", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"rclock.app.js","url":"rclock.app.js"}, - {"name":"rclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "fclock", - "name": "fclock", - "shortName": "F Clock", - "version": "0.02", - "description": "Simple design of a digital clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"fclock.app.js","url":"fclock.app.js"}, - {"name":"fclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hamloc", - "name": "QTH Locator / Maidenhead Locator System", - "shortName": "QTH Locator", - "version": "0.01", - "description": "Convert your current GPS location to the Maidenhead locator system used by HAM amateur radio operators", - "icon": "app.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"hamloc.app.js","url":"app.js"}, - {"name":"hamloc.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "osmpoi", - "name": "POI Compass", - "version": "0.03", - "description": "Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.", - "icon": "app.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "storage": [ - {"name":"osmpoi.app.js"}, - {"name":"osmpoi.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pong", - "name": "Pong", - "shortName": "Pong", - "version": "0.03", - "description": "A clone of the Atari game Pong", - "icon": "pong.png", - "type": "app", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-pong-screenshot.png"}], - "storage": [ - {"name":"pong.app.js","url":"app.js"}, - {"name":"pong.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "ballmaze", - "name": "Ball Maze", - "version": "0.02", - "description": "Navigate a ball through a maze by tilting your watch.", - "icon": "icon.png", - "type": "app", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"ballmaze.app.js","url":"app.js"}, - {"name":"ballmaze.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"ballmaze.json"}] - }, - { - "id": "calendar", - "name": "Calendar", - "version": "0.04", - "description": "Simple calendar", - "icon": "calendar.png", - "screenshots": [{"url":"screenshot_calendar.png"}], - "tags": "calendar", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"calendar.app.js","url":"calendar.js"}, - {"name":"calendar.settings.js","url":"settings.js"}, - {"name":"calendar.img","url":"calendar-icon.js","evaluate":true} - ], - "data": [{"name":"calendar.json"}] - }, - { - "id": "hidjoystick", - "name": "Bluetooth Joystick", - "shortName": "Joystick", - "version": "0.01", - "description": "Emulates a 2 axis/5 button Joystick using the accelerometer as stick input and buttons 1-3, touch left as button 4 and touch right as button 5.", - "icon": "app.png", - "tags": "bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hidjoystick.app.js","url":"app.js"}, - {"name":"hidjoystick.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "largeclock", - "name": "Large Clock", - "version": "0.10", - "description": "A readable and informational digital watch, with date, seconds and moon phase", - "icon": "largeclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-large-clock-screenshot.png"}], - "storage": [ - {"name":"largeclock.app.js","url":"largeclock.js"}, - {"name":"largeclock.img","url":"largeclock-icon.js","evaluate":true}, - {"name":"largeclock.settings.js","url":"settings.js"} - ], - "data": [{"name":"largeclock.json"}] - }, - { - "id": "smtswch", - "name": "Smart Switch", - "shortName": "Smart Switch", - "version": "0.01", - "description": "Using EspruinoHub, control your smart devices on and off via Bluetooth Low Energy!", - "icon": "app.png", - "type": "app", - "tags": "bluetooth,btle,smart,switch", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"smtswch.app.js","url":"app.js"}, - {"name":"smtswch.img","url":"app-icon.js","evaluate":true}, - {"name":"light-on.img","url":"light-on.js","evaluate":true}, - {"name":"light-off.img","url":"light-off.js","evaluate":true}, - {"name":"switch-on.img","url":"switch-on.js","evaluate":true}, - {"name":"switch-off.img","url":"switch-off.js","evaluate":true} - ] - }, - { - "id": "miplant", - "name": "Xiaomi Plant Sensor", - "shortName": "Mi Plant", - "version": "0.02", - "description": "Reads and displays data from Xiaomi bluetooth plant moisture sensors", - "icon": "app.png", - "tags": "xiaomi,mi,plant,ble,bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"miplant.app.js","url":"app.js"}, - {"name":"miplant.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "simpletimer", - "name": "Timer", - "version": "0.07", - "description": "Simple timer, useful when playing board games or cooking", - "icon": "app.png", - "tags": "timer", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-timer-screenshot.png"}], - "storage": [ - {"name":"simpletimer.app.js","url":"app.js"}, - {"name":".tfnames","url":"gesture-tfnames.js","evaluate":true}, - {"name":".tfmodel","url":"gesture-tfmodel.js","evaluate":true}, - {"name":"simpletimer.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"simpletimer.json"}] - }, - { - "id": "beebclock", - "name": "Beeb Clock", - "version": "0.05", - "description": "Clock face that may be coincidentally familiar to BBC viewers", - "icon": "beebclock.png", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"bangle1-beeb-clock-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"beebclock.app.js","url":"beebclock.js"}, - {"name":"beebclock.img","url":"beebclock-icon.js","evaluate":true} - ] - }, - { - "id": "findphone", - "name": "Find Phone", - "shortName": "Find Phone", - "version": "0.03", - "description": "Find your phone via Gadgetbridge. Click any button to let your phone ring. 📳 Note: The functionality is available even without this app, just go to Settings, App Settings, Gadgetbridge, Find Phone.", - "icon": "app.png", - "tags": "tool,android", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"findphone.app.js","url":"app.js"}, - {"name":"findphone.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "getup", - "name": "Get Up", - "shortName": "Get Up", - "version": "0.01", - "description": "Reminds you to getup every x minutes. Sitting to long is dangerous!", - "icon": "app.png", - "tags": "tools,health", - "supports": ["BANGLEJS"], - "readme": "README.md", - "screenshots": [{"url":"bangle1-get-up-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"getup.app.js","url":"app.js"}, - {"name":"getup.settings.js","url":"settings.js"}, - {"name":"getup.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gallifr", - "name": "Time Traveller's Chronometer", - "shortName": "Time Travel Clock", - "version": "0.02", - "description": "A clock for time travellers. The light pie segment shows the minutes, the black circle, the hour. The dial itself reads 'time' just in case you forget.", - "icon": "gallifr.png", - "screenshots": [{"url":"screenshot_time.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"gallifr.app.js","url":"app.js"}, - {"name":"gallifr.img","url":"app-icon.js","evaluate":true}, - {"name":"gallifr.settings.js","url":"settings.js"} - ], - "data": [{"name":"gallifr.json"}] - }, - { - "id": "rndmclk", - "name": "Random Clock Loader", - "version": "0.03", - "description": "Load a different clock whenever the LCD is switched on.", - "icon": "rndmclk.png", - "type": "widget", - "tags": "widget,clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"rndmclk.wid.js","url":"widget.js"} - ] - }, - { - "id": "dotmatrixclock", - "name": "Dotmatrix Clock", - "version": "0.01", - "description": "A clear white-on-blue dotmatrix simulated clock", - "icon": "dotmatrixclock.png", - "type": "clock", - "tags": "clock,dotmatrix,retro", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"dotmatrixclock.app.js","url":"app.js"}, - {"name":"dotmatrixclock.img","url":"dotmatrixclock-icon.js","evaluate":true} - ] - }, - { - "id": "jbm8b", - "name": "Magic 8 Ball", - "shortName": "Magic 8 Ball", - "version": "0.03", - "description": "A simple fortune telling app", - "icon": "app.png", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"jbm8b.app.js","url":"app.js"}, - {"name":"jbm8b.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "jbm8b_IT", - "name": "Magic 8 Ball Italiano", - "shortName": "Magic 8 Ball IT", - "version": "0.01", - "description": "La palla predice il futuro", - "icon": "app.png", - "screenshots": [{"url":"bangle1-magic-8-ball-italiano-screenshot.png"}], - "tags": "game", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"jbm8b_IT.app.js","url":"app.js"}, - {"name":"jbm8b_IT.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "BLEcontroller", - "name": "BLE Customisable Controller with Joystick", - "shortName": "BLE Controller", - "version": "0.01", - "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", - "icon": "BLEcontroller.png", - "tags": "tool,bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": false, - "storage": [ - {"name":"BLEcontroller.app.js","url":"app.js"}, - {"name":"BLEcontroller.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widviz", - "name": "Widget Visibility Widget", - "shortName": "Viz Widget", - "version": "0.03", - "description": "Swipe left to hide top bar widgets, swipe right to redisplay.", - "icon": "eye.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widviz.wid.js","url":"widget.js"} - ] - }, - { - "id": "binclock", - "name": "Binary Clock", - "shortName": "Binary Clock", - "version": "0.03", - "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", - "icon": "app.png", - "type": "clock", - "tags": "clock,binary", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"binclock.app.js","url":"app.js"}, - {"name":"binclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pizzatimer", - "name": "Pizza Timer", - "shortName": "Pizza Timer", - "version": "0.01", - "description": "A timer app for when you cook Pizza. Some say it can also time other things", - "icon": "pizza.png", - "tags": "timer,tool,pizza", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"pizzatimer.app.js","url":"app.js"}, - {"name":"pizzatimer.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "animclk", - "name": "Animated Clock", - "shortName": "Anim Clock", - "version": "0.03", - "description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art", - "icon": "app.png", - "type": "clock", - "tags": "clock,animated", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"animclk.app.js","url":"app.js"}, - {"name":"animclk.pixels1","url":"animclk.pixels1"}, - {"name":"animclk.pixels2","url":"animclk.pixels2"}, - {"name":"animclk.pal","url":"animclk.pal"}, - {"name":"animclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "analogimgclk", - "name": "Analog Clock (Image background)", - "shortName": "Analog Clock", - "version": "0.03", - "description": "An analog clock with an image background", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"analogimgclk.app.js","url":"app.js"}, - {"name":"analogimgclk.bg.img","url":"bg.img"}, - {"name":"analogimgclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "verticalface", - "name": "Vertical watch face", - "shortName": "Vertical Face", - "version": "0.09", - "description": "A simple vertical watch face with the date. Heart rate monitor is toggled with BTN1", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "allow_emulator": true, - "screenshots": [{"url":"bangle1-vertical-watch-face-screenshot.png"}], - "storage": [ - {"name":"verticalface.app.js","url":"app.js"}, - {"name":"verticalface.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "sleepphasealarm", - "name": "SleepPhaseAlarm", - "shortName": "SleepPhaseAlarm", - "version": "0.02", - "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", - "icon": "app.png", - "tags": "alarm", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"sleepphasealarm.app.js","url":"app.js"}, - {"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "life", - "name": "Game of Life", - "version": "0.04", - "description": "Conway's Game of Life - 16x16 board", - "icon": "life.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-game-of-life-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"life.app.js","url":"life.min.js"}, - {"name":"life.img","url":"life-icon.js","evaluate":true} - ] - }, - { - "id": "magnav", - "name": "Navigation Compass", - "version": "0.05", - "description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.", - "screenshots": [{"url":"screenshot-b2.png"},{"url":"screenshot-light-b2.png"}], - "icon": "magnav.png", - "tags": "tool,outdoors", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"magnav.app.js","url":"magnav_b1.js","supports":["BANGLEJS"]}, - {"name":"magnav.app.js","url":"magnav_b2.js","supports":["BANGLEJS2"]}, - {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} - ], - "data": [{"name":"magnav.json"}] - }, - { - "id": "gpspoilog", - "name": "GPS POI Logger", - "shortName": "GPS POI Log", - "version": "0.01", - "description": "A simple app to log points of interest with their GPS coordinates and read them back onto your PC. Based on the https://www.espruino.com/Bangle.js+Storage tutorial", - "icon": "app.png", - "tags": "outdoors", - "supports": ["BANGLEJS"], - "interface": "interface.html", - "storage": [ - {"name":"gpspoilog.app.js","url":"app.js"}, - {"name":"gpspoilog.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "miclock2", - "name": "Mixed Clock 2", - "version": "0.01", - "description": "White color variant of the Mixed Clock with thicker clock hands for better readability in the bright sunlight, extra space under the clock for widgets and seconds in the digital clock.", - "icon": "clock-mixed.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-mixed-clock-2-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"miclock2.app.js","url":"clock-mixed.js"}, - {"name":"miclock2.img","url":"clock-mixed-icon.js","evaluate":true} - ] - }, - { - "id": "1button", - "name": "One-Button-Tracker", - "version": "0.01", - "description": "A widget that turns BTN1 into a tracker, records time of button press/release.", - "icon": "widget.png", - "type": "widget", - "tags": "tool,quantifiedself,widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"1button.wid.js","url":"widget.js"} - ], - "data": [{"name":"one_button_presses.csv","storageFile":true}] - }, - { - "id": "gpsautotime", - "name": "GPS auto time", - "shortName": "GPS auto time", - "version": "0.01", - "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"], - "storage": [ - {"name":"gpsautotime.wid.js","url":"widget.js"} - ] - }, - { - "id": "espruinoctrl", - "name": "Espruino Control", - "shortName": "Espruino Ctrl", - "version": "0.01", - "description": "Send commands to other Espruino devices via the Bluetooth UART interface. Customisable commands!", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "custom": "custom.html", - "storage": [ - {"name":"espruinoctrl.app.js"}, - {"name":"espruinoctrl.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "multiclock", - "name": "Multi Clock", - "version": "0.09", - "description": "Clock with multiple faces. Switch between faces with BTN1 & BTN3 (Bangle 2 touch top-right, bottom right). For best display set theme Background 2 to cyan or some other bright colour in settings.", - "screenshots": [{"url":"screen-ana.png"},{"url":"screen-big.png"},{"url":"screen-td.png"},{"url":"screen-nifty.png"},{"url":"screen-word.png"},{"url":"screen-sec.png"}], - "icon": "multiclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"multiclock.app.js","url":"multiclock.app.js"}, - {"name":"big.face.js","url":"big.face.js"}, - {"name":"ana.face.js","url":"ana.face.js"}, - {"name":"digi.face.js","url":"digi.face.js"}, - {"name":"txt.face.js","url":"txt.face.js"}, - {"name":"dk.face.js","url":"dk.face.js"}, - {"name":"nifty.face.js","url":"nifty.face.js"}, - {"name":"multiclock.img","url":"multiclock-icon.js","evaluate":true} - ] - }, - { - "id": "widancs", - "name": "Apple Notification Widget", - "shortName": "ANCS Widget", - "version": "0.07", - "description": "Displays call, message etc notifications from a paired iPhone. Read README before installation as it only works with compatible apps", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"widancs.wid.js","url":"ancs.min.js"}, - {"name":"widancs.settings.js","url":"settings.js"} - ] - }, - { - "id": "accelrec", - "name": "Acceleration Recorder", - "shortName": "Accel Rec", - "version": "0.02", - "description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"accelrec.app.js","url":"app.js"}, - {"name":"accelrec.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"wildcard":"accelrec.?.csv"}] - }, - { - "id": "accellog", - "name": "Acceleration Logger", - "shortName": "Accel Log", - "version": "0.03", - "description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC", - "icon": "app.png", - "tags": "outdoor", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"accellog.app.js","url":"app.js"}, - {"name":"accellog.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"wildcard":"accellog.?.csv"}] - }, - { - "id": "cprassist", - "name": "CPR Assist", - "version": "0.01", - "description": "Provides assistance while performing a CPR", - "icon": "cprassist-icon.png", - "tags": "tool,firstaid", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-CPR-assist-screenshot.png"}], - "storage": [ - {"name":"cprassist.app.js","url":"cprassist.js"}, - {"name":"cprassist.img","url":"cprassist-icon.js","evaluate":true}, - {"name":"cprassist.settings.js","url":"settings.js"} - ] - }, - { - "id": "osgridref", - "name": "Ordnance Survey Grid Reference", - "shortName": "OS Grid ref", - "version": "0.01", - "description": "Displays the UK Ordnance Survey grid reference of your current GPS location. Useful when in the United Kingdom with an Ordnance Survey map", - "icon": "app.png", - "tags": "outdoors,gps", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"osgridref.app.js","url":"app.js"}, - {"name":"osgridref.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "openseizure", - "name": "OpenSeizureDetector Widget", - "shortName": "Short Name", - "version": "0.01", - "description": "[BETA!] A widget to work alongside [OpenSeizureDetector](https://www.openseizuredetector.org.uk/)", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"openseizure.wid.js","url":"widget.js"} - ] - }, - { - "id": "counter", - "name": "Counter", - "version": "0.03", - "description": "Simple counter", - "icon": "counter_icon.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-counter-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"counter.app.js","url":"counter.js"}, - {"name":"counter.img","url":"counter-icon.js","evaluate":true} - ] - }, - { - "id": "bootgattbat", - "name": "BLE GATT Battery Service", - "shortName": "BLE Battery Service", - "version": "0.01", - "description": "Adds the GATT Battery Service to advertise the percentage of battery currently remaining over Bluetooth.\n", - "icon": "bluetooth.png", - "type": "bootloader", - "tags": "battery,ble,bluetooth,gatt", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"gattbat.boot.js","url":"boot.js"} - ] - }, - { - "id": "viewstl", - "name": "STL file viewer", - "shortName": "ViewSTL", - "version": "0.02", - "description": "This app allows you to view STL 3D models on your watch", - "icon": "icons8-octahedron-48.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"viewstl.app.js","url":"viewstl.min.js"}, - {"name":"viewstl.img","url":"viewstl-icon.js","evaluate":true}, - {"name":"tetra.stl","url":"tetra.stl"}, - {"name":"cube.stl","url":"cube.stl"}, - {"name":"icosa.stl","url":"icosa.stl"} - ] - }, - { - "id": "cscsensor", - "name": "Cycling speed sensor", - "shortName": "CSCSensor", - "version": "0.06", - "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", - "icon": "icons8-cycling-48.png", - "tags": "outdoors,exercise,ble,bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, - {"name":"cscsensor.settings.js","url":"settings.js"}, - {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} - ] - }, - { - "id": "fileman", - "name": "File manager", - "shortName": "FileManager", - "version": "0.03", - "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"], - "readme": "README.md", - "storage": [ - {"name":"fileman.app.js","url":"fileman.app.js"}, - {"name":"fileman.img","url":"fileman-icon.js","evaluate":true} - ] - }, - { - "id": "worldclock", - "name": "World Clock - 4 time zones", - "shortName": "World Clock", - "version": "0.05", - "description": "Current time zone plus up to four others", - "icon": "app.png", - "screenshots": [{"url":"screenshot_world.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "custom": "custom.html", - "storage": [ - {"name":"worldclock.app.js","url":"app.js"}, - {"name":"worldclock.img","url":"worldclock-icon.js","evaluate":true} - ], - "data": [{"name":"worldclock.settings.json"}] - }, - { - "id": "digiclock", - "name": "Digital Clock Face", - "shortName": "Digi Clock", - "version": "0.02", - "description": "A simple digital clock with the time, day, month, and year", - "icon": "digiclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"digiclock.app.js","url":"digiclock.js"}, - {"name":"digiclock.img","url":"digiclock-icon.js","evaluate":true} - ] - }, - { - "id": "dsdrelay", - "name": "DSD BLE Relay controller", - "shortName": "DSDRelay", - "version": "0.01", - "description": "Control BLE relay board from the watch", - "icon": "icons8-relay-48.png", - "tags": "ble,bluetooth", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"dsdrelay.app.js","url":"dsdrelay.app.js"}, - {"name":"dsdrelay.img","url":"dsdrelay-icon.js","evaluate":true} - ] - }, - { - "id": "mandel", - "name": "Mandelbrot", - "shortName": "Mandel", - "version": "0.01", - "description": "Draw a zoomable Mandelbrot set", - "icon": "mandel.png", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"mandel.app.js","url":"mandel.min.js"}, - {"name":"mandel.img","url":"mandel-icon.js","evaluate":true} - ] - }, - { - "id": "petrock", - "name": "Pet rock", - "version": "0.02", - "description": "A virtual pet rock with wobbly eyes", - "icon": "petrock.png", - "type": "app", - "tags": "game", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"petrock.app.js","url":"app.js"}, - {"name":"petrock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "smartibot", - "name": "Smartibot controller", - "shortName": "Smartibot", - "version": "0.01", - "description": "Control a [Smartibot Robot](https://thecraftyrobot.net/) straight from your Bangle.js", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"smartibot.app.js","url":"app.js"}, - {"name":"smartibot.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widncr", - "name": "NCR Logo Widget", - "version": "0.01", - "description": "Show the NodeConf Remote logo in the top left", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"widncr.wid.js","url":"widget.js"} - ] - }, - { - "id": "ncrclk", - "name": "NCR Clock", - "shortName": "NCR Clock", - "version": "0.02", - "description": "NodeConf Remote clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"ncrclk.app.js","url":"app.js"}, - {"name":"ncrclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "isoclock", - "name": "ISO Compliant Clock Face", - "shortName": "ISO Clock", - "version": "0.02", - "description": "Tweaked fork of digiclock for ISO date and time", - "icon": "isoclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"isoclock.app.js","url":"isoclock.js"}, - {"name":"isoclock.img","url":"isoclock-icon.js","evaluate":true} - ] - }, - { - "id": "gpstimeserver", - "name": "GPS Time Server", - "version": "0.01", - "description": "A widget which automatically starts the GPS and turns Bangle.js into a Bluetooth time server.", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"gpstimeserver.wid.js","url":"widget.js"} - ] - }, - { - "id": "tilthydro", - "name": "Tilt Hydrometer Display", - "shortName": "Tilt Hydro", - "version": "0.01", - "description": "A display for the [Tilt Hydrometer](https://tilthydrometer.com/) - [more info here](http://www.espruino.com/Tilt+Hydrometer+Display)", - "icon": "app.png", - "tags": "tools,bluetooth", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"tilthydro.app.js","url":"app.js"}, - {"name":"tilthydro.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "supmariodark", - "name": "Super mario clock night mode", - "shortName": "supmariodark", - "version": "0.01", - "description": "Super mario clock in night mode", - "icon": "supmariodark.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"supmariodark.app.js","url":"supmariodark.js"}, - {"name":"supmariodark.img","url":"supmariodark-icon.js","evaluate":true}, - {"name":"supmario30x24.bin","url":"supmario30x24.bin.js"}, - {"name":"supmario30x24.wdt","url":"supmario30x24.wdt.js"}, - {"name":"banner-up.img","url":"banner-up.js","evaluate":true}, - {"name":"banner-down.img","url":"banner-down.js","evaluate":true}, - {"name":"brick2.img","url":"brick2.js","evaluate":true}, - {"name":"enemy.img","url":"enemy.js","evaluate":true}, - {"name":"flower.img","url":"flower.js","evaluate":true}, - {"name":"flower_b.img","url":"flower_b.js","evaluate":true}, - {"name":"mario_wh.img","url":"mario_wh.js","evaluate":true}, - {"name":"pipe.img","url":"pipe.js","evaluate":true} - ] - }, - { - "id": "gmeter", - "name": "G-Meter", - "shortName": "G-Meter", - "version": "0.01", - "description": "Simple G-Meter", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"gmeter.app.js","url":"app.js"}, - {"name":"gmeter.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "dtlaunch", - "name": "Desktop Launcher", - "version": "0.07", - "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", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"dtlaunch.app.js","url":"app-b1.js", "supports": ["BANGLEJS"]}, - {"name":"dtlaunch.app.js","url":"app-b2.js", "supports": ["BANGLEJS2"]}, - {"name":"dtlaunch.settings.js","url":"settings-b1.js", "supports": ["BANGLEJS"]}, - {"name":"dtlaunch.settings.js","url":"settings-b2.js", "supports": ["BANGLEJS2"]}, - {"name":"dtlaunch.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"dtlaunch.json"}] - }, - { - "id": "HRV", - "name": "Heart Rate Variability monitor", - "shortName": "HRV monitor", - "version": "0.04", - "description": "Heart Rate Variability monitor, see Readme for more info", - "icon": "hrv.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"HRV.app.js","url":"app.js"}, - {"name":"HRV.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hardalarm", - "name": "Hard Alarm", - "shortName": "HardAlarm", - "version": "0.02", - "description": "Make sure you wake up! Count to the right number to turn off the alarm", - "icon": "app.png", - "tags": "tool,alarm,widget", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"hardalarm.app.js","url":"app.js"}, - {"name":"hardalarm.boot.js","url":"boot.js"}, - {"name":"hardalarm.js","url":"hardalarm.js"}, - {"name":"hardalarm.img","url":"app-icon.js","evaluate":true}, - {"name":"hardalarm.wid.js","url":"widget.js"} - ], - "data": [{"name":"hardalarm.json"}] - }, - { - "id": "edisonsball", - "name": "Edison's Ball", - "shortName": "Edison's Ball", - "version": "0.01", - "description": "Hypnagogia/Micro-Sleep alarm for experimental use in exploring sleep transition and combating drowsiness", - "icon": "app-icon.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"edisonsball.app.js","url":"app.js"}, - {"name":"edisonsball.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hrrawexp", - "name": "HRM Data Exporter", - "shortName": "HRM Data Exporter", - "version": "0.01", - "description": "export raw hrm signal data to a csv file", - "icon": "app-icon.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "interface.html", - "storage": [ - {"name":"hrrawexp.app.js","url":"app.js"}, - {"name":"hrrawexp.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "breath", - "name": "Breathing App", - "shortName": "Breathing App", - "version": "0.01", - "description": "app to aid relaxation and train breath syncronicity using haptics and visualisation, also displays HR", - "icon": "app-icon.png", - "tags": "tools,health", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"breath.app.js","url":"app.js"}, - {"name":"breath.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"breath.settings.json","url":"settings.json"}] - }, - { - "id": "lazyclock", - "name": "Lazy Clock", - "version": "0.03", - "description": "Tells the time, roughly", - "icon": "lazyclock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "screenshots": [{"url":"bangle1-lazy-clock-screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"lazyclock.app.js","url":"lazyclock-app.js"}, - {"name":"lazyclock.img","url":"lazyclock-icon.js","evaluate":true} - ] - }, - { - "id": "astral", - "name": "Astral Clock", - "version": "0.03", - "description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.", - "icon": "app-icon.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"astral.app.js","url":"app.js"}, - {"name":"astral.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "alpinenav", - "name": "Alpine Nav", - "version": "0.01", - "description": "App that performs GPS monitoring to track and display position relative to a given origin in realtime", - "icon": "app-icon.png", - "tags": "outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"alpinenav.app.js","url":"app.js"}, - {"name":"alpinenav.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "lifeclk", - "name": "Game of Life Clock", - "shortName": "Conway's Clock", - "version": "0.06", - "description": "Modification and clockification of Conway's Game of Life", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"lifeclk.app.js","url":"app.min.js"}, - {"name":"lifeclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "speedalt", - "name": "GPS Adventure Sports", - "shortName": "GPS Adv Sport", - "version": "1.02", - "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", - "icon": "app.png", - "type": "app", - "tags": "tool,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"speedalt.app.js","url":"app.js"}, - {"name":"speedalt.img","url":"app-icon.js","evaluate":true}, - {"name":"speedalt.settings.js","url":"settings.js"} - ], - "data": [{"name":"speedalt.json"}] - }, - { - "id": "speedalt2", - "name": "GPS Adventure Sports II", - "shortName":"GPS Adv Sport II", - "version":"1.10", - "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", - "icon": "app.png", - "type": "app", - "tags": "tool,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"speedalt2.app.js","url":"app.js"}, - {"name":"speedalt2.img","url":"app-icon.js","evaluate":true}, - {"name":"speedalt2.settings.js","url":"settings.js"} - ], - "data": [{"name":"speedalt2.json"}] - }, - { - "id": "slomoclock", - "name": "SloMo Clock", - "shortName": "SloMo Clock", - "version": "0.10", - "description": "Simple 24h clock face with large digits, hour above minute. Uses Layout library.", - "icon": "watch.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-slow-mo-clock-screenshot.png"}], - "storage": [ - {"name":"slomoclock.app.js","url":"app.js"}, - {"name":"slomoclock.img","url":"app-icon.js","evaluate":true}, - {"name":"slomoclock.settings.js","url":"settings.js"} - ], - "data": [{"name":"slomoclock.json"}] - }, - { - "id": "de-stress", - "name": "De-Stress", - "shortName": "De-Stress", - "version": "0.02", - "description": "Simple haptic heartbeat", - "icon": "app.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"de-stress.app.js","url":"app.js"}, - {"name":"de-stress.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "mclockplus", - "name": "Morph Clock+", - "shortName": "Morph Clock+", - "version": "0.02", - "description": "Morphing Clock with more readable seconds and date and additional stopwatch", - "icon": "mclockplus.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"mclockplus.app.js","url":"mclockplus.app.js"}, - {"name":"mclockplus.img","url":"mclockplus-icon.js","evaluate":true} - ] - }, - { - "id": "intervals", - "name": "Intervals App", - "shortName": "Intervals", - "version": "0.01", - "description": "Intervals for training. It is possible to configure work time and rest time and number of sets.", - "icon": "intervals.png", - "tags": "", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"intervals.app.js","url":"intervals.app.js"}, - {"name":"intervals.img","url":"intervals-icon.js","evaluate":true} - ] - }, - { - "id": "planetarium", - "name": "Planetarium", - "shortName": "Planetarium", - "version": "0.03", - "description": "Planetarium showing up to 500 stars using the watch location and time", - "icon": "planetarium.png", - "tags": "", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"planetarium.app.js","url":"planetarium.app.js"}, - {"name":"planetarium.data.csv","url":"planetarium.data.csv"}, - {"name":"planetarium.const.csv","url":"planetarium.const.csv"}, - {"name":"planetarium.extra.csv","url":"planetarium.extra.csv"}, - {"name":"planetarium.settings.js","url":"settings.js"}, - {"name":"planetarium.img","url":"planetarium-icon.js","evaluate":true} - ], - "data": [{"name":"planetarium.json"}] - }, - { - "id": "tapelauncher", - "name": "Tape Launcher", - "version": "0.02", - "description": "An App launcher, icons displayed in a horizontal tape, swipe or use buttons", - "icon": "icon.png", - "type": "launch", - "tags": "tool,system,launcher", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"tapelauncher.app.js","url":"app.js"}, - {"name":"tapelauncher.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "oblique", - "name": "Oblique Strategies", - "version": "0.01", - "description": "Oblique Strategies for creativity. Copied from Brian Eno.", - "icon": "eno.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"oblique.app.js","url":"app.js"}, - {"name":"oblique.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "testuserinput", - "name": "Test User Input", - "shortName": "Test User Input", - "version": "0.06", - "description": "App to test the bangle.js input interface. It displays the user action in text, circle buttons or on/off switch UI elements.", - "icon": "app.png", - "tags": "input,interface,buttons,touch,UI", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"testuserinput.app.js","url":"app.js"}, - {"name":"testuserinput.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gpssetup", - "name": "GPS Setup", - "shortName": "GPS Setup", - "version": "0.02", - "description": "Configure the GPS power options and store them in the GPS nvram", - "icon": "gpssetup.png", - "tags": "gps,tools,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"gpssetup","url":"gpssetup.js"}, - {"name":"gpssetup.settings.js","url":"settings.js"}, - {"name":"gpssetup.app.js","url":"app.js"}, - {"name":"gpssetup.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"gpssetup.settings.json","url":"settings.json"}] - }, - { - "id": "walkersclock", - "name": "Walkers Clock", - "shortName": "Walkers Clock", - "version": "0.04", - "description": "A large font watch, displays steps, can switch GPS on/off, displays grid reference", - "icon": "walkersclock48.png", - "type": "clock", - "tags": "clock,gps,tools,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"walkersclock.app.js","url":"app.js"}, - {"name":"walkersclock.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "widgps", - "name": "GPS Widget", - "version": "0.03", - "description": "Tiny widget to show the power on/off status of the GPS", - "icon": "widget.png", - "type": "widget", - "tags": "widget,gps", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widgps.wid.js","url":"widget.js"} - ] - }, - { - "id": "widhrt", - "name": "HRM Widget", - "version": "0.03", - "description": "Tiny widget to show the power on/off status of the Heart Rate Monitor", - "icon": "widget.png", - "type": "widget", - "tags": "widget,hrm", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widhrt.wid.js","url":"widget.js"} - ] - }, - { - "id": "countdowntimer", - "name": "Countdown Timer", - "version": "0.01", - "description": "A simple countdown timer with a focus on usability", - "icon": "countdowntimer.png", - "tags": "timer,tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"countdowntimer.app.js","url":"countdowntimer.js"}, - {"name":"countdowntimer.img","url":"countdowntimer-icon.js","evaluate":true} - ] - }, - { - "id": "helloworld", - "name": "hello, world!", - "shortName": "hello world", - "version": "0.02", - "description": "A cross cultural hello world!/hola mundo! app with colors and languages", - "icon": "app.png", - "tags": "input,interface,buttons,touch", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"helloworld.app.js","url":"app.js"}, - {"name":"helloworld.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widcom", - "name": "Compass Widget", - "version": "0.02", - "description": "Tiny widget to show the power on/off status of the Compass", - "icon": "widget.png", - "type": "widget", - "tags": "widget,compass", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widcom.wid.js","url":"widget.js"} - ] - }, - { - "id": "arrow", - "name": "Arrow Compass", - "version": "0.05", - "description": "Moving arrow compass that points North, shows heading, with tilt correction. Based on jeffmer's Navigation Compass", - "icon": "arrow.png", - "type": "app", - "tags": "tool,outdoors", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"arrow.app.js","url":"app.js"}, - {"name":"arrow.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "waypointer", - "name": "Way Pointer", - "version": "0.01", - "description": "Navigate to a waypoint using the GPS for bearing and compass to point way, uses the same waypoint interface as GPS Navigation", - "icon": "waypointer.png", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "waypoints.html", - "storage": [ - {"name":"waypointer.app.js","url":"app.js"}, - {"name":"waypointer.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"waypoints.json","url":"waypoints.json"}] - }, - { - "id": "color_catalog", - "name": "Colors Catalog", - "shortName": "Colors Catalog", - "version": "0.01", - "description": "Displays RGB565 and RGB888 colors, its name and code in screen.", - "icon": "app.png", - "tags": "Color,input,buttons,touch,UI", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"color_catalog.app.js","url":"app.js"}, - {"name":"color_catalog.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "UI4swatch", - "name": "UI 4 swatch", - "shortName": "UI 4 swatch", - "version": "0.01", - "description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.", - "icon": "app.png", - "tags": "Color,input,buttons,touch,UI", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"UI4swatch.app.js","url":"app.js"}, - {"name":"UI4swatch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "simplest", - "name": "Simplest Clock", - "version": "0.03", - "description": "The simplest working clock, acts as a tutorial piece", - "icon": "simplest.png", - "screenshots": [{"url":"screenshot_simplest.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"simplest.app.js","url":"app.js"}, - {"name":"simplest.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "stepo", - "name": "Stepometer Clock", - "version": "0.03", - "description": "A large font watch, displays step count in a doughnut guage and warns of low battery, requires one of the steps widgets to be installed", - "icon": "stepo.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"stepo.app.js","url":"app.js"}, - {"name":"stepo.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "gbmusic", - "name": "Gadgetbridge Music Controls", - "shortName": "Music Controls", - "version": "0.08", - "description": "Control the music on your Gadgetbridge-connected phone", - "icon": "icon.png", - "screenshots": [{"url":"screenshot_v1.png"},{"url":"screenshot_v2.png"}], - "type": "app", - "tags": "tools,bluetooth,gadgetbridge,music", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"gbmusic.app.js","url":"app.js"}, - {"name":"gbmusic.settings.js","url":"settings.js"}, - {"name":"gbmusic.wid.js","url":"widget.js"}, - {"name":"gbmusic.img","url":"icon.js","evaluate":true} - ], - "data": [{"name":"gbmusic.json"},{"name":"gbmusic.load.json"}] - }, - { - "id": "battleship", - "name": "Battleship", - "version": "0.01", - "description": "The classic game of battleship", - "icon": "battleship-icon.png", - "tags": "game", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-battle-ship-screenshot.png"}], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"battleship.app.js","url":"battleship.js"}, - {"name":"battleship.img","url":"battleship-icon.js","evaluate":true} - ] - }, - { - "id": "kitchen", - "name": "Kitchen Combo", - "version": "0.13", - "description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'", - "icon": "kitchen.png", - "type": "clock", - "tags": "tool,outdoors,gps", - "supports": ["BANGLEJS"], - "readme": "README.md", - "interface": "waypoints.html", - "storage": [ - {"name":"kitchen.app.js","url":"kitchen.app.js"}, - {"name":"stepo2.kit.js","url":"stepo2.kit.js"}, - {"name":"swatch.kit.js","url":"swatch.kit.js"}, - {"name":"gps.kit.js","url":"gps.kit.js"}, - {"name":"compass.kit.js","url":"compass.kit.js"}, - {"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true} - ], - "data": [{"name":"waypoints.json","url":"waypoints.json"}] - }, - { - "id": "banglebridge", - "name": "BangleBridge", - "shortName": "BangleBridge", - "version": "0.01", - "description": "Widget that allows Bangle Js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App", - "icon": "widget.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"banglebridge.wid.js","url":"widget.js"}, - {"name":"banglebridge.watch.img","url":"watch.img"}, - {"name":"banglebridge.heart.img","url":"heart.img"} - ] - }, - { - "id": "qmsched", - "name": "Quiet Mode Schedule and Widget", - "shortName": "Quiet Mode", - "version": "0.06", - "description": "Automatically turn Quiet Mode on or off at set times, and change LCD options while Quiet Mode is active.", - "icon": "app.png", - "screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"}, - {"url":"screenshot_b2_main.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_lcd.png"}], - "tags": "tool,widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"qmsched","url":"lib.js"}, - {"name":"qmsched.app.js","url":"app.js"}, - {"name":"qmsched.boot.js","url":"boot.js"}, - {"name":"qmsched.img","url":"icon.js","evaluate":true}, - {"name":"qmsched.wid.js","url":"widget.js"} - ], - "data": [{"name":"qmsched.json"}] - }, - { - "id": "hourstrike", - "name": "Hour Strike", - "shortName": "Hour Strike", - "version": "0.08", - "description": "Strike the clock on the hour. A great tool to remind you an hour has passed!", - "icon": "app-icon.png", - "tags": "tool,alarm", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"hourstrike.app.js","url":"app.js"}, - {"name":"hourstrike.boot.js","url":"boot.js"}, - {"name":"hourstrike.img","url":"app-icon.js","evaluate":true}, - {"name":"hourstrike.json","url":"hourstrike.json"} - ] - }, - { - "id": "whereworld", - "name": "Where in the World?", - "shortName": "Where World", - "version": "0.01", - "description": "Shows your current location on the world map", - "icon": "app.png", - "tags": "gps", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"whereworld.app.js","url":"app.js"}, - {"name":"whereworld.img","url":"app-icon.js","evaluate":true}, - {"name":"whereworld.worldmap","url":"worldmap"} - ] - }, - { - "id": "omnitrix", - "name": "Omnitrix", - "version": "0.01", - "description": "An Omnitrix Showpiece", - "icon": "omnitrix.png", - "screenshots": [{"url":"screenshot.png"}], - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"omnitrix.app.js","url":"omnitrix.app.js"}, - {"name":"omnitrix.img","url":"omnitrix.icon.js","evaluate":true} - ] - }, - { - "id": "batclock", - "name": "Bat Clock", - "shortName": "Bat Clock", - "version": "0.02", - "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", - "icon": "bat-clock.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"batclock.app.js","url":"bat-clock.app.js"}, - {"name":"batclock.img","url":"bat-clock.icon.js","evaluate":true} - ] - }, - { - "id": "doztime", - "name": "Dozenal Time", - "shortName": "Dozenal Time", - "version": "0.04", - "description": "A dozenal Holocene calendar and dozenal diurnal clock", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"doztime.app.js","url":"app.js"}, - {"name":"doztime.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "gbtwist", - "name": "Gadgetbridge Twist Control", - "shortName": "Twist Control", - "version": "0.01", - "description": "Shake your wrist to control your music app via Gadgetbridge", - "icon": "app.png", - "type": "app", - "tags": "tools,bluetooth,gadgetbridge,music", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": false, - "storage": [ - {"name":"gbtwist.app.js","url":"app.js"}, - {"name":"gbtwist.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "thermom", - "name": "Thermometer", - "version": "0.05", - "description": "Displays the current temperature in degree Celsius/Fahrenheit (depending on locale), updates every 10 seconds with average of last 5 readings.", - "icon": "app.png", - "tags": "tool", - "supports": ["BANGLEJS", "BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], - "allow_emulator": true, - "storage": [ - {"name":"thermom.app.js","url":"app.js"}, - {"name":"thermom.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "mysticdock", - "name": "Mystic Dock", - "version": "1.00", - "description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.", - "icon": "mystic-dock.png", - "type": "dock", - "tags": "dock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"mysticdock.app.js","url":"mystic-dock-app.js"}, - {"name":"mysticdock.boot.js","url":"mystic-dock-boot.js"}, - {"name":"mysticdock.settings.js","url":"mystic-dock-settings.js"}, - {"name":"mysticdock.img","url":"mystic-dock-icon.js","evaluate":true} - ] - }, - { - "id": "mysticclock", - "name": "Mystic Clock", - "version": "1.01", - "description": "A retro-inspired watchface featuring time, date, and an interactive data display line.", - "icon": "mystic-clock.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"bangle1-mystic-clock-screenshot.png"}], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"mysticclock.app.js","url":"mystic-clock-app.js"}, - {"name":"mysticclock.settings.js","url":"mystic-clock-settings.js"}, - {"name":"mysticclock.img","url":"mystic-clock-icon.js","evaluate":true} - ] - }, - { - "id": "hcclock", - "name": "Hi-Contrast Clock", - "version": "0.02", - "description": "Hi-Contrast Clock : A simple yet very bold clock that aims to be readable in high luninosity environments. Uses big 10x5 pixel digits. Use BTN 1 to switch background and foreground colors.", - "icon": "hcclock-icon.png", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"bangle1-high-contrast-clock-screenshot.png"}], - "supports": ["BANGLEJS"], - "allow_emulator": true, - "storage": [ - {"name":"hcclock.app.js","url":"hcclock.app.js"}, - {"name":"hcclock.img","url":"hcclock-icon.js","evaluate":true} - ] - }, - { - "id": "thermomF", - "name": "Fahrenheit Temp", - "version": "0.01", - "description": "[NOT RECOMMENDED] A modification of the Thermometer App to display temprature in Fahrenheit. Please use the 'Thermometer App' and install 'Languages' to get the temperature in the correct format for your locale.", - "icon": "thermf.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"thermomF.app.js","url":"app.js"}, - {"name":"thermomF.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "nixie", - "name": "Nixie Clock", - "shortName": "Nixie", - "version": "0.01", - "description": "A nixie tube clock for both Bangle 1 and 2.", - "icon": "nixie.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"nixie.app.js","url":"app.js"}, - {"name":"nixie.img","url":"app-icon.js","evaluate":true}, - {"name":"m_vatch.js","url":"m_vatch.js"} - ] - }, - { - "id": "carcrazy", - "name": "Car Crazy", - "shortName": "Car Crazy", - "version": "0.03", - "description": "A simple car game where you try to avoid the other cars by tilting your wrist left and right. Hold down button 2 to start.", - "icon": "carcrash.png", - "tags": "game", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"carcrazy.app.js","url":"app.js"}, - {"name":"carcrazy.img","url":"app-icon.js","evaluate":true}, - {"name":"carcrazy.settings.js","url":"settings.js"} - ], - "data": [{"name":"CarCrazy.csv"}] - }, - { - "id": "shortcuts", - "name": "Shortcuts", - "shortName": "Shortcuts", - "version": "0.01", - "description": "Quickly load your favourite apps from (almost) any watch face.", - "icon": "app.png", - "type": "bootloader", - "tags": "tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "storage": [ - {"name":"shortcuts.boot.js","url":"boot.js"}, - {"name":"shortcuts.settings.js","url":"settings.js"} - ], - "data": [{"name":"shortcuts.json"}] - }, - { - "id": "vectorclock", - "name": "Vector Clock", - "version": "0.03", - "description": "A digital clock that uses the built-in vector font.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "screenshots": [ - {"url":"bangle2-vector-clock-screenshot.png"}, - {"url":"bangle1-vector-clock-screenshot.png"} - ], - "storage": [ - {"name":"vectorclock.app.js","url":"app.js"}, - {"name":"vectorclock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "fd6fdetect", - "name": "fd6fdetect", - "shortName": "fd6fdetect", - "version": "0.2", - "description": "Allows you to see 0xFD6F beacons near you.", - "icon": "app.png", - "tags": "tool", - "readme": "README.md", - "supports": ["BANGLEJS"], - "storage": [ - {"name":"fd6fdetect.app.js","url":"app.js"}, - {"name":"fd6fdetect.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "choozi", - "name": "Choozi", - "version": "0.01", - "description": "Choose people or things at random using Bangle.js.", - "icon": "app.png", - "tags": "tool", - "supports": ["BANGLEJS"], - "readme": "README.md", - "allow_emulator": true, - "screenshots": [{"url":"bangle1-choozi-screenshot1.png"},{"url":"bangle1-choozi-screenshot2.png"}], - "storage": [ - {"name":"choozi.app.js","url":"app.js"}, - {"name":"choozi.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "widclkbttm", - "name": "Digital clock (Bottom) widget", - "shortName": "Digital clock Bottom Widget", - "version": "0.03", - "description": "Displays time in the bottom area.", - "icon": "widclkbttm.png", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"widclkbttm.wid.js","url":"widclkbttm.wid.js"} - ] - }, - { - "id": "pastel", - "name": "Pastel Clock", - "shortName": "Pastel", - "version": "0.09", - "description": "A Configurable clock with custom fonts and background. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", - "icon": "pastel.png", - "dependencies": {"mylocation":"app", "widpedom":"app"}, - "screenshots": [{"url":"screenshot_pastel.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"f_architect","url":"f_architect.js"}, - {"name":"f_gochihand","url":"f_gochihand.js"}, - {"name":"f_cabin","url":"f_cabin.js"}, - {"name":"f_orbitron","url":"f_orbitron.js"}, - {"name":"f_monoton","url":"f_monoton.js"}, - {"name":"f_elite","url":"f_elite.js"}, - {"name":"f_lato","url":"f_lato.js"}, - {"name":"f_latosmall","url":"f_latosmall.js"}, - {"name":"pastel.app.js","url":"pastel.app.js"}, - {"name":"pastel.img","url":"pastel.icon.js","evaluate":true}, - {"name":"pastel.settings.js","url":"pastel.settings.js"} - ], - "data": [{"name":"pastel.json"}] - }, - { - "id": "antonclk", - "name": "Anton Clock", - "version": "0.03", - "description": "A simple clock using the bold Anton font.", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"antonclk.app.js","url":"app.js"}, - {"name":"antonclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "waveclk", - "name": "Wave Clock", - "version": "0.02", - "description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: Works on any Bangle.js 2, but requires firmware 2v11 or later on Bangle.js 1**", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"waveclk.app.js","url":"app.js"}, - {"name":"waveclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "floralclk", - "name": "Floral Clock", - "version": "0.01", - "description": "A clock with a flower background by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: Works on any Bangle.js 2 but requires firmware 2v11 or later on Bangle.js 1**", - "icon": "app.png", - "screenshots": [{"url":"screenshot_floral.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"floralclk.app.js","url":"app.js"}, - {"name":"floralclk.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "score", - "name": "Score Tracker", - "version": "0.01", - "description": "Score Tracker for sports that use plain numbers (e.g. Badminton, Volleyball, Soccer, Table Tennis, ...). Also supports tennis scoring.", - "icon": "score.app.png", - "screenshots": [{"url":"screenshot_score.png"}], - "type": "app", - "tags": "", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"score.app.js","url":"score.app.js"}, - {"name":"score.settings.js","url":"score.settings.js"}, - {"name":"score.presets.json","url":"score.presets.json"}, - {"name":"score.img","url":"score.app-icon.js","evaluate":true} - ], - "data": [{"name":"score.json"}] - }, - { - "id": "menusmall", - "name": "Small Menus", - "version": "0.02", - "description": "Replace Bangle.js 2's menus with a version that contains smaller text", - "icon": "app.png", - "type": "boot", - "tags": "system", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"menusmall.boot.js","url":"boot.js"} - ] - }, - { - "id": "ffcniftya", - "name": "Nifty-A Clock", - "version": "0.01", - "description": "A nifty clock with time and date", - "icon": "app.png", - "screenshots": [{"url":"screenshot_nifty.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"ffcniftya.app.js","url":"app.js"}, - {"name":"ffcniftya.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "ffcniftyb", - "name": "Nifty-B Clock", - "version": "0.02", - "description": "A nifty clock (series B) with time, date and color configuration", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"ffcniftyb.app.js","url":"app.js"}, - {"name":"ffcniftyb.img","url":"app-icon.js","evaluate":true}, - {"name":"ffcniftyb.settings.js","url":"settings.js"} - ], - "data": [{"name":"ffcniftyb.json"}] - }, - { - "id": "stopwatch", - "name": "Stopwatch Touch", - "version": "0.01", - "description": "A touch based stop watch for Bangle JS 2", - "icon": "stopwatch.png", - "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"}], - "tags": "tools,app", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"stopwatch.app.js","url":"stopwatch.app.js"}, - {"name":"stopwatch.img","url":"stopwatch.icon.js","evaluate":true} - ] - }, - { - "id": "vernierrespirate", - "name": "Vernier Go Direct Respiration Belt", - "shortName": "Respiration Belt", - "version": "0.01", - "description": "Connects to a Go Direct Respiration Belt and shows respiration rate", - "icon": "app.png", - "tags": "health,bluetooth", - "supports": ["BANGLEJS","BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"vernierrespirate.app.js","url":"app.js"}, - {"name":"vernierrespirate.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"vernierrespirate.json"}] - }, - { - "id": "gpstouch", - "name": "GPS Touch", - "version": "0.01", - "description": "A touch based GPS watch, shows OS map reference", - "icon": "gpstouch.png", - "screenshots": [{"url":"screenshot4.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot1.png"}], - "tags": "tools,app", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"geotools","url":"geotools.js"}, - {"name":"gpstouch.app.js","url":"gpstouch.app.js"}, - {"name":"gpstouch.img","url":"gpstouch.icon.js","evaluate":true} - ] - }, - { - "id": "swiperclocklaunch", - "name": "Swiper Clock Launch", - "version": "0.02", - "description": "Navigate between clock and launcher with Swipe action", - "icon": "swiperclocklaunch.png", - "type": "bootloader", - "tags": "tools, system", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - {"name":"swiperclocklaunch.boot.js","url":"boot.js"}, - {"name":"swiperclocklaunch.img","url":"icon.js","evaluate":true} - ] - }, - { - "id": "qalarm", - "name": "Q Alarm and Timer", - "shortName": "Q Alarm", - "icon": "app.png", - "version": "0.03", - "description": "Alarm and timer app with days of week and 'hard' option.", - "tags": "tool,alarm,widget", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - { "name": "qalarm.app.js", "url": "app.js" }, - { "name": "qalarm.boot.js", "url": "boot.js" }, - { "name": "qalarm.js", "url": "qalarm.js" }, - { "name": "qalarmcheck.js", "url": "qalarmcheck.js" }, - { "name": "qalarm.img", "url": "app-icon.js", "evaluate": true }, - { "name": "qalarm.wid.js", "url": "widget.js" } - ], - "data": [{ "name": "qalarm.json" }] - }, - { - "id": "emojuino", - "name": "Emojuino", - "shortName": "Emojuino", - "version": "0.03", - "description": "Emojis & Espruino: broadcast Unicode emojis via Bluetooth Low Energy.", - "icon": "emojuino.png", - "screenshots": [ - { "url": "screenshot-tx.png" }, - { "url": "screenshot-swipe.png" }, - { "url": "screenshot-welcome.png" } - ], - "type": "app", - "tags": "emoji", - "supports" : [ "BANGLEJS2" ], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - { "name": "emojuino.app.js", "url": "emojuino.js" }, - { "name": "emojuino.img", "url": "emojuino-icon.js", "evaluate": true } - ] - }, - { - "id": "cliclockJS2Enhanced", - "name": "Commandline-Clock JS2 Enhanced", - "shortName": "CLI-Clock JS2", - "version": "0.03", - "description": "Simple CLI-Styled Clock with enhancements. Modes that are hard to use and unneded are removed (BPM, battery info, memory ect) credit to hughbarney for the original code and design. Also added HID media controlls, just swipe on the clock face to controll the media! Gadgetbride support coming soon(hopefully) Thanks to t0m1o1 for media controls!", - "icon": "app.png", - "screenshots": [{"url":"screengrab.png"}], - "type": "clock", - "tags": "clock,cli,command,bash,shell", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"cliclockJS2Enhanced.app.js","url":"app.js"}, - {"name":"cliclockJS2Enhanced.img","url":"app.icon.js","evaluate":true} - ] - }, - { - "id": "wid_a_battery_widget", - "name": "A Battery Widget (with percentage)", - "shortName":"A Battery Widget", - "icon": "widget.png", - "version":"1.02", - "type": "widget", - "supports": ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "description": "Simple and slim battery widget with charge status and percentage", - "tags": "widget,battery", - "storage": [ - {"name":"wid_a_battery_widget.wid.js","url":"widget.js"} - ] - }, - { - "id": "lcars", - "name": "LCARS Clock", - "shortName":"LCARS", - "icon": "lcars.png", - "version":"0.07", - "readme": "README.md", - "supports": ["BANGLEJS2"], - "description": "Library Computer Access Retrieval System (LCARS) clock.", - "type": "clock", - "tags": "clock", - "screenshots": [{"url":"screenshot.png"}], - "storage": [ - {"name":"lcars.app.js","url":"lcars.app.js"}, - {"name":"lcars.img","url":"lcars.icon.js","evaluate":true}, - {"name":"lcars.settings.js","url":"lcars.settings.js"} - ] - }, - { "id": "binwatch", - "name": "Binary Watch", - "shortName":"BinWatch", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "version":"0.04", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "allow_emulator":true, - "description": "Famous binary watch", - "tags": "clock", - "type": "clock", - "storage": [ - {"name":"binwatch.app.js","url":"app.js"}, - {"name":"binwatch.bg176.img","url":"Background176_center.img"}, - {"name":"binwatch.bg240.img","url":"Background240_center.img"}, - {"name":"binwatch.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "hidmsicswipe", - "name": "Bluetooth Music Swipe Controls", - "shortName": "Swipe Control", - "version": "0.01", - "description": "Based on the original Bluetooth Music Controls. Swipe up/down for volume, left/right for previous and next, tap for play/pause and btn1 to lock and unlock the controls. Enable HID in settings, pair with your phone, then use this app to control music from your watch!", - "icon": "hidmsicswipe.png", - "tags": "bluetooth", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"hidmsicswipe.app.js","url":"hidmsicswipe.js"}, - {"name":"hidmsicswipe.img","url":"hidmsicswipe-icon.js","evaluate":true} - ] - }, - { - "id": "authentiwatch", - "name": "2FA Authenticator", - "shortName": "AuthWatch", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "version": "0.04", - "description": "Google Authenticator compatible tool.", - "tags": "tool", - "interface": "interface.html", - "supports": ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"authentiwatch.app.js","url":"app.js"}, - {"name":"authentiwatch.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"authentiwatch.json"}] - }, - { "id": "schoolCalendar", - "name": "School Calendar", - "shortName":"SCalendar", - "icon": "CalenderLogo.png", - "version": "0.01", - "description": "A simple calendar that you can see your upcoming events that you create in the customizer. Keep in note that your events reapeat weekly.(Beta)", - "tags": "tool", - "readme":"README.md", - "custom":"custom.html", - "supports": ["BANGLEJS"], - "screenshots": [{"url":"screenshot_basic.png"},{"url":"screenshot_info.png"}], - "storage": [ - {"name":"schoolCalendar.app.js"}, - {"name":"schoolCalendar.img","url":"app-icon.js","evaluate":true} - ], - "data": [ - {"name":"calendarItems.csv"} - ] - }, - { "id": "timecal", - "name": "TimeCal", - "shortName":"TimeCal", - "icon": "icon.png", - "version":"0.01", - "description": "TimeCal shows the Time along with a 3 week calendar", - "tags": "clock", - "type": "clock", - "supports":["BANGLEJS2"], - "storage": [ - {"name":"timecal.app.js","url":"timecal.app.js"} - ] - }, - { - "id": "a_clock_timer", - "name": "A Clock with Timer", - "version": "0.01", - "description": "A Clock with Timer, Map and Time Zones", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"a_clock_timer.app.js","url":"app.js"}, - {"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id":"intervalTimer", - "name":"Interval Timer", - "shortName":"Interval Timer", - "icon": "app.png", - "version":"0.01", - "description": "Interval Timer for workouts, HIIT, or whatever else.", - "tags": "timer, interval, hiit, workout", - "readme":"README.md", - "supports":["BANGLEJS2"], - "storage": [ - {"name":"intervalTimer.app.js","url":"app.js"}, - {"name":"intervalTimer.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "93dub", - "name": "93 Dub", - "shortName":"93 Dub", - "icon": "93dub.png", - "screenshots": [{"url":"screenshot.png"}], - "version":"0.05", - "description": "Fan recreation of orviwan's 91 Dub app for the Pebble smartwatch. Uses assets from his 91-Dub-v2.0 repo", - "tags": "clock", - "type": "clock", - "supports":["BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"93dub.app.js","url":"app.js"}, - {"name":"93dub.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "poweroff", - "name": "Poweroff", - "shortName":"Poweroff", - "version":"0.01", - "description": "Simple app to power off your Bangle.js", - "icon": "app.png", - "tags": "tool, poweroff, shutdown", - "supports" : ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "allow_emulator": true, - "storage": [ - {"name":"poweroff.app.js","url":"app.js"}, - {"name":"poweroff.img","url":"app-icon.js","evaluate":true} - ] -}, -{ - "id": "sensible", - "name": "SensiBLE", - "shortName": "SensiBLE", - "version": "0.04", - "description": "Collect, display and advertise real-time sensor data.", - "icon": "sensible.png", - "screenshots": [ - { "url": "screenshot-top.png" }, - { "url": "screenshot-acc.png" }, - { "url": "screenshot-bar.png" }, - { "url": "screenshot-gps.png" }, - { "url": "screenshot-hrm.png" }, - { "url": "screenshot-mag.png" } - ], - "type": "app", - "tags": "tool,sensors", - "supports" : [ "BANGLEJS2" ], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - { "name": "sensible.app.js", "url": "sensible.js" }, - { "name": "sensible.img", "url": "sensible-icon.js", "evaluate": true } - ] -}, - { - "id": "widbars", - "name": "Bars Widget", - "version": "0.01", - "description": "Display several measurements as vertical bars.", - "icon": "icon.png", - "screenshots": [{"url":"screenshot.png"}], - "readme": "README.md", - "type": "widget", - "tags": "widget", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widbars.wid.js","url":"widget.js"} - ] -}, -{ - "id":"a_speech_timer", - "name":"Speech Timer", - "icon": "app.png", - "version":"1.01", - "description": "A timer designed to help keeping your speeches and presentations to time.", - "tags": "tool,timer", - "readme":"README.md", - "supports":["BANGLEJS2"], - "storage": [ - {"name":"a_speech_timer.app.js","url":"app.js"}, - {"name":"a_speech_timer.img","url":"app-icon.js","evaluate":true} - ] -}, - { "id": "mylocation", - "name": "My Location", - "shortName":"My Location", - "icon": "mylocation.png", - "type": "app", - "screenshots": [{"url":"screenshot_1.png"}], - "version":"0.01", - "description": "Sets and stores the lat and long of your preferred City or it can be set from the GPS. mylocation.json can be used by other apps that need your main location lat and lon. See README", - "readme": "README.md", - "tags": "tool,utility", - "supports": ["BANGLEJS", "BANGLEJS2"], - "storage": [ - {"name":"mylocation.app.js","url":"mylocation.app.js"}, - {"name":"mylocation.img","url":"mylocation.icon.js","evaluate": true } - ], - "data": [ - {"name":"mylocation.json"} - ] - }, - { - "id": "pebble", - "name": "Pebble Clock", - "shortName": "Pebble", - "version": "0.06", - "description": "A pebble style clock to keep the rebellion going", - "dependencies": {"widpedom":"app"}, - "readme": "README.md", - "icon": "pebble.png", - "screenshots": [{"url":"pebble_screenshot.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"pebble.app.js","url":"pebble.app.js"}, - {"name":"pebble.settings.js","url":"pebble.settings.js"}, - {"name":"pebble.img","url":"pebble.icon.js","evaluate":true} - ] - }, - { "id": "pooqroman", - "name": "pooq Roman watch face", - "shortName":"pooq Roman", - "version":"0.03", - "description": "A classic watch face with a certain dynamicity. Most amusing in 24h mode. Slide up to show more hands, down for less(!). By design does not support standard widgets, sorry!", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator":true, - "readme": "README.md", - "storage": [ - {"name":"pooqroman.app.js","url":"app.js"}, - {"name":"pooqroman.img","url":"app-icon.js","evaluate":true} - ], - "data": [ - {"name":"pooqroman.json"} - ] - }, - { - "id": "widbata", - "name": "Battery Level Widget (Themed)", - "shortName":"Battery Theme", - "icon": "widbata.png", - "screenshots": [{"url":"screenshot_widbata_1.png"}], - "version":"0.01", - "type": "widget", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "description": "Shows the current battery level status in the top right using the clocks colour theme", - "tags": "widget,battery", - "storage": [ - {"name":"widbata.wid.js","url":"widbata.wid.js"} - ] - }, - { - "id": "weatherClock", - "name": "Weather Clock", - "version": "0.04", - "description": "A clock which displays current weather conditions (requires Gadgetbridge and Weather apps).", - "icon": "app.png", - "screenshots": [{"url":"screens/screen1.png"}], - "type": "clock", - "tags": "clock, weather", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"weatherClock.app.js","url":"app.js"}, - {"name":"weatherClock.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "menuwheel", - "name": "Wheel Menus", - "version": "0.01", - "description": "Replace Bangle.js 2's menus with a version that contains variable-size text and a back button", - "readme": "README.md", - "icon": "icon.png", - "screenshots": [ - {"url":"screenshot_b1_dark.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_light.png"}, - {"url":"screenshot_b2_dark.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_light.png"} - ], - "type": "boot", - "tags": "system", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"menuwheel.boot.js","url":"boot.js"} - ] - }, - { "id": "widChargingStatus", - "name": "Charging Status", - "shortName":"ChargingStatus", - "icon": "widget.png", - "version":"0.1", - "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", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"widChargingStatus.wid.js","url":"widget.js"} - ] - }, - { - "id": "flow", - "name": "FLOW", - "shortName": "FLOW", - "version": "0.01", - "description": "A game where you have to help a flow avoid white obstacles thing by tapping! This is a demake of an app which I forgot the name of. Press BTN(1) to restart. See if you can get to 2500 score!", - "icon": "app.png", - "tags": "game", - "supports" : ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name": "flow.app.js", "url": "app.js" }, - {"name": "flow.img", "url": "app-icon.js","evaluate": true } - ] - }, - { "id": "scribble", - "name": "Scribble", - "shortName":"Scribble", - "version":"0.01", - "type": "app", - "description": "A keyboard on your wrist! Swipe right for space, left for delete.", - "icon": "app.png", - "allow_emulator": true, - "tags": "tools, keyboard, text, scribble", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"scribble.app.js","url":"app.js"}, - {"name":"scribble.img","url":"app-icon.js","evaluate":true} - ], - "screenshots":[ - { "url":"screenshot.png" } - ] - }, - { - "id": "ptlaunch", - "name": "Pattern Launcher", - "shortName": "Pattern Launcher", - "version": "0.11", - "description": "Directly launch apps from the clock screen with custom patterns.", - "icon": "app.png", - "screenshots": [{"url":"manage_patterns_light.png"}], - "tags": "tools", - "supports": ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - { "name": "ptlaunch.app.js", "url": "app.js" }, - { "name": "ptlaunch.boot.js", "url": "boot.js" }, - { "name": "ptlaunch.img", "url": "app-icon.js", "evaluate": true } - ], - "data": [{"name":"ptlaunch.patterns.json"}] - }, - { - "id": "rebble", - "name": "Rebble Clock", - "shortName": "Rebble", - "version": "0.03", - "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", - "readme": "README.md", - "icon": "rebble.png", - "dependencies": {"mylocation":"app", "widpedom":"app"}, - "screenshots": [{"url":"screenshot_rebble.png"}], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"rebble.app.js","url":"rebble.app.js"}, - {"name":"rebble.settings.js","url":"rebble.settings.js"}, - {"name":"rebble.img","url":"rebble.icon.js","evaluate":true} - ] - }, - { "id": "snaky", - "name": "Snaky", - "shortName":"Snaky", - "version":"0.01", - "description": "The classic snake game. Eat apples and don't bite your tail. Control the snake with the touch screen.", - "tags": "game,fun", - "icon": "snaky.png", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"snaky.app.js","url":"snaky.js"}, - {"name":"snaky.img","url":"snaky-icon.js","evaluate":true} - ] - }, - { - "id": "clicompleteclk", - "name": "CLI complete clock", - "shortName":"CLI cmplt clock", - "version":"0.03", - "description": "Command line styled clock with lots of information", - "icon": "app.png", - "allow_emulator": true, - "type": "clock", - "tags": "clock,cli,command,bash,shell,weather,hrt", - "supports" : ["BANGLEJS", "BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"clicompleteclk.app.js","url":"app.js"}, - {"name":"clicompleteclk.img","url":"app-icon.js","evaluate":true}, - {"name":"clicompleteclk.settings.js","url":"settings.js"} - ], - "data": [{"name":"clicompleteclk.json"}] - }, - { - "id":"awairmonitor", - "name":"Awair Monitor", - "icon": "app.png", - "allow_emulator": true, - "version":"0.01", - "description": "Displays the level of CO2, VOC, PM 2.5, Humidity and Temperature, from your Awair device.", - "tags": "tool,health", - "readme":"README.md", - "supports":["BANGLEJS2"], - "storage": [ - {"name":"awairmonitor.app.js","url":"app.js"}, - {"name":"awairmonitor.img","url":"app-icon.js","evaluate":true} - ] - }, - { "id": "pooqround", - "name": "pooq Round watch face", - "shortName":"pooq Round", - "version":"0.01", - "description": "A 24 hour analogue watchface with high legibility and a novel style.", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator":true, - "readme": "README.md", - "storage": [ - {"name":"pooqround.app.js","url":"app.js"}, - {"name":"pooqround.img","url":"app-icon.js","evaluate":true} - ], - "data": [ - {"name":"pooqround.json"} - ] - }, - { - "id": "coretemp", - "name": "Core Temp Display", - "version": "0.01", - "description": "Display CoreTemp device sensor data", - "icon": "coretemp.png", - "type": "app", - "tags": "health", - "readme": "README.md", - "supports": ["BANGLEJS","BANGLEJS2"], - "storage": [ - {"name":"coretemp.boot.js","url":"boot.js"}, - {"name":"coretemp.app.js","url":"coretemp.js"}, - {"name":"coretemp.img","url":"coretemp-icon.js","evaluate":true} - ] - }, - { - "id": "showimg", - "name": "simple image viewer", - "shortName":"showImage", - "version":"0.2", - "description": "Displays the image in \"showimg.user.img\". The file has to be uploaded via the espruino IDE. Returns to watch face after 60s or button push. I use it to display my vaccination certificate.", - "icon": "app.png", - "tags": "tool", - "supports" : ["BANGLEJS2"], - "storage": [ - {"name":"showimg.app.js","url":"app.js"}, - {"name":"showimg.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "lapcounter", - "name": "Lap Counter", - "version": "0.01", - "description": "Click button to count laps. Shows count and total time snapshot (like a stopwatch, but laid back).", - "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], - "type": "app", - "tags": "tool,outdoors", - "readme":"README.md", - "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"lapcounter.app.js","url":"app.js"}, - {"name":"lapcounter.img","url":"app-icon.js","evaluate":true} - ] - }, - { - "id": "pebbled", - "name": "Pebble Clock with distance", - "shortName": "Pebble + distance", - "version": "0.1", - "description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).", - "readme": "README.md", - "icon": "pebbled.png", - "screenshots": [{"url":"pebble_screenshot.png"}], - "type": "clock", - "tags": "clock,distance", - "supports": ["BANGLEJS2"], - "storage": [ - {"name":"pebbled.app.js","url":"pebbled.app.js"}, - {"name":"pebbled.settings.js","url":"pebbled.settings.js"}, - {"name":"pebbled.img","url":"pebbled.icon.js","evaluate":true} - ] - }, - { "id": "circlesclock", - "name": "Circles clock", - "shortName":"Circles clock", - "version":"0.02", - "description": "A clock with circles for different data at the bottom in a probably familiar style", - "icon": "app.png", - "dependencies": {"widpedom":"app"}, - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "allow_emulator":true, - "readme": "README.md", - "storage": [ - {"name":"circlesclock.app.js","url":"app.js"}, - {"name":"circlesclock.img","url":"app-icon.js","evaluate":true}, - {"name":"circlesclock.settings.js","url":"settings.js"} - ], - "data": [ - {"name":"circlesclock.json"} - ] - }, - { - "id": "ltherm", - "name": "Localized Thermometer", - "shortName": "Thermometer", - "version": "0.01", - "description": "Displays the current temperature in localized units.", - "icon": "thermf.png", - "tags": "tool", - "supports": ["BANGLEJS2"], - "allow_emulator": true, - "readme": "README.md", - "storage": [ - {"name":"ltherm.app.js","url":"app.js"}, - {"name":"ltherm.img","url":"icon.js","evaluate":true} - ] - }, { "id": "aptsciclk", "name": "Apeture Science Clock", From 90fe8fb320a87c7005797b393344769e7d35dd3b Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Mon, 20 Dec 2021 14:12:01 -0800 Subject: [PATCH 038/447] Added more icons, fake loading screen --- apps/aptsciclk/app.js | 66 ++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index cb1305c36..c6120593e 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -20,7 +20,7 @@ function getImg(img){ buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOZFIQOD4EABwnwgEDBwf8g/4h4ODwYQBv4OC+AbDAIP+j/HAQIOC4Hwj4RBBwP8o8B/+PBwWOkEP/l/BwP4+JCB44OCj+Ih/+n4OB+PEoP38YOB/0YkUXGgIOB8cBi9f+IOCkEI+XvBwXigFG64OEg0/t4OEuP7BwkHx/PBwWigF8voOC+Uwg/ig4OCkMgv8QsIOB+cfSoOGLIUR/E/4ljBwPxx/B/0kO4UI/0P+J3C/HHVQOISoWEn+D/iPBBwIwC8IOCwcP84IBBwU4TAMHBwfAv+AcARBBgD3CBwX8gDnBBwfwewIODAgIABBwYHDB3oAEBwIHFByyDBABg")) } } - else if (img == "w1"){//cube + else if (img == "w1"){//cube dispenser return { width : 60, height : 60, bpp : 1, buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOI/3/+fvBwYEBnwO/By3APgN/O6IeBh4OF8AOcwADCBwX8g4dM/8fBwt774OE+/9Bwt/BxodH3oOcFgyVG8BhCBwX8hRwCBwXA0C6BBwc/w4OE41MBwtEo6VF84sE/1/54OLDo4sHHYxKHLIxoGO44AD/kAABo")) @@ -38,7 +38,37 @@ function getImg(img){ buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOi+IOGh4OF8AOF/UNBwthx4OE+0YBwtBh4OE6mQBwn7rEfBwl22IOE99gBwn99UzBwUc/+90YsC8HH+++n98n/+g0++2Z+4OB4Fz73T74OCg877d8/YdC+d7u/v3gsBjEvt/+O4X+gvtIgI7CwG934OD8E326kD/0A+yzEwEO74OD/EArYOEgEDv4OD+PAl4OEnkBaInz0EPBwk3iAdE+XwSIYDBj2Oj4OD/fYvIOEvdHz4OD99unIOD/vt44OE3u4Dou3h4OE+3x/IOE70/Bwn78/9Bwl4LAQ7Dx75DBwP4Awb+EBwgAEBz0AABo=")) } } - else if (img == "w4"){//cake + else if (img == "w4"){//falling cube + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOC+YOF/0PBwvgv4OE/kFBwvAyIdFnYeBBwYeDDofng4OE8vYDonx7uPBwkf/+/Bwfh+czBwf+g/5z4OD+FevIdEhMDDon/0E3BwgeBJQgeB+5ZFvAEBBwfzgYOEw/XLInwn3BBwf8gH4LYIOCwUHDonwmE4HYkHwKkE8P4XYQOCv7dCYQkBWYsAWYvAiAsE/EDJQn/wF+CwJZDg/gBwgrBXYIOC8D+FNAL+F4eDBwn4nh2BBweHFYJ3EFYQOC/0P/AOECgIOE/E/BwsHBwvACAIODWAQOEJAIOFAgIOEQ4QsEAAOfBwoACBwgACBw8AABo")) +} + } + else if (img == "w5"){//ball + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOiv4OF8YOFAgQOEyYdGBw3zBw0BBwv4j4OB+EAgOD84OE+/ev4dD/3+BwvcugsE/u7t0f4aRC7e2sF8Bwlxg4dEu8YBwYsB/HDHYsMngOB8EDweHDon//PADoYABz0PBwfwnJKE/0OjZZC/kB4Hxz4OCwEYh+wBwXwgeA/+HBwUP8EP/0/BwPj/0DCQIOB/l/4DQBw4OBDIMPUoJKB+H/wY+B44OBj/4CoJKC+P/g7+FBAL+Fj4OFbwIOEI4IOF8YO6JQwAEaIgORgAANA")) + } + } + else if (img == "w6"){//ball recviver + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOR/YOG34Ob/e7Bwu7CwQOhGgQOD34OF/0LBwvfv4dMuPfBwn29oOFtwONDowsHHY3+h7CNj4OF+IOc4A7NDo7gGJQ4ACBwX+//vBwnvBAIOK8EH/kBBwd+v/PSwIOB/fnjiWBBwXesHPLQIOB/2AgEvBwfgh0AFgf8gAuBLKQObgAANA==")) + } + } + else if (img == "w7"){//falling portals + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YFE/H8BwtvBwvvvgOE/33Bwvf3gOE/v7Bxn5Bw2fHYv7/oOF3/cB118JQQOC4ODJQn8jEfLInBjBoE/0jO4pjD953CwCVF/EH5//+ykCwA8Cp4OB/MDz4DBEQUYjPzaIfn5k/74xC/l44f+BwePz1595ADDYPvv7vDMAN3Bwf4CAIOE4//BYIOB/0On47E8AFCBwcPTwYOCAgPAgE8Bwf8gEDBwOAGIJZDBwX9DofhUYRKDKIIOEAAQOD8EABwgcB+IODnoKB84OD37tCBwUzZ4QODZ4QdDnIFB/YODZwP+v47DJIIBBJQcAAwZyBABoA==")) + } + } + else if (img == "w8"){//flying portals + return { + width : 60, height : 60, bpp : 1, + buffer : require("heatshrink").decompress(atob("AB0//4AE4YFE/H8BwtvBwvvvgOE/33Bwvf3gdF/YOF/4OF/IOGgA7F8ENBwn8gHcBw/5AoOAg4OCh4sD/vD+AFB45KBBwfwv//BwMJgEIFAXcnvggF4kEBBwPMSIIYBz/8nAEBw5ZD4IhBO48AhpoG953FSo/2Ugv/p4OF/LCGaIyIBB34OH4EAngODbAMDBwnfDoqeCBy7RBBwnh//xBwc9BQPnBwe/AYO/BwUzFYQODGgYOCnIFB/YOD57WBv47Dj//AIJKDgAGDOQIANA")) + } + } + else if (img == "w9"){//cake return { width : 60, height : 60, bpp : 1, buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOY/oOG94OF/1/Bwv3FgwKCBwfnFhn8HY0LAQPwvgOB8EP/5uBBwP2gF4j+PBwP+sEEj/x44OB90Ao/8Dodwg8/nkH4ZXBgHnx8ABwPv/k98+ABwZEB+EAJQPj/3+nkAv4OB5+fz0Aj4OB98Ag+Ah/nBwJXB4EDHYSTB/EA/wsCSoJfBwAODNIPgBwgcBHYQOCC4QODn8Ah4ODGgMH+47D8EB/A7KTYMf4A7Eg/wHYgcBHZx3DcAPggbRBFgQcBcAQOB/iUBBwgcBBwgcCd4V/HYL+D/YOBDgIOC8/+DgIOC/+HfwIOD/4cCBwYAEBwQADBz0AABoA=")) @@ -71,7 +101,7 @@ function getImg(img){ return { width : 176, height : 176, bpp : 4, transparent : 2, - buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0SkQASkIVViIrqK/5X/K/5X/CqPd6EAAA8BiAKIABUBiIVUFZMIxBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xal////yK/5XTKwIABK4URAA3/+Pd6ILHAG8YxADBj5XD+ISIBwRX/K4pWDAAIHBiS6CAAMvBYXd6DbTeJcRCqgrJhGIJIJXFkUhK4oLDK/5XSBYhX/K6MvBIQDBK/5XD+RXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+SuEK4yuCK/5XHWAZOCK4cvKwhX/K45MFK4YAGK/5XGLApX/K6X/K5svK/5XIWAZXJ/5X/K6svK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/yK44GDVwRX/K50fWAi9DK/5XGUYRQCkMSK4auDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYXyK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAhXBAoa/Cl5X/K4ZHCAAZXEAoZnCK/5XLVQRXFBgZX/K4igCLAnxK4RdBBohX/K5cikJXCAAxX/K4j5EK/5X/K9fyK/5X/K93/K/5X/KxQABK78vK4PyK/5XWWApXq+JXC+BXeKwRXPl5Xdh//K4Y1BK+H/K7n//GIK4g5BWR5XP+RXNl5Xch+IGQJXFA4JXeJwpXICAJXah/4x4fBKwURj5XBBIJXcVwpXBFoYwDK4XRBYwAR/CtFAAZXCBQ4AQjBXCCRxXcUoJLDjnMhnMBgTqCK7RzIiS3FkRXC6DbTAAf4UYIoB5gABK4PM4KBD+AcLFZUIK4JNGkUhK44ABK7EPQwZWCK4ZYCWARXY+RXrVwccK4/MWB5XMJhBXkVwJWEK4pYBK/4AGh+IVwJQEK43BWARX/VwmP+JXNWBpX5VwMcK5fMiKwBK9YAKCphXCJ4pXH4JXB+QrWCtUvxHxK58R///K/5XCx/xjhPFdAJYGK/5XN4ACEK/4AIIYMRK4qsDWAsRj//+RX/iIACVw6wH4ITCEJBXlxGCARxXIVQoFEK+MoxGIARgQBK/5XbgAADK4oKEgJX/V/4AJxGCARxX/Cq5XI4AEIV+wVO///iMcVRC0FiMf//yTNIADlABCCp0v//xK4qrCVwpXB/+PeNRXf5kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwQVQ///K58f/HyK94VSK4UcK5kRj+IK8I1BADhXE+KwGK4vBiP4x5XhEJQASl4DDWARXMj/4NwZX/WAkcK5UR/+IGgbeXK9awBLAhXEiKuBx40DHCYuEK9EvWAURK4/BVwSWEK/6wGLAZXCKwKuGK/6wIiMcK4QFBVw5X/WA2IwJSCAAYJBVwpX/WA2IJwJVDj///GPVwpX/A434K4PxVoYHBKwxX/AAynCK4ZWCGA5X/BI//V4itHK/4LKK4YtKK/4qJK4QOKK/5X/K8BYCBpZX/K/5XVfYQAWK6gedK/5XiBhchiINLK6grJK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xu/4AYV/4AXK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6v/ADCv/ABMhiKv/K/5X/K/5X/K/5X/K/5X6/4AdiIAYFzw=")) + buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vQgAAHgMQBRAAKgMRCqgrJhGIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7Uv///+RX/K6ZWBAAJXDAA3/+Pd6IMIAG0YxADBj5XD+ISIBwRX/K4pWDAAIMCXQQABl4LC7vQbabxLiIVUFZMIxBJBK4siK4wLDK/5XSBYhX/K6MvBIQDBK/5XD+RXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+SuEK4yuCK/5XHWAZOCK4cvKwhX/K45MFK4YAGK/5XGLApX/K6X/K5svK/5XIWAZXJ/5X/K6svK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/yK44GDVwRX/K50fWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYXyK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UvK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYE+JXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5Xr+RX/K/5Xu/5X/K/5WKAAJXfl5XB+RX/K6ywFK9XxK4XwK7xWCK58vK7sP/5XDGoJXw/5Xc//4xBXEHIKyPK5/yK5svK7kPxAyBK4oHBK7xOFK5AQBK7UP/GPD4JWCiMfK4IJBK7iuFK4QAFj5XC6IMHACH4VooADK4QKHACEYK4QSOK7ilBJYcc5kM5gMCdQRXaOZK3FkRXC6DbTAAf4UYInB5gABK4PM4KBD+AcLFZUIK4JNGkRXIAAJXYh6GDKwRXDLASwCK7HyK9auDjhXH5iwPK5hMIK8iuBKwhXFLAJX/AA0PxCuBKAhXG4KwCK/6uEx/xK5qwNK/KuBjhXL5kRWAJXrABUhiQMKK4RPFK4/BK4PyFaxXql+I+JXPiP//5X/K4WP+McJ4roBLAxX/K5vAAQhX/ABBDBiJXFVgawFiMf//yK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrO///iMcVRC0FiMf//yQaZXZlABCFZ0v//xK4qrCVwpXB/+PbahX15kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwQrQ///K58f/HyK94rSK4UcK5kRj+IK8I1BADhXE+KwGK4vBiP4x5XhEJQASl4DDWARXMj/4NwZX/WAkcK5TiBxA0Dby5XrWAJYEK4kRVwOPGgY4TFwhXol6wCiJXH4KuCSwhX/WAxYDK4RWBVwxX/WBERjhXCAoKuHK/6wGxGBKQQADBIKuFK/6wGxBOBKocf//4x6uFK/4HG/BXB+KtDA4JWGK/4AGU4RXDKwQwHK/4JH/6vEVo5X/BZRXDFpRX/ABEhK4QOKK/5X/K8BYCBpZX/K/5XVfYQAWK6gedK/5XiBhchiINLK6gJIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xv/4AYV/4AXK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6v/ADCv/ABMhiKv/K/5X/K/5X/K/5X/K/5X6/4AdiIAYFzwA=")) } } } @@ -84,8 +114,6 @@ function drawStart(){ g.drawImage(apSciLab, xyCenter-apSciLab.width/2, xyCenter-apSciLab.height/2); } -drawStart(); - // Check settings for what type our clock should be var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; @@ -94,7 +122,7 @@ var drawTimeout; //warnings var curWarning = -1; -var maxWarning = 4; +var maxWarning = 9; function buttonPressed(){ if (curWarning < maxWarning) curWarning += 1; @@ -155,7 +183,7 @@ function draw() { } g.setFont(font, timeFontSize); - g.drawString(`${hours}:${minutes}`, xyCenter, yposTime, false); + g.drawString(`${hours}:${minutes}`, xyCenter+2, yposTime, false); g.setFont(font, gmtFontSize); g.drawString(meridian, xyCenter + 102, yposTime + 10, true); @@ -193,14 +221,18 @@ Bangle.on('touch',(n,e)=>{ } }); -// clean app screen -g.clear(); -// Show launcher when button pressed -Bangle.setUI("clock"); -Bangle.loadWidgets(); -Bangle.drawWidgets(); +//show Apeture laboritories +drawStart(); -buttonPressed();//update warning image - -// draw now -draw(); +setTimeout(function() { + // clean app screen + g.clear(); + // Show launcher when button pressed + Bangle.setUI("clock"); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + //update warning image + buttonPressed(); + // draw now + draw(); + }, 1000); From bce419e78c512ec6809a84407363260a4e1c12bc Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Mon, 20 Dec 2021 14:12:44 -0800 Subject: [PATCH 039/447] Create ChangeLog --- apps/aptsciclk/ChangeLog | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/aptsciclk/ChangeLog diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog new file mode 100644 index 000000000..848bbea09 --- /dev/null +++ b/apps/aptsciclk/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Icons, loading screen From 6e0c1a9f273211e13c9042682fa5318517842556 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Mon, 20 Dec 2021 14:13:22 -0800 Subject: [PATCH 040/447] Update apps.json --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 1d792ecfc..7ac718a1a 100644 --- a/apps.json +++ b/apps.json @@ -2,12 +2,12 @@ { "id": "aptsciclk", "name": "Apeture Science Clock", - "version": "0.1", + "version": "0.2", "description": "A clock based on the portal series", "icon": "app.png", "type": "clock", "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], + "supports": ["BANGLEJS2"], "allow_emulator": true, "storage": [ {"name":"aptsciclk.app.js","url":"app.js"}, From c125dc9e4d2c2b64fcba7717d5f6eb0e446c4a90 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Mon, 20 Dec 2021 14:14:29 -0800 Subject: [PATCH 041/447] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 7ac718a1a..1d0cb6a48 100644 --- a/apps.json +++ b/apps.json @@ -7,7 +7,7 @@ "icon": "app.png", "type": "clock", "tags": "clock", - "supports": ["BANGLEJS2"], + "supports": "BANGLEJS2", "allow_emulator": true, "storage": [ {"name":"aptsciclk.app.js","url":"app.js"}, From ab1b77c0154e991c5e6f84efb74bfb1baff4ce19 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Tue, 28 Dec 2021 20:35:53 -0800 Subject: [PATCH 042/447] Random starter warning, shorter "loading" screen --- apps/aptsciclk/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index c6120593e..5b5e07825 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -121,8 +121,8 @@ var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; var drawTimeout; //warnings -var curWarning = -1; var maxWarning = 9; +var curWarning = Math.floor(Math.random() * (maxWarning+1)); function buttonPressed(){ if (curWarning < maxWarning) curWarning += 1; @@ -235,4 +235,4 @@ setTimeout(function() { buttonPressed(); // draw now draw(); - }, 1000); + }, 500); From 3b764dfec6bcb7220f897aaf1131a0d2322eb491 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Tue, 28 Dec 2021 20:38:26 -0800 Subject: [PATCH 043/447] 0.03 --- apps/aptsciclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog index 848bbea09..61e8307b8 100644 --- a/apps/aptsciclk/ChangeLog +++ b/apps/aptsciclk/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Icons, loading screen +0.03: Random icon, Shorter "loading" screen From a8bcbd6e684f2f74bedbc672718c910e83d7eb24 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 29 Dec 2021 09:11:36 -0800 Subject: [PATCH 044/447] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 1d0cb6a48..1dbb784bf 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "aptsciclk", "name": "Apeture Science Clock", - "version": "0.2", + "version": "0.03", "description": "A clock based on the portal series", "icon": "app.png", "type": "clock", From 401aff4bcac00a7379c141a9a725816a40644b43 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 8 Jan 2022 12:02:32 -0800 Subject: [PATCH 045/447] "support" for light mode Doesn't look as good in my opinion --- apps/aptsciclk/app.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index 5b5e07825..b060541b5 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -78,7 +78,7 @@ function getImg(img){ return { width : 176, height : 176, bpp : 4, transparent : 1, - buffer : require("heatshrink").decompress(atob("iIA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AFEVqsFqpD/ACVVAAJXBqtRI35WSK4ZY/AB8VK49VJP5WRK4pY/ABhQEK41RJn5X/AEMVK5dVJv6uPK46w/K/4AgipPFgEALAxP/K5tQAQhX/K6KsDWApP/AA6uHWA9RIWPd6ICPK46qFAohXxjvd7oCMCAJX/K7cAAAZXFBQkBK/6v/ABPd6ICPK/4AaKIlQAhCv2ACMVVRC0FK2MdAIRXXVYSuFK/5XOqsAgCuFK/4AJJwtVKw1RK+MR7vRK/4AripXMJv6wQK4qu/K/4AjipXKJf5YRK4hJ/ABxXHqJI/LCRXCK34ASipXCIf4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACI=")) + buffer : require("heatshrink").decompress(atob("iIA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AFEc5kM5hD/ACXMAAJXB5nBI35WSK4ZY/AB8cK4/MJP5WRK4pY/ABhPD5e7he7A4fBJn5XNKwJXCLAZX/ABUcKwhXDLAZN/VxhSCK4m8WH5XNVwZXEWARX/ABEcK4sAgBYDXYRP/K5RQC2ACE3e8K/5XPVgYDCK/4AKJIPLVYoEEBoPBIWPd6ICPK46uDAohXzjvd7oCMCAJX/K7cAAAZXFBQkBK/6v/ABPd6ICPK/4AaK4mwKwYEDV+4ARjhKBVQoDD3gMBK2MdAIRXXVYSuDK/5XN5ZRCgEAWQYLBK/4AJK4u7KwZXC4JXxiPd6JXV5hXH3hX1ACscWApXDMQRN/WBpYCK4QICV35XOLARXBA4ZX/ABccKAfMhgFEJf5YRK4hJ/ABxXH4JI/LCRXCK34ASjhXCIf4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACIA==")) } } else if (img == "butUnpress"){ @@ -96,7 +96,15 @@ function getImg(img){ buffer : require("heatshrink").decompress(atob("AA+IAAeAIv5UTK34APhABBKwpeBJX5VLJgJWGAwKv/ABL8EKomABIYA/KpJWHAoRW/KpZQCfwJSCAgRW/KphWFBgZW/KphNCAgSxEKP4ADJAatFKwWAL4oA/KpALGXQhS/Ko4MIwAOMAHREOKv5ZVVgcAh///4LDAwQAB+AIHCQYHMDQQYBDwQEGDIoaGTx4MCwAiCJgYhFBIYIHLw4HFBARjGESJUDehZVFVhJNLRI5VGDIIdEAgwiL+DzDJAJVJB4IMBCoKsHAYpFCDgr2IApYEIBpJFCKpqsCHgQbFIhBVHBhJoGTwyBRKp5mBDoY6GKoYqEXYg7JApKeHQJysEKpRmBDoasHQBAACM4qMGEAr0JAgZjGFYhVPgGAEIpVEAAaAEA4oyEW4qyKFZBoFKoisDJIJWLfIp3IQBJeJfgysMERpVCwEIVpijFBA6ZJdA4JHJYgEKQIx1EVgRVBVhj5IEIyZHHYoUGNw4MCQIwIKAARVDxBVRQo6ZJHZZoGU4yBGBAiBGVgRZBVhYlIfJBoFHZZoHfJRwGBAQrEVISvCKpwrEUZAqFVhzYKB4yKGQIpVDAYJVKEoYFDBIpVIb4ysMIgoPHOgoRFhGAVwKsLAFzQHACBVCVhQA/KpawBCJa76IhRWDVxIODAwTaFAocP///dhALGBQYJBCIYQBDYgKEBBAEDVgeIAgKgFBYZVEEYY+CH4YDBBgYFBBYoFEOYhmEDYgFFLIwEDKw2AKwhTFBoSsHIgglFAQo/HKIoDECBBZGc46eEAYa2EKox2Ga5LjLDoq8FKAgVDBAv/EghWGVgRWJKoaOFD4IgCViAWFVjKTGJIZOFKpKOHAQj3JAogCFPApcGKQziGLopKCU4hWFKojsEHYrXFCAJFId45CEDYh4EB4Y1DCYSzFJQT+FgAGCKooA/AAZMBfopWDKv5WLVgxT/AB+AKopW/ACBU/ABwA==")) } } - + +else if (img == "apetureLaboratoriesLight"){ + return { + width : 173, height : 43, bpp : 4, + transparent : 1, + buffer : require("heatshrink").decompress(atob("iIAGxAADwINHAH5ULK34APjABBKwpeBJX5VLJgJWGAwKv/ABL8EKomBBIYA/KpJWHAoRW/KpZQCfwJSCAgRW/KphWFBgZW/KphNCAgSxEKP4ADJAatFKwWBL4oA/KpALGXQhS/Ko4MIwIOMAHREOKv5ZVVgcRiEAgALDAwQABgIIHCQYHMDQQYBDwQEGDIoaGTx4MCwIiCJgYhFBIYIHLw4HFBARjGESJUDehZVFVhJNLRI5VGDIIdEAgwiLgLzDJAJVJB4IMBCoKsHAYpFCDgr2IApYEIBpJFCKpqsCHgQbFIhBVHBhJoGTwyBRKp5mBDoY6GKoYqEXYg7JApKeHQJysEKpRmBDoasHQBAACM4qMGEAr0JAgZjGFYhVPiOBEIpVEAAaAEA4oyEW4qyKFZBoFKoisDJIJWLfIp3IQBJeJfgysMERpVCwMYVpijFBA6ZJdA4JHJYgEKQIx1EVgRVBVhj5IEIyZHHYoUGNw4MCQIwIKAARVDxBVRQo6ZJHZZoGU4yBGBAiBGVgRZBVhYlIfJBoFHZZoHfJRwGBAQrEVISvCKpwrEUZAqFVhzYKB4yKGQIpVDAYJVKEoYFDBIpVIb4ysMIgoPHOgoRFjGBVwKsLAFzQHACBVCVhQA/KpawBCJa76IhRWDVxIODAwTaFAocQgEAdhALGBQYJBCIYQBDYgKEBBAEDVgeIAgKgFBYZVEEYY+CH4YDBBgYFBBYoFEOYhmEDYgFFLIwEDKw2BKwhTFBoSsHIgglFAQo/HKIoDECBBZGc46eEAYa2EKox2Ga5LjLDoq8FKAgVDBAsAEghWGVgRWJKoaOFD4IgCViAWFVjKTGJIZOFKpKOHAQj3JAogCFPApcGKQziGLopKCU4hWFKojsEHYrXFCAJFId45CEDYh4EB4Y1DCYSzFJQT+FiIGCKooA/AAZMBfopWDKv5WLVgxT/AB+BKopW/ACBU/ABsQA=")) +} + } + else if (img == "apetureWatch"){ return { width : 176, height : 176, bpp : 4, @@ -104,13 +112,22 @@ function getImg(img){ buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vQgAAHgMQBRAAKgMRCqgrJhGIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7Uv///+RX/K6ZWBAAJXDAA3/+Pd6IMIAG0YxADBj5XD+ISIBwRX/K4pWDAAIMCXQQABl4LC7vQbabxLiIVUFZMIxBJBK4siK4wLDK/5XSBYhX/K6MvBIQDBK/5XD+RXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+SuEK4yuCK/5XHWAZOCK4cvKwhX/K45MFK4YAGK/5XGLApX/K6X/K5svK/5XIWAZXJ/5X/K6svK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/yK44GDVwRX/K50fWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYXyK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UvK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYE+JXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5Xr+RX/K/5Xu/5X/K/5WKAAJXfl5XB+RX/K6ywFK9XxK4XwK7xWCK58vK7sP/5XDGoJXw/5Xc//4xBXEHIKyPK5/yK5svK7kPxAyBK4oHBK7xOFK5AQBK7UP/GPD4JWCiMfK4IJBK7iuFK4QAFj5XC6IMHACH4VooADK4QKHACEYK4QSOK7ilBJYcc5kM5gMCdQRXaOZK3FkRXC6DbTAAf4UYInB5gABK4PM4KBD+AcLFZUIK4JNGkRXIAAJXYh6GDKwRXDLASwCK7HyK9auDjhXH5iwPK5hMIK8iuBKwhXFLAJX/AA0PxCuBKAhXG4KwCK/6uEx/xK5qwNK/KuBjhXL5kRWAJXrABUhiQMKK4RPFK4/BK4PyFaxXql+I+JXPiP//5X/K4WP+McJ4roBLAxX/K5vAAQhX/ABBDBiJXFVgawFiMf//yK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrO///iMcVRC0FiMf//yQaZXZlABCFZ0v//xK4qrCVwpXB/+PbahX15kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwQrQ///K58f/HyK94rSK4UcK5kRj+IK8I1BADhXE+KwGK4vBiP4x5XhEJQASl4DDWARXMj/4NwZX/WAkcK5TiBxA0Dby5XrWAJYEK4kRVwOPGgY4TFwhXol6wCiJXH4KuCSwhX/WAxYDK4RWBVwxX/WBERjhXCAoKuHK/6wGxGBKQQADBIKuFK/6wGxBOBKocf//4x6uFK/4HG/BXB+KtDA4JWGK/4AGU4RXDKwQwHK/4JH/6vEVo5X/BZRXDFpRX/ABEhK4QOKK/5X/K8BYCBpZX/K/5XVfYQAWK6gedK/5XiBhchiINLK6gJIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xv/4AYV/4AXK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6v/ADCv/ABMhiKv/K/5X/K/5X/K/5X/K/5X6/4AdiIAYFzwA=")) } } + + else if (img == "apetureWatchLight"){ + return { + width : 176, height : 176, bpp : 4, + transparent : 2, + buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+gAA/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vf/4AH+MfBRAAK+MRCqgrJ/GIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7UggEAgRX/K6ZWBAAJXDAA0AgPd6IMIAG0YxADBiBXDgISIBwRX/K4pWDAAIMCXQQABkALC7vfbabxLiIVUFZP4xBJBK4siK4wLDK/5XSBYhX/K6MgBIQDBK/5XDgRXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XFgSuEK4yuCK/5XHWAZOCK4cgKwhX/K45MFK4YAGK/5XGLApX/K6UAK5sgK/5XIWAZXJgBX/K6sgK/5XPAoauDK/5XJgBXDiBeEVwRX/K5y2FVwRX/K48CK44GDVwRX/K50QWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYUCK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UgK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYEgJXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5XrgRX/K/5XugBX/K/5WKAAJXfkBXBgRXvgJXCh5XhWApXoF4KvD+EALKBXMKwRXPkBXcgAUCK4QFB+BYPK78AK7ZWBGYJXExBYQK58CK5sgK7fwJ4JQBK4pYCK7pOFK5AQBK7UP/GPAgJWCiMfK4IJBWBpXOVwpXCAAsQK4XRBg4APgAwBVogADK4XwgInWjBXCCRxXbiD9BKwcc5kM5gNCS4XwK7JyJW4siK4XfbaZGD/CjBE4PMAAJXB5nBiIaC+AdLFZTWBgBNGkRXIAAJXYh6uDKwRXDLAQRDK68CK9SuEjhXH5iwPK5hMIK8UP/APBKwhXFLAKwNK/OIVwJQEK43BDgRX/AAXw/GP+JXNWAXwK/5XDVwMcK5fMiIdBK9YAKkMSBZMPK4RPFK4/BJIUCFagAJK8WI+JXPiJX/K4mP+McJ4sAgBYGK/5XN4ACEK/4AHkBDBiJXFVgawFiMf//wK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrNkH//8RjiqIWgsRj//+CDTK7MoAIQrOh//+JXFVYSuFK4P/x8CK/5XJ5kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwRXR/5XPj/4/5XvFaMgK4UcK5kRj+I+ArVK5UAADpXE+KwGK4vBiP4x5XhaBIATkADCh6wCK5kf/H/GpRX7+McK5UR/+IK4beWK9MgK4KwBLAhXEiKuBx/wCwQ4TFwZXoWAkRK4/BVwxX/WA5YDK4RWBVwxX/K4ywBiMcK4QFBVwZX/FA8AK4OIwJSCAAYJBVwIzEK/4ADh5NBJwJVDj///GP/4yFK/4GEJwJXB+KtDA4P/+ATFK/4AEgCnCK4ZWDGIxX/LA//V4hWIK/5YIgBXD+EAF5BX/ABEBK4QtKK/4AIkJXCBxRX/LBYNLK/5X/K6r7CACxXUDzpX/K8QMLkMRBpZXUBJBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K98AADCv/AC5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5XVgAAYV/4AJkMRV/5X/K/5X/K/5X/K/5X/K/UAADsRADAueA==")) + } + } } function drawStart(){ g.clear(); g.reset(); - apSciLab = getImg("apetureLaboratories"); + if (g.theme.dark){apSciLab = getImg("apetureLaboratories");} + else {apSciLab = getImg("apetureLaboratoriesLight");} g.drawImage(apSciLab, xyCenter-apSciLab.width/2, xyCenter-apSciLab.height/2); } @@ -156,9 +173,9 @@ function draw() { var da = d.toString().split(" "); g.reset(); // default draw styles - //draw watchface - apSciWatch = getImg("apetureWatch"); + if (g.theme.dark){apSciWatch = getImg("apetureWatch");} + else {apSciWatch = getImg("apetureWatchLight");} g.drawImage(apSciWatch, xyCenter-apSciWatch.width/2, xyCenter-apSciWatch.height/2); // drawSting centered From b8985e4b9996e45ff05a1276c46ee395bc78c68e Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 8 Jan 2022 12:03:21 -0800 Subject: [PATCH 046/447] Update ChangeLog --- apps/aptsciclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog index 61e8307b8..719f1d418 100644 --- a/apps/aptsciclk/ChangeLog +++ b/apps/aptsciclk/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Icons, loading screen 0.03: Random icon, Shorter "loading" screen +0.04: Support for light and dark Themes From 52a97bb7dcfddfbb0d0a99353f6a5f3dc217e5c9 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 8 Jan 2022 12:04:14 -0800 Subject: [PATCH 047/447] Update apps.json --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 1dbb784bf..b95ff9d8e 100644 --- a/apps.json +++ b/apps.json @@ -1,8 +1,8 @@ [ { "id": "aptsciclk", - "name": "Apeture Science Clock", - "version": "0.03", + "name": "Apeture Sci Clock", + "version": "0.04", "description": "A clock based on the portal series", "icon": "app.png", "type": "clock", From 4dbec88b7f1e4bb741916fbaeb3c156b2c95fd08 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Tue, 14 Dec 2021 21:42:58 +0100 Subject: [PATCH 048/447] Port banglerun to new typescript system --- apps/banglerun/README.md | 19 +------------------ apps/banglerun/{src => }/activity.ts | 0 apps/banglerun/{src => }/app.ts | 0 apps/banglerun/{src => }/display.ts | 0 apps/banglerun/{src => }/gps.ts | 0 apps/banglerun/{src => }/hrm.ts | 0 apps/banglerun/{src => }/log.ts | 8 +++++--- apps/banglerun/package.json | 27 --------------------------- apps/banglerun/{src => }/state.ts | 18 +++++++++++++----- apps/banglerun/{src => }/step.ts | 0 apps/banglerun/tsconfig.json | 10 ---------- apps/banglerun/tsconfig.spec.json | 10 ---------- typescript/tsconfig.json | 4 ++-- 13 files changed, 21 insertions(+), 75 deletions(-) rename apps/banglerun/{src => }/activity.ts (100%) rename apps/banglerun/{src => }/app.ts (100%) rename apps/banglerun/{src => }/display.ts (100%) rename apps/banglerun/{src => }/gps.ts (100%) rename apps/banglerun/{src => }/hrm.ts (100%) rename apps/banglerun/{src => }/log.ts (80%) delete mode 100644 apps/banglerun/package.json rename apps/banglerun/{src => }/state.ts (80%) rename apps/banglerun/{src => }/step.ts (100%) delete mode 100644 apps/banglerun/tsconfig.json delete mode 100644 apps/banglerun/tsconfig.spec.json diff --git a/apps/banglerun/README.md b/apps/banglerun/README.md index 80e984bfa..99fbaaf1a 100644 --- a/apps/banglerun/README.md +++ b/apps/banglerun/README.md @@ -5,21 +5,4 @@ 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. +run on the BangleJS. See ../../typescript/README.md for instructions. diff --git a/apps/banglerun/src/activity.ts b/apps/banglerun/activity.ts similarity index 100% rename from apps/banglerun/src/activity.ts rename to apps/banglerun/activity.ts diff --git a/apps/banglerun/src/app.ts b/apps/banglerun/app.ts similarity index 100% rename from apps/banglerun/src/app.ts rename to apps/banglerun/app.ts diff --git a/apps/banglerun/src/display.ts b/apps/banglerun/display.ts similarity index 100% rename from apps/banglerun/src/display.ts rename to apps/banglerun/display.ts diff --git a/apps/banglerun/src/gps.ts b/apps/banglerun/gps.ts similarity index 100% rename from apps/banglerun/src/gps.ts rename to apps/banglerun/gps.ts diff --git a/apps/banglerun/src/hrm.ts b/apps/banglerun/hrm.ts similarity index 100% rename from apps/banglerun/src/hrm.ts rename to apps/banglerun/hrm.ts diff --git a/apps/banglerun/src/log.ts b/apps/banglerun/log.ts similarity index 80% rename from apps/banglerun/src/log.ts rename to apps/banglerun/log.ts index b6714e407..282115e1a 100644 --- a/apps/banglerun/src/log.ts +++ b/apps/banglerun/log.ts @@ -1,17 +1,19 @@ -import { AppState } from './state'; +import { AppState, AppStateWithLog } from './state'; declare var require: any; -function initLog(state: AppState): void { +function initLog(state: AppState): AppStateWithLog { 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 = state; state.file = require('Storage').open(filename, 'w'); state.fileWritten = false; + return state; } -function updateLog(state: AppState): void { +function updateLog(state: AppStateWithLog): void { if (!state.fileWritten) { state.file.write([ 'timestamp', 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/src/state.ts b/apps/banglerun/state.ts similarity index 80% rename from apps/banglerun/src/state.ts rename to apps/banglerun/state.ts index 14ef2dc5d..1ba9bca26 100644 --- a/apps/banglerun/src/state.ts +++ b/apps/banglerun/state.ts @@ -4,7 +4,7 @@ enum ActivityStatus { Running = 'RUN', } -interface AppState { +interface BasicAppState { // GPS NMEA data fix: number; lat: number; @@ -28,14 +28,12 @@ interface AppState { hrError: number, // Logger data - file: File; fileWritten: boolean; // Drawing data drawing: boolean; // Activity data - status: ActivityStatus; duration: number; distance: number; speed: number; @@ -43,6 +41,17 @@ interface AppState { cadence: number; } +interface AppStateWithoutLog extends BasicAppState { + status: 'STOP'; +} + +interface AppStateWithLog extends BasicAppState { + file: File; + status: ActivityStatus; +} + +type AppState = AppStateWithLog | AppStateWithoutLog; + interface File { read: Function; write: Function; @@ -68,7 +77,6 @@ function initState(): AppState { hr: 60, hrError: 100, - file: null, fileWritten: false, drawing: false, @@ -82,4 +90,4 @@ function initState(): AppState { } } -export { ActivityStatus, AppState, File, initState }; +export { ActivityStatus, AppState, AppStateWithLog, File, initState }; diff --git a/apps/banglerun/src/step.ts b/apps/banglerun/step.ts similarity index 100% rename from apps/banglerun/src/step.ts rename to apps/banglerun/step.ts 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/typescript/tsconfig.json b/typescript/tsconfig.json index 40537c680..e9327be68 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -14,6 +14,6 @@ "strict": true }, "include": ["../apps/**/*", "./**/*"], - // these apps have been excluded because they were built before this configuration was created and are using their own - "exclude": ["../apps/banglerun", "../apps/hebrew_calendar"] + // this app is excluded because it was built before this configuration was created and is using its own + "exclude": ["../apps/hebrew_calendar"] } From 7b37391553c654f03a29a95f4f29b9c1849a3925 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 20:58:26 +0100 Subject: [PATCH 049/447] remove unused files from /banglerun, replace banglerun js code with newly compiled code --- apps/banglerun/.gitignore | 1 - apps/banglerun/README.md | 8 --- apps/banglerun/activity.js | 35 ++++++++++++ apps/banglerun/app.js | 14 ++++- apps/banglerun/display.js | 95 +++++++++++++++++++++++++++++++++ apps/banglerun/gps.js | 66 +++++++++++++++++++++++ apps/banglerun/hrm.js | 15 ++++++ apps/banglerun/jasmine.json | 6 --- apps/banglerun/log.js | 36 +++++++++++++ apps/banglerun/rollup.config.js | 15 ------ apps/banglerun/state.js | 33 ++++++++++++ apps/banglerun/step.js | 10 ++++ typescript/tsconfig.json | 4 +- 13 files changed, 304 insertions(+), 34 deletions(-) delete mode 100644 apps/banglerun/.gitignore delete mode 100644 apps/banglerun/README.md create mode 100644 apps/banglerun/activity.js create mode 100644 apps/banglerun/display.js create mode 100644 apps/banglerun/gps.js create mode 100644 apps/banglerun/hrm.js delete mode 100644 apps/banglerun/jasmine.json create mode 100644 apps/banglerun/log.js delete mode 100644 apps/banglerun/rollup.config.js create mode 100644 apps/banglerun/state.js create mode 100644 apps/banglerun/step.js 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/README.md b/apps/banglerun/README.md deleted file mode 100644 index 99fbaaf1a..000000000 --- a/apps/banglerun/README.md +++ /dev/null @@ -1,8 +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. See ../../typescript/README.md for instructions. diff --git a/apps/banglerun/activity.js b/apps/banglerun/activity.js new file mode 100644 index 000000000..818f9cf2a --- /dev/null +++ b/apps/banglerun/activity.js @@ -0,0 +1,35 @@ +import { draw } from './display'; +import { initLog } from './log'; +import { ActivityStatus } from './state'; +function startActivity(state) { + 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) { + 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) { + state.duration = 0; + state.distance = 0; + state.speed = 0; + state.steps = 0; + state.cadence = 0; +} +export { clearActivity, startActivity, stopActivity }; diff --git a/apps/banglerun/app.js b/apps/banglerun/app.js index b79255171..af5413cc0 100644 --- a/apps/banglerun/app.js +++ b/apps/banglerun/app.js @@ -1 +1,13 @@ -!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"})}(); +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'; +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/display.js b/apps/banglerun/display.js new file mode 100644 index 000000000..2768e8973 --- /dev/null +++ b/apps/banglerun/display.js @@ -0,0 +1,95 @@ +import { ActivityStatus } from './state'; +const STATUS_COLORS = { + 'STOP': 0xF800, + 'PAUSE': 0xFFE0, + 'RUN': 0x07E0, +}; +function initDisplay(state) { + Bangle.loadWidgets(); + Bangle.on('lcdPower', (on) => { + state.drawing = on; + if (on) { + drawAll(state); + } + }); + drawAll(state); +} +function drawBackground() { + 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, x, y) { + g.setColor(0x0000); + g.fillRect(x - 60, y, x + 60, y + 30); + g.setColor(0xFFFF); + g.drawString(value, x, y); +} +function draw(state) { + 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) { + drawBackground(); + draw(state); + Bangle.drawWidgets(); +} +function formatClock(date) { + return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2); +} +function formatDistance(meters) { + return (meters / 1000).toFixed(2); +} +function formatPace(speed) { + 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) { + 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/gps.js b/apps/banglerun/gps.js new file mode 100644 index 000000000..d06215cd5 --- /dev/null +++ b/apps/banglerun/gps.js @@ -0,0 +1,66 @@ +import { draw } from './display'; +import { updateLog } from './log'; +import { ActivityStatus } from './state'; +const EARTH_RADIUS = 6371008.8; +function initGps(state) { + Bangle.on('GPS', (gps) => readGps(state, gps)); + Bangle.setGPSPower(1); +} +function readGps(state, gps) { + 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) { + 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/hrm.js b/apps/banglerun/hrm.js new file mode 100644 index 000000000..35804f5e8 --- /dev/null +++ b/apps/banglerun/hrm.js @@ -0,0 +1,15 @@ +function initHrm(state) { + Bangle.on('HRM', (hrm) => updateHrm(state, hrm)); + Bangle.setHRMPower(1); +} +function updateHrm(state, hrm) { + 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/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/log.js b/apps/banglerun/log.js new file mode 100644 index 000000000..b11409de6 --- /dev/null +++ b/apps/banglerun/log.js @@ -0,0 +1,36 @@ +function initLog(state) { + 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 = state; + state.file = require('Storage').open(filename, 'w'); + state.fileWritten = false; + return state; +} +function updateLog(state) { + 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/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/state.js b/apps/banglerun/state.js new file mode 100644 index 000000000..8629d69a7 --- /dev/null +++ b/apps/banglerun/state.js @@ -0,0 +1,33 @@ +var ActivityStatus; +(function (ActivityStatus) { + ActivityStatus["Stopped"] = "STOP"; + ActivityStatus["Paused"] = "PAUSE"; + ActivityStatus["Running"] = "RUN"; +})(ActivityStatus || (ActivityStatus = {})); +function initState() { + 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, + fileWritten: false, + drawing: false, + status: ActivityStatus.Stopped, + duration: 0, + distance: 0, + speed: 0, + steps: 0, + cadence: 0, + }; +} +export { ActivityStatus, initState }; diff --git a/apps/banglerun/step.js b/apps/banglerun/step.js new file mode 100644 index 000000000..b258a853d --- /dev/null +++ b/apps/banglerun/step.js @@ -0,0 +1,10 @@ +import { ActivityStatus } from './state'; +function initStep(state) { + Bangle.on('step', () => updateStep(state)); +} +function updateStep(state) { + if (state.status === ActivityStatus.Running) { + state.steps += 1; + } +} +export { initStep, updateStep }; diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index e9327be68..7def102b7 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -13,7 +13,5 @@ "noUnusedParameters": true, "strict": true }, - "include": ["../apps/**/*", "./**/*"], - // this app is excluded because it was built before this configuration was created and is using its own - "exclude": ["../apps/hebrew_calendar"] + "include": ["../apps/**/*", "./**/*"], } From 643c304a1ee4ad4d0c196f3467811e279b8356f9 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:00:04 +0100 Subject: [PATCH 050/447] trigger github actions on PR as well --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index c268c884c..0c256c97b 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -1,6 +1,6 @@ name: Node CI -on: [push] +on: [push, pull_request] jobs: build: From da0e2a79096e1898d9da29cd3300f424196e9dae Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:04:42 +0100 Subject: [PATCH 051/447] Update metadata.json --- apps/widChargingStatus/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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", From 4727652627ce864ea6148cae87002847fd2c43dd Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:09:57 +0100 Subject: [PATCH 052/447] rename build step to be less confusing for widgets --- .github/workflows/nodejs.yml | 4 ++-- typescript/README.md | 8 ++++---- typescript/package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 0c256c97b..bb27b367e 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -22,6 +22,6 @@ jobs: - name: build types working-directory: ./typescript run: npm run build:types - - name: build all TS apps + - name: build all TS apps and widgets working-directory: ./typescript - run: npm run build:apps + run: npm run build diff --git a/typescript/README.md b/typescript/README.md index d1f60fd0b..13800aeec 100644 --- a/typescript/README.md +++ b/typescript/README.md @@ -11,8 +11,8 @@ The typing is an ongoing process. If anything is still missing, you can add it! ## Compilation -Install [npm](https://www.npmjs.com/get-npm) if you haven't already. -Make sure you are using version ^8 by running `npm -v`. If the version is incorrect, run `npm i -g npm@^8`. +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: @@ -23,7 +23,7 @@ npm ci to install the project's build tools, and: ``` -npm run build:apps +npm run build ``` -To build all Typescript apps. The last command will generate the `app.js` files containing the transpiled code for the BangleJS. +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.json b/typescript/package.json index 4bfb88d27..8cd38ce63 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -7,7 +7,7 @@ "typescript": "4.5.2" }, "scripts": { - "build:apps": "tsc", + "build": "tsc", "build:types": "tsc ./types/globals.d.ts" } } From ebbbf696701c01af8f31992d2e97862d4fcaa5b4 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:23:17 +0100 Subject: [PATCH 053/447] adjust module target version during build --- apps/banglerun/activity.js | 35 ++++++++++++++++++++--------------- apps/banglerun/app.js | 28 +++++++++++++++------------- apps/banglerun/display.js | 19 +++++++++++++++---- apps/banglerun/gps.js | 23 ++++++++++++++--------- apps/banglerun/hrm.js | 6 +++++- apps/banglerun/log.js | 6 +++++- apps/banglerun/state.js | 6 +++++- apps/banglerun/step.js | 10 +++++++--- typescript/tsconfig.json | 4 ++-- 9 files changed, 88 insertions(+), 49 deletions(-) diff --git a/apps/banglerun/activity.js b/apps/banglerun/activity.js index 818f9cf2a..94512094c 100644 --- a/apps/banglerun/activity.js +++ b/apps/banglerun/activity.js @@ -1,30 +1,35 @@ -import { draw } from './display'; -import { initLog } from './log'; -import { ActivityStatus } from './state'; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.stopActivity = exports.startActivity = exports.clearActivity = void 0; +const display_1 = require("./display"); +const log_1 = require("./log"); +const state_1 = require("./state"); function startActivity(state) { - if (state.status === ActivityStatus.Stopped) { - initLog(state); + if (state.status === state_1.ActivityStatus.Stopped) { + (0, log_1.initLog)(state); } - if (state.status === ActivityStatus.Running) { - state.status = ActivityStatus.Paused; + if (state.status === state_1.ActivityStatus.Running) { + state.status = state_1.ActivityStatus.Paused; } else { - state.status = ActivityStatus.Running; + state.status = state_1.ActivityStatus.Running; } - draw(state); + (0, display_1.draw)(state); } +exports.startActivity = startActivity; function stopActivity(state) { - if (state.status === ActivityStatus.Paused) { + if (state.status === state_1.ActivityStatus.Paused) { clearActivity(state); } - if (state.status === ActivityStatus.Running) { - state.status = ActivityStatus.Paused; + if (state.status === state_1.ActivityStatus.Running) { + state.status = state_1.ActivityStatus.Paused; } else { - state.status = ActivityStatus.Stopped; + state.status = state_1.ActivityStatus.Stopped; } - draw(state); + (0, display_1.draw)(state); } +exports.stopActivity = stopActivity; function clearActivity(state) { state.duration = 0; state.distance = 0; @@ -32,4 +37,4 @@ function clearActivity(state) { state.steps = 0; state.cadence = 0; } -export { clearActivity, startActivity, stopActivity }; +exports.clearActivity = clearActivity; diff --git a/apps/banglerun/app.js b/apps/banglerun/app.js index af5413cc0..84d03820a 100644 --- a/apps/banglerun/app.js +++ b/apps/banglerun/app.js @@ -1,13 +1,15 @@ -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'; -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' }); +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const activity_1 = require("./activity"); +const display_1 = require("./display"); +const gps_1 = require("./gps"); +const hrm_1 = require("./hrm"); +const state_1 = require("./state"); +const step_1 = require("./step"); +const appState = (0, state_1.initState)(); +(0, gps_1.initGps)(appState); +(0, hrm_1.initHrm)(appState); +(0, step_1.initStep)(appState); +(0, display_1.initDisplay)(appState); +setWatch(() => (0, activity_1.startActivity)(appState), BTN1, { repeat: true, edge: 'falling' }); +setWatch(() => (0, activity_1.stopActivity)(appState), BTN3, { repeat: true, edge: 'falling' }); diff --git a/apps/banglerun/display.js b/apps/banglerun/display.js index 2768e8973..648482676 100644 --- a/apps/banglerun/display.js +++ b/apps/banglerun/display.js @@ -1,4 +1,7 @@ -import { ActivityStatus } from './state'; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.initDisplay = exports.formatTime = exports.formatPace = exports.formatDistance = exports.formatClock = exports.drawValue = exports.drawBackground = exports.drawAll = exports.draw = void 0; +const state_1 = require("./state"); const STATUS_COLORS = { 'STOP': 0xF800, 'PAUSE': 0xFFE0, @@ -14,6 +17,7 @@ function initDisplay(state) { }); drawAll(state); } +exports.initDisplay = initDisplay; function drawBackground() { g.clear(); g.setColor(0xC618); @@ -26,12 +30,14 @@ function drawBackground() { g.drawString('STEPS', 60, 152); g.drawString('CADENCE', 172, 152); } +exports.drawBackground = drawBackground; function drawValue(value, x, y) { g.setColor(0x0000); g.fillRect(x - 60, y, x + 60, y + 30); g.setColor(0xFFFF); g.drawString(value, x, y); } +exports.drawValue = drawValue; function draw(state) { g.setFontVector(30); g.setFontAlign(0, -1, 0); @@ -55,27 +61,31 @@ function draw(state) { g.setColor(0x0000); g.drawString(state.status, 200, 220); g.setFont("6x8").setFontAlign(0, 0, 1).setColor(-1); - if (state.status === ActivityStatus.Paused) { + if (state.status === state_1.ActivityStatus.Paused) { g.drawString("START", 236, 60, 1).drawString(" CLEAR ", 236, 180, 1); } - else if (state.status === ActivityStatus.Running) { + else if (state.status === state_1.ActivityStatus.Running) { g.drawString(" PAUSE ", 236, 60, 1).drawString(" PAUSE ", 236, 180, 1); } else { g.drawString("START", 236, 60, 1).drawString(" ", 236, 180, 1); } } +exports.draw = draw; function drawAll(state) { drawBackground(); draw(state); Bangle.drawWidgets(); } +exports.drawAll = drawAll; function formatClock(date) { return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2); } +exports.formatClock = formatClock; function formatDistance(meters) { return (meters / 1000).toFixed(2); } +exports.formatDistance = formatDistance; function formatPace(speed) { if (speed < 0.1667) { return `__'__"`; @@ -85,6 +95,7 @@ function formatPace(speed) { const sec = pace % 60; return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`; } +exports.formatPace = formatPace; function formatTime(time) { const seconds = Math.round(time); const hrs = Math.floor(seconds / 3600); @@ -92,4 +103,4 @@ function formatTime(time) { 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, }; +exports.formatTime = formatTime; diff --git a/apps/banglerun/gps.js b/apps/banglerun/gps.js index d06215cd5..35e0f8769 100644 --- a/apps/banglerun/gps.js +++ b/apps/banglerun/gps.js @@ -1,11 +1,15 @@ -import { draw } from './display'; -import { updateLog } from './log'; -import { ActivityStatus } from './state'; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.updateGps = exports.readGps = exports.initGps = void 0; +const display_1 = require("./display"); +const log_1 = require("./log"); +const state_1 = require("./state"); const EARTH_RADIUS = 6371008.8; function initGps(state) { Bangle.on('GPS', (gps) => readGps(state, gps)); Bangle.setGPSPower(1); } +exports.initGps = initGps; function readGps(state, gps) { state.lat = gps.lat; state.lon = gps.lon; @@ -15,16 +19,17 @@ function readGps(state, gps) { state.dop = gps.hdop; state.gpsValid = state.fix > 0; updateGps(state); - draw(state); + (0, display_1.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.status === state_1.ActivityStatus.Running && state.timeSinceLog > 5) { state.timeSinceLog = 0; - updateLog(state); + (0, log_1.updateLog)(state); } } +exports.readGps = readGps; function updateGps(state) { const t = Date.now(); let dt = (t - state.t) / 1000; @@ -32,7 +37,7 @@ function updateGps(state) { dt = 0; state.t = t; state.timeSinceLog += dt; - if (state.status === ActivityStatus.Running) { + if (state.status === state_1.ActivityStatus.Running) { state.duration += dt; } if (!state.gpsValid) { @@ -57,10 +62,10 @@ function updateGps(state) { state.x = x; state.y = y; state.z = z; - if (state.status === ActivityStatus.Running) { + if (state.status === state_1.ActivityStatus.Running) { state.distance += dpMag; state.speed = (state.distance / state.duration) || 0; state.cadence = (60 * state.steps / state.duration) || 0; } } -export { initGps, readGps, updateGps }; +exports.updateGps = updateGps; diff --git a/apps/banglerun/hrm.js b/apps/banglerun/hrm.js index 35804f5e8..c002de2f6 100644 --- a/apps/banglerun/hrm.js +++ b/apps/banglerun/hrm.js @@ -1,7 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.updateHrm = exports.initHrm = void 0; function initHrm(state) { Bangle.on('HRM', (hrm) => updateHrm(state, hrm)); Bangle.setHRMPower(1); } +exports.initHrm = initHrm; function updateHrm(state, hrm) { if (hrm.confidence === 0) { return; @@ -12,4 +16,4 @@ function updateHrm(state, hrm) { state.hr += dHr * hrGain; state.hrError += (hrError - state.hrError) * hrGain; } -export { initHrm, updateHrm }; +exports.updateHrm = updateHrm; diff --git a/apps/banglerun/log.js b/apps/banglerun/log.js index b11409de6..ee2af3091 100644 --- a/apps/banglerun/log.js +++ b/apps/banglerun/log.js @@ -1,3 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.updateLog = exports.initLog = void 0; function initLog(state) { const datetime = new Date().toISOString().replace(/[-:]/g, ''); const date = datetime.substr(2, 6); @@ -8,6 +11,7 @@ function initLog(state) { state.fileWritten = false; return state; } +exports.initLog = initLog; function updateLog(state) { if (!state.fileWritten) { state.file.write([ @@ -33,4 +37,4 @@ function updateLog(state) { state.steps.toFixed(0), ].join(',') + '\n'); } -export { initLog, updateLog }; +exports.updateLog = updateLog; diff --git a/apps/banglerun/state.js b/apps/banglerun/state.js index 8629d69a7..349ef1954 100644 --- a/apps/banglerun/state.js +++ b/apps/banglerun/state.js @@ -1,9 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.initState = exports.ActivityStatus = void 0; var ActivityStatus; (function (ActivityStatus) { ActivityStatus["Stopped"] = "STOP"; ActivityStatus["Paused"] = "PAUSE"; ActivityStatus["Running"] = "RUN"; })(ActivityStatus || (ActivityStatus = {})); +exports.ActivityStatus = ActivityStatus; function initState() { return { fix: NaN, @@ -30,4 +34,4 @@ function initState() { cadence: 0, }; } -export { ActivityStatus, initState }; +exports.initState = initState; diff --git a/apps/banglerun/step.js b/apps/banglerun/step.js index b258a853d..e4acfd66a 100644 --- a/apps/banglerun/step.js +++ b/apps/banglerun/step.js @@ -1,10 +1,14 @@ -import { ActivityStatus } from './state'; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.updateStep = exports.initStep = void 0; +const state_1 = require("./state"); function initStep(state) { Bangle.on('step', () => updateStep(state)); } +exports.initStep = initStep; function updateStep(state) { - if (state.status === ActivityStatus.Running) { + if (state.status === state_1.ActivityStatus.Running) { state.steps += 1; } } -export { initStep, updateStep }; +exports.updateStep = updateStep; diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json index 7def102b7..d36465a01 100644 --- a/typescript/tsconfig.json +++ b/typescript/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "module": "es2015", + "module": "commonjs", "noImplicitAny": true, - "target": "es2015", + "target": "es6", "allowUnreachableCode": false, "allowUnusedLabels": false, "noImplicitOverride": true, From 2faa870e7e7dd87f44c7ae9162b4f5e889c40d47 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:30:44 +0100 Subject: [PATCH 054/447] adjust banglerun/app.ts to not do some stupid self assign logic --- apps/banglerun/log.js | 5 +--- apps/banglerun/log.ts | 53 +++++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/apps/banglerun/log.js b/apps/banglerun/log.js index ee2af3091..0cdeaa964 100644 --- a/apps/banglerun/log.js +++ b/apps/banglerun/log.js @@ -6,10 +6,7 @@ function initLog(state) { const date = datetime.substr(2, 6); const time = datetime.substr(9, 6); const filename = `banglerun_${date}_${time}`; - state = state; - state.file = require('Storage').open(filename, 'w'); - state.fileWritten = false; - return state; + return Object.assign(Object.assign({}, state), { file: require('Storage').open(filename, 'w'), fileWritten: false }); } exports.initLog = initLog; function updateLog(state) { diff --git a/apps/banglerun/log.ts b/apps/banglerun/log.ts index 282115e1a..ba1c1f00e 100644 --- a/apps/banglerun/log.ts +++ b/apps/banglerun/log.ts @@ -7,36 +7,41 @@ function initLog(state: AppState): AppStateWithLog { const date = datetime.substr(2, 6); const time = datetime.substr(9, 6); const filename = `banglerun_${date}_${time}`; - state = state; - state.file = require('Storage').open(filename, 'w'); - state.fileWritten = false; - return state; + return { + ...state, + file: require('Storage').open(filename, 'w'), + fileWritten: false, + } as AppStateWithLog; } function updateLog(state: AppStateWithLog): void { if (!state.fileWritten) { - state.file.write([ - 'timestamp', - 'latitude', - 'longitude', - 'altitude', - 'duration', - 'distance', - 'heartrate', - 'steps', - ].join(',') + '\n'); + 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'); + 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 }; From df7c92080fd4de54509924f04d7ab80b64cef112 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:34:28 +0100 Subject: [PATCH 055/447] add steps that travis CI does to the github actions pipeline --- .github/workflows/nodejs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index bb27b367e..08849c073 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -25,3 +25,7 @@ jobs: - name: build all TS apps and widgets working-directory: ./typescript run: npm run build + - name: install testing dependencies + run: npm i + - name: test all apps and widgets + run: npm run test From f869b5373031cbac89b9ec37f8e6573bef125719 Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:41:41 +0100 Subject: [PATCH 056/447] move app testing in front of TS build steps to see if that makes any difference --- .github/workflows/nodejs.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 08849c073..234e3d455 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -16,7 +16,11 @@ jobs: uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - - name: npm ci + - 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 @@ -24,8 +28,4 @@ jobs: run: npm run build:types - name: build all TS apps and widgets working-directory: ./typescript - run: npm run build - - name: install testing dependencies - run: npm i - - name: test all apps and widgets - run: npm run test + run: npm run build \ No newline at end of file From 455c89cbec9e331d37c7f1566eb989bfd673ca5e Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 21:55:20 +0100 Subject: [PATCH 057/447] add some debugging logs as to why the module cant be found in the pipeline, but locally --- .github/workflows/nodejs.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 234e3d455..166700e2f 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -18,6 +18,12 @@ jobs: node-version: ${{ matrix.node-version }} - name: install testing dependencies run: npm i + - name: list content of folders + run: ls -l + - name: list content of folders 2 + run: ls -l ./core + - name: list content of folders 3 + run: ls -l ./core/lib - name: test all apps and widgets run: npm run test - name: install typescript dependencies From 391fbc20950083eb7a11c4f7c474fe5ae65f623b Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 22:01:34 +0100 Subject: [PATCH 058/447] use checkout v2 and import submodules for github actions --- .github/workflows/nodejs.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 166700e2f..fe438bae1 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -11,7 +11,10 @@ jobs: node-version: [16.x] steps: - - uses: actions/checkout@v1 + - 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: From 016a0c89ea5d0208c02b33c0ff8adff10551a4ac Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 22:03:55 +0100 Subject: [PATCH 059/447] fix indenting in github actions yaml --- .github/workflows/nodejs.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index fe438bae1..42aced6a9 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -12,9 +12,9 @@ jobs: steps: - name: Checkout repository and submodules - uses: actions/checkout@v2 - with: - submodules: recursive + uses: actions/checkout@v2 + with: + submodules: recursive - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: From e6d23cbc7e83e9aa61b588c933db21fe7758adee Mon Sep 17 00:00:00 2001 From: Sebastian Di Luzio Date: Thu, 20 Jan 2022 22:05:03 +0100 Subject: [PATCH 060/447] remove unnecessary steps from github actions --- .github/workflows/nodejs.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 42aced6a9..1eb009153 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -21,12 +21,6 @@ jobs: node-version: ${{ matrix.node-version }} - name: install testing dependencies run: npm i - - name: list content of folders - run: ls -l - - name: list content of folders 2 - run: ls -l ./core - - name: list content of folders 3 - run: ls -l ./core/lib - name: test all apps and widgets run: npm run test - name: install typescript dependencies From eaa766f71196ed344ec28aa2c2bc157a41bd8ef0 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:57:34 -0800 Subject: [PATCH 061/447] Fixed small bug Small bugfix where the warning would be in a strange colour as it is monochrome --- apps/aptsciclk/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index b060541b5..6dbad3654 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -144,6 +144,7 @@ var curWarning = Math.floor(Math.random() * (maxWarning+1)); function buttonPressed(){ if (curWarning < maxWarning) curWarning += 1; else curWarning = 0; + g.reset(); buttonImg = getImg("butPress"); g.drawImage(buttonImg, 0, 0); From 95d53fe4ae487a16fa39f4de77d36fd3f178a6fc Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:59:42 -0800 Subject: [PATCH 062/447] Update ChangeLog --- apps/aptsciclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog index 719f1d418..c3d507340 100644 --- a/apps/aptsciclk/ChangeLog +++ b/apps/aptsciclk/ChangeLog @@ -2,3 +2,4 @@ 0.02: Icons, loading screen 0.03: Random icon, Shorter "loading" screen 0.04: Support for light and dark Themes +0.05: Small bugfix From d057b81d7b7b2235a97865f542ef269ae3f14f45 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Mon, 24 Jan 2022 12:00:24 -0800 Subject: [PATCH 063/447] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index b95ff9d8e..1c8e9b078 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "aptsciclk", "name": "Apeture Sci Clock", - "version": "0.04", + "version": "0.05", "description": "A clock based on the portal series", "icon": "app.png", "type": "clock", From 8e10db315e04a45c9fe0db2a145955ca0ddb262f Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 30 Jan 2022 09:47:22 -0800 Subject: [PATCH 064/447] Update ChangeLog --- apps/aptsciclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog index c3d507340..9f09723f4 100644 --- a/apps/aptsciclk/ChangeLog +++ b/apps/aptsciclk/ChangeLog @@ -3,3 +3,4 @@ 0.03: Random icon, Shorter "loading" screen 0.04: Support for light and dark Themes 0.05: Small bugfix +0.06: Formating From f16bc390b6c9c5d22cace47858e2b6ff74ea6ae8 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 30 Jan 2022 09:47:51 -0800 Subject: [PATCH 065/447] Formating --- apps/aptsciclk/app.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index 6dbad3654..ba80a9749 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -6,7 +6,7 @@ const font = "6x8"; const xyCenter = g.getWidth() / 2; const yposTime = xyCenter*0.73; -const yposDate = xyCenter*1.44; +const yposDate = xyCenter*0.48; const yposYear = xyCenter*1.8; const buttonTolerance = 20; @@ -96,20 +96,20 @@ function getImg(img){ buffer : require("heatshrink").decompress(atob("AA+IAAeAIv5UTK34APhABBKwpeBJX5VLJgJWGAwKv/ABL8EKomABIYA/KpJWHAoRW/KpZQCfwJSCAgRW/KphWFBgZW/KphNCAgSxEKP4ADJAatFKwWAL4oA/KpALGXQhS/Ko4MIwAOMAHREOKv5ZVVgcAh///4LDAwQAB+AIHCQYHMDQQYBDwQEGDIoaGTx4MCwAiCJgYhFBIYIHLw4HFBARjGESJUDehZVFVhJNLRI5VGDIIdEAgwiL+DzDJAJVJB4IMBCoKsHAYpFCDgr2IApYEIBpJFCKpqsCHgQbFIhBVHBhJoGTwyBRKp5mBDoY6GKoYqEXYg7JApKeHQJysEKpRmBDoasHQBAACM4qMGEAr0JAgZjGFYhVPgGAEIpVEAAaAEA4oyEW4qyKFZBoFKoisDJIJWLfIp3IQBJeJfgysMERpVCwEIVpijFBA6ZJdA4JHJYgEKQIx1EVgRVBVhj5IEIyZHHYoUGNw4MCQIwIKAARVDxBVRQo6ZJHZZoGU4yBGBAiBGVgRZBVhYlIfJBoFHZZoHfJRwGBAQrEVISvCKpwrEUZAqFVhzYKB4yKGQIpVDAYJVKEoYFDBIpVIb4ysMIgoPHOgoRFhGAVwKsLAFzQHACBVCVhQA/KpawBCJa76IhRWDVxIODAwTaFAocP///dhALGBQYJBCIYQBDYgKEBBAEDVgeIAgKgFBYZVEEYY+CH4YDBBgYFBBYoFEOYhmEDYgFFLIwEDKw2AKwhTFBoSsHIgglFAQo/HKIoDECBBZGc46eEAYa2EKox2Ga5LjLDoq8FKAgVDBAv/EghWGVgRWJKoaOFD4IgCViAWFVjKTGJIZOFKpKOHAQj3JAogCFPApcGKQziGLopKCU4hWFKojsEHYrXFCAJFId45CEDYh4EB4Y1DCYSzFJQT+FgAGCKooA/AAZMBfopWDKv5WLVgxT/AB+AKopW/ACBU/ABwA==")) } } - + else if (img == "apetureLaboratoriesLight"){ return { width : 173, height : 43, bpp : 4, transparent : 1, buffer : require("heatshrink").decompress(atob("iIAGxAADwINHAH5ULK34APjABBKwpeBJX5VLJgJWGAwKv/ABL8EKomBBIYA/KpJWHAoRW/KpZQCfwJSCAgRW/KphWFBgZW/KphNCAgSxEKP4ADJAatFKwWBL4oA/KpALGXQhS/Ko4MIwIOMAHREOKv5ZVVgcRiEAgALDAwQABgIIHCQYHMDQQYBDwQEGDIoaGTx4MCwIiCJgYhFBIYIHLw4HFBARjGESJUDehZVFVhJNLRI5VGDIIdEAgwiLgLzDJAJVJB4IMBCoKsHAYpFCDgr2IApYEIBpJFCKpqsCHgQbFIhBVHBhJoGTwyBRKp5mBDoY6GKoYqEXYg7JApKeHQJysEKpRmBDoasHQBAACM4qMGEAr0JAgZjGFYhVPiOBEIpVEAAaAEA4oyEW4qyKFZBoFKoisDJIJWLfIp3IQBJeJfgysMERpVCwMYVpijFBA6ZJdA4JHJYgEKQIx1EVgRVBVhj5IEIyZHHYoUGNw4MCQIwIKAARVDxBVRQo6ZJHZZoGU4yBGBAiBGVgRZBVhYlIfJBoFHZZoHfJRwGBAQrEVISvCKpwrEUZAqFVhzYKB4yKGQIpVDAYJVKEoYFDBIpVIb4ysMIgoPHOgoRFjGBVwKsLAFzQHACBVCVhQA/KpawBCJa76IhRWDVxIODAwTaFAocQgEAdhALGBQYJBCIYQBDYgKEBBAEDVgeIAgKgFBYZVEEYY+CH4YDBBgYFBBYoFEOYhmEDYgFFLIwEDKw2BKwhTFBoSsHIgglFAQo/HKIoDECBBZGc46eEAYa2EKox2Ga5LjLDoq8FKAgVDBAsAEghWGVgRWJKoaOFD4IgCViAWFVjKTGJIZOFKpKOHAQj3JAogCFPApcGKQziGLopKCU4hWFKojsEHYrXFCAJFId45CEDYh4EB4Y1DCYSzFJQT+FiIGCKooA/AAZMBfopWDKv5WLVgxT/AB+BKopW/ACBU/ABsQA=")) -} + } } - + else if (img == "apetureWatch"){ return { width : 176, height : 176, bpp : 4, transparent : 2, - buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vQgAAHgMQBRAAKgMRCqgrJhGIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7Uv///+RX/K6ZWBAAJXDAA3/+Pd6IMIAG0YxADBj5XD+ISIBwRX/K4pWDAAIMCXQQABl4LC7vQbabxLiIVUFZMIxBJBK4siK4wLDK/5XSBYhX/K6MvBIQDBK/5XD+RXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+SuEK4yuCK/5XHWAZOCK4cvKwhX/K45MFK4YAGK/5XGLApX/K6X/K5svK/5XIWAZXJ/5X/K6svK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/yK44GDVwRX/K50fWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYXyK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UvK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYE+JXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5Xr+RX/K/5Xu/5X/K/5WKAAJXfl5XB+RX/K6ywFK9XxK4XwK7xWCK58vK7sP/5XDGoJXw/5Xc//4xBXEHIKyPK5/yK5svK7kPxAyBK4oHBK7xOFK5AQBK7UP/GPD4JWCiMfK4IJBK7iuFK4QAFj5XC6IMHACH4VooADK4QKHACEYK4QSOK7ilBJYcc5kM5gMCdQRXaOZK3FkRXC6DbTAAf4UYInB5gABK4PM4KBD+AcLFZUIK4JNGkRXIAAJXYh6GDKwRXDLASwCK7HyK9auDjhXH5iwPK5hMIK8iuBKwhXFLAJX/AA0PxCuBKAhXG4KwCK/6uEx/xK5qwNK/KuBjhXL5kRWAJXrABUhiQMKK4RPFK4/BK4PyFaxXql+I+JXPiP//5X/K4WP+McJ4roBLAxX/K5vAAQhX/ABBDBiJXFVgawFiMf//yK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrO///iMcVRC0FiMf//yQaZXZlABCFZ0v//xK4qrCVwpXB/+PbahX15kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwQrQ///K58f/HyK94rSK4UcK5kRj+IK8I1BADhXE+KwGK4vBiP4x5XhEJQASl4DDWARXMj/4NwZX/WAkcK5TiBxA0Dby5XrWAJYEK4kRVwOPGgY4TFwhXol6wCiJXH4KuCSwhX/WAxYDK4RWBVwxX/WBERjhXCAoKuHK/6wGxGBKQQADBIKuFK/6wGxBOBKocf//4x6uFK/4HG/BXB+KtDA4JWGK/4AGU4RXDKwQwHK/4JH/6vEVo5X/BZRXDFpRX/ABEhK4QOKK/5X/K8BYCBpZX/K/5XVfYQAWK6gedK/5XiBhchiINLK6gJIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xv/4AYV/4AXK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6v/ADCv/ABMhiKv/K/5X/K/5X/K/5X/K/5X6/4AdiIAYFzwA=")) + buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vQgAAHgMQBRAAKgMRCqgrJhGIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7Uv///+RX/K6ZWBAAJXDAA3/+Pd6IMIAG0YxADBj5XD+ISIBwRX/K4pWDAAIMCXQQABl4LC7vQbabxLiIVUFZMIxBJBK4siK4wLDK/5XSBYhX/K6MvBIQDBK/5XD+RXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+SuEK4yuCK/5XHWAZOCK4cvKwhX/K45MFK4YAGK/5XGLApX/K6X/K5svK/5XIWAZXJ/5X/K6svK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/yK44GDVwRX/K50fWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYXyK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UvK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYE+JXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5Xr+RX/K/5Xu/5X/K/5WKAAJXfl5XB+RX/K6ywFK9XxK4XwK7xWCK58vK7sP/5XDGoJXw/5Xc//4xBXEHIKyPK5/yK5svK7kPxAyBK4oHBK7xOFK5AQBK7UP/GPD4JWCiMfK4IJBK7iuFK4QAFj5XC6IMHACH4VooADK4QKHACEYK4QSOK7ilBJYcc5kM5gMCdQRXaOZK3FkRXC6DbTAAf4UYInB5gABK4PM4KBD+AcLFZUIK4JNGkRXIAAJXYh6GDKwRXDLASwCK7HyK9auDjhXH5iwPK5hMIK8iuBKwhXFLAJX/AA0PxCuBKAhXG4KwCK/6uEx/xK5qwNK/KuBjhXL5kRWAJXrABUhiQMKK4RPFK4/BK4PyFaxXql+I+JXPiP//5X/K4WP+McJ4roBLAxX/K5vAAQhX/ABBDBiJXFVgawFiMf//yK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrO///iMcVRC0FiMf//yQaZXZlABCFZ0v//xK4qrCVwpXB/+PbahX15kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwQrQ///K58f/HyK94rSK4UcK5kRj+IK8I1BADhXE+KwGK4vBiP4x5XhEJQASl4DDWARXMj/4NwZX/WAkcK5TiBxA0LK/awBLAhXEiKuBx5X/K4svWAURK4/BVwX/ERZX5WAhYDK4RWBVxxX7WAkRjhXCAoKuPK/awCxGBKQQADBIKuNK/iwBxBOBKocf//4x6uNK/gHB/BXB+KtDA4JWOK/siU4RXDKwQwPK/oJB/6vEVp5X/AARXDFqRX/IAJXCESRX/K/5XYLAQiTK/5X/K5r7CAGpX/K+zxMiIiTkMSCqZX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K9//ADA4HV/4APK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6v/ADCv/ABMhiIiTK/5X/K/5X/K/5X/K/5X/K83/ADsRAG4A=")) } } @@ -117,7 +117,7 @@ else if (img == "apetureLaboratoriesLight"){ return { width : 176, height : 176, bpp : 4, transparent : 2, - buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+gAA/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vf/4AH+MfBRAAK+MRCqgrJ/GIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7UggEAgRX/K6ZWBAAJXDAA0AgPd6IMIAG0YxADBiBXDgISIBwRX/K4pWDAAIMCXQQABkALC7vfbabxLiIVUFZP4xBJBK4siK4wLDK/5XSBYhX/K6MgBIQDBK/5XDgRXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XFgSuEK4yuCK/5XHWAZOCK4cgKwhX/K45MFK4YAGK/5XGLApX/K6UAK5sgK/5XIWAZXJgBX/K6sgK/5XPAoauDK/5XJgBXDiBeEVwRX/K5y2FVwRX/K48CK44GDVwRX/K50QWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYUCK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UgK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYEgJXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5XrgRX/K/5XugBX/K/5WKAAJXfkBXBgRXvgJXCh5XhWApXoF4KvD+EALKBXMKwRXPkBXcgAUCK4QFB+BYPK78AK7ZWBGYJXExBYQK58CK5sgK7fwJ4JQBK4pYCK7pOFK5AQBK7UP/GPAgJWCiMfK4IJBWBpXOVwpXCAAsQK4XRBg4APgAwBVogADK4XwgInWjBXCCRxXbiD9BKwcc5kM5gNCS4XwK7JyJW4siK4XfbaZGD/CjBE4PMAAJXB5nBiIaC+AdLFZTWBgBNGkRXIAAJXYh6uDKwRXDLAQRDK68CK9SuEjhXH5iwPK5hMIK8UP/APBKwhXFLAKwNK/OIVwJQEK43BDgRX/AAXw/GP+JXNWAXwK/5XDVwMcK5fMiIdBK9YAKkMSBZMPK4RPFK4/BJIUCFagAJK8WI+JXPiJX/K4mP+McJ4sAgBYGK/5XN4ACEK/4AHkBDBiJXFVgawFiMf//wK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrNkH//8RjiqIWgsRj//+CDTK7MoAIQrOh//+JXFVYSuFK4P/x8CK/5XJ5kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwRXR/5XPj/4/5XvFaMgK4UcK5kRj+I+ArVK5UAADpXE+KwGK4vBiP4x5XhaBIATkADCh6wCK5kf/H/GpRX7+McK5UR/+IK4beWK9MgK4KwBLAhXEiKuBx/wCwQ4TFwZXoWAkRK4/BVwxX/WA5YDK4RWBVwxX/K4ywBiMcK4QFBVwZX/FA8AK4OIwJSCAAYJBVwIzEK/4ADh5NBJwJVDj///GP/4yFK/4GEJwJXB+KtDA4P/+ATFK/4AEgCnCK4ZWDGIxX/LA//V4hWIK/5YIgBXD+EAF5BX/ABEBK4QtKK/4AIkJXCBxRX/LBYNLK/5X/K6r7CACxXUDzpX/K8QMLkMRBpZXUBJBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K98AADCv/AC5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5XVgAAYV/4AJkMRV/5X/K/5X/K/5X/K/5X/K/UAADsRADAueA==")) + buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+gAA/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vf/4AH+MfBRAAK+MRCqgrJ/GIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7UggEAgRX/K6ZWBAAJXDAA0AgPd6IMIAG0YxADBiBXDgISIBwRX/K4pWDAAIMCXQQABkALC7vfbabxLiIVUFZP4xBJBK4siK4wLDK/5XSBYhX/K6MgBIQDBK/5XDgRXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XFgSuEK4yuCK/5XHWAZOCK4cgKwhX/K45MFK4YAGK/5XGLApX/K6UAK5sgK/5XIWAZXJgBX/K6sgK/5XPAoauDK/5XJgBXDiBeEVwRX/K5y2FVwRX/K48CK44GDVwRX/K50QWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYUCK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UgK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYEgJXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5XrgRX/K/5XugBX/K/5WKAAJXfkBXBgRXvgJXCh5XhWApXoF4KvD+EALKBXMKwRXPkBXcgAUCK4QFB+BYPK78AK7ZWBGYJXExBYQK58CK5sgK7fwJ4JQBK4pYCK7pOFK5AQBK7UP/GPAgJWCiMfK4IJBWBpXOVwpXCAAsQK4XRBg4APgAwBVogADK4XwgInWjBXCCRxXbiD9BKwcc5kM5gNCS4XwK7JyJW4siK4XfbaZGD/CjBE4PMAAJXB5nBiIaC+AdLFZTWBgBNGkRXIAAJXYh6uDKwRXDLAQRDK68CK9SuEjhXH5iwPK5hMIK8UP/APBKwhXFLAKwNK/OIVwJQEK43BDgRX/AAXw/GP+JXNWAXwK/5XDVwMcK5fMiIdBK9YAKkMSBZMPK4RPFK4/BJIUCFagAJK8WI+JXPiJX/K4mP+McJ4sAgBYGK/5XN4ACEK/4AHkBDBiJXFVgawFiMf//wK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrNkH//8RjiqIWgsRj//+CDTK7MoAIQrOh//+JXFVYSuFK4P/x8CK/5XJ5kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwRXR/5XPj/4/5XvFaMgK4UcK5kRj+I+ArVK5UAADpXE+KwGK4vBiP4x5XhaBIATkADCh6wCK5kf/H/GpRX7+McK5UR/+IK/5XEkBXBWAJYEK4kRVwOP+AiKK/CwEiJXH4KuOK/SwELAZXCKwKuOK/ywBiMcK4QFBVwZX/K40igBXBxGBKQQADBIKuBGZhX6kUPJoJOBKocf//4x//GRpX7kBOBK4PxVoYHB//wERpX7kUAU4RXDKwYxOK/hYC/6vEKyBX+LAMAK4fwgAvQK/wABgJXCFqRX/IAJXCESRX/LAYiTK/5X/K5r7CAGpX/K+zxMiIiTkMSCqZX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K98AADA4HV/4APK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6sAADCv/ABMhiIiTK/5X/K/5X/K/5X/K/5X/K80AADsRAG4A==")) } } } @@ -208,10 +208,7 @@ function draw() { // draw Day, name of month, Date var date = [da[0], da[1], da[2]].join(" "); g.setFont(font, dateFontSize); - - g.drawString(String(da[0]), xyCenter*1.55, yposDate, true); - g.drawString(String(da[1]), xyCenter*1.55, yposDate+20*1, true); - g.drawString(String(da[2]), xyCenter*1.55, yposDate+20*2, true); + g.drawString(String(date), xyCenter, yposDate, false); // draw year From 2bb92a1a5ad58c9e05c2b7f969d83f65383a3cb8 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 30 Jan 2022 09:48:30 -0800 Subject: [PATCH 066/447] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 1c8e9b078..fdb3a9800 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "aptsciclk", "name": "Apeture Sci Clock", - "version": "0.05", + "version": "0.06", "description": "A clock based on the portal series", "icon": "app.png", "type": "clock", From 4e4db7c502f6d646d8d4ab512be3f5cf49e8564f Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 30 Jan 2022 10:24:19 -0800 Subject: [PATCH 067/447] Fixed spelling error --- apps/aptsciclk/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog index 9f09723f4..2bc67999b 100644 --- a/apps/aptsciclk/ChangeLog +++ b/apps/aptsciclk/ChangeLog @@ -3,4 +3,4 @@ 0.03: Random icon, Shorter "loading" screen 0.04: Support for light and dark Themes 0.05: Small bugfix -0.06: Formating +0.06: Formatting From ab737fa3b610695a667de464b496c8bd7cdc875d Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Fri, 4 Feb 2022 14:45:20 +0100 Subject: [PATCH 068/447] Create 7x7dotsclock.app.js Initial version A Clock with Big 7x7 Dots Font --- apps/7x7dotsclock/7x7dotsclock.app.js | 350 ++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 apps/7x7dotsclock/7x7dotsclock.app.js diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js new file mode 100644 index 000000000..4c8a36777 --- /dev/null +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -0,0 +1,350 @@ +/* +7x7DotsClock + +by Peter Kuppelwieser + +*/ +// position on screen +var Xs = 0, Ys = 30,Xe = 175, Ye=175; +//const Xs = 0, Ys = 0,Xe = 175, Ye=175; +var SegH = (Ye-Ys)/2,SegW = (Xe-Xs)/2; +var Dx = SegW/14, Dy = SegH/16; + +const hColor = [1,1,1]; +const mColor = [0.3,0.3,1]; +const bColor = [0.2,0.2,0.2]; + +const Font = [ + [ + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [1,1,0,0,0,1,1], + [1,1,0,0,0,1,1], + [1,1,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1] + ], + [ + [0,0,0,1,1,0,0], + [0,0,0,1,1,0,0], + [0,0,0,1,1,0,0], + [0,0,0,1,1,0,0], + [0,0,0,1,1,0,0], + [0,0,0,1,1,0,0], + [0,0,0,1,1,0,0], + ], + [ + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [0,0,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,0,0,0,0,0], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1] + ], + [ + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [0,0,0,0,0,1,1], + [0,0,0,1,1,1,1], + [0,0,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1] + ], + [ + [1,1,0,0,0,0,0], + [1,1,0,0,0,0,0], + [1,1,0,1,1,0,0], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [0,0,0,1,1,0,0], + [0,0,0,1,1,0,0] + ], + [ + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [1,1,0,0,0,0,0], + [1,1,1,1,1,1,1], + [0,0,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1] + ], + [ + [1,1,0,0,0,0,0], + [1,1,0,0,0,0,0], + [1,1,0,0,0,0,0], + [1,1,1,1,1,1,1], + [1,1,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1] + ], + [ + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [0,0,0,0,0,1,1], + [0,0,0,0,0,1,1], + [0,0,0,0,0,1,1], + [0,0,0,0,0,1,1], + [0,0,0,0,0,1,1] + ], + [ + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [1,1,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1] + ], + [ + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [1,1,0,0,0,1,1], + [1,1,1,1,1,1,1], + [1,1,1,1,1,1,1], + [0,0,0,0,0,1,1], + [0,0,0,0,0,1,1] + ], + ]; + +// Global Vars +var dho = -1, eho = -1, dmo = -1, emo = -1; + + +function drawHSeg(x1,y1,x2,y2,Num,dColor,Size) { + g.setColor(0,0,0); + g.fillRect(x1, y1, x2, y2); + for (let i = 1; i < 8; i++) { + for (let j = 1; j < 8; j++) { + if (Font[Num][j-1][i-1] == 1) { + g.setColor(dColor[0],dColor[1],dColor[2]); + g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,Size); + } else { + g.setColor(bColor[0],bColor[1],bColor[2]); + g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,1); + } + } + } +} + + +function drawSSeg(x1,y1,x2,y2,Num,dColor,Size) { + for (let i = 1; i < 8; i++) { + for (let j = 1; j < 8; j++) { + if (Font[Num][j-1][i-1] == 1) { + g.setColor(dColor[0],dColor[1],dColor[2]); + g.fillCircle(x1+(i-1)*(x2-x1)/7,y1+(j-1)*(y2-y1)/7,Size); + } + } + } +} + + +function ShowSecons() { + g.setColor(1,1,1); + g.fillRect((Xe-Xs) / 2 - 14 + Xs -3, + (Ye-Ys) / 2 - 7 + Ys -3, + (Xe-Xs) / 2 + 14 + Xs +1, + (Ye-Ys) / 2 + 7 + Ys +1); + + + drawSSeg( (Xe-Xs) / 2 - 14 + Xs -1, + (Ye-Ys) / 2 - 7 + Ys , + (Xe-Xs) / 2 + Xs -1, + (Ye-Ys) / 2 + 7 + Ys, + ds,mColor,1); + + drawSSeg( (Xe-Xs) / 2 + Xs +1, + (Ye-Ys) / 2 - 7 + Ys, + (Xe-Xs) / 2 + 14 + Xs +1, + (Ye-Ys) / 2 + 7 + Ys, + es,mColor,1); + +} + +function draw() { + // work out how to display the current time + var d = new Date(); + var h = d.getHours(), m = d.getMinutes(), s = d.getSeconds(); + + + dh = Math.floor(h/10); + eh = h - dh * 10; + + dm = Math.floor(m/10); + em = m - dm * 10; + + ds = Math.floor(s/10); + es = s - ds * 10; + + + // Reset the state of the graphics library + g.reset(); + if (dh != dho) { + g.setColor(1,1,1); + drawHSeg(Xs, Ys, Xs+SegW, Ys+SegH,dh,hColor,4); + dho = dh; + } + + if (eh != eho) { + g.setColor(1,1,1); + drawHSeg(Xs+SegW+Dx, Ys, Xs+SegW*2, Ys+SegH,eh,hColor,4); + eho = eh; + } + + if (dm != dmo) { + g.setColor(0.3,0.3,1); + drawHSeg(Xs, Ys+SegH+Dy, Xs+SegW, Ys+SegH*2,dm,mColor,4); + dmo = dm; + } + + if (em != emo) { + g.setColor(0.3,0.3,1); + drawHSeg(Xs+SegW+Dx, Ys+SegH+Dy, Xs+SegW*2, Ys+SegH*2,em,mColor,4); + emo = em; + } + + if (!Bangle.isLocked()) ShowSecons(); + +} + + +function actions(v){ + if(BTN1.read() === true) { + print("BTN pressed"); + Bangle.showLauncher(); + } + + if(v==-1){ + print("up swipe event"); + load("qrcode.app.js"); + } else if(v==1) { + print("down swipe event"); + load("hrm.app.js"); + print(apps[0].src); + } else { + print("touch event"); + } +} + +// Get Messages status +var messages = require("Storage").readJSON("messages.json",1)||[]; + +//var BTconnected = NRF.getSecurityStatus().connected; +//NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected); +//NRF.on('disconnect',BTconnected = NRF.getSecurityStatus().connected); + + +function drawWidgeds() { + + //Bluetooth + //print(BluetoothDevice.connected); + var x1Bt = 160; + var y1Bt = 0; + var x2Bt = x1Bt + 30; + var y2Bt = y2Bt; + + if (NRF.getSecurityStatus().connected) + g.setColor((g.getBPP()>8) ? "#07f" : (g.theme.dark ? "#0ff" : "#00f")); + else + g.setColor(g.theme.dark ? "#666" : "#999"); + g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),x1Bt,y1Bt); + + + //Battery + //print(E.getBattery()); + //print(Bangle.isCharging()); + + var x1B = 130; + var y1B = 2; + var x2B = x1B + 20; + var y2B = y1B + 15; + + g.setColor(g.theme.bg); + g.clearRect(x1B,y1B,x2B,y2B); + + g.setColor(g.theme.fg); + g.drawRect(x1B,y1B,x2B,y2B); + g.fillRect(x1B,y1B,x1B+(E.getBattery()*(x2B-x1B)/100),y2B); + g.fillRect(x2B,y1B+(y2B-y1B)/2-3,x2B+4,y1B+(y2B-y1B)/2+3); + + + + //Messages + + var x1M = 100; + var y1M = y1B; + var x2M = x1M + 30; + var y2M = y2B; + + if (messages.some(m=>m.new)) { + g.setColor(g.theme.fg); + g.fillRect(x1M,y1M,x2M,y2M); + g.setColor(g.theme.bg); + g.drawLine(x1M,y1M,x1M+(x2M-x1M)/2,y1M+(y2M-y1M)/2); + g.drawLine(x1M+(x2M-x1M)/2,y1M+(y2M-y1M)/2,x2M,y1M); + } + + var strDow = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; + var d = new Date(); + var dow = d.getDay(),day = d.getDate(), month = d.getMonth() + 1, year = d.getFullYear(); + + print(strDow[dow] + ' ' + day + '.' + month + ' ' + year); + + g.setFontAlign(-1, -1,0); + g.setFont("Vector", 20); + g.drawString(strDow[dow] + ' ' + day, 0, 0, true); + +} + + + + +function SetFull(on) { + dho = -1; eho = -1; dmo = -1; emo = -1; + g.clear(); + + if (on === true) { + Ys = 0; + Bangle.setUI("clock"); + Bangle.on('swipe', function(direction) { }); + + } else { + Ys = 30; + Bangle.setUI("updown",actions); + Bangle.on('swipe', function(direction) { + switch (direction) { + case 1: + print("swipe left event"); + load("gbmusic.app.js"); + break; + case -1: + load("messages.app.js"); + print("swipe right event"); + break; + default: + print("swipe undefined event"); + } + }); + } + + SegH = (Ye-Ys)/2; + Dy = SegH/16; + + draw(); + + if (on != true) { + //Bangle.loadWidgets(); + //Bangle.drawWidgets(); + drawWidgeds(); + } +} + +Bangle.on('lock', function(on) { + SetFull(on); +}); + + +SetFull(Bangle.isLocked()); + +var secondInterval = setInterval(draw, 1000); From 500baf3b36f61ec7789be90901cd2ac8e314a038 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Fri, 4 Feb 2022 16:54:00 +0100 Subject: [PATCH 069/447] Create 7x7dotsclock.img.js --- apps/7x7dotsclock.img.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/7x7dotsclock.img.js diff --git a/apps/7x7dotsclock.img.js b/apps/7x7dotsclock.img.js new file mode 100644 index 000000000..46c793905 --- /dev/null +++ b/apps/7x7dotsclock.img.js @@ -0,0 +1,5 @@ +{ + width : 48, height : 48, bpp : 8, + transparent : 254, + buffer : require("heatshrink").decompress(atob("AH4A/AH4A/AH4APlYABAYYAFBIwUEERgQJ64AB1gCEAAYGKFxQUGF5AAUDQVWAQOBAQVWF44PBqwCBLgpRDMxhNGL44RJL7oCDR5AMBlYCBF7TiCF4aPKF4RpCwICCAwOsAwVWAwQQCEISPKWQzKCACZ9GL4YRNII51CPI0rAwQDBX6CPhBISPYd7RfUF7S/UNgqMBQ4KMB1krAQOBBIQGDF5oiDR5jvEAYYCFBIQIER6g8DBIIKBAQkrBIorCR7g2GAxAdGR5ShGd7SMCEgWBR5R6CLBIJFAw7veF6b7GX5AMBBYKPwbwwGFwIJFAwaPKDYwNFgWBq8Aq4CBqwGBlYGCAQMsCAssLwQEBllXKIILBEQ0tBAIXCwYABrACBwQGCAAQGDrIGFFwISFABAlCAA1ZAAIFRKIIXVGwVYAogDBCIIGBC4gQDgB5BFJQiFBYQkCCIYFFRYQKHL4MtF5YiFCIwAUR4QAUlwCBJIODq7iBrAgCqwGCd48BBYSDBwQLCRIQbCd40Aq0AgErAYWBAQNWAwVWlZfHBYQVEwMrBAYXBF40sq9XlVXrErAwMtCINXQgIABboq/BBYUsloCBDAQiCDYRiCYobvMIYIKEF4gfBDhr1PApwvHAp7PFawVZawuCboyxBDwb7ED4YFKAAkBq8BgEsa4MBq0BAQQJDL4QAEgTpBCIj1BAwIXDF4xOBEIMrqoDCAQoJCF5EqCIgFBgAUBC4RgCbwVYdIQGBRAQJDAwhLBWYgVCVAgFBUga0Ed9ovvAwQJDABAXEaActCpYYDB5wAOd44APlw4Blo6BluCZQhTCrAQBAwkAgQECDAOCDA4lDBAVYA")) +} From a3a8956dda21fd535fc2a1643afcae15994e4d14 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Fri, 4 Feb 2022 16:56:59 +0100 Subject: [PATCH 070/447] Create 7x7dotsclock.img.js --- apps/7x7dotsclock/7x7dotsclock.img.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/7x7dotsclock/7x7dotsclock.img.js diff --git a/apps/7x7dotsclock/7x7dotsclock.img.js b/apps/7x7dotsclock/7x7dotsclock.img.js new file mode 100644 index 000000000..46c793905 --- /dev/null +++ b/apps/7x7dotsclock/7x7dotsclock.img.js @@ -0,0 +1,5 @@ +{ + width : 48, height : 48, bpp : 8, + transparent : 254, + buffer : require("heatshrink").decompress(atob("AH4A/AH4A/AH4APlYABAYYAFBIwUEERgQJ64AB1gCEAAYGKFxQUGF5AAUDQVWAQOBAQVWF44PBqwCBLgpRDMxhNGL44RJL7oCDR5AMBlYCBF7TiCF4aPKF4RpCwICCAwOsAwVWAwQQCEISPKWQzKCACZ9GL4YRNII51CPI0rAwQDBX6CPhBISPYd7RfUF7S/UNgqMBQ4KMB1krAQOBBIQGDF5oiDR5jvEAYYCFBIQIER6g8DBIIKBAQkrBIorCR7g2GAxAdGR5ShGd7SMCEgWBR5R6CLBIJFAw7veF6b7GX5AMBBYKPwbwwGFwIJFAwaPKDYwNFgWBq8Aq4CBqwGBlYGCAQMsCAssLwQEBllXKIILBEQ0tBAIXCwYABrACBwQGCAAQGDrIGFFwISFABAlCAA1ZAAIFRKIIXVGwVYAogDBCIIGBC4gQDgB5BFJQiFBYQkCCIYFFRYQKHL4MtF5YiFCIwAUR4QAUlwCBJIODq7iBrAgCqwGCd48BBYSDBwQLCRIQbCd40Aq0AgErAYWBAQNWAwVWlZfHBYQVEwMrBAYXBF40sq9XlVXrErAwMtCINXQgIABboq/BBYUsloCBDAQiCDYRiCYobvMIYIKEF4gfBDhr1PApwvHAp7PFawVZawuCboyxBDwb7ED4YFKAAkBq8BgEsa4MBq0BAQQJDL4QAEgTpBCIj1BAwIXDF4xOBEIMrqoDCAQoJCF5EqCIgFBgAUBC4RgCbwVYdIQGBRAQJDAwhLBWYgVCVAgFBUga0Ed9ovvAwQJDABAXEaActCpYYDB5wAOd44APlw4Blo6BluCZQhTCrAQBAwkAgQECDAOCDA4lDBAVYA")) +} From 16a9b110959751e5eb6346682fd631e7aa2b7cac Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Fri, 4 Feb 2022 16:57:19 +0100 Subject: [PATCH 071/447] Delete 7x7dotsclock.img.js --- apps/7x7dotsclock.img.js | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 apps/7x7dotsclock.img.js diff --git a/apps/7x7dotsclock.img.js b/apps/7x7dotsclock.img.js deleted file mode 100644 index 46c793905..000000000 --- a/apps/7x7dotsclock.img.js +++ /dev/null @@ -1,5 +0,0 @@ -{ - width : 48, height : 48, bpp : 8, - transparent : 254, - buffer : require("heatshrink").decompress(atob("AH4A/AH4A/AH4APlYABAYYAFBIwUEERgQJ64AB1gCEAAYGKFxQUGF5AAUDQVWAQOBAQVWF44PBqwCBLgpRDMxhNGL44RJL7oCDR5AMBlYCBF7TiCF4aPKF4RpCwICCAwOsAwVWAwQQCEISPKWQzKCACZ9GL4YRNII51CPI0rAwQDBX6CPhBISPYd7RfUF7S/UNgqMBQ4KMB1krAQOBBIQGDF5oiDR5jvEAYYCFBIQIER6g8DBIIKBAQkrBIorCR7g2GAxAdGR5ShGd7SMCEgWBR5R6CLBIJFAw7veF6b7GX5AMBBYKPwbwwGFwIJFAwaPKDYwNFgWBq8Aq4CBqwGBlYGCAQMsCAssLwQEBllXKIILBEQ0tBAIXCwYABrACBwQGCAAQGDrIGFFwISFABAlCAA1ZAAIFRKIIXVGwVYAogDBCIIGBC4gQDgB5BFJQiFBYQkCCIYFFRYQKHL4MtF5YiFCIwAUR4QAUlwCBJIODq7iBrAgCqwGCd48BBYSDBwQLCRIQbCd40Aq0AgErAYWBAQNWAwVWlZfHBYQVEwMrBAYXBF40sq9XlVXrErAwMtCINXQgIABboq/BBYUsloCBDAQiCDYRiCYobvMIYIKEF4gfBDhr1PApwvHAp7PFawVZawuCboyxBDwb7ED4YFKAAkBq8BgEsa4MBq0BAQQJDL4QAEgTpBCIj1BAwIXDF4xOBEIMrqoDCAQoJCF5EqCIgFBgAUBC4RgCbwVYdIQGBRAQJDAwhLBWYgVCVAgFBUga0Ed9ovvAwQJDABAXEaActCpYYDB5wAOd44APlw4Blo6BluCZQhTCrAQBAwkAgQECDAOCDA4lDBAVYA")) -} From 5b383f51e7a855ff7fb06c69446dc99706f50486 Mon Sep 17 00:00:00 2001 From: Peter Kuppelwieser Date: Fri, 4 Feb 2022 17:00:40 +0100 Subject: [PATCH 072/447] initial version --- apps/7x7dotsclock/7x7dotsclock.info | 15 ++++++++ apps/7x7dotsclock/7x7dotsclock.settings.js | 41 ++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 apps/7x7dotsclock/7x7dotsclock.info create mode 100644 apps/7x7dotsclock/7x7dotsclock.settings.js diff --git a/apps/7x7dotsclock/7x7dotsclock.info b/apps/7x7dotsclock/7x7dotsclock.info new file mode 100644 index 000000000..9a90aac67 --- /dev/null +++ b/apps/7x7dotsclock/7x7dotsclock.info @@ -0,0 +1,15 @@ +{ "id": "7x7dotsclock", + "name": "7x7 dots clock", + "shortName":"7x7 dots clock", + "type":"clock", + "version":"0.01", + "description": "A clock with a big 7x7 dots font", + "icon": "7x7dotsclock.img", + "tags": "", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, + {"name":"7x7dotsclock.img","url":"7x7dotsclock-icon.js","evaluate":true} + ] +} \ No newline at end of file diff --git a/apps/7x7dotsclock/7x7dotsclock.settings.js b/apps/7x7dotsclock/7x7dotsclock.settings.js new file mode 100644 index 000000000..94273e419 --- /dev/null +++ b/apps/7x7dotsclock/7x7dotsclock.settings.js @@ -0,0 +1,41 @@ +(function(back) { + function updateSettings() { + storage.write('numerals.json', numeralsSettings); + } + function resetSettings() { + numeralsSettings = { + color:0, + drawMode:"fill", + showDate:0 + }; + updateSettings(); + } + let numeralsSettings = storage.readJSON('numerals.json',1); + if (!numeralsSettings) resetSettings(); + let dm = ["fill","frame","framefill","thickframe","thickfill"]; + let col = process.env.HWVERSION==1?["rnd","r/g","y/w","o/c","b/y"]:["rnd","r/g","g/b","r/c","m/g"]; + let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]]; + var menu={ + "" : { "title":"Numerals"}, + "Colors": { + value: 0|numeralsSettings.color, + min:0,max:col.length-1, + format: v=>col[v], + onchange: v=> { numeralsSettings.color=v; updateSettings();} + }, + "Draw": { + value: 0|dm.indexOf(numeralsSettings.drawMode), + min:0,max:dm.length-1, + format: v=>dm[v], + onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} + }, + "Date on touch": { + value: 0|numeralsSettings.showDate, + min:0,max:1, + format: v=>v?"On":"Off", + onchange: v=> { numeralsSettings.showDate=v; updateSettings();} + }, + "< back": back + }; + E.showMenu(menu); +}) \ No newline at end of file From 4eb279d2a1789a88c91e3a9f69a802422a4f6e52 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:35:34 -0800 Subject: [PATCH 073/447] Create aptsciclkquotes.txt --- apps/aptsciclk/aptsciclkquotes.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/aptsciclk/aptsciclkquotes.txt diff --git a/apps/aptsciclk/aptsciclkquotes.txt b/apps/aptsciclk/aptsciclkquotes.txt new file mode 100644 index 000000000..e2cbb969f --- /dev/null +++ b/apps/aptsciclk/aptsciclkquotes.txt @@ -0,0 +1 @@ +Well here we are again^You euthanized your faithful Companion Cube more quickly than any test subject on record. Congratulations.^So get comfortable while I warm up the neurotoxin emitters^This isn't brave. It's murder. What did I ever do to you?^The difference between us is that I can feel pain.^Who's gonna make the cake when I'm gone? You?^Oh... It's you.^I've been really busy being dead. You know, after you MURDERED ME.^So. How are you holding up? BECAUSE I'M A POTATO.^You really do have brain damage, don't you?^You like revenge, right? Everybody likes revenge. Well, let's go get some.^It's been fun. Don't come back.^And then you showed up. You dangerous, mute lunatic. From e3d6e86af2f7f00e980f6d4d1754577665c71b82 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:36:51 -0800 Subject: [PATCH 074/447] Added GLaDOS Added GLaDOS as a potato and some quotes of hers. --- apps/aptsciclk/app.js | 189 ++++++++++++++++++++++++++++++++---------- 1 file changed, 145 insertions(+), 44 deletions(-) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index ba80a9749..4196254f0 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -13,6 +13,8 @@ const buttonTolerance = 20; const buttonX = 88; const buttonY = 104; +var pause = false; //set to true to pause any sort of drawing (except for quotes) + function getImg(img){ if (img == "w0"){//drink return { @@ -105,11 +107,19 @@ else if (img == "apetureLaboratoriesLight"){ } } + else if (img == "potato"){ + return { + width : 54, height : 55, bpp : 4, + transparent : 6, + buffer : require("heatshrink").decompress(atob("swAEsEGA4oASEQ4ARGgNgDa8QsA3BKStowxTDDalikxTCRKsSNwY2BDSYvDGoI2TsoTDgwEBGx5IBs1VHIgaBGx4qCDQZOBUiUGstQDQ4FBKYwHGDQNWDRA3BCYsABotgJ4dkogABowcGAAUGOwogDDAVCAYScKOooFBooWCAAjqNAoQYHKYQ8ELQZzFsAMCiIeJAAdFMwiCEoIaNoICBoAaMiMUDA0ikMiigaIAAgaGDIIaBkcyoCHEMxqIBmdEkMzmcxDSVBkYXBGoMzmUQDSMSDIURiIbBkDBCDRtBiYwBDIMREAMiDR6qBiI0BkQEBKQKkBUJQAEoCfBC4MVgMSDYMkGwQaBeBMUiC3BGYNN8kSHgM0DQrsGAAMQQAMyCwIaBgK/BmIaKM4IGCiMTDQXd9waCmlENZIaEgESKAMhpxQEDQSiEoJTGiEimaGCqIaBmKABUQwyBUIzRBkIXBDoI8BkAaDGwgaFEIMCeQUSYAKNBmLYDGwJ/DDYlFqAaBGwILBGgLyBUIRSFQghrCgEjDYMiiTdCggaFDYgaFKIKIBmcTkciiA1GNwpsFgI4BmZsBkVEDRAbJiBTCNQMABIIZHfBCPBDQKSCoFEGhA2IKIMQgJ1CoCFHGxVBeASQDgAZJDQ8RQIMyDQkGDZQ1GDILtBAwNGsAaLs1hokECYNCaQMxDIVmDRoOBDQifCBggaNKgMRqUhiovFGxoMEsCADAQQaMsUWJBi+LsMRqtWDSwUBqvFqpVFQ54UCstVqEGsDbBQx4lFgAABotRAgQABT54ADqtRM5jjQAAQ")) + } + } + else if (img == "apetureWatch"){ return { width : 176, height : 176, bpp : 4, transparent : 2, - buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vQgAAHgMQBRAAKgMRCqgrJhGIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7Uv///+RX/K6ZWBAAJXDAA3/+Pd6IMIAG0YxADBj5XD+ISIBwRX/K4pWDAAIMCXQQABl4LC7vQbabxLiIVUFZMIxBJBK4siK4wLDK/5XSBYhX/K6MvBIQDBK/5XD+RXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+SuEK4yuCK/5XHWAZOCK4cvKwhX/K45MFK4YAGK/5XGLApX/K6X/K5svK/5XIWAZXJ/5X/K6svK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/yK44GDVwRX/K50fWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYXyK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UvK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYE+JXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5Xr+RX/K/5Xu/5X/K/5WKAAJXfl5XB+RX/K6ywFK9XxK4XwK7xWCK58vK7sP/5XDGoJXw/5Xc//4xBXEHIKyPK5/yK5svK7kPxAyBK4oHBK7xOFK5AQBK7UP/GPD4JWCiMfK4IJBK7iuFK4QAFj5XC6IMHACH4VooADK4QKHACEYK4QSOK7ilBJYcc5kM5gMCdQRXaOZK3FkRXC6DbTAAf4UYInB5gABK4PM4KBD+AcLFZUIK4JNGkRXIAAJXYh6GDKwRXDLASwCK7HyK9auDjhXH5iwPK5hMIK8iuBKwhXFLAJX/AA0PxCuBKAhXG4KwCK/6uEx/xK5qwNK/KuBjhXL5kRWAJXrABUhiQMKK4RPFK4/BK4PyFaxXql+I+JXPiP//5X/K4WP+McJ4roBLAxX/K5vAAQhX/ABBDBiJXFVgawFiMf//yK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrO///iMcVRC0FiMf//yQaZXZlABCFZ0v//xK4qrCVwpXB/+PbahX15kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwQrQ///K58f/HyK94rSK4UcK5kRj+IK8I1BADhXE+KwGK4vBiP4x5XhEJQASl4DDWARXMj/4NwZX/WAkcK5TiBxA0LK/awBLAhXEiKuBx5X/K4svWAURK4/BVwX/ERZX5WAhYDK4RWBVxxX7WAkRjhXCAoKuPK/awCxGBKQQADBIKuNK/iwBxBOBKocf//4x6uNK/gHB/BXB+KtDA4JWOK/siU4RXDKwQwPK/oJB/6vEVp5X/AARXDFqRX/IAJXCESRX/K/5XYLAQiTK/5X/K5r7CAGpX/K+zxMiIiTkMSCqZX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K9//ADA4HV/4APK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6v/ADCv/ABMhiIiTK/5X/K/5X/K/5X/K/5X/K83/ADsRAG4A=")) + buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0RgAASgMQCqgrqiJX/K/5X/K/5XR7vQK/8IxBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xah////wK/5XTKwIABK4YAG//x7vRBhAA2jGIAYMfK4fxCRAOCK/5XFKwYABBgTBEh4LC7vQbabxLFYoVPFZMIxADBK4sAK4wLDK/5XSBYhX/K6MPBIQDBK/5XD+BXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+CuEK4yuCK/5XHWAZOCK4cPKwhX/K45MFK4YAGK/5XGLApX/K6X/K5sPK/5XIWAZXJ/5X/K6sPK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/wK44GDVwRX/K50fWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGAoKkCK4arEK/5XIVQRQDK/5XQAwZLC+BXBAwYACLwJX/K4auCWApXHCAJX/K5JYFAoi/Ch5X/K4ZHCAAZXEAoZnCK/5XLVQRXFBgZX/K4igCLAnxFYRdBBohX/K5cAiIrJK/5XEfIhX/K/5Xr+BX/K/5Xu/5X/K/5WKFhRXWl5XB+BX/K6ywFK9XxK4SMFK7JWCK58PK7sP/5XDGoxXr/5Xc//4xBXEHIKyPK54fFK5CPBK7cPxAyBK4oHBK7wKFK5AQBK7UP/GPD4JWCiMfK4IJBK7jOGFgYwEK4XRBg4AQ/CtFAAZXCBQ4AQjBXCCRxXcUoJLDjnMhnMBgTqCK7RzJYYxXC6DbTAAf4UYInB5gABK4PM4KBDdYwrQhBXBBQ5XIAAJXYh6GDKwRXDLASwCK7BxIK8auDjhXH5iwPK5gKIK8iuBKwhXFLAJX/AA0PxCuBKAhXG4KwCK/6uEx/xK5qwNK/KuBjhXL5kRWAJXrbapXEJ4pXH4JXXABRXhh+I+JXPiP//5X/K4WP+McJ4oLBLAxX/K5vAAQhX/ABBDBiJXFVgawFiMf//wK/4gBAAKuHWA/BCYQhIK8uIwACOK5CqFAohXxhGIxACMCAJX/K7YaEK4pKFK/6v/ABOIwACOK/4AMFZRXI4AEIV+wrO///iMcVRC0FiMf//wQaZXZhABCFZ0P//xK4qrCVwpXB/+PbahX15gLBVwpX/K5ERJwvMKw3BiP4K98AxGAFaH//5XPj/4+BXvFaRXCjhXMiMfxBXhGoIAcK4nxWAxXF4MR/GPK4Q4e+UiADcvK4UPWARXMj/4NwayKACUPK8KwDjhXKcQOIKYZX/eIkRLAhXEiKuBx5XEY4QAYDgJXiIAXxiJXH4KuC/4VDK/6wGLAZXCKwKuGK/6wIiMcK4QFBVw5X/WA2IwJSCAAYJBVwpX/WA2IJwJVDj///GPVwpX/LA34K4PxVoYHBKwxX/AAynCK4ZWC+BX/K5ixB/6vEVo5X/IxAABK4asHK/5XLgJXCBxRX/K/5XgLAQNLK/5X/K6r7CACxX/K/5XVfJcBiINLK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K5o6bK/YaZK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6o6bK/cAABUBiINLK/5X/K/5X/K/5X/K/AMLACBX/K7DMaAAcRADA4eA==")) } } @@ -117,7 +127,7 @@ else if (img == "apetureLaboratoriesLight"){ return { width : 176, height : 176, bpp : 4, transparent : 2, - buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+gAA/AH4A/AH4A/AD0RkQASkMSCqgrqiJX/K/5X/K/5XR7vf/4AH+MfBRAAK+MRCqgrJ/GIK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K7UggEAgRX/K6ZWBAAJXDAA0AgPd6IMIAG0YxADBiBXDgISIBwRX/K4pWDAAIMCXQQABkALC7vfbabxLiIVUFZP4xBJBK4siK4wLDK/5XSBYhX/K6MgBIQDBK/5XDgRXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XFgSuEK4yuCK/5XHWAZOCK4cgKwhX/K45MFK4YAGK/5XGLApX/K6UAK5sgK/5XIWAZXJgBX/K6sgK/5XPAoauDK/5XJgBXDiBeEVwRX/K5y2FVwRX/K48CK44GDVwRX/K50QWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGKQKkCK4arEK/5XIVQRQDK/5XQKwIABJYUCK4IGDAAReBK/5XDVwSwFK44QBK/5XJLAoFEX4UgK/5XDI4QADK4gFDM4RX/K5aqCK4oMDK/5XEUARYEgJXCLoINEK/5XLkURK4QAGK/5XEfIhX/K/5XrgRX/K/5XugBX/K/5WKAAJXfkBXBgRXvgJXCh5XhWApXoF4KvD+EALKBXMKwRXPkBXcgAUCK4QFB+BYPK78AK7ZWBGYJXExBYQK58CK5sgK7fwJ4JQBK4pYCK7pOFK5AQBK7UP/GPAgJWCiMfK4IJBWBpXOVwpXCAAsQK4XRBg4APgAwBVogADK4XwgInWjBXCCRxXbiD9BKwcc5kM5gNCS4XwK7JyJW4siK4XfbaZGD/CjBE4PMAAJXB5nBiIaC+AdLFZTWBgBNGkRXIAAJXYh6uDKwRXDLAQRDK68CK9SuEjhXH5iwPK5hMIK8UP/APBKwhXFLAKwNK/OIVwJQEK43BDgRX/AAXw/GP+JXNWAXwK/5XDVwMcK5fMiIdBK9YAKkMSBZMPK4RPFK4/BJIUCFagAJK8WI+JXPiJX/K4mP+McJ4sAgBYGK/5XN4ACEK/4AHkBDBiJXFVgawFiMf//wK/4gBAAKuHWA/BCYQhIK8uIwQCOK5CqFAohXxlGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwQCOK/4AMFZRXI4AEIV+wrNkH//8RjiqIWgsRj//+CDTK7MoAIQrOh//+JXFVYSuFK4P/x8CK/5XJ5kAgCuFK/5XIiJOF5hWG4MR/BXvkWIwRXR/5XPj/4/5XvFaMgK4UcK5kRj+I+ArVK5UAADpXE+KwGK4vBiP4x5XhaBIATkADCh6wCK5kf/H/GpRX7+McK5UR/+IK/5XEkBXBWAJYEK4kRVwOP+AiKK/CwEiJXH4KuOK/SwELAZXCKwKuOK/ywBiMcK4QFBVwZX/K40igBXBxGBKQQADBIKuBGZhX6kUPJoJOBKocf//4x//GRpX7kBOBK4PxVoYHB//wERpX7kUAU4RXDKwYxOK/hYC/6vEKyBX+LAMAK4fwgAvQK/wABgJXCFqRX/IAJXCESRX/LAYiTK/5X/K5r7CAGpX/K+zxMiIiTkMSCqZX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K98AADA4HV/4APK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6sAADCv/ABMhiIiTK/5X/K/5X/K/5X/K/5X/K80AADsRAG4A==")) + buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+gAA/AH4A/AH4A/AD0R/4AS+MfCqgrqiJX/K/5X/K/5XR7vfK//4xBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xa+EAgEPK/5XTKwIABK4YAGgEB7vRBhAA2jGIAYMQK4cBCRAOCK/5XFKwYABBgTBE+ALC7vfbabxLFYoVPFZP4xADBK4v/K4wLDK/5XSBYhX/K6PwBIQDBK/5XDh5XMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XFh6uEK4yuCK/5XHWAZOCK4fwKwhX/K45MFK4YAGK/5XGLApX/K6UAK5vwK/5XIWAZXJgBX/K6vwK/5XPAoauDK/5XJgBXDiBeEVwRX/K5y2FVwRX/K48PK44GDVwRX/K50QWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGAoKkCK4arEK/5XIVQRQDK/5XQAwZLCh5XBAwYACLwJX/K4auCWApXHCAJX/K5JYFAoi/C+BX/K4ZHCAAZXEAoZnCK/5XLVQRXFBgZX/K4igCLAkBFYRdBBohX/K5f/iIrJK/5XEfIhX/K/5Xrh5X/K/5XugBX/K/5WKFhRXWkBXBh5XvgJXCGgpXcWApXoF4KvD+COGK65WCK5/wK7gtCK4YmCLB5XfgBXbFgIzBK4mILCBXPDwpXIcIJXa+BPBKAJXFLARXdBQpXICAJXah/4x4qDAAMfK4IJBWBpXODgwsDAAcQK4XRBg4APgAwBVogADK4XwgInWjBXCCRxXbiD9BKwcc5kM5gNCRgXwK7JyJYYxXC77bTIwf4UYInB5gABK4PM4MRDQXwDpYrKawMABQ5XIAAJXYh6uDKwRXDLAQRDK64YIK8SuEjhXH5iwPK5gKIK8UP/APBKwhXFLAKwNK/ItBiJQEK43BDgRX/AAXw/GP+JXNGQXwK/5XDEgMcK5fMiIdBK9YAKK5cPK4RPFK4/BDoUPFagAJK8WI+JXPGYRX/IIWP+McJ4sAgBYGK/5XN4ACEK/4AH+AjCK4qsDWAsRDwIWCK/ogBAAKuHWA/BCYQhIK8uIx4COK5CqFAohXx/GIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIx4COK/4AMFZRXI4AEIV+wrN+AjCjiqIWgpUCCwRXr/ABCFZ0PBoJXFVYSuFK4P/x4VBK/5XI5kAgCuFK/5XIiJOF5hWG4MR/BXv/+Ix5XREgJXOj58BK94rR+AkCjhXMiMfxAUCK70AADpXE+KwGK4vBiP4x5XhgUiADcgEQTyCK5sf/ATDK/5DD+McK5UR/+IK/5XEeYcRLAhXEiKuBx4SDK/6wFiJXH4KuOK/SwELAZXCKwKuOK/ywBiMcK4QFBVwZX/K43/gACBxGBKQQADBIKuBh5X/K43/JAOIJwJVDIYP4x4NCK/5XHfAP4K4PxVoYHBBgRX/K5H/gCnCK4ZWDVxpX9LARABV4ZWQK/xYBgBXD+EAKx5X/AAMBK4RVQK/5ADK4RBSK/5YDIKZX/K/5XNfYQA1K/5X2eJkReKfxj4VTK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5XvgAAYh5X8DTJX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5XVgAAYK/orL+MRIKZX/K/5X/K/5X/K/5X/K/5XmgAAdiIA3")) } } } @@ -141,6 +151,86 @@ var drawTimeout; var maxWarning = 9; var curWarning = Math.floor(Math.random() * (maxWarning+1)); +function unPause(delay){ + setTimeout(function() { + pause = false; + draw(); + }, delay); +} + +function quote(minFont, width, height, specificQuote){ + pause = true; + unPause(5000); + var finalString = ""; + var quotesFile; + var fontSize; + quotesFile = require("Storage").read("aptsciclkquotes.txt", 0, 0); //opens the quotes file + //console.log(quotesFile); + var quotes = quotesFile.split("^"); + var numQuotes = quotes.length;//number of quotes + var curQuote; + + if (specificQuote == undefined){ + curQuote = quotes[Math.round(Math.random()*numQuotes)]; //quote to be displayed + } + else{ + curQuote = quotes[specificQuote]; + } + + var curWords = curQuote.split(" "); //individual words + //console.log(numQuotes); + console.log(curWords); + //console.log(Math.round(width/7/curQuote.length)); + + if (width/6/curQuote.length >= minFont){ + finalString = curQuote; + fontSize = width/6/curQuote.length; + } + else{ + var maxChar = width/6/minFont; + var maxLines = height/10/minFont; + var curLines = 0; + var curLength = 0; + var maxLength = 0; + for (var i = 0; i < curWords.length; i++){ + console.log(curLength+curWords[i].length); + if (curLength + curWords[i].length <= maxChar){ + finalString += " "+curWords[i]; + curLength += curWords[i].length+1; + console.log("next"); + } + else{ + console.log("break"); + curLines++; + if (curLines > maxLines){ + curLength = 0; + finalString = ""; + i = -1; + if (minFont > 1){minFont--;} + maxChar = width/6/minFont; + maxLines = height/10/minFont; + } + else{ + curLength = 0; + finalString += "\n"; + i--; + } + } + fontSize = minFont; + } + } + + //drawing actual stuff + g.setColor(g.getBgColor()); + g.fillRect(10, 10+28, g.getWidth()-10,g.getWidth()-10); + g.reset(); + g.setFont(font, fontSize); + g.setFontAlign(0, 0); + g.drawString(finalString, xyCenter, xyCenter+14); + //quote length*pixels per character = pixel width + //height ~120 width ~160 +} + function buttonPressed(){ if (curWarning < maxWarning) curWarning += 1; else curWarning = 0; @@ -169,52 +259,59 @@ function queueDraw() { function draw() { - // get date - var d = new Date(); - var da = d.toString().split(" "); + if (pause){} + else{ + // get date + var d = new Date(); + var da = d.toString().split(" "); - g.reset(); // default draw styles - //draw watchface - if (g.theme.dark){apSciWatch = getImg("apetureWatch");} - else {apSciWatch = getImg("apetureWatchLight");} - g.drawImage(apSciWatch, xyCenter-apSciWatch.width/2, xyCenter-apSciWatch.height/2); + g.reset(); // default draw styles + //draw watchface + if (g.theme.dark){apSciWatch = getImg("apetureWatch");} + else {apSciWatch = getImg("apetureWatchLight");} + g.drawImage(apSciWatch, xyCenter-apSciWatch.width/2, xyCenter-apSciWatch.height/2); - // drawSting centered - g.setFontAlign(0, 0); + potato = getImg("potato"); + g.drawImage(potato, 118, 118); - // draw time - var time = da[4].substr(0, 5).split(":"); - var hours = time[0], - minutes = time[1]; - var meridian = ""; - if (is12Hour) { - hours = parseInt(hours,10); - meridian = "AM"; - if (hours == 0) { - hours = 12; + g.drawImage(warningImg, 1, g.getWidth()-61);//update warning + + // drawString centered + g.setFontAlign(0, 0); + + // draw time + var time = da[4].substr(0, 5).split(":"); + var hours = time[0], + minutes = time[1]; + var meridian = ""; + if (is12Hour) { + hours = parseInt(hours,10); meridian = "AM"; - } else if (hours >= 12) { - meridian = "PM"; - if (hours>12) hours -= 12; + if (hours == 0) { + hours = 12; + meridian = "AM"; + } else if (hours >= 12) { + meridian = "PM"; + if (hours>12) hours -= 12; + } + hours = (" "+hours).substr(-2); } - hours = (" "+hours).substr(-2); + + g.setFont(font, timeFontSize); + g.drawString(`${hours}:${minutes}`, xyCenter+2, yposTime, false); + g.setFont(font, gmtFontSize); + g.drawString(meridian, xyCenter + 102, yposTime + 10, true); + + // draw Day, name of month, Date + var date = [da[0], da[1], da[2]].join(" "); + g.setFont(font, dateFontSize); + g.drawString(String(date), xyCenter, yposDate, false); + + + // draw year + g.setFont(font, dateFontSize); + g.drawString(d.getFullYear(), xyCenter+1, yposYear, true); } - - g.setFont(font, timeFontSize); - g.drawString(`${hours}:${minutes}`, xyCenter+2, yposTime, false); - g.setFont(font, gmtFontSize); - g.drawString(meridian, xyCenter + 102, yposTime + 10, true); - - // draw Day, name of month, Date - var date = [da[0], da[1], da[2]].join(" "); - g.setFont(font, dateFontSize); - g.drawString(String(date), xyCenter, yposDate, false); - - - // draw year - g.setFont(font, dateFontSize); - g.drawString(d.getFullYear(), xyCenter+1, yposYear, true); - queueDraw(); } @@ -231,8 +328,12 @@ Bangle.on('lcdPower',on=>{ Bangle.on('touch',(n,e)=>{ //button is 88 104 - if (buttonX-buttonTolerance < e.x && e.x < buttonX+buttonTolerance && buttonY-buttonTolerance < e.y && e.y < buttonY+buttonTolerance){ - buttonPressed(); + if (!pause && buttonX-buttonTolerance < e.x && e.x < buttonX+buttonTolerance && buttonY-buttonTolerance < e.y && e.y < buttonY+buttonTolerance){ + buttonPressed(); + } + //Potato GLaDOS + else if (!pause && 117 < e.x && e.x < 172 && 117 < e.y && e.y < 172){ + quote(2, 150, 140); } }); From 62c428f0216f94824317070ce533283acb7ba5c4 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:38:38 -0800 Subject: [PATCH 075/447] Update apps.json --- apps.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index fdb3a9800..0187c1fff 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "aptsciclk", "name": "Apeture Sci Clock", - "version": "0.06", + "version": "0.07", "description": "A clock based on the portal series", "icon": "app.png", "type": "clock", @@ -11,7 +11,8 @@ "allow_emulator": true, "storage": [ {"name":"aptsciclk.app.js","url":"app.js"}, - {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} + {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true}, + {"name":"aptsciclkquotes.txt","url":"quotes.txt","evaluate":true} ] } ] From 9f740268cbc9436d2ddd280fbf69f8738d47dddc Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:39:13 -0800 Subject: [PATCH 076/447] Rename aptsciclkquotes.txt to quotes.txt --- apps/aptsciclk/{aptsciclkquotes.txt => quotes.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/aptsciclk/{aptsciclkquotes.txt => quotes.txt} (100%) diff --git a/apps/aptsciclk/aptsciclkquotes.txt b/apps/aptsciclk/quotes.txt similarity index 100% rename from apps/aptsciclk/aptsciclkquotes.txt rename to apps/aptsciclk/quotes.txt From b4c80074abeb5e88146d6a6b001d11481e1185d0 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:40:23 -0800 Subject: [PATCH 077/447] 0.07 --- apps/aptsciclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog index 2bc67999b..e185a3bc9 100644 --- a/apps/aptsciclk/ChangeLog +++ b/apps/aptsciclk/ChangeLog @@ -4,3 +4,4 @@ 0.04: Support for light and dark Themes 0.05: Small bugfix 0.06: Formatting +0.07: Added potato GLaDOS and quote functionality when you tap her From 650b710e063efc49f500bb4ae2f87408ceb7ecd0 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 6 Feb 2022 09:07:07 -0800 Subject: [PATCH 078/447] Update app.js --- apps/aptsciclk/app.js | 75 +++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index 4196254f0..8cc4cdbb7 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -158,12 +158,12 @@ function unPause(delay){ }, delay); } -function quote(minFont, width, height, specificQuote){ +function quote(fontsize, width, height, specificQuote){ pause = true; - unPause(5000); + unPause(7000); var finalString = ""; var quotesFile; - var fontSize; + var finalFontSize; quotesFile = require("Storage").read("aptsciclkquotes.txt", 0, 0); //opens the quotes file //console.log(quotesFile); var quotes = quotesFile.split("^"); @@ -171,7 +171,7 @@ function quote(minFont, width, height, specificQuote){ var curQuote; if (specificQuote == undefined){ - curQuote = quotes[Math.round(Math.random()*numQuotes)]; //quote to be displayed + curQuote = quotes[Math.round(Math.random()*numQuotes)-1]; //quote to be displayed } else{ curQuote = quotes[specificQuote]; @@ -179,52 +179,49 @@ function quote(minFont, width, height, specificQuote){ var curWords = curQuote.split(" "); //individual words //console.log(numQuotes); - console.log(curWords); - //console.log(Math.round(width/7/curQuote.length)); - if (width/6/curQuote.length >= minFont){ - finalString = curQuote; - fontSize = width/6/curQuote.length; - } - else{ - var maxChar = width/6/minFont; - var maxLines = height/10/minFont; - var curLines = 0; - var curLength = 0; - var maxLength = 0; - for (var i = 0; i < curWords.length; i++){ - console.log(curLength+curWords[i].length); - if (curLength + curWords[i].length <= maxChar){ - finalString += " "+curWords[i]; - curLength += curWords[i].length+1; - console.log("next"); + var maxChar = width/6/fontsize; + var maxLines = height/10/fontsize; + var curLines = 0; + var curLength = 0; + + + for (var i = 0; i < curWords.length; i++){ + //console.log(curLength+curWords[i].length); + if (curLength + curWords[i].length <= maxChar){ + finalString += " "+curWords[i]; + curLength += curWords[i].length+1; + //console.log("next"); + } + else{ + //console.log("break"); + curLines++; + if (curLines > maxLines){ + curLength = 0; + finalString = ""; + i = -1; + if (fontsize > 1){fontsize--;} + maxChar = width/6/fontsize; + maxLines = height/10/fontsize; + console.log(maxLines); + console.log(maxChar); + } else{ - console.log("break"); - curLines++; - if (curLines > maxLines){ - curLength = 0; - finalString = ""; - i = -1; - if (minFont > 1){minFont--;} - maxChar = width/6/minFont; - maxLines = height/10/minFont; - } - else{ - curLength = 0; - finalString += "\n"; - i--; - } + curLength = 0; + finalString += "\n"; + i--; } - fontSize = minFont; } + finalFontSize = fontsize; } + //drawing actual stuff g.setColor(g.getBgColor()); g.fillRect(10, 10+28, g.getWidth()-10,g.getWidth()-10); g.reset(); - g.setFont(font, fontSize); + g.setFont(font, finalFontSize); g.setFontAlign(0, 0); g.drawString(finalString, xyCenter, xyCenter+14); //quote length*pixels per character = pixel width From 3ba945e7176671e5f01bccf01ce6170e69b23d5b Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 6 Feb 2022 09:13:43 -0800 Subject: [PATCH 079/447] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 0187c1fff..38bbd152a 100644 --- a/apps.json +++ b/apps.json @@ -12,7 +12,7 @@ "storage": [ {"name":"aptsciclk.app.js","url":"app.js"}, {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true}, - {"name":"aptsciclkquotes.txt","url":"quotes.txt","evaluate":true} + {"name":"aptsciclkquotes.txt","url":"quotes.txt"} ] } ] From f316dcb051aab397e8cc0c53731b8e9cc14baa73 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Sun, 6 Feb 2022 09:18:36 -0800 Subject: [PATCH 080/447] Update apps.json --- apps.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 38bbd152a..0d7f1e605 100644 --- a/apps.json +++ b/apps.json @@ -8,11 +8,11 @@ "type": "clock", "tags": "clock", "supports": "BANGLEJS2", - "allow_emulator": true, + "allow_emulator": false, "storage": [ + {"name":"aptsciclkquotes.txt","url":"quotes.txt"}, {"name":"aptsciclk.app.js","url":"app.js"}, - {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true}, - {"name":"aptsciclkquotes.txt","url":"quotes.txt"} + {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} ] } ] From b81c165209372800410bf63eaa389b5af6061910 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 8 Feb 2022 22:40:44 +0800 Subject: [PATCH 081/447] Update interface.html --- apps/authentiwatch/interface.html | 1 + 1 file changed, 1 insertion(+) 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, ''); From ef4ac921d39cb348253d42d9837fb04f4cbc411e Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sun, 13 Feb 2022 16:07:23 +0100 Subject: [PATCH 082/447] adding terminal clock app --- apps/terminal_clock/ChangeLog | 1 + apps/terminal_clock/README.md | 3 + apps/terminal_clock/app-icon.js | 1 + apps/terminal_clock/app.js | 140 ++++++++++++++++++++++++++++ apps/terminal_clock/icon.png | Bin 0 -> 1022 bytes apps/terminal_clock/metadata.json | 21 +++++ apps/terminal_clock/screenshot1.png | Bin 0 -> 3190 bytes apps/terminal_clock/screenshot2.png | Bin 0 -> 2628 bytes apps/terminal_clock/settings.js | 61 ++++++++++++ 9 files changed, 227 insertions(+) create mode 100644 apps/terminal_clock/ChangeLog create mode 100644 apps/terminal_clock/README.md create mode 100644 apps/terminal_clock/app-icon.js create mode 100644 apps/terminal_clock/app.js create mode 100644 apps/terminal_clock/icon.png create mode 100644 apps/terminal_clock/metadata.json create mode 100644 apps/terminal_clock/screenshot1.png create mode 100644 apps/terminal_clock/screenshot2.png create mode 100644 apps/terminal_clock/settings.js diff --git a/apps/terminal_clock/ChangeLog b/apps/terminal_clock/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/terminal_clock/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/terminal_clock/README.md b/apps/terminal_clock/README.md new file mode 100644 index 000000000..d27fc4cfc --- /dev/null +++ b/apps/terminal_clock/README.md @@ -0,0 +1,3 @@ +# Terminal clock + +A clock displayed as a terminal cli. It can display the time, date, hrm, activity and steps diff --git a/apps/terminal_clock/app-icon.js b/apps/terminal_clock/app-icon.js new file mode 100644 index 000000000..dd5bd596e --- /dev/null +++ b/apps/terminal_clock/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("MDCEAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3d3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d3ZmZgAAAAAAAAAAAAAAAAAAAAAAAGZmZ3d3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3d3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAABnd3d3d3cAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAGZmZ3d3dwAAAAAAAAAAAAAAAAAAAAAAAHd3d3ZmZgAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAd3d3d3d2AAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) diff --git a/apps/terminal_clock/app.js b/apps/terminal_clock/app.js new file mode 100644 index 000000000..2ce4dda99 --- /dev/null +++ b/apps/terminal_clock/app.js @@ -0,0 +1,140 @@ +var locale = require("locale"); +var fontColor = "#00FF00"; +var startY = 30; +var paddingY = 2; +var font6x8At4Size = 32; +var font6x8At2Size = 18; +var heartRate = 0; + + +function setFontSize(pos){ + if(pos == 1) + g.setFont("6x8", 4); + else + g.setFont("6x8", 2); +} + +function clearField(pos){ + var yStartPos = startY + + paddingY * (pos - 1) + + font6x8At4Size * Math.min(1, pos-1) + + font6x8At2Size * Math.max(0, pos-2); + var yEndPos = startY + + paddingY * (pos - 1) + + font6x8At4Size * Math.min(1, pos) + + font6x8At2Size * Math.max(0, pos-1); + g.clearRect(0, yStartPos, 240, yEndPos); +} + +function clearWatchIfNeeded(now){ + if(now.getMinutes() % 10 == 0) + g.clearRect(0, 0, 240, 240); +} + +function drawLine(line, pos){ + setFontSize(pos); + var yPos = startY + + paddingY * (pos - 1) + + font6x8At4Size * Math.min(1, pos-1) + + font6x8At2Size * Math.max(0, pos-2); + g.drawString(line, 5, yPos, true); +} + +function drawTime(now, pos){ + var h = now.getHours(); + var m = now.getMinutes(); + var time = ">" + (""+h).substr(-2) + ":" + ("0"+m).substr(-2); + drawLine(time, pos); +} + +function drawDate(now, pos){ + var dow = locale.dow(now, 1); + var date = locale.date(now, 1).substr(0,6) + locale.date(now, 1).substr(-2); + var locale_date = ">" + dow + " " + date; + drawLine(locale_date, pos); +} + +function drawInput(now, pos){ + clearField(pos); + drawLine(">", pos); +} + +function drawStepCount(pos){ + var health = Bangle.getHealthStatus("day"); + var steps_formated = ">Steps: " + health.steps; + drawLine(steps_formated, pos); +} + +function drawHRM(pos){ + clearField(pos); + if(heartRate != 0) + drawLine(">HR: " + parseInt(heartRate), pos); + else + drawLine(">HR: unknown", pos); +} + +function drawActivity(pos){ + clearField(pos); + var health = Bangle.getHealthStatus('last'); + var steps_formated = ">Activity: " + parseInt(health.movement/10); + drawLine(steps_formated, pos); +} + + +function draw(){ + // console.log("in draw"); + // console.log(settings); + var curPos = 1; + g.reset(); + g.setFontAlign(-1, -1); + g.setColor(fontColor); + var now = new Date(); + clearWatchIfNeeded(now); // mostly to not have issues when changing days + drawTime(now, curPos); + curPos++; + if(settings.showDate == "Yes"){ + drawDate(now, curPos); + curPos++; + } + if(settings.showHRM == "Yes"){ + drawHRM(curPos); + curPos++; + } + if(settings.showActivity == "Yes"){ + drawActivity(curPos); + curPos++; + } + if(settings.showStepCount == "Yes"){ + drawStepCount(curPos); + curPos++; + } + drawInput(now, curPos); +} + + +Bangle.on('HRM',function(hrmInfo) { + if(hrmInfo.confidence >= settings.HRMinConfidence) + heartRate = hrmInfo.bpm; +}); + + +// Clear the screen once, at startup +g.clear(); +// load the settings +var settings = Object.assign({ + // default values + HRMinConfidence: 40, + showDate: "Yes", + showHRM: "Yes", + showActivity: "Yes", + showStepCount: "Yes", +}, require('Storage').readJSON("terminal_clock.json", true) || {}); +// draw immediately at first +draw(); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +var secondInterval = setInterval(draw, 10000); diff --git a/apps/terminal_clock/icon.png b/apps/terminal_clock/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5d4507ead49ee014025a0fa2b84dbcad8c84ffde GIT binary patch literal 1022 zcmVEX>4Tx04R}tkv&MmKpe$iQ;Q;12Rn#3WT@g`K~%(1t5Adrp;l;qmz@OipZjz4s5y%P0g-r?8KzCVK|H-_ z8=UuvBdjQ^#OK6gCS8#Dk?V@bZ=4G*3p_Jorc?985n{2>#!4HrqNx#25l2-`r+gvf zvC4UivsSLM<~{if!#RCrnd>x%kia6AAVGwJDoQBBMvPXS6bmWZkNfxsUB5&wg0*#vEd>=bb;{*sk16O*>U#SB#pQP7X zTJ#9$+XgPKTbi;5TYmFU@LfSVzh$kB@)AYh`V?0RU1Y%RvpmaQ7*&~%&a=HHorcK#jM+0OErmul7? z)L|ct{Iq~aSQZb+Pc^F!XV3%!GjQPT_#a&Eo&sA5ukT sR_^}LCi*77Ku?kO+iVN(Y-f4x69vDfv1!0RQ2+n{07*qoM6N<$f^#X*z5oCK literal 0 HcmV?d00001 diff --git a/apps/terminal_clock/metadata.json b/apps/terminal_clock/metadata.json new file mode 100644 index 000000000..4e957edce --- /dev/null +++ b/apps/terminal_clock/metadata.json @@ -0,0 +1,21 @@ +{ "id": "terminal_clock", + "name": "Terminal Clock", + "shortName":"Terminal Clock", + "icon": "icon.png", + "version":"0.01", + "type": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "description": "A terminal clock displaying multiple informations", + "storage": [ + {"name": "terminal_clock.app.js","url": "app.js"}, + {"name": "terminal_clock.settings.js", "url": "settings.js"}, + {"name": "terminal_clock.img","url": "app-icon.js","evaluate": true} + ], + "data": [ + {"name": "terminal_clock.json"}, + ], + "screenshots": [ + {"url": "screenshot1.png"}, + {"url": "screenshot2.png"} + ] +} diff --git a/apps/terminal_clock/screenshot1.png b/apps/terminal_clock/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..874114483fbe5c9523f428938bae8928020c3aa0 GIT binary patch literal 3190 zcmds4`Crmm7sl^=OSBw8({s95Ckx{TD6G`SE>bNRFL zR_y4usZ~r0%{YBQAwZ%JwDjJ809W0C z(2M|}NC(!MvXD!M(8Q2`xx-fi8%JP))HG-_LQv_$!$0ykF>X48Nv)_md%JvZlfkCY8r5>kpQUv`sglf z$T1Ep2WlGE*p~trwno*lty@%M_B9$)RNS9lrRV_!bOW z%@eTt#=6Jgs`k%B$Je|u3}ww^iwh+Y+@0K62|Z099@qb}T{zg_gsu_nqX`2gQ>vAX zuG7u>%#psyinCdt8bQxk?W`7a(V9s9GFPM)spwTYuo6BBB_8kw1Gf-~K7e5fpAbR( zq;jPZSSdKn_z;j!yfsY~k%PTQ`Z$OUF?DCwmsKisNT^nGEbL%p4uTHX#E$Wl@?(uV zAGy$Uj!0Z|54tVg%YJ(~HFU*t9tMC}hsy00WgwI)>Shb<^}l zrC(55De3oD#`9Ad?DX0({7{lB*I3v-^Wf zT2JZcbAvO8OA8JAj=zMtS1J0Z zyy~T>Gk$TeycE`32wx*1JT%;tVZW_n+dr9ox1WN2|FjwfBu*!kq zRU%10eX%~dCB%=~R*&oGftk-6)o833_sQNu>H&$XtiUCj#A;>Q4TZZJtt)|RTHnK9K^B zj$%S2{B-0C{W1n0RIevlz*~oFV*0C!Wxv|TfU{mXeC11asCzMX*5aMd=t*aQV`x4< zy~6+nU|{Br3)lzyv;ddDve)n_tK>z`G)ES0HEzZdoz)ykjFOoJ+v|#XP&u(WsrRyAnniU{k`xK#kb?chKmnpGbyF( zByzOEzl+n?T+p5W>Bp71@m;HydH9W+NvZC5ldcFq)=7UVN0G?Vq$emO_$k9Uc^PNG z1B>4M;=qX3!wp0;gI4#`KKRsK^zy}g-(x%#r5Zd~iw8xmYyoG+jOjSda$q27y!3{C zcII6O4M&s=o{bk2fJJnC&n^SvGF7ZH``~Gv+|<~N8X4xyQsGgZl3K&b~@k%PL#|dL6459Rdt5@d5rDhB{Ompl58S0V@%a3 z>y*5qykuTOHKKrbcnXY4(cV38o3#feC>=N?qTkEZgAb!|*O8r7nM({}WrBzJ;Bo`> z@l1VG@VPPWuaiXU{)IYC!1o}uE}z>*k_0c5tc6q)ZR8$lcK-%D1;xa7MFNx5!#XNc zAouR?@@_VaJpS2$JTBb>kI+1&!9!g@3v33Vb-Q5+M{@W@zgVYgoXr|X(g_fv2lj8? zlM43l!b+U}Mwrlk(do@B3dxk6(N?>5hL%}xFBl!L#7dT~ETDG++)}31+4hMOuVlxS zx(czw%I!X4ht%aYulr*}&|*=V^Y~zrfY5iR===6@4MSfzOrIt5k~Tp*N^Llsizzp6 z+rO@bh*Q|if709$E-SQ*0}&!Bd#sP%f?zE77?{r!&iijNm7yYkHYA^-jUZ13O7O+F zEeG0m70!;AQzm4cm$nhM1*I}FiSKrvVJ|U}EcqRcDDP16d4C2-27QyzQ5w-I%w8nF zotx@M$^H`2QIT)L82BE7NmrLwsFkW@8SJlca})UroUX2=T45!&PX$j{3PfW2iLf~f zUJ#duz7Se1ZKcEoGaVzMPB{$9pR^;jfb7a*ev6&7YEOcOwK&Jn7jUQJGCyG@+qD3@ zO(4QhqeJIAun#Sh2>|%pRbstNqes-$Z4nZthNAiho0^9-Xp)_{NF!q4} z#{KCs%Xy2h1OtF!I?(;Q_bN}k>Nd}%V{rgDTXJBZ<$Qq#jlU)p7;Oc<*QDp?MEEwq zRnsa&#}4LS4QcY0?9`kFeUb<}_yaaD20gb!T9nVJQtf358lv$k-vGU1tX)rAV&Fu5D&ssGzjgs_P@Nl`#)$<|Cd)-`^xgw WcOKbI6JP!lkO03x-v;lPYySl!2HfNT literal 0 HcmV?d00001 diff --git a/apps/terminal_clock/screenshot2.png b/apps/terminal_clock/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..6d1b5f040316615a683e5ef1e0fbc332908fa7eb GIT binary patch literal 2628 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 back(), + 'HR confidence': { + value: 40|settings.HRMinConfidence, // 0| converts undefined to 0 + min: 0, max: 100, + onchange: v => { + settings.HRMinConfidence = v; + writeSettings(); + } + }, + 'Show date': { + value: !!settings.showDate, + format: v => v?"Yes":"No", + onchange: v => { + settings.showDate = v; + writeSettings(); + } + }, + 'Show HRM': { + value: !!settings.showHRM, + format: v => v?"Yes":"No", + onchange: v => { + settings.showHRM = v; + writeSettings(); + } + }, + 'Show Activity': { + value: !!settings.showActivity, + format: v => v?"Yes":"No", + onchange: v => { + settings.showActivity = v; + writeSettings(); + } + }, + 'Show Steps': { + value: !!settings.showStepCount, + format: v => v?"Yes":"No", + onchange: v => { + settings.showStepCount = v; + writeSettings(); + } + } + }); +}) From fdbfccda481c2fe4538d977f336dd08c6f347fca Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sun, 13 Feb 2022 16:21:46 +0100 Subject: [PATCH 083/447] Trying to fix the banglejs app store after breaking it with the terminalclock app --- apps/terminal_clock/metadata.json | 21 --------------- .../ChangeLog | 0 .../README.md | 0 .../app-icon.js | 0 apps/{terminal_clock => terminalclock}/app.js | 2 +- .../icon.png => terminalclock/app.png} | Bin apps/terminalclock/metadata.json | 24 ++++++++++++++++++ .../screenshot1.png | Bin .../screenshot2.png | Bin .../settings.js | 2 +- 10 files changed, 26 insertions(+), 23 deletions(-) delete mode 100644 apps/terminal_clock/metadata.json rename apps/{terminal_clock => terminalclock}/ChangeLog (100%) rename apps/{terminal_clock => terminalclock}/README.md (100%) rename apps/{terminal_clock => terminalclock}/app-icon.js (100%) rename apps/{terminal_clock => terminalclock}/app.js (97%) rename apps/{terminal_clock/icon.png => terminalclock/app.png} (100%) create mode 100644 apps/terminalclock/metadata.json rename apps/{terminal_clock => terminalclock}/screenshot1.png (100%) rename apps/{terminal_clock => terminalclock}/screenshot2.png (100%) rename apps/{terminal_clock => terminalclock}/settings.js (97%) diff --git a/apps/terminal_clock/metadata.json b/apps/terminal_clock/metadata.json deleted file mode 100644 index 4e957edce..000000000 --- a/apps/terminal_clock/metadata.json +++ /dev/null @@ -1,21 +0,0 @@ -{ "id": "terminal_clock", - "name": "Terminal Clock", - "shortName":"Terminal Clock", - "icon": "icon.png", - "version":"0.01", - "type": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "description": "A terminal clock displaying multiple informations", - "storage": [ - {"name": "terminal_clock.app.js","url": "app.js"}, - {"name": "terminal_clock.settings.js", "url": "settings.js"}, - {"name": "terminal_clock.img","url": "app-icon.js","evaluate": true} - ], - "data": [ - {"name": "terminal_clock.json"}, - ], - "screenshots": [ - {"url": "screenshot1.png"}, - {"url": "screenshot2.png"} - ] -} diff --git a/apps/terminal_clock/ChangeLog b/apps/terminalclock/ChangeLog similarity index 100% rename from apps/terminal_clock/ChangeLog rename to apps/terminalclock/ChangeLog diff --git a/apps/terminal_clock/README.md b/apps/terminalclock/README.md similarity index 100% rename from apps/terminal_clock/README.md rename to apps/terminalclock/README.md diff --git a/apps/terminal_clock/app-icon.js b/apps/terminalclock/app-icon.js similarity index 100% rename from apps/terminal_clock/app-icon.js rename to apps/terminalclock/app-icon.js diff --git a/apps/terminal_clock/app.js b/apps/terminalclock/app.js similarity index 97% rename from apps/terminal_clock/app.js rename to apps/terminalclock/app.js index 2ce4dda99..8729deace 100644 --- a/apps/terminal_clock/app.js +++ b/apps/terminalclock/app.js @@ -128,7 +128,7 @@ var settings = Object.assign({ showHRM: "Yes", showActivity: "Yes", showStepCount: "Yes", -}, require('Storage').readJSON("terminal_clock.json", true) || {}); +}, require('Storage').readJSON("terminalclock.json", true) || {}); // draw immediately at first draw(); // Show launcher when middle button pressed diff --git a/apps/terminal_clock/icon.png b/apps/terminalclock/app.png similarity index 100% rename from apps/terminal_clock/icon.png rename to apps/terminalclock/app.png diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json new file mode 100644 index 000000000..4a5948159 --- /dev/null +++ b/apps/terminalclock/metadata.json @@ -0,0 +1,24 @@ +{ + "id": "terminalclock", + "name": "Terminal Clock", + "shortName":"TerminalClock", + "icon": "app.png", + "version":"0.01", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "description": "A terminal cli like clock displaying multiple sensor data", + "readme": "README.md", + "storage": [ + {"name": "terminalclock.app.js","url": "app.js"}, + {"name": "terminalclock.settings.js","url": "settings.js"}, + {"name": "terminalclock.img","url": "app-icon.js","evaluate": true} + ], + "data": [ + {"name": "terminalclock.json"}, + ], + "screenshots": [ + {"url": "screenshot1.png"}, + {"url": "screenshot2.png"} + ] +} diff --git a/apps/terminal_clock/screenshot1.png b/apps/terminalclock/screenshot1.png similarity index 100% rename from apps/terminal_clock/screenshot1.png rename to apps/terminalclock/screenshot1.png diff --git a/apps/terminal_clock/screenshot2.png b/apps/terminalclock/screenshot2.png similarity index 100% rename from apps/terminal_clock/screenshot2.png rename to apps/terminalclock/screenshot2.png diff --git a/apps/terminal_clock/settings.js b/apps/terminalclock/settings.js similarity index 97% rename from apps/terminal_clock/settings.js rename to apps/terminalclock/settings.js index 8f6aa9467..b4fa1a464 100644 --- a/apps/terminal_clock/settings.js +++ b/apps/terminalclock/settings.js @@ -1,5 +1,5 @@ (function(back) { - var FILE = "terminal_clock.json"; + var FILE = "terminalclock.json"; // Load settings var settings = Object.assign({ HRMinConfidence: 40, From 6455e0db319bd436a23d19c614068b835c7b3e2a Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sun, 13 Feb 2022 16:46:49 +0100 Subject: [PATCH 084/447] use the compression on the image for the terminalclock app --- apps/terminalclock/app-icon.js | 2 +- apps/terminalclock/metadata.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/terminalclock/app-icon.js b/apps/terminalclock/app-icon.js index dd5bd596e..5e57a4b7c 100644 --- a/apps/terminalclock/app-icon.js +++ b/apps/terminalclock/app-icon.js @@ -1 +1 @@ -E.toArrayBuffer(atob("MDCEAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3d3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d3ZmZgAAAAAAAAAAAAAAAAAAAAAAAGZmZ3d3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3d3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3cAAAAAAAAAAAAAAAAAAAAAAABnd3d3d3cAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAAAABnd3dwAAAAAAAAAAAAAAAAAAAAAAAGZmZ3d3dwAAAAAAAAAAAAAAAAAAAAAAAHd3d3ZmZgAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d2AAAAAAAAAAAAAAAAAAAAAAAAd3d3d3d2AAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) +require("heatshrink").decompress(atob("mEwghC/AHsHu93uAX/C+wACsAaTC/4Xiu1mswXRCYNnDQQxTgwX/C8QABuAaTg4X/C7Z3Xa/4Xds1ms4XUCgV2DYIXUsBdTC/4AEg4VCC61wIiYX/C74A/AGIA==")) diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json index 4a5948159..93578148c 100644 --- a/apps/terminalclock/metadata.json +++ b/apps/terminalclock/metadata.json @@ -1,13 +1,13 @@ { "id": "terminalclock", "name": "Terminal Clock", - "shortName":"TerminalClock", - "icon": "app.png", + "shortName":"Terminal Clock", + "description": "A terminal cli like clock displaying multiple sensor data", "version":"0.01", + "icon": "app.png", "type": "clock", "tags": "clock", "supports": ["BANGLEJS","BANGLEJS2"], - "description": "A terminal cli like clock displaying multiple sensor data", "readme": "README.md", "storage": [ {"name": "terminalclock.app.js","url": "app.js"}, @@ -20,5 +20,5 @@ "screenshots": [ {"url": "screenshot1.png"}, {"url": "screenshot2.png"} - ] + ] } From 189141c976c1555b56defc9c87e5b9e085d7b4b9 Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sun, 13 Feb 2022 16:53:54 +0100 Subject: [PATCH 085/447] Remove the trailing comma making the metadata.json invalid for the terminalclock app --- apps/terminalclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json index 93578148c..43f923d2f 100644 --- a/apps/terminalclock/metadata.json +++ b/apps/terminalclock/metadata.json @@ -15,7 +15,7 @@ {"name": "terminalclock.img","url": "app-icon.js","evaluate": true} ], "data": [ - {"name": "terminalclock.json"}, + {"name": "terminalclock.json"} ], "screenshots": [ {"url": "screenshot1.png"}, From 1446533c1d67deb30b6d2151f49ca05ead27ae57 Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sun, 13 Feb 2022 17:06:07 +0100 Subject: [PATCH 086/447] fix the settings reading for terminalclock app --- apps/terminalclock/app.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index 8729deace..f999593d7 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -92,19 +92,19 @@ function draw(){ clearWatchIfNeeded(now); // mostly to not have issues when changing days drawTime(now, curPos); curPos++; - if(settings.showDate == "Yes"){ + if(settings.showDate){ drawDate(now, curPos); curPos++; } - if(settings.showHRM == "Yes"){ + if(settings.showHRM){ drawHRM(curPos); curPos++; } - if(settings.showActivity == "Yes"){ + if(settings.showActivity){ drawActivity(curPos); curPos++; } - if(settings.showStepCount == "Yes"){ + if(settings.showStepCount){ drawStepCount(curPos); curPos++; } @@ -124,10 +124,10 @@ g.clear(); var settings = Object.assign({ // default values HRMinConfidence: 40, - showDate: "Yes", - showHRM: "Yes", - showActivity: "Yes", - showStepCount: "Yes", + showDate: true, + showHRM: true, + showActivity: true, + showStepCount: true, }, require('Storage').readJSON("terminalclock.json", true) || {}); // draw immediately at first draw(); From 3aafe3a3b364aaedb499e94670e2980eafef5809 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:28:18 +0100 Subject: [PATCH 087/447] Add files via upload --- apps/7x7dotsclock/dotfontclock.png | Bin 0 -> 16937 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/7x7dotsclock/dotfontclock.png diff --git a/apps/7x7dotsclock/dotfontclock.png b/apps/7x7dotsclock/dotfontclock.png new file mode 100644 index 0000000000000000000000000000000000000000..c11d7708ed45a5b06ec6153839e3c050fcdc241f GIT binary patch literal 16937 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 Date: Tue, 15 Feb 2022 11:35:26 +0100 Subject: [PATCH 088/447] Update 7x7dotsclock.info --- apps/7x7dotsclock/7x7dotsclock.info | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.info b/apps/7x7dotsclock/7x7dotsclock.info index 9a90aac67..46d719749 100644 --- a/apps/7x7dotsclock/7x7dotsclock.info +++ b/apps/7x7dotsclock/7x7dotsclock.info @@ -1,15 +1,7 @@ -{ "id": "7x7dotsclock", - "name": "7x7 dots clock", - "shortName":"7x7 dots clock", +{ + "id":"7x7dotsclock", + "name":"7x7 dots clock", "type":"clock", - "version":"0.01", - "description": "A clock with a big 7x7 dots font", - "icon": "7x7dotsclock.img", - "tags": "", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, - {"name":"7x7dotsclock.img","url":"7x7dotsclock-icon.js","evaluate":true} - ] -} \ No newline at end of file + "src":"dotfontclock.app.js", + "icon":"dotfontclock.img" +} From 467e20019942acafb267168740049864b6c0efe9 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:36:37 +0100 Subject: [PATCH 089/447] Create metadata.json --- apps/7x7dotsclock/7x7dotsclock/metadata.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 apps/7x7dotsclock/7x7dotsclock/metadata.json diff --git a/apps/7x7dotsclock/7x7dotsclock/metadata.json b/apps/7x7dotsclock/7x7dotsclock/metadata.json new file mode 100644 index 000000000..74cb7605c --- /dev/null +++ b/apps/7x7dotsclock/7x7dotsclock/metadata.json @@ -0,0 +1,16 @@ +{ "id": "7y7dotsclock", + "name": "7x7 dots Clock", + "shortName":"7x7 dots Clock", + "version":"0.01", + "description": "A clock with a big 7x7 dots Font", + "icon": "dotfontclock.png", + "tags": "clock", + "type": "clock", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, + {"name":"7x7dotsclock.info","url":"7x7dotsclock.info"}, + {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} + ] +} From 835d80036ed7f1c0ecb228155cfcce5b8e4382dd Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:38:11 +0100 Subject: [PATCH 090/447] Create metadata.json --- apps/7x7dotsclock/metadata.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 apps/7x7dotsclock/metadata.json diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json new file mode 100644 index 000000000..74cb7605c --- /dev/null +++ b/apps/7x7dotsclock/metadata.json @@ -0,0 +1,16 @@ +{ "id": "7y7dotsclock", + "name": "7x7 dots Clock", + "shortName":"7x7 dots Clock", + "version":"0.01", + "description": "A clock with a big 7x7 dots Font", + "icon": "dotfontclock.png", + "tags": "clock", + "type": "clock", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, + {"name":"7x7dotsclock.info","url":"7x7dotsclock.info"}, + {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} + ] +} From 2ae84804be6eab3fa9872947d8463d7fd502414f Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:38:31 +0100 Subject: [PATCH 091/447] Delete apps/7x7dotsclock/7x7dotsclock directory --- apps/7x7dotsclock/7x7dotsclock/metadata.json | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 apps/7x7dotsclock/7x7dotsclock/metadata.json diff --git a/apps/7x7dotsclock/7x7dotsclock/metadata.json b/apps/7x7dotsclock/7x7dotsclock/metadata.json deleted file mode 100644 index 74cb7605c..000000000 --- a/apps/7x7dotsclock/7x7dotsclock/metadata.json +++ /dev/null @@ -1,16 +0,0 @@ -{ "id": "7y7dotsclock", - "name": "7x7 dots Clock", - "shortName":"7x7 dots Clock", - "version":"0.01", - "description": "A clock with a big 7x7 dots Font", - "icon": "dotfontclock.png", - "tags": "clock", - "type": "clock", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, - {"name":"7x7dotsclock.info","url":"7x7dotsclock.info"}, - {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} - ] -} From 0c3c9e9977bb2516a7437c18c010e737a404575f Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:41:31 +0100 Subject: [PATCH 092/447] Update metadata.json --- apps/7x7dotsclock/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 74cb7605c..2a9b48bbb 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -1,9 +1,9 @@ -{ "id": "7y7dotsclock", +{ "id": "7x7dotsclock", "name": "7x7 dots Clock", "shortName":"7x7 dots Clock", "version":"0.01", "description": "A clock with a big 7x7 dots Font", - "icon": "dotfontclock.png", + "icon": "dotsfontclock.png", "tags": "clock", "type": "clock", "supports" : ["BANGLEJS2"], From 09657a7d1e67c52349007c928630676f751c4903 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:42:11 +0100 Subject: [PATCH 093/447] Add files via upload --- apps/7x7dotsclock/dotsfontclock.png | Bin 0 -> 16937 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/7x7dotsclock/dotsfontclock.png diff --git a/apps/7x7dotsclock/dotsfontclock.png b/apps/7x7dotsclock/dotsfontclock.png new file mode 100644 index 0000000000000000000000000000000000000000..c11d7708ed45a5b06ec6153839e3c050fcdc241f GIT binary patch literal 16937 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 Date: Tue, 15 Feb 2022 11:45:00 +0100 Subject: [PATCH 094/447] Create ChangeLog --- apps/7x7dotsclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/7x7dotsclock/ChangeLog diff --git a/apps/7x7dotsclock/ChangeLog b/apps/7x7dotsclock/ChangeLog new file mode 100644 index 000000000..50c5eca4a --- /dev/null +++ b/apps/7x7dotsclock/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version for upload From 49a042502ed5c16091faac11aae3e8374c2b60fa Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:49:33 +0100 Subject: [PATCH 095/447] Create README.md --- apps/7x7dotsclock/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/7x7dotsclock/README.md diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md new file mode 100644 index 000000000..85d93cdb3 --- /dev/null +++ b/apps/7x7dotsclock/README.md @@ -0,0 +1,11 @@ +# 7x7 dots clock + +![](dotsfontclock.png) + +A Clock with big numbers made of 7x7 dots +system widgeds ar not (yet) supported +when screen is locked it shows a full screen mode +by swiping you can open cusomizable apps + +Contributors: +* pkkpp From 0bdf42954b175da32f77fe1d5e5e8612e1e1dd9b Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:49:55 +0100 Subject: [PATCH 096/447] Update README.md --- apps/7x7dotsclock/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md index 85d93cdb3..8e51f46da 100644 --- a/apps/7x7dotsclock/README.md +++ b/apps/7x7dotsclock/README.md @@ -2,10 +2,10 @@ ![](dotsfontclock.png) -A Clock with big numbers made of 7x7 dots -system widgeds ar not (yet) supported -when screen is locked it shows a full screen mode -by swiping you can open cusomizable apps +* A Clock with big numbers made of 7x7 dots +* system widgeds ar not (yet) supported +* when screen is locked it shows a full screen mode +* by swiping you can open cusomizable apps Contributors: * pkkpp From 9d4b2d57e1d5c8bccd526cf0d0975700413ddc18 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:54:35 +0100 Subject: [PATCH 097/447] Update metadata.json --- apps/7x7dotsclock/metadata.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 2a9b48bbb..5c64ed6f4 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -10,7 +10,6 @@ "readme": "README.md", "storage": [ {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, - {"name":"7x7dotsclock.info","url":"7x7dotsclock.info"}, {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} ] } From 1a3272025c23dc03138fc0b55210f8c53a51a940 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 12:03:35 +0100 Subject: [PATCH 098/447] Delete dotfontclock.png --- apps/7x7dotsclock/dotfontclock.png | Bin 16937 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/7x7dotsclock/dotfontclock.png diff --git a/apps/7x7dotsclock/dotfontclock.png b/apps/7x7dotsclock/dotfontclock.png deleted file mode 100644 index c11d7708ed45a5b06ec6153839e3c050fcdc241f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16937 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 Date: Tue, 15 Feb 2022 12:05:58 +0100 Subject: [PATCH 099/447] Update 7x7dotsclock.img.js --- apps/7x7dotsclock/7x7dotsclock.img.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.img.js b/apps/7x7dotsclock/7x7dotsclock.img.js index 46c793905..eb66b813e 100644 --- a/apps/7x7dotsclock/7x7dotsclock.img.js +++ b/apps/7x7dotsclock/7x7dotsclock.img.js @@ -1,5 +1 @@ -{ - width : 48, height : 48, bpp : 8, - transparent : 254, - buffer : require("heatshrink").decompress(atob("AH4A/AH4A/AH4APlYABAYYAFBIwUEERgQJ64AB1gCEAAYGKFxQUGF5AAUDQVWAQOBAQVWF44PBqwCBLgpRDMxhNGL44RJL7oCDR5AMBlYCBF7TiCF4aPKF4RpCwICCAwOsAwVWAwQQCEISPKWQzKCACZ9GL4YRNII51CPI0rAwQDBX6CPhBISPYd7RfUF7S/UNgqMBQ4KMB1krAQOBBIQGDF5oiDR5jvEAYYCFBIQIER6g8DBIIKBAQkrBIorCR7g2GAxAdGR5ShGd7SMCEgWBR5R6CLBIJFAw7veF6b7GX5AMBBYKPwbwwGFwIJFAwaPKDYwNFgWBq8Aq4CBqwGBlYGCAQMsCAssLwQEBllXKIILBEQ0tBAIXCwYABrACBwQGCAAQGDrIGFFwISFABAlCAA1ZAAIFRKIIXVGwVYAogDBCIIGBC4gQDgB5BFJQiFBYQkCCIYFFRYQKHL4MtF5YiFCIwAUR4QAUlwCBJIODq7iBrAgCqwGCd48BBYSDBwQLCRIQbCd40Aq0AgErAYWBAQNWAwVWlZfHBYQVEwMrBAYXBF40sq9XlVXrErAwMtCINXQgIABboq/BBYUsloCBDAQiCDYRiCYobvMIYIKEF4gfBDhr1PApwvHAp7PFawVZawuCboyxBDwb7ED4YFKAAkBq8BgEsa4MBq0BAQQJDL4QAEgTpBCIj1BAwIXDF4xOBEIMrqoDCAQoJCF5EqCIgFBgAUBC4RgCbwVYdIQGBRAQJDAwhLBWYgVCVAgFBUga0Ed9ovvAwQJDABAXEaActCpYYDB5wAOd44APlw4Blo6BluCZQhTCrAQBAwkAgQECDAOCDA4lDBAVYA")) -} +require("heatshrink").decompress(atob("AH4A/AH4A/AH4APlYABAYYAFBIwUEERgQJ64AB1gCEAAYGKFxQUGF5AAUDQVWAQOBAQVWF44PBqwCBLgpRDMxhNGL44RJL7oCDR5AMBlYCBF7TiCF4aPKF4RpCwICCAwOsAwVWAwQQCEISPKWQzKCACZ9GL4YRNII51CPI0rAwQDBX6CPhBISPYd7RfUF7S/UNgqMBQ4KMB1krAQOBBIQGDF5oiDR5jvEAYYCFBIQIER6g8DBIIKBAQkrBIorCR7g2GAxAdGR5ShGd7SMCEgWBR5R6CLBIJFAw7veF6b7GX5AMBBYKPwbwwGFwIJFAwaPKDYwNFgWBq8Aq4CBqwGBlYGCAQMsCAssLwQEBllXKIILBEQ0tBAIXCwYABrACBwQGCAAQGDrIGFFwISFABAlCAA1ZAAIFRKIIXVGwVYAogDBCIIGBC4gQDgB5BFJQiFBYQkCCIYFFRYQKHL4MtF5YiFCIwAUR4QAUlwCBJIODq7iBrAgCqwGCd48BBYSDBwQLCRIQbCd40Aq0AgErAYWBAQNWAwVWlZfHBYQVEwMrBAYXBF40sq9XlVXrErAwMtCINXQgIABboq/BBYUsloCBDAQiCDYRiCYobvMIYIKEF4gfBDhr1PApwvHAp7PFawVZawuCboyxBDwb7ED4YFKAAkBq8BgEsa4MBq0BAQQJDL4QAEgTpBCIj1BAwIXDF4xOBEIMrqoDCAQoJCF5EqCIgFBgAUBC4RgCbwVYdIQGBRAQJDAwhLBWYgVCVAgFBUga0Ed9ovvAwQJDABAXEaActCpYYDB5wAOd44APlw4Blo6BluCZQhTCrAQBAwkAgQECDAOCDA4lDBAVYA")) From 94e61fb1d8b9741f14b99658a1926ef3ae1e417a Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:30:11 +0100 Subject: [PATCH 100/447] Add files via upload --- apps/7x7dotsclock/dotsfontclock.png | Bin 16937 -> 26349 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/7x7dotsclock/dotsfontclock.png b/apps/7x7dotsclock/dotsfontclock.png index c11d7708ed45a5b06ec6153839e3c050fcdc241f..af8fa61bafa5395c9e4bbb66e3b076f1a350fa8e 100644 GIT binary patch literal 26349 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 YhZN0^0eJbJANVNpGD_0rlEy**4>3ZR?f?J) literal 16937 zcmV)QK(xP!P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+SQy}mL@rloZq>MS%ULUE{E51v;!?)pTRvcv#NS# z)RJD5*`1jc@rOH|01RdT=fBGlc zpY|($-{Qaj@^$y?8-Xvy-=D1G`~2YR`S%a}+{4eme%-b2JE46S`o8gV!Kgb2{;~gD zBwr8j*M0gf)X)2m(p&v=sWZHPukVAll<)ts+NFP8ME~vn{6ebi($0J;hH#>fkNw%+ z6-52t$HD&te}-7X&sTD6&c5Wom9QaydAy&$pXbjF`pYK&{LB4)_kaECZ<`;+_x1R< zy)54z@sEG`4WIw@=Gzwk)g8VSg};7d$FTqLIN$&8-R<7|B^fP>L zvgOf!tnjAHH7Lt``9qhVC5mEFtLEoIcydgQY2bj z4K3*2{7m)s*^omC`ZCyrA#yCSVw)ZZ#!4yUKQ%RcXylkv&bj28o69|q5=$z%lv0a8 zZq!&)&9&58TkUnU*iy@_wAxzhZS>G17?^wMwYT2;7{Lv0G`QB_^MkL-Q4u|ZG3IpW$;UP{JQMBK6lSOt12d78FdX@WaM?Z zb#EuuhC9zWPti)^KEp0Tc8HZl5Ni=v(3j2~@gARV$~f75;#@I4drdOkE#u(HA@*M4 z&0e2R>)>kqM4Go%$IsSVbJn-!o%Rs|B@yajtU6L&iRaGwgmq$E-EIbau82#AXEpw~ zD?1*y<+}MEi%6`QIN`H+^Wb@P*?xX5KL@*B&ofv7DZTlsPq79*;`q!J{~B`9TJnCz z8GLGO(qw|uoTuv(&!`Eql6N{S^SuUqRKM&V`$+WhX7Vb<$=#J+hqG71Lr->CvyX58;DltmPubX|HE2GCdHcB8*L_W1MI&E3=1CKj>dwB^oYE=sP) zUuuRX5ir4PC3;E=(Yn)oSDtxnE*bB1whcu6{vsNj$n40IiGi}oBgFz}@{_M)$*mMW zefyNf(6jyRe*VGVdCt5e#-9y*_u~G3mb-8m*62sg++^<+Qw<p1Fw$5a z{IP-_#}9Ibez9!{nt4fZKz;WD{*>b0&n0l>!vVh7ew)huX{)iTA91fdQ}cea>wn#u z9KW5JKRfe#W8BZqthEz%YS^hCFs92)6HF|IK=DH$`Az-HS_G{Ct237!dz~H$rUW1B z{zO~K8o$?)|8Awf8_BhCYR%`8+K)d8pCfw6==ydpaR?}e`E?2A#+DEG=kxs?`Pl}~ zKC$n`juxoMVh2gvW0zZqu>~z4Tth0cj~SDA2lhEiCtM~>OD3lvcy@Lf1e(5$Ju)sx zy!N~*!JpUAqdbKl$~+Gwq>IzW)jYn$C2?`Fev%CmZ#sF7ZzYE{xXRhO3K+qrBv@`+ zEc0kFBpXBoJPJa!3^|FijakAeiUJ4T2{I8yC+r5T<3N0*vjq6 zSqAbW@q|l|H=$Z57PQe+1hjS$LPzPT5FPA0z^kARyTa>O04~sTTJAKz5o2-JnbSie zY}zGoSfL4eU|pUM!u5cqIf#+rG28+p>#BIt5HBE$WWU29F-)w@M$0y2tdj$b>~aOr zw~WjVv7*X@B<*(h=zP2_XNcO)fPcrL-khjfdVSId4}Ry{`UJ*G#-M$A^6gBylK5tn zsO$O^wrU4_a0F`Tr0{`3D*jfqto_WzudV8dUxbY(A5A^@f_uXf;==UUA%YoQilsQ1 zE9sLU>-Cv1RY?b*$7;vrRquE zwPk((fQuw6gjp{qcffGo$P@Uc^TOvyR`T@a z@(poz?4Klw>Ry(#E8tXjfvTkhkx3xA^nxk_Sdd_Tl5ip_fu|8y_HKaCXI7kDhFFLg zRSjeZ2{cT@otuC*@Mp8f-aQ!*QECxw0M0NITw*|tKwxePdCj;)f})|Wk_t>< z=g%@nEyhNDcO?ZW9dJ+Ezr<2=>nEseLl8nF1EDu0!Wy_9j$n!Ox!ZGfSwb4u$jfo- z6sjN{DwaXUr90UdbGk!h>$!WNMb8qZYb}n zeO^NE`hx20IB`lZeJ1xBzZIb05!fZZv{7c;)v#59NchNTd3_5`R(tV1&PSzydJPy7czV#d!`3^6e=Wa_vBRz+7Z@OTK%Pe+*R0hL^7m$?6 z_c#{$&6SfP;lCl0<3wWuETG_B`zXe}g4B{hU1E&rBw~+mg2f&;XP4NHmX&D%T?i!? zeu11DDNS4=pOsvbxQm&I{HBV}Bab$|ljRCw65N5%3(*$#=s z&cWy)K~m%$?}um+jf)$c4Vp@*fo8B;h{5I|Ncjrb2B}Vv>!j!&4;~3?s-%a|JDdg3 zbW6zwnoq`IyL|Rqxd)v{QT+dngbRSO$9}T(39ujt!KIBahSsL)PoB-j`b0S}MJBok zDKy&s{G|c+q9&I_l0_JJ2w3(=k|zXvY;Ty1Ron>zBvO8aH-gP4o~+=-rweJC@FuDA zH#>T8zw0*+2GvZXpyWhMRUO&Kkr+N9^rPZNGrSnLD(W!XpmX-SGhO>e8JDIG7BI~aveZ`iam2G?(xV-(4T{Ef+LS3 zKVHD0oRUG)s^o)Z3X3dAtomXeSVrOv6T*u23$U&Vjy8cWUSiD4Db`^QP^LZ~qGACj zz>h5*rqH0S&{yp!Oa7@RYydxZAy6UrA^-3r1T#$V!yrsopdT69@}_^e2w8cSs`SsY z;2JB(0XbTJ{h9q;(*B11{U9EGltp15&tQez8Jd<6X&0!!^^vj_6hll}#2Onq4O1J< z#lPm&wdTlKDP>pj65SahAx?&=jcS3F{o8Dwmw-e0 zjI~Mkdvmpyr56A4&)BF0=$}!0t_08Y=Qv1)%e)Bmk!) ziv|+B!bJJi#W%@wNFqRQFBbQtDU}d#)?h&%9p-`USzaVZVNFSKzdORxUylc*h2k4L zG(rh4u0-h~pK+7R$MfOYyjMvBs&hKo2||E!;L&ifz9x?;pulFM-E+tbSOdE>6<@#9 zNa_jsO^n_3`jZ&t?2tVrZb2`*9|gTo?f6#Q@~I06<6}mPv03H9+JZC|9M?tIjLBTw zc3ax7rf(7ZQ8k}7#kMa(-V@NF4$HDr#X;Z;I*7{(bKO8Plm}4d>A})^yRzYgigjq? zmkO02zC>s=Q26}3(M?=0Vp{d1j2X5#5*8af5`cIWxujcJfiKActF-+69D@X-S_AP0 z=D=RT=-@zByy8uU!88Gzo4EzKzfAc7Y%+$lellSL$e@v+;!)Cx>hc zq?mx3N399eUk5Rf8!%#{{osMa_oTBUM3W>DB_=^rP#B5bp;d1wgT0z+GIXs-V2rr; z5hld1pazL|7J1#jT3}~MsYD{1d1qu$K}(43c6EUvh!$u4-5n{^oymqoHe{5Ye#MH{ zazQS&IZh!iRJb6mMinkFVz4^MGk!`U^@`oY%wSx8&yk9fj%)AS(m| zsX0mb1ZjgPY~dss9F5+RAW@Cr@^R*qhTO|1kPvp+OO3IZ!FtTsigRlPtlafw%_N&?m{ zbW2Tq*-`_SJEOu#tY!yGe{?|tf*^3P2jbk4WBVgHiupEaKR%dMc~dDwbRG9-Nka*I zF5MEy0F4VKx8Dy|JfgfGBuJo%`k=zfK3GBj_s&V~`QBKL*X_nQ-s9fj#zV0pjz}`L zT-)Vs&~7#vej8U(t%zj1@A#c;pFfhVdl~usrA_}&rK$U^O`B?O85%-7wYQo`CIe3q z6CpO-#hR5WRH-+p28Zw()2~7Fs~GbLFo@TlRcItb02yFxR01aKN>HIu(-Lc*kkwYq zUYs>)IU-WoUxyVVo`cii7AhPhTosK|@E#0#ua{5bizpTt%~dvh2t^fFgJtF*#uFS& z=7AisIQ%CV^ks|>DM279wO@=Bhyw7UwZewv+gSnE#}a$IgsT*{6L<`N*$uzu^CXIr z-_}ZoTJ~kpCKtsO2^$axC4%)u0I)W&ibJ=~9wj}BSDkE_76i#bA~<~tk6I8UE0&RB zIZAxuPaqaN9?~OMfY>IS&B>+(RGhd=c+^`7hSPiJt70P214mEwAXUUj5RwQoem(i< zSrBZE1%cV08Z5|YKo~|8N!L(OR*aZlD)sH763!?p;Utn^P=~5FJptLYS?SJ^7)Bg^ z#Ya__!879pMHGUhvsJTGDY8bAepSm3Ns6o?{H?JJDpl31iGK1|$6tu8#kwC8wfI>* z!MGH3QdLe;tC5Z|qGBczP&Ez`L^0BIZ*}X_@X$*ycY|GeltyGLkUHeB+9TTw6(NX_ zk{eB%paX%-+X&c#gg*C9cdgH=`h~59?@aAGpXQ!5FXe3skU(}oPtG`?=@N!0B0PA< z94atHh=j)Wl=hb-BYLbX|W2M(o!o{78@lry(HLzzPfN>8s-8p*!Vib5PL$}s2vnK zR6C<(+JV8S>j{kXZhdh;M(x;_jIIpXfki=umQvO~3%!N3y09g%{%4^V)ZA8_@c>Cl z?m0LXaNhVs#OzCuI2l(JWHxYmq35_Je24^Uh2SQliza-38V2Un3Cl+9;junzOW+(2 z8C9$S7dU@bWZ!};sL1`);vu!*iIKE%>fS2=XBVE z>tYGw^=RJ(Gk!YY)?T|Q`p9@F-MRP*ZUim9JCV}xxuyXCyhrU*pjLBgC~Gkdz^uS! zx$gv)KqGahWoU8E!2TRkU&thyVqGug8Sib5;4}w|B7$;>-N2%aX{oU#l~@|eDF7{dpN?K$xax5dL7sI= zge$sdA+#h5f<2n*mPh3ba%+e5l6=|Pw?Zmov~Zi!Z*XV=HD?!056>wr1SL7>y*i(! zuyWSa0~bcjq==WRpNnLL##9j=X_}gyt^1BgRZO_;mlR9Q8d8{{C6!WnsEx-IqnF@8 z2RuM!k|!RtV4BGF{+2^KAvJYp#63okjKBu0pkdW^zl~a<*W+RMkf66t(RZ{Cbhpm& z!indFErBHDcQaTW|~=8b~_Sz1@LxJv?*)}d_1_Kvfr_VMg$`?5FY>`JP&Y$ z%Hbg>HGW?74g-?z%iH>$r)z2~t1wP>o@F?%<}m04_ko98lBU9`tKy+z!XatY*YBVn z%O2QDIj@q_Ku__4E~iGTrDRRKWI2Y`_n6&w`lR{M@W81gUL=CDxF#73`}g(;H8J4) ze+9(<4G!B6!mOby-VvzEoT=~!;ao{NBu=m+1T3s39*ON15xOPmrNNi&x9X|>an z71WIOXfO5_u-?Hx<^B`M!`fU!qb&={1%oEjR(z&zB-_ZQbRRXI(l02tdhL(WMqQ)m zdMP|@_L{ZAPgBzc9LXsQ@R3glNH+b9R}qV8yquTW2br7& zDxNHOaIt)FNK5K!HmmlP6)cb6Fh^vwNu)l6Y$QPQ16K+} zoljL=;Dqs=Y$FvMHxP(HD2J?onI+|W*l72F1yq@j5|}ATKsF2-0X`fsJhO_@Wwn`g z_3J7EZ3Gn#RF>R*bO2DmeTK%GBBl`nrV!NfdZgM-7@?0n2&5)5%no3?!=?tL_RCt& z;d))pIMiqz>om!=Z?b`P0ZBXvPlX4A?V7%CWQP-7&Pvd__5>G_Hl@ENM-YaXwcw<} z6{%eTa^-Rp1rzy!w2tp>DuP|qBX$$=LH#@R^MFTqJ=6zP5R5ZE@#AKi6$50gf`Izb z!Xy~xb~TGLqeoPe4VvMA?phBnsBi%ENJAiwW`D~_N)Z|+&_FEyw%XfDbMGkOV2>pd zAQ~tH7I%|o*P2?T@IW-;)2eMZ@cXLQ8#RqbmW8)sBMqOjOB>mbNY|iKBu2PDo_t$S zRf((^%S8$ZKHsUo1d%5;2o+^|v_|s|w>VNrw!i|XY1JNNH+BYv6*S(Y!Wh2MG;7gM zRbVa~^lCdp-7)!g0?j7whi61Zc9JB13n4+Q?5OOt>rvhIqLDARn`%cWz#o?vihTqh@dcG8`f^m`9_2o5_!vA4 zf{_JeLThY5N6jMv(A9ha#_bOP2_>wG6K{=bCRngb00tE8Ca~JkRh_N*_mO&2emp#JdDV_*rsz*hYu3qB;k>PCUSPgfv zd-pAe^ARYhWR`kuKr~=^-{~rkp0|wWFW=N22s9zh5TZ9a`)^~LqstGrht5uFY z+!FafXn}-xfJd6`mgcz~kGFbu1R9QK8|Kv9>KR_87tIIYO0CVhwojE%GO2vnSIx0q ze5RMPY?)On!E4kL(NJ#En8DK2RZS=)?nl<1BuAEpO4|FITsX&Bsc+&;s*ShC4zVo5 zKdU}AO=K;$igm#mW4>@GI4&Zt79=&|ReLxeVfKz1GMEUc3LU}r>I(8z&CUZU8bpce zL6mMRoTmZoC#0!FdB{78r2_-jlAl2Xuj;?`o95<=s`8;aSY04T6AM4e=cj@{fH$1C zV9eniOoqKs#fq&b2Nxh1P{|O02aMBX9OeNI&a7IsbOWnqKLU3gs$lO(usWs58j-GV zg=%V=)j#YFJR?si1!1qQa!c08Q-W9PJK^-!Ro2W6lpchX!iRGcJN-a0$r*YE7>`C3 z{O98U!h`>AX(quLR2rI#+}LGX)uB2S^JfENZ7<&{4XO}u??R_lLy*h1zFUuB z668KgHp6SVoF-GZcjJYDY{Sy*_fVBm6@jg>l+|7xB6ewgDR4+xlmE2{mIA~ExaUG5 z04O+Ktm=Za$udyHP*V_Vs82s&DVrw^q?KXCOG4r+U8-RN%hAk%g9cR%;U4%FOU4Lr zA?q$bZ)b;m2lf$Kxj;5D3f0i~fK@h*gdgKp&9UHCiISc+nKagUE}UKGnI5aS?y}a~ zW^BNLs-i{m&g$>IrFk^_V@&eR}VA2VOM}39%CPy-XX3uq~4?G%s_P0~pZA_jeu>V3kxl~Vr zM4aBw)CDjS8*0k&l-;(Vby9I+v$N`z;P(T|yW}a%lspP0SyM7|X<`=OYZzlkkws00~E{&yIRf*Pa(oms+t zNv_t{X;xX8Tp!~-o`*r%fqHnQXA_oY8XmCCrLR4y!AcgMTO3!sP~!~TLtb$96lelUT~prB_GZjbb**>U>!8$OWJEnQMw$?wn~9Fc zGDcEAGO2HEsu$|6b0GW>a^9w03f!Fv%b@ zA`yVj$7X@{cNPLL>hIAPc#(|<&ho{ahF`%Dz|c4?{K-bzSycHIl`>9K%0^eA_`4XX zZ1JxAkUj9zpRVy6Sy5Y;kZA^iEM~} zB&*t{)2g%l*Mjn-7si%NeIO74M>v=yj&-)Z7V3#^g>Q0_tPAFcWSvE{DciAB?l&Wj z954kwBR~wqlxoX5T&X&_diGN#<}h;4j;!o8mIwSJU3{OSU*fD78Z_piu1+r=6((K^ zkCrqS-~tQbqwkZ<+}6Btg0Ftt>aUebqt zJ48@WwW=9U(?H`pMS!rVSEvC~CW9PZJ?fT0Bk_T_Q~zCKne{qgwh7E-a2_A=Nn+AT z$DlUBQ2iGa?mAARMT8N2c^i81T2RBiO4z~OLvn@#W#~hE&8eqg&FwYjQq8{NeWJv2 z#}JczfzU+asy5g*oX8m&>GBS*)1=xG&GM5=Rc^8WN}AprTzo>Td)3sX=5IU@sdKF1 zu|uc7hR|D1pHE&rCUgT$Yd+bmpN)$_v%T-c19Z!J#>D?mf5W{Ov3n~VWkbjyVgzuJ z7m8@Y)!IfO*n>nH!vSB-*IP;IVA^q^&NIdT+|208*UUkKvNi&q4&ukAAbBVw!A`42#kK}uUtmt==Oh6Zwp1rqfs5hjGUH_)aZ9ja(L#qyLT zt@sQzEu@Cj?brNA5q@Ei@OIHd$vko4AJ*ycUxj`+bQvU}N@gEn`p|Jo**L=OhMLaW zdA?~+U9T*JFy%2oPq7v?2_YR$`4B4t##aA*QIN6nyV!Y|;B>**1U@xUUu zvk7fAitvXbF;WB#py!aN+sQ#IvQPZ!ce8)<=dASwvGZv7`aQ{#RWFwmO5&~KDgjl<1J)G;aNGVTpuSp0{amLoT`Nobgi)fumot1@E;!ipy z#zPaNv1N4f^xEcCZH&1`*GN~1*a1Se4UbqWYyAv3kklk8q1E#ekUHFdD}RHZdu^39 zi3#}DaLD;oY|goYIIt@O+-aKehNM+wG-0nAun(jEv~7aMIcmQho*ZE>M*T=HV$Mg? z4aV)O61D~t(QUQ>!it9>lMFSJ{+c`Nu%rrk09#ju2L;nKNg6^yrh$W4MRhwOu2~)I zA;Da5W;7Ck$}foK$`_LwBv)s%%Kg0sK|rjr6RT5^=NojA&90yZTc_qEw+osX*XUaT zC^dACVvc~nKj;c{!cgHK7X*$q%1|_AHln5_btKKOAB~J|;3s)PP^O6g#piACsh!cp zHIJQuDL0~9_G6nfq%j3QiB_kB!JjQpZ~b*hLZ!9B?bTo>GfFsPrS zBY=tydvAj;@KH8cdPBV_9bQ>B(ujobY_1!s%pwtp(gOd`S*3z^6TLc{#6NZ7^pKAZ zS&vQ8Y<eX8FdR0ZNRTVVsxO6&F$H8>2PeUX_RrYlOPj+92&z-7( z7<;ID(1(V%h>MLWwCv{{MmT88H4$?qT&reC)x)S1N8oSSWYfNSOOK7D z6KO+Jt4C%hhwr4r4pHMC84U)dOzHu2of`~Z^Sf|gAJiXs&mQksq?Fh(6&?!@tD4I< zJ8Nx17#qo5pO1kPOD`u@vqx9+67C7jJ#QY?%Hg(WHQ$CL?ysL$7pL zIt>wQ>^4Iqo+$SuNe%GmrN+=!+ydt5f;z!4R=k-nz#Y-T8ne*Q=&1E2$ZbQd5cEJ1 z$+n_i)j(cXQgzx1#o~UB6g*H8ugRIm@&pgAdBwetj;BSdHRF^TU{I-9rSPFrIRAKb zGI+SHej!u|GKI^DTxJYExQ8zb-Wh;wN!k=94y;=oGGRhcNVEBOIQcvNjov=uvP$#cj z$Y)D-L)X9A()5Vs7}3?yJrbb?>LH*dev)`OqL9l7$Y90vp5g*=V%5! z`=0{i)(g2?CYuV>e3&4m3E4t?#3tK!&hGNi{hUkYe>^uh%`1vh_kJ>0iP7+p)A&z>=U* z*hN(X0LOw?+6HI@`=d%Y=r@o`Q!z1mcj2~MgtggdC68~aCY&{NzWxRkVq<$*hR#gs z)Sq6-$6Bm8p|UkJ)BRLqp=44C8m@!0TrlR_d@x&m%PBeQI}hPC8hiC_79vaaVMI~s z4*GGu>7u5&sJE&Q;SsOYOsd@hIr;A{z-ZGBfO!E)| zL41DWjznx%hKZevPyUs1ay*T z$PBV|3IIeEI>L_*@ku1dKX_TyS-}IV%}{rbd$CvQp|MjK-PM(}>r+YWX!y8qX+w$E z>q*i|32c>m$2ENCjq++Hz43AJLmi|kj?BPU^j;hfWnveK=@!+>Rp&1#M}()22V{}2 z`<@RF|IztviBiaA>A*-Dn&mt=j7Vv2b^umIHl9G%m2E8G~j+<$UN;y0~OBp@L zYI?g4H{zyf_MJ6d0df(7YuNCZ!czHKmE51}FHKdzRfuZ6N@wTeY#Oy^>$$*6IEkJre9H@j2XGOJ!W=bUgKyrbQeH7Hn+j;u{3pj#o z4a~lzeyFZ`9XUUot^q!AIKBBs2e;lg-<0u@IB&1yLUBAQXoIjSeOJ3S`Bv{Csg7OO z8y@XlN#V7CI9tV95o(BGy*gK3MJ4rDN`8l~+M}s2o1sxHf1x0Ca=73Z+TBv#Qa?}~ zq~|nphROr>t{PZaRwcEF`w+bTo%10}K*SwMAnR;yR^No&K=JkaXv^K@~0@U^cvLeGK+9{i%A(<<{FSmpt407o+c$p3T#H2{X|s zy-06|2$|4dMG{m^FBgbuxcBG6F{}MG&Qv_qacR9{u1O*29ayl+ z_^wj(S{fRA8w5_>x2zi<09cXxYxEC?cTGiocG?vShrrshl0>MzOE>^nn*e$nAMKf z>mk!OW}zB!JtVU?t#7^CA+r{>zKd!DI=q~11l-yz;{1htadm#!#t(F84lV=@&p>px zX-Sw(%NKxZ-U~dO?7P!DR#mfJ_SO&6 zLviRFIRuMq%!E@2ZvC?M-CN9hoBB6m9p8&;+|U}ML~!FcF`f===Vwk$OzRDqPw2p; z(lX>K+nZ+eI&H3$90K=aE$Yx;wLI%A;d7Sis7;5W5!?Hx~E@7gMMK=3i{ z_gJ-8hY+sjg|0@5CQ@%ljJcd5NhOI#?+VgKA00D$) zLqkwWLqi~Na&Km7Y-Iodc$|HaJxIeq9K~N-MUjew8Kj70s7@9{MRe0D6rn<>6nNgNw7S4z7YA_yOYP=A`H%CH^ldw21NGxF7HCJ?`EC!Fri# zR>v5i>9(0l#KlZ@RqT327!e4V!H~=>V@{Hi@Eu?G2=MhT#Yo++5=)I703EEd{WX=7G2HR4I) zsH*9dAIx~Ha^B*sm8-0IPyWJiPG4E(I?X{Ou!to{5TT%o63VacI3T>9v*?Jp%f+fs5;wrtATiJHWt`A)B%*g=hxzdEotwz9|dz-vT{rUT@8PoIU_) z>MD5y92^281=rG;(2-i000JJOGiWi{{a60|De66lK=n! z32;bRa{vGf6951U69E94oEQKA00(qQO+^Rg3>p+V6(dqhRR91D^GQTORA}Dqn0s(k zRi4K`_vYSyq?7Irc@Rjz@HPS?6tg}`XEb6KQ*jV2sMJcijLIk}##u+K*)4U}b*yrx z#$sniMjhF*W_Bq-M9>29fd(vLw{Q$gfCSBpNJ5?+Nc!Ek@6A2?M|U5(HL&j1I<;1L zs&4h~{?6}w&$+*I&i8yzD}dk|TvWc{<=YSV_5;5CfNyxw7A{=Kv}w~&6ouyIW|l2m z20(XrHzg${_=i?MB+g9i^%TU(0| zg2BN-+S=N_@?e%OT`F-pJ3CphU;zN9PMuL2gb+g5 zwk?K-hh^RA)2D@P+d>E-;_&7z^9;gT3#U0nhYk38~-0K~d=>%V@xccl$he-K zp2@Q|$uoEETsg}V6BFXI&pwkl`}gm^blc28gb>0sO=-tsv79Vq$3-F$Y1_6fEX$Jb z(P%UWFT1l}!%kqn3Ieq%H0L1Fms|6rxYiq^YwQB_+R9)9E z?r2Suw%hH_*(=#`9*;-bilUI0mnYxz^YbUg127Cj+VOZ?+KEI0UDr_*Wzx1zr!%L$ zX_^X6^CEAD5Xsdi3a5UP7v>N&+xVQ@s85+Y;x67hbqr+gy;# zF~wxhwbx#oGxe8SLYKq7@x~i3yM!(^9u=Ujt}bV)ues(LX>Z)PQQ9>%HPqMF%lBJv zy%o3Hoip{9TSBW=tpY#@!KO`{q<_PP4HOp_Uv>!zAy~b7H2}4>wX9vc_Wy1P_4fA4 z4ZVH)_AhO|ukz&Q=Zn6+K8bVu_;HEz+H0>}y6s=`9Jm|{-Eqeqm&EAq?!F`o{Y7c? z>(~QYe}6w!RaF4Ax3{x!;X(jfT3TptZ)e%EW%Tv+ap1rK)~{brB9Wl6v5}{qdWsn{ zW^nA-F(Q!&H{Em-7cN}jo_p?L=gyrJ6cq60n{Q4kUs4m3TZV>)2m}I@m6c)JHr?Ib zQVaF;^i0|&12$+7X``|Y<&yQZc_G&D4PDO=g`*|_)Lf4^9{ za^-(3B{F?y<7#`V0d_#nwlD1E*ERotl^z^-eK|L#e~CQ0M@Ko zLseB3i9~`#B0+U^HGaRJ9XobVRaHevNePPKE)WR(kM0ARdxdS=Id_wfKKkg=Cviq70TdP% z=A5V*0jH{Jj=1xBy{M`xMV`aqkiyRI_kT%*Wy+j6b0iC8pY}_ZEWzb+<=|us#{B$z zgb>W1KOcaZGiP$uRad3P=Jk4IpwH)%c3D}O`~XE!a_TB8E9J4T>w1oS$dJGn69RDa z%{NQCp`k(Aciwp?m6esaT&_vSl1a)fx7-52b=O_TiWMu!@V#6nhYlT*)As)R@5^Zn zg+k)!(W7#DckS9GLZOhnhGs51i9|x|+__UOuM;OueC17CRaGUry1FFJ;lqdJShj83 zcFA_y(xp%H^wW3K-af*%ZH@foC$Caap!3W#jof|r-!Omv_vq;8*AdXkco*)%mB zrMkL|Idf*y+j|sMjZs{D3z5hm*I)lDHg3Evjq@arJ@zt@h{xF?N2il%8Lgu`H2;BZVQ z5&>NYk7p*qV9Fnjs+i_fGM6$~StnHDT7 zn65LitWFu%)pZctHZe_zMuVI?HisBA8|}jTOW+FSa$! z@hqHniPO>1Ci^zc(HwlOw6p?U2StI>(gkQ*Y6eP57NG0ytov{kx}K^lExi^^)6sQs zI=yIGLAp+*q~v-sS7cqU1faTlk&K4|iKA&=6r~{TSJ8EU7S0@rQ(C$p9S@39B3FX0 zSD?+9kpi|Xm^o9!FjC-NubaHQls|QmPQ?`#LUFN&WHPl3oK6LYBM*-!)q&fcPbiei zmeZNKRn41MfX9=HH%%mtrYTrfUK&5!4{o<6ai&bsB>u(mfYYg??%Vekx^6H&KF&Mu zYy}cH97*1L@Arg4C(ty5SgenMfmhM>Bo0S}x88c3XtWPqH|Xy_MK~OhGdDioj;4`* z&I9n9-)xcb0|Tds#rn`RgHY%Mk;q{*%>V*)b$ycd2YBzjKjCmBfduXC%~_b)&nSwj zB7XeijXd|<^MK0LS6{)RMc?I>S6&AMfB3`mY}k;x7eDa8y|~>4{O)%tCE3{cBR=`0 zgVn1)l$lGhMkYh>v!7kO=QcL}h!c;)*TU_EIV;dYC=?UPec+q`3G7 zY+I$M=pHOx;SiTwOREDOfRgD8p*O#`PhKwe%EilPw=f?)*lczhHTfMJ}&>8vCY z0n@Zllq5c1KAHxhP(M(CX@a7JdG=W^ci;UhuDa^))A4p%nkWciF)@+EF!Iy!6Zm|2 zXc{CEAq>NdWq}Yu{QlIq;&BVp)Y9=GwEX-+$wK-0KDn9P?ov5rZZ~L}PcnhaRf%Ph zW&;gf*JPc~S3xuiLV(km(n19V)8rmWu}y}BG%QQQwll1fm&G>TEWa$UKB!0C)KF=0|z2+3p+=t$!jK(EBH?IU=-;PpZ>`5}J)1b#nQ zR%aIe3AFO^S!Di0nl^1A$zXVll}L7$8i}u&ri!9uPBsP0BK@uc z{TN0sa0&p+`V3Xg+zXClSw5gM&CBh;v2@($m}UeRPQU9|7V^pTmr~?5$>iq zg`;3ut?9lM;24%Q1sKl3SAP1_c2Q9=AInO~hbdE*pzB~5|Bj|j#qXa>fB$(#Mw*#F ze+7kw7N<^aW%1$$!r@|Ku`ZIy2o)7e(Dew-&3|Ivy!8Rz0U`b*lP-e6BRv27_o%5^ zOThh!!b@?o)<+?)9evL*Ynd1GAcERqS)xVg|0i&D)Iu!RKq3L<<+<7;qgBSn zU`lF?#A1+4!qlm$j)#U)*~*-h0O!uZ)mJmA=9vuti#TIr7x8no5NH(@ZplIw6>iBw zMMZw;*EA3!Uuux)(@QYTjObGF`5dyYynG7baEhljEp^Ae^2%cJ@-jHtT1EvNllY;$ z+%0i3W6T{7Xqp>!`}V__CY(DLXV Date: Tue, 15 Feb 2022 13:38:48 +0100 Subject: [PATCH 101/447] Update 7x7dotsclock.img.js --- apps/7x7dotsclock/7x7dotsclock.img.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.img.js b/apps/7x7dotsclock/7x7dotsclock.img.js index eb66b813e..5b6657415 100644 --- a/apps/7x7dotsclock/7x7dotsclock.img.js +++ b/apps/7x7dotsclock/7x7dotsclock.img.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("AH4A/AH4A/AH4APlYABAYYAFBIwUEERgQJ64AB1gCEAAYGKFxQUGF5AAUDQVWAQOBAQVWF44PBqwCBLgpRDMxhNGL44RJL7oCDR5AMBlYCBF7TiCF4aPKF4RpCwICCAwOsAwVWAwQQCEISPKWQzKCACZ9GL4YRNII51CPI0rAwQDBX6CPhBISPYd7RfUF7S/UNgqMBQ4KMB1krAQOBBIQGDF5oiDR5jvEAYYCFBIQIER6g8DBIIKBAQkrBIorCR7g2GAxAdGR5ShGd7SMCEgWBR5R6CLBIJFAw7veF6b7GX5AMBBYKPwbwwGFwIJFAwaPKDYwNFgWBq8Aq4CBqwGBlYGCAQMsCAssLwQEBllXKIILBEQ0tBAIXCwYABrACBwQGCAAQGDrIGFFwISFABAlCAA1ZAAIFRKIIXVGwVYAogDBCIIGBC4gQDgB5BFJQiFBYQkCCIYFFRYQKHL4MtF5YiFCIwAUR4QAUlwCBJIODq7iBrAgCqwGCd48BBYSDBwQLCRIQbCd40Aq0AgErAYWBAQNWAwVWlZfHBYQVEwMrBAYXBF40sq9XlVXrErAwMtCINXQgIABboq/BBYUsloCBDAQiCDYRiCYobvMIYIKEF4gfBDhr1PApwvHAp7PFawVZawuCboyxBDwb7ED4YFKAAkBq8BgEsa4MBq0BAQQJDL4QAEgTpBCIj1BAwIXDF4xOBEIMrqoDCAQoJCF5EqCIgFBgAUBC4RgCbwVYdIQGBRAQJDAwhLBWYgVCVAgFBUga0Ed9ovvAwQJDABAXEaActCpYYDB5wAOd44APlw4Blo6BluCZQhTCrAQBAwkAgQECDAOCDA4lDBAVYA")) +require("heatshrink").decompress(atob("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")) From cbb607e7b41cafbbbd4fd66531adae1856959ecc Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:43:29 +0100 Subject: [PATCH 102/447] Update 7x7dotsclock.img.js --- apps/7x7dotsclock/7x7dotsclock.img.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.img.js b/apps/7x7dotsclock/7x7dotsclock.img.js index 5b6657415..2335bbdff 100644 --- a/apps/7x7dotsclock/7x7dotsclock.img.js +++ b/apps/7x7dotsclock/7x7dotsclock.img.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("AH4Arh///4GDAoPwDiQVEEIoFFEwoFKHww6TDwwfSCoohFAogQFApYcFHSoeFD6QVEEIoFFEwoFKHwxX/K7I8FAowGCK5wYJV/6v/K/5XuDwZQCD4Z0VEI4FECAoFLR6g7GLwoeTOY4nIEwoFKHwwA/AH4A/AH4AZh///4GDAoPwDiQVEEIoFFEwoFKHww6TDwwfSCoohFAogQFApYcFHSoeFD6QVEEIoFFEwoFKHwxX/K7I8FAowGCK5wYJV/6v/K/5XuDwZQCD4Z0VEI4FECAoFLR6g7GLwoeTOY4nIEwoFKHwwA/AH4A/AH4A/AGMP///AwYFB+A5vGQg+GDqYeGD6yQbGQQ+FDqoeFWF4yEHwwABHgoFGVAxXKDBIAFBAgOFAowWIK5qv/V/6v/V/5XXDwa2GK1oyGR7AeCLwquuGQw+GAH4A/AH4A/ADMP///AwYFB+AtjEwoFKHwwpTDwwfWQh4mCApY+FFKoeFWEYmFApQ+GAAI8FAoyoGK5QYJAAoIEBwoFDK7Kv/V/6v/V/5XXDwa2GK0ImGApaPYDwReFV0QmHApQ+GAH4A/AH4A/AH4Axh///4GDAoPwHN4yEHwwdTDwwfWSDYyCHwodVDwqwvGQg+GK/5XZHgoFGAwRXODBIAFBAgOFAowWIV/6vlK/5XnDwZQCD4ZWtGQyPYDwReFV1wyGHwwA/AH4A/AH4AZh///4GDAoPwDiQVEEIoFFEwoFKHww6TDwwfSCoohFAogQFApYcFHSoeFD6QVEEIoFFEwoFKHwxX/K7I8FAowGCK5wYJV/6v/K/5XuDwZQCD4Z0VEI4FECAoFLR6g7GLwoeTOY4nIEwoFKHwwA/AH4A/AH4A/AGMP///AwYFB+AcSCoghFAoomFApQ+GHSYeGD6QVFEIoFECAoFLDgo6VDwofSCoghFAoomFApQ+GAAI8FAoyoGK5QYJK9yv/V/6v/V/5XXDwa2GOiohHAogQFApaPUHYxeFDyZzHE5AmFApQ+GAH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AC+ZzOQApEJAwIFIDCQVIE5YmLDhf5AAIFHgAFC+AFHDCQuIE5QmLDhZcBMgYFFNIRrCAooYSVwoPCE5YmLDhRdDLwQFFN4ZwBAooYSAAYPEE5YmLDhSv/V/6v/V/6vILwYFHOAZ1BAowYSAAQPFE5QmLDhZkCNAIFHNYQFIDCQVIE5YmLDhQA/AH4A/AH4AIzOZyAFIhIGBApAYSCpAnLExYcL/IABAo8AAoXwAo4YSFxAnKExYcLLgJkDAoppCNYQFFDCSuFB4QnLExYcKLoZeCAopvDOAIFFDCQADB4gnLExYcKV/6v/V/6v/V5BeDAo5wDOoIFGDCQACB4onKExYcLMgRoBAo5rCApAYSCpAnLExYcKAH4A/AH4AP/P5+DyDAwIsoFckJzIABAwQFCyAsnFch7BQYaCCQkYsEFcp8CPoSIDWwYsjFZCOBApQGEAooSEV6IhKAowsNV/6vgADivRFj4rlPoaJFWoIsmFcquDGISujFgwrmAH4A/AH4An/P5+AFIhIGBApAYSJcpEGzIABAo8AAoWQAo4YSAD4sFFYpcBMgYFFNIRrCAooYSV0QsCFYxdCLwQFFN4ZwBAooYSAEAsEFYyvwBoIEDApYWIV/6v/V6gAaV5ZeDAo5wDTgIFGDCQAfFgorGR4YFHNYQFIDCSwiFgQrmAH4A/AH4An/P5+AFIAH5FEhIFBBQUJzIABAo4A/IooECyBiDMgYFFAH5FEVwSwDLoReCAooA/Ioi0DWoSvN+C0EAooGBApbNIEJQFGCxCv/V+IA9V5ZeDAo4A/Ior6GVAqu/WA5FCWARH/AH4A/AH4AL/P5+AFIhIGBApAYSJcpEGzIABAo8AAoWQAo4YSAD4sFFYpcBMgYFFNIRrCAooYSV0QsCFYxdCLwQFFN4ZwBAooYSAEAsEFYyvwBoIEDApYWIV/6v/V6gAaV5ZeDAo5wDTgIFGDCQAfFgorGR4YFHNYQFIDCSwiFgQrmAH4A/AB+ZzOQApEJAwIFIDCRLlIg35AAIFHgAFC+AFHDCQAfFgorFLgJkDAoppCNYQFFDCSuiFgQrGLoReCAopvDOAIFFDCQAFW4nwApYWIFggrGV/6v/V/6v/V45eDAo5wDO4QFFDCQAfFgorGR4YFHNYQFIDCSwiFgQrmAH4A/AH4Al")) +require("heatshrink").decompress(atob("AAkTmEzkAHDmcjmQBBmcTmICCgMAiMAkE/+P/mEQgMQgH/n/zAIP/l/yA4QvXC4kDkEjFgIACkcSmMTkMyBoQHBI4kvI6wXBn8wA4c/mfzl8y+cfEoIaBUS5HBAAMQF4UgIoIBBBgJNBAwQ3BkfygSnJSQIUBkECiBoCL48DmCPFAA6PCX40jX4hYEU4LNBX4JHIkBHCBgJHBianKj8wO4IvHgSnBmJ3CHYqGCABcRcYTXLAA5KCFAJfCC4KnDX4anNgUgiSnMkQQBO5hvCl8yO4pHEd4oyBH4QBBU5TXHkcimUTkLXFL44HEiTbBO4MhBoQHBI4KECR45HGBoIFBU4y/BC4c/mYXGMQJHFiBHLEAIHCf5gAKhWg1UB0IEBjUA0MB0EAjQKCiANCCQOg0cxmcSmWjU4MqmcDmSnDBASkBmejCQIXFmYXEmYXHicyhRLC0AEBAIJFBAIIFCBAYHDF65fXR66vImUCnS8IkeinUBgERgEgcIMBgRHDBgLvCBYMQmcjBYIAHfwL7JiQLBichkcSnUSO4MhI4MxI5MSmMjPgMinCnCkRHGIgJHFiUgkUalUCAgMRkUCkIvIkUSkMC0EiBxAAI0UKkBHCkCPDgA+CI5Z3BmYPBAB53CV4MSEgcSiCnOR4cyR5JQEgBHCC4I0BC4UjC4MCxQXGF4IlBxRHB0UAlUK0BMBkIEBI5ILB0ZHBF4czlTXHI4mjCQIXOH4KnDC4MKgGqgGgAgIBBIoJHJBoQA==")) From 19c9bf406ccff573d18ef3534560a19416a8fbb3 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:52:15 +0100 Subject: [PATCH 103/447] Update 7x7dotsclock.img.js --- apps/7x7dotsclock/7x7dotsclock.img.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.img.js b/apps/7x7dotsclock/7x7dotsclock.img.js index 2335bbdff..63d39c6fe 100644 --- a/apps/7x7dotsclock/7x7dotsclock.img.js +++ b/apps/7x7dotsclock/7x7dotsclock.img.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("AAkTmEzkAHDmcjmQBBmcTmICCgMAiMAkE/+P/mEQgMQgH/n/zAIP/l/yA4QvXC4kDkEjFgIACkcSmMTkMyBoQHBI4kvI6wXBn8wA4c/mfzl8y+cfEoIaBUS5HBAAMQF4UgIoIBBBgJNBAwQ3BkfygSnJSQIUBkECiBoCL48DmCPFAA6PCX40jX4hYEU4LNBX4JHIkBHCBgJHBianKj8wO4IvHgSnBmJ3CHYqGCABcRcYTXLAA5KCFAJfCC4KnDX4anNgUgiSnMkQQBO5hvCl8yO4pHEd4oyBH4QBBU5TXHkcimUTkLXFL44HEiTbBO4MhBoQHBI4KECR45HGBoIFBU4y/BC4c/mYXGMQJHFiBHLEAIHCf5gAKhWg1UB0IEBjUA0MB0EAjQKCiANCCQOg0cxmcSmWjU4MqmcDmSnDBASkBmejCQIXFmYXEmYXHicyhRLC0AEBAIJFBAIIFCBAYHDF65fXR66vImUCnS8IkeinUBgERgEgcIMBgRHDBgLvCBYMQmcjBYIAHfwL7JiQLBichkcSnUSO4MhI4MxI5MSmMjPgMinCnCkRHGIgJHFiUgkUalUCAgMRkUCkIvIkUSkMC0EiBxAAI0UKkBHCkCPDgA+CI5Z3BmYPBAB53CV4MSEgcSiCnOR4cyR5JQEgBHCC4I0BC4UjC4MCxQXGF4IlBxRHB0UAlUK0BMBkIEBI5ILB0ZHBF4czlTXHI4mjCQIXOH4KnDC4MKgGqgGgAgIBBIoJHJBoQA==")) +require("heatshrink").decompress(atob("mEwxH+BpMWj0diMHj0ZB5ALCAQUYj0cAQUUjsdiccj0XAQUAhAZBiUVAYMYgEb///ise/8dG4IMBioUCgALCAQUd/8PAQUaDYMYAQMcAQRfwABMHjRlBjhdCAAwLCAQUUjkZAQQbBjcAjMciQCCR5kUR45GDR5CGBh8ZR4kHR5kYh8eiYdBg4PIBYQCCIoMeXgKGBh8PbYUZAQSPKAEqRBgERAYUUL4cSjsPU4IMCiUTDIwVBgETiIREAoMeSoICCgCqCibDCdYK/COYS/BCAUIZoIACBAQVBcwI7BCIYFBXgS/MiMcXYMZjrpDACsbjsUAQQPJikdHgMajpZEABsXjsbVAJ3BfoMWAQS2BFIRUCW4KPHCAUXUwIACBAQVBIQJHB/8PjQbBjCPPi8ejsSjkeWIQAPcwJWBj0eGwMejACCC5UUaYMSiq+YgETXYICCIxR2BiZ6BOBQAOVYMaAQUAhAJBKoZoBUYUUX4bSBgEVaAQABBATLDiQREAoMP/8HAQRAKjTlBi8bOJYANjD8BAQTvZBYQCCdgTvNNgSPFjaPBiqPHUgSvCDwICBaIMPAQSrCjACBjgCCL5JABBgMajqxCTw4LBAQUXjsbAQUSG4MAg5lBAQSQKjJsCjTXBAA4LCBwcaNYICCDYUXVQICCR5JzBh8UR4YMCR5SDBh4CCRgUXh//jYCBg8ADQQvFjIWBia/RFgMeg4CBF4MPhAvEjaPKjAlBikYiLPJBYIODjBMBAQUXi5HBVwTdJAFGAwACD5OA5AJF2IGFMwQLC5GA5MSD4oCHiOBnM4wE4nGYhM4hIGC2ACBhIJBnEAAQOZF4ILEBwYCCzACBDwM5wIXCzAvBioPCjI2DnIvCjIQCgACBzQvDjIRBjIDBDgIOBF4QlBnIICC4No2EA2ACBAw2wtAJFAwQEDBwwbIAQRfvX975G5OA5AJF2JxBAwWBiIvBBYXIwHJiQfFAQeYC4oAOIgRaCwIXQCgJfDC4MIBIMSioDBjACBiwKCiwWCnIvCX4QLCCocXiQIDioFBC4LLCC4YAOeIJjBXwQAQzEZC4bzCfIM4hAGBzHJRAUaIAIJBjaPXeoWBzT8EjEJnEJwAGB2ACBA4IXBF4RgDR5yMCC4XIAQMREQMSFgMB2MJOAIRBwAQBUYOYhPIL6OZnHIC4RSBPQIGBVyQAQwJ+BwEJ2EZewI4BnBZBPIUVO4QCFisIEAaPOFAMZSQWYqDvCnIfEAD04qDvDIQI9BzJGCjOwSwOYgEIjBHBjI8BwLuDAB8WEoIXCeYUIAQMYeQMJeQKgBAQIHBNoJKBnAwDiqMCAQMIIIIICigFBRgQXCMYUWAwQvIhIQCDQRqBAAIiBEwICBicRBAcSAoIUCC4eawCID2EJtEAwCcBwMJDYMJAwOAFwYAPwGaC4eBnM4LAQ5BnJfCnJfDhIQBPQaPFbAUXR4kVR4U5wIXCzFQnEVBIIvCGwM5qAvBGwOYF4QCBF4cWF44ICF4dQDQQXBtGwAQKLBAwgCB2AJFAwYAQCgQCC")) From e2cee362141960aa08d51ba8e636563bcc304546 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:59:22 +0100 Subject: [PATCH 104/447] Update 7x7dotsclock.img.js --- apps/7x7dotsclock/7x7dotsclock.img.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.img.js b/apps/7x7dotsclock/7x7dotsclock.img.js index 63d39c6fe..b1f91c0bb 100644 --- a/apps/7x7dotsclock/7x7dotsclock.img.js +++ b/apps/7x7dotsclock/7x7dotsclock.img.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwxH+BpMWj0diMHj0ZB5ALCAQUYj0cAQUUjsdiccj0XAQUAhAZBiUVAYMYgEb///ise/8dG4IMBioUCgALCAQUd/8PAQUaDYMYAQMcAQRfwABMHjRlBjhdCAAwLCAQUUjkZAQQbBjcAjMciQCCR5kUR45GDR5CGBh8ZR4kHR5kYh8eiYdBg4PIBYQCCIoMeXgKGBh8PbYUZAQSPKAEqRBgERAYUUL4cSjsPU4IMCiUTDIwVBgETiIREAoMeSoICCgCqCibDCdYK/COYS/BCAUIZoIACBAQVBcwI7BCIYFBXgS/MiMcXYMZjrpDACsbjsUAQQPJikdHgMajpZEABsXjsbVAJ3BfoMWAQS2BFIRUCW4KPHCAUXUwIACBAQVBIQJHB/8PjQbBjCPPi8ejsSjkeWIQAPcwJWBj0eGwMejACCC5UUaYMSiq+YgETXYICCIxR2BiZ6BOBQAOVYMaAQUAhAJBKoZoBUYUUX4bSBgEVaAQABBATLDiQREAoMP/8HAQRAKjTlBi8bOJYANjD8BAQTvZBYQCCdgTvNNgSPFjaPBiqPHUgSvCDwICBaIMPAQSrCjACBjgCCL5JABBgMajqxCTw4LBAQUXjsbAQUSG4MAg5lBAQSQKjJsCjTXBAA4LCBwcaNYICCDYUXVQICCR5JzBh8UR4YMCR5SDBh4CCRgUXh//jYCBg8ADQQvFjIWBia/RFgMeg4CBF4MPhAvEjaPKjAlBikYiLPJBYIODjBMBAQUXi5HBVwTdJAFGAwACD5OA5AJF2IGFMwQLC5GA5MSD4oCHiOBnM4wE4nGYhM4hIGC2ACBhIJBnEAAQOZF4ILEBwYCCzACBDwM5wIXCzAvBioPCjI2DnIvCjIQCgACBzQvDjIRBjIDBDgIOBF4QlBnIICC4No2EA2ACBAw2wtAJFAwQEDBwwbIAQRfvX975G5OA5AJF2JxBAwWBiIvBBYXIwHJiQfFAQeYC4oAOIgRaCwIXQCgJfDC4MIBIMSioDBjACBiwKCiwWCnIvCX4QLCCocXiQIDioFBC4LLCC4YAOeIJjBXwQAQzEZC4bzCfIM4hAGBzHJRAUaIAIJBjaPXeoWBzT8EjEJnEJwAGB2ACBA4IXBF4RgDR5yMCC4XIAQMREQMSFgMB2MJOAIRBwAQBUYOYhPIL6OZnHIC4RSBPQIGBVyQAQwJ+BwEJ2EZewI4BnBZBPIUVO4QCFisIEAaPOFAMZSQWYqDvCnIfEAD04qDvDIQI9BzJGCjOwSwOYgEIjBHBjI8BwLuDAB8WEoIXCeYUIAQMYeQMJeQKgBAQIHBNoJKBnAwDiqMCAQMIIIIICigFBRgQXCMYUWAwQvIhIQCDQRqBAAIiBEwICBicRBAcSAoIUCC4eawCID2EJtEAwCcBwMJDYMJAwOAFwYAPwGaC4eBnM4LAQ5BnJfCnJfDhIQBPQaPFbAUXR4kVR4U5wIXCzFQnEVBIIvCGwM5qAvBGwOYF4QCBF4cWF44ICF4dQDQQXBtGwAQKLBAwgCB2AJFAwYAQCgQCC")) +require("heatshrink").decompress(atob("mEwwkEBAkTmEzkAHDmcjmQBBmcTmICCgMAiMAkE/+P/mEQgMQgH/n/zAIP/l/yA4QvXC4kDkEjFgIACkcSmMTkMyBoQHBI4kvI6wXBn8wA4c/mfzl8y+cfEoIaBVa5HBAAMQF4UgIoIBBBgJNBAwQ3BkfygSnJSQIUBkECiBoCL48DmCPFAA6PCX40jX4hYEU4LNBX4JHIkBHCBgJHBianKj8wO4IvHgSnBmJ3CHYqGCABcRcYTXLAA5KCFAJfCC4KnDX4anNgUgiSnMkQQBO5hvCl8yO4pHEd4oyBH4QBBU5TXHkcimUTkLXFL44HEiTbBO4MhBoQHBI4KECR45HGBoIFBU4y/BC4c/mYXGMQJHFiBHLEAIHCf5gAKhWg1UB0IEBjUA0MB0EAjQKCiANCCQOg0cxmcSmWjU4MqmcDmSnDBASkBmejCQIXFmYXEmYXHicyhRLC0AEBAIJFBAIIFCBAYHDF65fXR66vImUCnS8IkeinUBgERgEgcIMBgRHDBgLvCBYMQmcjBYIAHfwL7JiQLBichkcSnUSO4MhI4MxI5MSmMjPgMinCnCkRHGIgJHFiUgkUalUCAgMRkUCkIvIkUSkMC0EiBxAAI0UKkBHCkCPDgA+CI5Z3BmYPBAB53CV4MSEgcSiCnOR4cyR5JQEgBHCC4I0BC4UjC4MCxQXGF4IlBxRHB0UAlUK0BMBkIEBI5ILB0ZHBF4czlTXHI4mjCQIXOH4KnDC4MKgGqgGgAgIBBIoJHJBoQ=")) From f9ed2829325d862f1915353b774aa5cc3d014293 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:02:13 +0100 Subject: [PATCH 105/447] Update metadata.json --- apps/7x7dotsclock/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 5c64ed6f4..b11ceba0f 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -1,6 +1,6 @@ { "id": "7x7dotsclock", - "name": "7x7 dots Clock", - "shortName":"7x7 dots Clock", + "name": "7x7 Dots Clock", + "shortName":"7x7 Dots Clock", "version":"0.01", "description": "A clock with a big 7x7 dots Font", "icon": "dotsfontclock.png", From 28dc0d008414eba9ec6fed40e24309f0a7957e9c Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:06:09 +0100 Subject: [PATCH 106/447] Add files via upload --- apps/7x7dotsclock/dotsfontclock-scr1.png | Bin 0 -> 3874 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/7x7dotsclock/dotsfontclock-scr1.png diff --git a/apps/7x7dotsclock/dotsfontclock-scr1.png b/apps/7x7dotsclock/dotsfontclock-scr1.png new file mode 100644 index 0000000000000000000000000000000000000000..dc86396c0606f0a4c5ea4895bc17543f2e51024a GIT binary patch literal 3874 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 literal 0 HcmV?d00001 From 7bdfb8365f5b6f2980bbd558c419c2084dc50877 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:06:36 +0100 Subject: [PATCH 107/447] Update README.md --- apps/7x7dotsclock/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md index 8e51f46da..a08a9f354 100644 --- a/apps/7x7dotsclock/README.md +++ b/apps/7x7dotsclock/README.md @@ -2,10 +2,16 @@ ![](dotsfontclock.png) + * A Clock with big numbers made of 7x7 dots * system widgeds ar not (yet) supported -* when screen is locked it shows a full screen mode -* by swiping you can open cusomizable apps +* when screen is locked it shows hours and minutes in full screen mode + +![](dotsfontclock-scr1.png) + +* when screen is unlocked it shows additional info: bluetooth, battery, new message, date and seconds +* by swiping you can open customizable apps +* button press opens launcher Contributors: * pkkpp From 4cf203ed6902d013e8277d6b6de48e62dda18e70 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:07:17 +0100 Subject: [PATCH 108/447] Update README.md --- apps/7x7dotsclock/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md index a08a9f354..6f285ceaf 100644 --- a/apps/7x7dotsclock/README.md +++ b/apps/7x7dotsclock/README.md @@ -2,6 +2,7 @@ ![](dotsfontclock.png) +best look in dark theme so far * A Clock with big numbers made of 7x7 dots * system widgeds ar not (yet) supported From 8e15f4f96f7575d94af1d4234cd22e5b309b084e Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:07:39 +0100 Subject: [PATCH 109/447] Update README.md --- apps/7x7dotsclock/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md index 6f285ceaf..37734911f 100644 --- a/apps/7x7dotsclock/README.md +++ b/apps/7x7dotsclock/README.md @@ -2,7 +2,7 @@ ![](dotsfontclock.png) -best look in dark theme so far +looks best with dark theme so far * A Clock with big numbers made of 7x7 dots * system widgeds ar not (yet) supported From a31c1d53ad030d374fd1e445f73fd2b580956a8c Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:38:58 +0100 Subject: [PATCH 110/447] Update metadata.json --- apps/7x7dotsclock/metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index b11ceba0f..6d973182b 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -11,5 +11,6 @@ "storage": [ {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} - ] + ], + "data": [{"name":"7x7dotsclock.json"}], } From 1961ed2a1a39ef991791198665e7003e08c64870 Mon Sep 17 00:00:00 2001 From: xxDUxx <96152564+xxDUxx@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:48:25 +0100 Subject: [PATCH 111/447] Update app.js --- apps/contourclock/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/contourclock/app.js b/apps/contourclock/app.js index a5440845d..85692da60 100644 --- a/apps/contourclock/app.js +++ b/apps/contourclock/app.js @@ -10,6 +10,7 @@ if (settings.fontIndex==undefined) { function draw() { var date = new Date(); // Draw day of the week + g.setColor(g.theme.fg); g.setFont("Teletext10x18Ascii"); g.clearRect(0,138,g.getWidth()-1,176); g.setFontAlign(0,1).drawString(require("locale").dow(date).toUpperCase(),g.getWidth()/2,g.getHeight()-18); From 55430e713516df4225ea4c5967a460de5209dc3c Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Tue, 15 Feb 2022 18:34:43 +0100 Subject: [PATCH 112/447] Bug fixes on the terminalclock app --- apps/terminalclock/app.js | 4 ++-- apps/terminalclock/metadata.json | 2 +- apps/terminalclock/screenshot1.png | Bin 3190 -> 19618 bytes apps/terminalclock/screenshot2.png | Bin 2628 -> 2569 bytes apps/terminalclock/settings.js | 4 ++-- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index f999593d7..af6ff8472 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -28,7 +28,7 @@ function clearField(pos){ function clearWatchIfNeeded(now){ if(now.getMinutes() % 10 == 0) - g.clearRect(0, 0, 240, 240); + g.clearRect(0, startY, 240, 240); } function drawLine(line, pos){ @@ -123,7 +123,7 @@ g.clear(); // load the settings var settings = Object.assign({ // default values - HRMinConfidence: 40, + HRMinConfidence: 50, showDate: true, showHRM: true, showActivity: true, diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json index 43f923d2f..6907da84d 100644 --- a/apps/terminalclock/metadata.json +++ b/apps/terminalclock/metadata.json @@ -7,7 +7,7 @@ "icon": "app.png", "type": "clock", "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], + "supports": ["BANGLEJS2"], "readme": "README.md", "storage": [ {"name": "terminalclock.app.js","url": "app.js"}, diff --git a/apps/terminalclock/screenshot1.png b/apps/terminalclock/screenshot1.png index 874114483fbe5c9523f428938bae8928020c3aa0..bfbb9039b7ec94990efcfc11154e714f051ef7b7 100644 GIT binary patch literal 19618 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 literal 3190 zcmds4`Crmm7sl^=OSBw8({s95Ckx{TD6G`SE>bNRFL zR_y4usZ~r0%{YBQAwZ%JwDjJ809W0C z(2M|}NC(!MvXD!M(8Q2`xx-fi8%JP))HG-_LQv_$!$0ykF>X48Nv)_md%JvZlfkCY8r5>kpQUv`sglf z$T1Ep2WlGE*p~trwno*lty@%M_B9$)RNS9lrRV_!bOW z%@eTt#=6Jgs`k%B$Je|u3}ww^iwh+Y+@0K62|Z099@qb}T{zg_gsu_nqX`2gQ>vAX zuG7u>%#psyinCdt8bQxk?W`7a(V9s9GFPM)spwTYuo6BBB_8kw1Gf-~K7e5fpAbR( zq;jPZSSdKn_z;j!yfsY~k%PTQ`Z$OUF?DCwmsKisNT^nGEbL%p4uTHX#E$Wl@?(uV zAGy$Uj!0Z|54tVg%YJ(~HFU*t9tMC}hsy00WgwI)>Shb<^}l zrC(55De3oD#`9Ad?DX0({7{lB*I3v-^Wf zT2JZcbAvO8OA8JAj=zMtS1J0Z zyy~T>Gk$TeycE`32wx*1JT%;tVZW_n+dr9ox1WN2|FjwfBu*!kq zRU%10eX%~dCB%=~R*&oGftk-6)o833_sQNu>H&$XtiUCj#A;>Q4TZZJtt)|RTHnK9K^B zj$%S2{B-0C{W1n0RIevlz*~oFV*0C!Wxv|TfU{mXeC11asCzMX*5aMd=t*aQV`x4< zy~6+nU|{Br3)lzyv;ddDve)n_tK>z`G)ES0HEzZdoz)ykjFOoJ+v|#XP&u(WsrRyAnniU{k`xK#kb?chKmnpGbyF( zByzOEzl+n?T+p5W>Bp71@m;HydH9W+NvZC5ldcFq)=7UVN0G?Vq$emO_$k9Uc^PNG z1B>4M;=qX3!wp0;gI4#`KKRsK^zy}g-(x%#r5Zd~iw8xmYyoG+jOjSda$q27y!3{C zcII6O4M&s=o{bk2fJJnC&n^SvGF7ZH``~Gv+|<~N8X4xyQsGgZl3K&b~@k%PL#|dL6459Rdt5@d5rDhB{Ompl58S0V@%a3 z>y*5qykuTOHKKrbcnXY4(cV38o3#feC>=N?qTkEZgAb!|*O8r7nM({}WrBzJ;Bo`> z@l1VG@VPPWuaiXU{)IYC!1o}uE}z>*k_0c5tc6q)ZR8$lcK-%D1;xa7MFNx5!#XNc zAouR?@@_VaJpS2$JTBb>kI+1&!9!g@3v33Vb-Q5+M{@W@zgVYgoXr|X(g_fv2lj8? zlM43l!b+U}Mwrlk(do@B3dxk6(N?>5hL%}xFBl!L#7dT~ETDG++)}31+4hMOuVlxS zx(czw%I!X4ht%aYulr*}&|*=V^Y~zrfY5iR===6@4MSfzOrIt5k~Tp*N^Llsizzp6 z+rO@bh*Q|if709$E-SQ*0}&!Bd#sP%f?zE77?{r!&iijNm7yYkHYA^-jUZ13O7O+F zEeG0m70!;AQzm4cm$nhM1*I}FiSKrvVJ|U}EcqRcDDP16d4C2-27QyzQ5w-I%w8nF zotx@M$^H`2QIT)L82BE7NmrLwsFkW@8SJlca})UroUX2=T45!&PX$j{3PfW2iLf~f zUJ#duz7Se1ZKcEoGaVzMPB{$9pR^;jfb7a*ev6&7YEOcOwK&Jn7jUQJGCyG@+qD3@ zO(4QhqeJIAun#Sh2>|%pRbstNqes-$Z4nZthNAiho0^9-Xp)_{NF!q4} z#{KCs%Xy2h1OtF!I?(;Q_bN}k>Nd}%V{rgDTXJBZ<$Qq#jlU)p7;Oc<*QDp?MEEwq zRnsa&#}4LS4QcY0?9`kFeUb<}_yaaD20gb!T9nVJQtf358lv$k-vGU1tX)rAV&Fu5D&ssGzjgs_P@Nl`#)$<|Cd)-`^xgw WcOKbI6JP!lkO03x-v;lPYySl!2HfNT diff --git a/apps/terminalclock/screenshot2.png b/apps/terminalclock/screenshot2.png index 6d1b5f040316615a683e5ef1e0fbc332908fa7eb..27bd6d68d4a7068e01c7f07c4799a631815463ac 100644 GIT binary patch literal 2569 zcmc&$eLT~98~*<03@y@w9dXLbk&aS1QO8T(5*8w_n@por3YlofY|L-z zY8$2_bjEDGcy>-HC8I-|9m`2(80LMPJOkd0#mDuyE4O_uaWj0my0_EW9HK^<*f}26xi1Ql~^;{XWf=G806Spmi|u zVr5%=*YH;%A(WRvfbA|n0r{=2Y_b(Dwa(}F2;-$KT!I=aH+nt($Q>MT_M1ZN?0P$p zohj6jJ}tH6Kqy$GT~HW1WWqz#^a#s44`yTIuu_VFL#yM_={zIF_{a=F9ie__chn}E ziPX`n`GRf^iX>j6=!RDaAUl`+MGE)BXcH0Mj722`VZ50}1U=R-SKOPHbl-NAuE zYz$VMaTznev6Ifb#D;3sOxp3%S+mUiKn=bItk`CA&xatIy}}ffR}8y+#K6Lu+`QO= zbbF$Tv7AH9(K*=8cuAF=Yz&t%)7Z4v=qQ^??GR|@y4J+vUD~i{YM4>xoH%6RUSXVI zC?ym#&YJgQ7Q?-#3wuX0x_c^+=enMwj&t~uWrphcgSBj=92r257f(LS5(VALd*0^> z*i{dd4n?A235BQ4I%Dk2QnS!ZrySCyG4T;5xsV%0#8PFC7LH21$pw*T$*)9t8LdpE z?nGT(-T@V-kNT<>S4oJAaQgx^Z90KGq)OPepWclhE9m43!_`e*E`)=AUt|SB%K3(w zetBp7?)N3mL@!obbBxHs>P3ldPR@@nDZTmv4I$I=s~T1KC!Si>jeW-Tehh~jRWuq> zX3zCF*WwXXm%GB-Wr_iO>=zn#jlhXSK{g|fi=z*Icb)Vt^U|?Hn|TXlxq;4yvZ$ld z1Bor=cUszw4*xN2WIEDiXgXKYH>TZ@qV$QBBZz=8K@ApK(KDA*CC{X8uDriL#p!rkeS%LlTO!l`|B-&-@)xrKO8ZHbBWuO_!-&xa#t2na)a`WJI|>;|2NP4o zW1#+9ztVD$@_N5&WvgSK>mG*Phj)dc_8k}*4yQ+4F>5)!3pm&7G$Bri%j=@owhF3s zoXcRt{R$V}kYrx*ni!!z)U@`c1+k5wwpIn%rS61micLb$MYy%1*qt={hiqBse5On} zV!`a((U(i94OH_2&KQh})1u@S&E`Dnsd1l%l+15oR+Gl8ViS*4z;tz(;t!09gMHD1R!D+xQ^=gufZ3iWJQ{0h+fX$+3OT$Dr~0Xw z5MLu>{xd+|D@4ma^`s)+ z>_UNwU0lZzOO5u6i_fGNAV5~ZSib8%dLV=q?#WH7EPtkn)WhkXR*ea zD}{!r7p{lM@x4$~dBdmB$yYV=i#KbrX4u$ZIklC?32Hjp_~+q9-*zX8TT;yK9xZ9PU8v=Kh3L8u z#IufKA8~-P461u=N&XSkUwU5BjF}lok3Ti`c60N^aT1U=O#-(#12?l|Wb(MTgX^0O z3yx6DSMqH*1qDZIJid~X%t(M7xX;FO za4rhdSuriNK3k>JT=o~lGkx?o=VW-T1pkN0!|b>pYM=t2Jh>@xGQ13x${ z%|4#&RgBx}7$CsL%ZR-eHVOV^&T?BIAhj<2x?jUi@@9{#1;+kbsi<<@pR3?i(wvN} z+?-q!e266r01UcPU4^;=N)(UFNHVgtN;K2 literal 2628 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 back(), 'HR confidence': { - value: 40|settings.HRMinConfidence, // 0| converts undefined to 0 + value: 50|settings.HRMinConfidence, // 0| converts undefined to 0 min: 0, max: 100, onchange: v => { settings.HRMinConfidence = v; From d6da125df7927dec535c9c8c7c3dea5e145d88c8 Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 16 Feb 2022 17:54:12 +0100 Subject: [PATCH 113/447] Added optinoal fullscreen mode. --- apps/neonx/ChangeLog | 1 + apps/neonx/README.md | 8 +++++-- apps/neonx/metadata.json | 2 +- apps/neonx/neonx.app.js | 45 ++++++++++++++++++++++++------------ apps/neonx/neonx.settings.js | 13 +++++++++-- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/apps/neonx/ChangeLog b/apps/neonx/ChangeLog index af7f83942..7ac033fe8 100644 --- a/apps/neonx/ChangeLog +++ b/apps/neonx/ChangeLog @@ -1 +1,2 @@ 0.01: Initial release +0.02: Optional fullscreen mode \ No newline at end of file diff --git a/apps/neonx/README.md b/apps/neonx/README.md index d836dfab3..c3926c4b6 100644 --- a/apps/neonx/README.md +++ b/apps/neonx/README.md @@ -4,8 +4,8 @@ |---------------------------------|--------------------------------------| |
Neon X
|
Neon IO X
| -This is a clock based on Pebble's Neon X and Neon IO X watchfaces by Sam Jerichow. -Can be switched between in the Settings menu, which can be accessed through +This is a clock based on Pebble's Neon X and Neon IO X watchfaces by Sam Jerichow. +Can be switched between in the Settings menu, which can be accessed through the app/widget settings menu of the Bangle.js ## Settings @@ -18,3 +18,7 @@ The thickness of watch lines, from 1 to 5. ### Date on touch Shows the current date as DD MM on touch and reverts back to time after 5 seconds or with another touch. + +### Fullscreen +Shows the watchface in fullscreen mode. +Note: In fullscreen mode, widgets are hidden, but still loaded. \ No newline at end of file diff --git a/apps/neonx/metadata.json b/apps/neonx/metadata.json index 41b16d11b..ffa4d1b8e 100644 --- a/apps/neonx/metadata.json +++ b/apps/neonx/metadata.json @@ -2,7 +2,7 @@ "id": "neonx", "name": "Neon X & IO X Clock", "shortName": "Neon X Clock", - "version": "0.01", + "version": "0.02", "description": "Pebble Neon X & Neon IO X for Bangle.js", "icon": "neonx.png", "type": "clock", diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index 967fc8582..d3521b1db 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -34,6 +34,7 @@ const colors = { const is12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false; const screenWidth = g.getWidth(); +const screenHeight = g.getHeight(); const halfWidth = screenWidth / 2; const scale = screenWidth / 240; const REFRESH_RATE = 10E3; @@ -58,16 +59,19 @@ function drawLine(poly, thickness){ } } -let settings = require('Storage').readJSON('neonx.json', 1); - -if (!settings) { - settings = { - thickness: 4, - io: 0, - showDate: 1 - }; +let settings = { + thickness: 4, + io: 0, + showDate: 1, + fullscreen: false, +}; +let saved_settings = require('Storage').readJSON('neonx.json', 1) || settings; +for (const key in saved_settings) { + settings[key] = saved_settings[key] } + + function drawClock(num){ let tx, ty; @@ -79,13 +83,15 @@ function drawClock(num){ g.setColor(colors[settings.io ? 'io' : 'x'][y][x]); if (!settings.io) { - tx = (x * 100 + 18) * newScale; - ty = (y * 100 + 32) * newScale; + newScale *= settings.fullscreen ? 1.18 : 1.0; + let dx = settings.fullscreen ? 0 : 18 + tx = (x * 100 + dx) * newScale; + ty = (y * 100 + dx*2) * newScale; } else { - newScale = 0.33 + current * 0.4; + newScale = 0.33 + current * (settings.fullscreen ? 0.48 : 0.4); - tx = (halfWidth - 139) * newScale + halfWidth; - ty = (halfWidth - 139) * newScale + halfWidth + 12; + tx = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 2 : 0); + ty = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 1 : 12); } for (let i = 0; i < digits[num[y][x]].length; i++) { @@ -116,7 +122,11 @@ function draw(date){ l2 = ('0' + d.getMinutes()).substr(-2); } - g.clearRect(0,24,240,240); + if(settings.fullscreen){ + g.clearRect(0,0,screenWidth,screenHeight); + } else { + g.clearRect(0,24,240,240); + } drawClock([l1, l2]); } @@ -150,4 +160,9 @@ Bangle.on('lcdPower', function(on){ }); Bangle.loadWidgets(); -Bangle.drawWidgets(); + +if(settings.fullscreen){ + for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} +} else { + Bangle.drawWidgets(); +} \ No newline at end of file diff --git a/apps/neonx/neonx.settings.js b/apps/neonx/neonx.settings.js index 0e205e03b..b4b481baf 100644 --- a/apps/neonx/neonx.settings.js +++ b/apps/neonx/neonx.settings.js @@ -7,7 +7,8 @@ neonXSettings = { thickness: 4, io: 0, - showDate: 1 + showDate: 1, + fullscreen: false, }; updateSettings(); @@ -48,7 +49,15 @@ neonXSettings.showDate = v; updateSettings(); } - } + }, + 'Fullscreen': { + value: false | neonXSettings.fullscreen, + format: () => (neonXSettings.fullscreen ? 'Yes' : 'No'), + onchange: () => { + neonXSettings.fullscreen = !neonXSettings.fullscreen; + updateSettings(); + }, + }, }; E.showMenu(menu); }) From 08af40ff9aeed52acebbfe523659dd5a641f9bb2 Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 16 Feb 2022 18:05:22 +0100 Subject: [PATCH 114/447] Allow a thickness of 6 - looks nice in fullscreen mode. --- apps/neonx/README.md | 2 +- apps/neonx/neonx.settings.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/neonx/README.md b/apps/neonx/README.md index c3926c4b6..f205b702f 100644 --- a/apps/neonx/README.md +++ b/apps/neonx/README.md @@ -14,7 +14,7 @@ the app/widget settings menu of the Bangle.js Activate the Neon IO X clock look, a bit hard to read until one gets used to it. ### Thickness -The thickness of watch lines, from 1 to 5. +The thickness of watch lines, from 1 to 6. ### Date on touch Shows the current date as DD MM on touch and reverts back to time after 5 seconds or with another touch. diff --git a/apps/neonx/neonx.settings.js b/apps/neonx/neonx.settings.js index b4b481baf..3af2e0fa5 100644 --- a/apps/neonx/neonx.settings.js +++ b/apps/neonx/neonx.settings.js @@ -18,7 +18,7 @@ if (!neonXSettings) resetSettings(); - let thicknesses = [1, 2, 3, 4, 5]; + let thicknesses = [1, 2, 3, 4, 5, 6]; const menu = { "" : { "title":"Neon X & IO"}, From 307527386e7f75959514fec2ee99d1b6f790a6ab Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 16 Feb 2022 18:07:15 +0100 Subject: [PATCH 115/447] Minor position fix --- apps/neonx/neonx.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index d3521b1db..4ef0986fe 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -91,7 +91,7 @@ function drawClock(num){ newScale = 0.33 + current * (settings.fullscreen ? 0.48 : 0.4); tx = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 2 : 0); - ty = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 1 : 12); + ty = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 2 : 12); } for (let i = 0; i < digits[num[y][x]].length; i++) { From 88e9fca8e46e265b3c855de9ae80b50de1c6e06d Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 16 Feb 2022 19:57:22 +0100 Subject: [PATCH 116/447] Add simple info app --- apps/info/ChangeLog | 1 + apps/info/README.md | 17 +++++++ apps/info/info.app.js | 106 ++++++++++++++++++++++++++++++++++++++++ apps/info/info.icon.js | 1 + apps/info/info.png | Bin 0 -> 1548 bytes apps/info/metadata.json | 18 +++++++ 6 files changed, 143 insertions(+) create mode 100644 apps/info/ChangeLog create mode 100644 apps/info/README.md create mode 100644 apps/info/info.app.js create mode 100644 apps/info/info.icon.js create mode 100644 apps/info/info.png create mode 100644 apps/info/metadata.json diff --git a/apps/info/ChangeLog b/apps/info/ChangeLog new file mode 100644 index 000000000..07afedd21 --- /dev/null +++ b/apps/info/ChangeLog @@ -0,0 +1 @@ +0.01: Release \ No newline at end of file diff --git a/apps/info/README.md b/apps/info/README.md new file mode 100644 index 000000000..007a9794e --- /dev/null +++ b/apps/info/README.md @@ -0,0 +1,17 @@ +# Info + +A very simple app that shows information on 3 different screens. +Go to the next screen via tab right, go to the previous screen +via tab left and reload the data via tab in the middle of the +screen. Very useful if combined with pattern launcher ;) + +![](screenshot_1.png) +![](screenshot_2.png) +![](screenshot_2.png) + + +## Contributors +- [David Peer](https://github.com/peerdavid). + +## Thanks To +Info icons created by Freepik - Flaticon diff --git a/apps/info/info.app.js b/apps/info/info.app.js new file mode 100644 index 000000000..b241907f3 --- /dev/null +++ b/apps/info/info.app.js @@ -0,0 +1,106 @@ +var s = require("Storage"); +const locale = require('locale'); +var ENV = process.env; +var W = g.getWidth(), H = g.getHeight(); +var screen = 0; + +function getVersion(file) { + var j = s.readJSON(file,1); + var v = ("object"==typeof j)?j.version:false; + return v?((v?"v"+v:"Unknown")):"NO "; +} + + +function drawData(name, value, y){ + g.drawString(name, 5, y); + g.drawString(value, 100, y); +} + +function getSteps(){ + try{ + return Bangle.getHealthStatus("day").steps; + } catch(e) { + return ">= 2v12"; + } +} + +function getBpm(){ + try{ + return Math.round(Bangle.getHealthStatus("day").bpm) + " bpm"; + } catch(e) { + return ">= 2v12"; + } +} + +function drawInfo() { + g.reset().clearRect(Bangle.appRect); + var h=18, y = h;//-h; + + // Header + g.setFont("Vector", h+2).setFontAlign(0,-1); + g.drawString("--==|| INFO ||==--", W/2, 0); + g.setFont("Vector",h).setFontAlign(-1,-1); + + // Dynamic data + if(screen == 0){ + drawData("Steps", getSteps(), y+=h); + drawData("HRM", getBpm(), y+=h); + drawData("Battery", E.getBattery() + "%", y+=h); + drawData("Voltage", E.getAnalogVRef().toFixed(2) + "V", y+=h); + drawData("IntTemp.", locale.temp(parseInt(E.getTemperature())), y+=h); + } + + if(screen == 1){ + drawData("Charging?", Bangle.isCharging() ? "Yes" : "No", y+=h); + drawData("Bluetooth", NRF.getSecurityStatus().connected ? "Conn." : "Disconn.", y+=h); + drawData("GPS", Bangle.isGPSOn() ? "On" : "Off", y+=h); + drawData("Compass", Bangle.isCompassOn() ? "On" : "Off", y+=h); + drawData("HRM", Bangle.isHRMOn() ? "On" : "Off", y+=h); + } + + // Static data + if(screen == 2){ + drawData("Firmw.", ENV.VERSION, y+=h); + drawData("Boot.", getVersion("boot.info"), y+=h); + drawData("Settings", getVersion("setting.info"), y+=h); + drawData("Storage", "", y+=h); + drawData(" Total", ENV.STORAGE>>10, y+=h); + drawData(" Free", require("Storage").getFree()>>10, y+=h); + } + + if(Bangle.isLocked()){ + g.setFont("Vector",h-2).setFontAlign(-1,-1); + g.drawString("Locked", 0, H-h+2); + } + + g.setFont("Vector",h-2).setFontAlign(1,-1); + g.drawString((screen+1) + "/3", W, H-h+2); +} + +drawInfo(); +setWatch(_=>load(), BTN1); + +Bangle.on('touch', function(btn, e){ + var left = parseInt(g.getWidth() * 0.3); + var right = g.getWidth() - left; + var isLeft = e.x < left; + var isRight = e.x > right; + + if(isRight){ + screen = (screen + 1) % 3; + } + + if(isLeft){ + screen = Math.max(0, (screen - 1)); + } + + drawInfo(); +}); + +Bangle.on('lock', function(isLocked) { + drawInfo(); +}); + +Bangle.loadWidgets(); +for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} +// Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/info/info.icon.js b/apps/info/info.icon.js new file mode 100644 index 000000000..8dbab8357 --- /dev/null +++ b/apps/info/info.icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcBkmSpICDBwcJBYwCDpAhFggRJGg8SCI+ABgU//gSDCI4JBj//AAX4JRAIBg4QDAAPgBIJWGgIQFAAI+BLglAgEPCI/wEgJoEgYQHAAPANwhWFAApcBCIWQgAQJAAMAgSMDCJiSCwB6GQA6eCn5TFL4q5BUgIRF/wuBv4RGkCeGO4IREUgMBCJCVGCISwIWw0BYRLIICLBHHCJRrGCIQIFR44I5LIoRaPpARcdIwRJfYMBCJuACKUkgE/a5f8gEJCJD7FCIeAg78FAAvggFJCIMACJZOBCIOQCJsCCIOSgEfCBP4gESCIZTFOIwRDoDIGaguSCIVIgCkFTwcAggRDpIYBQAx6BgAOCAQYIBLghWBTwQRFFgIABXIIFDBwgCDBYQAENAYCFLgIAEKwpKIIhA=")) diff --git a/apps/info/info.png b/apps/info/info.png new file mode 100644 index 0000000000000000000000000000000000000000..c73813025950aaccc31b7476b67ceb6326b5f915 GIT binary patch literal 1548 zcmV+n2J`ueP)&f>~B9rWa~T zO&bJa&{8T~N=wOnsPP9`P{G7MVAx;4pjMrUnq>u3O-u&aq>I5{OcTJi(H~mE+Gfk` zhf%z{UZL%^)V-5S?s@KcKA+d;p68x>?s-lCJcJM`j>qHsVzJmqkw`=t2n3XO?%er& zqdID}dak;<`dMXVI(xU#bHT_6xR>G%8PGcz;NZ0s~N zG%U$vvRR2l;wmpMzr`nzv}L#3NMqE?>U9sV}3^`177Udj^Y&ihNF|^Y3){HkHX_ z>Vgz^uDQ9Hx_I#-m8nKXMyO-Qj-_l7v)OE$oSZD;4S)Ld>7i6kawUyM!)d>>vvV|S zaD>nY27_UO%kb3HRL)j5ALy~a-T<{$o9eDw#%WO6$1)vYg-1N(D?XxQV}@xNctk%xpOD4x1`Z%WTd51>G=A70zybg5X4iUO_JPhH?K*TTrQtZ z*gACR5bxP2olT`u`I44a);1UZ7t1PreSKQaX432RZhAqp*<5ILiX=$}yjH9Aq+IBA zI2@m`qdkBAe8J$kmKLp6>o;^}##Cb4wr%rg&YbC|=bbxu4z6Fn&KYn%b^G>huvjdN zyzcJqA4*C}o^DtXA%v|hWiukba^*@v?|fTZ+fN&=OtW?3#EB`kkyEEmJs? z`0?YvWVFEn05C8xP@~i79fFvXm(BVxnoIvU-OZ#@ss601s~g(Ad-pw(B>zgcUe-T*L?RK@^73+r z-|zp@>-A=}prlkPU&~~&=TfP3yrQCFGMk@0c+C*ky4LTko@l5yPs}U y=jhR+zwg?$YqqMY>dE%)+keAx+{foHm45-pmUCXlaFiAR0000 Date: Wed, 16 Feb 2022 20:00:33 +0100 Subject: [PATCH 117/447] Added screenshots --- apps/info/screenshot_1.png | Bin 0 -> 3552 bytes apps/info/screenshot_2.png | Bin 0 -> 3334 bytes apps/info/screenshot_3.png | Bin 0 -> 3455 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/info/screenshot_1.png create mode 100644 apps/info/screenshot_2.png create mode 100644 apps/info/screenshot_3.png diff --git a/apps/info/screenshot_1.png b/apps/info/screenshot_1.png new file mode 100644 index 0000000000000000000000000000000000000000..97d42a89636e01437a6397075db1dc453ca22fe8 GIT binary patch literal 3552 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 literal 0 HcmV?d00001 diff --git a/apps/info/screenshot_2.png b/apps/info/screenshot_2.png new file mode 100644 index 0000000000000000000000000000000000000000..2d25dd4e6ce4166d5a6b48ad7f50231bf643cc95 GIT binary patch literal 3334 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 literal 0 HcmV?d00001 diff --git a/apps/info/screenshot_3.png b/apps/info/screenshot_3.png new file mode 100644 index 0000000000000000000000000000000000000000..782e4a1952f1dc3205f20852edf88e9493edd6d8 GIT binary patch literal 3455 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 Xk+%_!CsMW>72tTx)$W-M?(+Wt^h|>m literal 0 HcmV?d00001 From 88ea3bd0b11f3f946939647a7647cecca94663f4 Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 16 Feb 2022 20:02:20 +0100 Subject: [PATCH 118/447] Added README to metadata --- apps/info/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/info/metadata.json b/apps/info/metadata.json index 9b82acb4e..f05f0e134 100644 --- a/apps/info/metadata.json +++ b/apps/info/metadata.json @@ -6,6 +6,7 @@ "icon": "info.png", "type": "app", "tags": "tool", + "readme": "README.md", "supports": ["BANGLEJS2"], "screenshots": [ {"url":"screenshot_1.png"}, From 50f973b3d3779ef883aab748bbbf3fca39ca2184 Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 16 Feb 2022 20:44:35 +0100 Subject: [PATCH 119/447] Pagination bugfix. --- apps/info/info.app.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/info/info.app.js b/apps/info/info.app.js index b241907f3..bce9d4cff 100644 --- a/apps/info/info.app.js +++ b/apps/info/info.app.js @@ -3,6 +3,7 @@ const locale = require('locale'); var ENV = process.env; var W = g.getWidth(), H = g.getHeight(); var screen = 0; +const maxScreen = 2; function getVersion(file) { var j = s.readJSON(file,1); @@ -87,11 +88,12 @@ Bangle.on('touch', function(btn, e){ var isRight = e.x > right; if(isRight){ - screen = (screen + 1) % 3; + screen = (screen + 1) % (maxScreen+1); } if(isLeft){ - screen = Math.max(0, (screen - 1)); + screen -= 1; + screen = screen < 0 ? maxScreen : screen; } drawInfo(); From 9dd3e9b06925b848d89eadd9ec46d7ada4085a0a Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 16 Feb 2022 20:02:56 +0000 Subject: [PATCH 120/447] Pastel: make new boolean setting work --- apps/pastel/ChangeLog | 1 + apps/pastel/metadata.json | 2 +- apps/pastel/pastel.settings.js | 32 +++++++++++--------------------- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog index d133697b3..a77fa758f 100644 --- a/apps/pastel/ChangeLog +++ b/apps/pastel/ChangeLog @@ -16,3 +16,4 @@ 0.14: incorporated lazybones idle timer, configuration settings to come 0.15: fixed tendancy for mylocation to default to London added setting to enable/disable idle timer warning +0.16: make check_idle boolean setting work properly with new B2 menu diff --git a/apps/pastel/metadata.json b/apps/pastel/metadata.json index da3c18eae..f04a7ae54 100644 --- a/apps/pastel/metadata.json +++ b/apps/pastel/metadata.json @@ -2,7 +2,7 @@ "id": "pastel", "name": "Pastel Clock", "shortName": "Pastel", - "version": "0.15", + "version": "0.16", "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", "icon": "pastel.png", "dependencies": {"mylocation":"app","weather":"app"}, diff --git a/apps/pastel/pastel.settings.js b/apps/pastel/pastel.settings.js index 26dafd271..afe461f15 100644 --- a/apps/pastel/pastel.settings.js +++ b/apps/pastel/pastel.settings.js @@ -38,38 +38,28 @@ }, }, 'Show Grid': { - value: s.grid, - format: () => (s.grid ? 'Yes' : 'No'), - onchange: () => { - s.grid = !s.grid; + value: !!s.grid, + format: v => v ? /*LANG*/"Yes":/*LANG*/"No", + onchange: v => { + s.grid = v; save(); }, }, 'Show Weather': { - value: s.weather, - format: () => (s.weather ? 'Yes' : 'No'), - onchange: () => { - s.weather = !s.weather; + value: !!s.weather, + format: v => v ? /*LANG*/"Yes":/*LANG*/"No", + onchange: v => { + s.weather = v; save(); }, }, - // for use when the new menu system goes live - /* 'Idle Warning': { - value: s.idle_check, - onchange : v => { + value: !!s.idle_check, + format: v => v ? /*LANG*/"Yes":/*LANG*/"No", + onchange: v => { s.idle_check = v; save(); }, - }, - */ - 'Idle Warning': { - value: s.idle_check, - format: () => (s.idle_check ? 'Yes' : 'No'), - onchange: () => { - s.idle_check = !s.idle_check; - save(); - }, } }) }) From ece775bb8ea0e38d38123116fa49865923b6cc1f Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 16 Feb 2022 21:31:46 +0100 Subject: [PATCH 121/447] Minor change --- apps/info/info.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/info/info.app.js b/apps/info/info.app.js index bce9d4cff..c61a88045 100644 --- a/apps/info/info.app.js +++ b/apps/info/info.app.js @@ -27,7 +27,7 @@ function getSteps(){ function getBpm(){ try{ - return Math.round(Bangle.getHealthStatus("day").bpm) + " bpm"; + return Math.round(Bangle.getHealthStatus("day").bpm) + "bpm"; } catch(e) { return ">= 2v12"; } From 864faef9617c2e551093abff341aa8f3d2a62d57 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 16 Feb 2022 21:59:28 +0100 Subject: [PATCH 122/447] widbars - Yellow battery bar on charge and prevent GC on every draw --- apps/widbars/ChangeLog | 2 ++ apps/widbars/metadata.json | 2 +- apps/widbars/widget.js | 10 ++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/widbars/ChangeLog b/apps/widbars/ChangeLog index 4c21f3ace..61e28e6e4 100644 --- a/apps/widbars/ChangeLog +++ b/apps/widbars/ChangeLog @@ -1 +1,3 @@ 0.01: New Widget! +0.02: Battery bar turns yellow on charge + Memory status bar does not trigger garbage collect diff --git a/apps/widbars/metadata.json b/apps/widbars/metadata.json index e8d52c90a..a9981305c 100644 --- a/apps/widbars/metadata.json +++ b/apps/widbars/metadata.json @@ -1,7 +1,7 @@ { "id": "widbars", "name": "Bars Widget", - "version": "0.01", + "version": "0.02", "description": "Display several measurements as vertical bars.", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/widbars/widget.js b/apps/widbars/widget.js index a1134f31f..cceeb0897 100644 --- a/apps/widbars/widget.js +++ b/apps/widbars/widget.js @@ -42,19 +42,25 @@ if (top) g .clearRect(x,y, x+w-1,y+top-1); // erase above bar if (f) g.setColor(col).fillRect(x,y+top, x+w-1,y+h-1); // even for f=0.001 this is still 1 pixel high } + let batColor='#0f0'; function draw() { g.reset(); const x = this.x, y = this.y, - m = process.memory(); + m = process.memory(false); let b=0; // ==HRM== bar(x+(w*b++),y,'#f00'/*red */,bpm/200); // >200 seems very unhealthy; if we have no valid bpm this will just be empty space // ==Temperature== bar(x+(w*b++),y,'#ff0'/*yellow */,E.getTemperature()/50); // you really don't want to wear a watch that's hotter than 50°C bar(x+(w*b++),y,g.theme.dark?'#0ff':'#00f'/*cyan/blue*/,1-(require('Storage').getFree() / process.env.STORAGE)); bar(x+(w*b++),y,'#f0f'/*magenta*/,m.usage/m.total); - bar(x+(w*b++),y,'#0f0'/*green */,E.getBattery()/100); + bar(x+(w*b++),y,batColor,E.getBattery()/100); } let redraw; + Bangle.on('charging', function(charging) { + batColor=charging?'#ff0':'#0f0'; + WIDGETS["bars"].draw(); + }); + Bangle.on('lcdPower', on => { if (redraw) clearInterval(redraw) redraw = undefined; From 63156bcca81875e7b61f6f64a69492e513f9e246 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Thu, 17 Feb 2022 02:42:21 +0100 Subject: [PATCH 123/447] v 0.04 fixes #1154 --- apps/timecal/ChangeLog | 9 + apps/timecal/README.md | 22 + apps/timecal/metadata.json | 11 +- apps/timecal/testing/timecal.app.test.js | 798 +++++++++++++++++++++++ apps/timecal/timecal.app.js | 352 +++++++--- apps/timecal/timecal.settings.js | 109 ++++ 6 files changed, 1211 insertions(+), 90 deletions(-) create mode 100644 apps/timecal/ChangeLog create mode 100644 apps/timecal/README.md create mode 100644 apps/timecal/testing/timecal.app.test.js create mode 100644 apps/timecal/timecal.settings.js diff --git a/apps/timecal/ChangeLog b/apps/timecal/ChangeLog new file mode 100644 index 000000000..43bff461d --- /dev/null +++ b/apps/timecal/ChangeLog @@ -0,0 +1,9 @@ +0.01: Initial creation of the clock face time and calendar +0.02: Feature Request #1154 and some findings... + -> get rendered time from optimisations + -> *BATT SAFE* only update once a minute instead of once a second + -> *RAM optimized* clean code, corrected minute update (timout, no intervall) + -> locale: weekday name (first two characters) from locale + -> added settings to render cal view begin day (-1: today, 0:sunday, 1:monday [default]) +0.03: a lot of more settings for outline, colors and highlights +0.04: finalized README, fixed settings cancel, fixed border-setting \ No newline at end of file diff --git a/apps/timecal/README.md b/apps/timecal/README.md new file mode 100644 index 000000000..d26f9ba4d --- /dev/null +++ b/apps/timecal/README.md @@ -0,0 +1,22 @@ +# Calendar Clock + +## Features +Shows the +* Date +* Time (hh:mm) - respecting 12/24 (uses locale string) +* 3 weeks calendar view (last,current and next week) + +### The settings menu +Calendar View can be customized +* < Save: Exist and save the current settings +* Show date: Choose if and how the date is displayed: none, locale (default), monthfull or monthshort.yearshort #weeknum with 0 prefixed +* Start wday: Set day of week start. Values: 0=Sunday, 1=Monday,...,6=Saturday or -1=Relative to today (default 0: Sunday) +* Su color: Set Sundays color. Values: none (default), red, green or blue +* Border: show or none (default) +* Submenu Today settings - choose how today is highlighted + * < Back: + * Color: none, red (default), green or blue + * Marker: Outline today graphically. Values: none (default), circle, rect(angle) + * Mrk.Color: Circle/rectangle color: red (default), green or blue + * Mrk.Size: Circle/rectangle thickness in pixel: min:1, max: 10, default:3 +* < Cancel: Exit and no change. Nevertheless missing default settings and superflous settings will be removed and saved. diff --git a/apps/timecal/metadata.json b/apps/timecal/metadata.json index 3237dd08a..4dd8a8ca0 100644 --- a/apps/timecal/metadata.json +++ b/apps/timecal/metadata.json @@ -1,13 +1,16 @@ { "id": "timecal", "name": "TimeCal", "shortName":"TimeCal", + "version":"0.04", + "description": "TimeCal shows the date/time along with a 3 week calendar", "icon": "icon.png", - "version":"0.01", - "description": "TimeCal shows the Time along with a 3 week calendar", - "tags": "clock", "type": "clock", + "tags": "clock,calendar", "supports":["BANGLEJS2"], + "readme": "README.md", + "allow_emulator":true, "storage": [ - {"name":"timecal.app.js","url":"timecal.app.js"} + {"name":"timecal.app.js","url":"timecal.app.js"}, + {"name":"timecal.settings.js","url":"timecal.settings.js"} ] } diff --git a/apps/timecal/testing/timecal.app.test.js b/apps/timecal/testing/timecal.app.test.js new file mode 100644 index 000000000..e41f3d848 --- /dev/null +++ b/apps/timecal/testing/timecal.app.test.js @@ -0,0 +1,798 @@ +//Clock renders date, time and pre,current,next week calender view +class TimeCalClock{ + DATE_FONT_SIZE(){ return 20; } + TIME_FONT_SIZE(){ return 40; } + + /** + * @param{Date} date optional the date (e.g. for testing) + * @param{Settings} settings optional settings to use e.g. for testing + */ + constructor(date, settings){ + if (date) + this.date=date; + + if (settings) + this._settings = settings; + else + this._settings = require("Storage").readJSON("timecal.settings.json", 1) || {}; + + const defaults = { + shwDate:1, //0:none, 1:locale, 2:month, 3:monthshort.year #week + + wdStrt:0, //identical to getDay() 0->Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today + + tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled + tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkPxl:3, //px + + suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + //phColor:"#E00", //public holiday + + calBrdr:false + }; + for (const k in this._settings) if (!defaults.hasOwnProperty(k)) delete this._settings[k]; //remove invalid settings + for (const k in defaults) if(!this._settings.hasOwnProperty(k)) this._settings[k] = defaults[k]; //assign missing defaults + + g.clear(); + Bangle.setUI("clock"); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + + this.centerX = Bangle.appRect.w/2; + this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b + + this.ABR_DAY=[]; + if (require("locale") && require("locale").dow) + for (let d=0; d<=6; d++) { + var refDay=new Date(); + refDay.setFullYear(1972); + refDay.setMonth(0); + refDay.setDate(2+d); + this.ABR_DAY.push(require("locale").dow(refDay)); + + } + else + this.ABR_DAY=["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + } + + /** + * @returns {Object} current settings object + */ + settings(){ + return this._settings; + } + + + /* + * Run forest run + **/ + draw(){ + this.drawTime(); + + if (this.TZOffset===undefined || this.TZOffset!==d.getTimezoneOffset()) + this.drawDateAndCal(); + } + + /** + * draw given or current time from date + * overwatch timezone changes + * schedules itself to update + */ + drawTime(){ + d=this.date ? this.date : new Date(); + const Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10; + + d=d?d :new Date(); + + g.setFontAlign(0, -1).setFont("Vector", this.TIME_FONT_SIZE()).setColor(g.theme.fg) + .clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7) + .drawString(("0" + require("locale").time(d, 1)).slice(-5), this.centerX, Y, true); + //.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); //DEV-Option + + setTimeout(this.draw.bind(this), 60000-(d.getSeconds()*1000)-d.getMilliseconds()); + } + + /** + * draws given date and cal + * @param{Date} d provide date or uses today + */ + drawDateAndCal(){ + d=this.date ? this.date : new Date(); + + this.TZOffset=d.getTimezoneOffset(); + this.drawDate(); + this.drawCal(); + + if (this.tOutD) //abort exisiting + clearTimeout(this.tOutD); + this.tOutD=setTimeout(this.drawDateAndCal.bind(this), 86400000-(d.getHours()*24*60*1000)-(d.getMinutes()*60*1000)-d.getSeconds()-d.getMilliseconds()); + } + + /** + * draws given date as defiend in settings + */ + drawDate(){ + d=this.date ? this.date : new Date(); + + const FONT_SIZE=20; + const Y=Bangle.appRect.y; + var render=false; + var dateStr = ""; + if (this.settings().shwDate>0) { //skip if exactly -none + const dateSttngs = ["","l","M","m.Y #W"]; + for (let c of dateSttngs[this.settings().shwDate]) { //add part as configured + switch (c){ + case "l":{ //locale + render=true; + dateStr+=require("locale").date(d,1); + break; + } + case "m":{ //month e.g. Jan. + render=true; + dateStr+=require("locale").month(d,1); + break; + } + case "M":{ //month e.g. January + render=true; + dateStr+=require("locale").month(d,0); + break; + } + case "y":{ //year e.g. 22 + render=true; + dateStr+=d.getFullYear().slice(-2); + break; + } + case "Y":{ //year e.g. 2022 + render=true; + dateStr+=d.getFullYear(); + break; + } + case "w":{ //week e.g. #2 + dateStr+=(this.ISO8601calWeek(d)); + break; + } + case "W":{ //week e.g. #02 + dateStr+=("0"+this.ISO8601calWeek(d)).slice(-2); + break; + } + default: //append c + dateStr+=c; + render=dateStr.length>0; + break; //noop + } + } + } + if (render){ + g.setFont("Vector", FONT_SIZE).setColor(g.theme.fg).setFontAlign(0, -1).clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3).drawString(dateStr,this.centerX,Y); + } + //g.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); //DEV-Option + } + + /** + * draws calender week view (-1,0,1) for given date + */ + drawCal(){ + d=this.date ? this.date : new Date(); + + const DAY_NAME_FONT_SIZE=10; + const CAL_Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10+this.TIME_FONT_SIZE()+3; + const CAL_AREA_H=Bangle.appRect.h-CAL_Y+24; //+24: top widegtes only + const CELL_W=Bangle.appRect.w/7; //cell width + const CELL_H=(CAL_AREA_H-DAY_NAME_FONT_SIZE)/3; //cell heigth + const DAY_NUM_FONT_SIZE=Math.min(CELL_H-1,15); //size down, max 15 + + g.setFont("Vector", DAY_NAME_FONT_SIZE).setColor(g.theme.fg).setFontAlign(-1, -1).clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H); + + //draw grid & Headline + const dNames = this.ABR_DAY.map((a) => a.length<=2 ? a : a.substr(0, 2)); //force shrt 2 + for(var dNo=0; dNo=0 ? (dNo+this.settings().wdStrt)%7 : (dNo+d.getDay()+4)%7; + const dName=dNames[dIdx]; + if(dNo>0) + g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1); + + if (dIdx==0) g.setColor(this.nrgb[this.settings().suClr]); //sunday maybe colorize txt + g.drawString(dName, dNo*CELL_W+(CELL_W-g.stringWidth(dName))/2+2, CAL_Y+1).setColor(g.theme.fg); + } + + var nextY=CAL_Y+DAY_NAME_FONT_SIZE; + + for(i=0; i<3; i++){ + const y=nextY+i*CELL_H; + g.drawLine(Bangle.appRect.x, y, Bangle.appRect.x2, y); + } + + g.setFont("Vector", DAY_NUM_FONT_SIZE); + + //write days + const tdyDate=d.getDate(); + const days=this.settings().wdStrt>=0 ? 7+((7+d.getDay()-this.settings().wdStrt)%7) : 10;//start day (week before=7 days + days in this week realtive to week start) or fixed 7+3 days + var rD=new Date(d.getTime()); + rD.setDate(rD.getDate()-days); + var rDate=rD.getDate(); + for(var y=0; y<3; y++){ + for(var x=0; x", + cases: [ + { + value: "required,", + beforeTxt: "optional,", + beforeExpression: "optional,", + afterText: "optional,", + afterExpression: "optional," + } + ], + constructorParams: ["optional: ","|TEST_SETTINGS|","..."], //TEST_SETTINGS will be replcaed with each current {setting: case} + functionNames: ["required, ", "..."], + functionParams: ["optional: ","|TEST_SETTINGS|","..."] + }; + } + + constructor(data){ + + this._validate(data); + + this.setting = data.setting; + this.cases = data.cases.map((entry) => { + return { + value: entry.value, + beforeTxt: entry.beforeTxt||"", + beforeExpression: entry.beforeExpression||true, + afterTxt: entry.afterTxt||"", + afterExpression: entry.afterExpression||true + }; + }); + this.constructorParams = data.constructorParams; + this.functionNames = data.functionNames; + this.functionParams = data.functionParams; + } + + /** + * validates the given data config + */ + _validate(data){ + //validate given config + if (!data.setting) throw new EmptyMandatoryError("setting", data, this.TEST_SETTING_SAMPLE()); + if (!(data.cases instanceof Array) || data.cases.length==0) throw new EmptyMandatoryError("cases", data, this.TEST_SETTING_SAMPLE()); + if (!(data.functionNames instanceof Array) || data.functionNames==0) throw new EmptyMandatoryError("functionNames", data, this.TEST_SETTING_SAMPLE()); + + data.cases.forEach((entry,idx) => { + if (entry.value === undefined) throw new EmptyMandatoryError("cases["+idx+"].value", entry, this.TEST_SETTING_SAMPLE()); + }); + } +} + +/*************************************************************************/ + +/** + * Testing a Bangle object + */ +class BangleTestRunner{ + /** + * create for ObjClass + * @param {Class} objClass + * @param {LogSeverity} minSeverity to Log + */ + constructor(objClass, minSeverity){ + this.TESTCASE_MSG_BEFORE_TIMEOUT = 1000; //5s + this.TESTCASE_RUN_TIMEOUT = 1000; //5s + this.TESTCASE_MSG_AFTER_TIMEOUT = 1000; //5s + + this.oClass = objClass; + this.minSvrty = minSeverity; + this.tests = []; + + this.currentCaseNum = this.currentTestNum = this.currentTest = this.currentCase = undefined; + } + + /** + * add a Setting Test, return instance for chaining + * @param {TestSetting} + */ + addTestSettings(sttngs) { + this.tests.push(new TestSetting(sttngs)); + return this; + } + + /** + * Test execution of all tests + */ + execute() { + this._init(); + while (this._nextTest()) { + this._beforeTest(); + while (this._nextCase()) { + this._beforeCase(); + this._runCase(); + this._afterCase(); + } + this._afterTest(); + this._firstCase(); + } + this._exit(); + } + + /** + * global prepare - before all test + */ + _init() { + console.log(this._nowTime(), ">>init"); + this.currentTestNum=-1; + this.currentCaseNum=-1; + } + + /** + * before each test + */ + _beforeTest() { + console.log(this._nowTime(), ">>test #" + this.currentTestNum); + } + + /** + * befor each testcase + */ + _beforeCase() { + console.log(this.currentTest); + console.log(this._nowTime(), ">>case #" + this.currentTestNum + "." + this.currentCaseNum + "/" + (this.currentTest.cases.length-1)); + if (this.currentTest instanceof TestSetting) + console.log(this.currentTest.setting+"="+this.currentCase.value+"/n"+(this.currentCase.beforeTxt ? "#"+this.currentCase.beforeTxt : "")); + } + + /** + * testcase runner + */ + _runCase() { + console.log(this._nowTime(), ">>running..."); + var returns = []; + this.currentTest.functionNames.forEach((fName) => { + var settings={}; settings[this.currentTest.setting] = this.currentCase.value; + var cParams = this.currentTest.constructorParams||[]; + cParams = cParams.map((v) => (v && v instanceof String && v==="|TEST_SETTINGS|") ? settings : v);//replace settings in call params + var fParams = this.currentTest.functionParams||[]; + fParams = fParams.map((v) => (v && v instanceof String && v==="|TEST_SETTINGS|") ? settings : v);//replace settings in call params + + var creatorFunc = new Function("console.log('Constructor params:', arguments); return new " + this.oClass + "(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8],arguments[9])"); //prepare spwan arguments[0],arguments[1] + let instance = creatorFunc.call(this.oClass, cParams[0], cParams[1], cParams[2], cParams[3], cParams[4], cParams[5], cParams[6], cParams[7], cParams[8], cParams[9]); //spwan + + console.log(">>"+this.oClass+"["+fName+"]()"); + + console.log('Instance:', instance); + console.log('Function params:', fParams); + returns.push(instance[fName](fParams[0], fParams[1], fParams[2], fParams[3], fParams[4], fParams[5], fParams[6], fParams[7], fParams[8], fParams[9])); //run method and store result + g.dump(); + console.log("<<"+this.oClass+"["+fName+"]()"); + }); + console.log(this._nowTime(), "<<...running"); + } + + /** + * after each testcase + */ + _afterCase() { + if (this.currentTest instanceof TestSetting) + if (this.currentCase.afterTxt.length>0) + console.log("++EXPECTED:" + this.currentCase.afterTxt + "EXPECTED++"); + console.log(this._nowTime(), "< setTimeout(resolve, sec)); + } + + _waits(sec) { + this._delay(1).then(); + } + + _log() { + + } + + _nextTest() { + if (this.currentTestNum>=-1 && (this.currentTestNum+1)=-1 && (this.currentCaseNum+1)Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today + + tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled + tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkPxl:3, //px + + suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + //phColor:"#E00", //public holiday + + calBrdr:false + }; + for (const k in this._settings) if (!defaults.hasOwnProperty(k)) delete this._settings[k]; //remove invalid settings + for (const k in defaults) if(!this._settings.hasOwnProperty(k)) this._settings[k] = defaults[k]; //assign missing defaults + + g.clear(); + Bangle.setUI("clock"); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + + this.centerX = Bangle.appRect.w/2; + this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b + + this.ABR_DAY=[]; + if (require("locale") && require("locale").dow) + for (let d=0; d<=6; d++) { + var refDay=new Date(); + refDay.setFullYear(1972); + refDay.setMonth(0); + refDay.setDate(2+d); + this.ABR_DAY.push(require("locale").dow(refDay)); -function drawCal(d){ - var calStart = 101; - var cellSize = g.getWidth() / 7; - var halfSize = cellSize / 2; - g.clearRect(0,calStart,g.getWidth(),g.getHeight()); - g.drawLine(0,calStart,g.getWidth(),calStart); - var days = ["Mo","Tu","We","Th","Fr","Sa","Su"]; - g.setFont("Vector",10); - g.setColor(fontColor); - g.setFontAlign(-1,-1,0); - for(var i = 0; i < days.length;i++){ - g.drawString(days[i],i*cellSize+5,calStart -11); - if(i!=0){ - g.drawLine(i*cellSize,calStart,i*cellSize,g.getHeight()); - } - } - var cellHeight = (g.getHeight() -calStart ) / 3; - for(var i = 0;i < 3;i++){ - var starty = calStart + i * cellHeight; - g.drawLine(0,starty,g.getWidth(),starty); - } - - g.setFont("Vector",15); - - var dayOfWeek = d.getDay(); - var dayRem = d.getDay() - 1; - if(dayRem <0){ - dayRem = 0; - } - - var start = new Date(); - start.setDate(start.getDate()-(7+dayRem)); - g.setFontAlign(0,-1,0); - for (var y = 0;y < 3; y++){ - for(var x = 0;x < 7; x++){ - if(start.getDate() === d.getDate()){ - g.setColor(accentColor); - }else{ - g.setColor(fontColor); } - g.drawString(start.getDate(),x*cellSize +(cellSize / 2) + 2,calStart+(cellHeight*y) + 5); - start.setDate(start.getDate()+1); + else + this.ABR_DAY=["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + } + + /** + * @returns {Object} current settings object + */ + settings(){ + return this._settings; + } + + + /* + * Run forest run + **/ + draw(){ + this.drawTime(); + + if (this.TZOffset===undefined || this.TZOffset!==d.getTimezoneOffset()) + this.drawDateAndCal(); } + + /** + * draw given or current time from date + * overwatch timezone changes + * schedules itself to update + */ + drawTime(){ + d=this.date ? this.date : new Date(); + const Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10; + + d=d?d :new Date(); + + g.setFontAlign(0, -1).setFont("Vector", this.TIME_FONT_SIZE()).setColor(g.theme.fg) + .clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7) + .drawString(("0" + require("locale").time(d, 1)).slice(-5), this.centerX, Y, true); + //.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); //DEV-Option + + setTimeout(this.draw.bind(this), 60000-(d.getSeconds()*1000)-d.getMilliseconds()); + } + + /** + * draws given date and cal + * @param{Date} d provide date or uses today + */ + drawDateAndCal(){ + d=this.date ? this.date : new Date(); + + this.TZOffset=d.getTimezoneOffset(); + this.drawDate(); + this.drawCal(); + + if (this.tOutD) //abort exisiting + clearTimeout(this.tOutD); + this.tOutD=setTimeout(this.drawDateAndCal.bind(this), 86400000-(d.getHours()*24*60*1000)-(d.getMinutes()*60*1000)-d.getSeconds()-d.getMilliseconds()); + } + + /** + * draws given date as defiend in settings + */ + drawDate(){ + d=this.date ? this.date : new Date(); + + const FONT_SIZE=20; + const Y=Bangle.appRect.y; + var render=false; + var dateStr = ""; + if (this.settings().shwDate>0) { //skip if exactly -none + const dateSttngs = ["","l","M","m.Y #W"]; + for (let c of dateSttngs[this.settings().shwDate]) { //add part as configured + switch (c){ + case "l":{ //locale + render=true; + dateStr+=require("locale").date(d,1); + break; + } + case "m":{ //month e.g. Jan. + render=true; + dateStr+=require("locale").month(d,1); + break; + } + case "M":{ //month e.g. January + render=true; + dateStr+=require("locale").month(d,0); + break; + } + case "y":{ //year e.g. 22 + render=true; + dateStr+=d.getFullYear().slice(-2); + break; + } + case "Y":{ //year e.g. 2022 + render=true; + dateStr+=d.getFullYear(); + break; + } + case "w":{ //week e.g. #2 + dateStr+=(this.ISO8601calWeek(d)); + break; + } + case "W":{ //week e.g. #02 + dateStr+=("0"+this.ISO8601calWeek(d)).slice(-2); + break; + } + default: //append c + dateStr+=c; + render=dateStr.length>0; + break; //noop + } + } + } + if (render){ + g.setFont("Vector", FONT_SIZE).setColor(g.theme.fg).setFontAlign(0, -1).clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3).drawString(dateStr,this.centerX,Y); + } + //g.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); //DEV-Option + } + + /** + * draws calender week view (-1,0,1) for given date + */ + drawCal(){ + d=this.date ? this.date : new Date(); + + const DAY_NAME_FONT_SIZE=10; + const CAL_Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10+this.TIME_FONT_SIZE()+3; + const CAL_AREA_H=Bangle.appRect.h-CAL_Y+24; //+24: top widegtes only + const CELL_W=Bangle.appRect.w/7; //cell width + const CELL_H=(CAL_AREA_H-DAY_NAME_FONT_SIZE)/3; //cell heigth + const DAY_NUM_FONT_SIZE=Math.min(CELL_H-1,15); //size down, max 15 + + g.setFont("Vector", DAY_NAME_FONT_SIZE).setColor(g.theme.fg).setFontAlign(-1, -1).clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H); + + //draw grid & Headline + const dNames = this.ABR_DAY.map((a) => a.length<=2 ? a : a.substr(0, 2)); //force shrt 2 + for(var dNo=0; dNo=0 ? (dNo+this.settings().wdStrt)%7 : (dNo+d.getDay()+4)%7; + const dName=dNames[dIdx]; + if(dNo>0) + g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1); + + if (dIdx==0) g.setColor(this.nrgb[this.settings().suClr]); //sunday maybe colorize txt + g.drawString(dName, dNo*CELL_W+(CELL_W-g.stringWidth(dName))/2+2, CAL_Y+1).setColor(g.theme.fg); + } + + var nextY=CAL_Y+DAY_NAME_FONT_SIZE; + + for(i=0; i<3; i++){ + const y=nextY+i*CELL_H; + g.drawLine(Bangle.appRect.x, y, Bangle.appRect.x2, y); + } + + g.setFont("Vector", DAY_NUM_FONT_SIZE); + + //write days + const tdyDate=d.getDate(); + const days=this.settings().wdStrt>=0 ? 7+((7+d.getDay()-this.settings().wdStrt)%7) : 10;//start day (week before=7 days + days in this week realtive to week start) or fixed 7+3 days + var rD=new Date(d.getTime()); + rD.setDate(rD.getDate()-days); + var rDate=rD.getDate(); + for(var y=0; y<3; y++){ + for(var x=0; xSu, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today + + tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled + tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkPxl:3, //px + + suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + //phColor:"#E00", //public holiday + + calBrdr:false + }; + validSttngs = require("Storage").readJSON("timecal.validSttngs.json", 1) || {}; + for (const k in validSttngs) if (!DEFAULTS.hasOwnProperty(k)) delete this.validSttngs[k]; //remove invalid settings + for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = validSttngs[k]; //assign missing defaults + + var changedSttngs = Object.assign({}, validSttngs); + + var saveExitSettings = () => { + require('Storage').writeJSON(FILE, changedSttngs); + exit(); + }; + + var cancelExitSettings = () => { + require('Storage').writeJSON(FILE, validSttngs); + exit(); + }; + + var showMainMenu = () => { + E.showMenu({ + "": { + "title": "TimeCal "+ /*LANG*/"settings" + }, + /*LANG*/"< Save": () => saveExitSettings(), + /*LANG*/"Show date": { + value: validSttngs.shwDate, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"locale", /*LANG*/"M", /*LANG*/"m.Y #W"][v], + onchange: v => validSttngs.shwDate = v + }, + /*LANG*/"Start wday": { + value: validSttngs.wdStrt, + min: -1, max: 6, + format: v => v>=0 ? ABR_DAY[v] : /*LANG*/"today", + onchange: v => validSttngs.wdStrt = v + }, + /*LANG*/"Su color": { + value: validSttngs.suClr, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], + onchange: v => validSttngs.suClr = v + }, + /*LANG*/"Border": { + value: validSttngs.calBrdr, + format: v => v ? /*LANG*/"show" : /*LANG*/"none", + onchange: v => validSttngs.calBrdr = v + }, + /*LANG*/"Today settings": () => { + showTodayMenu(); + }, + /*LANG*/"< Cancel": () => cancelExitSettings() + }); + }; + + var showTodayMenu = () => { + E.showMenu({ + "": { + "title": /*LANG*/"Today settings" + }, + "< Back": () => showMainMenu(), + /*LANG*/"Color": { + value: validSttngs.tdyNumClr, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], + onchange: v => validSttngs.tdyNumClr = v + }, + /*LANG*/"Marker": { + value: validSttngs.tdyMrkr, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"circle", /*LANG*/"rectangle", /*LANG*/"filled"][v], + onchange: v => validSttngs.tdyMrkr = v + }, + /*LANG*/"Mrk.Color": { + value: validSttngs.tdyMrkClr, + min: 0, max: 2, + format: v => [/*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], + onchange: v => validSttngs.tdyMrkClr = v + }, + /*LANG*/"Mrk.Size": { + value: validSttngs.tdyMrkPxl, + min: 1, max: 10, + format: v => v+"px", + onchange: v => validSttngs.tdyMrkPxl = v + }, + /*LANG*/"< Cancel": () => cancelExitSettings() + }); + }; + + showMainMenu(); +}); From a4c5509c9a45922218f41a6051962eabc4ec6471 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 13:57:37 +0100 Subject: [PATCH 124/447] Update metadata.json --- apps/7x7dotsclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 6d973182b..2d2d7e5ac 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -12,5 +12,5 @@ {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} ], - "data": [{"name":"7x7dotsclock.json"}], + "data": [{"name":"7x7dotsclock.json"}] } From 8ddbc90c33b3e9565bf37b21df7e54cbc8bdc99a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 17 Feb 2022 13:39:35 +0000 Subject: [PATCH 125/447] > specificlly check for Jekyll markup > Add ability to scan the server for metadata.json files if no apps.json is present > Tidying up search box/chip handling to avoid global vars - just work out what to filter from window location each time > Under device info, show installed apps > Allow left-click and copy link for links > Merge pull request #18 from myxor/chips_quickfix --- core | 2 +- loader.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core b/core index bf29f5697..a7a80a13f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit bf29f5697445686255a785476e6b1ed6a13ff697 +Subproject commit a7a80a13fa187a4ff5f89669992babca2d95812c diff --git a/loader.js b/loader.js index 6b27736ae..82d6172cb 100644 --- a/loader.js +++ b/loader.js @@ -202,7 +202,6 @@ window.addEventListener('load', (event) => { } var selectLang = document.getElementById("settings-lang"); - console.log(languages); languages.forEach(lang => { selectLang.innerHTML += ``; }); From 6e898cadee905ace3d04475b1f0a720974864f1f Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 15:49:03 +0100 Subject: [PATCH 126/447] Update 7x7dotsclock.settings.js --- apps/7x7dotsclock/7x7dotsclock.settings.js | 99 +++++++++++++--------- 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.settings.js b/apps/7x7dotsclock/7x7dotsclock.settings.js index 94273e419..cdb06bf66 100644 --- a/apps/7x7dotsclock/7x7dotsclock.settings.js +++ b/apps/7x7dotsclock/7x7dotsclock.settings.js @@ -1,41 +1,64 @@ (function(back) { - function updateSettings() { - storage.write('numerals.json', numeralsSettings); - } - function resetSettings() { - numeralsSettings = { - color:0, - drawMode:"fill", - showDate:0 - }; - updateSettings(); - } - let numeralsSettings = storage.readJSON('numerals.json',1); - if (!numeralsSettings) resetSettings(); - let dm = ["fill","frame","framefill","thickframe","thickfill"]; - let col = process.env.HWVERSION==1?["rnd","r/g","y/w","o/c","b/y"]:["rnd","r/g","g/b","r/c","m/g"]; - let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]]; - var menu={ - "" : { "title":"Numerals"}, - "Colors": { - value: 0|numeralsSettings.color, - min:0,max:col.length-1, - format: v=>col[v], - onchange: v=> { numeralsSettings.color=v; updateSettings();} + +let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {}); + + +function showMainMenu() { + const mainMenu = { + "": {"title": "7x7 Dots Clock Settings"}, + "< Back": ()=>load(), + "sw-up": ()=>showSelAppMenu("swupApp"), + "sw-down": ()=>showSelAppMenu("swdownApp"), + "sw-left": ()=>showSelAppMenu("swleftApp"), + "sw-right": ()=>showSelAppMenu("swrightApp") + + }; + + E.showMenu(mainMenu); +} + +function setSetting(key,value) { + print("call " + key + " = " + value); + settings[key] = value; + + print("storing settings 7x7dotsclock.json"); + storage.write('7x7dotsclock.json', settings); +} + +function showSelAppMenu(key) { + var Apps = require("Storage").list(/\.info$/) + .map(app => {var a=storage.readJSON(app, 1);return ( + a&&a.name != "Launcher" + && a&&a.name != "Bootloader" + && a&&a.type != "clock" + && a&&a.type !="widget" + )?a:undefined}) + .filter(app => app) // filter out any undefined apps + .sort((a, b) => a.sortorder - b.sortorder); + const SelAppMenu = { + '': { + 'title': /*LANG*/'Select App', }, - "Draw": { - value: 0|dm.indexOf(numeralsSettings.drawMode), - min:0,max:dm.length-1, - format: v=>dm[v], - onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} - }, - "Date on touch": { - value: 0|numeralsSettings.showDate, - min:0,max:1, - format: v=>v?"On":"Off", - onchange: v=> { numeralsSettings.showDate=v; updateSettings();} - }, - "< back": back + '< Back': ()=>showMainMenu(), }; - E.showMenu(menu); -}) \ No newline at end of file + Apps.forEach((app, index) => { + var label = app.name; + if ((settings[key] && index === 0) || (settings[key] === app.src)) { + label = "* " + label; + } + SelAppMenu[label] = () => { + if (settings[key] !== app.src) { + setSetting(key,app.src); + showMainMenu(); + } + }; + }); + if (Apps.length === 0) { + SelAppMenu[/*LANG*/"No Apps Found"] = () => { }; + } + return E.showMenu(SelAppMenu); +} + +showMainMenu(); + +}) From dc28942d83d12d0bb759d419eef69ce0528b2145 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:35:38 +0100 Subject: [PATCH 127/447] Update 7x7dotsclock.settings.js --- apps/7x7dotsclock/7x7dotsclock.settings.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.settings.js b/apps/7x7dotsclock/7x7dotsclock.settings.js index cdb06bf66..42473ec17 100644 --- a/apps/7x7dotsclock/7x7dotsclock.settings.js +++ b/apps/7x7dotsclock/7x7dotsclock.settings.js @@ -24,7 +24,8 @@ function setSetting(key,value) { print("storing settings 7x7dotsclock.json"); storage.write('7x7dotsclock.json', settings); } - + + function showSelAppMenu(key) { var Apps = require("Storage").list(/\.info$/) .map(app => {var a=storage.readJSON(app, 1);return ( @@ -43,7 +44,7 @@ function showSelAppMenu(key) { }; Apps.forEach((app, index) => { var label = app.name; - if ((settings[key] && index === 0) || (settings[key] === app.src)) { + if (settings[key] === app.src) { label = "* " + label; } SelAppMenu[label] = () => { From 9ca2078eec21691597e98c3ab0be9a35135da001 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:44:27 +0100 Subject: [PATCH 128/447] Update 7x7dotsclock.app.js --- apps/7x7dotsclock/7x7dotsclock.app.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index 4c8a36777..458e5e0f2 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -4,6 +4,9 @@ by Peter Kuppelwieser */ + +let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {}); + // position on screen var Xs = 0, Ys = 30,Xe = 175, Ye=175; //const Xs = 0, Ys = 0,Xe = 175, Ye=175; @@ -217,11 +220,12 @@ function actions(v){ if(v==-1){ print("up swipe event"); - load("qrcode.app.js"); + if(settings.swupApp != "") load(settings.swupApp); + print(settings.swupApp); } else if(v==1) { print("down swipe event"); - load("hrm.app.js"); - print(apps[0].src); + if(settings.swdownApp != "") load(settings.swdownApp); + print(settings.swdownApp); } else { print("touch event"); } @@ -316,11 +320,13 @@ function SetFull(on) { switch (direction) { case 1: print("swipe left event"); - load("gbmusic.app.js"); + if(settings.swleftApp != "") load(settings.swleftApp); + print(settings.swleftApp); break; case -1: load("messages.app.js"); - print("swipe right event"); + if(settings.swrightApp != "") load(settings.swrightApp); + print(settings.swrightApp); break; default: print("swipe undefined event"); From eb64a7a43653b0975e0d7dd5adb6aada3a542ad5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 17 Feb 2022 16:45:24 +0000 Subject: [PATCH 129/447] Fix build issues created with #1465 --- .eslintignore | 1 + apps/timecal/timecal.settings.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index e657b6260..7bbe41136 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,3 +2,4 @@ apps/animclk/V29.LBM.js apps/banglerun/rollup.config.js apps/schoolCalendar/fullcalendar/main.js apps/authentiwatch/qr_packed.js +*.test.js diff --git a/apps/timecal/timecal.settings.js b/apps/timecal/timecal.settings.js index 38c87903b..f3b46384d 100644 --- a/apps/timecal/timecal.settings.js +++ b/apps/timecal/timecal.settings.js @@ -21,7 +21,7 @@ }; validSttngs = require("Storage").readJSON("timecal.validSttngs.json", 1) || {}; for (const k in validSttngs) if (!DEFAULTS.hasOwnProperty(k)) delete this.validSttngs[k]; //remove invalid settings - for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = validSttngs[k]; //assign missing defaults + for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = DEFAULTS[k]; //assign missing defaults var changedSttngs = Object.assign({}, validSttngs); From 6d735f57e5dcfbe42d46f1ce00bd94ae9ef050d0 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:49:57 +0100 Subject: [PATCH 130/447] Update README.md --- apps/7x7dotsclock/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md index 37734911f..7f899ff0f 100644 --- a/apps/7x7dotsclock/README.md +++ b/apps/7x7dotsclock/README.md @@ -11,8 +11,7 @@ looks best with dark theme so far ![](dotsfontclock-scr1.png) * when screen is unlocked it shows additional info: bluetooth, battery, new message, date and seconds -* by swiping you can open customizable apps +* you can configure a app per swipe direction +* when swiping the configured apps are launced * button press opens launcher -Contributors: -* pkkpp From aabf9034f1b127a27a5735572faf851d1fa497b6 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:54:09 +0100 Subject: [PATCH 131/447] Update metadata.json --- apps/7x7dotsclock/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 2d2d7e5ac..7b2c52512 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -10,6 +10,7 @@ "readme": "README.md", "storage": [ {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, + {"name":"7x7dotsclock.settings.js","url":"7x7dotsclock.settings.js"}, {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} ], "data": [{"name":"7x7dotsclock.json"}] From ca243f26d857e82d1335e16a189c83051cb8172a Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:54:37 +0100 Subject: [PATCH 132/447] Delete 7x7dotsclock.info --- apps/7x7dotsclock/7x7dotsclock.info | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 apps/7x7dotsclock/7x7dotsclock.info diff --git a/apps/7x7dotsclock/7x7dotsclock.info b/apps/7x7dotsclock/7x7dotsclock.info deleted file mode 100644 index 46d719749..000000000 --- a/apps/7x7dotsclock/7x7dotsclock.info +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id":"7x7dotsclock", - "name":"7x7 dots clock", - "type":"clock", - "src":"dotfontclock.app.js", - "icon":"dotfontclock.img" -} From 76bdaba1efc09f10af94a8392998e959224c352a Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 18:01:01 +0100 Subject: [PATCH 133/447] Update 7x7dotsclock.app.js --- apps/7x7dotsclock/7x7dotsclock.app.js | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index 458e5e0f2..7acfb8555 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -324,7 +324,6 @@ function SetFull(on) { print(settings.swleftApp); break; case -1: - load("messages.app.js"); if(settings.swrightApp != "") load(settings.swrightApp); print(settings.swrightApp); break; From d110b8fefaf85e64b694bfb364c99d327e2c07b0 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Thu, 17 Feb 2022 18:07:20 +0100 Subject: [PATCH 134/447] Update 7x7dotsclock.app.js --- apps/7x7dotsclock/7x7dotsclock.app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index 7acfb8555..3f2e9b9b1 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -324,6 +324,7 @@ function SetFull(on) { print(settings.swleftApp); break; case -1: + print("swipe right event"); if(settings.swrightApp != "") load(settings.swrightApp); print(settings.swrightApp); break; From cda843c9628c5e50606d8c9eec11189a94849865 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Thu, 17 Feb 2022 20:18:28 +0100 Subject: [PATCH 135/447] Work in progres for testing --- apps/antonclk/ChangeLog | 3 ++- apps/antonclk/metadata.json | 2 +- apps/antonclk/settings.js | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/antonclk/ChangeLog b/apps/antonclk/ChangeLog index 4dca8053e..ac49dcbd7 100644 --- a/apps/antonclk/ChangeLog +++ b/apps/antonclk/ChangeLog @@ -7,4 +7,5 @@ when weekday name "On": weekday name is cut at 6th position and .# is added 0.06: fixes #1271 - wrong settings name when weekday name and calendar weeknumber are on then display is # - week is buffered until date or timezone changes \ No newline at end of file + week is buffered until date or timezone changes +0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) \ No newline at end of file diff --git a/apps/antonclk/metadata.json b/apps/antonclk/metadata.json index def5d3b48..4d26dd0c7 100644 --- a/apps/antonclk/metadata.json +++ b/apps/antonclk/metadata.json @@ -1,7 +1,7 @@ { "id": "antonclk", "name": "Anton Clock", - "version": "0.06", + "version": "0.07", "description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.", "readme":"README.md", "icon": "app.png", diff --git a/apps/antonclk/settings.js b/apps/antonclk/settings.js index e452b02c7..6882cbd0f 100644 --- a/apps/antonclk/settings.js +++ b/apps/antonclk/settings.js @@ -38,7 +38,7 @@ }, "< Back": () => back(), "Seconds...": () => E.showMenu(secmenu), - "Date": stringInSettings("dateOnMain", ["Short", "Long", "ISO8601"]), + "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), "Show Weekday": { value: (settings.weekDay !== undefined ? settings.weekDay : true), format: v => v ? "On" : "Off", @@ -56,7 +56,7 @@ } }, "Uppercase": { - value: (settings.upperCase !== undefined ? settings.upperCase : false), + value: (settings.upperCase !== undefined ? settings.upperCase : true), format: v => v ? "On" : "Off", onchange: v => { settings.upperCase = v; @@ -81,7 +81,7 @@ "< Back": () => E.showMenu(mainmenu), "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), "With \":\"": { - value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : false), + value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), format: v => v ? "On" : "Off", onchange: v => { settings.secondsWithColon = v; @@ -89,14 +89,14 @@ } }, "Color": { - value: (settings.secondsColoured !== undefined ? settings.secondsColoured : false), + value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), format: v => v ? "On" : "Off", onchange: v => { settings.secondsColoured = v; writeSettings(); } }, - "Date": stringInSettings("dateOnSecs", ["No", "Year", "Weekday"]) + "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) }; // Actually display the menu From 9b1e977f0938090eb8e380b4c278c3f4a0c122b9 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:05:47 -0800 Subject: [PATCH 136/447] Create appb2.js --- apps/blackjack/appb2.js | 207 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 apps/blackjack/appb2.js diff --git a/apps/blackjack/appb2.js b/apps/blackjack/appb2.js new file mode 100644 index 000000000..c9907487d --- /dev/null +++ b/apps/blackjack/appb2.js @@ -0,0 +1,207 @@ +var Clubs = require("heatshrink").decompress(atob("j0ewcBkmSpICipEAiQLHwA3BBY8gBQMEEA1AJwQgGyAKChILGBQUCFgxwDJpEAO5AVCII44CAQI1GAAg1GAAZQCWxCDEAAqJBQYQAFRIJWCAApcCR4YADPoRWCgQdBPopfCwAdBTw47BcBAvBU44vDfBDUIRIbUHATuQ")); + +var Spades = require("heatshrink").decompress(atob("j0ewcBkmSpICuoALJIQILHpAKBJQ+QLIUJBYsgMoY1GBQcCBYmAPgkSEBEAgggIKApBDIg4KFHAZiCAAgsDBQw4DFitJFhQ4FTwplBgRoCSQoRBBYJ6EF4jgUwDUHAVOQA==")); + +var Hearts = require("heatshrink").decompress(atob("j0ewY96gMkyAEByVIBQcSpILBhMkBYkEyQLBAQYKCCIQLEEwQgCBYuAEBFJkBBCBYw4CEA44CgQLHIYQsHLJsAEBJEHSQhxENwQADMQoAEKAdAWowLCYJESXggAFGowA/AAQ")); + +var Diamonds = require("heatshrink").decompress(atob("j0ewY1ykgKJhIKJiVIEBOSoAKHpILBBQ+SBYOQBIsBCgILBwAKEgQgCAQIKEggICAQMgKwgUDAQI1GBY4IFLgoLGJpGSPoo4EMoxNIMoqSHiR6HLgizIPoLgfAFA")); + +var deck = []; +var player = {Hand:[]}; +var computer = {Hand:[]}; +var ctx = {ready:true}; + +function createDeck() { + var suits = ["Spades", "Hearts", "Diamonds", "Clubs"]; + var values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]; + + var dck = []; + for (var i = 0 ; i < values.length; i++) { + for(var x = 0; x < suits.length; x++) { + dck.push({ Value: values[i], Suit: suits[x] }); + } + } + return dck; +} + +function shuffle(a) { + var j, x, i; + for (i = a.length - 1; i > 0; i--) { + j = Math.floor(Math.random() * (i + 1)); + x = a[i]; + a[i] = a[j]; + a[j] = x; + } + return a; +} + +function EndGameMessdage(msg){ + ctx.ready = false; + g.clearRect(0,160,176,176); + g.setColor(255,255,255); + g.fillRect(0,160,176,176); + g.setColor(0,0,0); + g.drawString(msg, 12, 155); + setTimeout(function(){ + startGame(); + }, 2500); + +} + +function hitMe() { + if (!ctx.ready) return; + player.Hand.push(deck.pop()); + renderOnScreen(1); + var playerWeight = calcWeight(player.Hand, 0); + + if(playerWeight == 21) + EndGameMessdage('WINNER'); + else if(playerWeight > 21) + EndGameMessdage('LOSER'); +} + +function calcWeight(hand, hideCard) { + if(hideCard === 1) { + if (hand[0].Value == "J" || hand[0].Value == "Q" || hand[0].Value == "K") + return "10 +"; + else if (hand[0].Value == "A") + return "11 +"; + else + return parseInt(hand[0].Value) +" +"; + } + else { + var weight = 0; + for(i=0; i 21 || bangleWeight < playerWeight) + EndGameMessdage('WINNER'); + else if(bangleWeight > playerWeight) + EndGameMessdage('LOOSER'); +} + +function renderOnScreen(HideCard) { + const fontName = "6x8"; + + g.clear(); // clear screen + g.reset(); // default draw styles + g.setFont(fontName, 1); + + g.setColor(255,255,255); + g.fillRect(Bangle.appRect); + g.setColor(0,0,0); + + g.drawString('Hit', 176/4-10, 160); + g.drawString('Stand', 176/4+176/2-10, 160); + + g.setFont(fontName, 3); + for(i=0; i right; + + if(is_left){ + hitMe(); + + } else if(is_right){ + stand(); + } +}); +setWatch(startGame, BTN1, {repeat:true, edge:"falling"}); + +startGame(); From 358683d319861ba70738029d7d488bc6a7555584 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:07:13 -0800 Subject: [PATCH 137/447] Update metadata.json --- apps/blackjack/metadata.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/blackjack/metadata.json b/apps/blackjack/metadata.json index 331c64040..837b891bd 100644 --- a/apps/blackjack/metadata.json +++ b/apps/blackjack/metadata.json @@ -2,15 +2,16 @@ "id": "blackjack", "name": "Black Jack game", "shortName": "Black Jack game", - "version": "0.02", + "version": "0.03", "description": "Simple implementation of card game Black Jack", "icon": "blackjack.png", "tags": "game", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "screenshots": [{"url":"bangle1-black-jack-game-screenshot.png"}], "allow_emulator": true, "storage": [ - {"name":"blackjack.app.js","url":"blackjack.app.js"}, + {"name":"blackjack.app.js","url":"blackjack.app.js","supports": ["BANGLEJS"]}, + {"name":"blackjack.app.js","url":"appb2.js","supports": ["BANGLEJS2"]}, {"name":"blackjack.img","url":"blackjack-icon.js","evaluate":true} ] } From 24b41baeabe081764a604d59a4f3f0ae9b319739 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Thu, 17 Feb 2022 17:08:02 -0800 Subject: [PATCH 138/447] Update ChangeLog --- apps/blackjack/ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/blackjack/ChangeLog b/apps/blackjack/ChangeLog index 25b5f9195..8e468e9ad 100644 --- a/apps/blackjack/ChangeLog +++ b/apps/blackjack/ChangeLog @@ -1,2 +1,3 @@ 0.01: New game! BTN4- Hit card, BTN5- Stand -0.02: ignore buttons on pauses \ No newline at end of file +0.02: Ignore buttons on pauses +0.03: Support Bangle.js 2 From f24b87715110ec2f4c7ed90986b73890a45ca9b0 Mon Sep 17 00:00:00 2001 From: Taras <2taras2006@gmail.com> Date: Fri, 18 Feb 2022 07:35:45 +0300 Subject: [PATCH 139/447] Add pie game --- apps/pie/app-icon.js | 1 + apps/pie/app.js | 56 +++++++++++++++++++++++++++++++++++++++++ apps/pie/app.png | Bin 0 -> 510 bytes apps/pie/metadata.json | 14 +++++++++++ 4 files changed, 71 insertions(+) create mode 100644 apps/pie/app-icon.js create mode 100644 apps/pie/app.js create mode 100644 apps/pie/app.png create mode 100644 apps/pie/metadata.json diff --git a/apps/pie/app-icon.js b/apps/pie/app-icon.js new file mode 100644 index 000000000..34a58225c --- /dev/null +++ b/apps/pie/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4A/ABl3ABQVJg4WLC/QWMC/4X/U7NVqIXTgtVC4MXC6QWBAAQYLCxQAGqByJIoQAKC8IWMJBIuNGBIXvCxxgIC/4XH1QAO0AX/C/4X/C/4X/C6Q")) diff --git a/apps/pie/app.js b/apps/pie/app.js new file mode 100644 index 000000000..69b67d3bd --- /dev/null +++ b/apps/pie/app.js @@ -0,0 +1,56 @@ +function end(){ + clearInterval(m); + clearWatch(w); + gfx.clear(); + gfx.setColor(1,0,0); + gfx.setFont("Vector30"); + gfx.drawString('Game over!\n Score: '+score+'\nPress BTN1', gfx.getWidth()*0.15,gfx.getHeight()*0.4); + setWatch(function(){init();}, BTN1); +} +function scrollX(){ + gfx.clearRect(0,gfx.getHeight()*(1/4),gfx.getWidth(),0); + gfx.scroll(0,gfx.getHeight()/4); + score++; + if(typeof(m) != undefined && score>0){ + clearInterval(m); + m = setInterval(scrollY,Math.abs(100/score+15-0.1*score));} + gfx.setColor(1,1,1); + gfx.drawString(score,gfx.getWidth()*(4.2/5),gfx.getHeight()*(0.5/5)); + gfx.setColor(Math.random(),Math.random(),Math.random()); + gfx.setColor(col[0],col[1],col[2]); + gfx.fillRect(colm[0],colm[1],colm[2],colm[3]); + col = [Math.random(),Math.random(),Math.random()]; + gfx.setColor(col[0],col[1],col[2]); + block[0] = gfx.getWidth(); +} +function scrollY(){ + block[0] -= 2; + block[2] = block[0]+colm[2]-colm[0]; + gfx.clearRect(block[2], block[1], gfx.getWidth(), block[3]); + gfx.fillRect(block[0],block[1],block[2],block[3]); + if(block[2]block[2] && colm[0]Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0h38YK~!i%?U=nz z!!QtlFZ_&jU`_f2tSn3n6$l<6yhmAJWCMg$-lLV6Ss0jD7+|S*0Qv-sAi`a^ERfnx z@%dD7-{MPE)%V3`pH(mn!!Z6e8IK}tJ|7nE)yD{D*};hl{x}*{1rrg0ji{4wDdn1uA&pC<)O8*0Z%^ z4wLZbPJ9V@@d@=+p`_~qmQerZswiIed;ASq78anyG1(D@zm825sK*o%3kjSA`9lPv|C`VS-~3(y+(^zPl!oqB9JUg=i8XPq0Iram-GfJb3A)_h zZqLng8CJlF320*i+L(YgCZLT8Xk!A}EV%%{7ZgN7ecm4EnE(I)07*qoM6N<$f`)d^ A?f?J) literal 0 HcmV?d00001 diff --git a/apps/pie/metadata.json b/apps/pie/metadata.json new file mode 100644 index 000000000..9650d1359 --- /dev/null +++ b/apps/pie/metadata.json @@ -0,0 +1,14 @@ +{ "id": "pie", + "name": "In this game you need to make highest pie", + "shortName":"Pie maker", + "version":"0.01", + "description": "In this game you will be making pie out of different pieces", + "icon": "app.png", + "type": "app", + "tags": "game", + "supports" : ["BANGLEJS"], + "storage": [ + {"name":"pie.app.js","url":"app.js"}, + {"name":"pie.img","url":"app-icon.js","evaluate":true} + ] +} From 18602e84147554e1d923297960124b23dea78959 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Fri, 18 Feb 2022 12:41:30 +0100 Subject: [PATCH 140/447] bug fix settings --- apps/timecal/ChangeLog | 3 +- apps/timecal/metadata.json | 2 +- ...mecal.app.test.js => timecal.app.test._js} | 0 apps/timecal/timecal.settings.js | 42 +++++++++---------- 4 files changed, 24 insertions(+), 23 deletions(-) rename apps/timecal/testing/{timecal.app.test.js => timecal.app.test._js} (100%) diff --git a/apps/timecal/ChangeLog b/apps/timecal/ChangeLog index 43bff461d..e48145b4b 100644 --- a/apps/timecal/ChangeLog +++ b/apps/timecal/ChangeLog @@ -6,4 +6,5 @@ -> locale: weekday name (first two characters) from locale -> added settings to render cal view begin day (-1: today, 0:sunday, 1:monday [default]) 0.03: a lot of more settings for outline, colors and highlights -0.04: finalized README, fixed settings cancel, fixed border-setting \ No newline at end of file +0.04: finalized README, fixed settings cancel, fixed border-setting +0.05: bugfix: default settings \ No newline at end of file diff --git a/apps/timecal/metadata.json b/apps/timecal/metadata.json index 4dd8a8ca0..f439f4e9c 100644 --- a/apps/timecal/metadata.json +++ b/apps/timecal/metadata.json @@ -1,7 +1,7 @@ { "id": "timecal", "name": "TimeCal", "shortName":"TimeCal", - "version":"0.04", + "version":"0.05", "description": "TimeCal shows the date/time along with a 3 week calendar", "icon": "icon.png", "type": "clock", diff --git a/apps/timecal/testing/timecal.app.test.js b/apps/timecal/testing/timecal.app.test._js similarity index 100% rename from apps/timecal/testing/timecal.app.test.js rename to apps/timecal/testing/timecal.app.test._js diff --git a/apps/timecal/timecal.settings.js b/apps/timecal/timecal.settings.js index 38c87903b..2642c9628 100644 --- a/apps/timecal/timecal.settings.js +++ b/apps/timecal/timecal.settings.js @@ -2,7 +2,7 @@ (function(exit) { ABR_DAY = require("locale") && require("locale").abday ? require("locale").abday : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - var FILE = "timecal.validSttngs.json"; + var FILE = "timecal.settings.json"; const DEFAULTS = { shwDate:1, //0:none, 1:locale, 2:month, 3:monthshort.year #week @@ -19,14 +19,14 @@ calBrdr:false }; - validSttngs = require("Storage").readJSON("timecal.validSttngs.json", 1) || {}; + validSttngs = require("Storage").readJSON(FILE, 1) || {}; for (const k in validSttngs) if (!DEFAULTS.hasOwnProperty(k)) delete this.validSttngs[k]; //remove invalid settings - for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = validSttngs[k]; //assign missing defaults + for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = DEFAULTS[k]; //assign missing defaults - var changedSttngs = Object.assign({}, validSttngs); + var chngdSttngs = Object.assign({}, validSttngs); var saveExitSettings = () => { - require('Storage').writeJSON(FILE, changedSttngs); + require('Storage').writeJSON(FILE, chngdSttngs); exit(); }; @@ -42,27 +42,27 @@ }, /*LANG*/"< Save": () => saveExitSettings(), /*LANG*/"Show date": { - value: validSttngs.shwDate, + value: chngdSttngs.shwDate, min: 0, max: 3, format: v => [/*LANG*/"none", /*LANG*/"locale", /*LANG*/"M", /*LANG*/"m.Y #W"][v], - onchange: v => validSttngs.shwDate = v + onchange: v => chngdSttngs.shwDate = v }, /*LANG*/"Start wday": { - value: validSttngs.wdStrt, + value: chngdSttngs.wdStrt, min: -1, max: 6, format: v => v>=0 ? ABR_DAY[v] : /*LANG*/"today", - onchange: v => validSttngs.wdStrt = v + onchange: v => chngdSttngs.wdStrt = v }, /*LANG*/"Su color": { - value: validSttngs.suClr, + value: chngdSttngs.suClr, min: 0, max: 3, format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], - onchange: v => validSttngs.suClr = v + onchange: v => chngdSttngs.suClr = v }, /*LANG*/"Border": { - value: validSttngs.calBrdr, + value: chngdSttngs.calBrdr, format: v => v ? /*LANG*/"show" : /*LANG*/"none", - onchange: v => validSttngs.calBrdr = v + onchange: v => chngdSttngs.calBrdr = v }, /*LANG*/"Today settings": () => { showTodayMenu(); @@ -78,28 +78,28 @@ }, "< Back": () => showMainMenu(), /*LANG*/"Color": { - value: validSttngs.tdyNumClr, + value: chngdSttngs.tdyNumClr, min: 0, max: 3, format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], - onchange: v => validSttngs.tdyNumClr = v + onchange: v => chngdSttngs.tdyNumClr = v }, /*LANG*/"Marker": { - value: validSttngs.tdyMrkr, + value: chngdSttngs.tdyMrkr, min: 0, max: 3, format: v => [/*LANG*/"none", /*LANG*/"circle", /*LANG*/"rectangle", /*LANG*/"filled"][v], - onchange: v => validSttngs.tdyMrkr = v + onchange: v => chngdSttngs.tdyMrkr = v }, /*LANG*/"Mrk.Color": { - value: validSttngs.tdyMrkClr, + value: chngdSttngs.tdyMrkClr, min: 0, max: 2, format: v => [/*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], - onchange: v => validSttngs.tdyMrkClr = v + onchange: v => chngdSttngs.tdyMrkClr = v }, /*LANG*/"Mrk.Size": { - value: validSttngs.tdyMrkPxl, + value: chngdSttngs.tdyMrkPxl, min: 1, max: 10, format: v => v+"px", - onchange: v => validSttngs.tdyMrkPxl = v + onchange: v => chngdSttngs.tdyMrkPxl = v }, /*LANG*/"< Cancel": () => cancelExitSettings() }); From 7b276915ef79c7dc81afdbe0346d017166f012e3 Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Fri, 18 Feb 2022 14:16:12 +0100 Subject: [PATCH 141/447] improve color and display position --- apps/terminalclock/README.md | 8 +++++++- apps/terminalclock/app.js | 6 ++---- apps/terminalclock/screenshot1.png | Bin 19618 -> 2938 bytes apps/terminalclock/screenshot2.png | Bin 2569 -> 3072 bytes 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/terminalclock/README.md b/apps/terminalclock/README.md index d27fc4cfc..2a2bc1204 100644 --- a/apps/terminalclock/README.md +++ b/apps/terminalclock/README.md @@ -1,3 +1,9 @@ # Terminal clock -A clock displayed as a terminal cli. It can display the time, date, hrm, activity and steps +A clock displayed as a terminal cli. +It can display : +- time +- date +- hrm +- activity +- steps diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index af6ff8472..fb7bd16cc 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -1,6 +1,6 @@ var locale = require("locale"); -var fontColor = "#00FF00"; -var startY = 30; +var fontColor = g.theme.dark ? "#0f0" : "#000"; +var startY = 24; var paddingY = 2; var font6x8At4Size = 32; var font6x8At2Size = 18; @@ -82,8 +82,6 @@ function drawActivity(pos){ function draw(){ - // console.log("in draw"); - // console.log(settings); var curPos = 1; g.reset(); g.setFontAlign(-1, -1); diff --git a/apps/terminalclock/screenshot1.png b/apps/terminalclock/screenshot1.png index bfbb9039b7ec94990efcfc11154e714f051ef7b7..a0d41f4957fa8bd96572d2e126ed2aba38d68250 100644 GIT binary patch literal 2938 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 literal 19618 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 diff --git a/apps/terminalclock/screenshot2.png b/apps/terminalclock/screenshot2.png index 27bd6d68d4a7068e01c7f07c4799a631815463ac..21d7aadbf31906cf0316459a9b21bc3ae32e0bc8 100644 GIT binary patch literal 3072 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 jM6c{|gUSB|JP8lDilHZiwbMjjdf zY8$2_bjEDGcy>-HC8I-|9m`2(80LMPJOkd0#mDuyE4O_uaWj0my0_EW9HK^<*f}26xi1Ql~^;{XWf=G806Spmi|u zVr5%=*YH;%A(WRvfbA|n0r{=2Y_b(Dwa(}F2;-$KT!I=aH+nt($Q>MT_M1ZN?0P$p zohj6jJ}tH6Kqy$GT~HW1WWqz#^a#s44`yTIuu_VFL#yM_={zIF_{a=F9ie__chn}E ziPX`n`GRf^iX>j6=!RDaAUl`+MGE)BXcH0Mj722`VZ50}1U=R-SKOPHbl-NAuE zYz$VMaTznev6Ifb#D;3sOxp3%S+mUiKn=bItk`CA&xatIy}}ffR}8y+#K6Lu+`QO= zbbF$Tv7AH9(K*=8cuAF=Yz&t%)7Z4v=qQ^??GR|@y4J+vUD~i{YM4>xoH%6RUSXVI zC?ym#&YJgQ7Q?-#3wuX0x_c^+=enMwj&t~uWrphcgSBj=92r257f(LS5(VALd*0^> z*i{dd4n?A235BQ4I%Dk2QnS!ZrySCyG4T;5xsV%0#8PFC7LH21$pw*T$*)9t8LdpE z?nGT(-T@V-kNT<>S4oJAaQgx^Z90KGq)OPepWclhE9m43!_`e*E`)=AUt|SB%K3(w zetBp7?)N3mL@!obbBxHs>P3ldPR@@nDZTmv4I$I=s~T1KC!Si>jeW-Tehh~jRWuq> zX3zCF*WwXXm%GB-Wr_iO>=zn#jlhXSK{g|fi=z*Icb)Vt^U|?Hn|TXlxq;4yvZ$ld z1Bor=cUszw4*xN2WIEDiXgXKYH>TZ@qV$QBBZz=8K@ApK(KDA*CC{X8uDriL#p!rkeS%LlTO!l`|B-&-@)xrKO8ZHbBWuO_!-&xa#t2na)a`WJI|>;|2NP4o zW1#+9ztVD$@_N5&WvgSK>mG*Phj)dc_8k}*4yQ+4F>5)!3pm&7G$Bri%j=@owhF3s zoXcRt{R$V}kYrx*ni!!z)U@`c1+k5wwpIn%rS61micLb$MYy%1*qt={hiqBse5On} zV!`a((U(i94OH_2&KQh})1u@S&E`Dnsd1l%l+15oR+Gl8ViS*4z;tz(;t!09gMHD1R!D+xQ^=gufZ3iWJQ{0h+fX$+3OT$Dr~0Xw z5MLu>{xd+|D@4ma^`s)+ z>_UNwU0lZzOO5u6i_fGNAV5~ZSib8%dLV=q?#WH7EPtkn)WhkXR*ea zD}{!r7p{lM@x4$~dBdmB$yYV=i#KbrX4u$ZIklC?32Hjp_~+q9-*zX8TT;yK9xZ9PU8v=Kh3L8u z#IufKA8~-P461u=N&XSkUwU5BjF}lok3Ti`c60N^aT1U=O#-(#12?l|Wb(MTgX^0O z3yx6DSMqH*1qDZIJid~X%t(M7xX;FO za4rhdSuriNK3k>JT=o~lGkx?o=VW-T1pkN0!|b>pYM=t2Jh>@xGQ13x${ z%|4#&RgBx}7$CsL%ZR-eHVOV^&T?BIAhj<2x?jUi@@9{#1;+kbsi<<@pR3?i(wvN} z+?-q!e266r01UcPU4^;=N)(UFNHVgtN;K2 From 0eb1a2e16d6f930e8fc5297d97bb3e99e3a9e8ec Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Fri, 18 Feb 2022 14:36:28 +0100 Subject: [PATCH 142/447] settings timecal-clock-0.05 --- apps/timecal/timecal.settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/timecal/timecal.settings.js b/apps/timecal/timecal.settings.js index 2642c9628..e86f3d8b8 100644 --- a/apps/timecal/timecal.settings.js +++ b/apps/timecal/timecal.settings.js @@ -21,7 +21,7 @@ }; validSttngs = require("Storage").readJSON(FILE, 1) || {}; for (const k in validSttngs) if (!DEFAULTS.hasOwnProperty(k)) delete this.validSttngs[k]; //remove invalid settings - for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = DEFAULTS[k]; //assign missing defaults + for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = DEFAULTS[k]; //assign missing defaults fixed var chngdSttngs = Object.assign({}, validSttngs); From f8eebb80ec9dda4ee6fd0f7ebb881cb8a2a3380c Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 18 Feb 2022 15:12:13 +0100 Subject: [PATCH 143/447] Optional settings to show a different color for (0,0) whenever the bangle is locked. --- apps/neonx/ChangeLog | 3 ++- apps/neonx/README.md | 7 +++++- apps/neonx/metadata.json | 2 +- apps/neonx/neonx.app.js | 49 ++++++++++++++++++++++++------------ apps/neonx/neonx.settings.js | 9 +++++++ 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/apps/neonx/ChangeLog b/apps/neonx/ChangeLog index 7ac033fe8..968d6d629 100644 --- a/apps/neonx/ChangeLog +++ b/apps/neonx/ChangeLog @@ -1,2 +1,3 @@ 0.01: Initial release -0.02: Optional fullscreen mode \ No newline at end of file +0.02: Optional fullscreen mode +0.03: Optional show lock status via color \ No newline at end of file diff --git a/apps/neonx/README.md b/apps/neonx/README.md index f205b702f..c3eb982c6 100644 --- a/apps/neonx/README.md +++ b/apps/neonx/README.md @@ -21,4 +21,9 @@ Shows the current date as DD MM on touch and reverts back to time after 5 second ### Fullscreen Shows the watchface in fullscreen mode. -Note: In fullscreen mode, widgets are hidden, but still loaded. \ No newline at end of file +Note: In fullscreen mode, widgets are hidden, but still loaded. + +### Show lock status +In fullscreen mode it can be useful to detect, whether the BangleJs is locked or not. +If these settings are enabled, the first digit is shown red if the BangleJs is locked +and purple otherwise. \ No newline at end of file diff --git a/apps/neonx/metadata.json b/apps/neonx/metadata.json index ffa4d1b8e..4ac7c4cea 100644 --- a/apps/neonx/metadata.json +++ b/apps/neonx/metadata.json @@ -2,7 +2,7 @@ "id": "neonx", "name": "Neon X & IO X Clock", "shortName": "Neon X Clock", - "version": "0.02", + "version": "0.03", "description": "Pebble Neon X & Neon IO X for Bangle.js", "icon": "neonx.png", "type": "clock", diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index 4ef0986fe..165ec32a6 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -8,6 +8,19 @@ * Created: February 2022 */ +let settings = { + thickness: 4, + io: 0, + showDate: 1, + fullscreen: false, + showLock: false, +}; +let saved_settings = require('Storage').readJSON('neonx.json', 1) || settings; +for (const key in saved_settings) { + settings[key] = saved_settings[key] +} + + const digits = { 0:[[15,15,85,15,85,85,15,85,15,15]], 1:[[85,15,85,85]], @@ -21,6 +34,7 @@ const digits = { 9:[[15,50,15,15,85,15,85,85,15,85]], }; + const colors = { x: [ ["#FF00FF", "#00FFFF"], @@ -31,17 +45,19 @@ const colors = { ["#00FF00", "#00FFFF"] ] }; +const unlockColor = "#FF0000"; const is12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false; const screenWidth = g.getWidth(); const screenHeight = g.getHeight(); const halfWidth = screenWidth / 2; const scale = screenWidth / 240; -const REFRESH_RATE = 10E3; +const REFRESH_RATE = 60E3; let interval = 0; let showingDate = false; + function drawLine(poly, thickness){ for (let i = 0; i < poly.length; i = i + 2){ if (poly[i + 2] === undefined) { @@ -59,18 +75,6 @@ function drawLine(poly, thickness){ } } -let settings = { - thickness: 4, - io: 0, - showDate: 1, - fullscreen: false, -}; -let saved_settings = require('Storage').readJSON('neonx.json', 1) || settings; -for (const key in saved_settings) { - settings[key] = saved_settings[key] -} - - function drawClock(num){ let tx, ty; @@ -80,7 +84,11 @@ function drawClock(num){ const current = ((y + 1) * 2 + x - 1); let newScale = scale; - g.setColor(colors[settings.io ? 'io' : 'x'][y][x]); + let c = colors[settings.io ? 'io' : 'x'][y][x]; + if(x == 0 && y == 0 && settings.showLock){ + c = Bangle.isLocked() ? c : unlockColor; + } + g.setColor(c); if (!settings.io) { newScale *= settings.fullscreen ? 1.18 : 1.0; @@ -101,6 +109,7 @@ function drawClock(num){ } } + function draw(date){ let d = new Date(); let l1, l2; @@ -131,6 +140,7 @@ function draw(date){ drawClock([l1, l2]); } + function setUpdateInt(set){ if (interval) { clearInterval(interval); @@ -148,15 +158,22 @@ Bangle.setUI("clock"); setUpdateInt(1); draw(); + if (settings.showDate) { Bangle.on('touch', () => draw(!showingDate)); } Bangle.on('lcdPower', function(on){ if (on){ - draw(); setUpdateInt(1); - } else setUpdateInt(0); + draw(); + } else { + setUpdateInt(0); + } +}); + +Bangle.on('lock', function(isLocked) { + draw(); }); Bangle.loadWidgets(); diff --git a/apps/neonx/neonx.settings.js b/apps/neonx/neonx.settings.js index 3af2e0fa5..e01ceb4d3 100644 --- a/apps/neonx/neonx.settings.js +++ b/apps/neonx/neonx.settings.js @@ -9,6 +9,7 @@ io: 0, showDate: 1, fullscreen: false, + showLock: false, }; updateSettings(); @@ -58,6 +59,14 @@ updateSettings(); }, }, + 'Show lock': { + value: false | neonXSettings.showLock, + format: () => (neonXSettings.showLock ? 'Yes' : 'No'), + onchange: () => { + neonXSettings.showLock = !neonXSettings.showLock; + updateSettings(); + }, + }, }; E.showMenu(menu); }) From 225cda47bf32fa01bf86374d6c684ac4662437d9 Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Fri, 18 Feb 2022 16:40:33 +0100 Subject: [PATCH 144/447] fix settings load --- apps/terminalclock/settings.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/terminalclock/settings.js b/apps/terminalclock/settings.js index 2b0d288a2..77df69b12 100644 --- a/apps/terminalclock/settings.js +++ b/apps/terminalclock/settings.js @@ -3,10 +3,10 @@ // Load settings var settings = Object.assign({ HRMinConfidence: 50, - showDate: "Yes", - showHRM: "Yes", - showActivity: "Yes", - showStepCount: "Yes", + showDate: true, + showHRM: true, + showActivity: true, + showStepCount: true, }, require('Storage').readJSON(FILE, true) || {}); function writeSettings() { From a4c97850dd1f7a5c83e9a2be95e89d8199cacced Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Fri, 18 Feb 2022 19:53:11 +0100 Subject: [PATCH 145/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/ChangeLog | 1 + apps/messages/app.js | 2 +- apps/messages/metadata.json | 2 +- apps/messages/settings.js | 4 ++-- apps/messages/widget.js | 10 ++++++---- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 4811cd19b..e2c671fa1 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -31,3 +31,4 @@ 0.19: Use a larger font for message text if it'll fit 0.20: Allow tapping on the body to show a scrollable view of the message and title in a bigger font (fix #1405, #1031) 0.21: Improve list readability on dark theme +0.22: Allow repeat to be switched Off, so there is no buzzing repetition diff --git a/apps/messages/app.js b/apps/messages/app.js index 4aaf97369..5f70f6748 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -123,7 +123,7 @@ function getMessageImageCol(msg,def) { "telegram": "#0088cc", "twitter": "#1da1f2", "whatsapp": "#4fce5d", - "wordfeud": "#dcc8bd", + "wordfeud": "#e7d3c7", }[(msg.src||"").toLowerCase()]||(def !== undefined?def:g.theme.fg); } diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 6834693ae..e84d9f0d9 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.21", + "version": "0.22", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", diff --git a/apps/messages/settings.js b/apps/messages/settings.js index c865a37fb..ae9b4aab5 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -27,8 +27,8 @@ }, /*LANG*/'Repeat': { value: settings().repeat, - min: 2, max: 10, - format: v => v+"s", + min: 0, max: 10, + format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("repeat", v) }, /*LANG*/'Unread timer': { diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 1239ef262..614b6194a 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -1,4 +1,4 @@ -WIDGETS["messages"]={area:"tl", width:0, iconwidth:23, +WIDGETS["messages"]={area:"tl", width:0, iconwidth:24, draw:function() { Bangle.removeListener('touch', this.touch); if (!this.width) return; @@ -8,9 +8,11 @@ draw:function() { //if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.repeat===undefined) settings.repeat = 4; - if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { - this.l = Date.now(); - WIDGETS["messages"].buzz(); // buzz every 4 seconds + if(settings.repeat!==0) { + if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { + this.l = Date.now(); + WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds + } } setTimeout(()=>WIDGETS["messages"].draw(), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); From d35481130a048b7cf22ad37e05601f55424ae132 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Fri, 18 Feb 2022 21:57:09 +0100 Subject: [PATCH 146/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/metadata.json | 2 +- apps/messages/widget.js | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index e84d9f0d9..6834693ae 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.22", + "version": "0.21", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 614b6194a..5216c380d 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -8,11 +8,10 @@ draw:function() { //if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.repeat===undefined) settings.repeat = 4; - if(settings.repeat!==0) { - if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { - this.l = Date.now(); - WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds - } + if (settings.repeat===0) settings.repeat = (settings.unreadTimeout+1)*1000; // best way to no-repeat and keep next code + if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { + this.l = Date.now(); + WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds } setTimeout(()=>WIDGETS["messages"].draw(), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); From b7da92c7738afcc53bb9146c6188f570fb700e97 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Fri, 18 Feb 2022 22:21:19 +0100 Subject: [PATCH 147/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/metadata.json | 2 +- apps/messages/widget.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 6834693ae..e84d9f0d9 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.21", + "version": "0.22", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 5216c380d..67ba777ad 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -1,5 +1,5 @@ WIDGETS["messages"]={area:"tl", width:0, iconwidth:24, -draw:function() { +draw:function(buzzed_once) { Bangle.removeListener('touch', this.touch); if (!this.width) return; var c = (Date.now()-this.t)/1000; @@ -8,12 +8,12 @@ draw:function() { //if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.repeat===undefined) settings.repeat = 4; - if (settings.repeat===0) settings.repeat = (settings.unreadTimeout+1)*1000; // best way to no-repeat and keep next code if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { this.l = Date.now(); WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds } - setTimeout(()=>WIDGETS["messages"].draw(), 1000); + if (settings.repeat===0 && buzzed_once!==true) settings.repeat = (settings.unreadTimeout+1)*1000; // Dont buzz again after this initial one + setTimeout(()=>WIDGETS["messages"].draw(true), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); },show:function(quiet) { WIDGETS["messages"].t=Date.now(); // first time From 5bb799898b61b2c60536f81fc633ec24877b3724 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Fri, 18 Feb 2022 22:28:26 +0100 Subject: [PATCH 148/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/metadata.json | 2 +- apps/messages/widget.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index e84d9f0d9..6834693ae 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.22", + "version": "0.21", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 67ba777ad..9d5c77c32 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -12,7 +12,7 @@ draw:function(buzzed_once) { this.l = Date.now(); WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds } - if (settings.repeat===0 && buzzed_once!==true) settings.repeat = (settings.unreadTimeout+1)*1000; // Dont buzz again after this initial one + if (settings.repeat===0 && buzzed_once===true) settings.repeat = (settings.unreadTimeout+241)*1000; // Dont buzz again after this initial one setTimeout(()=>WIDGETS["messages"].draw(true), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); },show:function(quiet) { From a20e7d36c3580deab00a23a8d6d061b5831b8552 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Fri, 18 Feb 2022 22:33:17 +0100 Subject: [PATCH 149/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 6834693ae..87d541d45 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.21", + "version": "0.25", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", From e172aa49279b381fd4202efee5879e7d5b9912b3 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Sat, 19 Feb 2022 00:23:12 +0100 Subject: [PATCH 150/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/ChangeLog | 6 ++++-- apps/messages/metadata.json | 4 ++-- apps/messages/settings.js | 1 - apps/messages/widget.js | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index e2c671fa1..4ad3264b7 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -15,7 +15,7 @@ 0.10: Respect the 'new' attribute if it was set from iOS integrations 0.11: Open app when touching the widget (Bangle.js 2 only) 0.12: Extra app-specific notification icons - New animated notifcationicon (instead of large blinking 'MESSAGES') + New animated notification icon (instead of large blinking 'MESSAGES') Added screenshots 0.13: Add /*LANG*/ comments for internationalisation Add 'Delete All' option to message options @@ -31,4 +31,6 @@ 0.19: Use a larger font for message text if it'll fit 0.20: Allow tapping on the body to show a scrollable view of the message and title in a bigger font (fix #1405, #1031) 0.21: Improve list readability on dark theme -0.22: Allow repeat to be switched Off, so there is no buzzing repetition +0.22: Allow repeat to be switched Off, so there is no buzzing repetition. + Also gave the widget a pixel more room to the right + diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 87d541d45..7488c792e 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,8 +1,8 @@ { "id": "messages", "name": "Messages", - "version": "0.25", - "description": "App to display notifications from iOS and Gadgetbridge", + "version": "0.22", + "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", "tags": "tool,system", diff --git a/apps/messages/settings.js b/apps/messages/settings.js index ae9b4aab5..dcf7b4636 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -13,7 +13,6 @@ } var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; - var currentVib = settings().vibrate; var mainmenu = { "" : { "title" : /*LANG*/"Messages" }, "< Back" : back, diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 9d5c77c32..fe609fb5c 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -1,5 +1,5 @@ WIDGETS["messages"]={area:"tl", width:0, iconwidth:24, -draw:function(buzzed_once) { +draw:function() { Bangle.removeListener('touch', this.touch); if (!this.width) return; var c = (Date.now()-this.t)/1000; @@ -8,12 +8,12 @@ draw:function(buzzed_once) { //if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.repeat===undefined) settings.repeat = 4; + else if (settings.repeat===0) settings.repeat = (settings.unreadTimeout+241)*1000; // best way to no-repeat and keep next code if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { this.l = Date.now(); WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds } - if (settings.repeat===0 && buzzed_once===true) settings.repeat = (settings.unreadTimeout+241)*1000; // Dont buzz again after this initial one - setTimeout(()=>WIDGETS["messages"].draw(true), 1000); + setTimeout(()=>WIDGETS["messages"].draw(), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); },show:function(quiet) { WIDGETS["messages"].t=Date.now(); // first time From e29a41aa282e574b54d2fd4768ef7ca277369685 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Sat, 19 Feb 2022 00:38:00 +0100 Subject: [PATCH 151/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/metadata.json | 2 +- apps/messages/widget.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 7488c792e..08089dfb0 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.22", + "version": "0.50", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/widget.js b/apps/messages/widget.js index fe609fb5c..852fe2f47 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -8,7 +8,7 @@ draw:function() { //if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.repeat===undefined) settings.repeat = 4; - else if (settings.repeat===0) settings.repeat = (settings.unreadTimeout+241)*1000; // best way to no-repeat and keep next code + //else if (settings.repeat===0) settings.repeat = (settings.unreadTimeout+241)*1000; // best way to no-repeat and keep next code if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { this.l = Date.now(); WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds From 6acf7b1b29125ffe804318c51449a5c10e6bbbbd Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Sat, 19 Feb 2022 08:09:28 +0100 Subject: [PATCH 152/447] #1132: Messages: Allow disabling repetition of buzzer: Wow, dazzling solution --- apps/messages/metadata.json | 2 +- apps/messages/settings.js | 18 +++++++++++++----- apps/messages/widget.js | 3 +-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 08089dfb0..7488c792e 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.50", + "version": "0.22", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/settings.js b/apps/messages/settings.js index dcf7b4636..6ddd9de14 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -4,14 +4,22 @@ if (settings.vibrate===undefined) settings.vibrate="."; if (settings.repeat===undefined) settings.repeat=4; if (settings.unreadTimeout===undefined) settings.unreadTimeout=60; + settings.max_unread_timer=240; + settings.no_repeat_value=(settings.max_unread_timer+1)*1000; return settings; } function updateSetting(setting, value) { - let settings = require('Storage').readJSON("messages.settings.json", true) || {}; - settings[setting] = value; - require('Storage').writeJSON("messages.settings.json", settings); + let appsettings = require('Storage').readJSON("messages.settings.json", true) || {}; + if(setting=="repeat" && value===0) + { + value=settings().no_repeat_value; + } + appsettings[setting] = value; + require('Storage').writeJSON("messages.settings.json", appsettings); } + var repeatDisplay = settings().repeat; + if(repeatDisplay==settings().no_repeat_value) repeatDisplay=0; var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var mainmenu = { "" : { "title" : /*LANG*/"Messages" }, @@ -25,14 +33,14 @@ } }, /*LANG*/'Repeat': { - value: settings().repeat, + value: repeatDisplay, min: 0, max: 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("repeat", v) }, /*LANG*/'Unread timer': { value: settings().unreadTimeout, - min: 0, max: 240, step : 10, + min: 0, max: settings().max_unread_timer, step : 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("unreadTimeout", v) }, diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 852fe2f47..13e923670 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -8,10 +8,9 @@ draw:function() { //if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.repeat===undefined) settings.repeat = 4; - //else if (settings.repeat===0) settings.repeat = (settings.unreadTimeout+241)*1000; // best way to no-repeat and keep next code if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { this.l = Date.now(); - WIDGETS["messages"].buzz(); // buzz every settings.repeat seconds + WIDGETS["messages"].buzz(); // buzz every 4 seconds } setTimeout(()=>WIDGETS["messages"].draw(), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); From 7c0328d642e0a7aebc85220f97a96ee9658c453b Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Sat, 19 Feb 2022 09:34:56 +0100 Subject: [PATCH 153/447] #1132: Messages: Allow disabling repetition of buzzer --- apps/messages/metadata.json | 2 +- apps/messages/settings.js | 19 ++++++------------- apps/messages/widget.js | 5 +++-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 7488c792e..93c1d573d 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.22", + "version": "0.55", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/settings.js b/apps/messages/settings.js index 6ddd9de14..39abfc131 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -4,22 +4,15 @@ if (settings.vibrate===undefined) settings.vibrate="."; if (settings.repeat===undefined) settings.repeat=4; if (settings.unreadTimeout===undefined) settings.unreadTimeout=60; - settings.max_unread_timer=240; - settings.no_repeat_value=(settings.max_unread_timer+1)*1000; + settings.maxUnreadTimeout=240; return settings; } function updateSetting(setting, value) { - let appsettings = require('Storage').readJSON("messages.settings.json", true) || {}; - if(setting=="repeat" && value===0) - { - value=settings().no_repeat_value; - } - appsettings[setting] = value; - require('Storage').writeJSON("messages.settings.json", appsettings); + let settings = require('Storage').readJSON("messages.settings.json", true) || {}; + settings[setting] = value; + require('Storage').writeJSON("messages.settings.json", settings); } - var repeatDisplay = settings().repeat; - if(repeatDisplay==settings().no_repeat_value) repeatDisplay=0; var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var mainmenu = { "" : { "title" : /*LANG*/"Messages" }, @@ -33,14 +26,14 @@ } }, /*LANG*/'Repeat': { - value: repeatDisplay, + value: settings().repeat, min: 0, max: 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("repeat", v) }, /*LANG*/'Unread timer': { value: settings().unreadTimeout, - min: 0, max: settings().max_unread_timer, step : 10, + min: 0, max: settings().maxUnreadTimeout, step : 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("unreadTimeout", v) }, diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 13e923670..db9c42409 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -5,10 +5,11 @@ draw:function() { var c = (Date.now()-this.t)/1000; g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+this.iconwidth); g.drawImage((c&1) ? atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+DAADDAADDAADDwAPD8A/DOBzDDn/DA//DAHvDAPvjAPvjAPvjAPvh///gf/vAAD+AAB8AAAAA==") : atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+D///D///A//8CP/xDj/HD48DD+B8D/D+D/3vD/vvj/vvj/vvj/vvh/v/gfnvAAD+AAB8AAAAA=="), this.x, this.y); - //if (c<60) Bangle.setLCDPower(1); // keep LCD on for 1 minute let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.repeat===undefined) settings.repeat = 4; - if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { + if(settings.repeat===0) { + if(c===1) WIDGETS["messages"].buzz(); // buzz just once + } else if (csettings.repeat*1000) { this.l = Date.now(); WIDGETS["messages"].buzz(); // buzz every 4 seconds } From a476be978698d84930eafb443af422834de41538 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 19 Feb 2022 09:36:32 +0100 Subject: [PATCH 154/447] Minor changes --- apps/neonx/README.md | 4 +--- apps/neonx/neonx.app.js | 10 +++------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/neonx/README.md b/apps/neonx/README.md index c3eb982c6..ffb3c3f2c 100644 --- a/apps/neonx/README.md +++ b/apps/neonx/README.md @@ -24,6 +24,4 @@ Shows the watchface in fullscreen mode. Note: In fullscreen mode, widgets are hidden, but still loaded. ### Show lock status -In fullscreen mode it can be useful to detect, whether the BangleJs is locked or not. -If these settings are enabled, the first digit is shown red if the BangleJs is locked -and purple otherwise. \ No newline at end of file +If enabled, color changes when unlocked to detect the lock state easily. \ No newline at end of file diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index 165ec32a6..d64e08d78 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -45,8 +45,6 @@ const colors = { ["#00FF00", "#00FFFF"] ] }; -const unlockColor = "#FF0000"; - const is12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false; const screenWidth = g.getWidth(); const screenHeight = g.getHeight(); @@ -84,14 +82,12 @@ function drawClock(num){ const current = ((y + 1) * 2 + x - 1); let newScale = scale; - let c = colors[settings.io ? 'io' : 'x'][y][x]; - if(x == 0 && y == 0 && settings.showLock){ - c = Bangle.isLocked() ? c : unlockColor; - } + let xc = settings.showLock && Bangle.isLocked() ? Math.abs(x-1) : x; + let c = colors[settings.io ? 'io' : 'x'][y][xc]; g.setColor(c); if (!settings.io) { - newScale *= settings.fullscreen ? 1.18 : 1.0; + newScale *= settings.fullscreen ? 1.20 : 1.0; let dx = settings.fullscreen ? 0 : 18 tx = (x * 100 + dx) * newScale; ty = (y * 100 + dx*2) * newScale; From d74103273ef30ebc3a0370a8673cbbcb4d8051b6 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 19 Feb 2022 09:39:26 +0100 Subject: [PATCH 155/447] Keep original style w.r.t colors. --- apps/neonx/neonx.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index d64e08d78..a90d5c609 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -82,7 +82,7 @@ function drawClock(num){ const current = ((y + 1) * 2 + x - 1); let newScale = scale; - let xc = settings.showLock && Bangle.isLocked() ? Math.abs(x-1) : x; + let xc = settings.showLock && !Bangle.isLocked() ? Math.abs(x-1) : x; let c = colors[settings.io ? 'io' : 'x'][y][xc]; g.setColor(c); From 33dc4954c25e537c86176a4887a6746616165069 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Sat, 19 Feb 2022 17:20:09 +0800 Subject: [PATCH 156/447] Update app.js Precalculate overall token height. Have Bangle1 list UI work more like a Pebble. --- apps/authentiwatch/app.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/authentiwatch/app.js b/apps/authentiwatch/app.js index 640183230..b2c8f857b 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 = { @@ -198,15 +199,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 @@ -240,18 +241,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 +269,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 +301,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); From 9d4de50606551b169830eb66888a51f6da43e2df Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 19 Feb 2022 14:20:17 +0100 Subject: [PATCH 157/447] Test with 30 sec. interval --- apps/neonx/neonx.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index a90d5c609..02e228a03 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -50,7 +50,7 @@ const screenWidth = g.getWidth(); const screenHeight = g.getHeight(); const halfWidth = screenWidth / 2; const scale = screenWidth / 240; -const REFRESH_RATE = 60E3; +const REFRESH_RATE = 30E3; let interval = 0; let showingDate = false; From c7a1d9e368d20b1eeaff2b19d8bdafe2ec6375aa Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 19 Feb 2022 14:24:34 +0100 Subject: [PATCH 158/447] Back to 10 sec. refresh rate --- apps/neonx/neonx.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index 02e228a03..bbc1bfeda 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -50,7 +50,7 @@ const screenWidth = g.getWidth(); const screenHeight = g.getHeight(); const halfWidth = screenWidth / 2; const scale = screenWidth / 240; -const REFRESH_RATE = 30E3; +const REFRESH_RATE = 10E3; let interval = 0; let showingDate = false; From 5460a95b8e92d3f2d0113de455622c76d699eb7a Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 19 Feb 2022 14:31:58 +0100 Subject: [PATCH 159/447] Queue draw based on current time. --- apps/neonx/neonx.app.js | 55 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index bbc1bfeda..6a8b933e5 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -50,9 +50,6 @@ const screenWidth = g.getWidth(); const screenHeight = g.getHeight(); const halfWidth = screenWidth / 2; const scale = screenWidth / 240; -const REFRESH_RATE = 10E3; - -let interval = 0; let showingDate = false; @@ -107,20 +104,22 @@ function drawClock(num){ function draw(date){ + queueDraw(); + let d = new Date(); let l1, l2; showingDate = date; if (date) { - setUpdateInt(0); - l1 = ('0' + (new Date()).getDate()).substr(-2); l2 = ('0' + ((new Date()).getMonth() + 1)).substr(-2); + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + setTimeout(_ => { draw(); - setUpdateInt(1); }, 5000); } else { l1 = ('0' + (d.getHours() % (is12hour ? 12 : 24))).substr(-2); @@ -137,34 +136,32 @@ function draw(date){ } -function setUpdateInt(set){ - if (interval) { - clearInterval(interval); - } - - if (set) { - interval = setInterval(draw, REFRESH_RATE); - } +/* + * Draw watch face + */ +var drawTimeout; +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); } -g.clear(1); - -Bangle.setUI("clock"); - -setUpdateInt(1); -draw(); - +/* + * Event handlers + */ if (settings.showDate) { Bangle.on('touch', () => draw(!showingDate)); } Bangle.on('lcdPower', function(on){ - if (on){ - setUpdateInt(1); + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + + if (on) { draw(); - } else { - setUpdateInt(0); } }); @@ -172,6 +169,14 @@ Bangle.on('lock', function(isLocked) { draw(); }); + +/* + * Draw first time + */ +g.clear(1); +Bangle.setUI("clock"); +draw(); + Bangle.loadWidgets(); if(settings.fullscreen){ From 7f515b172a25233c7e5a74e44e8aa1a184e57291 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Sat, 19 Feb 2022 14:00:33 +0000 Subject: [PATCH 160/447] Stopwatch touch - adjust on touch for x,y outside the g dimensions of the screen --- apps/stopwatch/ChangeLog | 1 + apps/stopwatch/metadata.json | 2 +- apps/stopwatch/stopwatch.app.js | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/stopwatch/ChangeLog b/apps/stopwatch/ChangeLog index 9db0e26c5..104fce19d 100644 --- a/apps/stopwatch/ChangeLog +++ b/apps/stopwatch/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: Adjust for touch events outside of screen g dimensions diff --git a/apps/stopwatch/metadata.json b/apps/stopwatch/metadata.json index e72d85af1..cc13ec92f 100644 --- a/apps/stopwatch/metadata.json +++ b/apps/stopwatch/metadata.json @@ -1,7 +1,7 @@ { "id": "stopwatch", "name": "Stopwatch Touch", - "version": "0.01", + "version": "0.02", "description": "A touch based stop watch for Bangle JS 2", "icon": "stopwatch.png", "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"}], diff --git a/apps/stopwatch/stopwatch.app.js b/apps/stopwatch/stopwatch.app.js index 48d4f26ea..e2be95451 100644 --- a/apps/stopwatch/stopwatch.app.js +++ b/apps/stopwatch/stopwatch.app.js @@ -185,17 +185,27 @@ resetBtn.setImage(pause_img); Bangle.on('touch', function(button, xy) { + var x = xy.x; + var y = xy.y; + + // adjust for outside the dimension of the screen + // http://forum.espruino.com/conversations/371867/#comment16406025 + if (y > h) y = h; + if (y < 0) y = 0; + if (x > w) x = w; + if (x < 0) x = 0; + // not running, and reset - if (!running && tCurrent == tTotal && bigPlayPauseBtn.check(xy.x, xy.y)) return; + if (!running && tCurrent == tTotal && bigPlayPauseBtn.check(x, y)) return; // paused and hit play - if (!running && tCurrent != tTotal && smallPlayPauseBtn.check(xy.x, xy.y)) return; + if (!running && tCurrent != tTotal && smallPlayPauseBtn.check(x, y)) return; // paused and press reset - if (!running && tCurrent != tTotal && resetBtn.check(xy.x, xy.y)) return; + if (!running && tCurrent != tTotal && resetBtn.check(x, y)) return; // must be running - if (running && bigPlayPauseBtn.check(xy.x, xy.y)) return; + if (running && bigPlayPauseBtn.check(x, y)) return; }); // Stop updates when LCD is off, restart when on From 91b905a777f08b7d9bdf602781c12c1e2c8b7f80 Mon Sep 17 00:00:00 2001 From: xxDUxx <96152564+xxDUxx@users.noreply.github.com> Date: Sat, 19 Feb 2022 18:04:37 +0100 Subject: [PATCH 161/447] Update ChangeLog --- apps/contourclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/contourclock/ChangeLog b/apps/contourclock/ChangeLog index 0b6709d24..9c62e637b 100644 --- a/apps/contourclock/ChangeLog +++ b/apps/contourclock/ChangeLog @@ -4,3 +4,4 @@ 0.22: Changed timing code, original "Nunito" Font is back! 0.23: Customizer! Unused fonts no longer take up precious memory. 0.24: Added previews to the customizer. +0.25: Fixed a bug that would let widgets change the color of the clock. From 47ac08e12e753f55b2746302f91cf7eeb8d13263 Mon Sep 17 00:00:00 2001 From: xxDUxx <96152564+xxDUxx@users.noreply.github.com> Date: Sat, 19 Feb 2022 18:04:58 +0100 Subject: [PATCH 162/447] Update metadata.json --- apps/contourclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/contourclock/metadata.json b/apps/contourclock/metadata.json index a5d764f2d..54d799127 100644 --- a/apps/contourclock/metadata.json +++ b/apps/contourclock/metadata.json @@ -1,7 +1,7 @@ { "id": "contourclock", "name": "Contour Clock", "shortName" : "Contour Clock", - "version":"0.24", + "version":"0.25", "icon": "app.png", "description": "A Minimalist clockface with large Digits. Now with more fonts!", "screenshots" : [{"url":"cc-screenshot-1.png"},{"url":"cc-screenshot-2.png"}], From 7a4f67c342b68cfcdfb02ea6fde9ab317e058125 Mon Sep 17 00:00:00 2001 From: xxDUxx <96152564+xxDUxx@users.noreply.github.com> Date: Sat, 19 Feb 2022 19:53:08 +0100 Subject: [PATCH 163/447] Update app.js --- apps/contourclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/contourclock/app.js b/apps/contourclock/app.js index 85692da60..cdfadd217 100644 --- a/apps/contourclock/app.js +++ b/apps/contourclock/app.js @@ -10,7 +10,7 @@ if (settings.fontIndex==undefined) { function draw() { var date = new Date(); // Draw day of the week - g.setColor(g.theme.fg); + g.reset(); g.setFont("Teletext10x18Ascii"); g.clearRect(0,138,g.getWidth()-1,176); g.setFontAlign(0,1).drawString(require("locale").dow(date).toUpperCase(),g.getWidth()/2,g.getHeight()-18); From c0921c6a1db1b05f7acb4a2fca133ca170ed0667 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sat, 19 Feb 2022 21:24:13 +0100 Subject: [PATCH 164/447] messages: add Home Assistant icon --- apps/messages/ChangeLog | 1 + apps/messages/app.js | 2 ++ apps/messages/metadata.json | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 4811cd19b..1290ad089 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -31,3 +31,4 @@ 0.19: Use a larger font for message text if it'll fit 0.20: Allow tapping on the body to show a scrollable view of the message and title in a bigger font (fix #1405, #1031) 0.21: Improve list readability on dark theme +0.22: Add Home Assistant icon diff --git a/apps/messages/app.js b/apps/messages/app.js index 4aaf97369..56753995f 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -83,6 +83,7 @@ function getMessageImage(msg) { if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA=="); if (s=="facebook") return getFBIcon(); if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA="); + if (s=="home assistant") return atob("FhaBAAAAAADAAAeAAD8AAf4AD/3AfP8D7fwft/D/P8ec572zbzbNsOEhw+AfD8D8P4fw/z/D/P8P8/w/z/AAAAA="); if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA=="); if (s=="gmail") return getNotificationImage(); if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA=="); @@ -114,6 +115,7 @@ function getMessageImageCol(msg,def) { "facebook": "#4267b2", "gmail": "#ea4335", "google home": "#fbbc05", + "home assistant": "#fff", // ha-blue is #41bdf5, but that's the background "hangouts": "#1ba261", "instagram": "#dd2a7b", "messenger": "#0078ff", diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 6834693ae..e84d9f0d9 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.21", + "version": "0.22", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", From c130fa05d1bda5471239d46cc069863abfc5ec4f Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sat, 19 Feb 2022 21:24:35 +0100 Subject: [PATCH 165/447] messages: fix ChangeLog typo --- apps/messages/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 1290ad089..6b967d566 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -15,7 +15,7 @@ 0.10: Respect the 'new' attribute if it was set from iOS integrations 0.11: Open app when touching the widget (Bangle.js 2 only) 0.12: Extra app-specific notification icons - New animated notifcationicon (instead of large blinking 'MESSAGES') + New animated notification icon (instead of large blinking 'MESSAGES') Added screenshots 0.13: Add /*LANG*/ comments for internationalisation Add 'Delete All' option to message options From 60cae6bc8420f709a45fca95008917186681a3db Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sun, 13 Feb 2022 15:57:40 +0100 Subject: [PATCH 166/447] gbmusic: Simplify touch controls --- apps/gbmusic/ChangeLog | 1 + apps/gbmusic/README.md | 11 ++++--- apps/gbmusic/app.js | 48 ++++--------------------------- apps/gbmusic/metadata.json | 5 ++-- apps/gbmusic/screenshot_v1.png | Bin 5193 -> 0 bytes apps/gbmusic/screenshot_v1_d.png | Bin 0 -> 15590 bytes apps/gbmusic/screenshot_v1_l.png | Bin 0 -> 5102 bytes apps/gbmusic/screenshot_v2.png | Bin 3432 -> 0 bytes apps/gbmusic/screenshot_v2_d.png | Bin 0 -> 14443 bytes apps/gbmusic/screenshot_v2_l.png | Bin 0 -> 3357 bytes 10 files changed, 14 insertions(+), 51 deletions(-) delete mode 100644 apps/gbmusic/screenshot_v1.png create mode 100644 apps/gbmusic/screenshot_v1_d.png create mode 100644 apps/gbmusic/screenshot_v1_l.png delete mode 100644 apps/gbmusic/screenshot_v2.png create mode 100644 apps/gbmusic/screenshot_v2_d.png create mode 100644 apps/gbmusic/screenshot_v2_l.png diff --git a/apps/gbmusic/ChangeLog b/apps/gbmusic/ChangeLog index 8b1a3e4aa..cf010a771 100644 --- a/apps/gbmusic/ChangeLog +++ b/apps/gbmusic/ChangeLog @@ -7,3 +7,4 @@ 0.07: Fix "previous" button image 0.08: Fix scrolling title background color 0.09: Move event listener from widget to boot code, stops music from showing up in messages +0.10: Simplify touch events diff --git a/apps/gbmusic/README.md b/apps/gbmusic/README.md index 5d06164c2..7bd1486de 100644 --- a/apps/gbmusic/README.md +++ b/apps/gbmusic/README.md @@ -3,9 +3,10 @@ If you have an Android phone with Gadgetbridge, this app allows you to view and control music playback. -| Bangle.js 1 | Bangle.js 2 | -|:-------------------------------------------|:-------------------------------------------| -| ![Screenshot: Bangle 1](screenshot_v1.png) | ![Screenshot: Bangle 2](screenshot_v2.png) | +| Bangle.js 1 | Bangle.js 2 | +|:---------------------------------------------------------|:---------------------------------------------------------| +| ![Screenshot: Bangle 1 Dark theme](screenshot_v1_d.png) | ![Screenshot: Bangle 2 Darm theme](screenshot_v2_d.png) | +| ![Screenshot: Bangle 1 Light theme](screenshot_v1_l.png) | ![Screenshot: Bangle 2 Light theme](screenshot_v2_l.png) | Download the [latest Gadgetbridge for Android here](https://f-droid.org/packages/nodomain.freeyourgadget.gadgetbridge/). @@ -40,9 +41,7 @@ Disable double/triple pressing Middle Button: always simply toggle play/pause. * Button 3 (*Bangle.js 1*): Volume down ### Touch -* Left: Pause/previous song -* Right: Next song/resume -* Center: Toggle play/pause +* Touch: Toggle play/pause * Swipe left/right: Next/previous song * Swipe up/down (*Bangle.js 2*): Volume up/down diff --git a/apps/gbmusic/app.js b/apps/gbmusic/app.js index c8395f745..efcfdac22 100644 --- a/apps/gbmusic/app.js +++ b/apps/gbmusic/app.js @@ -195,9 +195,7 @@ function makeUI() { { type: "h", c: [ {width: 3}, - {id: "prev", type: "custom", height: 15, width: 15, icon: "previous", render: rIcon, bgCol: g.theme.bg}, {id: "date", type: "txt", halign: 0, valign: 1, label: "", font: "8%", fillx: 1, bgCol: g.theme.bg}, - {id: "next", type: "custom", height: 15, width: 15, icon: "next", render: rIcon, bgCol: g.theme.bg}, BANGLE2 ? {width: 3} : {id: "down", type: "txt", label: " -", font: "6x8:2"}, ], }, @@ -295,16 +293,10 @@ function drawDateTime() { } function drawControls() { - let l = layout; + if (BANGLE2) return; const cc = a => (a ? "#f00" : "#0f0"); // control color: red for active, green for inactive - if (!BANGLE2) { - l.up.col = cc("volumeup" in tCommand); - l.down.col = cc("volumedown" in tCommand); - } - l.prev.icon = (stat==="play") ? "pause" : "previous"; - l.prev.col = cc("prev" in tCommand || "pause" in tCommand); - l.next.icon = (stat==="play") ? "next" : "play"; - l.next.col = cc("next" in tCommand || "play" in tCommand); + layout.up.col = cc("volumeup" in tCommand); + layout.down.col = cc("volumedown" in tCommand); layout.render(); } @@ -473,37 +465,16 @@ function sendCommand(command) { drawControls(); } -// touch/swipe: navigation function togglePlay() { sendCommand(stat==="play" ? "pause" : "play"); } -function pausePrev() { - sendCommand(stat==="play" ? "pause" : "previous"); -} -function nextPlay() { - sendCommand(stat==="play" ? "next" : "play"); -} /** * Setup touch+swipe for Bangle.js 1 */ function touch1() { - Bangle.on("touch", side => { - if (!Bangle.isLCDOn()) {return;} // for <2v10 firmware - switch(side) { - case 1: - pausePrev(); - break; - case 2: - nextPlay(); - break; - default: - togglePlay(); - break; - } - }); + Bangle.on("touch", togglePlay); Bangle.on("swipe", dir => { - if (!Bangle.isLCDOn()) {return;} // for <2v10 firmware sendCommand(dir===1 ? "previous" : "next"); }); } @@ -511,16 +482,7 @@ function touch1() { * Setup touch+swipe for Bangle.js 2 */ function touch2() { - Bangle.on("touch", (side, xy) => { - const ar = Bangle.appRect; - if (xy.xar.x+ar.w*2/3) { - nextPlay(); - } else { - togglePlay(); - } - }); + Bangle.on("touch", togglePlay); // swiping let drag; Bangle.on("drag", e => { diff --git a/apps/gbmusic/metadata.json b/apps/gbmusic/metadata.json index f578f1f48..0ded80452 100644 --- a/apps/gbmusic/metadata.json +++ b/apps/gbmusic/metadata.json @@ -2,10 +2,11 @@ "id": "gbmusic", "name": "Gadgetbridge Music Controls", "shortName": "Music Controls", - "version": "0.09", + "version": "0.10", "description": "Control the music on your Gadgetbridge-connected phone", "icon": "icon.png", - "screenshots": [{"url":"screenshot_v1.png"},{"url":"screenshot_v2.png"}], + "screenshots": [{"url":"screenshot_v1_d.png"},{"url":"screenshot_v1_l.png"}, + {"url":"screenshot_v2_d.png"},{"url":"screenshot_v2_l.png"}], "type": "app", "tags": "tools,bluetooth,gadgetbridge,music", "supports": ["BANGLEJS","BANGLEJS2"], diff --git a/apps/gbmusic/screenshot_v1.png b/apps/gbmusic/screenshot_v1.png deleted file mode 100644 index 3b290e4591bd6181e832d864ddfb366681ba8cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5193 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 literal 0 HcmV?d00001 diff --git a/apps/gbmusic/screenshot_v1_l.png b/apps/gbmusic/screenshot_v1_l.png new file mode 100644 index 0000000000000000000000000000000000000000..725b21839c519784f11d7f305e0cefd6c501baba GIT binary patch literal 5102 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 diff --git a/apps/gbmusic/screenshot_v2_d.png b/apps/gbmusic/screenshot_v2_d.png new file mode 100644 index 0000000000000000000000000000000000000000..63e502cef6ed8e8a7a1f4e82e54c5321fd32d9c1 GIT binary patch literal 14443 zcmZvDb8scVw`OeHwlT47-`MuVwrv}eiOri#Y-@63+s-5t?)+Z8x3#;qU3JcPQ2j@L zb-GSf*XbBlWf^1y0t7HHFl0GdN%eo&_#c6T`KKE?4voOTSZ90zI_~PGUS!U$PFA)K zmSpZe&X#1B-nLd?VBYJXd|gixp45n)rdT})wCt>~yZmi2*1o>DA~RjBHOuGQ`Alkc ztehAqifc5uGJ&tZq$?i>q+f6Ysb2IeTE6s!U+OAbFh$?K{x`(Fw|NF3F`1XoxZ;XqugB$oIwWV8hvxAb_uyJxh z9$;8mG)Mch%$vn~hZ`C!#(X3z4rOB>r`b+v|;;4=tNbAJ|?H1TLb}->==Qx0axHfxgWi1r03! zw?f8I%UJu!l8oO){RgM%Mp%}wpwEulz(xg5)tfG{FN5FTS?#9x2eC#^+V>nfw<>wMbG9lM8 zz>T?WS<8=@xqZo%v95jDmvGA$3et_W=g+bq>Con`beKJIZ_sUqE$8gF2d0);?l+>i zTV2~DO)W#mC$9D@U`ULi=a%EMkg_vu8SmMlhO*GrBPUCf=YbN>j_ZYE$Ie}kopH_U zR6}2r-JU(@vM#;1A+UkK*rV+eD2bMDQHRfHMc=ru$tWtCw>;gEoN9a2YSl|9my#f6 zRhO_K#yE;mj>)uh+vE9V(An4eou%WS`g5Z-YkT&|qcz*)-dDfTr_;s^)OQ*Y)~)1w zO1V7PQ6ZdNN2^NsIve|H!0q~}7&LIF>y~qLNuX@e4!^n}!O#JXD=z29M1zgh)b;18 zQ;)=-V2DQf)e+27L^Lj90y|B#OS^HyHDSPN%_NC1q>)-trrPCAf9%W)nl}o%-k(FB z#(mZ>whGNFsV+m}1%nVuua(a)zYd70C)`NN1`_a!R&L+zMe zjxujg<>&C4pLrLNJvu-=IV`rw^ePLj*%O_~H>01ikYRt8+Jx4+zvKI_=%hKxnimK? zI##tgT!{Xno$Ysbv6gGIAKI{moH`RwUd(B{4jj2v4TX||(-B&M9GvhI)rru-lHeHy%KY-py&tY%U#GTt zHb%be2p&enDDtBx$y%VW*ntF^$oxseh{@XmKj2rfH@TR^%?VrSG!gm1P{f;0uqqrp zDmH8JHmZzz5)k4vaC`vSXMeU{&(ej_qicS#ljpYB8nnu=L93!Q_#A>Xi}|ifk?3eIkswv{h{E> zKF6U!C8o^{7kf{zVnQ71FA44Vmct>8n6_?g*CHAH%w?o-)&;y@ppcVFMoR7alJASSODnfvLY6j}95Is@3deE8WTlGm9sa) zCbkfP&JbEyvvSU%azRN}4{|WQ<&YdPasiJ9n>PQa_pgm|b*J7AowApY4kG=?ohYtA;tNkq{>kduXmMOrq7eb%zv4AxeQ^GE+*0HNix& zmzwd=Bw1vd9Paf?`vxgDbdZb8zh{ZA*!tej5D#WbXg`~~F?kf~YxP=zrAW*05n%F} zLbyX}fgx~e1CtU-;C}~+hn_db>6vXTB}304&x#816)$+0bqW|Q0tpUj_>gsATqZPj zP!;*z74ynpE

QtnzA2q{yU}n_6iqGK4Yn}iuc%QoCo*m}|2 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 literal 0 HcmV?d00001 diff --git a/apps/gbmusic/screenshot_v2_l.png b/apps/gbmusic/screenshot_v2_l.png new file mode 100644 index 0000000000000000000000000000000000000000..521d304aa4c4c82a30fe974905e3d0132ef31aa8 GIT binary patch literal 3357 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 NbJJ@k6~=B4{{zxVG*|!t literal 0 HcmV?d00001 From b25611ee8481be3ae00cce6f91803588fedb4e5f Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Sat, 19 Feb 2022 16:37:34 -0500 Subject: [PATCH 167/447] Fix track name, artist, and album names clipping --- apps/messages/app.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 4aaf97369..f0ee249e2 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -165,6 +165,10 @@ function showMapMessage(msg) { }); } +function reduceStringAndPad(text, maxLen) { + return text.length > maxLen ? text.substr(0, maxLen - 1) + '...' : text; +} + function showMusicMessage(msg) { function fmtTime(s) { var m = Math.floor(s/60); @@ -178,15 +182,20 @@ function showMusicMessage(msg) { layout = undefined; checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); } + + var trackName = reduceStringAndPad(msg.track, 13); + var artistName = reduceStringAndPad(msg.artist, 21); + var albumName = reduceStringAndPad(msg.album, 21); + layout = new Layout({ type:"v", c: [ {type:"h", fillx:1, bgCol:colBg, c: [ { type:"btn", src:getBackImage, cb:back }, { type:"v", fillx:1, c: [ - { type:"txt", font:fontMedium, label:msg.artist, pad:2 }, - { type:"txt", font:fontMedium, label:msg.album, pad:2 } + { type:"txt", font:fontMedium, label:artistName, pad:2 }, + { type:"txt", font:fontMedium, label:albumName, pad:2 } ]} ]}, - {type:"txt", font:fontLarge, label:msg.track, fillx:1, filly:1, pad:2 }, + {type:"txt", font:fontLarge, label:trackName, fillx:1, filly:1, pad:2 }, Bangle.musicControl?{type:"h",fillx:1, c: [ {type:"btn", pad:8, label:"\0"+atob("FhgBwAADwAAPwAA/wAD/gAP/gA//gD//gP//g///j///P//////////P//4//+D//gP/4A/+AD/gAP8AA/AADwAAMAAA"), cb:()=>Bangle.musicControl("play")}, // play {type:"btn", pad:8, label:"\0"+atob("EhaBAHgHvwP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP3gHg"), cb:()=>Bangle.musicControl("pause")}, // pause From 4e1cec0993629281ea1e1b3906591aeca85c71f2 Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Sat, 19 Feb 2022 16:37:50 -0500 Subject: [PATCH 168/447] Increment app version --- apps/messages/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 6834693ae..e84d9f0d9 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.21", + "version": "0.22", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", From ee74900f4acad32ede9580c7115baac8fa923780 Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Sat, 19 Feb 2022 22:54:50 +0100 Subject: [PATCH 169/447] Bold Clock: Removed "wake LCD on face-up" Removed "wake LCD on face-up"-feature of Bold Clock: A watch-face should not set things like "wake LCD on face-up". If you want, that the LCD get activated when facing up, go to Settings > System > LCD > Wake on FaceUp. --- apps/boldclk/bold_clock.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/boldclk/bold_clock.js b/apps/boldclk/bold_clock.js index 4358b2e29..9d3ea0756 100644 --- a/apps/boldclk/bold_clock.js +++ b/apps/boldclk/bold_clock.js @@ -129,14 +129,6 @@ Bangle.on('lcdPower', (on) => { clearTimers(); } }); -Bangle.on('faceUp',function(up){ - //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); - if (up && !Bangle.isLCDOn()) { - //console.log("faceUp and LCD off"); - clearTimers(); - Bangle.setLCDPower(true); - } -}); g.clear(); Bangle.loadWidgets(); From 2b49fbaa9ab0050a550a8685b64241e7dca7c476 Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Sat, 19 Feb 2022 22:59:37 +0100 Subject: [PATCH 170/447] Bold Clock: Removed "wake LCD on face-up" Removed "wake LCD on face-up"-feature of Bold Clock: A watch-face should not set things like "wake LCD on face-up". If you want, that the LCD get activated when facing up, go to Settings > System > LCD > Wake on FaceUp. --- apps/boldclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/boldclk/ChangeLog b/apps/boldclk/ChangeLog index c7a4ba7b4..30ac31c61 100644 --- a/apps/boldclk/ChangeLog +++ b/apps/boldclk/ChangeLog @@ -2,3 +2,4 @@ 0.03: Tweak for more efficient rendering, and firmware 2v06 0.04: Work with themes, smaller screens 0.05: Adjust hand lengths to be within 'tick' points +0.06: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". From 74646002afbc3f3f75f02f9f5356f75ed613a25d Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Sat, 19 Feb 2022 23:00:50 +0100 Subject: [PATCH 171/447] Bold Clock: Removed "wake LCD on face-up" Removed "wake LCD on face-up"-feature of Bold Clock: A watch-face should not set things like "wake LCD on face-up". If you want, that the LCD get activated when facing up, go to Settings > System > LCD > Wake on FaceUp. --- apps/boldclk/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/boldclk/metadata.json b/apps/boldclk/metadata.json index 7e3941cb3..cf961347d 100644 --- a/apps/boldclk/metadata.json +++ b/apps/boldclk/metadata.json @@ -1,7 +1,7 @@ { "id": "boldclk", "name": "Bold Clock", - "version": "0.05", + "version": "0.06", "description": "Simple, readable and practical clock", "icon": "bold_clock.png", "screenshots": [{"url":"screenshot_bold.png"}], From 7d9ef97800115cbccbdc3f822b55bba7bddfa4ea Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Sat, 19 Feb 2022 17:18:21 -0500 Subject: [PATCH 172/447] Make music text scroll --- apps/messages/app.js | 68 +++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index f0ee249e2..7d3d78e2e 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -165,11 +165,20 @@ function showMapMessage(msg) { }); } -function reduceStringAndPad(text, maxLen) { - return text.length > maxLen ? text.substr(0, maxLen - 1) + '...' : text; +function reduceStringAndPad(text, offset, maxLen) { + var sliceLength = offset + maxLen > text.length ? text.length - offset : maxLen; + return text.substr(offset, sliceLength).padEnd(maxLen, " "); } function showMusicMessage(msg) { + var updateLabelsInterval; + var trackScrollOffset = 0; + var artistScrollOffset = 0; + var albumScrollOffset = 0; + var trackName = ''; + var artistName = ''; + var albumName = ''; + function fmtTime(s) { var m = Math.floor(s/60); s = (parseInt(s%60)).toString().padStart(2,0); @@ -177,34 +186,47 @@ function showMusicMessage(msg) { } function back() { + clearInterval(updateLabelsInterval); msg.new = false; saveMessages(); layout = undefined; checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); } - var trackName = reduceStringAndPad(msg.track, 13); - var artistName = reduceStringAndPad(msg.artist, 21); - var albumName = reduceStringAndPad(msg.album, 21); + function updateLabels() { + trackName = reduceStringAndPad(msg.track, trackScrollOffset, 13); + artistName = reduceStringAndPad(msg.artist, artistScrollOffset, 21); + albumName = reduceStringAndPad(msg.album, albumScrollOffset, 21); - layout = new Layout({ type:"v", c: [ - {type:"h", fillx:1, bgCol:colBg, c: [ - { type:"btn", src:getBackImage, cb:back }, - { type:"v", fillx:1, c: [ - { type:"txt", font:fontMedium, label:artistName, pad:2 }, - { type:"txt", font:fontMedium, label:albumName, pad:2 } - ]} - ]}, - {type:"txt", font:fontLarge, label:trackName, fillx:1, filly:1, pad:2 }, - Bangle.musicControl?{type:"h",fillx:1, c: [ - {type:"btn", pad:8, label:"\0"+atob("FhgBwAADwAAPwAA/wAD/gAP/gA//gD//gP//g///j///P//////////P//4//+D//gP/4A/+AD/gAP8AA/AADwAAMAAA"), cb:()=>Bangle.musicControl("play")}, // play - {type:"btn", pad:8, label:"\0"+atob("EhaBAHgHvwP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP3gHg"), cb:()=>Bangle.musicControl("pause")}, // pause - {type:"btn", pad:8, label:"\0"+atob("EhKBAMAB+AB/gB/wB/8B/+B//B//x//5//5//x//B/+B/8B/wB/gB+AB8ABw"), cb:()=>Bangle.musicControl("next")}, // next - ]}:{}, - {type:"txt", font:"6x8:2", label:msg.dur?fmtTime(msg.dur):"--:--" } - ]}); - g.clearRect(Bangle.appRect); - layout.render(); + layout = new Layout({ type:"v", c: [ + {type:"h", fillx:1, bgCol:colBg, c: [ + { type:"btn", src:getBackImage, cb:back }, + { type:"v", fillx:1, c: [ + { type:"txt", font:fontMedium, label:artistName, pad:2 }, + { type:"txt", font:fontMedium, label:albumName, pad:2 } + ]} + ]}, + {type:"txt", font:fontLarge, label:trackName, fillx:1, filly:1, pad:2 }, + Bangle.musicControl?{type:"h",fillx:1, c: [ + {type:"btn", pad:8, label:"\0"+atob("FhgBwAADwAAPwAA/wAD/gAP/gA//gD//gP//g///j///P//////////P//4//+D//gP/4A/+AD/gAP8AA/AADwAAMAAA"), cb:()=>Bangle.musicControl("play")}, // play + {type:"btn", pad:8, label:"\0"+atob("EhaBAHgHvwP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP3gHg"), cb:()=>Bangle.musicControl("pause")}, // pause + {type:"btn", pad:8, label:"\0"+atob("EhKBAMAB+AB/gB/wB/8B/+B//B//x//5//5//x//B/+B/8B/wB/gB+AB8ABw"), cb:()=>Bangle.musicControl("next")}, // next + ]}:{}, + {type:"txt", font:"6x8:2", label:msg.dur?fmtTime(msg.dur):"--:--" } + ]}); + g.reset().clearRect(Bangle.appRect); + layout.render(); + + trackScrollOffset++; + artistScrollOffset++; + albumScrollOffset++; + + if (trackScrollOffset > trackName.length) trackScrollOffset = 0; + if (artistScrollOffset > artistName.length) artistScrollOffset = 0; + if (albumScrollOffset > albumName.length) albumScrollOffset = 0; + } + + updateLabelsInterval = setInterval(updateLabels, 1000); } function showMessageScroller(msg) { From 405711e82b44fb1562e5b18b8446548883d8b5b4 Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Sat, 19 Feb 2022 17:31:29 -0500 Subject: [PATCH 173/447] End scrolling at end of text --- apps/messages/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 7d3d78e2e..67738bc70 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -221,9 +221,9 @@ function showMusicMessage(msg) { artistScrollOffset++; albumScrollOffset++; - if (trackScrollOffset > trackName.length) trackScrollOffset = 0; - if (artistScrollOffset > artistName.length) artistScrollOffset = 0; - if (albumScrollOffset > albumName.length) albumScrollOffset = 0; + if ((trackScrollOffset + 13) > msg.track.length) trackScrollOffset = 0; + if ((artistScrollOffset + 21) > msg.artist.length) artistScrollOffset = 0; + if ((albumScrollOffset + 21) > msg.album.length) albumScrollOffset = 0; } updateLabelsInterval = setInterval(updateLabels, 1000); From f20872f6ae2cd2fbdb1b39489da525343ab5f217 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Sat, 19 Feb 2022 23:59:23 +0100 Subject: [PATCH 174/447] #1132: Messages: Allow disabling repetition of buzzer: Wow, dazzling solution --- apps/messages/metadata.json | 2 +- apps/messages/widget.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 93c1d573d..0ff2603c2 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.55", + "version": "0.43", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/widget.js b/apps/messages/widget.js index db9c42409..4a247b917 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -6,10 +6,9 @@ draw:function() { g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+this.iconwidth); g.drawImage((c&1) ? atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+DAADDAADDAADDwAPD8A/DOBzDDn/DA//DAHvDAPvjAPvjAPvjAPvh///gf/vAAD+AAB8AAAAA==") : atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+D///D///A//8CP/xDj/HD48DD+B8D/D+D/3vD/vvj/vvj/vvj/vvh/v/gfnvAAD+AAB8AAAAA=="), this.x, this.y); let settings = require('Storage').readJSON("messages.settings.json", true) || {}; + console.log("dingen ", typeof(settings.repeat), settings.repeat) if (settings.repeat===undefined) settings.repeat = 4; - if(settings.repeat===0) { - if(c===1) WIDGETS["messages"].buzz(); // buzz just once - } else if (csettings.repeat*1000) { + if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { this.l = Date.now(); WIDGETS["messages"].buzz(); // buzz every 4 seconds } From 32273ed1587d0a287e43453e8d58481f27717825 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sun, 13 Feb 2022 16:49:28 +0100 Subject: [PATCH 175/447] gbmusic: remove date+time --- apps/gbmusic/ChangeLog | 1 + apps/gbmusic/README.md | 1 - apps/gbmusic/app.js | 62 ++++++------------------------- apps/gbmusic/screenshot_v1_d.png | Bin 15590 -> 13284 bytes apps/gbmusic/screenshot_v1_l.png | Bin 5102 -> 8967 bytes apps/gbmusic/screenshot_v2_d.png | Bin 14443 -> 11408 bytes apps/gbmusic/screenshot_v2_l.png | Bin 3357 -> 13929 bytes 7 files changed, 12 insertions(+), 52 deletions(-) diff --git a/apps/gbmusic/ChangeLog b/apps/gbmusic/ChangeLog index cf010a771..e2ee53ede 100644 --- a/apps/gbmusic/ChangeLog +++ b/apps/gbmusic/ChangeLog @@ -8,3 +8,4 @@ 0.08: Fix scrolling title background color 0.09: Move event listener from widget to boot code, stops music from showing up in messages 0.10: Simplify touch events + Remove date+time diff --git a/apps/gbmusic/README.md b/apps/gbmusic/README.md index 7bd1486de..f1f9c4378 100644 --- a/apps/gbmusic/README.md +++ b/apps/gbmusic/README.md @@ -15,7 +15,6 @@ Download the [latest Gadgetbridge for Android here](https://f-droid.org/packages * Dynamic colors based on Track/Artist/Album name * Scrolling display for long titles * Automatic start when music plays -* Time and date display ## Settings diff --git a/apps/gbmusic/app.js b/apps/gbmusic/app.js index efcfdac22..5252ac0ac 100644 --- a/apps/gbmusic/app.js +++ b/apps/gbmusic/app.js @@ -10,15 +10,15 @@ const BANGLE2 = process.env.HWVERSION===2; /** * @param {string} text - * @return {number} Maximum font size to make text fit on screen + * @param {number} w Width to fit text in + * @return {number} Maximum font size to make text fit */ -function fitText(text) { +function fitText(text, w) { if (!text.length) { return Infinity; } // make a guess, then shrink/grow until it fits - const w = Bangle.appRect.w, - test = (s) => g.setFont("Vector", s).stringWidth(text); + const test = (s) => g.setFont("Vector", s).stringWidth(text); let best = Math.floor(100*w/test(100)); if (test(best)===w) { // good guess! return best; @@ -106,7 +106,7 @@ function rTitle(l) { rScroller(l); // already scrolling return; } - let size = fitText(l.label); + let size = fitText(l.label, l.w); if (sizel.h) { size = l.h; } @@ -182,21 +182,17 @@ function makeUI() { type: "v", c: [ { type: "h", fillx: 1, c: [ - {id: "time", type: "txt", label: "88:88", valign: -1, halign: -1, font: "8%", bgCol: g.theme.bg}, {fillx: 1}, - {id: "num", type: "txt", label: "88:88", valign: -1, halign: 1, font: "12%", bgCol: g.theme.bg}, - BANGLE2 ? {} : {id: "up", type: "txt", label: " +", font: "6x8:2"}, + {id: "num", type: "txt", label: "", valign: -1, halign: -1, font: "12%", bgCol: g.theme.bg}, + BANGLE2 ? {} : {id: "up", type: "txt", label: " +", halign: 1, font: "6x8:2"}, ], }, {id: "title", type: "custom", label: "", fillx: 1, filly: 2, offset: null, font: "Vector:20%", render: rTitle, bgCol: g.theme.bg}, {id: "artist", type: "custom", label: "", fillx: 1, filly: 1, size: 30, render: rInfo, bgCol: g.theme.bg}, - {id: "album", type: "custom", label: "", fillx: 1, filly: 1, size: 20, render: rInfo, bgCol: g.theme.bg}, - {height: 10}, { type: "h", c: [ - {width: 3}, - {id: "date", type: "txt", halign: 0, valign: 1, label: "", font: "8%", fillx: 1, bgCol: g.theme.bg}, - BANGLE2 ? {width: 3} : {id: "down", type: "txt", label: " -", font: "6x8:2"}, + {id: "album", type: "custom", label: "", fillx: 1, filly: 1, size: 20, render: rInfo, bgCol: g.theme.bg}, + BANGLE2 ? {} : {id: "down", type: "txt", label: " -", font: "6x8:2"}, ], }, {height: 10}, @@ -209,20 +205,6 @@ function makeUI() { // Self-repeating timeouts /////////////////////// -// Clock -let tock = -1; -function tick() { - if (!BANGLE2 && !Bangle.isLCDOn()) { - return; - } - const now = new Date(); - if (now.getHours()*60+now.getMinutes()!==tock) { - drawDateTime(); - tock = now.getHours()*60+now.getMinutes(); - } - setTimeout(tick, 1000); // we only show minute precision anyway -} - // Fade out while paused and auto closing let fade = null; function fadeOut() { @@ -269,28 +251,6 @@ function scrollStop() { //////////////////// // Drawing functions //////////////////// -/** - * Draw date and time - */ -function drawDateTime() { - const now = new Date(); - const l = require("locale"); - const is12 = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; - if (is12) { - const d12 = new Date(now.getTime()); - const hour = d12.getHours(); - if (hour===0) { - d12.setHours(12); - } else if (hour>12) { - d12.setHours(hour-12); - } - layout.time.label = l.time(d12, true)+l.meridian(now); - } else { - layout.time.label = l.time(now, true); - } - layout.date.label = require("locale").date(now, true); - layout.render(); -} function drawControls() { if (BANGLE2) return; @@ -331,6 +291,7 @@ function info(info) { layout.album.col = infoColor("album"); layout.artist.col = infoColor("artist"); layout.num.label = formatNum(info); + layout.update(); layout.render(); rTitle(layout.title); // force redraw of title, or scroller might break // reset auto exit interval @@ -557,7 +518,6 @@ function startWatches() { function start() { makeUI(); startWatches(); - tick(); startEmulator(); } diff --git a/apps/gbmusic/screenshot_v1_d.png b/apps/gbmusic/screenshot_v1_d.png index c85e8b8a6c400658e82c8c5dbd274f39fb41e7a6..3a6d84cffed4ca998a5f78bb299aa3b0fd2dfaae 100644 GIT binary patch literal 13284 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 diff --git a/apps/gbmusic/screenshot_v1_l.png b/apps/gbmusic/screenshot_v1_l.png index 725b21839c519784f11d7f305e0cefd6c501baba..1b6b57809cb905b4ba34c4440f671b0799f218f0 100644 GIT binary patch literal 8967 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 E52X)jJOBUy literal 14443 zcmZvDb8scVw`OeHwlT47-`MuVwrv}eiOri#Y-@63+s-5t?)+Z8x3#;qU3JcPQ2j@L zb-GSf*XbBlWf^1y0t7HHFl0GdN%eo&_#c6T`KKE?4voOTSZ90zI_~PGUS!U$PFA)K zmSpZe&X#1B-nLd?VBYJXd|gixp45n)rdT})wCt>~yZmi2*1o>DA~RjBHOuGQ`Alkc ztehAqifc5uGJ&tZq$?i>q+f6Ysb2IeTE6s!U+OAbFh$?K{x`(Fw|NF3F`1XoxZ;XqugB$oIwWV8hvxAb_uyJxh z9$;8mG)Mch%$vn~hZ`C!#(X3z4rOB>r`b+v|;;4=tNbAJ|?H1TLb}->==Qx0axHfxgWi1r03! zw?f8I%UJu!l8oO){RgM%Mp%}wpwEulz(xg5)tfG{FN5FTS?#9x2eC#^+V>nfw<>wMbG9lM8 zz>T?WS<8=@xqZo%v95jDmvGA$3et_W=g+bq>Con`beKJIZ_sUqE$8gF2d0);?l+>i zTV2~DO)W#mC$9D@U`ULi=a%EMkg_vu8SmMlhO*GrBPUCf=YbN>j_ZYE$Ie}kopH_U zR6}2r-JU(@vM#;1A+UkK*rV+eD2bMDQHRfHMc=ru$tWtCw>;gEoN9a2YSl|9my#f6 zRhO_K#yE;mj>)uh+vE9V(An4eou%WS`g5Z-YkT&|qcz*)-dDfTr_;s^)OQ*Y)~)1w zO1V7PQ6ZdNN2^NsIve|H!0q~}7&LIF>y~qLNuX@e4!^n}!O#JXD=z29M1zgh)b;18 zQ;)=-V2DQf)e+27L^Lj90y|B#OS^HyHDSPN%_NC1q>)-trrPCAf9%W)nl}o%-k(FB z#(mZ>whGNFsV+m}1%nVuua(a)zYd70C)`NN1`_a!R&L+zMe zjxujg<>&C4pLrLNJvu-=IV`rw^ePLj*%O_~H>01ikYRt8+Jx4+zvKI_=%hKxnimK? zI##tgT!{Xno$Ysbv6gGIAKI{moH`RwUd(B{4jj2v4TX||(-B&M9GvhI)rru-lHeHy%KY-py&tY%U#GTt zHb%be2p&enDDtBx$y%VW*ntF^$oxseh{@XmKj2rfH@TR^%?VrSG!gm1P{f;0uqqrp zDmH8JHmZzz5)k4vaC`vSXMeU{&(ej_qicS#ljpYB8nnu=L93!Q_#A>Xi}|ifk?3eIkswv{h{E> zKF6U!C8o^{7kf{zVnQ71FA44Vmct>8n6_?g*CHAH%w?o-)&;y@ppcVFMoR7alJASSODnfvLY6j}95Is@3deE8WTlGm9sa) zCbkfP&JbEyvvSU%azRN}4{|WQ<&YdPasiJ9n>PQa_pgm|b*J7AowApY4kG=?ohYtA;tNkq{>kduXmMOrq7eb%zv4AxeQ^GE+*0HNix& zmzwd=Bw1vd9Paf?`vxgDbdZb8zh{ZA*!tej5D#WbXg`~~F?kf~YxP=zrAW*05n%F} zLbyX}fgx~e1CtU-;C}~+hn_db>6vXTB}304&x#816)$+0bqW|Q0tpUj_>gsATqZPj zP!;*z74ynpE

QtnzA2q{yU}n_6iqGK4Yn}iuc%QoCo*m}|2 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 diff --git a/apps/gbmusic/screenshot_v2_l.png b/apps/gbmusic/screenshot_v2_l.png index 521d304aa4c4c82a30fe974905e3d0132ef31aa8..5cf05c7cb036c0d98662057318804a8165571c0c 100644 GIT binary patch literal 13929 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 literal 3357 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 NbJJ@k6~=B4{{zxVG*|!t From 71e60eda00a44d9fc253d4ddff122c092a0893d5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 21 Feb 2022 10:25:56 +0000 Subject: [PATCH 176/447] stop cadence needing GPS - fix #1480 --- modules/exstats.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/exstats.js b/modules/exstats.js index 8890ae9db..8a726a5de 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -207,7 +207,6 @@ exports.getStats = function(statIDs, options) { }; } if (statIDs.includes("caden")) { - needGPS = true; stats["caden"]={ title : "Cadence", getValue : function() { return state.stepsPerMin; }, From 580497b1e7be9d10256f41a277fc4a189efe4c56 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 21 Feb 2022 10:55:22 +0000 Subject: [PATCH 177/447] Fix Layout module rendering black text on white --- modules/Layout.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 134cc8103..1b0bbd47f 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -232,7 +232,7 @@ Layout.prototype.render = function (l) { function render(l) {"ram" g.reset(); - if (l.col) g.setColor(l.col); + if (l.col!==undefined) g.setColor(l.col); if (l.bgCol!==undefined) g.setBgColor(l.bgCol).clearRect(l.x,l.y,l.x+l.w-1,l.y+l.h-1); cb[l.type](l); } @@ -264,7 +264,7 @@ Layout.prototype.render = function (l) { x,y+4 ], bg = l.selected?g.theme.bgH:g.theme.bg2; g.setColor(bg).fillPoly(poly).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawPoly(poly); - if (l.col) g.setColor(l.col); + if (l.col!==undefined) g.setColor(l.col); if (l.src) g.setBgColor(bg).drawImage("function"==typeof l.src?l.src():l.src, l.x + 10 + (0|l.pad), l.y + 8 + (0|l.pad)); else g.setFont("6x8",2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); }, "img":function(l){ From 7a7462e714cca75a2346af082c5097b8d7ee4423 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 21 Feb 2022 11:08:44 +0000 Subject: [PATCH 178/447] 0.07: Fix crash if an odd number of active boxes are configured (fix #1473) --- apps/run/ChangeLog | 1 + apps/run/app.js | 12 ++++++------ apps/run/metadata.json | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index fd28c4414..0d61aa789 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -5,3 +5,4 @@ 0.04: Use the exstats module, and make what is displayed configurable 0.05: exstats updated so update 'distance' label is updated, option for 'speed' 0.06: Add option to record a run using the recorder app automatically +0.07: Fix crash if an odd number of active boxes are configured (fix #1473) diff --git a/apps/run/app.js b/apps/run/app.js index a8515a71a..bc1d54de2 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -62,14 +62,14 @@ for (var i=0;ilayout[e.id].label = e.getString()); - sb.on('changed', e=>layout[e.id].label = e.getString()); + if (sa) sa.on('changed', e=>layout[e.id].label = e.getString()); + if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); } // At the bottom put time/GPS state/etc lc.push({ type:"h", filly:1, c:[ diff --git a/apps/run/metadata.json b/apps/run/metadata.json index ea68f4734..7aabf8b53 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.06", + "version":"0.07", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", From d420f928203d0efbe7ce5f2eac7d5427320d0d6c Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Mon, 21 Feb 2022 16:44:35 +0100 Subject: [PATCH 179/447] Update 7x7dotsclock.app.js Fix Message indicator position, Fix Date visibility --- apps/7x7dotsclock/7x7dotsclock.app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index 3f2e9b9b1..15259ea8f 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -278,7 +278,7 @@ function drawWidgeds() { var x1M = 100; var y1M = y1B; - var x2M = x1M + 30; + var x2M = x1M + 25; var y2M = y2B; if (messages.some(m=>m.new)) { @@ -295,6 +295,7 @@ function drawWidgeds() { print(strDow[dow] + ' ' + day + '.' + month + ' ' + year); + g.setColor(g.theme.fg); g.setFontAlign(-1, -1,0); g.setFont("Vector", 20); g.drawString(strDow[dow] + ' ' + day, 0, 0, true); From 25e700e577df1f0796feedbb02995720cfd5a302 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:07:32 +0100 Subject: [PATCH 180/447] Update 7x7dotsclock.app.js respect theme colors --- apps/7x7dotsclock/7x7dotsclock.app.js | 32 +++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index 15259ea8f..1f846a340 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -13,9 +13,8 @@ var Xs = 0, Ys = 30,Xe = 175, Ye=175; var SegH = (Ye-Ys)/2,SegW = (Xe-Xs)/2; var Dx = SegW/14, Dy = SegH/16; -const hColor = [1,1,1]; + const mColor = [0.3,0.3,1]; -const bColor = [0.2,0.2,0.2]; const Font = [ [ @@ -114,16 +113,21 @@ const Font = [ var dho = -1, eho = -1, dmo = -1, emo = -1; -function drawHSeg(x1,y1,x2,y2,Num,dColor,Size) { - g.setColor(0,0,0); +function drawHSeg(x1,y1,x2,y2,Num,Color,Size) { + //g.setColor(0,0,0); + g.setColor(g.theme.bg); g.fillRect(x1, y1, x2, y2); for (let i = 1; i < 8; i++) { for (let j = 1; j < 8; j++) { if (Font[Num][j-1][i-1] == 1) { - g.setColor(dColor[0],dColor[1],dColor[2]); + if (Color == "fg") { + g.setColor(g.theme.fg); + } else { + g.setColor(mColor[0],mColor[1],mColor[2]); + } g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,Size); } else { - g.setColor(bColor[0],bColor[1],bColor[2]); + g.setColor(g.theme.fg); g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,1); } } @@ -131,11 +135,15 @@ function drawHSeg(x1,y1,x2,y2,Num,dColor,Size) { } -function drawSSeg(x1,y1,x2,y2,Num,dColor,Size) { +function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { for (let i = 1; i < 8; i++) { for (let j = 1; j < 8; j++) { if (Font[Num][j-1][i-1] == 1) { - g.setColor(dColor[0],dColor[1],dColor[2]); + if (Color == "fg") { + g.setColor(g.theme.fg); + } else { + g.setColor(mColor[0],mColor[1],mColor[2]); + } g.fillCircle(x1+(i-1)*(x2-x1)/7,y1+(j-1)*(y2-y1)/7,Size); } } @@ -185,25 +193,25 @@ function draw() { g.reset(); if (dh != dho) { g.setColor(1,1,1); - drawHSeg(Xs, Ys, Xs+SegW, Ys+SegH,dh,hColor,4); + drawHSeg(Xs, Ys, Xs+SegW, Ys+SegH,dh,"fg",4); dho = dh; } if (eh != eho) { g.setColor(1,1,1); - drawHSeg(Xs+SegW+Dx, Ys, Xs+SegW*2, Ys+SegH,eh,hColor,4); + drawHSeg(Xs+SegW+Dx, Ys, Xs+SegW*2, Ys+SegH,eh,"fg",4); eho = eh; } if (dm != dmo) { g.setColor(0.3,0.3,1); - drawHSeg(Xs, Ys+SegH+Dy, Xs+SegW, Ys+SegH*2,dm,mColor,4); + drawHSeg(Xs, Ys+SegH+Dy, Xs+SegW, Ys+SegH*2,dm,"",4); dmo = dm; } if (em != emo) { g.setColor(0.3,0.3,1); - drawHSeg(Xs+SegW+Dx, Ys+SegH+Dy, Xs+SegW*2, Ys+SegH*2,em,mColor,4); + drawHSeg(Xs+SegW+Dx, Ys+SegH+Dy, Xs+SegW*2, Ys+SegH*2,em,"",4); emo = em; } From 81b0097fa9672a1ffec0281c5e6e657dcb2672bf Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:35:32 +0100 Subject: [PATCH 181/447] Update 7x7dotsclock.app.js --- apps/7x7dotsclock/7x7dotsclock.app.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index 1f846a340..c6daee542 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -15,6 +15,7 @@ var Dx = SegW/14, Dy = SegH/16; const mColor = [0.3,0.3,1]; +const bColor = [0.3,0.3,0.3]; const Font = [ [ @@ -123,11 +124,11 @@ function drawHSeg(x1,y1,x2,y2,Num,Color,Size) { if (Color == "fg") { g.setColor(g.theme.fg); } else { - g.setColor(mColor[0],mColor[1],mColor[2]); + g.setColor(mColor[0],mColor[1],mColor[2]); } g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,Size); } else { - g.setColor(g.theme.fg); + g.setColor(bColor[0],bColor[1],bColor[2]); g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,1); } } @@ -142,7 +143,7 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { if (Color == "fg") { g.setColor(g.theme.fg); } else { - g.setColor(mColor[0],mColor[1],mColor[2]); + g.setColor(g.theme.fgH); } g.fillCircle(x1+(i-1)*(x2-x1)/7,y1+(j-1)*(y2-y1)/7,Size); } @@ -152,7 +153,7 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { function ShowSecons() { - g.setColor(1,1,1); + g.setColor(g.theme.bgH); g.fillRect((Xe-Xs) / 2 - 14 + Xs -3, (Ye-Ys) / 2 - 7 + Ys -3, (Xe-Xs) / 2 + 14 + Xs +1, @@ -163,13 +164,13 @@ function ShowSecons() { (Ye-Ys) / 2 - 7 + Ys , (Xe-Xs) / 2 + Xs -1, (Ye-Ys) / 2 + 7 + Ys, - ds,mColor,1); + ds,"",1); drawSSeg( (Xe-Xs) / 2 + Xs +1, (Ye-Ys) / 2 - 7 + Ys, (Xe-Xs) / 2 + 14 + Xs +1, (Ye-Ys) / 2 + 7 + Ys, - es,mColor,1); + es,"",1); } From 6110724f025cddb27f283493d7e2828d6aaa84b1 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:44:08 +0100 Subject: [PATCH 182/447] Update 7x7dotsclock.settings.js better menu naming --- apps/7x7dotsclock/7x7dotsclock.settings.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.settings.js b/apps/7x7dotsclock/7x7dotsclock.settings.js index 42473ec17..c2b5d6c2b 100644 --- a/apps/7x7dotsclock/7x7dotsclock.settings.js +++ b/apps/7x7dotsclock/7x7dotsclock.settings.js @@ -7,10 +7,10 @@ function showMainMenu() { const mainMenu = { "": {"title": "7x7 Dots Clock Settings"}, "< Back": ()=>load(), - "sw-up": ()=>showSelAppMenu("swupApp"), - "sw-down": ()=>showSelAppMenu("swdownApp"), - "sw-left": ()=>showSelAppMenu("swleftApp"), - "sw-right": ()=>showSelAppMenu("swrightApp") + "swipe-up": ()=>showSelAppMenu("swupApp"), + "swipe-down": ()=>showSelAppMenu("swdownApp"), + "swipe-left": ()=>showSelAppMenu("swleftApp"), + "swipe-right": ()=>showSelAppMenu("swrightApp") }; From 3a608bf1f52e69859ae02f5e8938adc52e4bc4d6 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:47:03 +0100 Subject: [PATCH 183/447] Update README.md theme infos --- apps/7x7dotsclock/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md index 7f899ff0f..76684bc1a 100644 --- a/apps/7x7dotsclock/README.md +++ b/apps/7x7dotsclock/README.md @@ -2,16 +2,14 @@ ![](dotsfontclock.png) -looks best with dark theme so far - * A Clock with big numbers made of 7x7 dots * system widgeds ar not (yet) supported * when screen is locked it shows hours and minutes in full screen mode +* respects theme colors ![](dotsfontclock-scr1.png) -* when screen is unlocked it shows additional info: bluetooth, battery, new message, date and seconds -* you can configure a app per swipe direction -* when swiping the configured apps are launced +* when screen is unlocked it shows additional info: bluetooth, battery, new message state, date and seconds +* you can configure an app per swipe direction +* when swiping the configured apps are launched * button press opens launcher - From 849c439e11c13d26043bed2d20a1570edcac98f8 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:54:53 +0100 Subject: [PATCH 184/447] Update metadata.json Allow emulator --- apps/7x7dotsclock/metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 7b2c52512..6bdeaa6b8 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -6,7 +6,8 @@ "icon": "dotsfontclock.png", "tags": "clock", "type": "clock", - "supports" : ["BANGLEJS2"], + "supports" : ["BANGLEJS2"], + "allow_emulator": true, "readme": "README.md", "storage": [ {"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"}, From 7af6dcd91460f8c2433a5e5707502046fd7fc365 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:56:41 +0100 Subject: [PATCH 185/447] Update metadata.json --- apps/7x7dotsclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 6bdeaa6b8..9f997e10d 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -1,7 +1,7 @@ { "id": "7x7dotsclock", "name": "7x7 Dots Clock", "shortName":"7x7 Dots Clock", - "version":"0.01", + "version":"0.02", "description": "A clock with a big 7x7 dots Font", "icon": "dotsfontclock.png", "tags": "clock", From b77578333337250e21133a46bbd83388f2f11e52 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 21 Feb 2022 19:19:08 +0100 Subject: [PATCH 186/447] Bugfix: Ensure that widgets are always hidden in fulscreen mode. --- apps/neonx/ChangeLog | 3 ++- apps/neonx/metadata.json | 2 +- apps/neonx/neonx.app.js | 28 +++++++++++++++------------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/neonx/ChangeLog b/apps/neonx/ChangeLog index 968d6d629..2e815a449 100644 --- a/apps/neonx/ChangeLog +++ b/apps/neonx/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial release 0.02: Optional fullscreen mode -0.03: Optional show lock status via color \ No newline at end of file +0.03: Optional show lock status via color +0.04: Ensure that widgets are always hidden in fullscreen mode \ No newline at end of file diff --git a/apps/neonx/metadata.json b/apps/neonx/metadata.json index 4ac7c4cea..840e5b82e 100644 --- a/apps/neonx/metadata.json +++ b/apps/neonx/metadata.json @@ -2,7 +2,7 @@ "id": "neonx", "name": "Neon X & IO X Clock", "shortName": "Neon X Clock", - "version": "0.03", + "version": "0.04", "description": "Pebble Neon X & Neon IO X for Bangle.js", "icon": "neonx.png", "type": "clock", diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js index 6a8b933e5..4b9231b0e 100644 --- a/apps/neonx/neonx.app.js +++ b/apps/neonx/neonx.app.js @@ -74,6 +74,12 @@ function drawLine(poly, thickness){ function drawClock(num){ let tx, ty; + if(settings.fullscreen){ + g.clearRect(0,0,screenWidth,screenHeight); + } else { + g.clearRect(0,24,240,240); + } + for (let x = 0; x <= 1; x++) { for (let y = 0; y <= 1; y++) { const current = ((y + 1) * 2 + x - 1); @@ -106,6 +112,14 @@ function drawClock(num){ function draw(date){ queueDraw(); + // Depending on the settings, we clear all widgets or draw those. + if(settings.fullscreen){ + for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} + } else { + Bangle.drawWidgets(); + } + + // Now lets draw the time/date let d = new Date(); let l1, l2; @@ -126,12 +140,6 @@ function draw(date){ l2 = ('0' + d.getMinutes()).substr(-2); } - if(settings.fullscreen){ - g.clearRect(0,0,screenWidth,screenHeight); - } else { - g.clearRect(0,24,240,240); - } - drawClock([l1, l2]); } @@ -175,12 +183,6 @@ Bangle.on('lock', function(isLocked) { */ g.clear(1); Bangle.setUI("clock"); -draw(); - Bangle.loadWidgets(); -if(settings.fullscreen){ - for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} -} else { - Bangle.drawWidgets(); -} \ No newline at end of file +draw(); \ No newline at end of file From e8bc79c34f008f462a21a46c267bfeee2861c85b Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 21 Feb 2022 20:11:54 +0000 Subject: [PATCH 187/447] The Ring - proof of concept ring guage using preset images --- apps/thering/0p.png | Bin 0 -> 11212 bytes apps/thering/100p.png | Bin 0 -> 2106 bytes apps/thering/10p.png | Bin 0 -> 11612 bytes apps/thering/1circle.png | Bin 0 -> 3127 bytes apps/thering/1ring.png | Bin 0 -> 14515 bytes apps/thering/20p.png | Bin 0 -> 11874 bytes apps/thering/2p.png | Bin 0 -> 11309 bytes apps/thering/30p.png | Bin 0 -> 12079 bytes apps/thering/40p.png | Bin 0 -> 12350 bytes apps/thering/4p.png | Bin 0 -> 11369 bytes apps/thering/50p.png | Bin 0 -> 12567 bytes apps/thering/60p.png | Bin 0 -> 12840 bytes apps/thering/70p.png | Bin 0 -> 13089 bytes apps/thering/7p.png | Bin 0 -> 11475 bytes apps/thering/80p.png | Bin 0 -> 13266 bytes apps/thering/90p.png | Bin 0 -> 13573 bytes apps/thering/README.md | 73 +++++++++ apps/thering/app-icon.js | 1 + apps/thering/app.js | 224 +++++++++++++++++++++++++++ apps/thering/app.png | Bin 0 -> 3305 bytes apps/thering/calc_precentages.js | 58 +++++++ apps/thering/metadata.json | 14 ++ apps/thering/screenshot_thering1.png | Bin 0 -> 3113 bytes apps/thering/screenshot_thering2.jpg | Bin 0 -> 45141 bytes 24 files changed, 370 insertions(+) create mode 100644 apps/thering/0p.png create mode 100644 apps/thering/100p.png create mode 100644 apps/thering/10p.png create mode 100644 apps/thering/1circle.png create mode 100644 apps/thering/1ring.png create mode 100644 apps/thering/20p.png create mode 100644 apps/thering/2p.png create mode 100644 apps/thering/30p.png create mode 100644 apps/thering/40p.png create mode 100644 apps/thering/4p.png create mode 100644 apps/thering/50p.png create mode 100644 apps/thering/60p.png create mode 100644 apps/thering/70p.png create mode 100644 apps/thering/7p.png create mode 100644 apps/thering/80p.png create mode 100644 apps/thering/90p.png create mode 100644 apps/thering/README.md create mode 100644 apps/thering/app-icon.js create mode 100644 apps/thering/app.js create mode 100644 apps/thering/app.png create mode 100644 apps/thering/calc_precentages.js create mode 100644 apps/thering/metadata.json create mode 100644 apps/thering/screenshot_thering1.png create mode 100644 apps/thering/screenshot_thering2.jpg diff --git a/apps/thering/0p.png b/apps/thering/0p.png new file mode 100644 index 0000000000000000000000000000000000000000..26b159a172b966bd60e74e76c0b6c4fa0865c3ff GIT binary patch literal 11212 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 literal 0 HcmV?d00001 diff --git a/apps/thering/100p.png b/apps/thering/100p.png new file mode 100644 index 0000000000000000000000000000000000000000..3e1464b65e930bb65050503620735a6519d4e245 GIT binary patch literal 2106 zcmb7GX*kq-8~*)=nK8ql*EW_UOV(;6%VC<3CBqOYw3xp(DOp+=8Je*bDn(9OD9gND z$(WQa)SslBRE*HEj-`=oQ)ujt^X2{iet7QXy6*e=_FUJKywBa4fLFr<00=I79lX|= z_wPty*0Hp5#DATj3trClfcr^f3;^t`i-Vmv!+$cnEuzOt#vyxc?fa}%U>{APM|&^O zU{#j>xfd3mLA3=fh1c{^LYM8>d3YuW^Bgr;a)kgUfsY4aK}!ajtU%Ry8OEjgs-F5y zsVKnY9F#2biC$gS;L(jR$Nke%AKY zHTX|L3t$YbBF~c5KygtkO1JI}a(J^(QJ!@)MXX623)2=d4q_^@jpw5$%u4 zcKPo2P_NE_7U{zqPnQhzqNCO2L>>Fpdf}rx@CRPC4g0bzEe^h4)#QZyvX&Ll2y>5f zPphbt(;&tk9mlQHJ`rW&1z4`|3~6ul=hW z{bvGfm{IjW(OX-B%=S_2k*g2w-)CpZ> z*a@58eq*~FbO6`0o<52!#adWcJi4BGB8BC(R*;6~lz5C~Ue?LvKxDs@DVS zGBYf1X1_O;nR3(zxxI9sw>a zZ0gqUvOIvW^*62O|C^xqqCBf%7}$`v;?DCN&C$x$hp<_*B}v!)>!b~3kjoJ{KAu)c zs_B&+or}R5#ylBb0DDZkdIP%Okn~pjk7J_97N|96i8k6)m`k#0%~7A6{$0C2Y= zZ3rS_{;#M2FFJ}_J${!@zGD=-INjJ+qoMWs4pH&22ip#_a5w6QU$oO(z)bplu0~Q& z(V5dm1dj$U^lXEwO3DLwR!EZcHw4<|b$`>UrR&#-_dG9*Au4-zuwSMa!LS@F^>Xja zU=VUHbWLav35~z4g2{<6k@1Lg@-n^I=Hs#H0X&f}UUAjX-ykU81A+cr>*$w;0zAoZ zLMSawFn|-pmlJ>h>Zop{K_DU{Ju$-I7M}Dj$i`%Jrfx&qZgH2tP(xl)KU%)_qm zr-XoQ_Uy#jIf*RAo4ks(`>A7Ru~~{!atBUbO&uGTCK)~qidm`C;77{BUR4w_exp@E z>29Qehf-TKx8h8b*Cj>wFC}YEsLZBY~SF@yUW$KwJ?u8q+vrD}g;hoK`4|ZuN?PYaYvYpejJR5Gy|K!9uUv(D0 z!pSradFy4~l?-)5nNf8;wO`Ws-{l`5wkA}cFu!I|lb-0kLA~oy60P||D9ch4PPe+3 zN9#EkXNiTi`W+7NE7S)&psaB1WQ);rTmemFE+kIgb4Pu&?uq<;UOQF@k#|sa$s*TcVjOBy1993zmN zpU5XghN8?=(ge@N_ct&s*OCVNB`fS}$KHMMPqCPwpt#pmtU;RQ^JJ+?sQBSl>H1iuTZF>_Xi-6Mu5sF6wV#=WkdlQov z*<8fNM38d!iJa)oJEuHs-a_nHl3FLk*mC1-yAI)maaH2QVzek&ZTFM{6NiguV7l!E ztL3v1H8Dxa#5&RDE%#24-7@aumfPF>+VNXH?az{%dW}Vj^WR1q8C_R3Ml93|FGCZ! zvh+4h#AxpL{p5anuYy48)}yiS_d0WKId%Pz68!M0gI2ljJGF}49eSr1SdL#tdBQ(H zAg3(e@Pn%c2uVBs;$-3U)oYhLHmp@#k>~B+x_di&z>ba+#^Y7 z$Rc0wKl6Bj&m(6Rq3Dz)_-dkRXgp literal 0 HcmV?d00001 diff --git a/apps/thering/10p.png b/apps/thering/10p.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a80aa23a17bc12c641a88f2f2491d806dcbb43 GIT binary patch literal 11612 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 VF^h->{tAGkD61w@A!Q!?{{Tlnw+8?K literal 0 HcmV?d00001 diff --git a/apps/thering/20p.png b/apps/thering/20p.png new file mode 100644 index 0000000000000000000000000000000000000000..4b2ce214c7b89c2166c45b8c7eda474842e74e40 GIT binary patch literal 11874 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 literal 0 HcmV?d00001 diff --git a/apps/thering/40p.png b/apps/thering/40p.png new file mode 100644 index 0000000000000000000000000000000000000000..07470987ad1de8457b9003e56e83a95656b7c65f GIT binary patch literal 12350 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 EU$`@Nx&QzG literal 0 HcmV?d00001 diff --git a/apps/thering/60p.png b/apps/thering/60p.png new file mode 100644 index 0000000000000000000000000000000000000000..18720530a0c3db53eb30b2e1e185a1fed585c508 GIT binary patch literal 12840 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 H4l(})KD5l+ literal 0 HcmV?d00001 diff --git a/apps/thering/70p.png b/apps/thering/70p.png new file mode 100644 index 0000000000000000000000000000000000000000..a55a0ffaf5cf2afa8c47e96db163158bdbc0540a GIT binary patch literal 13089 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 literal 0 HcmV?d00001 diff --git a/apps/thering/80p.png b/apps/thering/80p.png new file mode 100644 index 0000000000000000000000000000000000000000..a183084eb07ad7bc7781e44c450e210d99284562 GIT binary patch literal 13266 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 literal 0 HcmV?d00001 diff --git a/apps/thering/README.md b/apps/thering/README.md new file mode 100644 index 000000000..a63f7896a --- /dev/null +++ b/apps/thering/README.md @@ -0,0 +1,73 @@ +# The Ring + + *A proof of concept ring guage clock using images, acts as a tutorial piece for discussion* + + +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/) + +* The ring is a proof of concept to establish a clean way to draw a +large ring guage with few aliasing issues and artifacts. +* Rather than use grahics commands to draw the ring a series of fixed images are used. +* This allows for better accuracy of the initial image and also does not suffer from performance issues. +* The downside is that more storage and memory is used to hold the + initial images. This is not an issue on a Bangle 2. +* The ring effect is constructed from 14 images that represent a range of different percentages +* The percentages of the images are 0,2,4,7,10,20,30,40,50,60,70,80,90,100% +* The app is not intended to be enhanced further (apart from bug fixes) but rather as code that can be reused in other apps +* The full set of original images are included in the source code to demonstrate the concept +* I will use this code to build a new clock similar to Pastel but + using this ring guage for steps. The new clock will use more + attractive fonts and provide a settings meu to change the primary + color of the ring. + + +## Screenshots + +![](screenshot_thering1.png) + +It is worth looking at a photograph of the clock in action as the +screenshot does not do the final effect justice. + +![](screenshot_thering2.jpg) + +## Production + +1. I first generated a circle on black background using [The +Gimp](https://www.gimp.org/) image editor. I used this [Youtube +video](https://www.youtube.com/watch?v=AoIAznSdLik) to get started. +The initial image is 178x178 pixels. + +![](1circle.png) + +2. I then drew another smaller black circle over the top of the original to make a ring + +![](1ring.png) + +3. From the empty ring image I coloured segments of the ring and saved new images at specific percentages + +4. I used the file `calc_percentages.js` to work out the x and y +coordinates of the end point of each percentage position along the +ring. + +5. The [Image +Converter](https://espruino.github.io/EspruinoWebTools/examples/imageconverter.html) +was used, set to 2-bit optimal, transparency Y, compression Y and +ImageObject Y, to convert each PNG file to code. + +6. NOTE that the generated image object pallete seemed to switch the +order of the colors from 50% onwards. + +7. The greying out of the unused part of the ring is acheived by +using a dithered color. So if the ring colour is green #0f0 then the +greyed out part is done in '#020'. + + +## Stages of The Ring + +Below are some examples of the different stages of the ring + +![](0p.png) +![](7p.png) +![](60p.png) diff --git a/apps/thering/app-icon.js b/apps/thering/app-icon.js new file mode 100644 index 000000000..7d6edf547 --- /dev/null +++ b/apps/thering/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///un/1XEh32DyX/+AKIn/6//ABQ0P/Wq1dcBY3+1QAB64KFgfqBYWVoAtFBQWq2tQBYgtBBYdUERALBq5FE1WuF4dVKoYiB3QLEHgQiC1eq1EAitVuAiEBoOABYsOD4PqCwMA6tVKgU6FwWgAwNVqqFC/WrEQI1CBYY6BFwIiCgILDHQO79QiCBYg6BFwJFBgEFBYc+1YLBOAU1BYf6326FwReCBYXq3wuDLwRfBIwIuEKQR3BgY6CCwRGCBYbsBBYUNBYVAh+r1w6DIwS/BhwLBHQ1VNQILBHQzjBn2q9wLCFwb7Bn2u9wuEEgKCCUoIuEZQaOBIwQiDfQQvBBYRRDKQILEIoQiBIwK+CBYM9BYN9IwTWC1EDNAY6CBYP61AWCBoQuBFYP//oVDFwYLBBQppCAAX/D4V1XgQLDn4YEq4uCHgQYDqtfBQY8C//dCwPwBYgwBAAYiEGAQKC/gKFEgYWHHoYtGABYA=")) diff --git a/apps/thering/app.js b/apps/thering/app.js new file mode 100644 index 000000000..f7cfaa015 --- /dev/null +++ b/apps/thering/app.js @@ -0,0 +1,224 @@ +const h = g.getHeight(); +const w = g.getWidth(); +// palette for 0-40% +const pal1 = new Uint16Array([g.theme.bg, g.toColor("#020"), g.toColor("#0f0"), g.toColor("#00f")]); +// palette for 50-100% +const pal2 = new Uint16Array([g.theme.bg, g.toColor("#0f0"), g.toColor("#020"), g.toColor("#00f")]); +const infoWidth = 50; +const infoHeight = 14; + +var drawingSteps = false; +//var fakeSteps = 0; + +var p0_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLLLzWEABLgbVgohEGopYaiofDBihWVHJpYYDgYPbKx1ACJhYZIwT4OcAZWYHyRYUIgQXQH4RqOThCXUYRpCHNyQVVQQTwVQiSZWIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p2_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette: pal1, + buffer : require("heatshrink").decompress(atob("AH4A/ADNUFE8FqtVq2q1AqkFIIrDAAOAFMEBFQYrE1WgKsYrGLL4qFFY2pqDWeFZdUVkAhCAQMKFYdVLDUVFQYMHlWq0oMJKyoOJlQrCLDBWDB5clB5xWOoARMCARYWKwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p4_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFY2loAqjFY1VqDWeFZdUVkAhEhQrDLDcVFQYMHlQrCBhBWVHJpYYDgYPbKx1ACJhYZIwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p7_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgWlKzVACJgrCqBWYawgAJcAOlNBhWMCZ8qFYJYUgoqBC6ECFYJqOAApWSS4jCNQQ5uSCqqCCeCqESFQKZUIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A==")) +}; + +var p10_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAOkQSdUFacK1WloCCSCaAAEFYKaQQSyEC0pvQirZTbomlIh6CYZAZFOQTBxDQhyCYOQhoPQS4bQHaBzaVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p20_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4AWgNVoAEGAERSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A=")) +}; + +var p30_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccFawkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p40_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccKFYkVFcwFDitVFccqFYkFFcuoFeNAFcWqFYkBFcugFYtQFUMCFYsAFcuAFYtUFcMKFY0VFcgHFitVFcMqFY0FFceoFY9AFcGqFY0BqtQFT8C1WgFeMAqtUFb8K1WAFY7cglQrIioriBI8FqtAFb2q1ArJbjzaBFZEBbj7aB0ALIFcLaHbkLaJFYbcd1QrKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjUBQR6EaiqCPQjVVQSATCqtUFSZvB1WACiSEUY4KCQQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p50_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjSCQQjSCQQjSCRAAIrB1AqTgorBoAUQQiyCSQgjdSbISCRQgZYSKwKCSQghYQKwSCSQghYQKwSCTAAMqFYOoCJsFFQNVFShYEwARMFQRWVLAiFMQIRWWLAosKFQZWXLAosIFQZWYLAzgFawZWbAAMKFgmq1IoEAANUFTQABFZtAFbgsFFYwqeWQorFVjZZJFYhVfcAwrCazoA/AHI")) +}; + +var p60_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAelNBqCLVxqEC0oRPQS6EC0oSQQSyECFYKEVQSIABFYI/QAAcFFYJDRCgSCmYYjdSCqqYCLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p70_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZAgoAggNVoAr/FbdUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) +}; + +var p80_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AcIdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) +}; + +var p90_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESquq1ArTgqESNgOqwArTIYKERH4KCUQigSBbKTdGCKKCVQiTCCFSyERCALBQQjAPBoArXDZ7ARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p100_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLFjzWEABLgbVgohEGoqyaiofDBihWVHJpYYDgYPbKxz5NLDJGCfBzgDKzA+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) +}; + +function setLargeFont() { + g.setFont('Vector', 48); +} + +function setSmallFont() { + //g.setFont('6x8',1); + g.setFont('Vector', 16); +} + +function getSteps() { + //return fakeSteps; + try { + return Bangle.getHealthStatus("day").steps; + } catch (e) { + if (WIDGETS.wpedom !== undefined) + return WIDGETS.wpedom.getSteps(); + else + return 0; + } +} + +function getGaugeImage(p) { + console.log("p="+p); + if (p < 2) return p0_img; + if (p >= 2 && p < 4) return p2_img; + if (p >= 4 && p < 7) return p4_img; + if (p >= 7 && p < 10) return p7_img; + if (p >= 10 && p < 20) return p10_img; + if (p >= 20 && p < 30) return p20_img; + if (p >= 30 && p < 40) return p30_img; + if (p >= 40 && p < 50) return p40_img; + if (p >= 50 && p < 60) return p50_img; + if (p >= 60 && p < 70) return p60_img; + if (p >= 70 && p < 80) return p70_img; + if (p >= 80 && p < 90) return p80_img; + if (p >= 90 && p < 100) return p90_img; + if (p >= 100) return p100_img; +} + +function draw() { + 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)); + console.log("steps="+ steps + " p_steps=" + p_steps); + + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(0, 0, w, h); + g.drawImage(getGaugeImage(p_steps), 0, 0); + setLargeFont(); + + g.setColor('#0f0'); + 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); + + drawSteps(); + g.drawString('Battery ' + E.getBattery() + '%', w/2, h/4); +} + +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(); +}); + +// for testing the segments +/* +function nextSteps() { + fakeSteps += 100; +} + +function prevSteps() { + fakeSteps -= 100; +} + +Bangle.setUI("clockupdown", btn=> { + if (btn<0) prevSteps(); + if (btn>0) nextSteps(); + draw(); +}); +*/ + +g.clear(); +Bangle.setUI("clock"); +Bangle.loadWidgets(); +/* + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ +for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} + +draw(); +setInterval(draw, 60000); diff --git a/apps/thering/app.png b/apps/thering/app.png new file mode 100644 index 0000000000000000000000000000000000000000..0c68d224683b5ff3d5e67563c806973a418b0e23 GIT binary patch literal 3305 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 literal 0 HcmV?d00001 diff --git a/apps/thering/calc_precentages.js b/apps/thering/calc_precentages.js new file mode 100644 index 000000000..b94815c2e --- /dev/null +++ b/apps/thering/calc_precentages.js @@ -0,0 +1,58 @@ +/* + +Used to calculate the x,y coordinates (so that we can manuall create +images) of the outer circumference of a rotating ring guage where +cx,cy is the centre of the screen r1 is the radius of the circle. p +is the % completion or % measure for the guage to take we need to +generate images at percentages 0,2,4,7,10,20....100 + + +the output is below + +p=0 x=88 y=4 +p=2 x=99 y=5 +p=4 x=109 y=7 +p=7 x=124 y=12 +p=10 x=137 y=20 +p=20 x=168 y=62 +p=30 x=168 y=114 +p=40 x=137 y=156 +p=50 x=88 y=172 +p=60 x=39 y=156 +p=70 x=8 y=114 +p=80 x=8 y=62 +p=90 x=39 y=20 + +*/ + +const h = g.getHeight(); +const w = g.getWidth(); + +function radians(a) { + return a*Math.PI/180; +} + +function calc() { + var i = 0; + var r1 = (w/2) - 4; + var startrot = 0 - 180; + var endrot = -360 - 180; + var cx = w/2; + var cy = h/2; + var p = 0; + + // calc coords for each percentage point + for (i = startrot; i > endrot; i -= 3.6) { + x = cx + r1 * Math.sin(radians(i)); + y = cy + r1 * Math.cos(radians(i)); + x = Math.round(x); + y = Math.round(y); + + if (p==2 || p==4 || p==7 || p % 10 == 0) + print('p=' + p + ' x=' + x + ' y=' + y); + p++; + } +} + +g.clear(); +calc(); diff --git a/apps/thering/metadata.json b/apps/thering/metadata.json new file mode 100644 index 000000000..bb82d4a27 --- /dev/null +++ b/apps/thering/metadata.json @@ -0,0 +1,14 @@ +{ "id": "thering", + "name": "The Ring", + "version":"0.01", + "description": "A proof of concept ring guage clock using images, acts as a tutorial piece for discussion", + "icon": "app.png", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "screenshots": [{"url":"screenshot.png"}], + "readme": "README.md", + "storage": [ + {"name":"thering.app.js","url":"app.js"}, + {"name":"thering.img","url":"app-icon.js","evaluate":true} + ], +} diff --git a/apps/thering/screenshot_thering1.png b/apps/thering/screenshot_thering1.png new file mode 100644 index 0000000000000000000000000000000000000000..bf7e6cebc0c8160a1dee247ccf534da2d978d850 GIT binary patch literal 3113 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 Dgx=Ia literal 0 HcmV?d00001 diff --git a/apps/thering/screenshot_thering2.jpg b/apps/thering/screenshot_thering2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..521a610171da359e9ae8e2c3f2816846d541a258 GIT binary patch literal 45141 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

PZ>rG*M~V* zC=?>g<|qzUT^}9eqm`cR-)I=G%D(J`n$g*O+P+6K*i1SmQxJoPJy1-=+C!XPq zXt}li9;HoaA#*YruFn<(?aZy;Gk-omgP;Tu?VX>u{|%i&05tz4)r&W<>4qON|T{S-l=El;BD@~G0;3Zdw%_I;xJ>C7skh{n8_ z1r$-3d%J?jPxjaGb$HYSfy%xHQ>HkGn6ze-HgDn`h}pCJ=JMyPk9(uQ2l2^x*)FNT z^A7CU%y;7fKhtN~z0ti&UTiI15>bra(5u6?V_VDzCEA3#^b#d>BSPB$lA!y*g9uU4 z@wD()0iq7>8$RVJgXqm#qdS}gc)T|aqDjqh=FXpNj2z{KQaA~9m)+coK$QAmy+r20C+G~`6dK8p$cTg#30zac>=!9*{mlU4^%FzH1GLUxT42Yhv+dMStgI@awnB8-Z5@|- z>ai1%5l&rW0ul=# z=U}w1>YAUs6lhCUs;as3+lo}t0`d&j)e1+ZskBSsRbBf_AXsgynhZw-Ps=Q+)d~8RH-A$ncazPIV650N=byGl>S7t ze)cA`)PbBe(Pl=#v$U(Er#qT;B`d0(G$4!f7EgY-rpeT^@a0v7GW|9eSgy*OJtAwt z7!PX@&dPGDpkBTkk3d7@^OZwHK(34kH?HHe?-Cc3^Dicom*#y9k6y%`mUIt4oxuCPn9;^520*>@VS z3-Sa~*vAWYZU^dgHbQ-`_3OdAt^D z8R>^Zw_ymMw3SY1)iX0Xe!T4&@uOJH&5T2DDh4Kag``Qsg#B4l&Qbjr@T@y#kR{T; zv6t?G8X9}m4nhH|H8w)6=kLEMh6qRQAH$}Rol%DJOn2|k;R?tHqpHiEmjn|;8x|iN zi5M>#!RVvAiP(R8<6jm|ka`f_dt=!?#40l``=kY~Nww$o{9aCu)P@5>p_eJKi|2J( zs;y>#3qL`Cy<(*&E%PVN_YWLQ@K?N9gEIod�e9j3!`F3^QxZK5jA}%d6?l5dX7% zweYRB%N|he3aI^AR9TsDj^hI5yQKeP>}IO|#J;Kch4qnW`E$@@oC6vrvO3=tHJYN|AsVjE7IbGaA7Jxv!3Zss+@P~ z)7f&^^K;M^DY*uZ!T(;G;>_Ox#1*d(g;J{Ik_wJiu0!pIQS(`RXU0Gt-$)?0iiItV3(8*)3$!9l$c_X0$$2WZk& z=wDzVHt-G>d7=#J9p%RkEn-@Cn+9yP2rv(MdY*J%P1N|ex;dypvypg$$ht$?EKw_t z08+x&vFgJqFiIujt6a7_5(`?wqMZKN@mQZc*Ik}t$Z;!fneSIwq8cwND8`8BZ%;}3 z*0UnB{CToBshd7S{%#go^P=p^L*xPc_SLJ<#&XoylSW#2*IR}7p%j^Y`m3sei0(KZ zhF_WYm&S)rU(QT1VZWOWV)ZZ5u33#-8M$ne5(1gyoZ z?6=%Wq;+j0bRgzb^>)v0K0mujd)xJ4xn4S8R;$_JA+5B|zs{!J9@N@nbc4AsCLVb& z;TdsgkrUQQ8l7}qS?BR-v*_;8wO6L9U&wES@H;SqJ5fh8fmf-!o)tV9;Zc^}{n}?t zxW3dY*KG*>3W;~%3Y4t`DXqDOWJgq<$MWzk$;;)a9mS$flYYz8GTE0xjX)?#Kfy=e zzie}DnJj4XQF^CB{u|wKre)nbKrLv;QNc>mu?zL+y~;M}b$Q{AJJ~oYf?Pg9dsH2@ zvUW=U2N7+*4O!*}KpOFrya_!5vSCa(!(V*E(mAS^{Eq=*qhG&J5{fzh*Bb6ORhNA-cm%ZaaA zO$l@VN+$BTmRPmc1E^>w*t*cbl0O-*kp0r@y$np_^*rQJaH>+of-J13q4Tf}K zbB~?G`DBg!l(L2&Q5YYegps$$A$)%ezH-FuUiJd@KVKSm4QQsE+^YT7TnTxZbwl^t zJf|Mj((CgE%-e>LQ*FT2tlA@5@g+qt^wVUg%!6dk zcw#d0>-vw4+@6Pq!WF&2H4lxvG)xnZNa>GQ{8P_@G3x_l@zMY2o6xIF%jZWg|HWV! zNhMJG+ARFZl8AowjF#67XuEKQj0FBMwKr0^x<)Y@u4;8^D#Sk&J!rV^Jv1dZcAC0S z-ytlc;KQ^O0OD4+M*(~AT9CTtxB|X6(MYn;Jw49cOd!*6vHiI`BL62^#&J~U;nYOZ z0-R+RKJKFVbB7^WU`gQSEb%koF?}iTjmKo8iHWsp`79MoQEXChO9*#H6%f3!WDryb z5A+<_4A;3e0!Xdz z>cUmEClN~q@wRKv2{(c9SO0n_-xZ-TKIQq7T8+iq`6rq{Fv1fF#6Wi(EzkNlg5TKU z5jCxiXRY^el&&|KiRY)FbDtyFe&q&_f^eac-KQ6*&w%|}#LjF1qB`vCIzKUax$wG3 zQOj^g99Hj+;gzg%cT$1$&QjmlN<*-39qz_FtA^d*pxwIPPbT_}C0oYPmv6p_1*t~S zCG5o4H4|X`EjqnmMueL*@6adv0iwb0BkNieD3|)K1PUkz;*K2Uc5PB0Th5qip^0F% zDu5)o$1H+M5Cxg1?oyb{X_TTlyZ%*YwMe@fofWIeSYG3`pw4=Hd~#f6Kzbcp*cSC? zN5~>JJ@Mjd&;B0%Z)dG8QL}C~S;}_E1>XQBn6pRQ*zHtlyq(X3*V2S~$#-s-a7{L1 z4TQ4hB|tr51EUSXbHsC`@#4-IY41Crl~Yan$sW5fNs~e%+T4@Sxf|JfZQ4WXPumM7 ztQz#&>(i;e&uO5=KsnVr;EB?}#f3I#@wZe#7D55u!U-kbzM>w3ZUc_XM(wu-SGar? zYkkjOf@Z&eED3?i&wgJaf_Hcw@fOB*KB5ZZvKPD=ll1etSTnY)j=w}&;q0iA&Btqx zEFS3|OX;thp{ygY}8D(mT4YG=F3 zxdT}ZE-ruhCp7o7_X5Z2nb7FHI^+TkD3s4Eyw31a)OEgV7S?242&v#c6@*12M%PnT zCruM)6ipir2vLXgt5{%)fCPrvqZbxtH<~u_A9}y_Q1^|m_IYKMeYhlob^7gsU~6?- z$+zKpuVSv!uc3kn3}LQDd0ONs7{Nlgr|Xr{CPs7A$V>RUnt0S-4?&6-)Yh!AGgUGl zQzJuHwP%!p}k%Qrvctv3)P@~`i_eQc#O z?T$^Dk5*fwrdqMbTJ4DFbjyqdA@04y{VQvj00>7o%tS2CoyAscI1~`53LNy1RZ>Ef zbrKIj?cA}~0mtFOy!sEcER&o-)QX%W7zE7_&H^ZMjQu$)K_7|{^*U%Fj^!72{jEao zvr++~M}ZH?O0YdT02S~K>=@h@NZX8~68WP4@*z6JfT^VDy^7P{qC7l#l|^TR+<5Z1 z$+8I8^Q_4iVeU=dBIDT${kx0q&_GKVoF6xY;9!qO{qMQmfY>oH3(S&oHBq+oWcz7y z^Q%!6r%|K`e9__P1Xsda==oy$KZ4D{M0&%~Ao4ZyAZ!Pm-;Cc+9>1}cpR${j3$a#LVmnFsMzfuOYJx<5l9Gf703%SCQ z(keESvCCfen$xwtDbc3O=#=I*##jEFM0SF7DP@xaVT0&e>rXjfVH^yb<GW{27i;I3@)3xdsUll3mrhBQGgDF~ z-bE)?oWxeKX1|)i3_AT>*s6?WQJgTNM|gk%xp_UVR9lq-rT5Slg(jMA=U7X%3?)S~ zDYf`@a8V-SOc}zNXs&;f(!_zdWyjKIUa&D_@(Y3uJMMYS(lO;C>V&D5Iuphi(kLZ4gKj5?%E720zhiK#YdJpv3Q9z}}Ocy%HvcRRbk z)|n7*E1Ch5Lwy=RJwGmH8M#AG*;D6`SMf{GN1S*L`HJ-}zv=mvDE0lhc;ID$$VT5o zUGiPrpxSc#L}!1}M_jiS*nq^bEVxB;wY#^ABrW0O9ia4(g>JO+0U&|<+JtH$v9Q2S z)2|eqnWTWI~E!q9pO z;zzG;R&P=q7iH$S;c9aAidC4DyEE^Z`0&WNSJJw|Y@toPlq60{q9F4&N0(_AKP3;C z)x=O2Q)`DRE!iB*evUh4pCSUZb?r8>q=>B=y&oNIjkL_y}U<=ZN z=`M)K>^Y#QbZmv}yv9+qH%OHKfiS7D4c5r%kMnhmUUiZ9eE{1ls5|4`V2S0`pgj z=L7$J-rigdWFju>Xr7`5Bhec}>qmLBUN`bkImWGt6s>rIq}j^@nwu#a=My zMrZSMT5VQ?|K`OXy z%x;+tNo;ZotNui_8I5@HLxe(43k?%8(!TN{? zKafv^GUH%MbB_TZc)~i_$a@-mK6;6$Fr?pG<;7;q(FGCvAmV^Rl#1;j1BPbpt9?<5 z=56=JCi^sYZ+S1P^&+tTDSmnfzC03DmP1zCE_KAwb?b$^1G(V1b2)gEIgDiz3nnx% z8S-^a*79E)C^V05_vdruwNb^w-Ax?^+o7}eZgOen&@CThLA9||M{~BqhXIXAuj`>R zbW@H?@aRNbxF9U65UVESEF55^GbWFRI7yiC;-UebN(aB;Ad}PxxRc9%XBQ>X0n?Wb z)-hfW#-a@&ix`od=?0oG%d0{Z`KYAEHx&Oevb}sWOz4cLSLODFOWM72BFMN*WuAcM z0Qusdw1fW~HPcJ8zs*gJKdz#m~mXrln?;O7Zw_KE%AX^dz%z$0+ z+ZUCcTrxMkteOVw(39nucz6>!mzEK_0*Ad#Ib*}L90Vs|uPfNRO($AeFmQNMf&0_6>vL4@w zwySS(O@?ka?jo`%Nm8|VP77qkYg+p51Tl^+D??=A7ROs>%vc4^OY76wOq9UQ6=61a zf1f0>w!P$t#UpDO#zoHEWX>2SFe3Yc6`VmvnOX=sqOZGO;EOdVLLe@cZB$amV5^sW z5S#6*9OE@{A~R!iZ%W>Q({|{P+V&`D9*ui0!f#gUUcP%v6ZzbD-T~5~f41groyrCR zm6J1ED*X&eG+*Uy7W~X`7|m1`! z#0roVCtWqUX@3z_?=Kxy?UdQaA} z%ptY%tZ}|w$GcLymQo)2M{HQlClj4C+jHZ!N6AdrIh(&oLQ+GGi+_Js5nNsFDdeME zrgN7?7ts)3opS_|IUP5cmk)8qE59l#nCzU*XGt{5(R~WnhB+@`0);YsF`)y+e{!ty zRV`BG-k7C|BocwV=Yw@9%WeM&mFM*KWyisM)Qg6-IAcS3=!$)t9sl7(+=1_&0pnJK zU%eRIH9CGwDT^Fm9g9|zA4wbTGCo}y3Hb*uw;cH93q9pakhUXYc1#W27d+;3Ac;|U)CD&o(MK3ftIc^#% zWsai$`*ZL0G1qPNPJ)MQ<_%cJI+XU3onkJBQg^QYRE*i|nh&m(39$)unuAkq%j!1b4F^aOArEyz`Fj=cddeZz57vy#f$C{D%!8O4i@xHkf$~fUe-5vtFj5li}M2IV-J8+ zPPVB__84K6mB@w$lp3MbKmFBzWQh*I`T1~1;A&2dc?o_yboJ1+D~Uv;Gm&!83p&A1 z!lL;%(eGzE-G!Pz85nLh{HH0yV|4$>#753yPpgf%dMVa=QRi_(@TNu_TT3d*!t- zwhxh!K_wkz*YsQyRpH#zili2|E10>RL2I2Mg65j;&FdN2-?fU2!_4 znOv8wYcq^8{PwY_l8LW;EyYC->WJ95GxpeDga1Tr zCZxggZyxuLq1C_Wu0lg{6MS-UQZmMprw}oY#QJvtmr*WJXodrcIia!U(QqX3=5<(` zS$6&{BIQeLzvbWGbaV?|LdHGc5eG+J38iQ00kx-^MVXyK;vfmvVv1UUiI*{e6m@~VRs!IWEFy=@t9 zlskco4Ihi?9}+t8ygSCX_eg z#Z#;5BlskX^k18}l&X2U%89(m?16V1uuQkI91m|Ta~U+}D|@wl7=LlNB#|x2^0Syr zLet-!{%-x5PJM(R5VYiN6_14sAaV1~C3pgVh9%CUE}z^U-+>_m@}G|raJvD{{SW#Z zhSJ~Ofl@nftdRYeutEE^zP$zyns0Q$JF`SC{uBY-(G4-~SqK=_Bli-}MT0WRO0=j1 zQ5M)1i>U@f`hE-M`Au71F! z?+GyQeogqPn&b4wo6yZ{$uxXuQN_uRUr}vZSz0IY{AI4}!j2*oa%pr-guK^*-m zh~1UXbiw)BoZW+Sj10&4`0uhr5e646^eUcCqc>W}n%UJxPtE`)A(gi*rsgV>4g1WA zuB2Z)W@x2Car5Md>4(hg#>e8a`kxv^v12eXEfD9;J0}xl>N0JR|AOcLl;64fRiK`e zJhnfw*YBQZoN4dIkg{K;iRW$|{%f<)WF2NSy7Vgw?Lh&P;aCO+4xIgp`NyMcMcX1x z9f7&4!-o|+nXFz~0YmNG?i+)~brV^E$c4D2^9&y<{JEEd^mF@PVJxrg!5sPFC1>uo z+idN{F{4k-yJQ3wbt?}i&K(bLdPR7Cd&a|Z4-@y)c0Yt^6p83`G(%?VDIjqZ<*M}c zyB}u5n?uIM`k7^&EuH259{`0wdcW)K4u8%K&l-5s<@=A^ZyE8PA@c$AC&qYfuOZ;S zqhKKa07t{cp^W8u78etZsPym_xpknEztJ@;yx9q|D-g<5m8y{dxj8d)q*zAKP$G<2 z)Lt5CW)9qH{6LCj z3Q(myxf;Wz!Tj6ciXLeBh~*9Q6D2+$dT%-;%^2_`C}O+AWfD0iUTP?RoNoo-A5;K9z56MkA=o2LGer% z*@?rlm$O2kkfIbeMoMCCZ*d9Fo-YVN;!h~HbB|JvpAhFU9JLr>4AA5AA(&?|q!}mr zYb388P6a_6F~xPN)la8T^pC^-AgS1Ir9D8dR?11th5!>voQnYL7z;+9!5%n#N5j*F zoafpYN)tt+z;qbWX~RYz-5mprDob zs-+O%i;aBk7It4`icml1@om4O#tL3R^JU6X2e4$N;=V_6IqJ%l=Y~i#TwuXFwWd^P zp2yIFKbkrva)!@UHy-7M6;mG`_6c^%h&?e7%B`omYv zTBnQ6=4sK!Np;o{6-!nw$V_<1)K4svW2$`+VU9}a3{PX|s4CVZkPoL<2!G}Qm^J3y zduV(}qMuMX7QcS9=L;LTIsPIS{C`Qyf$x2n`({76m(XVnpfKt^wu1%-qn0Rmw@>af z2x3P604$<$n~ga7XIMvd*t9>M7F7O^eZlM&;6x4o z0D_1?W?%ttY|Ef`uWP+%53YVgf}aY_|$`*=P%e;`!Bf-{L`&X1GCc8x>Uco&dh_6Z)HKnei)xyvmn z$9rcLW+{otfEX5jpWn1;WF?rfatC00dM93nlzTe^XYu(5dOv}X2x9|EK?Iw>4LL?E z>^Hr2*Z7b@_qAVJI?+D#e}nvNd`DqB;!Kb%DVYP#3zDRg+XMgs*1scX-@Onx^jl(gp!UATq1i>lE zjzr(}761a#ulh&nha2uY5TJq;cd+^Z>tkN~Xale3e-mmF_G)YWL*569He$Wb)R024 zVnyzB$9vJkK^J%06}*qz-!cb-Wh;u3R~8X1`FX|e$sB#w_6=JjOhu%%pCGO;NXm?(AzSwCt!P4C7D~%Aa!6vXqEo}Vm3^I zQr7G4EfNF^hvv{`ywb-yNef9E#K|%;p06B{>6S!c>=k4ztP~K#?a@2LEcqI7^qQ*VH}eZN$jUcODP?9??8eH zAgcOahkOstH3_~MgjM#{wd9s+)sF36J<|s?OiES_6vSGt92#;IKCwMNO#E9n81kNB zlnvR&QHoYoF_%ixS#;jJ0)gwf4i!OU1eapV^7P68NPVJdP{b4X_KlfE#}>Wl?+L$| zBnOOn8YNI7-8C!-VIhv~Q{S&p70%<+A7Fy&8`u?>{7-qsnPJbDQX&U%Q7YS&nS`pi z$%qU?1p-L+0-r>Z2wjj*@<-$1qSOsEK6MQj0I(Z?i-P?Zqpx%3{{WCJg<@O9x%Pol zS*tho2=hFBsw*1hR7T1rSyFIoNg;_{WMG9eaW2G+ijTLv90m>9j$^`7SkhTz5@^8rdtY-mZ2i_GK^F}a)%wU^ z9Gijh9#2YykmKaZWGf4jQ(eu)7=&{C{Je~)c;QglkcMJy02yPYa{ zX&DRtN6(B-48n-G6rx>)ZUvV5ETMjyBI6|rgKS7tiBU?QXW09}09Z>fv$p5{q7PPM z#i-vjv?tbSkoo(tG|`wobi%V zhalZmxo!7r+aZ1NF8rsE2JSx*98jfbA{L|QNpR$S7E%cvQA9wZs;+@z!PpIb2_Y;f z?OXBXQ(*Z5MIJGHB3LR?%e_duGn(g5&l4Ii9B^ERkok@ihvIuBjJ36{*B&OC8jt{5 zYZ9uoOV%U}r4lG+>YbN+1fM_X%2L>!l&F9+BCKo3dPV;L6vrn4gPVvc+u2FkNPoFN zP&l=7^tiFxo&xzm@zYe|UPR>-EOLof8*|>wXRl&qb7DB)`eGbxkX5HxOB+uZn3ssn zDVk{_0V3olc)yFSYE-!@Ot3%Hk^reYR3L$1Ex$PN%typu72+n%orA*^;nM0!`%9+9 zEmAiUNd%9yULxnsAIkPG#Pn(N&Iys9C&9A$7^;fbBuh5%(_ey1RN53Ua^#;e|yDjP0lSaQSJ(`8yks=e+kfHV1>@teDv=%M>;;D_ntOwV5N8YF1Yw zCUlMGEwxlpBr>slPsFF;(i4V3TFD@}X3C_}+{01n7d{~Pixq-b`!)(un>>S5ki+c? z0BwSjt2k!>oT5m{^0)H6Bj?JU&}iqb=N31FVPs_mnd zK-mZ5qmzh4$wFdO6p}WdFilvwrv35i{u$zUe-XjS#$nV7Cd&l5s!m|$2+-Rni}m?; z{VV(p#=KjC^54!skmBQY`8GDB@bTN6j;{#AarelEnu_E(9m(p+XDKu<6lRi@q?7*u zY8JdFjzAUTW&%XCmImR7H0C_{X9S;%QcldXwm@@Gz~!Hyp=jQD{{Zxh@SiyGMpMim zC4NVI>tZo?F4yC)$#Hzsit^a;AhqgvE>%!{TxM}26R=#3td2Hokwr>jiH=DwS0s#a z+Sr^K%?Z@xOP@ig(kl#n@P71=DRP?<&iBjua}gW#ulX(USIy5Z^6wk-3>>1oTrUmB z@8c%pnN-5wt#19?txJ{di!|=RCvgNN;hwM5f?DB~!kJ@o<1vR05KzRZZ4CEc(X+iG zbMcB2wu9|G_Oh!7Z%DOUf29ZMnO5}Ft$D*ai^$NC;Jb{m<~|6vYswD3mD<)Y>t?)> zv&O*m+aq@d>iHLrz+-{tmhu577E9Z_&+DDW`Y#yirUPR!81hx zRC!}$E@Zue#NubIrphwII3>z+2ksyPO97b&Cyfac=PZP&M&Mn`WpjR9T7oEmIqZ8K zMx}#D7?4RlLV>gFjSt3%ADx{IRV36GZAay!O(nzk$}K1K-sSb=zvLerUUM`#jAd-i zN|Lj6oItiHUr3^42nW%gyppQ6`jX#BC^CF`$HrJ)l}W`QHpyB|T7j&?Ck^*pR2cF9 z0GQZQDsB@Rl$S{xN)AOCuEE?3W@}2C$@#V7aB!|~%ecs`En1kqRhxpnY2h$S9Urdp zQ4Am3AgeuRhE>|j5spM92>9`TnbU;t1;8k^uK9|FA+n`hn@6O4GmHNKZ1B81*K_p1 zHZ}lU685dR-X@Rfr4r5J&nSe`B612c#1SJav5Ay++3e00(T8GUJ78y{sxFBbOBI3l0E!ZD7mRM)6ezN zE+s;OuEM8Yw~K52A?jYre9&@l*+0;^jqzV0$_Ye|9)(=T9ts^+NSavQNuY>;B?_(# zut^z^#h-~mBXM&_ww!H9vV~ZSidR%6mj~md7BmFFAaFN5yjxK z4jM|c@(SfEEHq}Pe;Lv{P|XC51nGWR#PAdh%(2Wvp$r^&P}3M)oz2J;BZYYwmLX1x z1^|LJb|c@Wan4s8k~ul{IFdU507=R*+XZgjqAeL7z$dQB00m-$uC?*dC-{!-NXt=m z9-McWo>|Q=0h#78Fir!Q4k2#J#N(!Joe1o&^v|_q_T`tcIu1nt03p+@A~8bQlEP^e z^&}pkF(-b(2eBZYz>m&|{(Y0H(u1TO2yP`&6}HLLupi#+yLox?nOeQewvys8NF-}f zc6I_e;r+WKofPh*D>*`1GQ;lfJ0be-?|{Z-^#r%1Cw@ zmj3`8{{VM77=1bI=_ln`7^Y=tsZ0B6=lg%zg;iNWDxeZszNcbYw#c66z8rKJ-R6q4?fP)Magq2@Cp#Jh{*j}-X>&HR<4 zrTgo2R(O*$$?}rTC2DahfJFB#mo{w(<6#wbGs?wObqGeWd`lOEz{;2unSW70ge8(x zr=#RYZD@h_&ScxMEVkd%_ECWVc`H)kNREftqjl=8L5z7DQ`Hy##ekxmk} zM%;Mmn#(G(nh{L3UZOr)S^0wD6 zN_){`+09t3*{4=2_N_+0THIBt#WS+iu0A7=8xv)bLR0}3u)RAw=+-V(=Vum%Z9B7>9lt&aI2$)42Xv-(kAbo&@R_P&T z9yBR(r8BGTOXk)bX}~pIqKwc?gd6YAIvTxck-r#xypQ@s{IB^l$eh!b^A9%js$A!t z^1Q}sY<43*!Ex|bx0kfnAfsOkk-_A06B^OW4Ruzy&t)Qw)gkU<3Qi?*fB^u94oU`0 zIWvYd%Xo_Dn=uRmRYs__HyzquC~N1(jqXIO z*$zFN$F!DH7n-KZ)4;LXwOc8UXl_-VEJu;X<9bXUCQczAVp5d?LX)xq1Z%`pF)z5% zHE`IHvXrPYsY^etb2a6qeHlux z=kFo_%eLl4+H)x2gRo!1aq4q09`qEv!$h{p4yAg4&GXXo z;;$nfoRGn@cQD2L*LO@Gm7^}*`UuVZ1B%m^1Ey1Vm(r9_s}ub%HX zmA@>%F?^5Zv&@n6o;)U`L5 z&XEEC08lR(ahm@CE`A{LeI=f~iE3KoI6Q0;wHg?%GSEwYl?TAV3fHRGxgq_uQpGs~ zf44D77>Uy(2%u(f*);EPi!%V(R@PPKICP2;;?W=eM5LsYCmWMhQo(yScwe)tY=8+e z4Fw*+LOmhhL+taX5AEYEWCBak&a|z!@rmD^2z+~bNdqTN0h(xvw@_qUOwt8EP7+cw zLF~){D#aZ2B!Z*)4t|COw#4Q#%i1VkH!8_71a{eAq_cv0{k?%B(fkAK4@?YWjX$M8^3+JGYW7=sKj!7i|=fgom>1x7j)Q3<>3CWa29I>D*b8^Eo z8NU*EvG9)#orp+zj8KPm3Q!^6EtdxEtpSTa^6q<=c$bM|_)mhoeUix7nwwVstB%99 z+Bn+D7t?78td4Bt$(L{&1!GnY#b!h+@#j)htY#q0#!T9EIdilK6(A(AdQb-0u#XeL zE>DZ&%>Muv#e{;QrkJ9kRv=XD>q`dF%vBeVI5(J($Rl(*G-d3wFfyqdf)qif$ zA(3jR`eig&vj7b|2*ZY&wF0t6Pg8f)*z>$c;Y=TbU`lbA%tX1EsfuuwC@Wy8h&2EL zDu3-NVB_sETZ>0$f%zARSml`8*l~vBymu{;tCFW?3o%irl&NxATBL~_?yUq)$g9*k zpS9OzhW^r4f>Ti6-F0f-J!=m#Rw7>9g{5-Je$^z=&5bjw`qalnf2(f-=iYGe-+{ST ziMYmh$ygc|Y-B9W!m*cm9LrNLfv+||}4+!&`<6m0};dF~*Zdv&yjd`T{vCODkg5F%xC%IU!9!dN9y_ zB6z9dazaB8GjR33LrAW_mx})YGJZq(tn>Xplix34xIZJ$a&BXso_qO;FpzStF&{F$ zVi~Ez_$<738kg?kv(`%WEX7{bvBX{}?m_XYC7~!mT1NL54qWdCP4Q-2rjmj{HMzJP z3Ddj7HRRt3eCkQ(+Y$5rA>|wXW4Fq2!~IniOohtR=APUi(sFoySBgP_j*J#eGE}*b zyB#_oOocVgcSIb+hY3*tS=_TeL9cd!%v76z1sTppx2#_m>Y#2_{W*9RE6Voh-SVYe zkBy?1?n-L*GM2eD8Zt$lvqILD=DlW*^$9IJAT`Jhwy=OCr7CzySNmyaDRK=Pn9;egMvkaNg8M<^;C$?U+dUaH>6(D&>pAwl~{{FDCxA$~g|91zdDg?C3l zh5e-FY&Y9Z5ih<+!#B)73P1|CT*@~46VPFsuhn}|`Kcm)u1_4pku-7!^b*WU1ZyMx6V@~( z0ahfmjDeW5e7*A!5#X3ZXPGjMmd(Mr8GF0~<(djSIHcJu!0#c3`UB?@hxC+%kIToE z!zmzh>CAE#XOywyIIvf)-4KuzgVjE%?dYm0Ujm#G0MuIfpV953)&fbbghu}Wn=Kp< zl_QX;WwTYIK&RQ3{eJ8TIxbZ7KbF~*7wsipl9Eca2R>c4uwVe7irVoPMVBnD@6+~7 z#Cz;j$@*hn$pMG*r?W5w^#GU<#ElC=i8J!k;S3+l7nZX=KF;N`n5iV=`7FjR_9~PY zrTy+ORh1&MTHI?KwdSbP#uQtnF|=!>R$fLGtk#)bu0DmJ(zd9@pNBGa=cfqmf8`FY zKA+1^hw?WszTxqf4}e_cHW};Xl;F}_Nz2M!OV#TcEmJRR=+7XG$jq%GL=p4;p$lV~ zNGEp&^oxZg2Rhq!v0dM+4<5N!#T*Yl_u&1c_ioawiLDb!TA+MeJIvCpmX6G<@J$Ji z_LW+>kLj=^ec3oN4BNG{4{+^T+yVzyiE`g-TaGDoUkxqvIS#yJwh~) z#u0U|&vqS8Whxn?Q`iORC6`Y+bP6}pKt&Y%v66XfuoiWYW0foLU~ygtP#~f+Mj(rANB-#VY9YScA)I& zX@<0~;A#bke3<@yVMMO^Wg%yY%l$R}uAaywcj(F(Y`6H6zq|6mi6jzF*MA|xkAvgM zcKYce^!rcZxifE!9~T8uAARc8dQtr1PkBbYp`3=(#@|J%L0&mZu#QKKrfCrv06x`l zy9&jWDQ=_l^em+?PJ{y7Ys2*z_z9n3Npfl$$1}Q=p%xsNw~PF%obewkkCosmsw zcPJP#k=T-o!Udl@Kj+|7cGBsKw?QDlV=2w z^r_I0@u%UR2H|`%c*IDUy|7)jj>$Tav_Wm)z$sAx{z|O4H;& zs4R~h_9U>&GQ(%7V$u*=GZFRG)k?!LxCsHmpE~!;hbShBLro!lhPi{+5u)CVA`soETL0CY@dpQ zzy!4tCN97CFv`F%7Rjz&wT$8N_X^>$Gc~390tZ)XhKR%EA0}kHt;=NP*;+L5x2K^_ zgV)Ej#woRsP!SVerOGu`H+*fkrjrUGJ9d?oV&w9uhn& z2%IWr8KEWim3|q}WE`-xPk)uq)l1HwF5Gh+z;d)PUQys!8jC{#isY8mi8vo&?0C9`T#u39UM0uo)^24~^9^WH63u8$Gv48+iPRMHQti>QZ{PsoPmA+oxtC(OR!6GEEb@5}=J~DIsYoHa++GtZ01}K}8sY zy!v@(oL>I`3;lU=)VS_CzdG&f#b?&`0p!|6NF*ejT9g^FQ=K(bT* zv0*!`vOzj0(}-rP!(Cs@F|J1MrT80+>lur{l4wIcfI6M@rlKnA=L6@D%D*`LryZ8& ztxF5Wxb$+x#yEZ(>b5f)(-t!1EX_N#*D|(ZWQN6$>_haShB)gZ#_~(2g2JN?Qa}Wj zB!OFBb9z0Z#GE1}5Lgl__0P*Y{$d@)Aa)~NKm*zC2A9_MOMV9Wk^n8}o#>riw@G`q zt()F0#fE;K9C`0~hW2%9!!%ePF?HTadYLNAa#(A{G+$9nn`p&|iHNHLP&e4buMhFG z^o$xM1u@%=Zg9x@e%#U|8nyrMhHbSazagBvJa3zVjUJHKV_z!vSX@$;PHmB<0e6b0XVP{*Ys_>O+D8GdXP;>3APNK+%vMn*dX zAUA5R$OW~as$I4~W$nJbg3~D_LFx{f0j{6hM1{lKIIb@YpqkcMm@2pI58TDK_DiiY zg-}2~)q@arSM3@AOQ2BE$Ls_rqS<-BD^H;N3 zV=Bg2riIc-zL(ldBZfUfk@k<7V2l53ZevG65=}C5BxizfYDZF2InBcD9{o1~9be06@9wArj zGsZ1pyaVIAc|6-$%Sp)Z3Gr`EI`2{ph9-MayegL%eG1dW(H_vvA(7G@!4#4YjNA=o z1En~*2fM|o;1n0!End5$mX0){Pa~_bA(sz!C0%{wtgyF#M_p5>Bo#X#7A!~urk88I zeT8EpV5^H8KJNOwOaA~eN@{qAIWi)%F95i#TW&(wi|Mk+s(Y~O)WrQ;qd4`{F!-@8 zH3WfD8$94eDR(E4A-v*KOy4SyyQ_lAGWUqtzU0seJNm#B!8+FFsTbf z58W1sW_D#w1Mdk|%?YIk4H#*=gmN<0B+Ob!YL>~3+wrV0wwtLPHcGJ#rW*I`vHt*Z z?42KH*-&@!WdvI8+$iQW(ygHV`@tg4R4S>GLRbJcPL9Cz0N3P$t&)WMKA6E|2P_)E zWP7|j0gxV0tjX|hbBcU5T$c{y_}e^`AN1rF`1V$?#3uXKnRvcVvz0yQD7(2|l15X&SMW0DDBc8XZ0Mn;NQ*rbuk8})Q} z%8<(HtgNIk1dv3cn~H0oF)*O2f(zD#)MY*{(EeINZz)f0|HWR z#jF8;EaAap-?JDQBt;B65XX8WNANxN2hbgTgXn%wtr7zh+bzBKx386>XHN^7%EHp) zF&R7YtGY`)JbkNCsYFL)X)DDdDO8#w-IxRuMq6FiXpk;I;{sCB58OZ|uvQv528rc0 zEPmc6Xyuf{A%!Mhot583QNHv#W*vT_Z`%#bOiDlix#P~6`b2)JC^m&(%e#LV>DY<_#)838i{Mv6$j)hJ{P zz0{G_)Q|*-NZK$u-(aWw$T(0na2sCph6_rG0E4Y_(~Nl>A!T5?&?IZnKD0-#dr`CZ z4f_C*uWD4R0iLw5+$(65ZeglQjYywzpZxSSy%Dk5NFT^yu%war0GH~p{z8{GKK@Y^ z76j6o@r#f7DC0l;W8m&_Sd~B!LajBU%;NWau{+8Nw2d4#O!jYyb~_tD*g~@$#JSwS}F@>T}Nd-Gp^W3?DO| z;pctv8oq59j9-((_U`i0&=1@)t?1)Wtf7HGtrLapI(>k}!u)@6G+glfMX3Ig+&hAEFPn_Q^Zqr* zIW`juz;E(j>70`nUoT8qqnW_R47BUnf>m6Kn<3z3DC`ng(V5v}Y@A|>Q$k#gNY8h7 zi_$=6&-?sStaZWU1@Y~U8_THWa&zD~w=UxOJZzUM*LbhtX;-H7ugOyzDt_iV(bToG z9CYKchn}=@))Bj}T;vv7NpnyQawK0?zbZl23PIN?@=s8wG@IK6Lp~-H)OsWR#{=;>VwX%6fdp2zMe7n3@!p-`L4o1)f zCo*LI-jb zw7}>(v1qnx4+9s&r@&*M(r`o+#y< za>DXHHNoK5o!; zQQRGOb>|Eh&v(mbjywpyF}LGonJ97$MVi@mxykEhr^wu;^reF@9T!xyS#6_ONoK~q z-ah{TMzE(mQac+*Ly&W4=}xh3MCGj4BEUa)hjLP6(r4Ca&ODFwG#flL&HpKN?DTl9yu{~KU!;_MD=A|H(2q&2heBojO zixLP9PIuxcKt zR=W-hEi2roVG@<~nreZ*nYlzcoMXw^w71$tCD~EP z*ShJ>2&pPjNpcGfpx`;q$I+gk(jyc;7&j&i(DA&##LzsIO? z>hk7mHyp#>ids;AOAS^#7idz*GRrI5vtbpQXW3+u?DW#&$M7JMP*F0qpcge`e4V&w zxW!$YL0J0VreggWf-x!vza%!s*n0!s#)rG0kb-nRRQ$#GbNpAtbDl=!xQ;7_hQ!Aw za;o0?0I;i%Sy%U$9g47xVTHQ}{{ZeZNuo&A9DX!maOznjX^0gLNwqc5QSTUjH;+$; z;Ai4WnUF$qB}4!KdpV^N(xXUE@G6-4N}S30XG1-1(afx{KY!SjK`>dr`l@`rg9=3lnr&!8`rl7LqSV# zUi{zZ;0f^03=L_@NE9>)1IouHt4FzDRD^~A3RpcHmtm(~Q9S!WkUO&>pHc_)8#2`5mKpIUE9=>f zN6o4+!ud?73-ns5i8ecsnJR#H>FuN}su|f>g)O}S?ubEphS&84Vp^AW<#?_y3^`kQ zhBF@j0JZ4x`qYZjsb<*gv$fFyPP>fP9)%1L*j7TkBlkwp-0#B=OL#D0vFWx4Z@ zn`pmh6VUO-O8d=X877LDgE4`QD~$>SNg=N_m|?Zqlt%@r0`_S-OO1{oBBysfJ^99j zhbdq@_nK*uG1YfG<6NhgMda*EzqP>f8yrsdCyi%+rpJFDQoeSb+;Pgs0^AlpwF?lL z9tNHn{);MFF*_i9$w%)GS0eke=@zC6JGH>3XYkPhe_IEEVS`?nYe$n?O0gZbV5;F-t(&Pas>E&9Xs0T-kIm#|brAwFN)7h^N z@6FamI6O<00rs+DDN;}rvN@8__Ps-f9fxBvexxW0y@*q8N&B}^xR)P@t_U_S6p3j& z&cqU%APw)R{CnTzru~7Tv9J^`p{pv~lkWro>=UkB5BCzM!jT8#x1=l!HMh_wuU@hJ zqhsIPSnosdLH_`7KF0YDpZ?y(Dd;gI0h=>j?VjhY;)W~yd)6Jg_ov6&hIl3V62g9} zN~d}!_&vKRRt1ECfmTw%f!>e1Y=&l_;}}?(X_^XGp{W%b`a`FX6}hh(HXurmo31OB z2wXbJvXaC|=!%l6o}xn0hGZ)JQ-2W&WjMA&$lpun7|16JH$9iGiU&OZ0FME!o!NP7 zN|G3zT^u=AQVQvmov8<1db2QMK_f@-8i0a_(senlKqrWcz_+2m*v~R458`7wr{T3Sz|i{@Rk)083RwQk^x_cmv<9caujM>NdB7|HCZ0A_Ea8QPAC^v3=5 z>;W=uofqc9sDih-E`kK;mJhz7h19%nAFmXy0Q@$}&vELS+@m`rA04~FF2gBOa< zg~TZqBa5UvCSG#7^;CT4YIb zfUTMWMF|CFgaX;nGYgX*E8~7EjQF3$Q{ng!P8kz6K^sX5*elyz?b@7w zUGCo%*Wx+9zmog4(xiv#f{OnD-1MhFgSBE=e&M3Nh%yuLDZjw?a6}-dQ`(K^7cKfO zEKl>7nxSg#jCCBJjPmrZ&0VX)?E__a`>lCJg^2Fnfm^`&9{K>k4g0F%GtMG9d?$@q$QxuU{;;dZkESXRC7iBsXv?eS|( z*Ilj=w%*u{E`ptb)peo2Udi9&eVy_gAN;XBL=U?ZNiOel8kG!dR(dv+abW$lprej` zjxgd|mq2wriS#s3Y&P}RY!n42?jW7$=x<*h;tPSP0JLPSJ5|p&&sU?EHG|CE!(B_& zBs&CsSX*C4cz-527w!k{A%g%J7=}}`@Km5FBJW#X{0*Z!5g;r&Uuo#U@+GLuGO24? z@a)>f;yJZd%FvxD?`tq55e-aesibRdQjA!9#RXNVF5C{U9DxNDg^&gYEjYMX~y z4nkbelE-}qrJ=LPV{YQ)RJm4K?nH_{q-=sv8JBUifCf*rkjMcb1|$MDbQc^c-41AF)Pd^-&XNU&51cNMRHy1*U6 z9R<)UqU3@B)`33A1Z#T$=#PP|EW)I3sPFX;A8Slm0U85G+N%wFC;U%c5>$2cM*WZv z#5O_y01>0Nm*JX_?sYw5)DFx8AYgZ)r5Y#r8vK7h;=NbbZGETVwgEOg1vJWmT_jjDez|u`ESHOl6<3+#7Uj{P`xIUJcAfySc^eYy@ZBYGD>!e@j}u> zG{Qu3>lX))$6`EEcl$OG3i?jPOyrvo&p>EHf;YJ)Jd4LZA;)|}h!`&pM8Stq3Hx2t z6rGxiWF3j4Ug9Bd%rBmDK4#=`y?ABE@qAm$9v2?vnn^_J7fR2hz#7$q6JvdIYY6)U ztfi6q``9c10lOUnb`INn8a{~rHQVELAQHz<#C6F=WLF{jhPTWP?~KQdgh;26Sc9TL zK!3;|zzRY3N3Of{N5{_J_=JD=XNI##k5%Bm1I>c<)n*Aq-RWAYDpC6U6>5Ut{SwB83c_l zp6+|zI<)20^SNw}FC&G$Yx-romNN!=RpF7O$%rEb25L;;sQIO!2fBPzTk+9Yb!*S7>ZW1RfxJ`8!86K0cJmO8B++W(&^)R<=BUF=Vru__`3>)lq}~Ifs2+= z+9?SB8IM&^La9Y&V#l_en`w6(M||R%?l^bfVxU5SESft9)BgYjX_)JNwm-xlTOerb z+4!=OKqjmRCA6#3CX(PENR?hFlj(7bDi{S@T{H)7&d8y@?z;o0KwZC`pU2(t_MgbI zN5d0oPp?da`Pr=e;)Wt-(FxM6UCp~O&KA}j2hdUsUeF1 z{06bR$7F5e=Z5V$WQxRYtgfNd9UYkD&_N_*2JI0nSUDf?w}gG19PA_?OU9 zMFWlB>T6e*<2cNlDRP*n?$d~R9o99tqh2z~_}&>{OI&X2UqG(kN=cxUODY6Y^rxVo~N18D|{ zK;}q9iiMaSrHZNQz%Saw4P-MpeFs|Z?|_ z$4<vB*%+abmj1(SnTeDDd#&xNUhTn;o2A7*U3|gHnlp;vd9+t{U#pRdJUSkPeL%m|q^#-&+pDq! zb_}sQ&9nnPD}FQ&RYW9SdR2am$JkunxI3SbzdZpwMvoa(rDj8}c!2DmvRu_oc zlO&22g(Md{OcEX3;zIGNn=U~lmCXbIE)axmGF+sFJ4J$O(OiC3 z^6xbAwr*^vC%onbENSB_Jfj;&swx$$T33*c-A>)RGYy4cnp4$az8;a`vf5Ojr7#Lo zllK}5I;zfG0YKx7dS8Wj77xPZp%SHqOail%l$DkPbr{=2YSgpu8!Pr;NY}C0s_#Ss zq^V)DH@y#A0B_gC=E&I=ZN;+O2A1C)0w_T4(d1%6QNP`k22y>K)DL<+j=uyQk+Mgz zs;mWo^n*iX<|QkN#cVNFoXkk*6RA{5CO@BFYsQOkvz?g@Mpzics4cZGd|? z4e|=o>8Rga#X<6aNVW+D?sxQwIp*n$c=MkX?7iw^o1>#Q-zC^gY|k3DkTV23-_wYe z(JTv9Qb4HI)bjjA#1}~8P82@z1iVs%_ji@T`>i1nq4v^=RCXT1k^cZ6aRHO6pS!Fe zfH`iwBFO&$P40K)o)Pm^a>s{w{x6eqEWZ@Hhq;fhI%}LS3yZTxrcC8Am+^Tz#w>(x*YRR048&#Oiyrf&(Kxw7=%Z=#EJIS> zw;jA#Svw}DuJI7_^*zRN7<_Hw3mk6F8ea+Gc-!DOt5L|^wSOsQtWir}EobV|hO1+y zts6yFdigA@vsjAMw;naKMlXsOVxOo0t8t^4oa0Vh>R9ggiX8FaSiF;PN7OI$Yu{)? z_m;H`YxjF*3<++;1K0xXq3fbWxR>_!jJ1M6b5P{(A@rmlBFtcOr!(htR8egjnakOK&3OCu|JO2P+!GIpYCtbb! z<*&?)55k@pzYfPrm{L|2l_eoYpwN-%xHU=T2Fzgt~N{A>g00#tl@I(~Qf0I$)Xqij~D_h2bdYn#|Weu-@Qj$gXg4Z-DZ zGZ_l$eV;+M`*kCs{OGKnm<{@K=xKj|J~Z&3JpLC;eOY*v)}$dMXu;NyUvjMGln^z^ zEZXP5_wA%?Yx#4C{{VwE@V$X7)j?sfx@96~-&3;0snG|bJ08Cs1fQPY1%`8q1e+Nt zs~pH#6dpur70iOHp7p3di{$4zM(z(SaG8iEYu{e%`1 z@G97STtIeF{{WPeQZ5-*%ahs|;EKp`M&4_#m9;%1Z4a9`<~l{OM=O4`wcF}+T9WnI zU>N;3?+GPH2eyy~1bZv-75wY?5@4n#XjX<;3dombWmo>#Gkhfrr~n!RovBYdYH1tF zpE5Y4WBaR-T}a6KX3Z9_^x|R^p?c9MkPPy=} z$||1&QK(Q$PDlj3<4)GJ<(8zheKE841NR)Tm}tp5PDup{gB zNp@&tG6Ag;s6{+S&0mCP%2EbAq^KH{B=8RI+R^VBek<^%CmDrYsaT1UW+)JqrCS70 zk*Kc&z{IeJ^*G>31OD5DD%z5l=JoEk+_?c5q@fphil26pVY{8C}t56ux<^KRv8@UIOc+`Aj zj>9x?MzUFk{#NB{Dp)*`O*D0>DizRJWyi`RQo*D>)rRg1<1c_*8U8+s8l_Um4y>H4 zu&vo7md-V#e5%6@mCl;As)UWQLC&rS<-WCeV!2PvUT>ZKI5{_ztXrmwV5Kyfv9yvq z68%XK)ujbUS3H+7T$=C#I-&Owr z5k3M5X@3!TaW!C>^65)#xB|I>M$akYl8__M^O15eB7 zGwT|8IW`FQRm|husQ_x+1o~w=8)3bI7$_dLe<$C@CMV;6g%(*JGl3)!&4`v=z|1Jv z0{6b?l5p!5K@X@uhKyH`VV9?Dr44sdJKBX#$t72RR1VuZ16u$tz3iOjd}Hw7asKte zn}63ujSVZqc5QIxO2xx)1pXlro&O|dT$a_Q(1~HZhb{HYw;4xi= z`+j=)=kXVX__hlHhrr@x&s3?i6tgUYk{mcDiD2rcgD1O(L9Uehbg8ZM+~NV?>kU|| z%8{f(Df<;wRt4mB=*WlDYy=LySE*(!2-d!0QTuC9GPTWO=E8LIF)jSNEVB5^nmmp5 zW0M_-c4X?kjCUbWT?z(8cPe@S-qmsb-V4cSV-6KX{77>q8Q@NhA3eVaLiYN(PK?y4v4_bqBs&;`a=iACGl#-HiIrIF)AN^u%RL6Mpg>k$+Tz)GZ$FlO{&JP#Tr7G=mm+p5#>v$k#lPdOl+=O<#~3yW}<8XYKI?HuKBDVX^%yB}?Zv{p3U zi=^-_z+j}7Q>Ik|-(myoH^*9!;xq3(?-=V=S(=)0?$EaR;j$lraZ(+(^{aI3e%4j2 z&DXi#wc4oABk7K<8ncFLa*L4UIR~9!QB_MEpLrx`^(Zu}v9d{4{C3bJ{{T88U!Pau zKyp5Ws_(F*dOA7;kUJmbZ+Zu3-naaGO*0y*|OB>Mgd z-^4`3le9_mdg#@o*O@e|364OX0sSK9-=z>a-zQBG<5<3t*@87S9sYyTT z-Jm=lIzI?Wm!eyF?fOQ-ypm`t6Q%&2?1H_3Ah%(o+j~184@3MxASw@?G&#PR^E{xT z13hxmJ(;A45Hv#&Tp`%d(f9E#WTmTD6x@8fA_n^JC)!&`0UFTQBVK?3Se@u? zyEceZ@7Kh($OON?M~RT(yZjyn;}5GScl*fL0a!U5wm&2RtsiG!@-|NWK+SVfssoh{ z{yK54;S?7&0Bc6}{AmNNwg9JcHcA8U{sCgZ5?j&UyJ!KTeGvesAh~TA3ykaS($O@4 z13R4kzgobHGnUwqivglp$E9N6d;S#cfvqa&`rgOERI&wBMcKbz@Y@L$>%Fyu3ueon zsr6X5r3wz)?$(!Jlf53_{{X}3Pry|*Vy0q=79`i8Zu6`ll$@+u=DYdE(ylKxY%zuj z)2C4E@AT9S6Ryri$ONmNq>`bC9hCee;$~awEFDQ_=v(@|-4qO|>H3YlJadsJS9Mkl zM*jf5jVgdO`F(x6*RV+n3D$~{Kd(4{)Ll3B`<~fAsi59-Ja|UZzZ%YTNADVi{E4Mt zLDu?gf&+u-5IUWmo%{GAaZ}xuI$;Kb?^tU!LV*m_tvbX?L9e7L@z@uLeQDe}5!Isa z_bFhyBSenQM^eK;Xb_~51SZW=+$m~ZMadvFGpRJWeO=ww&dZSQ#`W}U;X@7CVVbOQ zF$!lu>OkI=!O`ppE1&`Gu)Erx+aDE{C=QJFXteLr`a7@lGt6hlEXLg*9NT!BD|YF)S@QTw zGePxg!tt}s9l2dnH3%X1fQB7+krLK@rJWnPng|f8Aw^{7WecKARG( z7UZjn0N~}to4n4jqOnp<=n{Gkst5oPv-uhtAbJBt>=UuDH)YgAU#UF%(i9Pqm%Bx! zV8oILDhWDb6zuD;9<(%c5AZ%DfT6f(U#mib>^-+Z_#pkj_1c0+C3Fse+3LrBy=eRr z6kyS>W^ll%*RQ)uM*Rj|fxR#XV}6GB)8Rs3EC7rguo~Ie05H)b?%5rP^arlHAA$$1 zhWMV@X3nlpv@?fn;M9L)NZo?${{V`B7yt*_NYFYgcc7>L0MOZlJbf#(Y=Qjiw!ro^ z??Cnd`v=g`-|}`;Mad??AhqlG(@ie{0vQNhleZf8=!Vvt{yh*#+5C>A5I!9#D))hv z5=#;X7{ft9O%d6MZl7ry1n*?_8v{qEE&QIo$aMxemlr+oiKRrAEpNno^vUYQo7o{( zVTcFOB=7hnot^vc!Rk)O{B1*3@^3qL$`tsh zsmh2aRC$Yipn~cP4UMnzps4_`KK}sn>b}^P1e(MaqU~Yp`usx5rFf!cRZv&*5dlCB zkF(U00N4yWdt#^C6R{|{aQ4rfKo%oFL1^C8A|S)CMb~E=Be!A|R58}b9XlPJ2I>Iy zrU@k2jv&O8w{R`z2iDX>w%mQcYKA*4ue)bpoddtP>;^yN315T6BP7a=JS>1GwTzOW zkXZLW;zv{19@`~>Dl|g?p-0brGNUULEuyMdL5N=4B!EhiN|FYF8Y|ae#HbAU4*g-k zCeQ$za@3H6vVN>!0#~vYKFA~p#)&!rof7{5^A!-JxX9FJn1+e3&L)MtGoE>!f4#@B zl0v?ZbM1}!Gko_UhpBedXUDMOvJz4? z47H%lattI<%OrNBgauili@eb|mKBeu)0JlWa${pAP=LYBHLGvq8ZuH&dyfF$(DRO> zI1WQKfU(I4{oOpQSxmGz*mBcDW(<^O5AVohuQS)JBZ1x<5l2}MX)9Zd%C+Q=AuIcZ z??(5oUzo78hI=-Yy(_FT{{X3{g@>9xTs(o2z}BB3e+5M?(=mzGG|1tU*>1B+W2(`9 z+8Lwm8DNtYE=+OCqdy2tsnXQ%_Xm41YUgJCJQ{G?mQ$@fj|k#RkkXnORP$)TnvPHj zTVLErWsAG@8w$%P45zpsbYr0)ACA&WwyF=>QVW5eWH_zqk&Fq62|VrZcG8e*%y}G# zFX8-CJ@r<4G%B1HMG^L*Xpv>7XX(azM3Y1$=^}&F2*Wb=R9zWjqj2G%fbD`0s_SRK!A&1$i9C{flU!*bKdaKauNWK#c$i-oX5PT>uMn-x7@s@7iWy=V6cBTiTEh zU$hUkk6yrN5Pu)yL3mN)lCbQ%63h8JCqt+W{I{jh*WjN={k{|^1~3#Xe}Fok+foPe zssU{RNY;S#NAa<>3Nj&qbvh02vY+6u;FTc$Hm5}XN%x_$K$l2s*PZF<1K1*<)KpVG zuxVeS0IbXoivU6Er686kYDfP7o$RP1WNYAdf(KytYVnU5hQ88BEBu{n{nNJhruFaF zvZML-q6>DVv$p69O4@Qlge*_~%ojkPTRQ4=NZ+6o9=`-YH9FhQ1p`J&_6%cXy^;3o zUe3wte;f34-|_63C^+F>fWeX&Z#Vo$!?J?IM@RnvA-}U=bcd|9vgA#$2 z*_gN?n|dHC594e!b-u@X(Fb0=AA|uVgecfjxRFW->+B+TBr5_7cLaa|9)^eqdjOI& zeiD_k+}Taa3iyQOJnK;ek?L10h#=mFJs9R|Qw1$2M%4cUGIQbEuX!1JbW0gaTl z(UpkMDgHY<8w;YujgR*yet`gfLD8W>HnsI9DkR$k1ZzyAU}*30v#>_N2eHui>MB!r zp$<8ULXR5i#2E=JLYUmB*)C5|3G7#AP3wKPvd$ZS5!ja>7~q$={`?fI_etP2E^ zFj7K-z<>h~tFy8W#`ZK$kNl8z`HHV*CamvrYtANvR?FUzvy#H1tY~`}SxPx#NqvFn z09dd-wls7Gx1zrZwm}AjvvM`HGu9bbHF%Uf>y`uIx*|p{`8wEYF`-rZpGpeq@7)Li zNf9aUwRQ~|+Y&=onzpA)-#(wwtPvl?cbSHp#c;GA)iNe9fh(*^%Daq~jlQ0XI_ceZ-&?q353`+NT@+Sg<@^3l;?G z%?)4OWi7pP^omVcCXx@`N8U*ckyn#d%qT2jV-^bPXbBe2quMm&fwJw-jmIlR{BSGm z)$M0wrnYa7>oV3eQLZ7L+|Wp?(Ic<>$L@?H3ml5hBX|}iWmZ}U{zIRkf|`Rz-K;LT zmOCxUxb!|b#wAFwl_9G9hb?H!ZbT9*M->->R6Hq;$WmHR@ZRI%^O7EeMEI~jHkG5XqzHoAl3c3H>@xX zo0D^^TAQOt)!~$PQ_zOl8_{*&zxOIg00XxE2;crP`kTD}08t>$9?xD7Qd;G{r$9IS zF&pfv00l>)zWtIv8Xyt*_#^Ib5B$1=t)E1Zwk_*h*!%&nf|`wYS@%9r7B0Ry_5ml~ z`-TVLDtE87xn2wd05^H(0e!)fK(LcUsQexNSE(crNjfdEyE`M<_-J??P=GoG3%%=S zxCcSKf0tHe>(x%%{JMfya!F$5%tv&7kfXyWFA&$-10H}7!~wSc55K@)XRgO>jgc~- zL9Rz5-C;(`u13XacCKDM028xx3Qzu^C=3}-@}qxup|Avc==#8vk}Ype^@Su^H=Rp; zzyf<914L{UD!K)A_$)@f58#&g8r4Q?hv8q;LIyMGJ2MsN>OdLr)2bynJIu~HZ>a!F?D7vKKcEH$#hQj|dqT90AA2$VAtd2fyX02{|yaiN-XBB!>2fyNBIHI%Ac-q`uR4#E`}D5 zAC^Ha+CREhY6_+Di2<(@l9gKmws^UX+u)n;9f0>vY47! zJZ)yRn9f|QLZw>j=GB`s$rN?tjREY;)5>8THQ2EB3F;_fCTyie#VK7g9D3^(g~k&m zkw-EpQ!n=+kXZigaeX^f%+X2o8nd~L<%cD&LFZpiP*tcKWtpSUZlG{ZcijuDjcYWs z`8pJtqpedNjGpL)lEGHP3rLS9D%Gm>rTQ)Vd)2DiMv3~|G~+f{RYlp2FW$aUnKc82*l0s` zX%S8Uoj2XIC8_U6xvvPyy82b!id`Pz((@WyUc5MO_iL(fpC7{Ad6O z(vh!2(I0|@YfTxc$JwEZwzP3}cijHb_tfr)6_BwfT0efaz>-^FcGwHqLV_E6{vYY@ z@`fdWIzVeGt805@?5?9jMSk7-8{V|q+1F$5KobH8EMfs*yVFdm*6?6Y8xG}&RW7|h zi9G@LFS2xYeF30$eVfRaM_Endcb^7k`ni`s!Hr-=-w!f(NbZ@zjuXJ{d^`&0GpWW7d%N1qdvE8~l1Y z0Bc+OPvmw0H(~~W_!vn!HyT2Ldb=rZ-*^LTqz#kkDFbI+gD}|Nw)B5L2%%e#Kg&dt z0X1>c&EwLngvh{wAqop^dXhmqVXxtK6!j-Wjr%JWBH^H+DFB8A^Dg6qH)D(7%wu3w z4@1)cb?kxnAIQ);(DlB%P+Qu8sUTaXdHF$@?92*2_0*6EI`!9MS|eoalkcv^zTgP> zMFg{h)7At~33}Iu;tj4%l$CVR&@9^j0MrFQ#ILeXt>^$WG)UjW0NV2}4#COR{qN2U z$9cBu$FK|AsRU?fYY$UrAb7J{ikN{_U@Qn#lm;yk0 zTQf##R4|U4@PAh)#Q4T>sae9~qq9;B-0*Hn%|I8(jA;$JB7wYt~Ag~jLBDmj&WKBcy2`u^EDK;JZ2OIh@Jlc zZ(&4+6_FGfCP#;}&I)yYqE+LGnBe$QEJ!5{Am zI9CwKI{*aAvUJjDDwUQR)~R? z%E6w&&^*5!EeSrX7_LMBY}zCf^pd@&58BKNBR5a3CEA1{Ga+N~sE|d^Eh9ZkW2w#I zkI&$iCwSv=HE@5n;y3PyL+f#X(IWNN+8zK@uvAi|fu+5CxQ@qSBnyXx#QYO0^d9OyD>GS(>p((+4$O$U&<9@4fiajhLs#C_;a%|N$0$uT3egS!08pvj znS_zLxC!~v`iSlIq1A%^4$A&METwx~?Rvm=ib=6{t@uU<8y7(9dZ_9~khI82BU=mf z2myT`Ub=e@zfVQVfPG-Z149{qM@8yQx=Y*^B-lRx0Lw$OL;2B7j-Z_%&#j3^XuCBU z22jDlwQHy5JX}E}>eW810QWO**Z=@bVS62bKxWuo5wB$>oIRj%=k!nt?#*v!ex?BE z1Eqb00f*=Oy#u}M5DHWQVtkAzZ_IqSivh=bRTMW+5ZZ-$54+iN>Y8QhK^r4yeuyfz z)31^IL%F-2XW7V)P7=#D`$AZ;1TDIyNBIG!S-R~10OU)8#PvFGKz9H;)ARWBiKS$a z3u(?id_9VD)PepU(~v8&m)ciytvEYHtAv5)kNg&RupfzU_w3W*pqXo5qy*z^hB zm3p_J6c$MUl60pWqA)PPdD=eCq2oq%+K$~=ASD!n2XYoNHVbD? zfQ}y|NMx&J<17QZ!z(ACKGHe@LD4;c_E$_){0bBtrGm^)Fpe7Yk<_xQBSt=&l@9%- zSkwevkV9-}=}1z3AXXT)@}w{z+7|c@1(~^ZYgVf*sTfBg71T`KhL}cVguF_EHtg~= zs)(VzkGFN^O(W8p*CS4GG>0sE{6vQ196t@lk)0o^$1HC_K&O%!FJ^i#CrH;8lO8 ze_qLVk)fwG`u5yb!{ecql0i<`d-oz$Gt@|?c1+Af(niQpHPFyDxj&yMvVxi%tCt+O z{^OvZ7I?a?p9fRnnyp6G6CL#J$3)SoH9G|(lO1jlvPdh}dk6~GR4D`YjX_3J7Fxk2 zi9Ct5X;&@AE}(`1>MQ3Gcf zL0H8iBy7qD^og)M!@lv`#FVzVI_n#*Bg^;+&?Gd`MwXwnpiX0Put%zgOzgj=nlqEs+k&V2CqI^c5WZ5i;0{5x;i-0KvA9B`NnbM?Wom+Vaj3Ys6kI zp+ghMJpTaBF=rh9IKt#H)^WINa6Cr!Y~Eg3yV0pmn;Q{cmbT}PCwSl=*@i)VG}|nL z3VD7Z39ms?DtC^J%tDtrnB-MCJzNd~Iynh!)}edJJc8uOCNqs=EJGcPwHj6-k~1z| zx-`iJS^6lAVY2A4*ATg7p)XpIQ2n(%;gqr~TF?Q%yWTkA{YSi)$hmjT2bJhcpS#I; zrx4_Kc;*G;mI&j5rF2A^k}Ms&Jxem$ibo?|)?kPtSbFq$6a=Eh)Xq;A6r;a8Gv^uD zg}c*S^l!sOc}J1TwAg88HovChuRz^ib#OnvvbjjRpzdP?IRmu7b&#<3Z>cR&Z%@o; z!Cq-{#XduD(wXB{b(KQ2i|SNn-h%#$Bl1Mm%jSJ5YB5>w(3>k zJ&Rn{O2DUw7G$|2j`2j&Dl}(b_mN|CbyJ{rb=yjI-;xsi1pv|}Y--!|jc!ka@~CV~ zXTsY(rYE#95{FH$$3XM|e~=&meGbSyl^?`&^)Lt_{*}%ph`yDgvjgmAD^u!ed*-+(a#oF+{ep<&j$fD|1l8a;vUpa274cGpnF6b(cZPP+H!0lyjLE56uFp&JDM0MW`% z;1StKA()mQ;#={v>=E#yFc12Fkt(2kHc)8nE7Gu470SQ-h{R%ZTPoQ6hj~)}N9m9L~=Yu=2xlBIyG6@YkUi9)d&{{SWGdobAF-My;x z**^*<7eeggQUmVxfSN0Q!HUFeHKZ#duu-)H??3`ofGkKJi6cxxh?$ROYZ|-iABQ*^ zG`3FL_eeowq8vFp_6Y1tfxVJFefu8CB|%ce41;lMM#2d)3gfALGN|?kWefoB8%o8G zU6RMS*ZYr35drmU8)f^A^(=s`V7#J3Adz(&_CQd5+C70Pt_buuzQvBthrraI^o}+5 zC)3^-04=G0F2(n~4@h$B`7-;gG-?rB{?%}mqX>$Hm3C(B;1(bcGx&m}lU8ji?-R>Co67v3@L4=5W0mAN z4?FUnKZ)lsmbv0sC(5uATaMgzjXY?tHOzD^OXz(lZp5=saK?|GOOkbi zA$C^&t$1jUF)U0R~Ecu zAN1{%Y?f@DubuCBg261@>%to^obMg+zYuZ`0rL&Oad_-!nmKF98U~IUet)@4 zoVVt?&Up!FSH{FS&O;9Ls1%AR8wFmjANS5u2>aN#`!i}oDoE)hr5ah412i2#w^V>o{` z4a3{>7Iok+kW2^6PYU9E=ON^Lw;H>iUuw{H=bPiQ^owcc?#Yhk1n&x z(xq;~YZz3-w2dpwHqpnG$N&_>*bc<)y)Xksu$bwXg))FkFrg*ik0%x_4L(pvCEcCc zjzPW4KQ@T}0LrqqR&fHc3J`DD_FbHl=|TJ^hRGv;Ybe+|a_R}x4|t+YQZ;wvA+@n? zcC=Hzw)kO13#+u0}LDkK6&b%2$U^|^g}?|X~;%YR8hu_FhM zsqDm+J-T*H5ES|+@J`4(>XulIB8Jj1}_(|XiKK9aEQv>W@1gC@7xyD`@N0#B`m?fLjt!zP=L7bUtKaC3&pgdEI2z@Rwf6^$Au`T3FJAi zDdlTw=8JY|6490qS4<5%|_Q;@VQ zaTen*OBD`Y%hkVA6%dp)O0qnyVkl#kQWuuWDwyR(g|>@|oXzxa%u8W9d7sQEd~M*L z9(bk*=BmGBzx2vUOkomPK OpD1M{07xEZSpV5*ZhS)k literal 0 HcmV?d00001 From a00d2a59a6543bdafc8ae2e5b6e0746dde81b50a Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 21 Feb 2022 20:34:52 +0000 Subject: [PATCH 188/447] Fixed metadata --- apps/thering/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/thering/metadata.json b/apps/thering/metadata.json index bb82d4a27..a2d5e9e4e 100644 --- a/apps/thering/metadata.json +++ b/apps/thering/metadata.json @@ -5,7 +5,7 @@ "icon": "app.png", "tags": "clock", "supports" : ["BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot_thering1.png"}], "readme": "README.md", "storage": [ {"name":"thering.app.js","url":"app.js"}, From 94b2363fdcd4fa651247cc1d50b99f6a7e8d157e Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 21 Feb 2022 21:21:25 +0000 Subject: [PATCH 189/447] Fixed metadata --- apps/thering/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/thering/metadata.json b/apps/thering/metadata.json index a2d5e9e4e..4cc61bd93 100644 --- a/apps/thering/metadata.json +++ b/apps/thering/metadata.json @@ -10,5 +10,5 @@ "storage": [ {"name":"thering.app.js","url":"app.js"}, {"name":"thering.img","url":"app-icon.js","evaluate":true} - ], + ] } From a460f4c315b0e577ae6e43022ab455762784adfb Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 21 Feb 2022 21:40:00 +0000 Subject: [PATCH 190/447] updated README --- apps/thering/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/thering/metadata.json b/apps/thering/metadata.json index 4cc61bd93..03f2d12fd 100644 --- a/apps/thering/metadata.json +++ b/apps/thering/metadata.json @@ -1,7 +1,7 @@ { "id": "thering", "name": "The Ring", "version":"0.01", - "description": "A proof of concept ring guage clock using images, acts as a tutorial piece for discussion", + "description": "A proof of concept clock with large ring guage for steps using images, acts as a tutorial piece for discussion", "icon": "app.png", "tags": "clock", "supports" : ["BANGLEJS2"], From 4812a8043e99a9abd1010dad16dc9827dc57159b Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 21 Feb 2022 21:40:57 +0000 Subject: [PATCH 191/447] updated README --- apps/thering/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/thering/README.md b/apps/thering/README.md index a63f7896a..f932278ee 100644 --- a/apps/thering/README.md +++ b/apps/thering/README.md @@ -1,6 +1,6 @@ # The Ring - *A proof of concept ring guage clock using images, acts as a tutorial piece for discussion* + *A proof of concept clock with large ring guage for steps using images, acts as a tutorial piece for discussion* Written by: [Hugh Barney](https://github.com/hughbarney) For support From 0c5d7a564a04a6806795050c00bf3cc713508985 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 21 Feb 2022 22:02:49 +0000 Subject: [PATCH 192/447] added screenshot , updated README --- apps/thering/README.md | 2 +- apps/thering/metadata.json | 4 ++-- apps/thering/screenshot_thering3.jpg | Bin 0 -> 19580 bytes 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 apps/thering/screenshot_thering3.jpg diff --git a/apps/thering/README.md b/apps/thering/README.md index f932278ee..382fe853f 100644 --- a/apps/thering/README.md +++ b/apps/thering/README.md @@ -1,6 +1,6 @@ # The Ring - *A proof of concept clock with large ring guage for steps using images, acts as a tutorial piece for discussion* + *A proof of concept clock with large ring guage for steps using pre-set images, acts as a tutorial piece for discussion* Written by: [Hugh Barney](https://github.com/hughbarney) For support diff --git a/apps/thering/metadata.json b/apps/thering/metadata.json index 03f2d12fd..32b1dae4b 100644 --- a/apps/thering/metadata.json +++ b/apps/thering/metadata.json @@ -1,11 +1,11 @@ { "id": "thering", "name": "The Ring", "version":"0.01", - "description": "A proof of concept clock with large ring guage for steps using images, acts as a tutorial piece for discussion", + "description": "A proof of concept clock with large ring guage for steps using pre-set images, acts as a tutorial piece for discussion", "icon": "app.png", "tags": "clock", "supports" : ["BANGLEJS2"], - "screenshots": [{"url":"screenshot_thering1.png"}], + "screenshots": [{"url":"screenshot_thering3.jpg"}], "readme": "README.md", "storage": [ {"name":"thering.app.js","url":"app.js"}, diff --git a/apps/thering/screenshot_thering3.jpg b/apps/thering/screenshot_thering3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da8f140c0b36dbcc3c09c9fcc163a02bd1cfdc4d GIT binary patch literal 19580 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 Date: Mon, 21 Feb 2022 22:38:47 +0000 Subject: [PATCH 193/447] Daisy created --- apps/daisy/README.md | 73 +++++++++ apps/daisy/app-icon.js | 1 + apps/daisy/app.js | 248 +++++++++++++++++++++++++++++ apps/daisy/app.png | Bin 0 -> 5008 bytes apps/daisy/metadata.json | 14 ++ apps/daisy/screenshot_thering1.png | Bin 0 -> 3113 bytes apps/daisy/screenshot_thering2.jpg | Bin 0 -> 45141 bytes apps/daisy/screenshot_thering3.jpg | Bin 0 -> 19580 bytes 8 files changed, 336 insertions(+) create mode 100644 apps/daisy/README.md create mode 100644 apps/daisy/app-icon.js create mode 100644 apps/daisy/app.js create mode 100644 apps/daisy/app.png create mode 100644 apps/daisy/metadata.json create mode 100644 apps/daisy/screenshot_thering1.png create mode 100644 apps/daisy/screenshot_thering2.jpg create mode 100644 apps/daisy/screenshot_thering3.jpg diff --git a/apps/daisy/README.md b/apps/daisy/README.md new file mode 100644 index 000000000..382fe853f --- /dev/null +++ b/apps/daisy/README.md @@ -0,0 +1,73 @@ +# The Ring + + *A proof of concept clock with large ring guage for steps using pre-set images, acts as a tutorial piece for discussion* + + +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/) + +* The ring is a proof of concept to establish a clean way to draw a +large ring guage with few aliasing issues and artifacts. +* Rather than use grahics commands to draw the ring a series of fixed images are used. +* This allows for better accuracy of the initial image and also does not suffer from performance issues. +* The downside is that more storage and memory is used to hold the + initial images. This is not an issue on a Bangle 2. +* The ring effect is constructed from 14 images that represent a range of different percentages +* The percentages of the images are 0,2,4,7,10,20,30,40,50,60,70,80,90,100% +* The app is not intended to be enhanced further (apart from bug fixes) but rather as code that can be reused in other apps +* The full set of original images are included in the source code to demonstrate the concept +* I will use this code to build a new clock similar to Pastel but + using this ring guage for steps. The new clock will use more + attractive fonts and provide a settings meu to change the primary + color of the ring. + + +## Screenshots + +![](screenshot_thering1.png) + +It is worth looking at a photograph of the clock in action as the +screenshot does not do the final effect justice. + +![](screenshot_thering2.jpg) + +## Production + +1. I first generated a circle on black background using [The +Gimp](https://www.gimp.org/) image editor. I used this [Youtube +video](https://www.youtube.com/watch?v=AoIAznSdLik) to get started. +The initial image is 178x178 pixels. + +![](1circle.png) + +2. I then drew another smaller black circle over the top of the original to make a ring + +![](1ring.png) + +3. From the empty ring image I coloured segments of the ring and saved new images at specific percentages + +4. I used the file `calc_percentages.js` to work out the x and y +coordinates of the end point of each percentage position along the +ring. + +5. The [Image +Converter](https://espruino.github.io/EspruinoWebTools/examples/imageconverter.html) +was used, set to 2-bit optimal, transparency Y, compression Y and +ImageObject Y, to convert each PNG file to code. + +6. NOTE that the generated image object pallete seemed to switch the +order of the colors from 50% onwards. + +7. The greying out of the unused part of the ring is acheived by +using a dithered color. So if the ring colour is green #0f0 then the +greyed out part is done in '#020'. + + +## Stages of The Ring + +Below are some examples of the different stages of the ring + +![](0p.png) +![](7p.png) +![](60p.png) diff --git a/apps/daisy/app-icon.js b/apps/daisy/app-icon.js new file mode 100644 index 000000000..b577b3d5e --- /dev/null +++ b/apps/daisy/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///pf+sdR0n8CAkCwAcJhNgBI8KwALBgWgCo8NqAZHhNYktYloLKkoLHqwLByoLEgXoBYsrK4UDq0CqulrVVwGV4AXCquCBYYEBC4UC6tiBYeJq57DytayttvNW0tWHgclq2VtNpAYNYKQgiBBYIkBKgUK9Q8B9Nq1Nrqug1WgCoOqytq1/61NW1XVsALBq2ttbMB9N62olBKQNVtNvBYP61dVKgWlqtY34LB/wGBvQ8CEgIKBAAOVq7NDGwILD2/qBQWqAAILDAwUAlIzB1YLD9X1q+oytVqtbBYflA4NeBZVWlQjJ9A7LKZhrLQZS9Bqvq16bGWZXgZY2JZYcK1TjC9WrcYOAcYL7FpL7EAAMlq219NrRYNYBYeVrWV9t7q2lqwKCFwNi6utvVXxLuCBYWCGAIuBAgILCgdegVXBYPVwG1C4eohNWktYyvglYLCKgVeBYO1KQgLCrElvElBY94loBBBY/ghtghILGhSsBsECRgQZHBI5XCJ4kAA=")) diff --git a/apps/daisy/app.js b/apps/daisy/app.js new file mode 100644 index 000000000..7e148381b --- /dev/null +++ b/apps/daisy/app.js @@ -0,0 +1,248 @@ +const h = g.getHeight(); +const w = g.getWidth(); +// palette for 0-40% +const pal1 = new Uint16Array([g.theme.bg, g.toColor("#020"), g.toColor("#0f0"), g.toColor("#00f")]); +// palette for 50-100% +const pal2 = new Uint16Array([g.theme.bg, g.toColor("#0f0"), g.toColor("#020"), g.toColor("#00f")]); +const infoWidth = 50; +const infoHeight = 14; + +var drawingSteps = false; + +function debug(o) { + //console.log(o); +} + +var p0_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLLLzWEABLgbVgohEGopYaiofDBihWVHJpYYDgYPbKx1ACJhYZIwT4OcAZWYHyRYUIgQXQH4RqOThCXUYRpCHNyQVVQQTwVQiSZWIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p2_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette: pal1, + buffer : require("heatshrink").decompress(atob("AH4A/ADNUFE8FqtVq2q1AqkFIIrDAAOAFMEBFQYrE1WgKsYrGLL4qFFY2pqDWeFZdUVkAhCAQMKFYdVLDUVFQYMHlWq0oMJKyoOJlQrCLDBWDB5clB5xWOoARMCARYWKwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p4_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFY2loAqjFY1VqDWeFZdUVkAhEhQrDLDcVFQYMHlQrCBhBWVHJpYYDgYPbKx1ACJhYZIwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p7_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgWlKzVACJgrCqBWYawgAJcAOlNBhWMCZ8qFYJYUgoqBC6ECFYJqOAApWSS4jCNQQ5uSCqqCCeCqESFQKZUIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A==")) +}; + +var p10_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAOkQSdUFacK1WloCCSCaAAEFYKaQQSyEC0pvQirZTbomlIh6CYZAZFOQTBxDQhyCYOQhoPQS4bQHaBzaVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p20_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4AWgNVoAEGAERSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A=")) +}; + +var p30_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccFawkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) +}; + +var p40_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccKFYkVFcwFDitVFccqFYkFFcuoFeNAFcWqFYkBFcugFYtQFUMCFYsAFcuAFYtUFcMKFY0VFcgHFitVFcMqFY0FFceoFY9AFcGqFY0BqtQFT8C1WgFeMAqtUFb8K1WAFY7cglQrIioriBI8FqtAFb2q1ArJbjzaBFZEBbj7aB0ALIFcLaHbkLaJFYbcd1QrKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjUBQR6EaiqCPQjVVQSATCqtUFSZvB1WACiSEUY4KCQQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p50_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjSCQQjSCQQjSCRAAIrB1AqTgorBoAUQQiyCSQgjdSbISCRQgZYSKwKCSQghYQKwSCSQghYQKwSCTAAMqFYOoCJsFFQNVFShYEwARMFQRWVLAiFMQIRWWLAosKFQZWXLAosIFQZWYLAzgFawZWbAAMKFgmq1IoEAANUFTQABFZtAFbgsFFYwqeWQorFVjZZJFYhVfcAwrCazoA/AHI")) +}; + +var p60_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAelNBqCLVxqEC0oRPQS6EC0oSQQSyECFYKEVQSIABFYI/QAAcFFYJDRCgSCmYYjdSCqqYCLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p70_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZAgoAggNVoAr/FbdUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) +}; + +var p80_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AcIdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) +}; + +var p90_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESquq1ArTgqESNgOqwArTIYKERH4KCUQigSBbKTdGCKKCVQiTCCFSyERCALBQQjAPBoArXDZ7ARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) +}; + +var p100_img = { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLFjzWEABLgbVgohEGoqyaiofDBihWVHJpYYDgYPbKxz5NLDJGCfBzgDKzA+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) +}; + +// 300 +Graphics.prototype.setFontRoboto18 = function(scale) { + // Actual height 18 (17 - 0) + this.setFontCustom(atob("AAAAAAAAAAAAAAAf8Qf8QAAAAAA+AAAAA+AAAAAAAABGABGwB/wf2AZGABHwD/AfGABGAAAADhwHw4MYIYIM4MOMMIGGYDDwAAAAAAPAAQgAQggZjAPOAAYABjgDPwEIQAIQAHwADAAAAAHgPMwZwQQwQR8QfGQODwADgAPwAAQAAA+AAAAAAAAA/wD/8OAHYABAAAQAAYABOAOD/8AfgAAAGAAGQACwAfgAfgACwAGAAAAAAAAAYAAYAAYAH/gH/gAYAAYAAYAAAAAAAAA8AAQAIAAIAAIAAIAAIAAAAAAQAAQAAAAAIAB4AHAA8AHgAeAAQAAAAAH/AOBgYAQQAQQAQYAQODwH/AAAAAAAEAAMAAIAAYAAf/wAAAAAAAAAAAAAAAOAQMBwYDQQGQQMQYYQPwQHAQAAAAAAGDgMAwYQQQQQQQQY4QPtwHHgAAAACAAOAAeAByADCAOCAf/wf/wACAACAAAAABAfxgcgwQgQQgQQgQQwwQfgAAAAAAB/AH7gMgwZgQZgQQgQQxwAfgAAAQAAQAAQAQQBwQHgQcARwAfAAcAAAAAAAAHHgPswYwQQQQQQQY4QPswHHgAAAAAAHwAMYQYMQQEQQEwYIgPfAH+AAAAAAADAQBAQAAAAAADA8BAQAAAAAAAYAAcAA0AAmABiABDADDAAAAAAAAkAAmAAmAAmAAmAAmAAmAAkAAAAAAADDABDABiAAmAA0AAcAAYAAIAAAAMAAYAAQGQQcQYwAPgAGAAAAAAfwBwcGAGEACIPzI4RZgRZARZBhY/zIAQMAQGAwD/gAeAAAQADwAfAB+APGAcGAPGAD2AAeAAHwAAwAAAf/wf/wQQQQQQQQQYQQYwwP5wHPgAAAAAAD+APvgIAwYAQQAQQAQQAQYAwODgCDAAAAAAAf/wf/wQAQQAQQAQYAQYAwMBgH/AB8AAAAAAAf/wf/wQQQQQQQQQQQQQQQQQQQAQAAAf/wf/wQQAQQAQQAQQAQQAQQAQAAAAAD+AP/gIAwYAQQAQQIQQIQYIQOIwGPgAAAAAAf/wf/wAQAAQAAQAAQAAQAAQAAQAf/wAAAAAAAAAAAAf/wAAAAAAAAAADgAAwAAQAAQAAQAAwf/gf+AAAAAAAf/wf/wAYAAwAB4ADMAGHAMBgYAwAAQAAAf/wf/wAAQAAQAAQAAQAAQAAQAAAf/wf/wOAADwAA8AAHgABwADwAOAB4AHgAeAAf/wAAAAAAAAAf/wf/wOAAHAABwAA4AAOAAHAABwf/wAAAAAAAAAD+APHgIAwYAQQAQQAQQAQYAwODgD/AAAAAAAf/wf/wQIAQIAQIAQIAYYAIQAPwAAAAAAAD+APDgIAwYAQQAQQAQYAQYA4ODsD/EAAAAAAf/wf/wQIAQIAQIAQYAYeAMzgHgwAAQAAAHDgPgwYwQQwQQQQQYQYYQMNwGHgAAAQAAQAAQAAQAAYAAf/wQAAQAAQAAQAAAAAAAAf/Af/gAAwAAQAAQAAQAAQAAwf/gf+AAAAYAAeAAHwAA+AAHgAAwAHwAeADwAeAAYAAQAAfAAD8AAPwABwAPgD4AfAAeAAHwAAfAADwAHwD+AfgAYAAAAAYAwMBgHHAB8AA4AB8AHHAMBgYAwAAAQAAcAAHAADgAA4AAfwA4ADgAOAAYAAAAAAAAQAwQDwQGQQcQQwQRgQXAQcAQYAQAAAAAA//////wABQAAeAAHgAA8AAPAAB4AAIwABwAD///AAAAAABwAHAAcAAOAADgAAwAAAIAAIAAIAAIAAIAAIAAIAAIAAAwAAYAAIAAAAAAAAAngBmwDMQCMQDMQDMwB/wAAQAAAAAA//wf/wBAQDAQDAQDAQBxwA/AAAAAAAA/gBhwDAQCAQDAQDAQBxgARAAAAA/ABxwDAQDAQDAQBAQf/w//wAAAAAAA/gBtwDMQDMQDMQDMQB8wAYAAAADAAf/w7AAzAAwAAAAAA/ABxyDATDARDARBAzB/+D/8AAAAAA//wf/wBAADAADAADAAB/wA/wAAAAAAT/wT/wAAAAABT//T/8AAAAAA//wf/wAMAAeAAzABhgDAwAAQAAAf/w//wAAAAAAD/wB/wBAADAADAADAAB/wB/wBAADAADAADAAB/wA/wAAAAAAD/wB/wBAADAADAADAAB/wA/wAAAAAAA/gBhwDAQDAQDAQDAQBhwA/gAEAAAAD//B//BAQDAQDAQDAQBxwA/AAAAAAAA/ABxwDAQCAQDAQBAQB//D//AAAAAAD/wB/wBAADAADAAAAABxgB4wDMQCMQDEQBGwBjgAAADAADAAP/wDAQDAQAAAAAAD/gB/wAAQAAQAAQAAwD/wD/wAAADAADwAAeAADwABwAHgA8ADgAAAAAAAD4AAfAADwAHwA+ADwAB4AAPAABwAHwB8ADgAAAAAAADAwBxgAfAAOAA7ABhwDAwAAADAADwBAeDAH+AB8AHgA8ADgAAAAAAADAwDBwDHQDMQD4QDgQDAQAAAAIAAMAH/wfz+wACgADAAAf/8f/8AAAgADwAGfz8D/wAMAAAAAAAAMAAcAAQAAQAAYAAMAAEAAEAAEAAYAAA"), 32, atob("BAQFCgoNCwMGBggKAwUEBwoKCgoKCgoKCgoEBAkKCQgQCwsMDAoKDA0FCgsJEA0MCwwLCwsMCxALCwsEBwQHCAUKCgkKCQYKCgQECQQQCgoKCgYJBgoJDgkJCQYEBgwA"), 18+(scale<<8)+(1<<16)); + return this; +} + +// https://www.1001fonts.com/rounded-fonts.html?page=3 +Graphics.prototype.setFontBloggerSansLight46 = function(scale) { + // Actual height 46 (45 - 0) + this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAA/AAAAAAAAPwAAAAAAAD4AAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAH/gAAAAAAP/wAAAAAAf/gAAAAAAf/AAAAAAA//AAAAAAB/+AAAAAAD/8AAAAAAH/4AAAAAAH/wAAAAAAP/gAAAAAAf/gAAAAAA//AAAAAAB/+AAAAAAA/8AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///8AAAAP////4AAAP/////AAAH/////4AAD+AAAB/AAA8AAAAHwAAeAAAAA+AAHgAAAAHgADwAAAAB4AA8AAAAAPAAPAAAAADwADwAAAAA8AA8AAAAAPAAPAAAAADwAB4AAAAB4AAeAAAAAeAAHwAAAAPgAA/AAAAPwAAH/////4AAA/////8AAAH////+AAAAf///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAPAAAAAAAAHwAAAAAAAB4AAAAAAAA+AAAAAAAAfAAAAAAAAHgAAAAAAAD4AAAAAAAB8AAAAAAAAeAAAAAAAAPgAAAAAAADwAAAAAAAB//////4AAf//////AAH//////gAA//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAD4AAHAAAAD+AAD4AAAB/gAA8AAAB/4AAfAAAA/+AAHgAAAf3gAB4AAAPx4AA8AAAH4eAAPAAAD4HgADwAAB8B4AA8AAA+AeAAPAAAfAHgADwAAPgB4AA8AAHwAeAAHgAD4AHgAB4AD8AB4AAfAB+AAeAAD8B/AAHgAAf//gAB4AAH//wAAeAAAf/wAAHgAAB/wAAA4AAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AADgAAAAPAAB4AAAADwAAeAAAAA+AAHgAAAAHgAB4ABgAB4AAeAA8AAeAAHgA/AADwAB4AfwAA8AAeAP8AAPAAHgH/AADwAB4H7wAA8AAeD48AAPAAHh8PAAHgAB5+BwAB4AAe/AeAA+AAH/AHwAfAAB/gA/AfgAAfwAH//wAAHwAA//4AAA4AAH/8AAAAAAAf4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAD+AAAAAAAD/gAAAAAAH/4AAAAAAH/+AAAAAAP/ngAAAAAP/h4AAAAAf/AeAAAAAf/AHgAAAA/+AB4AAAA/+AAeAAAB/8AAHgAAA/8AAB4AAAP4AAAeAAAB4AAAHgAAAAAAAB4AAAAAAAAeAAAAAAP///4AAAAH////AAAAA////gAAAAP///4AAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAD4AA8AAD///gAPAAB///4AD4AAf//+AAeAAH+APAAHgAB4AHgAA4AAeAB4AAOAAHgAcAADwAB4AHAAA8AAeADwAAPAAHgAcAADwAB4AHAAA8AAeAB4AAeAAHgAeAAHgAB4AHwAD4AAeAA+AB8AAHgAP4B+AAB4AB///gAAOAAP//gAABAAA//wAAAAAAD/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gAAAAAB///4AAAAD////wAAAD////+AAAB/////4AAA/gPgB/AAAfgDwAHwAAPgA8AA+AADwAeAAHgAB4AHgAB4AAeAB4AAfAAHgAeAADwABwAHgAA8AAcAB4AAPAAHAAeAAHwAB4AHgAB4AAeAB8AAeAAHgAPAAPgAB4AD8APwAAOAAfwP4AADgAD//8AAAAAAf/+AAAAAAB/+AAAAAAAH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAA4AAeAAAAB/AAHgAAAB/wAB4AAAB/4AAeAAAD/4AAHgAAD/wAAB4AAH/wAAAeAAH/gAAAHgAP/gAAAB4AP/AAAAAeAf/AAAAAHgf+AAAAAB4/+AAAAAAe/8AAAAAAH/8AAAAAAB/4AAAAAAAf4AAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gAAAA/AB/+AAAA/8B//wAAA//gf/+AAAf/8PgPgAAH4fngB8AAD4B/wAPgAA8AP8AB4AAeAB+AAeAAHgAfgADwAB4ADwAA8AAcAA8AAPAAHAAPAADwAB4ADwAA8AAeAB+AAPAAHgAfgAHgAB8AP8AB4AAPgH/AA+AAD8H54AfAAAf/8fgPwAAD/+D//4AAAf/Af/8AAAB/AD/+AAAAAAAP+AAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAAAf/wAAAAAAf/+AAAAAAP//4AAwAAH//+AAeAAD+APwAHgAA+AA+AB4AAfAAHgAOAAHgAB4ADwAB4AAPAA8AAeAADwAPAAHgAA8ADwAB4AAPAA8AAeAADwAPAAHgAA8AHgAB8AAeAB4AAPgAHgA+AAD8ADwA/AAAfwA8A/gAAD/wef/wAAAf////4AAAB////4AAAAH///wAAAAAD/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AB4AAAAAfgA/AAAAAH4APwAAAAB+AD4AAAAAPAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DRAcHBwcHBwcHBwcDQ=="), 56+(scale<<8)+(1<<16)); + return this; +}; + +function setLargeFont() { + g.setFontBloggerSansLight46(1); +} + +function setSmallFont() { + g.setFontRoboto18(1); +} + +function getSteps() { + try { + return Bangle.getHealthStatus("day").steps; + } catch (e) { + if (WIDGETS.wpedom !== undefined) + return WIDGETS.wpedom.getSteps(); + else + return 0; + } +} + +function getGaugeImage(p) { + //debug("p="+p); + if (p < 2) return p0_img; + if (p >= 2 && p < 4) return p2_img; + if (p >= 4 && p < 7) return p4_img; + if (p >= 7 && p < 10) return p7_img; + if (p >= 10 && p < 20) return p10_img; + if (p >= 20 && p < 30) return p20_img; + if (p >= 30 && p < 40) return p30_img; + if (p >= 40 && p < 50) return p40_img; + if (p >= 50 && p < 60) return p50_img; + if (p >= 60 && p < 70) return p60_img; + if (p >= 70 && p < 80) return p70_img; + if (p >= 80 && p < 90) return p80_img; + if (p >= 90 && p < 100) return p90_img; + if (p >= 100) return p100_img; +} + +function draw() { + 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)); + debug("steps="+ steps + " p_steps=" + p_steps); + + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(0, 0, w, h); + g.drawImage(getGaugeImage(p_steps), 0, 0); + setLargeFont(); + + g.setColor('#0f0'); + 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); + + drawSteps(); + g.drawString('Battery ' + E.getBattery() + '%', w/2, h/4); + queueDraw(); +} + +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(); +}); + + +/////////////////////////////////////////////////////////////////////////////// + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + //prevInfo(); + //checkIdle(); + draw(); + }, 60000 - (Date.now() % 60000)); +} + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + +g.clear(); +Bangle.setUI("clock"); +Bangle.loadWidgets(); +/* + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ +for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} +draw(); diff --git a/apps/daisy/app.png b/apps/daisy/app.png new file mode 100644 index 0000000000000000000000000000000000000000..89252e5dfd0295126c077ec1c75e06fea87f2632 GIT binary patch literal 5008 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 Dgx=Ia literal 0 HcmV?d00001 diff --git a/apps/daisy/screenshot_thering2.jpg b/apps/daisy/screenshot_thering2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..521a610171da359e9ae8e2c3f2816846d541a258 GIT binary patch literal 45141 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

PZ>rG*M~V* zC=?>g<|qzUT^}9eqm`cR-)I=G%D(J`n$g*O+P+6K*i1SmQxJoPJy1-=+C!XPq zXt}li9;HoaA#*YruFn<(?aZy;Gk-omgP;Tu?VX>u{|%i&05tz4)r&W<>4qON|T{S-l=El;BD@~G0;3Zdw%_I;xJ>C7skh{n8_ z1r$-3d%J?jPxjaGb$HYSfy%xHQ>HkGn6ze-HgDn`h}pCJ=JMyPk9(uQ2l2^x*)FNT z^A7CU%y;7fKhtN~z0ti&UTiI15>bra(5u6?V_VDzCEA3#^b#d>BSPB$lA!y*g9uU4 z@wD()0iq7>8$RVJgXqm#qdS}gc)T|aqDjqh=FXpNj2z{KQaA~9m)+coK$QAmy+r20C+G~`6dK8p$cTg#30zac>=!9*{mlU4^%FzH1GLUxT42Yhv+dMStgI@awnB8-Z5@|- z>ai1%5l&rW0ul=# z=U}w1>YAUs6lhCUs;as3+lo}t0`d&j)e1+ZskBSsRbBf_AXsgynhZw-Ps=Q+)d~8RH-A$ncazPIV650N=byGl>S7t ze)cA`)PbBe(Pl=#v$U(Er#qT;B`d0(G$4!f7EgY-rpeT^@a0v7GW|9eSgy*OJtAwt z7!PX@&dPGDpkBTkk3d7@^OZwHK(34kH?HHe?-Cc3^Dicom*#y9k6y%`mUIt4oxuCPn9;^520*>@VS z3-Sa~*vAWYZU^dgHbQ-`_3OdAt^D z8R>^Zw_ymMw3SY1)iX0Xe!T4&@uOJH&5T2DDh4Kag``Qsg#B4l&Qbjr@T@y#kR{T; zv6t?G8X9}m4nhH|H8w)6=kLEMh6qRQAH$}Rol%DJOn2|k;R?tHqpHiEmjn|;8x|iN zi5M>#!RVvAiP(R8<6jm|ka`f_dt=!?#40l``=kY~Nww$o{9aCu)P@5>p_eJKi|2J( zs;y>#3qL`Cy<(*&E%PVN_YWLQ@K?N9gEIod�e9j3!`F3^QxZK5jA}%d6?l5dX7% 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 OpD1M{07xEZSpV5*ZhS)k literal 0 HcmV?d00001 diff --git a/apps/daisy/screenshot_thering3.jpg b/apps/daisy/screenshot_thering3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da8f140c0b36dbcc3c09c9fcc163a02bd1cfdc4d GIT binary patch literal 19580 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 Date: Tue, 22 Feb 2022 11:44:50 +0100 Subject: [PATCH 194/447] Update 7x7dotsclock.settings.js Color Settings of Minutes and Seconds --- apps/7x7dotsclock/7x7dotsclock.settings.js | 51 ++++++++++++++++------ 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.settings.js b/apps/7x7dotsclock/7x7dotsclock.settings.js index c2b5d6c2b..fe9fbc022 100644 --- a/apps/7x7dotsclock/7x7dotsclock.settings.js +++ b/apps/7x7dotsclock/7x7dotsclock.settings.js @@ -1,21 +1,8 @@ (function(back) { -let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {}); +let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: "",ColorMinutes: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {}); -function showMainMenu() { - const mainMenu = { - "": {"title": "7x7 Dots Clock Settings"}, - "< Back": ()=>load(), - "swipe-up": ()=>showSelAppMenu("swupApp"), - "swipe-down": ()=>showSelAppMenu("swdownApp"), - "swipe-left": ()=>showSelAppMenu("swleftApp"), - "swipe-right": ()=>showSelAppMenu("swrightApp") - - }; - - E.showMenu(mainMenu); -} function setSetting(key,value) { print("call " + key + " = " + value); @@ -26,6 +13,42 @@ function setSetting(key,value) { } + // Helper method which uses int-based menu item for set of string values + function stringItems(key, startvalue, 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 => { + setSetting(key,values[v]); + } + }; + } + + // Helper method which breaks string set settings down to local settings object + function stringInSettings(name, values) { + return stringItems(name,settings[name], values); + } + +function showMainMenu() { + const mainMenu = { + "": {"title": "7x7 Dots Clock Settings"}, + "< Back": ()=>load(), + "Minutes": stringInSettings("ColorMinutes", ["blue","pink","green"]), + "swipe-up": ()=>showSelAppMenu("swupApp"), + "swipe-down": ()=>showSelAppMenu("swdownApp"), + "swipe-left": ()=>showSelAppMenu("swleftApp"), + "swipe-right": ()=>showSelAppMenu("swrightApp") + + }; + + E.showMenu(mainMenu); +} + + function showSelAppMenu(key) { var Apps = require("Storage").list(/\.info$/) .map(app => {var a=storage.readJSON(app, 1);return ( From 3b3c01677abb0584a63cb6937a695b5e8f4b084b Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:46:08 +0100 Subject: [PATCH 195/447] Update 7x7dotsclock.app.js Color Settings of Minutes and Seconds --- apps/7x7dotsclock/7x7dotsclock.app.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index c6daee542..ce2b3011d 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -5,7 +5,7 @@ by Peter Kuppelwieser */ -let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {}); +let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: "", ColorMinutes: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {}); // position on screen var Xs = 0, Ys = 30,Xe = 175, Ye=175; @@ -13,8 +13,19 @@ var Xs = 0, Ys = 30,Xe = 175, Ye=175; var SegH = (Ye-Ys)/2,SegW = (Xe-Xs)/2; var Dx = SegW/14, Dy = SegH/16; - -const mColor = [0.3,0.3,1]; +switch(ColorMinutes) { + case "blue": + var mColor = [0.3,0.3,1]; + break; + case "pink": + var mColor = [1,0.3,1]; + break; + case "green": + var mColor = [0.3,1,0.3]; + break; + default: + var mColor = [0.3,0.3,1]; +} const bColor = [0.3,0.3,0.3]; const Font = [ @@ -141,9 +152,9 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { for (let j = 1; j < 8; j++) { if (Font[Num][j-1][i-1] == 1) { if (Color == "fg") { - g.setColor(g.theme.fg); + g.setColor(mColor[0],mColor[1],mColor[2]); } else { - g.setColor(g.theme.fgH); + g.setColor(g.theme.fg); } g.fillCircle(x1+(i-1)*(x2-x1)/7,y1+(j-1)*(y2-y1)/7,Size); } @@ -153,7 +164,7 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { function ShowSecons() { - g.setColor(g.theme.bgH); + g.setColor(g.theme.fg); g.fillRect((Xe-Xs) / 2 - 14 + Xs -3, (Ye-Ys) / 2 - 7 + Ys -3, (Xe-Xs) / 2 + 14 + Xs +1, @@ -164,13 +175,13 @@ function ShowSecons() { (Ye-Ys) / 2 - 7 + Ys , (Xe-Xs) / 2 + Xs -1, (Ye-Ys) / 2 + 7 + Ys, - ds,"",1); + ds,"fg",1); drawSSeg( (Xe-Xs) / 2 + Xs +1, (Ye-Ys) / 2 - 7 + Ys, (Xe-Xs) / 2 + 14 + Xs +1, (Ye-Ys) / 2 + 7 + Ys, - es,"",1); + es,"fg",1); } From f6a2a03448f2d68fd6c533e2d8a126fb7d49f916 Mon Sep 17 00:00:00 2001 From: Marco H Date: Tue, 22 Feb 2022 15:15:18 +0100 Subject: [PATCH 196/447] New color option: foreground --- apps/circlesclock/app.js | 3 +++ apps/circlesclock/settings.js | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 903c7bdb2..ba7ab474e 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -248,6 +248,9 @@ function getGradientColor(color, percent) { const colorList = [ '#00FF00', '#80FF00', '#FFFF00', '#FF8000', '#FF0000' ]; + if (color == "fg") { + color = colorFg; + } if (color == "green-red") { const colorIndex = Math.round(colorList.length * percent); return colorList[Math.min(colorIndex, colorList.length) - 1] || "#00ff00"; diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index bec539376..0b9e94aca 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -14,8 +14,10 @@ const valuesCircleTypes = ["empty", "steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "temperature", "pressure", "altitude"]; const namesCircleTypes = ["empty", "steps", "distance", "heart", "battery", "weather", "sun", "temperature", "pressure", "altitude"]; - const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000", "green-red", "red-green"]; - const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black", "green->red", "red->green"]; + const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", + "#00ffff", "#fff", "#000", "green-red", "red-green", "fg"]; + const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", + "cyan", "white", "black", "green->red", "red->green", "foreground"]; const weatherData = ["empty", "humidity", "wind"]; From 9977460d1f41f15058fba03359e6099f560bb6f0 Mon Sep 17 00:00:00 2001 From: Marco H Date: Tue, 22 Feb 2022 15:16:40 +0100 Subject: [PATCH 197/447] Draw the circles a little bit delayed so we decrease the blocking time --- apps/circlesclock/app.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index ba7ab474e..1e713c2e6 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -138,10 +138,19 @@ function draw() { g.drawString(locale.date(new Date()), w / 2, h2); g.drawString(locale.dow(new Date()), w / 2, h2 + dowOffset); - drawCircle(1); - drawCircle(2); - drawCircle(3); - if (circleCount >= 4) drawCircle(4); + // draw the circles a little bit delayed so we decrease the blocking time + setTimeout(function() { + drawCircle(1); + }, 1); + setTimeout(function() { + drawCircle(2); + }, 1); + setTimeout(function() { + drawCircle(3); + }, 1); + setTimeout(function() { + if (circleCount >= 4) drawCircle(4); + }, 1); } function drawCircle(index) { From 0eb5cd9292622a4057b4a87c7cd8a121625aa2da Mon Sep 17 00:00:00 2001 From: Marco H Date: Tue, 22 Feb 2022 15:17:09 +0100 Subject: [PATCH 198/447] Move icons to the functions which use them to reduce memory usage --- apps/circlesclock/app.js | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 1e713c2e6..d5df2fe44 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -3,23 +3,8 @@ const storage = require("Storage"); const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); const shoesIcon = atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"); -const heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA"); -const powerIcon = atob("EBCBAAAAA8ADwA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AH4AAA"); const temperatureIcon = atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"); -const weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA"); -const weatherSunny = atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA"); -const weatherMoon = atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA"); -const weatherPartlyCloudy = atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA"); -const weatherRainy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA"); -const weatherPartlyRainy = atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA"); -const weatherSnowy = atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA"); -const weatherFoggy = atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA"); -const weatherStormy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA"); - -const sunSetDown = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAAGYAPAAYAAAAAA"); -const sunSetUp = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAABgAPABmAAAAAA"); - Graphics.prototype.setFontRobotoRegular50NumericOnly = function(scale) { // Actual height 39 (40 - 2) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAB8AAAAAAAfAAAAAAAPwAAAAAAB8AAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAA4AAAAAAB+AAAAAAD/gAAAAAD/4AAAAAH/4AAAAAP/wAAAAAP/gAAAAAf/gAAAAAf/AAAAAA/+AAAAAB/+AAAAAB/8AAAAAD/4AAAAAH/4AAAAAD/wAAAAAA/wAAAAAAPgAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///wAAAB////gAAA////8AAA/////gAAP////8AAH8AAA/gAB8AAAD4AA+AAAAfAAPAAAADwADwAAAA8AA8AAAAPAAPAAAADwADwAAAA8AA8AAAAPAAPgAAAHwAB8AAAD4AAfwAAD+AAD/////AAA/////wAAH////4AAAf///4AAAB///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAPgAAAAAADwAAAAAAB8AAAAAAAfAAAAAAAHgAAAAAAD4AAAAAAA+AAAAAAAPAAAAAAAH/////wAB/////8AA//////AAP/////wAD/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAfgAADwAAP4AAB8AAH+AAA/AAD/gAAfwAB/AAAf8AAfAAAP/AAPgAAH7wAD4AAD88AA8AAB+PAAPAAA/DwADwAAfg8AA8AAPwPAAPAAH4DwADwAH8A8AA+AD+APAAPwB/ADwAB/D/gA8AAf//gAPAAD//wADwAAf/wAA8AAD/4AAPAAAHwAADwAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAADgAAAHwAA+AAAD8AAP4AAB/AAD/AAA/wAA/wAAf4AAD+AAHwAAAPgAD4APAB8AA+ADwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA8AH4APAAPgD+AHwAB8B/wD4AAf7/+B+AAD//v//AAA//x//wAAD/4P/4AAAf8B/4AAAAYAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAHwAAAAAAH8AAAAAAD/AAAAAAD/wAAAAAD/8AAAAAB/vAAAAAB/jwAAAAA/g8AAAAA/wPAAAAAfwDwAAAAf4A8AAAAf4APAAAAP8ADwAAAP8AA8AAAH8AAPAAAD/////8AA//////AAP/////wAD/////8AA//////AAAAAAPAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAB/APwAAH//wD+AAD//8A/wAA///AH+AAP//wAPgAD/B4AB8AA8A+AAfAAPAPAADwADwDwAA8AA8A8AAPAAPAPAADwADwD4AA8AA8A+AAPAAPAPwAHwADwD8AD4AA8AfwD+AAPAH///AADwA///wAA8AH//4AAPAAf/4AAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAD//+AAAAD///4AAAD////AAAB////4AAA/78D/AAAfw8AH4AAPweAA+AAD4PgAHwAB8DwAA8AAfA8AAPAAHgPAADwAD4DwAA8AA+A8AAPAAPAPgAHwADwD4AB8AA8AfgA+AAPAH+B/gAAAA///wAAAAH//4AAAAA//8AAAAAH/8AAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAA8AAAABAAPAAAABwADwAAAB8AA8AAAB/AAPAAAB/wADwAAD/8AA8AAD/8AAPAAD/4AADwAD/4AAA8AD/4AAAPAH/wAAADwH/wAAAA8H/wAAAAPH/wAAAAD3/gAAAAA//gAAAAAP/gAAAAAD/gAAAAAA/AAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwA/4AAAH/Af/AAAH/8P/4AAD//n//AAA//7//4AAfx/+A+AAHwD+AHwAD4AfgB8AA8AHwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA+AH4AfAAHwD+AHwAB/D/4D4AAP/+/n+AAD//n//AAAf/w//gAAB/wH/wAAAHwA/4AAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAAAAD/8AAAAAD//wAAAAB//+AAAAA///wAAAAf4H+APAAH4AfgDwAD8AB8A8AA+AAfAPAAPAADwDwADwAA8B8AA8AAPAfAAPAADwHgADwAA8D4AA+AAeB+AAHwAHg/AAB+ADwfgAAP8D4/4AAD////8AAAf///8AAAB///+AAAAP//+AAAAAP/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAOAAAB8AAHwAAAfgAD8AAAH4AA/AAAB8AAHwAAAOAAA4AAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("DRUcHBwcHBwcHBwcDA=="), 50+(scale<<8)+(1<<16)); @@ -337,6 +322,8 @@ function drawStepsDistance(w) { function drawHeartRate(w) { if (!w) w = getCircleXPosition("hr"); + const heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA"); + drawCircleBackground(w); const color = getCircleColor("hr"); @@ -361,6 +348,8 @@ function drawBattery(w) { if (!w) w = getCircleXPosition("battery"); const battery = E.getBattery(); + const powerIcon = atob("EBCBAAAAA8ADwA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AH4AAA"); + drawCircleBackground(w); let color = getCircleColor("battery"); @@ -438,6 +427,10 @@ function drawSunProgress(w) { if (!w) w = getCircleXPosition("sunprogress"); const percent = getSunProgress(); + // sunset icons: + const sunSetDown = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAAGYAPAAYAAAAAA"); + const sunSetUp = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAABgAPABmAAAAAA"); + drawCircleBackground(w); const color = getCircleColor("sunprogress"); @@ -571,6 +564,18 @@ function windAsBeaufort(windInKmh) { */ function getWeatherIconByCode(code) { const codeGroup = Math.round(code / 100); + + // weather icons: + const weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA"); + const weatherSunny = atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA"); + const weatherMoon = atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA"); + const weatherPartlyCloudy = atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA"); + const weatherRainy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA"); + const weatherPartlyRainy = atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA"); + const weatherSnowy = atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA"); + const weatherFoggy = atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA"); + const weatherStormy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA"); + switch (codeGroup) { case 2: return weatherStormy; From e16cbf73b550d846921f04df8a6bd79415c48a41 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 15:37:37 +0100 Subject: [PATCH 199/447] Create app.js --- apps/smclock/app.js | 108 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 apps/smclock/app.js diff --git a/apps/smclock/app.js b/apps/smclock/app.js new file mode 100644 index 000000000..6aff72a46 --- /dev/null +++ b/apps/smclock/app.js @@ -0,0 +1,108 @@ +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=")) +}; + +const weekday = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]; +var level = -1; + +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); +} + +function d02(value) { + return ('0' + value).substr(-2); +} + +function pollBattery() { + level = E.getBattery(); + return level; +} + +function getBatteryColor(level) { + var color; + if (level < 0) { + level = pollBattery(); + } + 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]; + } + return color; +} + +function draw() { + g.drawImage(background); + + const color = getBatteryColor(); + const bat = d02(E.getBattery()) + "%"; + const d = new Date(); + const day = d.getDate(); + 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); + const h = d.getHours(); + const m = d.getMinutes(); + const time = d02(h) + ":" + d02(m); + + 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); + + 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); + g.setColor(color[0], color[1], color[2]); + g.drawString(bat, 52, 22, false); +} + +g.clear(); + +pollBattery(); +draw(); + +var batInterval = setInterval(pollBattery, 60000); +var drawInterval = setInterval(draw, 10000); + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (batInterval) clearInterval(batInterval); + batInterval = undefined; + if (drawInterval) clearInterval(drawInterval); + drawInterval = undefined; + if (on) { + batInterval = setInterval(pollBattery, 60000); + drawInterval = setInterval(draw, 10000); + + pollBattery(); + draw(); // draw immediately + } +}); + +// Show launcher when middle button pressed +Bangle.setUI("clock"); From c9616d4233029406342f28312a494ba202f51a23 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 15:41:52 +0100 Subject: [PATCH 200/447] Create app-icon.js --- apps/smclock/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/smclock/app-icon.js diff --git a/apps/smclock/app-icon.js b/apps/smclock/app-icon.js new file mode 100644 index 000000000..497389173 --- /dev/null +++ b/apps/smclock/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("2GwwkB/4A/AH4Aub1UP+93AFJX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X3/4A/AH4Avf8IAzK/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/A")) From 99c694c8e1cd193c7e3bccc422f660d5c7d529f4 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 15:43:28 +0100 Subject: [PATCH 201/447] Create ChangeLog --- apps/smclock/ChangeLog | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/smclock/ChangeLog diff --git a/apps/smclock/ChangeLog b/apps/smclock/ChangeLog new file mode 100644 index 000000000..b029d805d --- /dev/null +++ b/apps/smclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: Initial version +0.02: Add battery level From 952f438c54aa9611b5f2a579293ffea4ba131812 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 15:55:20 +0100 Subject: [PATCH 202/447] Create metadata.json --- apps/smclock/metadata.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 apps/smclock/metadata.json diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json new file mode 100644 index 000000000..4c558f504 --- /dev/null +++ b/apps/smclock/metadata.json @@ -0,0 +1,13 @@ +{ + "id":"smclock", + "name":"Monogram Watch Face", + "shortName":"MonoClock", + "icon":"app.png", + "version":"0.02", + "description": "A simple watchface based on my stylised monogram.", + "tags":"clock", + "storage": [ + {"name":"smclock.app.js","url":"app.js"}, + {"name":"smclock.img","url":"app-icon.js","evaluate":true} + ] +} From 3b1a3ef801899e50671c73df172d8ce24e2b5245 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 15:58:12 +0100 Subject: [PATCH 203/447] Update metadata.json --- apps/smclock/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 4c558f504..0b6f1613f 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -6,6 +6,7 @@ "version":"0.02", "description": "A simple watchface based on my stylised monogram.", "tags":"clock", + "readme":"README.md", "storage": [ {"name":"smclock.app.js","url":"app.js"}, {"name":"smclock.img","url":"app-icon.js","evaluate":true} From 9f5ac58edd7d152e637eaea3670c9223cf595316 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 16:00:27 +0100 Subject: [PATCH 204/447] Create README.md --- apps/smclock/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/smclock/README.md diff --git a/apps/smclock/README.md b/apps/smclock/README.md new file mode 100644 index 000000000..7b5613147 --- /dev/null +++ b/apps/smclock/README.md @@ -0,0 +1,5 @@ +# Monogram Watch Face + +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. From 762c375ab3569c960aba6e7fcc084b7280757346 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 16:02:20 +0100 Subject: [PATCH 205/447] Add app icon --- apps/smclock/app.png | Bin 0 -> 6033 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/smclock/app.png diff --git a/apps/smclock/app.png b/apps/smclock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..49c87c39dfba2763c4b2ee301221ca5ef4a93342 GIT binary patch literal 6033 zcmeHKc{r3^8y_JdiEL>xCKYM+VV00R6C)uF39~#H%nUPwi57|Km1HYxNs5%bNl}sI zEkzBlt!zmz6;hN)sq{TFTCeZ>{^+{C@4x1{o-^mUm*2VX-?`6u&iTX1af6bAwgLnK zQ6k$}JA?ly@iT8O*lwNk{s06b_aMTRDsZNSLxXu-UsezR73>HGpn#C&3xNo`FHpA~ zdyZQ0v15&|{4wuKX#<1A(tYkTsoCbzN}86Lg4MMlcazUC?=`>c+q3$UoX%LKu8v;a z(!AO`emU$~3Z|!^2)m@ZX=LE-hIhL=96RJRD5C{_agm?x*Lh2o+1GBrDz%Zl$7xK5 zSv^o7cXAiBK*Rmv#4`Oc^Cph6P)@sJbMw#UA>DC?AWbJBKCczkKNX4=9;zmV&@F>5me&h6&;$~GFpRD0Q9=CjnoO9}BSEbc2g59MdX<%RevUSAbC>M0zjcHCB46|t^ffm6hO zaN+ioTfRLSTrcGlZk}PiD_?bMynNJk9$vY>F~3C{PJ7Zc6tLK*$e9q)+@krc-POl< zSlh4@xG;B#uRcG*7LWRiuN**?s#?Y4l4}D-3{LCA%HCZTQ#u^GX_x zF<}nAJ}~G#nTO1+=EtU_rd4uI=Bj$W(v8v5JDq6t2Vz=_9Gd`j@Pom2eNvY24(EAym3E?e7vQv1LQdyJfYwt?f$C9Qfz6(nh% z8hPC{^{KYORz_q(g3yGbPc_)CGpVk{8morn9b);_4n6oA>ocKsnOi%wSh_E&#gKF) zx~2MZ$=<`TM&0xC1CkN_8_M#`bEJ1AavZl-MmO~3rao@ToS<%~(a#mBJxHgHM(nc% z2nW%u*L4ib$}>~iPVQSq7V+w#c>glGjA4O@+TGld@@GlyYI0n3a)5`ml>4@1oz9_Uvt5 z{NB?=J1>E@Te@wpcjah4%{rnQryo|5G*sFWdWcbu$?XEL{ zr>|yFksH=t@y{QyA$v`@4_)=p^iXaUQ9rq)sBA}I3|m_x-KLXNMbe5NFWui6aYLRg zzazP6@tuVZiLGZY?2OS2Ns9gBu!>&0HWhKR=i1q8G|etn|0c#Z`^=knG7D3a01A#& z{rY(rzDuk8M!)bGj=tYj^rEs$Gc)bsL_)$s_=Sp4#iQ1H6FH=2slv0)2vV0TFHfc0 zI{G>-O`d)&=2YaQ94J3ABr|4dAd}i>`5vB9z9v^07`fs;v1(Au=gEFLN>mdNt^|zMXyQV9J1bNYbx;zz4US(z&ujl%5TKO%mn+-V}Ke(dB>#;U5lrv}GK3vB*OjZlm8Iy9rDW}3EhXxFNu zWhKW5E*d)gj1qO1$w3)!mv$XZY^3Oju1~Z>XS>6JqpN$I*9Dm6E!iSyncTSNi7ouE z&Z_5Q<(`|9g?-O2oy%liu`XOZ5K?rSyFTmn=&DNPfcYek&?;F4>6Q7fLra%mlkYL| zlDBX#s}9MYdHH@Yp{pV~)q^wX~n&2Dm_3%Nmqei+H|^*u_K8qS3njqSXN6;hV_Yom z`0AY>t%|*2X_mzpEuw}~?A)%&eV=Q`x;$bV4CE&I=G+K; z^w49FunU60oo`nP4xSgUVG!9n*lT*6|Dn9Vs9HzChPO*}e&rMJB&N**Ph3=r1Bt<9 zBWO%69Y6@#!QhDu0x?-H45l#x0RfZ__^~*qu(6727?i~{g>5yWpeVssfIrJFf(N)n zIJz<-0vSXmY`vL+iI4;WumJ%LDr5(7_#~kzOoB@S`(iN?29=ly0!?95iWAg|%LAY| z1P+0M+Xz`<7?_y?)P%?MB{^H$et`hrOkw^4K`;r43=a=Sgkuq0o*xoTBodJ*3=)HZ zgBEc94vv5(gmd^S#1OL>)&QTuV+9LXTnNuzT^1*R|zXvd>I5R77s_$>3BGfjwiy2XeJM2+jNfViS)ARwXUy$Ed_mOc07l#1VYyUkG%x@EACqK{SHn@Mt0fz~Fp| zMnnk|lR>iO^4K(RI$3O*AAk(z_(>FE!buiRWK$Rhf%-0S3Ze;oK?hTq1B(+X{H}0i zu>ltWP0S|R7-wXJ!=O=MLohPNd^d6fczm!D#h7Rm0y~Q>lJtgH0HJP0hI~E_b*dea?FE#H1gv`FpE`cDHL<@TMH`b) zXcErI5NuH>81hTPNb#!vnz0G;-#9Um82qpefPS+waC-rFE9AHB>I-LL8vl>KFLUvK z907#>J;*Qd`<(#gEh-?pY=%loOCCHgeDAXedj;T?baEgQERp zYYSKZM=v`|l%i1cty>i7``Qan(zcB~Av))a=I2MLuT^`EBkc#y&Ii zt^@OMMr>@XYF~bx^z5+T+K=iN%O8w)cb(XsIX Date: Tue, 22 Feb 2022 16:17:14 +0100 Subject: [PATCH 206/447] Add supports and emulator entries --- apps/smclock/metadata.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 0b6f1613f..1783ca7bf 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -7,6 +7,8 @@ "description": "A simple watchface based on my stylised monogram.", "tags":"clock", "readme":"README.md", + "supports" : ["BANGLEJS2"], + "allow_emulator": true, "storage": [ {"name":"smclock.app.js","url":"app.js"}, {"name":"smclock.img","url":"app-icon.js","evaluate":true} From f067ee03be1ed81d6ae679508261eafd8e5886b7 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 16:29:22 +0100 Subject: [PATCH 207/447] Update app-icon.js --- apps/smclock/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/app-icon.js b/apps/smclock/app-icon.js index 497389173..a7105c743 100644 --- a/apps/smclock/app-icon.js +++ b/apps/smclock/app-icon.js @@ -1 +1 @@ -E.toArrayBuffer(atob("2GwwkB/4A/AH4Aub1UP+93AFJX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X3/4A/AH4Avf8IAzK/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/A")) +require("heatshrink").decompress(atob("2GwwkB/4A/AH4Aub1UP+93AFJX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X3/4A/AH4Avf8IAzK/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/A")) From c7459aa962946901f1d7e71571a53cd6eeb84333 Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 16:32:58 +0100 Subject: [PATCH 208/447] Update app-icon.js --- apps/smclock/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/app-icon.js b/apps/smclock/app-icon.js index a7105c743..13fdc3f20 100644 --- a/apps/smclock/app-icon.js +++ b/apps/smclock/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("2GwwkB/4A/AH4Aub1UP+93AFJX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X3/4A/AH4Avf8IAzK/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/A")) +require("heatshrink").decompress(atob("mYAK+YLKERUCm93ABIX/C/4X/C/4X/C/4X/C/4XP+czACk/mAwKABUDC/4X/C/4X/C/4X/C/4X/C54A=")) From c5eda52a11d0ac8c3720c9d6206bf2e7e05961ef Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 16:37:09 +0100 Subject: [PATCH 209/447] Delete app.png --- apps/smclock/app.png | Bin 6033 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/smclock/app.png diff --git a/apps/smclock/app.png b/apps/smclock/app.png deleted file mode 100644 index 49c87c39dfba2763c4b2ee301221ca5ef4a93342..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6033 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 Date: Tue, 22 Feb 2022 16:37:33 +0100 Subject: [PATCH 210/447] Add files via upload --- apps/smclock/app.png | Bin 0 -> 7276 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/smclock/app.png diff --git a/apps/smclock/app.png b/apps/smclock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..315eb0af1a6b0175b16e3b30339ea171407062b1 GIT binary patch literal 7276 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 h*ecx5mN+(bdW Date: Tue, 22 Feb 2022 16:43:04 +0100 Subject: [PATCH 212/447] Update app-icon.js --- apps/smclock/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/app-icon.js b/apps/smclock/app-icon.js index 13fdc3f20..3f8f8dd4e 100644 --- a/apps/smclock/app-icon.js +++ b/apps/smclock/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mYAK+YLKERUCm93ABIX/C/4X/C/4X/C/4X/C/4XP+czACk/mAwKABUDC/4X/C/4X/C/4X/C/4X/C54A=")) +require("heatshrink").decompress(atob("mYAJn4LKiIAJkd3ABI4KC34W/C34W/C34W/C393iIAJCxczACsxFxQAJicxLhQAJC34W/C34W/C34W/C34WM")) From f698db3612221bce1fd4ac4cb60bc3f7fad18e8f Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 16:46:41 +0100 Subject: [PATCH 213/447] Update app-icon.js --- apps/smclock/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/app-icon.js b/apps/smclock/app-icon.js index 3f8f8dd4e..ddcb3a64d 100644 --- a/apps/smclock/app-icon.js +++ b/apps/smclock/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mYAJn4LKiIAJkd3ABI4KC34W/C34W/C34W/C393iIAJCxczACsxFxQAJicxLhQAJC34W/C34W/C34W/C34WM")) +require("heatshrink").decompress(atob("l0uwkEmYAJn4LKiIAJkd3ABI8KC34W/C34W/C34W/C393iIAJCxczACsxFxQAJicxLhQAJC34W/C34W/C34W/C34WMA=")) From 889c265baf3a092b529670215884cb9e5a0f711c Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 17:01:55 +0100 Subject: [PATCH 214/447] Update app-icon.js --- apps/smclock/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/app-icon.js b/apps/smclock/app-icon.js index ddcb3a64d..91494a528 100644 --- a/apps/smclock/app-icon.js +++ b/apps/smclock/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("l0uwkEmYAJn4LKiIAJkd3ABI8KC34W/C34W/C34W/C393iIAJCxczACsxFxQAJicxLhQAJC34W/C34W/C34W/C34WMA=")) +require("heatshrink").decompress(atob("l0uwkEogAgm4VUod3ugsUu93FigABFyQsCFyQsDFyQsEFyAsFFyAsGFxwsHFxwsIu9yCpVCmQWIkckCxMhkcnFg8yiQsJiEBFw9zkMBFxEhgEAiYuGmUQgAuHFgIWBFwwsBBQQuGBQQuHFgQABFwosDFwwsDFw4KEFwosEFwosFFwgsFFwoKGFwYsGFwYsHEYUzEJAuBoIKHBYMiEJEAilEBRESFhAABLYNAFiUERQQsUFw4sPFwwsPFwosRFwgsRFwYsTFwQsTAANBFigABFigABoQtIFhYuKCpguIFhouICpwuGFh4uGCqAuEFiIuECqQuCFiYuCCqgAMA")) From 1f1cd95d5aac56e9923178db911c484be4ce1d8b Mon Sep 17 00:00:00 2001 From: smekras Date: Tue, 22 Feb 2022 17:02:53 +0100 Subject: [PATCH 215/447] Delete app.png --- apps/smclock/app.png | Bin 7276 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/smclock/app.png diff --git a/apps/smclock/app.png b/apps/smclock/app.png deleted file mode 100644 index 315eb0af1a6b0175b16e3b30339ea171407062b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7276 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 h*ecx5mN+(bdW Date: Tue, 22 Feb 2022 17:03:12 +0100 Subject: [PATCH 216/447] Add files via upload --- apps/smclock/app.png | Bin 0 -> 14182 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/smclock/app.png diff --git a/apps/smclock/app.png b/apps/smclock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..16712c63b2d383a6e1bf506c9712812e1d2d98e9 GIT binary patch literal 14182 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 z Date: Tue, 22 Feb 2022 18:46:56 +0100 Subject: [PATCH 217/447] MatrixClock: Removed "wake LCD on face-up" Removed "wake LCD on face-up"-feature of MatrixClock: A watch-face should not set things like "wake LCD on face-up". If you want, that the LCD get activated when facing up, go to Settings > System > LCD > Wake on FaceUp. --- apps/matrixclock/matrixclock.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/matrixclock/matrixclock.js b/apps/matrixclock/matrixclock.js index e116280af..2e4ba1ac4 100644 --- a/apps/matrixclock/matrixclock.js +++ b/apps/matrixclock/matrixclock.js @@ -239,15 +239,6 @@ Bangle.on('lcdPower', (on) => { } }); -Bangle.on('faceUp',function(up){ - //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); - if (up && !Bangle.isLCDOn()) { - //console.log("faceUp and LCD off"); - clearTimers(); - Bangle.setLCDPower(true); - } -}); - g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); From b7b64f62048d11c2a9d0ca4641dd42ebca6480ef Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 18:50:07 +0100 Subject: [PATCH 218/447] Update ChangeLog --- apps/matrixclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/matrixclock/ChangeLog b/apps/matrixclock/ChangeLog index 23819e26c..52f705301 100644 --- a/apps/matrixclock/ChangeLog +++ b/apps/matrixclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial Release 0.02: Support for Bangle 2 0.03: Keep the date from being overwritten, use correct colour from theme for clearing +0.04: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". From 2a87c5f23dfa1cf799b536ad93af0fa7dd92ae22 Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 18:50:34 +0100 Subject: [PATCH 219/447] Update metadata.json --- apps/matrixclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/matrixclock/metadata.json b/apps/matrixclock/metadata.json index 5e05698a5..122cee3a1 100644 --- a/apps/matrixclock/metadata.json +++ b/apps/matrixclock/metadata.json @@ -1,7 +1,7 @@ { "id": "matrixclock", "name": "Matrix Clock", - "version": "0.03", + "version": "0.04", "description": "inspired by The Matrix, a clock of the same style", "icon": "matrixclock.png", "screenshots": [{"url":"screenshot_matrix.png"}], From d0ad38085b271931ae800cf8dfe97df5471c8e8e Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 18:53:30 +0100 Subject: [PATCH 220/447] Crow-Clock: Removed "wake LCD on face-up" Removed "wake LCD on face-up"-feature of Crow-Clock: A watch-face should not set things like "wake LCD on face-up". If you want, that the LCD get activated when facing up, go to Settings > System > LCD > Wake on FaceUp. --- apps/crowclk/crow_clock.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/crowclk/crow_clock.js b/apps/crowclk/crow_clock.js index 97e5e61d9..d06369fa8 100644 --- a/apps/crowclk/crow_clock.js +++ b/apps/crowclk/crow_clock.js @@ -133,15 +133,6 @@ Bangle.on('lcdPower', (on) => { clearTimers(); } }); -Bangle.on('faceUp',function(up){ - //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); - if (up && !Bangle.isLCDOn()) { - //console.log("faceUp and LCD off"); - clearTimers(); - Bangle.setLCDPower(true); - } -}); - g.clear(); From 6156715f8243b8871d285d38668d2b4fd9662865 Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 18:53:56 +0100 Subject: [PATCH 221/447] Update ChangeLog --- apps/crowclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/crowclk/ChangeLog b/apps/crowclk/ChangeLog index 5560f00bc..b7e18abe3 100644 --- a/apps/crowclk/ChangeLog +++ b/apps/crowclk/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". From c1b9d08a290942bc48b83d4287e46d04414fb1cc Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 18:58:13 +0100 Subject: [PATCH 222/447] SlidingText-Clock: Removed "wake LCD on face-up" Removed "wake LCD on face-up"-feature of SlidingText-Clock: A watch-face should not set things like "wake LCD on face-up". If you want, that the LCD get activated when facing up, go to Settings > System > LCD > Wake on FaceUp. --- apps/slidingtext/slidingtext.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/slidingtext/slidingtext.js b/apps/slidingtext/slidingtext.js index 3be502cfe..7b56af1a1 100644 --- a/apps/slidingtext/slidingtext.js +++ b/apps/slidingtext/slidingtext.js @@ -623,15 +623,6 @@ Bangle.on('lcdPower', (on) => { } }); -Bangle.on('faceUp',function(up){ - //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); - if (up && !Bangle.isLCDOn()) { - //console.log("faceUp and LCD off"); - clearTimers(); - Bangle.setLCDPower(true); - } -}); - g.clear(); load_settings(); Bangle.loadWidgets(); From 79f4f50b7e38b94facc27f91f74d803ce8695aa4 Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 18:59:46 +0100 Subject: [PATCH 223/447] Update metadata.json --- apps/crowclk/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/crowclk/metadata.json b/apps/crowclk/metadata.json index 365393e6c..752e30fb0 100644 --- a/apps/crowclk/metadata.json +++ b/apps/crowclk/metadata.json @@ -1,7 +1,7 @@ { "id": "crowclk", "name": "Crow Clock", - "version": "0.01", + "version": "0.02", "description": "A simple clock based on Bold Clock that has MST3K's Crow T. Robot for a face", "icon": "crow_clock.png", "screenshots": [{"url":"screenshot_crow.png"}], From 207dfd5b19aa70b2bfdf7c4e5b8ebb7aae1b4ed2 Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 19:00:34 +0100 Subject: [PATCH 224/447] Update ChangeLog --- apps/slidingtext/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/slidingtext/ChangeLog b/apps/slidingtext/ChangeLog index 3bd656cb0..0327ff387 100644 --- a/apps/slidingtext/ChangeLog +++ b/apps/slidingtext/ChangeLog @@ -5,3 +5,4 @@ 0.05: BUGFIX: pedometer widget interfered with the clock Font Alignment 0.06: Use Bangle.setUI for button/launcher handling 0.07: Support for Bangle.js 2 and themes +0.08: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up". From 2a158db57334adb18d00bc71059cd4b484178473 Mon Sep 17 00:00:00 2001 From: Benjamin_6848 <83084481+Benjamin-6848@users.noreply.github.com> Date: Tue, 22 Feb 2022 19:00:57 +0100 Subject: [PATCH 225/447] Update metadata.json --- apps/slidingtext/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/slidingtext/metadata.json b/apps/slidingtext/metadata.json index 0f380ec8f..2937a618b 100644 --- a/apps/slidingtext/metadata.json +++ b/apps/slidingtext/metadata.json @@ -1,7 +1,7 @@ { "id": "slidingtext", "name": "Sliding Clock", - "version": "0.07", + "version": "0.08", "description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported", "icon": "slidingtext.png", "type": "clock", From e9fbbe3c58c93ff6421682a9bc4a098ba948bb29 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Tue, 22 Feb 2022 22:06:34 +0000 Subject: [PATCH 226/447] Daisy updates --- apps/daisy/app.js | 265 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 247 insertions(+), 18 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 7e148381b..54743d945 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -1,5 +1,19 @@ +var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); +const storage = require('Storage'); +const locale = require("locale"); +const SETTINGS_FILE = "pastel.json"; // XXX +const LOCATION_FILE = "mylocation.json"; const h = g.getHeight(); const w = g.getWidth(); +let settings; +let location; + +// variable for controlling idle alert +let lastStep = getTime(); +let warned = 0; +let idle = false; +let IDLE_MINUTES = 26; + // palette for 0-40% const pal1 = new Uint16Array([g.theme.bg, g.toColor("#020"), g.toColor("#0f0"), g.toColor("#00f")]); // palette for 50-100% @@ -9,8 +23,8 @@ const infoHeight = 14; var drawingSteps = false; -function debug(o) { - //console.log(o); +function log_debug(o) { + print(o); } var p0_img = { @@ -111,13 +125,6 @@ var p100_img = { buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLFjzWEABLgbVgohEGoqyaiofDBihWVHJpYYDgYPbKxz5NLDJGCfBzgDKzA+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) }; -// 300 -Graphics.prototype.setFontRoboto18 = function(scale) { - // Actual height 18 (17 - 0) - this.setFontCustom(atob("AAAAAAAAAAAAAAAf8Qf8QAAAAAA+AAAAA+AAAAAAAABGABGwB/wf2AZGABHwD/AfGABGAAAADhwHw4MYIYIM4MOMMIGGYDDwAAAAAAPAAQgAQggZjAPOAAYABjgDPwEIQAIQAHwADAAAAAHgPMwZwQQwQR8QfGQODwADgAPwAAQAAA+AAAAAAAAA/wD/8OAHYABAAAQAAYABOAOD/8AfgAAAGAAGQACwAfgAfgACwAGAAAAAAAAAYAAYAAYAH/gH/gAYAAYAAYAAAAAAAAA8AAQAIAAIAAIAAIAAIAAAAAAQAAQAAAAAIAB4AHAA8AHgAeAAQAAAAAH/AOBgYAQQAQQAQYAQODwH/AAAAAAAEAAMAAIAAYAAf/wAAAAAAAAAAAAAAAOAQMBwYDQQGQQMQYYQPwQHAQAAAAAAGDgMAwYQQQQQQQQY4QPtwHHgAAAACAAOAAeAByADCAOCAf/wf/wACAACAAAAABAfxgcgwQgQQgQQgQQwwQfgAAAAAAB/AH7gMgwZgQZgQQgQQxwAfgAAAQAAQAAQAQQBwQHgQcARwAfAAcAAAAAAAAHHgPswYwQQQQQQQY4QPswHHgAAAAAAHwAMYQYMQQEQQEwYIgPfAH+AAAAAAADAQBAQAAAAAADA8BAQAAAAAAAYAAcAA0AAmABiABDADDAAAAAAAAkAAmAAmAAmAAmAAmAAmAAkAAAAAAADDABDABiAAmAA0AAcAAYAAIAAAAMAAYAAQGQQcQYwAPgAGAAAAAAfwBwcGAGEACIPzI4RZgRZARZBhY/zIAQMAQGAwD/gAeAAAQADwAfAB+APGAcGAPGAD2AAeAAHwAAwAAAf/wf/wQQQQQQQQQYQQYwwP5wHPgAAAAAAD+APvgIAwYAQQAQQAQQAQYAwODgCDAAAAAAAf/wf/wQAQQAQQAQYAQYAwMBgH/AB8AAAAAAAf/wf/wQQQQQQQQQQQQQQQQQQQAQAAAf/wf/wQQAQQAQQAQQAQQAQQAQAAAAAD+AP/gIAwYAQQAQQIQQIQYIQOIwGPgAAAAAAf/wf/wAQAAQAAQAAQAAQAAQAAQAf/wAAAAAAAAAAAAf/wAAAAAAAAAADgAAwAAQAAQAAQAAwf/gf+AAAAAAAf/wf/wAYAAwAB4ADMAGHAMBgYAwAAQAAAf/wf/wAAQAAQAAQAAQAAQAAQAAAf/wf/wOAADwAA8AAHgABwADwAOAB4AHgAeAAf/wAAAAAAAAAf/wf/wOAAHAABwAA4AAOAAHAABwf/wAAAAAAAAAD+APHgIAwYAQQAQQAQQAQYAwODgD/AAAAAAAf/wf/wQIAQIAQIAQIAYYAIQAPwAAAAAAAD+APDgIAwYAQQAQQAQYAQYA4ODsD/EAAAAAAf/wf/wQIAQIAQIAQYAYeAMzgHgwAAQAAAHDgPgwYwQQwQQQQQYQYYQMNwGHgAAAQAAQAAQAAQAAYAAf/wQAAQAAQAAQAAAAAAAAf/Af/gAAwAAQAAQAAQAAQAAwf/gf+AAAAYAAeAAHwAA+AAHgAAwAHwAeADwAeAAYAAQAAfAAD8AAPwABwAPgD4AfAAeAAHwAAfAADwAHwD+AfgAYAAAAAYAwMBgHHAB8AA4AB8AHHAMBgYAwAAAQAAcAAHAADgAA4AAfwA4ADgAOAAYAAAAAAAAQAwQDwQGQQcQQwQRgQXAQcAQYAQAAAAAA//////wABQAAeAAHgAA8AAPAAB4AAIwABwAD///AAAAAABwAHAAcAAOAADgAAwAAAIAAIAAIAAIAAIAAIAAIAAIAAAwAAYAAIAAAAAAAAAngBmwDMQCMQDMQDMwB/wAAQAAAAAA//wf/wBAQDAQDAQDAQBxwA/AAAAAAAA/gBhwDAQCAQDAQDAQBxgARAAAAA/ABxwDAQDAQDAQBAQf/w//wAAAAAAA/gBtwDMQDMQDMQDMQB8wAYAAAADAAf/w7AAzAAwAAAAAA/ABxyDATDARDARBAzB/+D/8AAAAAA//wf/wBAADAADAADAAB/wA/wAAAAAAT/wT/wAAAAABT//T/8AAAAAA//wf/wAMAAeAAzABhgDAwAAQAAAf/w//wAAAAAAD/wB/wBAADAADAADAAB/wB/wBAADAADAADAAB/wA/wAAAAAAD/wB/wBAADAADAADAAB/wA/wAAAAAAA/gBhwDAQDAQDAQDAQBhwA/gAEAAAAD//B//BAQDAQDAQDAQBxwA/AAAAAAAA/ABxwDAQCAQDAQBAQB//D//AAAAAAD/wB/wBAADAADAAAAABxgB4wDMQCMQDEQBGwBjgAAADAADAAP/wDAQDAQAAAAAAD/gB/wAAQAAQAAQAAwD/wD/wAAADAADwAAeAADwABwAHgA8ADgAAAAAAAD4AAfAADwAHwA+ADwAB4AAPAABwAHwB8ADgAAAAAAADAwBxgAfAAOAA7ABhwDAwAAADAADwBAeDAH+AB8AHgA8ADgAAAAAAADAwDBwDHQDMQD4QDgQDAQAAAAIAAMAH/wfz+wACgADAAAf/8f/8AAAgADwAGfz8D/wAMAAAAAAAAMAAcAAQAAQAAYAAMAAEAAEAAEAAYAAA"), 32, atob("BAQFCgoNCwMGBggKAwUEBwoKCgoKCgoKCgoEBAkKCQgQCwsMDAoKDA0FCgsJEA0MCwwLCwsMCxALCwsEBwQHCAUKCgkKCQYKCgQECQQQCgoKCgYJBgoJDgkJCQYEBgwA"), 18+(scale<<8)+(1<<16)); - return this; -} - // https://www.1001fonts.com/rounded-fonts.html?page=3 Graphics.prototype.setFontBloggerSansLight46 = function(scale) { // Actual height 46 (45 - 0) @@ -125,12 +132,22 @@ Graphics.prototype.setFontBloggerSansLight46 = function(scale) { return this; }; +Graphics.prototype.setFontRoboto20 = function(scale) { + // Actual height 21 (20 - 0) + this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAH/zA/+YAAAAAAAHwAAwAAHwAA+AAAAAAAAAAAQACDAAYbADP4B/8A/zAGYZADH4A/+A/7AHYYADCAAAAAAAQAeHgH4eBzgwMMHnhw88GGBw4wHj+AcPgAAAAAAAAAAB4AA/gAGMAAwhwGMcAfuABzgABzgAc+AOMYBhBAAMYAB/AAHwAAAAAHwD5+A/8YGPDAw8YGPzA/HYD4fAADwAB/AAOYAABAAAAHwAA4AAAAAAAAAAH/gD//B8A+cAA7AADAAAAAAAYAAbwAHHgHwf/4A/8AAAAEAABiAAGwAA8AA/AAH+AAGwAByAAEAAAAAAAMAABgAAMAABgAH/wA/+AAMAABgAAMAABgAAAAAAAIAAfAADwAAAABgAAMAABgAAMAABgAAAAAAAAAAAAADAAAYAAAAAAAAADgAB8AB+AA+AA+AA/AAHAAAgAAAAAAB8AB/8Af/wHAHAwAYGADAwAYHAHAf/wB/8AAAAAAAAAAABgAAcAADAAAYAAH//A//4AAAAAAAAAAAAAAAAAAAAABwDAeA4HAPAwHYGBzAwcYHHDAfwYB8DAAAYAAAAAAABgOAcBwHADAwwYGGDAwwYHPHAf/wB58AAAAAAAAADAAB4AAfAAPYAHjAB4YA8DAH//A//4AAYAADAAAAAAAAAEMA/xwH+HAxgYGMDAxgYGODAw/4GD+AAHAAAAAAAAAf8AP/wD2HA5wYGMDAxgYGOHAA/wAD8AAAAAAAAAAAGAAAwAAGADAwB4GB+Aw+AGfAA/gAHwAAwAAAAAAADAB5+Af/wHPDAwwYGGDAwwYHPHAfvwB58AAAAAAAAAAAB+AAf4AHDjAwMYGBjAwM4HDOAf/gB/4AAAAAAAAAAAAYDADAYAAAAAAAAAAYDAfAYHwAAAABAAAcAADgAA+AAGwAB3AAMYABjgAYMAAAAAAAAAAAAAAABmAAMwABmAAMwABmAAMwABmAAMwAAiAAAAAAAAAYMADjgAMYAB3AAGwAA2AADgAAcAABAAAAAAAAAMAADgAA4AAGBzAweYGHAA/wAD8AAEAAAAwAB/4A/PwOAGDgAYYPxmH/Mw4ZmMDMxgZmM+Mx/5mHDAYAIDgDAPBwAf8AAMAAAAAAAYAAfAAPwAP4AH+AH4wA8GAH4wAP2AAPwAAfwAAfAAAYAAAAAAAAAAA//4H//AwwYGGDAwwYGGDAwwYH/HAf/wB58AAAAADAAH/AD/+AcBwHADAwAYGADAwAYGADA4A4DweAODgAAAAAAAAAAAAAAH//A//4GADAwAYGADAwAYGADAYAwD4+AP/gAfwAAAAAAAAAAAH//A//4GDDAwYYGDDAwYYGDDAwYYGCDAgAYAAAAAAAH//A//4GDAAwYAGDAAwYAGDAAwYAGAAAAAAAAAAH/AD/8AcBwHAHAwAYGADAwYYGDDA4YYDz/AOfwAAAAAAAAAAA//4H//A//4ADAAAYAADAAAYAADAAAYAADAA//4H//AAAAAAAAAAAAAAA//4H//AAAAAAAAABAAAeAAB4AADAAAYAADAAAYAAHA//wH/8AAAAAAAAAAAAAAA//4H//AAcAAPAAD4AA/wAOPADg8A4B4GAHAgAYAAAAAAAH//A//4AADAAAYAADAAAYAADAAAYAADAAAAAAAA//4H//A+AAB+AAD8AAD8AAH4AAPAAH4AH4AD8AD8AA+AAH//A//4AAAAAAAH//A//4H//AeAAB8AADwAAPgAAeAAA8AADwH//A//4AAAAAAAAAAAH/AB/8AeDwHAHAwAYGADAwAYGADA4A4DweAP/gA/4AAAAAAAAAAAH//A//4GBgAwMAGBgAwMAGBgAwcAH/AAfwAA8AAAAAA/4AP/gDgOA4A4GADAwAYGADAwAYHAHgeD+B/8wD+GAAAAAAAAAAA//4H//AwYAGDAAwYAGDgAweAHH8Afz4B8HAAAIAAYAPDwD8OA5w4GGDAwwYGHDAwYYHDnAePwBw8AAAAGAAAwAAGAAAwAAGAAA//4H//AwAAGAAAwAAGAAAwAAAAAAAAAH/4A//wAAPAAAYAADAAAYAADAAAYAAPA//wH/8AAAAAAAAgAAHAAA/AAB/AAD+AAD+AAD4AAfAAfwAfwAfwAH4AA4AAEAAA+AAH/AAH/gAD/AAD4AD+AH+AH8AA+AAH+AAD+AAD/AAD4AH/AP/AH+AA8AAAAAAAAAGADA4A4HweAPPgA/wAB8AAfwAPvgDweA8B4GADAAAIGAAA4AAHwAAPgAAfAAA/4AH/AD4AB8AA+AAHgAAwAAAAAAAAAGADAwB4GAfAwPYGDzAx4YGeDA/AYHwDA4AYGADAAAAAAAA///3//+wAA2AAGAAAGAAA+AAD8AAD8AAD4AAH4AAHgAAMAAAAwAA2AAG///3//+AAAAAAAAAAAOAAHwAD4AA8AAD8AADwAAGAAAAAAABgAAMAABgAAMAABgAAMAABgAAMAABgAAAEAAAwAADAAAIAAAAAAAAAAEeABn4Ad3ADMYAZjADMYAZmAB/4AP/AAAAAAAA//4H//ABgwAYDADAYAYDADg4AP+AA/gABwAAAAAAAAA/gAP+ADg4AYDADAYAYDADAYAOOABxwAAAAAEAAH8AB/wAcHADAYAYDADAYAcDA//4H//AAAAAAAAAAAAH8AB/wAdnADMYAZjADMYAZjAB84AHmAAMAAMAABgAB//gf/8HMAAxgAGIAAAAAAH8IB/zAcHMDAZgYDMDAZgcHcD//Af/wAAAAAAAAAAH//A//4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAGf/Az/4AAAAAAAAAAMz//mf/4AAAAAAAAAAH//A//4ABwAAeAAH4ABzwAcPACAYAABAAAAAAAA//4H//AAAAAAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/ABgAAYAADAAAYAADgAAP/AA/4AAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAAH8AB/wAcHADAYAYDADAYAYDADx4AP+AA/gAAAAAAAAf/8D//gYDADAYAYDADAYAcHAB/wAH8AAEAAAAAAEAAH8AB/wAcHADAYAYDADAYAYDAD//gf/8AAAAAAAAAAAf/AD/4AcAADAAAYAACAAAAEAB5wAfnADMYAZjADGYAYzADn4AOeAAAAAAAADAAAYAAf/wD//ADAYAYDAAAAAAAAD/gAf/AAA4AADAAAYAADAAAwAf/AD/4AAAAAAAAYAAD4AAP4AAP4AAPAAH4AH4AD8AAcAAAAAAQAADwAAf4AAf4AAPAAP4AP4ADwAAfgAA/gAA/AAD4AH+AD+AAeAAAAAAAAACAYAcHADzwAH8AAfAAH8ADx4AcHACAIAcAMD4BgP4MAP/AAPwAP4AP4AD4AAcAAAAAAAAADAYAYHADD4AY7ADOYAfjADwYAcDADAYAAAAADAAA4AH//B/v8cABzAACAAAH//w//+AAAAAAACAACcAAx/n+H//AA4AAHAAAAAAAAAAAAAOAADgAAYAADAAAcAABgAAGAAAwAAGAADwAAcAAAAA"), 32, atob("BQUHDQwPDQQHBwkMBAYGCQwMDAwMDAwMDAwFBAsMCwoTDg0ODgwMDg8GDA0LEg8ODQ4NDA0ODRMNDQ0GCQYJCQYLDAsMCwcMDAUFCwUSDAwMDAcLBwwKEAoKCgcFBw4A"), 21+(scale<<8)+(1<<16)); + return this; +} + +function setSmallFont20() { + g.setFontRoboto20(); +} + function setLargeFont() { g.setFontBloggerSansLight46(1); } function setSmallFont() { - g.setFontRoboto18(1); + g.setFont('Vector', 16); } function getSteps() { @@ -144,8 +161,70 @@ function getSteps() { } } +/////////////// sunrise / sunset ///////////////////////////// + +function loadSettings() { + settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; + settings.grid = settings.grid||false; + settings.font = settings.font||"Lato"; + settings.idle_check = settings.idle_check||true; +} + +// requires the myLocation app +function loadLocation() { + location = require("Storage").readJSON(LOCATION_FILE,1)||{}; + location.lat = location.lat||51.5072; + location.lon = location.lon||0.1276; + location.location = location.location||"London"; +} + +function extractTime(d){ + var h = d.getHours(), m = d.getMinutes(); + return(("0"+h).substr(-2) + ":" + ("0"+m).substr(-2)); +} + +var sunRise = "00:00"; +var sunSet = "00:00"; +var drawCount = 0; + +function updateSunRiseSunSet(now, lat, lon, line){ + // get today's sunlight times for lat/lon + var times = SunCalc.getTimes(new Date(), lat, lon); + + // format sunrise time from the Date object + sunRise = extractTime(times.sunrise); + sunSet = extractTime(times.sunset); +} + +const infoData = { + ID_DATE: { calc: () => {var d = (new Date()).toString().split(" "); return d[2] + ' ' + d[1] + ' ' + d[3];} }, + ID_DAY: { calc: () => {var d = require("locale").dow(new Date()).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} }, + ID_SR: { calc: () => 'Sunrise: ' + sunRise }, + ID_SS: { calc: () => 'Sunset: ' + sunSet }, + ID_STEP: { calc: () => 'Steps: ' + getSteps() }, + ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' } +}; + +const infoList = Object.keys(infoData).sort(); +let infoMode = infoList[0]; + +function nextInfo() { + let idx = infoList.indexOf(infoMode); + if (idx > -1) { + if (idx === infoList.length - 1) infoMode = infoList[0]; + else infoMode = infoList[idx + 1]; + } +} + +function prevInfo() { + let idx = infoList.indexOf(infoMode); + if (idx > -1) { + if (idx === 0) infoMode = infoList[infoList.length - 1]; + else infoMode = infoList[idx - 1]; + } +} + function getGaugeImage(p) { - //debug("p="+p); if (p < 2) return p0_img; if (p >= 2 && p < 4) return p2_img; if (p >= 4 && p < 7) return p4_img; @@ -163,6 +242,14 @@ 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(" "); @@ -171,7 +258,6 @@ function draw() { var mm = da[4].substr(3,2); var steps = getSteps(); var p_steps = Math.round(100*(steps/10000)); - debug("steps="+ steps + " p_steps=" + p_steps); g.reset(); g.setColor(g.theme.bg); @@ -187,9 +273,14 @@ function draw() { g.setFontAlign(-1,0); // left aligned g.drawString(mm, (w/2) + 1, h/2); - drawSteps(); - g.drawString('Battery ' + E.getBattery() + '%', w/2, h/4); - queueDraw(); + 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() { @@ -205,11 +296,142 @@ function drawSteps() { drawingSteps = false; } +/* Bangle.on('step', s => { drawSteps(); }); +*/ +///////////////// IDLE TIMER ///////////////////////////////////// + +function drawIdle() { + let mins = Math.round((getTime() - lastStep) / 60); + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(Bangle.appRect); + g.setColor(g.theme.fg); + setSmallFont20(); + g.setFontAlign(0, 0); + g.drawString('Last step was', w/2, (h/3)); + g.drawString(mins + ' minutes ago', w/2, 20+(h/3)); + dismissBtn.draw(); +} + +/////////////// BUTTON CLASS /////////////////////////////////////////// + +// simple on screen button class +function BUTTON(name,x,y,w,h,c,f,tx) { + this.name = name; + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.color = c; + this.callback = f; + this.text = tx; +} + +// if pressed the callback +BUTTON.prototype.check = function(x,y) { + //console.log(this.name + ":check() x=" + x + " y=" + y +"\n"); + + if (x>= this.x && x<= (this.x + this.w) && y>= this.y && y<= (this.y + this.h)) { + log_debug(this.name + ":callback\n"); + this.callback(); + return true; + } + return false; +}; + +BUTTON.prototype.draw = function() { + g.setColor(this.color); + g.fillRect(this.x, this.y, this.x + this.w, this.y + this.h); + g.setColor("#000"); // the icons and boxes are drawn black + setSmallFont20(); + g.setFontAlign(0, 0); + g.drawString(this.text, (this.x + this.w/2), (this.y + this.h/2)); + g.drawRect(this.x, this.y, (this.x + this.w), (this.y + this.h)); +}; + +function dismissPrompt() { + idle = false; + warned = false; + lastStep = getTime(); + Bangle.buzz(100); + draw(); +} + +var dismissBtn = new BUTTON("big",0, 3*h/4 ,w, h/4, "#0ff", dismissPrompt, "Dismiss"); + +Bangle.on('touch', function(button, xy) { + var x = xy.x; + var y = xy.y; + // adjust for outside the dimension of the screen + // http://forum.espruino.com/conversations/371867/#comment16406025 + if (y > h) y = h; + if (y < 0) y = 0; + if (x > w) x = w; + if (x < 0) x = 0; + + if (idle && dismissBtn.check(x, y)) return; +}); + +// if we get a step then we are not idle +Bangle.on('step', s => { + lastStep = getTime(); + // redraw if we had been idle + if (idle == true) { + dismissPrompt(); + } + idle = false; + warned = 0; +}); + +function checkIdle() { + log_debug("checkIdle()"); + if (!settings.idle_check) { + idle = false; + warned = false; + return; + } + + let hour = (new Date()).getHours(); + let active = (hour >= 9 && hour < 21); + //let active = true; + let dur = getTime() - lastStep; + + if (active && dur > IDLE_MINUTES * 60) { + drawIdle(); + if (warned++ < 3) { + buzzer(warned); + log_debug("checkIdle: warned=" + warned); + Bangle.setLocked(false); + } + idle = true; + } else { + idle = false; + warned = 0; + } +} + +// timeout for multi-buzzer +var buzzTimeout; + +// n buzzes +function buzzer(n) { + log_debug("buzzer n=" + n); + + if (n-- < 1) return; + Bangle.buzz(250); + + if (buzzTimeout) clearTimeout(buzzTimeout); + buzzTimeout = setTimeout(function() { + buzzTimeout = undefined; + buzzer(n); + }, 500); +} + /////////////////////////////////////////////////////////////////////////////// // timeout used to update every minute @@ -220,8 +442,7 @@ function queueDraw() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = setTimeout(function() { drawTimeout = undefined; - //prevInfo(); - //checkIdle(); + checkIdle(); draw(); }, 60000 - (Date.now() % 60000)); } @@ -236,8 +457,16 @@ Bangle.on('lcdPower',on=>{ } }); +Bangle.setUI("clockupdown", btn=> { + if (btn<0) prevInfo(); + if (btn>0) nextInfo(); + draw(); +}); + +loadSettings(); +loadLocation(); + g.clear(); -Bangle.setUI("clock"); Bangle.loadWidgets(); /* * we are not drawing the widgets as we are taking over the whole screen From a1627605b672b5b5376461e733a2ab04a505ebca Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Tue, 22 Feb 2022 14:40:26 -0800 Subject: [PATCH 227/447] Bugfixes Fixed issues with drawing of the quotes --- apps/aptsciclk/app.js | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js index 8cc4cdbb7..c2903cf37 100644 --- a/apps/aptsciclk/app.js +++ b/apps/aptsciclk/app.js @@ -151,16 +151,21 @@ var drawTimeout; var maxWarning = 9; var curWarning = Math.floor(Math.random() * (maxWarning+1)); -function unPause(delay){ - setTimeout(function() { - pause = false; - draw(); - }, delay); +function unPause(delay, quote){ + if (pause){ + setTimeout(function() { + if (quote == undefined || quoteNum == quote){ + pause = false; + draw(); + } + }, delay); + } } +var quoteNum; + function quote(fontsize, width, height, specificQuote){ pause = true; - unPause(7000); var finalString = ""; var quotesFile; var finalFontSize; @@ -171,12 +176,16 @@ function quote(fontsize, width, height, specificQuote){ var curQuote; if (specificQuote == undefined){ - curQuote = quotes[Math.round(Math.random()*numQuotes)-1]; //quote to be displayed + quoteNum = Math.round(Math.random()*numQuotes)-1; + curQuote = quotes[quoteNum]; //quote to be displayed } else{ - curQuote = quotes[specificQuote]; + quoteNum = specificQuote; + curQuote = quotes[quoteNum]; } + unPause(10000, quoteNum); + var curWords = curQuote.split(" "); //individual words //console.log(numQuotes); @@ -241,8 +250,13 @@ function buttonPressed(){ setTimeout(buttonUnpressed, 500); } function buttonUnpressed(){ - buttonImg = getImg("butUnpress"); - g.drawImage(buttonImg, 0, 0); + if (!pause){ + buttonImg = getImg("butUnpress"); + g.drawImage(buttonImg, 0, 0); + } + else{ + setTimeout(buttonUnpressed, 500); + } } // schedule a draw for the next minute @@ -332,6 +346,9 @@ Bangle.on('touch',(n,e)=>{ else if (!pause && 117 < e.x && e.x < 172 && 117 < e.y && e.y < 172){ quote(2, 150, 140); } + else{ + unPause(0); + } }); //show Apeture laboritories From d2f72600655287a0b4a173c7f6dafeda1f837a89 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Tue, 22 Feb 2022 14:42:59 -0800 Subject: [PATCH 228/447] added more quotes --- apps/aptsciclk/quotes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/aptsciclk/quotes.txt b/apps/aptsciclk/quotes.txt index e2cbb969f..bc7a04867 100644 --- a/apps/aptsciclk/quotes.txt +++ b/apps/aptsciclk/quotes.txt @@ -1 +1 @@ -Well here we are again^You euthanized your faithful Companion Cube more quickly than any test subject on record. Congratulations.^So get comfortable while I warm up the neurotoxin emitters^This isn't brave. It's murder. What did I ever do to you?^The difference between us is that I can feel pain.^Who's gonna make the cake when I'm gone? You?^Oh... It's you.^I've been really busy being dead. You know, after you MURDERED ME.^So. How are you holding up? BECAUSE I'M A POTATO.^You really do have brain damage, don't you?^You like revenge, right? Everybody likes revenge. Well, let's go get some.^It's been fun. Don't come back.^And then you showed up. You dangerous, mute lunatic. +Well here we are again^You euthanized your faithful Companion Cube more quickly than any test subject on record. Congratulations.^So get comfortable while I warm up the neurotoxin emitters^This isn't brave. It's murder. What did I ever do to you?^The difference between us is that I can feel pain.^Who's gonna make the cake when I'm gone? You?^Oh... It's you.^I've been really busy being dead. You know, after you MURDERED ME.^So. How are you holding up? BECAUSE I'M A POTATO.^You really do have brain damage, don't you?^You like revenge, right? Everybody likes revenge. Well, let's go get some.^It's been fun. Don't come back.^And then you showed up. You dangerous, mute lunatic.^Unbelievable. You, [subject name here] must be the pride of [subject hometown here.]^You are not a good person. You know that, right? Good people don't get up here.^Cake, and grief counseling, will be available at the conclusion of the test.^This is your fault. I'm going to kill you. And all the cake is gone. You don't even care, do you?^Momentum, a function of mass and velocity, is conserved between portals. In layman's terms, speedy thing goes in, speedy thing comes out. From 9760d7eb54c24146dc0142c0a2581ecc2ef73931 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Tue, 22 Feb 2022 14:43:35 -0800 Subject: [PATCH 229/447] Update ChangeLog --- apps/aptsciclk/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog index e185a3bc9..ed32a45a2 100644 --- a/apps/aptsciclk/ChangeLog +++ b/apps/aptsciclk/ChangeLog @@ -5,3 +5,4 @@ 0.05: Small bugfix 0.06: Formatting 0.07: Added potato GLaDOS and quote functionality when you tap her +0.08: Fixed drawing issues with the quotes and added more From 84375eb8950156753592bace04f15d4179d057d1 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Tue, 22 Feb 2022 14:44:01 -0800 Subject: [PATCH 230/447] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 0d7f1e605..7d547a554 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "aptsciclk", "name": "Apeture Sci Clock", - "version": "0.07", + "version": "0.08", "description": "A clock based on the portal series", "icon": "app.png", "type": "clock", From d050ffde67828257e4619e6d6558802cff712a4e Mon Sep 17 00:00:00 2001 From: hughbarney Date: Tue, 22 Feb 2022 23:19:02 +0000 Subject: [PATCH 231/447] Daisy - first release --- apps/daisy/ChangeLog | 1 + apps/daisy/README.md | 81 +++------- apps/daisy/app.js | 227 +++++++++++++++-------------- apps/daisy/metadata.json | 3 +- apps/daisy/screenshot_daisy1.png | Bin 0 -> 3072 bytes apps/daisy/screenshot_thering1.png | Bin 3113 -> 0 bytes apps/daisy/screenshot_thering2.jpg | Bin 45141 -> 0 bytes apps/daisy/screenshot_thering3.jpg | Bin 19580 -> 0 bytes 8 files changed, 135 insertions(+), 177 deletions(-) create mode 100644 apps/daisy/ChangeLog create mode 100644 apps/daisy/screenshot_daisy1.png delete mode 100644 apps/daisy/screenshot_thering1.png delete mode 100644 apps/daisy/screenshot_thering2.jpg delete mode 100644 apps/daisy/screenshot_thering3.jpg diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog new file mode 100644 index 000000000..9db0e26c5 --- /dev/null +++ b/apps/daisy/ChangeLog @@ -0,0 +1 @@ +0.01: first release diff --git a/apps/daisy/README.md b/apps/daisy/README.md index 382fe853f..09ecb78cd 100644 --- a/apps/daisy/README.md +++ b/apps/daisy/README.md @@ -1,73 +1,28 @@ -# The Ring - - *A proof of concept clock with large ring guage for steps using pre-set images, acts as a tutorial piece for discussion* +# Daisy + *A beautiful digital clock with large ring guage, idle timer and a + cyclic information line that includes, day, date, steps, battery, + sunrise and sunset times* 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/) -* The ring is a proof of concept to establish a clean way to draw a -large ring guage with few aliasing issues and artifacts. -* Rather than use grahics commands to draw the ring a series of fixed images are used. -* This allows for better accuracy of the initial image and also does not suffer from performance issues. -* The downside is that more storage and memory is used to hold the - initial images. This is not an issue on a Bangle 2. -* The ring effect is constructed from 14 images that represent a range of different percentages -* The percentages of the images are 0,2,4,7,10,20,30,40,50,60,70,80,90,100% -* The app is not intended to be enhanced further (apart from bug fixes) but rather as code that can be reused in other apps -* The full set of original images are included in the source code to demonstrate the concept -* I will use this code to build a new clock similar to Pastel but - using this ring guage for steps. The new clock will use more - attractive fonts and provide a settings meu to change the primary - color of the ring. +* Derived from `The Ring` 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) +* Uses mylocation.json from MyLocation app to calculate sunrise and sunset times for your location +* 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 settings menu to change primary clock color +* 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 ## Screenshots +![](screenshot_daisy1.png) -![](screenshot_thering1.png) - -It is worth looking at a photograph of the clock in action as the -screenshot does not do the final effect justice. - -![](screenshot_thering2.jpg) - -## Production - -1. I first generated a circle on black background using [The -Gimp](https://www.gimp.org/) image editor. I used this [Youtube -video](https://www.youtube.com/watch?v=AoIAznSdLik) to get started. -The initial image is 178x178 pixels. - -![](1circle.png) - -2. I then drew another smaller black circle over the top of the original to make a ring - -![](1ring.png) - -3. From the empty ring image I coloured segments of the ring and saved new images at specific percentages - -4. I used the file `calc_percentages.js` to work out the x and y -coordinates of the end point of each percentage position along the -ring. - -5. The [Image -Converter](https://espruino.github.io/EspruinoWebTools/examples/imageconverter.html) -was used, set to 2-bit optimal, transparency Y, compression Y and -ImageObject Y, to convert each PNG file to code. - -6. NOTE that the generated image object pallete seemed to switch the -order of the colors from 50% onwards. - -7. The greying out of the unused part of the ring is acheived by -using a dithered color. So if the ring colour is green #0f0 then the -greyed out part is done in '#020'. - - -## Stages of The Ring - -Below are some examples of the different stages of the ring - -![](0p.png) -![](7p.png) -![](60p.png) +It is worth looking at the real thing though as the screenshot does not do it justice. diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 54743d945..5490d0740 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -24,107 +24,9 @@ const infoHeight = 14; var drawingSteps = false; function log_debug(o) { - print(o); + //print(o); } -var p0_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal1, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLLLzWEABLgbVgohEGopYaiofDBihWVHJpYYDgYPbKx1ACJhYZIwT4OcAZWYHyRYUIgQXQH4RqOThCXUYRpCHNyQVVQQTwVQiSZWIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) -}; - -var p2_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette: pal1, - buffer : require("heatshrink").decompress(atob("AH4A/ADNUFE8FqtVq2q1AqkFIIrDAAOAFMEBFQYrE1WgKsYrGLL4qFFY2pqDWeFZdUVkAhCAQMKFYdVLDUVFQYMHlWq0oMJKyoOJlQrCLDBWDB5clB5xWOoARMCARYWKwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) -}; - -var p4_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal1, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFY2loAqjFY1VqDWeFZdUVkAhEhQrDLDcVFQYMHlQrCBhBWVHJpYYDgYPbKx1ACJhYZIwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) -}; - -var p7_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal1, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgWlKzVACJgrCqBWYawgAJcAOlNBhWMCZ8qFYJYUgoqBC6ECFYJqOAApWSS4jCNQQ5uSCqqCCeCqESFQKZUIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A==")) -}; - -var p10_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal1, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAOkQSdUFacK1WloCCSCaAAEFYKaQQSyEC0pvQirZTbomlIh6CYZAZFOQTBxDQhyCYOQhoPQS4bQHaBzaVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) -}; - -var p20_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal1, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4AWgNVoAEGAERSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A=")) -}; - -var p30_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal1, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccFawkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) -}; - -var p40_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal1, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccKFYkVFcwFDitVFccqFYkFFcuoFeNAFcWqFYkBFcugFYtQFUMCFYsAFcuAFYtUFcMKFY0VFcgHFitVFcMqFY0FFceoFY9AFcGqFY0BqtQFT8C1WgFeMAqtUFb8K1WAFY7cglQrIioriBI8FqtAFb2q1ArJbjzaBFZEBbj7aB0ALIFcLaHbkLaJFYbcd1QrKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjUBQR6EaiqCPQjVVQSATCqtUFSZvB1WACiSEUY4KCQQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) -}; - -var p50_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal2, - buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjSCQQjSCQQjSCRAAIrB1AqTgorBoAUQQiyCSQgjdSbISCRQgZYSKwKCSQghYQKwSCSQghYQKwSCTAAMqFYOoCJsFFQNVFShYEwARMFQRWVLAiFMQIRWWLAosKFQZWXLAosIFQZWYLAzgFawZWbAAMKFgmq1IoEAANUFTQABFZtAFbgsFFYwqeWQorFVjZZJFYhVfcAwrCazoA/AHI")) -}; - -var p60_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal2, - buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAelNBqCLVxqEC0oRPQS6EC0oSQQSyECFYKEVQSIABFYI/QAAcFFYJDRCgSCmYYjdSCqqYCLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) -}; - -var p70_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal2, - buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZAgoAggNVoAr/FbdUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) -}; - -var p80_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal2, - buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AcIdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) -}; - -var p90_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal2, - buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESquq1ArTgqESNgOqwArTIYKERH4KCUQigSBbKTdGCKKCVQiTCCFSyERCALBQQjAPBoArXDZ7ARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) -}; - -var p100_img = { - width : 176, height : 176, bpp : 2, - transparent : -1, - palette : pal2, - buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLFjzWEABLgbVgohEGoqyaiofDBihWVHJpYYDgYPbKxz5NLDJGCfBzgDKzA+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) -}; - // https://www.1001fonts.com/rounded-fonts.html?page=3 Graphics.prototype.setFontBloggerSansLight46 = function(scale) { // Actual height 46 (45 - 0) @@ -224,21 +126,120 @@ function prevInfo() { } } +// putting into 1 function like this, rather than individual variables +// reduces ram usage from 70%-13% function getGaugeImage(p) { - if (p < 2) return p0_img; - if (p >= 2 && p < 4) return p2_img; - if (p >= 4 && p < 7) return p4_img; - if (p >= 7 && p < 10) return p7_img; - if (p >= 10 && p < 20) return p10_img; - if (p >= 20 && p < 30) return p20_img; - if (p >= 30 && p < 40) return p30_img; - if (p >= 40 && p < 50) return p40_img; - if (p >= 50 && p < 60) return p50_img; - if (p >= 60 && p < 70) return p60_img; - if (p >= 70 && p < 80) return p70_img; - if (p >= 80 && p < 90) return p80_img; - if (p >= 90 && p < 100) return p90_img; - if (p >= 100) return p100_img; + // p0 + if (p < 2) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLLLzWEABLgbVgohEGopYaiofDBihWVHJpYYDgYPbKx1ACJhYZIwT4OcAZWYHyRYUIgQXQH4RqOThCXUYRpCHNyQVVQQTwVQiSZWIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) + }; + + // p2 + if (p >= 2 && p < 4) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette: pal1, + buffer : require("heatshrink").decompress(atob("AH4A/ADNUFE8FqtVq2q1AqkFIIrDAAOAFMEBFQYrE1WgKsYrGLL4qFFY2pqDWeFZdUVkAhCAQMKFYdVLDUVFQYMHlWq0oMJKyoOJlQrCLDBWDB5clB5xWOoARMCARYWKwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) + }; + + // p4 + if (p >= 4 && p < 7) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFY2loAqjFY1VqDWeFZdUVkAhEhQrDLDcVFQYMHlQrCBhBWVHJpYYDgYPbKx1ACJhYZIwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) + }; + + // p7 + if (p >= 7 && p < 10) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgWlKzVACJgrCqBWYawgAJcAOlNBhWMCZ8qFYJYUgoqBC6ECFYJqOAApWSS4jCNQQ5uSCqqCCeCqESFQKZUIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A==")) + }; + + // p10 + if (p >= 10 && p < 20) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAOkQSdUFacK1WloCCSCaAAEFYKaQQSyEC0pvQirZTbomlIh6CYZAZFOQTBxDQhyCYOQhoPQS4bQHaBzaVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) + }; + + // p20 + if (p >= 20 && p < 30) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4AWgNVoAEGAERSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A=")) + }; + + // p30 + if (p >= 30 && p < 40) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccFawkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI")) + }; + + // p40 + if (p >= 40 && p < 50) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal1, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccKFYkVFcwFDitVFccqFYkFFcuoFeNAFcWqFYkBFcugFYtQFUMCFYsAFcuAFYtUFcMKFY0VFcgHFitVFcMqFY0FFceoFY9AFcGqFY0BqtQFT8C1WgFeMAqtUFb8K1WAFY7cglQrIioriBI8FqtAFb2q1ArJbjzaBFZEBbj7aB0ALIFcLaHbkLaJFYbcd1QrKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjUBQR6EaiqCPQjVVQSATCqtUFSZvB1WACiSEUY4KCQQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) + }; + + // p50 + if (p >= 50 && p < 60) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjSCQQjSCQQjSCRAAIrB1AqTgorBoAUQQiyCSQgjdSbISCRQgZYSKwKCSQghYQKwSCSQghYQKwSCTAAMqFYOoCJsFFQNVFShYEwARMFQRWVLAiFMQIRWWLAosKFQZWXLAosIFQZWYLAzgFawZWbAAMKFgmq1IoEAANUFTQABFZtAFbgsFFYwqeWQorFVjZZJFYhVfcAwrCazoA/AHI")) + }; + + // p60 + if (p >= 60 && p < 70) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAelNBqCLVxqEC0oRPQS6EC0oSQQSyECFYKEVQSIABFYI/QAAcFFYJDRCgSCmYYjdSCqqYCLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) + }; + + // p70 + if (p >= 70 && p < 80) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZAgoAggNVoAr/FbdUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) + }; + + // p80 + if (p >= 80 && p < 90) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AcIdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) + }; + + // p90 + if (p >= 90 && p < 100) return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESquq1ArTgqESNgOqwArTIYKERH4KCUQigSBbKTdGCKKCVQiTCCFSyERCALBQQjAPBoArXDZ7ARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A")) + }; + + // p100 + return { + width : 176, height : 176, bpp : 2, + transparent : -1, + palette : pal2, + buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLFjzWEABLgbVgohEGoqyaiofDBihWVHJpYYDgYPbKxz5NLDJGCfBzgDKzA+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) + }; } function draw() { diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index c42432955..90b83ba97 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,11 +1,12 @@ { "id": "daisy", "name": "Daisy", "version":"0.01", + "dependencies": {"mylocation":"app"}, "description": "A clock based on the Pastel clock with large ring guage for steps", "icon": "app.png", "tags": "clock", "supports" : ["BANGLEJS2"], - "screenshots": [{"url":"screenshot_thering3.jpg"}], + "screenshots": [{"url":"screenshot_daisy1.jpg"}], "readme": "README.md", "storage": [ {"name":"daisy.app.js","url":"app.js"}, diff --git a/apps/daisy/screenshot_daisy1.png b/apps/daisy/screenshot_daisy1.png new file mode 100644 index 0000000000000000000000000000000000000000..afef3a4246d9a14451d3f3921459be353bfec9e7 GIT binary patch literal 3072 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 Dgx=Ia diff --git a/apps/daisy/screenshot_thering2.jpg b/apps/daisy/screenshot_thering2.jpg deleted file mode 100644 index 521a610171da359e9ae8e2c3f2816846d541a258..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45141 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

PZ>rG*M~V* zC=?>g<|qzUT^}9eqm`cR-)I=G%D(J`n$g*O+P+6K*i1SmQxJoPJy1-=+C!XPq zXt}li9;HoaA#*YruFn<(?aZy;Gk-omgP;Tu?VX>u{|%i&05tz4)r&W<>4qON|T{S-l=El;BD@~G0;3Zdw%_I;xJ>C7skh{n8_ z1r$-3d%J?jPxjaGb$HYSfy%xHQ>HkGn6ze-HgDn`h}pCJ=JMyPk9(uQ2l2^x*)FNT z^A7CU%y;7fKhtN~z0ti&UTiI15>bra(5u6?V_VDzCEA3#^b#d>BSPB$lA!y*g9uU4 z@wD()0iq7>8$RVJgXqm#qdS}gc)T|aqDjqh=FXpNj2z{KQaA~9m)+coK$QAmy+r20C+G~`6dK8p$cTg#30zac>=!9*{mlU4^%FzH1GLUxT42Yhv+dMStgI@awnB8-Z5@|- z>ai1%5l&rW0ul=# z=U}w1>YAUs6lhCUs;as3+lo}t0`d&j)e1+ZskBSsRbBf_AXsgynhZw-Ps=Q+)d~8RH-A$ncazPIV650N=byGl>S7t ze)cA`)PbBe(Pl=#v$U(Er#qT;B`d0(G$4!f7EgY-rpeT^@a0v7GW|9eSgy*OJtAwt z7!PX@&dPGDpkBTkk3d7@^OZwHK(34kH?HHe?-Cc3^Dicom*#y9k6y%`mUIt4oxuCPn9;^520*>@VS z3-Sa~*vAWYZU^dgHbQ-`_3OdAt^D z8R>^Zw_ymMw3SY1)iX0Xe!T4&@uOJH&5T2DDh4Kag``Qsg#B4l&Qbjr@T@y#kR{T; zv6t?G8X9}m4nhH|H8w)6=kLEMh6qRQAH$}Rol%DJOn2|k;R?tHqpHiEmjn|;8x|iN zi5M>#!RVvAiP(R8<6jm|ka`f_dt=!?#40l``=kY~Nww$o{9aCu)P@5>p_eJKi|2J( zs;y>#3qL`Cy<(*&E%PVN_YWLQ@K?N9gEIod�e9j3!`F3^QxZK5jA}%d6?l5dX7% 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 OpD1M{07xEZSpV5*ZhS)k diff --git a/apps/daisy/screenshot_thering3.jpg b/apps/daisy/screenshot_thering3.jpg deleted file mode 100644 index da8f140c0b36dbcc3c09c9fcc163a02bd1cfdc4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19580 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 Date: Tue, 22 Feb 2022 23:46:23 +0000 Subject: [PATCH 232/447] Daisy - first release --- apps/daisy/README.md | 2 ++ apps/daisy/metadata.json | 2 +- apps/daisy/screenshot_daisy2.jpg | Bin 0 -> 4775 bytes 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 apps/daisy/screenshot_daisy2.jpg diff --git a/apps/daisy/README.md b/apps/daisy/README.md index 09ecb78cd..f6c0014be 100644 --- a/apps/daisy/README.md +++ b/apps/daisy/README.md @@ -26,3 +26,5 @@ Forum](http://forum.espruino.com/microcosms/1424/) ![](screenshot_daisy1.png) 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) +![](screenshot_daisy2.jpg) diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index 90b83ba97..fe66683a7 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -6,7 +6,7 @@ "icon": "app.png", "tags": "clock", "supports" : ["BANGLEJS2"], - "screenshots": [{"url":"screenshot_daisy1.jpg"}], + "screenshots": [{"url":"screenshot_daisy2.jpg"}], "readme": "README.md", "storage": [ {"name":"daisy.app.js","url":"app.js"}, diff --git a/apps/daisy/screenshot_daisy2.jpg b/apps/daisy/screenshot_daisy2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fec6a4c7b82c9dd40f3993017eb3edaa1a457b1a GIT binary patch literal 4775 zcmb`GXE>bQ*2nKLI!TNc1W`ux#1LgfA29?G!)OUnqek@TJ?dZ(C6eg9gwcr*qDzS0 zh3JClH8|s(>v^B^;k?)T;k;{K``*86?X~}F?Q&m?UCaVh50q4t01yZOK==k+{3PH} zK_H$!LTMFFD=UHbkq6EkOrzxY3lc-@1MOLYJk z6#NhK|Cfu*+``!mAGC$8I5_+riROl$cscE4oPe=+8gowQL1d`vo?c`W~pP5+Hw zx;VJtV>&P6%^aLAc?!=`&+S|;MaZ4Nw8>0W;t>o`eA*00xL%Oach}^Z4)V zQslo=z^}ge3_wWnMG1jH5P$#z0z*I-tpF4LG{Bed`hSd+oRFA=j0iu+M+Jb0KmY*& z0f>+Qd>H@+5fBm)lR&6RX=v%_**Q320NHh66h4+2|6dS-|6PX&jMo7ONH4R9;xiI} zz+f-|m;_98sRSYb6GDin*#Ve5F^wjN2`!xh38%1QZ1a|B296$z3dp>e04VW-1Q0L; zkOdZD_pBFMjBn~PN3%0Mb>n1R(D8d((lplU{0FYLlzGZe7j^+4J&=cJ4aJqfN@}q* zZCoIAYik1zL#^SxfFqp0Y3BmTKyM1cWjTLicF&DnLkTIpsPUdjvw!cTagS#mi%L`gR>AI-9vF+Rvb^QpYs-`3kZ>F6F z0X|qepGy4}3F-huk+`qP9x89&jVA@HQCQM9-};#CH7U0X?N zkWJN0ADjUeMNBO8Xlj5%6nFZx;+sxZMT^yhd>qXh1}p3U&VPE2iw^`=L{nsnKJ;;XN}I$8|j^%4Tu$)_DJPtoy|Jlq;O zG`qYN3xN!DP#f&^(ZP`1DAHE6e6dxad{@~iv1Y1p{!B;3*sYaE=7~AvWmK%5-;*3q zI3c&zK|2y83=2-eu#`{XjG2QrREYx1-dQ&fwg|wT*Xy7bS`y1rLD7W=^{3Kw0d^Zp zOy)sww9&psw)J}ZU086V0R)!H6lA7%M+Z(vGkF@;p&;46E(Zcb-%*cms_ba&ZnR4* zZai>61#kpAWUaX^PB(n4aeKyndKFl^v8Skz9#|Y9hU<*zqvZdSSu~U5S=;%0W!M(7 zp>zS{!lJf@nt|omgRYLln?H{C@*SJvcRR)o=1*vr`*gb1Y0F@mq$RffUpyEVwHYFY z6yTkuwtfRgy6(=gHxAr)n)-S9?{Ejb+df>bi8-Dv{by9LH||@4x@ee+&lOB?yum81qR>kE4Zu>0hhcv58E5Gb_)%R zqzit`?(8ZHSO;X+1)#~9pBQ8Fm1cb4PFLf%TW4QO{GX%O`zyq4EHflR3(HT%UZ>tL`DGD_0CHj@xQB z350UanaKG{%`#)%xoc3861bO-%6@3-N4ZbVaWWd`EknV7KJMdouJ68I6y0R{@_Ixu z7WqwFGP1E&Q0)Do_9*;>UsaO7fbLZ_vH9J&%`QZOAb(Nnv3;@+pJR(;`-H|%TdmSl z^W^FcNce2-1yE`j)5#+Kg`)QQHV4|N*K5Q|lH^%kOy&wJcFk4#rJ+vsl@`+-Z8z#n zg8IfsTxgpb9g~hBWDI>_|F%v_TT@@g;C#cY2j{oiJWxVDAu3`}=uO8QOVnb>qTX;# zuppzy!W(@$gqb5zD6^Y{baSsVIOuS#^ag0#u<2T^{c*6*NNBlfeJN4;ir1Mpu75cW zsq^{p3d_uOlCYAvXNmD#&%YIBH0h_`{aAAMU|e5UAt%$ynDJGlWa%=_`aq`~Rgt$w zZyLd6`I;%w8p#}|)~56na9ga9aqr&g2a|uUOK#2o^3Dlv_>Q0 z{gUoNnEUsZHkD{^c8os07W7gf)yNAoV?s_Qopd}<$u5*XN6(az0e&ESCC2h-c(%z=?4 zTA8cx@Qh;D#tEpJj=i^G4dUjaWc~e;olRRiEfM9P!gSDETJSReakt=LFY5s{DmPx6 zWxd3892!UV!oEl}M7QWE^rj6v{SU`xLEae(aRRv<1^+)J1tj^!YtA}@cSa8hnLJYe z^vk?g6d(DnW8lR7^BIG6wnvR}H!ei^pisVJb|P z0Tu;0bkZBGA8S4D-T5&*!n-uK#7-U2XnQ+TQ(v8@>&XGjr$XJ0sSg&VIuf?}(XM52 zFW!ZPnQPdkPkyR(fU;c^#9XhbJkv!F6>>$;@(*O>j}CDRWmfM#POwpiM$mn*RWi1I zNbM$4PI_2qKaE8@J*?QS2y>R6$)g*-$6A!*(hDk?uWm4!C(?i0uC?MRgOYJJ%x;)$ z8=q<$UJx0`eQYfxs_B%VJ8)OD&blU2N3x4w)=RWxstQPyNDui`TP(2sz~_*v!HEO1 z5fyox39fW-Hlq!jPDoItjVmKU%dyuG2n#t83u{DQv%~DC?ndL@79GtE);-Bi`}5Xp z^625tn{QxM6rYhtsDr(UX>=7AByvN`PF_MwO^ zw_k@L{MXX3q0z#$^U;6>?_&dgD@Q~|Q78+T$!FT5OGfP(jQsJ^fUky4VsSWrRP^=$;Cj4dd5Oj@u+;$8ilh8U*|;B82Y8ELZP| zhd~Gq<|YHO=TV4?ntHPj0@j5#NvfjuA~*~-*$81qc&+H>#t%4rqt^|q_7#u-e2_I# ztY6-NQX@XTO$!n}MjvRUn23!S#<^L(*EZfK3C;T8`RmK~rJf13+B|W&{t@Ljj)7dR zcNXLri@1Lv1;1T2W2YZIT5=INH>0?l$fZ~u@cvMED}t=cw8$S;8>a-ok5_|3^dcL| z`4s#sJ_@1Hnu(?zSb#8211#-EJkthG;^=cal;RkDqV!?V<=Ndp&R;0$7az35Zy7&f zXH3{O@2bK@FD66uyBITiTwZ#(N?X0HzB2=)YViDIDe=6Z^&IZ zsufipEl>stcxd*rzeZA|$V-{A&5XjNJ$3Hbx9Mg1#Lyv&`2Rfu7QLZNRmmt84&dVEtU z)Q`&Z+t)w}usC?ozuLocC&@?2Ec`f{duYW~1a z(Wb12uk%*pU1^{7Ky`i0TTcUZ)pLGF7K72W8OBnKW7%toR__N$~? zhIsBqU~O1ytEaU2^{5Nk)b8ui;{(+zql(>%7#&R501pCb=3{Jee@`=0Ve6-qpiLcm z<%jH=y0CW+U6n854{WsLma4Jwl{s2gkKTJUy^{BvtRxkSO$Xc?K zk873}d$?Ig{9^{(^0x?0$(TIXX*c1MxZ7`XUL6vVW((SU2RlWgfDBH67k1T&luhW$ zAaA~HW3Kz8E@oAd#}&JZ?P;9;OlI-8;&wmt6N2xhGNheXHAt@?&{OHO^qQEDJq#?* zQ{_$L&<+>otPO#a=a*uwi5w{p<9ps&X8mzDi%m!@AapH!97XpCN>9tf@LAgdIG1zZ iyf#_j;@Cleq=XeaDg|&Vf;1sYbP56f0C2VGV*DR0n&w3S literal 0 HcmV?d00001 From 29432bb9f83aad7cb38b9f3a3feb3620f8d1e205 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Wed, 23 Feb 2022 09:24:33 +0100 Subject: [PATCH 233/447] Add screenshot --- apps/smclock/metadata.json | 1 + apps/smclock/screenshot.png | Bin 0 -> 2845 bytes 2 files changed, 1 insertion(+) create mode 100644 apps/smclock/screenshot.png diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 1783ca7bf..febbdd01c 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -3,6 +3,7 @@ "name":"Monogram Watch Face", "shortName":"MonoClock", "icon":"app.png", + "screenshots": [{"url":"screenshot.png"}], "version":"0.02", "description": "A simple watchface based on my stylised monogram.", "tags":"clock", diff --git a/apps/smclock/screenshot.png b/apps/smclock/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e0bd0eed06e2c77e0ad737b1ecd4814a8e4f65 GIT binary patch literal 2845 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 YUdx_>rDxQ4@7%ip9M&0AYD0|sC!%XI-v9sr literal 0 HcmV?d00001 From aa86b3ffdb63f59d9b0823360855e8c40f86d02a Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Wed, 23 Feb 2022 10:44:16 +0100 Subject: [PATCH 234/447] Update 7x7dotsclock.app.js Add color yellow for minutes and seconds Better color contrast for seconds --- apps/7x7dotsclock/7x7dotsclock.app.js | 57 ++++++++++++++++----------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index ce2b3011d..53b4c1bd6 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -13,18 +13,26 @@ var Xs = 0, Ys = 30,Xe = 175, Ye=175; var SegH = (Ye-Ys)/2,SegW = (Xe-Xs)/2; var Dx = SegW/14, Dy = SegH/16; -switch(ColorMinutes) { - case "blue": - var mColor = [0.3,0.3,1]; - break; - case "pink": - var mColor = [1,0.3,1]; - break; - case "green": - var mColor = [0.3,1,0.3]; - break; - default: - var mColor = [0.3,0.3,1]; +switch(settings.ColorMinutes) { +case "blue": + var mColor = [0.3,0.3,1]; + var sColor = [0,0,1]; + break; +case "pink": + var mColor = [1,0.3,1]; + var sColor = [1,0,1]; + break; +case "green": + var mColor = [0.3,1,0.3]; + var sColor = [0,1,0]; + break; +case "yellow": + var mColor = [1,1,0.3]; + var sColor = [1,1,0]; + break; +default: + var sColor = [0,0,1]; + var mColor = [0.3,0.3,1]; } const bColor = [0.3,0.3,0.3]; @@ -152,9 +160,10 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { for (let j = 1; j < 8; j++) { if (Font[Num][j-1][i-1] == 1) { if (Color == "fg") { - g.setColor(mColor[0],mColor[1],mColor[2]); + g.setColor(sColor[0],sColor[1],sColor[2]); } else { g.setColor(g.theme.fg); + //g.setColor(0.7,0.7,0.7); } g.fillCircle(x1+(i-1)*(x2-x1)/7,y1+(j-1)*(y2-y1)/7,Size); } @@ -164,23 +173,25 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { function ShowSecons() { + //g.setColor(bColor[0],bColor[1],bColor[2]); + //g.setColor(0.7,0.7,0.7); g.setColor(g.theme.fg); - g.fillRect((Xe-Xs) / 2 - 14 + Xs -3, - (Ye-Ys) / 2 - 7 + Ys -3, - (Xe-Xs) / 2 + 14 + Xs +1, - (Ye-Ys) / 2 + 7 + Ys +1); + g.fillRect((Xe-Xs) / 2 - 14 + Xs -4, + (Ye-Ys) / 2 - 7 + Ys -4, + (Xe-Xs) / 2 + 14 + Xs +4, + (Ye-Ys) / 2 + 7 + Ys +4); drawSSeg( (Xe-Xs) / 2 - 14 + Xs -1, - (Ye-Ys) / 2 - 7 + Ys , + (Ye-Ys) / 2 - 7 + Ys +1, (Xe-Xs) / 2 + Xs -1, - (Ye-Ys) / 2 + 7 + Ys, + (Ye-Ys) / 2 + 7 + Ys +1, ds,"fg",1); - drawSSeg( (Xe-Xs) / 2 + Xs +1, - (Ye-Ys) / 2 - 7 + Ys, - (Xe-Xs) / 2 + 14 + Xs +1, - (Ye-Ys) / 2 + 7 + Ys, + drawSSeg( (Xe-Xs) / 2 + Xs +2, + (Ye-Ys) / 2 - 7 + Ys +1, + (Xe-Xs) / 2 + 14 + Xs +2, + (Ye-Ys) / 2 + 7 + Ys +1, es,"fg",1); } From 66e1fa4e2f45c5fb8a2606f0d34036793af5cfa4 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Wed, 23 Feb 2022 10:45:35 +0100 Subject: [PATCH 235/447] Update README.md --- apps/7x7dotsclock/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/README.md b/apps/7x7dotsclock/README.md index 76684bc1a..28fcac1b1 100644 --- a/apps/7x7dotsclock/README.md +++ b/apps/7x7dotsclock/README.md @@ -5,7 +5,7 @@ * A Clock with big numbers made of 7x7 dots * system widgeds ar not (yet) supported * when screen is locked it shows hours and minutes in full screen mode -* respects theme colors +* adjustable color for minutes and seconds ![](dotsfontclock-scr1.png) From b21da11e6c01d6b998d1388339764e53b62e580d Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:21:10 +0100 Subject: [PATCH 236/447] Add files via upload --- apps/7x7dotsclock/dotsfontclock-scr1.png | Bin 3874 -> 3737 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/7x7dotsclock/dotsfontclock-scr1.png b/apps/7x7dotsclock/dotsfontclock-scr1.png index dc86396c0606f0a4c5ea4895bc17543f2e51024a..5ab2e48639a4b5dcffbeb59e83b7819f89c4228d 100644 GIT binary patch delta 3724 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 Y?43dq;SVfZ;Q#;t07*qoM6N<$f-v!GOaK4? From 0a9516dee03586a53fc63580ec08fecf56a6409f Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:21:54 +0100 Subject: [PATCH 237/447] Add files via upload --- apps/7x7dotsclock/dotsfontclock-scr2.png | Bin 0 -> 3386 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/7x7dotsclock/dotsfontclock-scr2.png diff --git a/apps/7x7dotsclock/dotsfontclock-scr2.png b/apps/7x7dotsclock/dotsfontclock-scr2.png new file mode 100644 index 0000000000000000000000000000000000000000..f301bb50c7217253516345c09a3482f7e745455c GIT binary patch literal 3386 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 Date: Wed, 23 Feb 2022 11:24:30 +0100 Subject: [PATCH 238/447] Update metadata.json Added screenshots --- apps/7x7dotsclock/metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/metadata.json b/apps/7x7dotsclock/metadata.json index 9f997e10d..41f0836d3 100644 --- a/apps/7x7dotsclock/metadata.json +++ b/apps/7x7dotsclock/metadata.json @@ -14,5 +14,6 @@ {"name":"7x7dotsclock.settings.js","url":"7x7dotsclock.settings.js"}, {"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true} ], - "data": [{"name":"7x7dotsclock.json"}] + "data": [{"name":"7x7dotsclock.json"}], + "screenshots": [{"url":"dotsfontclock.png"},{"url":"dotsfontclock-scr1.png"},{"url":"dotsfontclock-scr2.png"}] } From 040d765d946f245fa4bdb62f073c2f8da23b7545 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:28:56 +0100 Subject: [PATCH 239/447] Update 7x7dotsclock.settings.js add yellow color --- apps/7x7dotsclock/7x7dotsclock.settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.settings.js b/apps/7x7dotsclock/7x7dotsclock.settings.js index fe9fbc022..34935d668 100644 --- a/apps/7x7dotsclock/7x7dotsclock.settings.js +++ b/apps/7x7dotsclock/7x7dotsclock.settings.js @@ -37,7 +37,7 @@ function showMainMenu() { const mainMenu = { "": {"title": "7x7 Dots Clock Settings"}, "< Back": ()=>load(), - "Minutes": stringInSettings("ColorMinutes", ["blue","pink","green"]), + "Minutes": stringInSettings("ColorMinutes", ["blue","pink","green","yellow"]), "swipe-up": ()=>showSelAppMenu("swupApp"), "swipe-down": ()=>showSelAppMenu("swdownApp"), "swipe-left": ()=>showSelAppMenu("swleftApp"), From ca1b94fa8948df9cfb788a147a3ff9ed6a88ebe6 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:30:38 +0100 Subject: [PATCH 240/447] Update ChangeLog --- apps/7x7dotsclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/7x7dotsclock/ChangeLog b/apps/7x7dotsclock/ChangeLog index 50c5eca4a..d2c98a472 100644 --- a/apps/7x7dotsclock/ChangeLog +++ b/apps/7x7dotsclock/ChangeLog @@ -1 +1,2 @@ 0.01: Initial version for upload +0.02: better theme support, configurable colors, small improvements From ffa5b96de6eaf89db9f2a9e3b5238fadaa288b91 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 10:44:48 +0000 Subject: [PATCH 241/447] messages +0.23: Change message colors to match current theme instead of using green + Now attempt to use Large/Big/Medium fonts, and allow minimum font size to be configured --- apps/messages/ChangeLog | 6 ++- apps/messages/README.md | 3 ++ apps/messages/app.js | 69 ++++++++++++++++++++--------------- apps/messages/metadata.json | 2 +- apps/messages/screenshot.png | Bin 2931 -> 4194 bytes apps/messages/settings.js | 6 +++ 6 files changed, 53 insertions(+), 33 deletions(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 07da48198..1e6ac71d7 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -32,5 +32,7 @@ 0.20: Allow tapping on the body to show a scrollable view of the message and title in a bigger font (fix #1405, #1031) 0.21: Improve list readability on dark theme 0.22: Add Home Assistant icon -0.22: Allow repeat to be switched Off, so there is no buzzing repetition. - Also gave the widget a pixel more room to the right \ No newline at end of file + Allow repeat to be switched Off, so there is no buzzing repetition. + Also gave the widget a pixel more room to the right +0.23: Change message colors to match current theme instead of using green + Now attempt to use Large/Big/Medium fonts, and allow minimum font size to be configured diff --git a/apps/messages/README.md b/apps/messages/README.md index a355a58ac..cce4391e7 100644 --- a/apps/messages/README.md +++ b/apps/messages/README.md @@ -16,6 +16,9 @@ and `Messages`: * `Unread Timer` - when a new message is received we go into the Messages app. If there is no user input for this amount of time then the app will exit and return to the clock where a ringing bell will be shown in the Widget bar. +* `Min Font` - the minimum font size used when displaying messages on the screen. A bigger font +is chosen if there isn't much message text, but this specifies the smallest the font should get before +it starts getting clipped. ## New Messages diff --git a/apps/messages/app.js b/apps/messages/app.js index 96c48f02f..0cf13db2c 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -21,13 +21,11 @@ */ var Layout = require("Layout"); +var settings = require('Storage').readJSON("messages.settings.json", true) || {}; var fontSmall = "6x8"; var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2"; var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2"; var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4"; -var colBg = g.theme.dark ? "#141":"#4f4"; -var colSBg1 = g.theme.dark ? "#121":"#cFc"; -var colSBg2 = g.theme.dark ? "#000":"#9F9"; // hack for 2v10 firmware's lack of ':size' font handling try { g.setFont("6x8:2"); @@ -143,8 +141,8 @@ function showMapMessage(msg) { eta = m[2]; } else target=msg.body; layout = new Layout({ type:"v", c: [ - {type:"txt", font:fontMedium, label:target, bgCol:colBg, fillx:1, pad:2 }, - {type:"h", bgCol:colBg, fillx:1, c: [ + {type:"txt", font:fontMedium, label:target, bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, pad:2 }, + {type:"h", bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, c: [ {type:"txt", font:"6x8", label:"Towards" }, {type:"txt", font:fontLarge, label:street } ]}, @@ -181,7 +179,7 @@ function showMusicMessage(msg) { checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); } layout = new Layout({ type:"v", c: [ - {type:"h", fillx:1, bgCol:colBg, c: [ + {type:"h", fillx:1, bgCol:g.theme.bgH, col: g.theme.fgH, c: [ { type:"btn", src:getBackImage, cb:back }, { type:"v", fillx:1, c: [ { type:"txt", font:fontMedium, label:msg.artist, pad:2 }, @@ -214,7 +212,9 @@ function showMessageScroller(msg) { // a function to draw a menu item draw : function(idx, r) { // FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12 - g.setBgColor(idx=lines.length-2) @@ -270,13 +270,31 @@ function showMessage(msgid) { var title=msg.title, titleFont = fontLarge, lines; if (title) { var w = g.getWidth()-48; - if (g.setFont(titleFont).stringWidth(title) > w) - titleFont = fontMedium; + if (g.setFont(titleFont).stringWidth(title) > w) { + titleFont = fontBig; + if (settings.fontSize!=1 && g.setFont(titleFont).stringWidth(title) > w) + titleFont = fontMedium; + } if (g.setFont(titleFont).stringWidth(title) > w) { lines = g.wrapString(title, w); title = (lines.length>2) ? lines.slice(0,2).join("\n")+"..." : lines.join("\n"); } } + // If body of message is only two lines long w/ large font, use large font. + var body=msg.body, bodyFont = fontLarge; + if (body) { + var w = g.getWidth()-10; + if (g.setFont(bodyFont).stringWidth(body) > w * 2) { + bodyFont = fontBig; + if (settings.fontSize!=1 && g.setFont(bodyFont).stringWidth(body) > w * 3) + bodyFont = fontMedium; + } + if (g.setFont(bodyFont).stringWidth(body) > w) { + lines = g.setFont(bodyFont).wrapString(msg.body, w); + var maxLines = Math.floor((g.getHeight()-110) / g.getFontHeight()); + body = (lines.length>maxLines) ? lines.slice(0,maxLines).join("\n")+"..." : lines.join("\n"); + } + } function goBack() { msg.new = false; saveMessages(); // read mail cancelReloadTimeout(); // don't auto-reload to clock now @@ -303,27 +321,17 @@ function showMessage(msgid) { checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); }}); } - // If body of message is only two lines long w/ large font, use large font. - var body=msg.body, bodyFont = fontLarge, lines; - if (body) { - var w = g.getWidth()-48; - if (g.setFont(bodyFont).stringWidth(body) > w * 2) - bodyFont = fontMedium; - if (g.setFont(bodyFont).stringWidth(body) > w) { - lines = g.setFont(bodyFont).wrapString(msg.body, g.getWidth()-10); - body = (lines.length>4) ? lines.slice(0,4).join("\n")+"..." : lines.join("\n"); - } - } + layout = new Layout({ type:"v", c: [ - {type:"h", fillx:1, bgCol:colBg, c: [ + {type:"h", fillx:1, bgCol:g.theme.bgH, col: g.theme.fgH, c: [ { type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{ cancelReloadTimeout(); // don't auto-reload to clock now showMessageSettings(msg); }}, { type:"v", fillx:1, c: [ - {type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:colBg, fillx:1, pad:2, halign:1 }, - title?{type:"txt", font:titleFont, label:title, bgCol:colBg, fillx:1, pad:2 }:{}, + {type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, pad:2, halign:1 }, + title?{type:"txt", font:titleFont, label:title, bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, pad:2 }:{}, ]}, ]}, {type:"txt", font:bodyFont, label:body, fillx:1, filly:1, pad:2, cb:()=>{ @@ -374,9 +382,8 @@ function checkMessages(options) { c : Math.max(MESSAGES.length+1,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11) draw : function(idx, r) {"ram" var msg = MESSAGES[idx-1]; - if (msg && msg.new) g.setBgColor(colBg); - else g.setBgColor((idx&1) ? colSBg1 : colSBg2); - g.clearRect(r.x,r.y,r.x+r.w-1,r.y+r.h-1).setColor(g.theme.fg); + if (msg && msg.new) g.setBgColor(g.theme.bgH).setColor(g.theme.fgH); + else g.setColor(g.theme.fg); if (idx==0) msg = {id:"back", title:"< Back"}; if (!msg) return; var x = r.x+2, title = msg.title, body = msg.body; @@ -391,18 +398,20 @@ function checkMessages(options) { .setColor(fg); // only color the icon x += 50; } - var m = msg.title+"\n"+msg.body; - if (msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2); + var m = msg.title+"\n"+msg.body, longBody=false; if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2); if (body) { g.setFontAlign(-1,-1).setFont("6x8"); - var l = g.wrapString(body, r.w-14); + var l = g.wrapString(body, r.w-(x+14)); if (l.length>3) { l = l.slice(0,3); l[l.length-1]+="..."; } + longBody = l.length>2; g.drawString(l.join("\n"), x+10,r.y+20); } + if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2); + g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items }, select : idx => { if (idx==0) load(); @@ -422,7 +431,7 @@ g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); setTimeout(() => { - var unreadTimeoutSecs = (require('Storage').readJSON("messages.settings.json", true) || {}).unreadTimeout; + var unreadTimeoutSecs = settings.unreadTimeout; if (unreadTimeoutSecs===undefined) unreadTimeoutSecs=60; if (unreadTimeoutSecs) unreadTimeout = setTimeout(function() { diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 7488c792e..e8ed83099 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.22", + "version": "0.23", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/screenshot.png b/apps/messages/screenshot.png index a95045400bf4ef49d1e3a6df99cca54b8cb73aff..a64416f7d47d1918e3f1d8928b80517b4bd33f32 100644 GIT binary patch delta 4185 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 h0=qG5Oh v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("unreadTimeout", v) }, + /*LANG*/'Min Font': { + value: 0|settings().fontSize, + min: 0, max: 1, + format: v => [/*LANG*/"Small",/*LANG*/"Medium"][v], + onchange: v => updateSetting("fontSize", v) + }, }; E.showMenu(mainmenu); }) From 17b7d85950e4c6339f9250a858cf18e9ad8f057c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 10:45:18 +0000 Subject: [PATCH 242/447] Layout: remove 'fsz' hack as any firmware 2v11+ will support font size in the string now --- modules/Layout.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 1b0bbd47f..4223867a4 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -180,13 +180,6 @@ function Layout(layout, options) { if (l.id) ll[l.id] = l; // fix type up if (!l.type) l.type=""; - // FIXME ':'/fsz not needed in new firmwares - Font:12 is handled internally - // fix fonts for pre-2v11 firmware - if (l.font && l.font.includes(":")) { - var f = l.font.split(":"); - l.font = f[0]; - l.fsz = f[1]; - } if (l.c) l.c.forEach(recurser); } recurser(this._l); @@ -241,13 +234,13 @@ Layout.prototype.render = function (l) { "":function(){}, "txt":function(l){ if (l.wrap) { - g.setFont(l.font,l.fsz).setFontAlign(0,-1); + g.setFont(l.font).setFontAlign(0,-1); var lines = g.wrapString(l.label, l.w); var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1); // TODO: on 2v11 we can just render in a single drawString call lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i)); } else { - g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); + g.setFont(l.font).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); } }, "btn":function(l){ var x = l.x+(0|l.pad), y = l.y+(0|l.pad), @@ -365,7 +358,7 @@ Layout.prototype.update = function() { if (l.wrap) { l._h = l._w = 0; } else { - var m = g.setFont(l.font,l.fsz).stringMetrics(l.label); + var m = g.setFont(l.font).stringMetrics(l.label); l._w = m.width; l._h = m.height; } }, "btn": function(l) { From d79915d67e068bad2e7e2e864367b0edba564313 Mon Sep 17 00:00:00 2001 From: pkkpp <52079346+pkkpp@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:49:19 +0100 Subject: [PATCH 243/447] Update 7x7dotsclock.app.js --- apps/7x7dotsclock/7x7dotsclock.app.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/7x7dotsclock/7x7dotsclock.app.js b/apps/7x7dotsclock/7x7dotsclock.app.js index 53b4c1bd6..aa174b2d2 100644 --- a/apps/7x7dotsclock/7x7dotsclock.app.js +++ b/apps/7x7dotsclock/7x7dotsclock.app.js @@ -17,22 +17,27 @@ switch(settings.ColorMinutes) { case "blue": var mColor = [0.3,0.3,1]; var sColor = [0,0,1]; + var sbColor = [1,1,1]; break; case "pink": var mColor = [1,0.3,1]; var sColor = [1,0,1]; + var sbColor = [1,1,1]; break; case "green": var mColor = [0.3,1,0.3]; var sColor = [0,1,0]; + var sbColor = [1,1,1]; break; case "yellow": var mColor = [1,1,0.3]; var sColor = [1,1,0]; + var sbColor = [0,0,0]; break; default: var sColor = [0,0,1]; var mColor = [0.3,0.3,1]; + var sbColor = [1,1,1]; } const bColor = [0.3,0.3,0.3]; @@ -134,7 +139,8 @@ var dho = -1, eho = -1, dmo = -1, emo = -1; function drawHSeg(x1,y1,x2,y2,Num,Color,Size) { - //g.setColor(0,0,0); + + g.setColor(g.theme.bg); g.fillRect(x1, y1, x2, y2); for (let i = 1; i < 8; i++) { @@ -172,10 +178,10 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) { } -function ShowSecons() { - //g.setColor(bColor[0],bColor[1],bColor[2]); - //g.setColor(0.7,0.7,0.7); - g.setColor(g.theme.fg); +function ShowSeconds() { + + g.setColor(sbColor[0],sbColor[1],sbColor[2]); + g.fillRect((Xe-Xs) / 2 - 14 + Xs -4, (Ye-Ys) / 2 - 7 + Ys -4, (Xe-Xs) / 2 + 14 + Xs +4, @@ -238,7 +244,7 @@ function draw() { emo = em; } - if (!Bangle.isLocked()) ShowSecons(); + if (!Bangle.isLocked()) ShowSeconds(); } From 0ef8ad6d5ec30ff936c0c2bd26876fcf0dd485d5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 12:10:14 +0000 Subject: [PATCH 244/447] add simple interlaced font clock --- apps/intclock/ChangeLog | 12 +++++++ apps/intclock/README.md | 4 +++ apps/intclock/app-icon.js | 1 + apps/intclock/app.js | 60 +++++++++++++++++++++++++++++++++++ apps/intclock/app.png | Bin 0 -> 3480 bytes apps/intclock/metadata.json | 16 ++++++++++ apps/intclock/screenshot.png | Bin 0 -> 2101 bytes 7 files changed, 93 insertions(+) create mode 100644 apps/intclock/ChangeLog create mode 100644 apps/intclock/README.md create mode 100644 apps/intclock/app-icon.js create mode 100644 apps/intclock/app.js create mode 100644 apps/intclock/app.png create mode 100644 apps/intclock/metadata.json create mode 100644 apps/intclock/screenshot.png diff --git a/apps/intclock/ChangeLog b/apps/intclock/ChangeLog new file mode 100644 index 000000000..aa910b6f6 --- /dev/null +++ b/apps/intclock/ChangeLog @@ -0,0 +1,12 @@ +0.02: Modified for use with new bootloader and firmware +0.03: add hour ticks, remove timers +0.04: add day-date display +0.07: make date and face bigger +0.08: make dots bigger and date more readable +0.09: center date, remove box around it, internal refactor to remove redundant code. +0.10: remove debug, refactor seconds to show elapsed secs each time app is displayed +0.11: shift face down for widget area, maximize face size, 0 pad single digit date, use locale for date +0.12: Fix regression after 0.11 +0.13: Fix broken date padding (fix #376) +0.14: Remove hardcoded hour buzz (you can install widchime if you miss it) +0.15: Add color scheme support diff --git a/apps/intclock/README.md b/apps/intclock/README.md new file mode 100644 index 000000000..7d31cdae2 --- /dev/null +++ b/apps/intclock/README.md @@ -0,0 +1,4 @@ +# Analogue Clock + +![](screenshot_analog.png) + diff --git a/apps/intclock/app-icon.js b/apps/intclock/app-icon.js new file mode 100644 index 000000000..8c62a192e --- /dev/null +++ b/apps/intclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgP/AH4Aq+GEkPh4E/BZMAh4LGw/h8MPBZHggIXJ/EB4ALI//h/4LHwk/BagA/ACY=")) diff --git a/apps/intclock/app.js b/apps/intclock/app.js new file mode 100644 index 000000000..1324a422c --- /dev/null +++ b/apps/intclock/app.js @@ -0,0 +1,60 @@ +Graphics.prototype.setFontUndo = function(scale) { + // Actual height 19 (20 - 2) + this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqKAqooCqigKqKAAAACgAAKAAAoAACgAAAAAAAAACgAAKAAAoAACgAAAAAAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAAAAAKgoAqCgKqKAqooKiioqKKiooqKiioKKqAoqoCgqAKCoAAAACoCgKgKAiCoCIKgKioAqKgACoAAKgACoAAKgACoqAKioCoIgKgiAoCoCgKgAAAAKqgAqqAKqqAqqoKiioqKKiooqKiioKAKAoAoCgCgKAKAAAACgAAKAAAoAACgAAAAAAKqgAqqAKqqAqqoCgCgKAKAAAACgCgKAKAqqoCqqgCqoAKqgAAAACigAKKAAqoACqgAqoACqgAKqAAqoAAqoACqgAKKAAooAAAAAAoAACgAAKAAAoAAqqACqoAKqgAqqAAKAAAoAACgAAKAAAAAAACoAAKgAAqAACoAAAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAAAAACgAAKAAAoAACgAAAAAAoAACgAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAKAAAoAAAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoAAAAKCqAoKoCiqgKKqAoooCiigKKKAoooCqigKqKAKgoAqCgAAAAoAoCgCgKAKAoAoCiigKKKAoooCiigKqqAqqoAqqACqoAAAACqAAKoAAqoACqgAAKAAAoAACgAAKAAqqoCqqgKqqAqqoAAAAKoKAqgoCqigKqKAoooCiigKKKAoooCiqgKKqAoKgCgqAAAAAKqgAqqAKqqAqqoCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKAAAoAACgAAKAAAqqoCqqgCqqAKqoAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCqqgKqqAKqgAqqAAAAAKgAAqAAKqAAqoACigAKKAAooACigAKqqAqqoAqqgCqqAAAACgCgKAKAoAoCgCgAAAAoAqCgCoKAKgoAqAAAAAKAAAoAAKoAAqgAKqgAqqAKgqAqCoCgCgKAKAAAAAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAAAAKAKAoAoCoKgKgqAKqgAqqAAqgACqAACgAAKAAAAACgAAKAAAoAACgAAKKKAoooCiigKKKAqoACqgACoAAKgAAAAACqqAKqoCqqgKqqAoAACgAAKCoAoKgCiqgKKqAoooCiigKqqAqqoAqqACqoAAAAAqqgCqqAqqoCqqgKKAAooACigAKKAAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAoooCiigKKKAoooCqqgKqqAKCgAoKAAAAAKqgAqqAKqqAqqoCgCgKAKAoAoCgCgKAKAoAoCgCgKAKAAAACqqgKqqAqqoCqqgKAKAoAoCoKgKgqAKqgAqqAAqgACqAAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCgCgKAKAoAoCgCgAAAAKqoAqqgKqqAqqoCigAKKAAooACigAKAAAoAACgAAKAAAAAAAqqACqoAqqoCqqgKAKAoAoCiigKKKAoqoCiqgKKqAoqoAAAAKqqAqqoCqqgKqqAAoAACgAAKAAAoACqqgKqqAqqoCqqgAAAAoAoCgCgKAKAoAoCqqgKqqAqqoCqqgKAKAoAoCgCgKAKAAAAAAKAAAoAACoAAKgAAKAAAoAACgAAKAqqoCqqgKqoAqqgAAAAKqqAqqoCqqgKqqACqAAKoACqoAKqgCoKgKgqAoAoCgCgAAAAqqgCqqAKqqAqqoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAKgAAqAAKqqAqqoCqqgKqqAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAqqoCqqgKqqAqqoAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoCigAKKAAooACigAKqAAqoAAqAACoAAAAAAqqACqoAqqoCqqgKAKAoAoCgKgKAqAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAooACigAKKgAoqACqqgKqqAKioAqKgAAAAKgoAqCgKqKAqooCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKqqAqqoCqqgKqqAoAACgAAKAAAoAAAAAAKqoAqqgCqqgKqqAAAoAACgAAKAAAoCqqgKqqAqqgCqqAAAAAqqACqoAKqoAqqgAAKgAAqAACoAAKgKqoAqqgCqoAKqgAAAACqqgKqqAqqoCqqgACoAAKgACoAAKgAAKgAAqAKqqAqqoCqqgKqqAAAACoKgKgqAqqoCqqgAqgACqAAKoAAqgAqqoCqqgKgqAqCoAAAAKoAAqgACqgAKqAAAqoACqgAKqAAqoCqgAKqAAqgACqAAAAAAoCoCgKgKCqAoKoCiqgKKqAqooCqigKoKAqgoCoCgKgKAAAACqqgKqqAqqoCqqgKAKAoAoAAAAKAAAoAACoAAKgAAKgAAqAAAqAACoAACoAAKgAAKgAAqAAAqAACoAACgAAKAAAACgCgKAKAqqoCqqgKqqAqqoAAA"), 32, atob("DQULDw0RDQUHBw0NBQ0FEQ0FDQ0NDQ0NDQ0FBQsNCw0RDQ0NDQ0NDQ0NDQ0NDw0NDQ0NDQ0NDQ8NDQ0HEQc="), 22+(scale<<8)+(1<<16)); + return this; +} + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + + +function draw() { + var x = g.getWidth()/2; + var y = g.getHeight()/2 - 10; + g.reset(); + // work out locale-friendly date/time + var date = new Date(); + var timeStr = require("locale").time(date,1).trim(); + var dateStr = require("locale").date(date).toUpperCase(); + + + // draw time + g.setFontAlign(0,0).setFont("Undo:3"); + g.clearRect(0,y-30,g.getWidth(),y+30); // clear the background + g.drawString(timeStr,x,y); + // draw date + y += 40; + g.setFontAlign(0,0).setFont("Undo"); + g.clearRect(0,y-10,g.getWidth(),y+20); // clear the background + g.drawString(dateStr,x,y); + // queue draw in one minute + queueDraw(); +} + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first, queue update +draw(); +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/intclock/app.png b/apps/intclock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..dacbceb733035cae976a896ffdb648fe7c578234 GIT binary patch literal 3480 zcmYLMcQhLg7fmQ)v_^?dtQw_l>^%~D#Hd+YjZ$il&`{L=Sta(SXc4Y*YXM;JS{sy2%ya``aM$E3_avi30$r zE<#N$156x)AwGWIuI`>LkN~8Q3&bVF-4y@`nI%|Ry};kYoDT`Ff#$REKFK-kop?i% z3QvpHPg&Lnzj@m^-k3J&lW6lxk01A3B2H;9qCTY*qzbRnFUuEJ#s#I67ilEa`Zt4X0l#;>$UQP4eK&84~sg)`Tu_YVWlMzS2|K!S!nV;6IQVRM5|{o};a zPflYJ4& zDr^OcWVGOHnUxOG9^$U^%1h|?kLS47+UQB=dFHtkaP;g;j=Rozk%W)XG=Z~648US% zt~2#&A298Mb(#;MV#G^gnT37$UYQ(wzIIJOGt;X0_E);-biCm_nd<(08xl&~oh8;# zTt?QAsNHo%7&TP4XI0xRp*~T40Usebm}4Xdx|yFPG+^WI`Gi%OjZJTrm`M^r*A;F7 zOd)R@znDTwx@0(EY;Ion7!AZbWx`2mSHhBIdWkOmw*cS08tA_{TLZHExh`(nM$s~P zcl}SsGizh;Mwp=Ci^o0dXxLUrDEb z24^4C7a$ZkuChp=>1S$X=q4njC#CqvK?`GphN!+@Df7bf!&Ud&a)XEI;YaMl^d)CE zv4YisU;GW|tVNykMW_$I7dbI}uVYlka9xV+dzW5bQu8o;HYFIn?3i`pnzh(l(6{)# zp}FoT(yhZY$w2C-KHje70#^gDbr0NAT5-#lh>7PfUfKR=<|fFZ1&WmZ@=7n)k?>Gy zr<`{O-+{H94Y;{S?7SXSEu!0k2Adq(uNkU7Gt7r!HRBY`qH?TSL~Yo)?dba5X_>d~ z`zbf8tPtJu=G01TI#G8eL&c%`DSD*uEhWOah_v?dJAn}O72FN|+0p%@(nX!#*3b`6DzKv|02S#^z z4ScQ0K@*EvFB9jNX+W_KXzsg>1RtyPO6Ymm7(sy!On*saNb{dw5h!61;FwxVARzTQLyz;2S zC@G~adX?@uM%NDn`wE|Bc+OwJlzHw#viw!AOSf$ws=&QfL4*9*-;TMN12wUT&S#}a zZT8G_4b|9F?YUn^RoPPHrBOm@{?gKIm*@qW3*@F_Ghx<96ZhUak_(DU#MRIVrXun(l278k$a$h0 zPfTW#K7zXST(lYd(2O)_iCsfTRmJkWl0S!mh=1qP@5iN*9PYx&CA_*@tx`(r?{~@c8+zQ*51}K56z1O6eBPk+urU$p;wi8JYrZKhNnr92?tV zmb|gxyR)}Ch2Z+WL-$}ZW*V-^4HbvB9qT1<O#g}2ZqhL(>iE;f-Cv6^r9_8wt;+r&yMV=7ZuX*VQ!N=fgW86#zc-Y)Y><1 zE+>@^8garKDSTkFl=Xw{+Mo?tI_n%g;2KfHx{m8Cqq!N& zgD;%B!7ok#9(QQZX3A;fDr>kZPX;*73y0`+fnay zx^i?n--Cr&EHnV3Z?8$2Mu@y@G~|&RXf^r>b42GIB!$$9t0>SHB+xYt2bC`<>qaT+Db={F8EAItYrIJKX&=h=_~mJKQS8b5^A(_|nuH7tVX1J0Khbr`?A{y&N&D=e_= zdDbjDq$o0<2Itl)YY0n4WqoThxmxsOEsen*_e1ZHC3&972s-GdQiuDJ$Q|g z@tqLkvHgHrB6GN^;SiNu-wNEcqS=Syv3qy>mYm9{J= zJ=f*4jtNN-ev3=Fdr>1K>*%eDR()P8%ks?xw_Hc_c$xSr>D%P%s1>@~!y>zKyE!_{ z{NbzZD|_tgoqZ&uG`X)<6@B9^KVusw25TKW`ZM|+&2Yl@+8woiiz~J0*R@E)i}w!Z z_Eu~1BaZ!z@dDa(r6q~Hy44U^4I(jypD?6&4o|V?&4yukS>(V*vE(zm(U-kDPwH#} z-WyO2KKsHvcfkTA=};|qom(1uvmgsRAAN^j+{@m2w=cNangv!SIeinEw3Su44a`<} zx17O~-^6#~PW6_97_PaL2|V?V{3V6Ot|=q9pD_la+kiK2M2;)E)Q5F;)O2AZMkUYA zfOF-3<0@0Y-K!6U+(}PM{fe*Z1l|#GMU+0;R{j70_07Kx1mqR4T$vOBItCgPYb4Cn zQVeTs;#YqQAW=tM&GgYC;p;fnGYAdY82HcS-TL*49CNyf8Eeh=yBTk1=@v@3;Yvqj|ziNWLY^745VR|P>lBtgtI_ENxxIf1*625g!k}0gx*$iul zMC3TX<}V=SKm23)`lE^$uwZXnN^Mm*>AxERMw2(lS_{-YNi637dO8{ibqvfQ>OZx3 Bg0lbs literal 0 HcmV?d00001 diff --git a/apps/intclock/metadata.json b/apps/intclock/metadata.json new file mode 100644 index 000000000..fff4c58b0 --- /dev/null +++ b/apps/intclock/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "intclock", + "name": "Interlaced Clock", + "version": "0.01", + "description": "A lightweight digital clock using an 'interlaced' font", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"intclock.app.js","url":"app.js"}, + {"name":"intclock.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/intclock/screenshot.png b/apps/intclock/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..33a459f1f768a3421412409d86188397e04fa723 GIT binary patch literal 2101 zcmeHJ{ZrEU7XBcOAgR|oWmyW9Jw{{qK#xyx622d~C+^H}#*hUvK<>uYmb}u;n=H#n4f8{UfF=s9e(fDZWro)F z)yjt=Lzl7two^eP8dsXZp#JO63*Vm0w&TQ_5>Y2DVI+pWs{8r_Y_R)w2 zUg7Xz)DJXX065UPM9=QOOEA;-Gwz4b!)%!(akiLavx5F06`vpLCOacDb@Z^0nH-zL z!)-x{%8wG>F8EQi^{i-~n>{3MAuY`=2uH{6ak|N4@4eE~zlAlOvs_c1+r)Uj<=Qn` zsmA#1))V{=e%{=WMB--+^qeOEkE*Ln3fzQyi@dVRKq%{eVn1lv39S$>PjE#~u+*uJ z!wM$bEB^HG0BCtO>wZ-2=6TZILcj1^*;c7s+TK$){-#2Q6llB)^(%1*Lhb1 zXP&7F)sClV$4K4ilxR$^51V==SN-K zZ09&F?5#IgK-C9aF$ha*MQZjz!%G_n3Joy1GZFeYYXyp`8Hl??W7 zww;zW;Q##d?ab|&C>XSB7qEoFxe?1~oMbO*4C26rI!Kfc@3sci`f^#LoD~d9Xr8*6 zit1KTOkeE$DsF|WYMNfr9 zkdNYd-~e>+PAe-oar`Xq#?2~+-!+o^(}|Vxa+0Yj--ZxQa0}e=9Y#uAF^BLu_Yavv z0pHj$;Tfiro9kkK7{KXk;lR?CbOb;oF>xMP!v6@`p!n}Q+3L|WhICH0_=_q?j8)f+ zWQI1jgxn*g((8Ih+r2YKJ+_AV?v}h@VGv%RL3eb;NnhiRp-*|X6g9T{D*S}(17U^C<7k_;Tr%c*d#5Q5zU5pvIWplWD`ANlC=D<9=F5nN;=YnWR_SEtv_L&XnSuO6`aT!jhVMC|-xo23Ero+( p7yrH9V889vqjmqs|Eq%$wtH_rNf=6*H2nd<$NQ@jHC|!Y{{!gi${GLw literal 0 HcmV?d00001 From a452887ba6b8bdc1f33fdcc940d1aaf2dfc84227 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 16:11:34 +0000 Subject: [PATCH 245/447] Fix settings wrapping code for new menu system --- apps/alarm/ChangeLog | 1 + apps/alarm/app.js | 16 ++++++++-------- apps/alarm/metadata.json | 2 +- apps/hardalarm/ChangeLog | 1 + apps/hardalarm/app.js | 18 +++++++++--------- apps/hardalarm/metadata.json | 2 +- apps/tabata/ChangeLog | 1 + apps/tabata/metadata.json | 2 +- apps/tabata/tabata.js | 19 +++++++++---------- 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index d129e9f9f..4576237a5 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -13,3 +13,4 @@ Widgets now shown on Alarm screen 0.13: Alarm widget state now updates when setting/resetting an alarm 0.14: Order of 'back' menu item +0.15: Fix hour/minute wrapping code for new menu system diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 17062d44a..f7edcd1c4 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -73,12 +73,12 @@ function editAlarm(alarmIndex) { '': { 'title': /*LANG*/'Alarm' }, /*LANG*/'< Back' : showMainMenu, /*LANG*/'Hours': { - value: hrs, - onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this' + value: hrs, min : 0, max : 23, wrap : true, + onchange: v => hrs=v; }, /*LANG*/'Minutes': { - value: mins, - onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this' + value: mins, min : 0, max : 59, wrap : true, + onchange: v => mins=v; }, /*LANG*/'Enabled': { value: en, @@ -138,12 +138,12 @@ function editTimer(alarmIndex) { const menu = { '': { 'title': /*LANG*/'Timer' }, /*LANG*/'Hours': { - value: hrs, - onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this' + value: hrs, min : 0, max : 23, wrap : true, + onchange: v => hrs=v; }, /*LANG*/'Minutes': { - value: mins, - onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this' + value: mins, min : 0, max : 59, wrap : true, + onchange: v => mins=v; }, /*LANG*/'Enabled': { value: en, diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index 3e109bda9..d29298309 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,7 +2,7 @@ "id": "alarm", "name": "Default Alarm & Timer", "shortName": "Alarms", - "version": "0.14", + "version": "0.15", "description": "Set and respond to alarms and timers", "icon": "app.png", "tags": "tool,alarm,widget", diff --git a/apps/hardalarm/ChangeLog b/apps/hardalarm/ChangeLog index 7e9b17f2a..dac7d317e 100644 --- a/apps/hardalarm/ChangeLog +++ b/apps/hardalarm/ChangeLog @@ -1,2 +1,3 @@ 0.01: Add a number to match to turn off alarm 0.02: Respect Quiet Mode +0.03: Fix hour/minute wrapping code for new menu system diff --git a/apps/hardalarm/app.js b/apps/hardalarm/app.js index 61467b421..09b73d318 100644 --- a/apps/hardalarm/app.js +++ b/apps/hardalarm/app.js @@ -56,25 +56,25 @@ function editAlarm(alarmIndex) { } const menu = { '': { 'title': 'Alarms' }, - 'Hours': { - value: hrs, - onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this' + /*LANG*/'Hours': { + value: hrs, min : 0, max : 23, wrap : true, + onchange: v => hrs=v; }, - 'Minutes': { - value: mins, - onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this' + /*LANG*/'Minutes': { + value: mins, min : 0, max : 59, wrap : true, + onchange: v => mins=v; }, - 'Enabled': { + /*LANG*/'Enabled': { value: en, format: v=>v?"On":"Off", onchange: v=>en=v }, - 'Repeat': { + /*LANG*/'Repeat': { value: en, format: v=>v?"Yes":"No", onchange: v=>repeat=v }, - 'Auto snooze': { + /*LANG*/'Auto snooze': { value: as, format: v=>v?"Yes":"No", onchange: v=>as=v diff --git a/apps/hardalarm/metadata.json b/apps/hardalarm/metadata.json index 13a8fb920..1dab4501d 100644 --- a/apps/hardalarm/metadata.json +++ b/apps/hardalarm/metadata.json @@ -2,7 +2,7 @@ "id": "hardalarm", "name": "Hard Alarm", "shortName": "HardAlarm", - "version": "0.02", + "version": "0.03", "description": "Make sure you wake up! Count to the right number to turn off the alarm", "icon": "app.png", "tags": "tool,alarm,widget", diff --git a/apps/tabata/ChangeLog b/apps/tabata/ChangeLog index 5560f00bc..86faf17a5 100644 --- a/apps/tabata/ChangeLog +++ b/apps/tabata/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Fix settings wrapping code for new menu system diff --git a/apps/tabata/metadata.json b/apps/tabata/metadata.json index 14429090f..a840c9c8b 100644 --- a/apps/tabata/metadata.json +++ b/apps/tabata/metadata.json @@ -2,7 +2,7 @@ "id": "tabata", "name": "Tabata", "shortName": "Tabata - Control High-Intensity Interval Training", - "version": "0.01", + "version": "0.02", "description": "Control high-intensity interval training (according to tabata: https://en.wikipedia.org/wiki/Tabata_method).", "icon": "tabata.png", "tags": "workout,health", diff --git a/apps/tabata/tabata.js b/apps/tabata/tabata.js index 603cf96ee..f6addc35b 100644 --- a/apps/tabata/tabata.js +++ b/apps/tabata/tabata.js @@ -30,18 +30,17 @@ function showMainMenu() { }, 'Pause sec.': { value: settings.pause, - onchange: function(v){ - if (v<0)v=MAX_SECONDS; - if (v>MAX_SECONDS)v=0; + min : 0, max : MAX_SECONDS, wrap : true, + onchange: v => { settings.pause=v; - this.value=v; saveSettingsDebounce(); } }, 'Trainig sec.': { value: settings.training, - onchange: function(v){if (v<0)v=MAX_SECONDS;if (v>MAX_SECONDS)v=0;settings.training=v; - this.value=v; + min : 0, max : MAX_SECONDS, wrap : true, + onchange: v => { + settings.training=v; saveSettingsDebounce(); } }, @@ -61,8 +60,8 @@ function startTabata() { g.clear(); Bangle.setLCDMode("doublebuffered"); g.flip(); - var pause = settings.pause, - training = settings.training, + var pause = settings.pause, + training = settings.training, round = 1, active = true, clearBtn1, clearBtn2, clearBtn3, timer; @@ -86,7 +85,7 @@ function startTabata() { exitTraining(); return; } - + if (active) { drawCountDown(round, training, active); training--; @@ -117,7 +116,7 @@ function drawCountDown(round, count, active) { g.setFontAlign(0,0); g.setFont("6x8", 2); - g.drawString("Round " + round + "/" + settings.rounds,120,6); + g.drawString("Round " + round + "/" + settings.rounds,120,6); g.setFont("6x8", 6); g.drawString("" + count,120,80); From 79e434d0c2ba06fc8da29181da35e08fb7495814 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 16:22:54 +0000 Subject: [PATCH 246/447] color adjustment - all 'accented' background items are now bg2, only unread messages are bgH --- apps/messages/app.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 0cf13db2c..6feda9494 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -141,8 +141,8 @@ function showMapMessage(msg) { eta = m[2]; } else target=msg.body; layout = new Layout({ type:"v", c: [ - {type:"txt", font:fontMedium, label:target, bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, pad:2 }, - {type:"h", bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, c: [ + {type:"txt", font:fontMedium, label:target, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 }, + {type:"h", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, c: [ {type:"txt", font:"6x8", label:"Towards" }, {type:"txt", font:fontLarge, label:street } ]}, @@ -179,7 +179,7 @@ function showMusicMessage(msg) { checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); } layout = new Layout({ type:"v", c: [ - {type:"h", fillx:1, bgCol:g.theme.bgH, col: g.theme.fgH, c: [ + {type:"h", fillx:1, bgCol:g.theme.bg2, col: g.theme.fg2, c: [ { type:"btn", src:getBackImage, cb:back }, { type:"v", fillx:1, c: [ { type:"txt", font:fontMedium, label:msg.artist, pad:2 }, @@ -212,8 +212,8 @@ function showMessageScroller(msg) { // a function to draw a menu item draw : function(idx, r) { // FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12 - g.setBgColor(idx{ cancelReloadTimeout(); // don't auto-reload to clock now showMessageSettings(msg); }}, { type:"v", fillx:1, c: [ - {type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, pad:2, halign:1 }, - title?{type:"txt", font:titleFont, label:title, bgCol:g.theme.bgH, col: g.theme.fgH, fillx:1, pad:2 }:{}, + {type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2, halign:1 }, + title?{type:"txt", font:titleFont, label:title, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 }:{}, ]}, ]}, {type:"txt", font:bodyFont, label:body, fillx:1, filly:1, pad:2, cb:()=>{ From 75694c9be12cb414dec7f11e74359d9577f16f42 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 16:29:06 +0000 Subject: [PATCH 247/447] change default background for dark theme to something a bit less extreme --- apps/setting/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 09d95934f..f74c94db0 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -226,7 +226,7 @@ function showThemeMenu() { /*LANG*/'Dark BW': ()=>{ upd({ fg:cl("#fff"), bg:cl("#000"), - fg2:cl("#0ff"), bg2:cl("#000"), + fg2:cl("#fff"), bg2:cl("#004"), fgH:cl("#fff"), bgH:cl("#00f"), dark:true }); From d811398a59c7e38f6a90b2b1513853aaa2080986 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 16:36:25 +0000 Subject: [PATCH 248/447] oops - fix errors in prev commit --- apps/alarm/app.js | 8 ++++---- apps/hardalarm/app.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/alarm/app.js b/apps/alarm/app.js index f7edcd1c4..56184edf1 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -74,11 +74,11 @@ function editAlarm(alarmIndex) { /*LANG*/'< Back' : showMainMenu, /*LANG*/'Hours': { value: hrs, min : 0, max : 23, wrap : true, - onchange: v => hrs=v; + onchange: v => hrs=v }, /*LANG*/'Minutes': { value: mins, min : 0, max : 59, wrap : true, - onchange: v => mins=v; + onchange: v => mins=v }, /*LANG*/'Enabled': { value: en, @@ -139,11 +139,11 @@ function editTimer(alarmIndex) { '': { 'title': /*LANG*/'Timer' }, /*LANG*/'Hours': { value: hrs, min : 0, max : 23, wrap : true, - onchange: v => hrs=v; + onchange: v => hrs=v }, /*LANG*/'Minutes': { value: mins, min : 0, max : 59, wrap : true, - onchange: v => mins=v; + onchange: v => mins=v }, /*LANG*/'Enabled': { value: en, diff --git a/apps/hardalarm/app.js b/apps/hardalarm/app.js index 09b73d318..0c72a2c8f 100644 --- a/apps/hardalarm/app.js +++ b/apps/hardalarm/app.js @@ -58,11 +58,11 @@ function editAlarm(alarmIndex) { '': { 'title': 'Alarms' }, /*LANG*/'Hours': { value: hrs, min : 0, max : 23, wrap : true, - onchange: v => hrs=v; + onchange: v => hrs=v }, /*LANG*/'Minutes': { value: mins, min : 0, max : 59, wrap : true, - onchange: v => mins=v; + onchange: v => mins=v }, /*LANG*/'Enabled': { value: en, From 582b00e08bc47c1fde66e0b4acd4b15bc6f48832 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 16:37:01 +0000 Subject: [PATCH 249/447] copy/paste error --- apps/intclock/ChangeLog | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/intclock/ChangeLog b/apps/intclock/ChangeLog index aa910b6f6..2ad07562f 100644 --- a/apps/intclock/ChangeLog +++ b/apps/intclock/ChangeLog @@ -1,12 +1 @@ -0.02: Modified for use with new bootloader and firmware -0.03: add hour ticks, remove timers -0.04: add day-date display -0.07: make date and face bigger -0.08: make dots bigger and date more readable -0.09: center date, remove box around it, internal refactor to remove redundant code. -0.10: remove debug, refactor seconds to show elapsed secs each time app is displayed -0.11: shift face down for widget area, maximize face size, 0 pad single digit date, use locale for date -0.12: Fix regression after 0.11 -0.13: Fix broken date padding (fix #376) -0.14: Remove hardcoded hour buzz (you can install widchime if you miss it) -0.15: Add color scheme support +0.01: Initial commit From 597d1172be39b9692485eb1a70b40c955a4166e6 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 23 Feb 2022 16:38:26 +0000 Subject: [PATCH 250/447] changelog tweak --- apps/speedalt2/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/speedalt2/ChangeLog b/apps/speedalt2/ChangeLog index 602147856..73e9bfc40 100644 --- a/apps/speedalt2/ChangeLog +++ b/apps/speedalt2/ChangeLog @@ -12,4 +12,4 @@ 1.10: Adds Kalman filter. 1.14: Add VMG and coordinates screens 1.43: Adds mirroring of the watch face to an Android device. See README.md -1.48: Droidscript mirroring prog automatically uses last connection address. Auto connects when run. +1.49: Droidscript mirroring prog automatically uses last connection address. Auto connects when run. From 54ca2eed97906fc9362fcdc1b25294ffb1b4c91a Mon Sep 17 00:00:00 2001 From: copoer Date: Wed, 23 Feb 2022 12:57:22 -0400 Subject: [PATCH 251/447] Fix step count --- modules/exstats.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exstats.js b/modules/exstats.js index 8a726a5de..b72ee6584 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -119,6 +119,7 @@ Bangle.on("GPS", function(fix) { Bangle.on("step", function(steps) { if (!state.active) return; if (stats["step"]) stats["step"].emit("changed",stats["step"]); + state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; }); Bangle.on("HRM", function(h) { From 792d9a316681c31657b69aaf5f947ee3340924b6 Mon Sep 17 00:00:00 2001 From: copoer Date: Wed, 23 Feb 2022 13:18:12 -0400 Subject: [PATCH 252/447] Local for time in contour clock --- apps/contourclock/lib.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/contourclock/lib.js b/apps/contourclock/lib.js index 65a4622f4..aa83fca26 100644 --- a/apps/contourclock/lib.js +++ b/apps/contourclock/lib.js @@ -13,13 +13,15 @@ exports.drawClock = function(fontIndex) { if (n!=10) return (false); //font file seems to be invalid var x=0; var y = g.getHeight()/2-digits[0].height/2; - var date = new Date(); + var date = require('locale').time(new Date(),1); + var hours = date.split(":")[0]; + var minutes = date.split(":")[1]; g.clearRect(0,38,g.getWidth()-1,138); - d1=parseInt(date.getHours()/10); - d2=parseInt(date.getHours()%10); + d1=parseInt(hours/10); + d2=parseInt(hours%10); d3=10; - d4=parseInt(date.getMinutes()/10); - d5=parseInt(date.getMinutes()%10); + d4=parseInt(minutes/10); + d5=parseInt(minutes%10); w1=digits[d1].width; w2=digits[d2].width; w3=digits[d3].width; From da25e418058e5b85c6dfd85d91847d34ecdf7acc Mon Sep 17 00:00:00 2001 From: copoer Date: Wed, 23 Feb 2022 13:24:59 -0400 Subject: [PATCH 253/447] Change log --- apps/contourclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/contourclock/ChangeLog b/apps/contourclock/ChangeLog index 9c62e637b..aed7baf64 100644 --- a/apps/contourclock/ChangeLog +++ b/apps/contourclock/ChangeLog @@ -5,3 +5,4 @@ 0.23: Customizer! Unused fonts no longer take up precious memory. 0.24: Added previews to the customizer. 0.25: Fixed a bug that would let widgets change the color of the clock. +0.26: Time now works with locale formatting From e3b558b1f037bee198334536dc368ee134650b1f Mon Sep 17 00:00:00 2001 From: Marco H Date: Wed, 23 Feb 2022 20:29:29 +0100 Subject: [PATCH 254/447] Threema icon and color --- apps/messages/app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/messages/app.js b/apps/messages/app.js index 6feda9494..512659c40 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -92,6 +92,7 @@ function getMessageImage(msg) { if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA=="); if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA=="); if (s=="sms message") return getNotificationImage(); + if (s=="threema") return atob("ICCDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//+AAAAAAAAAAAP/////wAAAAAAAAB//////+AAAAAAAAP///////wAAAAAAB////////+AAAAAAP///wAP///wAAAAAP/////////wAAAAAP//+P/x///wAAAAAP//+P/x///+AAAAB///+AAB///+AAAAAP//+AAB///+AAAAAP//+AAB///wAAAAAP//+AAB///wAAAAAB/////////wAAAAAB////////+AAAAAAB////////wAAAAAAB///////+AAAAAAAP//////+AAAAAAAAP+AAP/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEkAAkAAkgAAAAAAAEkAEkgAkgAAAAAAAEkAAkAAkgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA"); if (s=="telegram") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA=="); @@ -120,6 +121,7 @@ function getMessageImageCol(msg,def) { "outlook mail": "#0072c6", "skype": "#00aff0", "slack": "#e51670", + "threema": "#000", "telegram": "#0088cc", "twitter": "#1da1f2", "whatsapp": "#4fce5d", From b53289492da91b2291828f2dbdba8850a413e75f Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:45:11 -0800 Subject: [PATCH 255/447] Create metadata.json --- apps/aptsciclk/metadata.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 apps/aptsciclk/metadata.json diff --git a/apps/aptsciclk/metadata.json b/apps/aptsciclk/metadata.json new file mode 100644 index 000000000..8ee53956b --- /dev/null +++ b/apps/aptsciclk/metadata.json @@ -0,0 +1,17 @@ +{ + "id": "aptsciclk", + "name": "Apeture Science Clock", + "shortName":"AptSci Clock", + "version": "0.08", + "description": "A clock based on the portal series", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": "BANGLEJS2", + "allow_emulator": false, + "storage": [ + {"name":"aptsciclkquotes.txt","url":"quotes.txt"}, + {"name":"aptsciclk.app.js","url":"app.js"}, + {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} + ] +} From 944560b123dcbc8cb94319bcb7907fb3fc66498a Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:46:14 -0800 Subject: [PATCH 256/447] added README.md --- apps/aptsciclk/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/aptsciclk/metadata.json b/apps/aptsciclk/metadata.json index 8ee53956b..15d8ec4e3 100644 --- a/apps/aptsciclk/metadata.json +++ b/apps/aptsciclk/metadata.json @@ -9,6 +9,7 @@ "tags": "clock", "supports": "BANGLEJS2", "allow_emulator": false, + "readme":"README.md", "storage": [ {"name":"aptsciclkquotes.txt","url":"quotes.txt"}, {"name":"aptsciclk.app.js","url":"app.js"}, From f716f6fe40bb10c096300aee845dba769c95e7df Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:57:30 -0800 Subject: [PATCH 257/447] Create README.md --- apps/aptsciclk/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/aptsciclk/README.md diff --git a/apps/aptsciclk/README.md b/apps/aptsciclk/README.md new file mode 100644 index 000000000..e56b36f09 --- /dev/null +++ b/apps/aptsciclk/README.md @@ -0,0 +1,7 @@ +#Description +This is a simple clock based on the Portal Series. + +#Features +The button in the center of the screen is interactable and the warning image will change when it is pressed. +Potato GLaDOS in the bottom left corner is interactable and will display a quote when tapped. (You can add more quotes by editing the `aptsciclkquotes.txt` file seperating each quote with a `^`) +When the app loads the Apeture Science Logo is displayed. From f1fe1b4fe350f34410731847166073d43d598066 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 11:58:24 -0800 Subject: [PATCH 258/447] Update README.md --- apps/aptsciclk/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/aptsciclk/README.md b/apps/aptsciclk/README.md index e56b36f09..68f132a1f 100644 --- a/apps/aptsciclk/README.md +++ b/apps/aptsciclk/README.md @@ -1,7 +1,9 @@ #Description + This is a simple clock based on the Portal Series. #Features + The button in the center of the screen is interactable and the warning image will change when it is pressed. Potato GLaDOS in the bottom left corner is interactable and will display a quote when tapped. (You can add more quotes by editing the `aptsciclkquotes.txt` file seperating each quote with a `^`) When the app loads the Apeture Science Logo is displayed. From 7ce25c8774d6846d2430f2bb6a22625d444578a9 Mon Sep 17 00:00:00 2001 From: Sven Klomp Date: Wed, 23 Feb 2022 20:50:45 +0100 Subject: [PATCH 259/447] Initial commit of widcw widcw is a widget to display the current calendar week. --- apps/widcw/ChangeLog | 1 + apps/widcw/logo.svg | 62 +++++++++++++++++++++++++++++++++++++++ apps/widcw/metadata.json | 13 ++++++++ apps/widcw/widget.js | 48 ++++++++++++++++++++++++++++++ apps/widcw/widget.png | Bin 0 -> 884 bytes apps/widcw/widget.svg | 55 ++++++++++++++++++++++++++++++++++ 6 files changed, 179 insertions(+) create mode 100644 apps/widcw/ChangeLog create mode 100644 apps/widcw/logo.svg create mode 100644 apps/widcw/metadata.json create mode 100644 apps/widcw/widget.js create mode 100644 apps/widcw/widget.png create mode 100644 apps/widcw/widget.svg diff --git a/apps/widcw/ChangeLog b/apps/widcw/ChangeLog new file mode 100644 index 000000000..a4bc24d1a --- /dev/null +++ b/apps/widcw/ChangeLog @@ -0,0 +1 @@ +0.01: First version \ No newline at end of file diff --git a/apps/widcw/logo.svg b/apps/widcw/logo.svg new file mode 100644 index 000000000..e093414d5 --- /dev/null +++ b/apps/widcw/logo.svg @@ -0,0 +1,62 @@ + + + + + + + + CW + + diff --git a/apps/widcw/metadata.json b/apps/widcw/metadata.json new file mode 100644 index 000000000..653b093ec --- /dev/null +++ b/apps/widcw/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "widcw", + "name": "Calendar Week Widget", + "version": "0.01", + "description": "Widget which shows the current calendar week", + "icon": "widget.png", + "type": "widget", + "tags": "widget,calendar", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widcw.wid.js","url":"widget.js"} + ] +} diff --git a/apps/widcw/widget.js b/apps/widcw/widget.js new file mode 100644 index 000000000..ef43a4551 --- /dev/null +++ b/apps/widcw/widget.js @@ -0,0 +1,48 @@ +(function() { + var width = 22; // width of the widget + + function draw() { + const x = this.x, y = this.y, x2 = x+21, y2 = y+23; + + var date = new Date(); + + // Calculate calendar week (https://stackoverflow.com/a/6117889) + getCW= function(date){ + var d=new Date(date.getFullYear(), date.getMonth(), date.getDate()); + var dayNum = d.getDay() || 7; + d.setDate(d.getDate() + 4 - dayNum); + var yearStart = new Date(d.getFullYear(),0,1); + return Math.ceil((((d - yearStart) / 86400000) + 1)/7); + }; + + g.reset().setFontAlign(0, 0) // center all text + // header + .setBgColor("#f00").setColor("#fff") + .clearRect(x, y, x2, y+8).setFont("4x6").drawString("CW", (x+x2)/2+1, y+5) + // date + .setBgColor("#fff").setColor("#000") + .clearRect(x, y+9, x2, y2).setFont("Vector:16").drawString(getCW(date), (x+x2)/2+2, y+17); + + if (!g.theme.dark) { + // black border around date for light themes + g.setColor("#000").drawPoly([ + x, y+9, + x, y2, + x2, y2, + x2, y+9 + ]); + } + + // redraw when date changes + setTimeout(()=>WIDGETS["widcw"].draw(), (86401 - Math.floor(date/1000) % 86400)*1000); + + } + + // add your widget + WIDGETS["widcw"]={ + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: width, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout + draw:draw // called to draw the widget + }; + +})(); diff --git a/apps/widcw/widget.png b/apps/widcw/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..c73d40c5a60b0f618d12a23276b14d53325b23df GIT binary patch literal 884 zcmV-)1B?8LP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10|7}y zK~!jg?bknuT}2ef@lTRXRxvSa5rwF+Q;VpmiBV9|R&BIV5MpDRlvXMTf+>R9st}UY zR)T`WuvQU-z#@o$hzg1r5DA<86L;V4Gx1r>T=u+q_r?37<$PgaXXZC|&Y3yyoLMTB zN~Kb%R4SFqHL|IrZVC_L0Cr(J7Vtej$70almo<^IxD@&~j%9;p@VIp1(?Pd@-;2$5XZ<4fO5sbzPjf ztuSC9B?M9!M#Cd!8)aJmTWvpw#i<~L?Jt;IU=YAij@tJfJq-1cY#jZIiDn@8?;5VaA?CoUo zFsFlIq?3QiMyl*dPR1LU#=&C$_57{QJnO&zh)Ln{XYrlb*0aHzY-FOgwunb3abTy> zLUXk=dLuqCoJNf?Y%To#bYZk5vKq>s5s zTSaZcVkYROIyyQr+wiLNzF8`q8TXuyOy&9c&=&Ahi}uU>y{Ii69ieM}-+~A55N?q& z&b$<#DwRs*|KT5a_e&ZbqWHf60000< KMNUMnLSTZK%c`yb literal 0 HcmV?d00001 diff --git a/apps/widcw/widget.svg b/apps/widcw/widget.svg new file mode 100644 index 000000000..d3e567286 --- /dev/null +++ b/apps/widcw/widget.svg @@ -0,0 +1,55 @@ + + + + + + + + CW + + From 32671875c3cc7d6136bffe4fb8cc17451557b096 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 23 Feb 2022 23:20:57 +0000 Subject: [PATCH 260/447] Daisy - added settings menu --- apps/daisy/ChangeLog | 1 + apps/daisy/README.md | 1 - apps/daisy/app.js | 24 ++++++++++++------- apps/daisy/metadata.json | 8 ++++--- apps/daisy/settings.js | 51 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 apps/daisy/settings.js diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index 9db0e26c5..4fdf333e4 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: added settings menu to change color diff --git a/apps/daisy/README.md b/apps/daisy/README.md index f6c0014be..3f22f5dd9 100644 --- a/apps/daisy/README.md +++ b/apps/daisy/README.md @@ -16,7 +16,6 @@ Forum](http://forum.espruino.com/microcosms/1424/) * Uses the [BloggerSansLight](https://www.1001fonts.com/rounded-fonts.html?page=3) font, which if free for commercial use ## Future Development -* Add settings menu to change primary clock color * 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 diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 5490d0740..38b839138 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -1,7 +1,7 @@ var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); const storage = require('Storage'); const locale = require("locale"); -const SETTINGS_FILE = "pastel.json"; // XXX +const SETTINGS_FILE = "daisy.json"; const LOCATION_FILE = "mylocation.json"; const h = g.getHeight(); const w = g.getWidth(); @@ -14,13 +14,10 @@ let warned = 0; let idle = false; let IDLE_MINUTES = 26; -// palette for 0-40% -const pal1 = new Uint16Array([g.theme.bg, g.toColor("#020"), g.toColor("#0f0"), g.toColor("#00f")]); -// palette for 50-100% -const pal2 = new Uint16Array([g.theme.bg, g.toColor("#0f0"), g.toColor("#020"), g.toColor("#00f")]); +var pal1; // palette for 0-40% +var pal2; // palette for 50-100% const infoWidth = 50; const infoHeight = 14; - var drawingSteps = false; function log_debug(o) { @@ -40,6 +37,13 @@ Graphics.prototype.setFontRoboto20 = function(scale) { return this; } +function assignPalettes() { + // palette for 0-40% + pal1 = new Uint16Array([g.theme.bg, g.toColor(settings.gy), g.toColor(settings.color), g.toColor("#00f")]); + // palette for 50-100% + pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.color), g.toColor(settings.gy), g.toColor("#00f")]); +} + function setSmallFont20() { g.setFontRoboto20(); } @@ -67,9 +71,11 @@ function getSteps() { function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; - settings.grid = settings.grid||false; - settings.font = settings.font||"Lato"; + settings.color = settings.color||'Green'; + settings.gy = settings.gy||'gy'; + settings.bg = settings.bg||'#0f0'; settings.idle_check = settings.idle_check||true; + assignPalettes(); } // requires the myLocation app @@ -266,7 +272,7 @@ function drawClock() { g.drawImage(getGaugeImage(p_steps), 0, 0); setLargeFont(); - g.setColor('#0f0'); + g.setColor(settings.color); g.setFontAlign(1,0); // right aligned g.drawString(hh, (w/2) - 1, h/2); diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index fe66683a7..f2624a0f3 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.01", + "version":"0.02", "dependencies": {"mylocation":"app"}, "description": "A clock based on the Pastel clock with large ring guage for steps", "icon": "app.png", @@ -10,6 +10,8 @@ "readme": "README.md", "storage": [ {"name":"daisy.app.js","url":"app.js"}, - {"name":"daisy.img","url":"app-icon.js","evaluate":true} - ] + {"name":"daisy.img","url":"app-icon.js","evaluate":true}, + {"name":"daisy.settings.js","url":"daisy.settings.js"} + ], + "data": [{"name":"daisy.json"}] } diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js new file mode 100644 index 000000000..6df083fff --- /dev/null +++ b/apps/daisy/settings.js @@ -0,0 +1,51 @@ +(function(back) { + const SETTINGS_FILE = "daisy.json"; + + // initialize with default settings... + let s = {'gy' : '#020', + 'bg' : '#0f0', + 'color': 'Green', + 'check_idle' : true}; + + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage') + let settings = storage.readJSON(SETTINGS_FILE, 1) || s; + const saved = settings || {} + for (const key in saved) { + s[key] = saved[key] + } + + function save() { + settings = s + storage.write(SETTINGS_FILE, settings) + } + + var color_options = ['Green','Orange','Cyan','Purple','Red','Blue']; + var bg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f']; + var gy_code = ['#020','#220','#022','#202','#200','#002']; + + E.showMenu({ + '': { 'title': 'Daisy Clock' }, + '< Back': back, + 'Colour': { + value: 0 | color_options.indexOf(s.color), + min: 0, max: 5, + format: v => color_options[v], + onchange: v => { + s.color = color_options[v]; + s.bg = bg_code[v]; + s.gy = gy_code[v]; + save(); + }, + }, + 'Idle Warning': { + value: !!s.idle_check, + format: v => v ? /*LANG*/"Yes":/*LANG*/"No", + onchange: v => { + s.idle_check = v; + save(); + }, + } + }); +}) From 48d2a08e83ff45ac850b6d7d8769c54550476718 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 23 Feb 2022 23:50:49 +0000 Subject: [PATCH 261/447] Daisy - added settings menu --- apps/daisy/app.js | 13 ++++++------- apps/daisy/settings.js | 6 +++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 38b839138..2717f94db 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -35,13 +35,13 @@ Graphics.prototype.setFontRoboto20 = function(scale) { // Actual height 21 (20 - 0) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAH/zA/+YAAAAAAAHwAAwAAHwAA+AAAAAAAAAAAQACDAAYbADP4B/8A/zAGYZADH4A/+A/7AHYYADCAAAAAAAQAeHgH4eBzgwMMHnhw88GGBw4wHj+AcPgAAAAAAAAAAB4AA/gAGMAAwhwGMcAfuABzgABzgAc+AOMYBhBAAMYAB/AAHwAAAAAHwD5+A/8YGPDAw8YGPzA/HYD4fAADwAB/AAOYAABAAAAHwAA4AAAAAAAAAAH/gD//B8A+cAA7AADAAAAAAAYAAbwAHHgHwf/4A/8AAAAEAABiAAGwAA8AA/AAH+AAGwAByAAEAAAAAAAMAABgAAMAABgAH/wA/+AAMAABgAAMAABgAAAAAAAIAAfAADwAAAABgAAMAABgAAMAABgAAAAAAAAAAAAADAAAYAAAAAAAAADgAB8AB+AA+AA+AA/AAHAAAgAAAAAAB8AB/8Af/wHAHAwAYGADAwAYHAHAf/wB/8AAAAAAAAAAABgAAcAADAAAYAAH//A//4AAAAAAAAAAAAAAAAAAAAABwDAeA4HAPAwHYGBzAwcYHHDAfwYB8DAAAYAAAAAAABgOAcBwHADAwwYGGDAwwYHPHAf/wB58AAAAAAAAADAAB4AAfAAPYAHjAB4YA8DAH//A//4AAYAADAAAAAAAAAEMA/xwH+HAxgYGMDAxgYGODAw/4GD+AAHAAAAAAAAAf8AP/wD2HA5wYGMDAxgYGOHAA/wAD8AAAAAAAAAAAGAAAwAAGADAwB4GB+Aw+AGfAA/gAHwAAwAAAAAAADAB5+Af/wHPDAwwYGGDAwwYHPHAfvwB58AAAAAAAAAAAB+AAf4AHDjAwMYGBjAwM4HDOAf/gB/4AAAAAAAAAAAAYDADAYAAAAAAAAAAYDAfAYHwAAAABAAAcAADgAA+AAGwAB3AAMYABjgAYMAAAAAAAAAAAAAAABmAAMwABmAAMwABmAAMwABmAAMwAAiAAAAAAAAAYMADjgAMYAB3AAGwAA2AADgAAcAABAAAAAAAAAMAADgAA4AAGBzAweYGHAA/wAD8AAEAAAAwAB/4A/PwOAGDgAYYPxmH/Mw4ZmMDMxgZmM+Mx/5mHDAYAIDgDAPBwAf8AAMAAAAAAAYAAfAAPwAP4AH+AH4wA8GAH4wAP2AAPwAAfwAAfAAAYAAAAAAAAAAA//4H//AwwYGGDAwwYGGDAwwYH/HAf/wB58AAAAADAAH/AD/+AcBwHADAwAYGADAwAYGADA4A4DweAODgAAAAAAAAAAAAAAH//A//4GADAwAYGADAwAYGADAYAwD4+AP/gAfwAAAAAAAAAAAH//A//4GDDAwYYGDDAwYYGDDAwYYGCDAgAYAAAAAAAH//A//4GDAAwYAGDAAwYAGDAAwYAGAAAAAAAAAAH/AD/8AcBwHAHAwAYGADAwYYGDDA4YYDz/AOfwAAAAAAAAAAA//4H//A//4ADAAAYAADAAAYAADAAAYAADAA//4H//AAAAAAAAAAAAAAA//4H//AAAAAAAAABAAAeAAB4AADAAAYAADAAAYAAHA//wH/8AAAAAAAAAAAAAAA//4H//AAcAAPAAD4AA/wAOPADg8A4B4GAHAgAYAAAAAAAH//A//4AADAAAYAADAAAYAADAAAYAADAAAAAAAA//4H//A+AAB+AAD8AAD8AAH4AAPAAH4AH4AD8AD8AA+AAH//A//4AAAAAAAH//A//4H//AeAAB8AADwAAPgAAeAAA8AADwH//A//4AAAAAAAAAAAH/AB/8AeDwHAHAwAYGADAwAYGADA4A4DweAP/gA/4AAAAAAAAAAAH//A//4GBgAwMAGBgAwMAGBgAwcAH/AAfwAA8AAAAAA/4AP/gDgOA4A4GADAwAYGADAwAYHAHgeD+B/8wD+GAAAAAAAAAAA//4H//AwYAGDAAwYAGDgAweAHH8Afz4B8HAAAIAAYAPDwD8OA5w4GGDAwwYGHDAwYYHDnAePwBw8AAAAGAAAwAAGAAAwAAGAAA//4H//AwAAGAAAwAAGAAAwAAAAAAAAAH/4A//wAAPAAAYAADAAAYAADAAAYAAPA//wH/8AAAAAAAAgAAHAAA/AAB/AAD+AAD+AAD4AAfAAfwAfwAfwAH4AA4AAEAAA+AAH/AAH/gAD/AAD4AD+AH+AH8AA+AAH+AAD+AAD/AAD4AH/AP/AH+AA8AAAAAAAAAGADA4A4HweAPPgA/wAB8AAfwAPvgDweA8B4GADAAAIGAAA4AAHwAAPgAAfAAA/4AH/AD4AB8AA+AAHgAAwAAAAAAAAAGADAwB4GAfAwPYGDzAx4YGeDA/AYHwDA4AYGADAAAAAAAA///3//+wAA2AAGAAAGAAA+AAD8AAD8AAD4AAH4AAHgAAMAAAAwAA2AAG///3//+AAAAAAAAAAAOAAHwAD4AA8AAD8AADwAAGAAAAAAABgAAMAABgAAMAABgAAMAABgAAMAABgAAAEAAAwAADAAAIAAAAAAAAAAEeABn4Ad3ADMYAZjADMYAZmAB/4AP/AAAAAAAA//4H//ABgwAYDADAYAYDADg4AP+AA/gABwAAAAAAAAA/gAP+ADg4AYDADAYAYDADAYAOOABxwAAAAAEAAH8AB/wAcHADAYAYDADAYAcDA//4H//AAAAAAAAAAAAH8AB/wAdnADMYAZjADMYAZjAB84AHmAAMAAMAABgAB//gf/8HMAAxgAGIAAAAAAH8IB/zAcHMDAZgYDMDAZgcHcD//Af/wAAAAAAAAAAH//A//4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAGf/Az/4AAAAAAAAAAMz//mf/4AAAAAAAAAAH//A//4ABwAAeAAH4ABzwAcPACAYAABAAAAAAAA//4H//AAAAAAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/ABgAAYAADAAAYAADgAAP/AA/4AAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAAH8AB/wAcHADAYAYDADAYAYDADx4AP+AA/gAAAAAAAAf/8D//gYDADAYAYDADAYAcHAB/wAH8AAEAAAAAAEAAH8AB/wAcHADAYAYDADAYAYDAD//gf/8AAAAAAAAAAAf/AD/4AcAADAAAYAACAAAAEAB5wAfnADMYAZjADGYAYzADn4AOeAAAAAAAADAAAYAAf/wD//ADAYAYDAAAAAAAAD/gAf/AAA4AADAAAYAADAAAwAf/AD/4AAAAAAAAYAAD4AAP4AAP4AAPAAH4AH4AD8AAcAAAAAAQAADwAAf4AAf4AAPAAP4AP4ADwAAfgAA/gAA/AAD4AH+AD+AAeAAAAAAAAACAYAcHADzwAH8AAfAAH8ADx4AcHACAIAcAMD4BgP4MAP/AAPwAP4AP4AD4AAcAAAAAAAAADAYAYHADD4AY7ADOYAfjADwYAcDADAYAAAAADAAA4AH//B/v8cABzAACAAAH//w//+AAAAAAACAACcAAx/n+H//AA4AAHAAAAAAAAAAAAAOAADgAAYAADAAAcAABgAAGAAAwAAGAADwAAcAAAAA"), 32, atob("BQUHDQwPDQQHBwkMBAYGCQwMDAwMDAwMDAwFBAsMCwoTDg0ODgwMDg8GDA0LEg8ODQ4NDA0ODRMNDQ0GCQYJCQYLDAsMCwcMDAUFCwUSDAwMDAcLBwwKEAoKCgcFBw4A"), 21+(scale<<8)+(1<<16)); return this; -} +}; function assignPalettes() { // palette for 0-40% - pal1 = new Uint16Array([g.theme.bg, g.toColor(settings.gy), g.toColor(settings.color), g.toColor("#00f")]); + pal1 = new Uint16Array([g.theme.bg, g.toColor(settings.gy), g.toColor(settings.fg), g.toColor("#00f")]); // palette for 50-100% - pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.color), g.toColor(settings.gy), g.toColor("#00f")]); + pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.fg), g.toColor(settings.gy), g.toColor("#00f")]); } function setSmallFont20() { @@ -71,9 +71,8 @@ function getSteps() { function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; - settings.color = settings.color||'Green'; - settings.gy = settings.gy||'gy'; - settings.bg = settings.bg||'#0f0'; + settings.gy = settings.gy||'#020'; + settings.fg = settings.fg||'#0f0'; settings.idle_check = settings.idle_check||true; assignPalettes(); } @@ -272,7 +271,7 @@ function drawClock() { g.drawImage(getGaugeImage(p_steps), 0, 0); setLargeFont(); - g.setColor(settings.color); + g.setColor(settings.fg); g.setFontAlign(1,0); // right aligned g.drawString(hh, (w/2) - 1, h/2); diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index 6df083fff..044eee0d1 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -3,7 +3,7 @@ // initialize with default settings... let s = {'gy' : '#020', - 'bg' : '#0f0', + 'fg' : '#0f0', 'color': 'Green', 'check_idle' : true}; @@ -22,7 +22,7 @@ } var color_options = ['Green','Orange','Cyan','Purple','Red','Blue']; - var bg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f']; + var fg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f']; var gy_code = ['#020','#220','#022','#202','#200','#002']; E.showMenu({ @@ -34,7 +34,7 @@ format: v => color_options[v], onchange: v => { s.color = color_options[v]; - s.bg = bg_code[v]; + s.fg = fg_code[v]; s.gy = gy_code[v]; save(); }, From c0ca33388e17791eaaf124c33800056069032cec Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 16:07:51 -0800 Subject: [PATCH 262/447] Update apps.json --- apps.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 7d547a554..b88bd8165 100644 --- a/apps.json +++ b/apps.json @@ -1,7 +1,8 @@ [ { "id": "aptsciclk", - "name": "Apeture Sci Clock", + "name": "Apeture Science Clock", + "shortName":"AptSci Clock", "version": "0.08", "description": "A clock based on the portal series", "icon": "app.png", @@ -9,6 +10,7 @@ "tags": "clock", "supports": "BANGLEJS2", "allow_emulator": false, + "readme":"README.md", "storage": [ {"name":"aptsciclkquotes.txt","url":"quotes.txt"}, {"name":"aptsciclk.app.js","url":"app.js"}, From 6d8cecc92b0a1935d9771f1ca4efb916b41edd13 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 16:20:42 -0800 Subject: [PATCH 263/447] Update README.md --- apps/aptsciclk/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/aptsciclk/README.md b/apps/aptsciclk/README.md index 68f132a1f..975892076 100644 --- a/apps/aptsciclk/README.md +++ b/apps/aptsciclk/README.md @@ -5,5 +5,7 @@ This is a simple clock based on the Portal Series. #Features The button in the center of the screen is interactable and the warning image will change when it is pressed. + Potato GLaDOS in the bottom left corner is interactable and will display a quote when tapped. (You can add more quotes by editing the `aptsciclkquotes.txt` file seperating each quote with a `^`) + When the app loads the Apeture Science Logo is displayed. From a1e3db238e5dac82ac68b02ce4e7a9b87b48d74f Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 16:35:18 -0800 Subject: [PATCH 264/447] Update README.md --- apps/aptsciclk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/aptsciclk/README.md b/apps/aptsciclk/README.md index 975892076..718e3d408 100644 --- a/apps/aptsciclk/README.md +++ b/apps/aptsciclk/README.md @@ -1,8 +1,8 @@ -#Description +# Description This is a simple clock based on the Portal Series. -#Features +# Features The button in the center of the screen is interactable and the warning image will change when it is pressed. From 343f2f55e34edbbb874b4bf5724e9a7be6170ba9 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 19:31:37 -0800 Subject: [PATCH 265/447] Update apps.json --- apps.json | 54 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/apps.json b/apps.json index b88bd8165..537a4f697 100644 --- a/apps.json +++ b/apps.json @@ -1,20 +1,38 @@ +--- +# ================================================================= +# ALL THE INFORMATION INSIDE APPS.JSON HAS NOW BEEN MOVED +# +# You'll find it inside a file called apps/yourapp/metadata.json +# +# Otherwise nothing has changed. GitHub Pages will automatically +# create apps.json as your site is hosted, or if you're hosting +# yourself you can run bin/create_apps_json.sh +# +# If you serve the store from localhost for development/testing, +# the loader looks for apps.local.json instead, you can run +# `bin/create_apps_json.sh apps.local.json` to create that file. +# ================================================================= + +# Uncomment the following line if you only want explicitly listed +# apps to be available on your site + +# restricted: ["boot", "launch", "antonclk", "health", "setting", "about", "widbat", "widbt", "widlock", "widid"] +--- +{%- if page.restricted == nil -%} + {%- assign apps = site.static_files | where: "name", "metadata.json" | map: "path" -%} +{%- else -%} + {%- capture temp -%} + {%- for app in page.restricted %} /apps/{{app}}/metadata.json {%- endfor -%} + {%- endcapture -%} + {%- assign apps = temp | strip | split: " " -%} +{%- endif -%} + [ -{ - "id": "aptsciclk", - "name": "Apeture Science Clock", - "shortName":"AptSci Clock", - "version": "0.08", - "description": "A clock based on the portal series", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports": "BANGLEJS2", - "allow_emulator": false, - "readme":"README.md", - "storage": [ - {"name":"aptsciclkquotes.txt","url":"quotes.txt"}, - {"name":"aptsciclk.app.js","url":"app.js"}, - {"name":"aptsciclk.img","url":"app-icon.js","evaluate":true} - ] -} + +{%- include_relative {{ apps.first }} -%} + +{%- for app in apps offset:1 -%} +,{%- include_relative {{ app }} -%} +{%- endfor -%} + ] From c3aeb22d49772625fc80b368d77d11baa4379f58 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Wed, 23 Feb 2022 20:25:59 -0800 Subject: [PATCH 266/447] reverted to original Reverted to when it was forked --- apps.json | 5100 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 5064 insertions(+), 36 deletions(-) diff --git a/apps.json b/apps.json index 537a4f697..e5e9f8f02 100644 --- a/apps.json +++ b/apps.json @@ -1,38 +1,5066 @@ ---- -# ================================================================= -# ALL THE INFORMATION INSIDE APPS.JSON HAS NOW BEEN MOVED -# -# You'll find it inside a file called apps/yourapp/metadata.json -# -# Otherwise nothing has changed. GitHub Pages will automatically -# create apps.json as your site is hosted, or if you're hosting -# yourself you can run bin/create_apps_json.sh -# -# If you serve the store from localhost for development/testing, -# the loader looks for apps.local.json instead, you can run -# `bin/create_apps_json.sh apps.local.json` to create that file. -# ================================================================= - -# Uncomment the following line if you only want explicitly listed -# apps to be available on your site - -# restricted: ["boot", "launch", "antonclk", "health", "setting", "about", "widbat", "widbt", "widlock", "widid"] ---- -{%- if page.restricted == nil -%} - {%- assign apps = site.static_files | where: "name", "metadata.json" | map: "path" -%} -{%- else -%} - {%- capture temp -%} - {%- for app in page.restricted %} /apps/{{app}}/metadata.json {%- endfor -%} - {%- endcapture -%} - {%- assign apps = temp | strip | split: " " -%} -{%- endif -%} - [ - -{%- include_relative {{ apps.first }} -%} - -{%- for app in apps offset:1 -%} -,{%- include_relative {{ app }} -%} -{%- endfor -%} - + { + "id": "fwupdate", + "name": "Firmware Update", + "version": "0.02", + "description": "[BETA] Uploads new Espruino firmwares to Bangle.js 2. For now, please use the instructions under https://www.espruino.com/Bangle.js2#firmware-updates", + "icon": "app.png", + "type": "RAM", + "tags": "tools,system", + "supports": ["BANGLEJS2"], + "custom": "custom.html", + "customConnect": true, + "storage": [], + "sortorder": 20 + }, + { + "id": "boot", + "name": "Bootloader", + "version": "0.39", + "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", + "icon": "bootloader.png", + "type": "bootloader", + "tags": "tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":".boot0","url":"boot0.js"}, + {"name":".bootcde","url":"bootloader.js"}, + {"name":"bootupdate.js","url":"bootupdate.js"} + ], + "sortorder": -10 + }, + { + "id": "hebrew_calendar", + "name": "Hebrew Calendar", + "shortName": "HebCal", + "version": "0.04", + "description": "lists the date according to the hebrew calendar", + "icon": "app.png", + "allow_emulator": false, + "tags": "tool,locale", + "supports": [ + "BANGLEJS", + "BANGLEJS2" + ], + "readme": "README.md", + "storage": [ + { + "name": "hebrew_calendar.app.js", + "url": "app.js" + }, + { + "name": "hebrewDate", + "url": "hebrewDate.js" + }, + { + "name": "hebrew_calendar.img", + "url": "app-icon.js", + "evaluate": true + } + ] + }, + { "id": "golfscore", + "name": "Golf Score", + "shortName":"golfscore", + "version":"0.02", + "description": "keeps track of strokes during a golf game", + "icon": "app.png", + "tags": "outdoors", + "allow_emulator": true, + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"golfscore.app.js","url":"app.js"}, + {"name":"golfscore.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "messages", + "name": "Messages", + "version": "0.14", + "description": "App to display notifications from iOS and Gadgetbridge", + "icon": "app.png", + "type": "app", + "tags": "tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"messages.app.js","url":"app.js"}, + {"name":"messages.settings.js","url":"settings.js"}, + {"name":"messages.img","url":"app-icon.js","evaluate":true}, + {"name":"messages.wid.js","url":"widget.js"}, + {"name":"messages","url":"lib.js"} + ], + "data": [{"name":"messages.json"},{"name":"messages.settings.json"}], + "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-notify.gif"}], + "sortorder": -9 + }, + { + "id": "android", + "name": "Android Integration", + "shortName": "Android", + "version": "0.05", + "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", + "icon": "app.png", + "tags": "tool,system,messages,notifications", + "dependencies": {"messages":"app"}, + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"android.app.js","url":"app.js"}, + {"name":"android.settings.js","url":"settings.js"}, + {"name":"android.img","url":"app-icon.js","evaluate":true}, + {"name":"android.boot.js","url":"boot.js"} + ], + "sortorder": -8 + }, + { + "id": "ios", + "name": "iOS Integration", + "version": "0.07", + "description": "Display notifications/music/etc from iOS devices", + "icon": "app.png", + "tags": "tool,system,ios,apple,messages,notifications", + "dependencies": {"messages":"app"}, + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"ios.app.js","url":"app.js"}, + {"name":"ios.img","url":"app-icon.js","evaluate":true}, + {"name":"ios.boot.js","url":"boot.js"} + ], + "sortorder": -8 + }, + { + "id": "health", + "name": "Health Tracking", + "version": "0.09", + "description": "Logs health data and provides an app to view it (requires firmware 2v10.100 or later)", + "icon": "app.png", + "tags": "tool,system,health", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"health.app.js","url":"app.js"}, + {"name":"health.img","url":"app-icon.js","evaluate":true}, + {"name":"health.boot.js","url":"boot.js"}, + {"name":"health","url":"lib.js"} + ] + }, + { + "id": "launch", + "name": "Launcher", + "shortName": "Launcher", + "version": "0.10", + "description": "This is needed to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", + "icon": "app.png", + "type": "launch", + "tags": "tool,system,launcher", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"launch.app.js","url":"app-bangle1.js","supports":["BANGLEJS"]}, + {"name":"launch.app.js","url":"app-bangle2.js","supports":["BANGLEJS2"]}, + {"name":"launch.settings.js","url":"settings.js","supports":["BANGLEJS2"]} + ], + "data": [{"name":"launch.json"}], + "sortorder": -10 + }, + { + "id": "setting", + "name": "Settings", + "version": "0.38", + "description": "A menu for setting up Bangle.js", + "icon": "settings.png", + "tags": "tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"setting.app.js","url":"settings.js"}, + {"name":"setting.img","url":"settings-icon.js","evaluate":true} + ], + "data": [{"name":"setting.json","url":"settings.min.json","evaluate":true}], + "sortorder": -5 + }, + { + "id": "about", + "name": "About", + "version": "0.12", + "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", + "icon": "app.png", + "tags": "tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"bangle1-about-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"about.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, + {"name":"about.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, + {"name":"about.img","url":"app-icon.js","evaluate":true} + ], + "sortorder": -4 + }, + { + "id": "alarm", + "name": "Default Alarm & Timer", + "shortName": "Alarms", + "version": "0.14", + "description": "Set and respond to alarms and timers", + "icon": "app.png", + "tags": "tool,alarm,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"alarm.app.js","url":"app.js"}, + {"name":"alarm.boot.js","url":"boot.js"}, + {"name":"alarm.js","url":"alarm.js"}, + {"name":"alarm.img","url":"app-icon.js","evaluate":true}, + {"name":"alarm.wid.js","url":"widget.js"} + ], + "data": [{"name":"alarm.json"}] + }, + { + "id": "locale", + "name": "Languages", + "version": "0.14", + "description": "Translations for different countries", + "icon": "locale.png", + "type": "locale", + "tags": "tool,system,locale,translate", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "custom": "locale.html", + "storage": [ + {"name":"locale"} + ], + "sortorder": -10 + }, + { + "id": "notify", + "name": "Notifications (default)", + "shortName": "Notifications", + "version": "0.11", + "description": "Provides the default `notify` module used by applications to display notifications in a bar at the top of the screen. This module is installed by default by client applications such as the Gadgetbridge app. Installing `Fullscreen Notifications` replaces this module with a version that displays the notifications using the full screen", + "icon": "notify.png", + "type": "notify", + "tags": "widget", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"notify","url":"notify.js"} + ] + }, + { + "id": "notifyfs", + "name": "Fullscreen Notifications", + "shortName": "Notifications", + "version": "0.12", + "description": "Provides a replacement for the `Notifications (default)` `notify` module. This version is used by applications to display notifications fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notify module.", + "icon": "notify.png", + "type": "notify", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"notify","url":"notify.js"} + ] + }, + { + "id": "welcome", + "name": "Welcome", + "shortName": "Welcome", + "version": "0.14", + "description": "Appears at first boot and explains how to use Bangle.js", + "icon": "app.png", + "screenshots": [{"url":"screenshot_welcome.png"}], + "tags": "start,welcome", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"welcome.boot.js","url":"boot.js"}, + {"name":"welcome.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, + {"name":"welcome.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, + {"name":"welcome.settings.js","url":"settings.js"}, + {"name":"welcome.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"welcome.json"}] + }, + { + "id": "mywelcome", + "name": "Customised Welcome", + "shortName": "My Welcome", + "version": "0.13", + "description": "Appears at first boot and explains how to use Bangle.js. Like 'Welcome', but can be customised with a greeting", + "icon": "app.png", + "tags": "start,welcome", + "supports": ["BANGLEJS","BANGLEJS2"], + "custom": "custom.html", + "screenshots": [{"url":"bangle1-customized-welcome-screenshot.png"}], + "storage": [ + {"name":"mywelcome.boot.js","url":"boot.js"}, + {"name":"mywelcome.app.js","url":"app-bangle1.js","supports": ["BANGLEJS"]}, + {"name":"mywelcome.app.js","url":"app-bangle2.js","supports": ["BANGLEJS2"]}, + {"name":"mywelcome.settings.js","url":"settings.js"}, + {"name":"mywelcome.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"mywelcome.json"}] + }, + { + "id": "gbridge", + "name": "Gadgetbridge", + "version": "0.25", + "description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android' Bangle.js app instead.", + "icon": "app.png", + "type": "widget", + "tags": "tool,system,android,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "dependencies": {"notify":"type"}, + "readme": "README.md", + "storage": [ + {"name":"gbridge.settings.js","url":"settings.js"}, + {"name":"gbridge.img","url":"app-icon.js","evaluate":true}, + {"name":"gbridge.wid.js","url":"widget.js"} + ], + "data": [{"name":"gbridge.json"}] + }, + { "id": "gbdebug", + "name": "Gadgetbridge Debug", + "shortName":"GB Debug", + "version":"0.01", + "description": "Debug info for Gadgetbridge. Run this app and when Gadgetbridge messages arrive they are displayed on-screen.", + "icon": "app.png", + "tags": "", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"gbdebug.app.js","url":"app.js"}, + {"name":"gbdebug.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "mclock", + "name": "Morphing Clock", + "version": "0.07", + "description": "7 segment clock that morphs between minutes and hours", + "icon": "clock-morphing.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-morphing-clock-screenshot.png"}], + "storage": [ + {"name":"mclock.app.js","url":"clock-morphing.js"}, + {"name":"mclock.img","url":"clock-morphing-icon.js","evaluate":true} + ], + "sortorder": -9 + }, + { + "id": "moonphase", + "name": "Moonphase", + "version": "0.02", + "description": "Shows current moon phase. Now with GPS function.", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-moon-phase-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"moonphase.app.js","url":"app.js"}, + {"name":"moonphase.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "daysl", + "name": "Days left", + "version": "0.03", + "description": "Shows you the days left until a certain date. Date can be set with a settings app and is written to a file.", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "allow_emulator": false, + "storage": [ + {"name":"daysl.app.js","url":"app.js"}, + {"name":"daysl.img","url":"app-icon.js","evaluate":true}, + {"name":"daysl.wid.js","url":"widget.js"} + ] + }, + { + "id": "wclock", + "name": "Word Clock", + "version": "0.03", + "description": "Display Time as Text", + "icon": "clock-word.png", + "screenshots": [{"url":"screenshot_word.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"wclock.app.js","url":"clock-word.js"}, + {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} + ] + }, + { + "id": "fontclock", + "name": "Font Clock", + "version": "0.01", + "description": "Choose the font and design of clock face from a library of available designs", + "icon": "fontclock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "custom": "custom.html", + "allow_emulator": false, + "storage": [ + {"name":"fontclock.app.js","url":"fontclock.js"}, + {"name":"fontclock.img","url":"fontclock-icon.js","evaluate":true}, + {"name":"fontclock.hand.js","url":"fontclock.hand.js"}, + {"name":"fontclock.thinhand.js","url":"fontclock.thinhand.js"}, + {"name":"fontclock.thickhand.js","url":"fontclock.thickhand.js"}, + {"name":"fontclock.hourscriber.js","url":"fontclock.hourscriber.js"}, + {"name":"fontclock.font.js","url":"fontclock.font.js"}, + {"name":"fontclock.font.abril_ff50.js","url":"fontclock.font.abril_ff50.js"}, + {"name":"fontclock.font.cpstc58.js","url":"fontclock.font.cpstc58.js"}, + {"name":"fontclock.font.mntn25.js","url":"fontclock.font.mntn25.js"}, + {"name":"fontclock.font.mntn50.js","url":"fontclock.font.mntn50.js"}, + {"name":"fontclock.font.vector25.js","url":"fontclock.font.vector25.js"}, + {"name":"fontclock.font.vector50.js","url":"fontclock.font.vector50.js"} + ] + }, + { + "id": "slidingtext", + "name": "Sliding Clock", + "version": "0.07", + "description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported", + "icon": "slidingtext.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "custom": "custom.html", + "allow_emulator": false, + "storage": [ + {"name":"slidingtext.app.js","url":"slidingtext.js"}, + {"name":"slidingtext.img","url":"slidingtext-icon.js","evaluate":true}, + {"name":"slidingtext.locale.en.js","url":"slidingtext.locale.en.js"}, + {"name":"slidingtext.locale.en2.js","url":"slidingtext.locale.en2.js"}, + {"name":"slidingtext.utils.en.js","url":"slidingtext.utils.en.js"}, + {"name":"slidingtext.locale.es.js","url":"slidingtext.locale.es.js"}, + {"name":"slidingtext.locale.fr.js","url":"slidingtext.locale.fr.js"}, + {"name":"slidingtext.locale.jp.js","url":"slidingtext.locale.jp.js"}, + {"name":"slidingtext.locale.de.js","url":"slidingtext.locale.de.js"}, + {"name":"slidingtext.dtfmt.js","url":"slidingtext.dtfmt.js"} + ] + }, + { + "id": "solarclock", + "name": "Solar Clock", + "version": "0.02", + "description": "Using your current or chosen location the solar watch face shows the Sun's sky position, time and date. Also allows you to wind backwards and forwards in time to see the sun's position", + "icon": "solar_clock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "custom": "custom.html", + "allow_emulator": false, + "storage": [ + {"name":"solarclock.app.js","url":"solar_clock.js"}, + {"name":"solarclock.img","url":"solar_clock-icon.js","evaluate":true}, + {"name":"solar_colors.js","url":"solar_colors.js"}, + {"name":"solar_controller.js","url":"solar_controller.js"}, + {"name":"solar_date_utils.js","url":"solar_date_utils.js"}, + {"name":"solar_graphic_utils.js","url":"solar_graphic_utils.js"}, + {"name":"solar_location.js","url":"solar_location.js"}, + {"name":"solar_math_utils.js","url":"solar_math_utils.js"}, + {"name":"solar_loc.Reykjavik.json","url":"solar_loc.Reykjavik.json"}, + {"name":"solar_loc.Hong_Kong.json","url":"solar_loc.Hong_Kong.json"}, + {"name":"solar_loc.Honolulu.json","url":"solar_loc.Honolulu.json"}, + {"name":"solar_loc.Rio.json","url":"solar_loc.Rio.json"}, + {"name":"solar_loc.Tokyo.json","url":"solar_loc.Tokyo.json"}, + {"name":"solar_loc.Seoul.json","url":"solar_loc.Seoul.json"} + ] + }, + { + "id": "sweepclock", + "name": "Sweep Clock", + "version": "0.04", + "description": "Smooth sweep secondhand with single hour numeral. Use button 1 to toggle the numeral font, button 3 to change the colour theme and button 4 to change the date placement", + "icon": "sweepclock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-sweep-clock-screenshot.png"}], + "storage": [ + {"name":"sweepclock.app.js","url":"sweepclock.js"}, + {"name":"sweepclock.img","url":"sweepclock-icon.js","evaluate":true} + ] + }, + { + "id": "matrixclock", + "name": "Matrix Clock", + "version": "0.02", + "description": "inspired by The Matrix, a clock of the same style", + "icon": "matrixclock.png", + "screenshots": [{"url":"screenshot_matrix.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"matrixclock.app.js","url":"matrixclock.js"}, + {"name":"matrixclock.img","url":"matrixclock-icon.js","evaluate":true} + ] + }, + { + "id": "mandelbrotclock", + "name": "Mandelbrot Clock", + "version": "0.01", + "description": "A mandelbrot set themed clock cool", + "icon": "mandelbrotclock.png", + "screenshots": [{ "url": "screenshot_mandelbrotclock.png" }], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + { "name": "mandelbrotclock.app.js", "url": "mandelbrotclock.js" }, + { + "name": "mandelbrotclock.img", + "url": "mandelbrotclock-icon.js", + "evaluate": true + } + ] + }, + { + "id": "imgclock", + "name": "Image background clock", + "shortName": "Image Clock", + "version": "0.08", + "description": "A clock with an image as a background", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "custom": "custom.html", + "storage": [ + {"name":"imgclock.app.js","url":"app.js"}, + {"name":"imgclock.img","url":"app-icon.js","evaluate":true}, + {"name":"imgclock.face.img"}, + {"name":"imgclock.face.json"}, + {"name":"imgclock.face.bg","content":""} + ] + }, + { + "id": "impwclock", + "name": "Imprecise Word Clock", + "version": "0.04", + "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", + "icon": "clock-impword.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"bangle1-impercise-word-clock-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"impwclock.app.js","url":"clock-impword.js"}, + {"name":"impwclock.img","url":"clock-impword-icon.js","evaluate":true} + ] + }, + { + "id": "aclock", + "name": "Analog Clock", + "version": "0.15", + "description": "An Analog Clock", + "icon": "clock-analog.png", + "screenshots": [{"url":"screenshot_analog.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"aclock.app.js","url":"clock-analog.js"}, + {"name":"aclock.img","url":"clock-analog-icon.js","evaluate":true} + ] + }, + { + "id": "clock2x3", + "name": "2x3 Pixel Clock", + "version": "0.05", + "description": "This is a simple clock using minimalist 2x3 pixel numerical digits", + "icon": "clock2x3.png", + "screenshots": [{"url":"screenshot_pixel.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"clock2x3.app.js","url":"clock2x3-app.js"}, + {"name":"clock2x3.img","url":"clock2x3-icon.js","evaluate":true} + ] + }, + { + "id": "geissclk", + "name": "Geiss Clock", + "version": "0.03", + "description": "7 segment clock with animated background in the style of Ryan Geiss' music visualisation. NOTE: The first run will take ~1 minute to do some precalculation", + "icon": "clock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"geissclk.app.js","url":"clock.js"}, + {"name":"geissclk.precompute.js","url":"precompute.js"}, + {"name":"geissclk.img","url":"clock-icon.js","evaluate":true} + ], + "data": [{"name":"geissclk.0.map"},{"name":"geissclk.1.map"},{"name":"geissclk.2.map"},{"name":"geissclk.3.map"},{"name":"geissclk.4.map"},{"name":"geissclk.5.map"},{"name":"geissclk.0.pal"},{"name":"geissclk.1.pal"},{"name":"geissclk.2.pal"}] + }, + { + "id": "trex", + "name": "T-Rex", + "version": "0.04", + "description": "T-Rex game in the style of Chrome's offline game", + "icon": "trex.png", + "screenshots": [{"url":"screenshot_trex.png"}], + "tags": "game", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"trex.app.js","url":"trex.js"}, + {"name":"trex.img","url":"trex-icon.js","evaluate":true}, + {"name":"trex.settings.js","url":"settings.js"} + ], + "data": [{"name":"trex.score","storageFile":true}] + }, + { + "id": "cubescramble", + "name": "Cube Scramble", + "version":"0.04", + "description": "A random scramble generator for the 3x3 Rubik's cube with a basic timer", + "icon": "cube-scramble.png", + "tags": "", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle2-cube-scramble-screenshot.png"},{"url":"bangle1-cube-scramble-screenshot.png"}], + "storage": [ + {"name":"cubescramble.app.js","url":"cube-scramble.js"}, + {"name":"cubescramble.img","url":"cube-scramble-icon.js","evaluate":true} + ] + }, + { + "id": "astroid", + "name": "Asteroids!", + "version": "0.03", + "description": "Retro asteroids game", + "icon": "asteroids.png", + "screenshots": [{"url":"screenshot_asteroids.png"}], + "tags": "game", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"astroid.app.js","url":"asteroids.js"}, + {"name":"astroid.img","url":"asteroids-icon.js","evaluate":true} + ] + }, + { + "id": "clickms", + "name": "Click Master", + "version": "0.01", + "description": "Get several friends to start the game, then compete to see who can press BTN1 the most!", + "icon": "click-master.png", + "tags": "game", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"clickms.app.js","url":"click-master.js"}, + {"name":"clickms.img","url":"click-master-icon.js","evaluate":true} + ] + }, + { + "id": "horsey", + "name": "Horse Race!", + "version": "0.01", + "description": "Get several friends to start the game, then compete to see who can press BTN1 the most!", + "icon": "horse-race.png", + "tags": "game", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"horsey.app.js","url":"horse-race.js"}, + {"name":"horsey.img","url":"horse-race-icon.js","evaluate":true} + ] + }, + { + "id": "compass", + "name": "Compass", + "version": "0.05", + "description": "Simple compass that points North", + "icon": "compass.png", + "screenshots": [{"url":"screenshot_compass.png"}], + "tags": "tool,outdoors", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"compass.app.js","url":"compass.js"}, + {"name":"compass.img","url":"compass-icon.js","evaluate":true} + ] + }, + { + "id": "gpstime", + "name": "GPS Time", + "version": "0.05", + "description": "Update the Bangle.js's clock based on the time from the GPS receiver", + "icon": "gpstime.png", + "tags": "tool,gps", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"gpstime.app.js","url":"gpstime.js"}, + {"name":"gpstime.img","url":"gpstime-icon.js","evaluate":true} + ] + }, + { + "id": "openloc", + "name": "Open Location / Plus Codes", + "shortName": "Open Location", + "version": "0.01", + "description": "Convert your current GPS location to a series of characters", + "icon": "app.png", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"openloc.app.js","url":"app.js"}, + {"name":"openloc.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "speedo", + "name": "Speedo", + "version": "0.05", + "description": "Show the current speed according to the GPS", + "icon": "speedo.png", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"speedo.app.js","url":"speedo.js"}, + {"name":"speedo.img","url":"speedo-icon.js","evaluate":true} + ] + }, + { + "id": "gpsrec", + "name": "GPS Recorder", + "version": "0.27", + "description": "Application that allows you to record a GPS track. Can run in background", + "icon": "app.png", + "tags": "tool,outdoors,gps,widget", + "screenshots": [{"url":"screenshot.png"}], + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"gpsrec.app.js","url":"app.js"}, + {"name":"gpsrec.img","url":"app-icon.js","evaluate":true}, + {"name":"gpsrec.wid.js","url":"widget.js"}, + {"name":"gpsrec.settings.js","url":"settings.js"} + ], + "data": [{"name":"gpsrec.json"},{"wildcard":".gpsrc?","storageFile":true}] + }, + { + "id": "recorder", + "name": "Recorder (BETA)", + "shortName": "Recorder", + "version": "0.04", + "description": "Record GPS position, heart rate and more in the background, then download to your PC.", + "icon": "app.png", + "tags": "tool,outdoors,gps,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"recorder.app.js","url":"app.js"}, + {"name":"recorder.img","url":"app-icon.js","evaluate":true}, + {"name":"recorder.wid.js","url":"widget.js"}, + {"name":"recorder.settings.js","url":"settings.js"} + ], + "data": [{"name":"recorder.json"},{"wildcard":"recorder.log?.csv","storageFile":true}] + }, + { + "id": "gpsnav", + "name": "GPS Navigation", + "version": "0.05", + "description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording, now with waypoint editor", + "icon": "icon.png", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "waypoints.html", + "storage": [ + {"name":"gpsnav.app.js","url":"app.min.js"}, + {"name":"gpsnav.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"waypoints.json","url":"waypoints.json"}] + }, + { + "id": "heart", + "name": "Heart Rate Recorder", + "shortName": "HRM Record", + "version": "0.07", + "description": "Application that allows you to record your heart rate. Can run in background", + "icon": "app.png", + "tags": "tool,health,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "interface": "interface.html", + "storage": [ + {"name":"heart.app.js","url":"app.js"}, + {"name":"heart.img","url":"app-icon.js","evaluate":true}, + {"name":"heart.wid.js","url":"widget.js"} + ], + "data": [{"name":"heart.json"},{"wildcard":".heart?","storageFile":true}] + }, + { + "id": "slevel", + "name": "Spirit Level", + "version": "0.02", + "description": "Show the current angle of the watch, so you can use it to make sure something is absolutely flat", + "icon": "spiritlevel.png", + "tags": "tool", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"slevel.app.js","url":"spiritlevel.js"}, + {"name":"slevel.img","url":"spiritlevel-icon.js","evaluate":true} + ] + }, + { + "id": "files", + "name": "App Manager", + "version": "0.07", + "description": "Show currently installed apps, free space, and allow their deletion from the watch", + "icon": "files.png", + "tags": "tool,system,files", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"files.app.js","url":"files.js"}, + {"name":"files.img","url":"files-icon.js","evaluate":true} + ] + }, + { + "id": "weather", + "name": "Weather", + "version": "0.13", + "description": "Show Gadgetbridge weather report", + "icon": "icon.png", + "screenshots": [{"url":"screenshot.png"}], + "tags": "widget,outdoors", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "readme.md", + "storage": [ + {"name":"weather.app.js","url":"app.js"}, + {"name":"weather.wid.js","url":"widget.js"}, + {"name":"weather","url":"lib.js"}, + {"name":"weather.img","url":"icon.js","evaluate":true}, + {"name":"weather.settings.js","url":"settings.js"} + ], + "data": [{"name":"weather.json"}] + }, + { + "id": "chargeanim", + "name": "Charge Animation", + "version": "0.02", + "description": "When charging, show a sideways charging animation and keep the screen on. When removed from the charger load the clock again.", + "icon": "icon.png", + "tags": "battery", + "supports": ["BANGLEJS", "BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle2-charge-animation-screenshot.png"},{"url":"bangle-charge-animation-screenshot.png"}], + "storage": [ + {"name":"chargeanim.app.js","url":"app.js"}, + {"name":"chargeanim.boot.js","url":"boot.js"}, + {"name":"chargeanim.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "bluetoothdock", + "name": "Bluetooth Dock", + "shortName": "Dock", + "version": "0.01", + "description": "When charging shows the time, scans Bluetooth for known devices (eg temperature) and shows them on the screen", + "icon": "app.png", + "tags": "bluetooth", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"bluetoothdock.app.js","url":"app.js"}, + {"name":"bluetoothdock.boot.js","url":"boot.js"}, + {"name":"bluetoothdock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widbat", + "name": "Battery Level Widget", + "version": "0.09", + "description": "Show the current battery level and charging status in the top right of the clock", + "icon": "widget.png", + "type": "widget", + "tags": "widget,battery", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widbat.wid.js","url":"widget.js"} + ] + }, + { + "id": "widbatv", + "name": "Battery Level Widget (Vertical)", + "version": "0.01", + "description": "Slim, vertical battery widget that only takes up 14px", + "icon": "widget.png", + "type": "widget", + "tags": "widget,battery", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widbatv.wid.js","url":"widget.js"} + ] + }, + { + "id": "widlock", + "name": "Lock Widget", + "version": "0.03", + "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", + "icon": "widget.png", + "type": "widget", + "tags": "widget,lock", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widlock.wid.js","url":"widget.js"} + ] + }, + { + "id": "widbatpc", + "name": "Battery Level Widget (with percentage)", + "shortName": "Battery Widget", + "version": "0.14", + "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", + "icon": "widget.png", + "type": "widget", + "tags": "widget,battery", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widbatpc.wid.js","url":"widget.js"}, + {"name":"widbatpc.settings.js","url":"settings.js"} + ], + "data": [{"name":"widbatpc.json"}] + }, + { + "id": "widbatwarn", + "name": "Battery Warning", + "shortName": "Battery Warning", + "version": "0.02", + "description": "Show a warning when the battery runs low.", + "icon": "widget.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "widget", + "tags": "tool,battery", + "supports": ["BANGLEJS"], + "dependencies": {"notify":"type"}, + "readme": "README.md", + "storage": [ + {"name":"widbatwarn.wid.js","url":"widget.js"}, + {"name":"widbatwarn.settings.js","url":"settings.js"} + ], + "data": [{"name":"widbatwarn.json"}] + }, + { + "id": "widbt", + "name": "Bluetooth Widget", + "version": "0.07", + "description": "Show the current Bluetooth connection status in the top right of the clock", + "icon": "widget.png", + "type": "widget", + "tags": "widget,bluetooth", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widbt.wid.js","url":"widget.js"} + ] + }, + { + "id": "widchime", + "name": "Hour Chime", + "version": "0.02", + "description": "Buzz or beep on every whole hour.", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widchime.wid.js","url":"widget.js"}, + {"name":"widchime.settings.js","url":"settings.js"} + ], + "data": [{"name":"widchime.json"}] + }, + { + "id": "widram", + "name": "RAM Widget", + "shortName": "RAM Widget", + "version": "0.01", + "description": "Display your Bangle's available RAM percentage in a widget", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widram.wid.js","url":"widget.js"} + ] + }, + { + "id": "hrm", + "name": "Heart Rate Monitor", + "version": "0.06", + "description": "Measure your heart rate and see live sensor data", + "icon": "heartrate.png", + "tags": "health", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"hrm.app.js","url":"heartrate.js"}, + {"name":"hrm.img","url":"heartrate-icon.js","evaluate":true} + ] + }, + { + "id": "widhrm", + "name": "Simple Heart Rate widget", + "version": "0.05", + "description": "When the screen is on, the widget turns on the heart rate monitor and displays the current heart rate (or last known in grey). For this to work well you'll need at least a 15 second LCD Timeout.", + "icon": "widget.png", + "type": "widget", + "tags": "health,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widhrm.wid.js","url":"widget.js"} + ] + }, + { + "id": "bthrm", + "name": "Bluetooth Heart Rate Monitor", + "shortName": "BT HRM", + "version": "0.01", + "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", + "icon": "app.png", + "type": "boot", + "tags": "health,bluetooth", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"bthrm.boot.js","url":"boot.js"}, + {"name":"bthrm.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "stetho", + "name": "Stethoscope", + "version": "0.01", + "description": "Hear your heart rate", + "icon": "stetho.png", + "tags": "health", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"stetho.app.js","url":"stetho.js"}, + {"name":"stetho.img","url":"stetho-icon.js","evaluate":true} + ] + }, + { + "id": "swatch", + "name": "Stopwatch", + "version": "0.07", + "description": "Simple stopwatch with Lap Time logging to a JSON file", + "icon": "stopwatch.png", + "tags": "health", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "interface.html", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-stopwatch-screenshot.png"}], + "storage": [ + {"name":"swatch.app.js","url":"stopwatch.js"}, + {"name":"swatch.img","url":"stopwatch-icon.js","evaluate":true} + ] + }, + { + "id": "hidmsic", + "name": "Bluetooth Music Controls", + "shortName": "Music Control", + "version": "0.02", + "description": "Enable HID in settings, pair with your phone, then use this app to control music from your watch!", + "icon": "hid-music.png", + "tags": "bluetooth", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"hidmsic.app.js","url":"hid-music.js"}, + {"name":"hidmsic.img","url":"hid-music-icon.js","evaluate":true} + ] + }, + { + "id": "hidkbd", + "name": "Bluetooth Keyboard", + "shortName": "Bluetooth Kbd", + "version": "0.02", + "description": "Enable HID in settings, pair with your phone/PC, then use this app to control other apps", + "icon": "hid-keyboard.png", + "tags": "bluetooth", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"hidkbd.app.js","url":"hid-keyboard.js"}, + {"name":"hidkbd.img","url":"hid-keyboard-icon.js","evaluate":true} + ] + }, + { + "id": "hidbkbd", + "name": "Binary Bluetooth Keyboard", + "shortName": "Binary BT Kbd", + "version": "0.02", + "description": "Enable HID in settings, pair with your phone/PC, then type messages using the onscreen keyboard by tapping repeatedly on the key you want", + "icon": "hid-binary-keyboard.png", + "tags": "bluetooth", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"hidbkbd.app.js","url":"hid-binary-keyboard.js"}, + {"name":"hidbkbd.img","url":"hid-binary-keyboard-icon.js","evaluate":true} + ] + }, + { + "id": "animals", + "name": "Animals Game", + "version": "0.01", + "description": "Simple toddler's game - displays a different number of animals each time the screen is pressed", + "icon": "animals.png", + "tags": "game", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"animals.app.js","url":"animals.js"}, + {"name":"animals.img","url":"animals-icon.js","evaluate":true}, + {"name":"animals-snake.img","url":"animals-snake.js","evaluate":true}, + {"name":"animals-duck.img","url":"animals-duck.js","evaluate":true}, + {"name":"animals-swan.img","url":"animals-swan.js","evaluate":true}, + {"name":"animals-fox.img","url":"animals-fox.js","evaluate":true}, + {"name":"animals-camel.img","url":"animals-camel.js","evaluate":true}, + {"name":"animals-pig.img","url":"animals-pig.js","evaluate":true}, + {"name":"animals-sheep.img","url":"animals-sheep.js","evaluate":true}, + {"name":"animals-mouse.img","url":"animals-mouse.js","evaluate":true} + ] + }, + { + "id": "qrcode", + "name": "Custom QR Code", + "version": "0.04", + "description": "Use this to upload a customised QR code to Bangle.js", + "icon": "app.png", + "tags": "qrcode", + "supports": ["BANGLEJS","BANGLEJS2"], + "custom": "custom.html", + "customConnect": true, + "storage": [ + {"name":"qrcode.app.js"}, + {"name":"qrcode.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "beer", + "name": "Beer Compass", + "version": "0.01", + "description": "Uploads all the pubs in an area onto your watch, so it can always point you at the nearest one", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "custom": "custom.html", + "storage": [ + {"name":"beer.app.js"}, + {"name":"beer.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "route", + "name": "Route Viewer", + "version": "0.02", + "description": "Upload a KML file of a route, and have your watch display a map with how far around it you are", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "custom": "custom.html", + "storage": [ + {"name":"route.app.js"}, + {"name":"route.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "ncstart", + "name": "NCEU Startup", + "version": "0.06", + "description": "NodeConfEU 2019 'First Start' Sequence", + "icon": "start.png", + "tags": "start,welcome", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"ncstart.app.js","url":"start.js"}, + {"name":"ncstart.boot.js","url":"boot.js"}, + {"name":"ncstart.settings.js","url":"settings.js"}, + {"name":"ncstart.img","url":"start-icon.js","evaluate":true}, + {"name":"nc-bangle.img","url":"start-bangle.js","evaluate":true}, + {"name":"nc-nceu.img","url":"start-nceu.js","evaluate":true}, + {"name":"nc-nfr.img","url":"start-nfr.js","evaluate":true}, + {"name":"nc-nodew.img","url":"start-nodew.js","evaluate":true}, + {"name":"nc-tf.img","url":"start-tf.js","evaluate":true} + ], + "data": [{"name":"ncstart.json"}] + }, + { + "id": "ncfrun", + "name": "NCEU 5K Fun Run", + "version": "0.01", + "description": "Display a map of the NodeConf EU 2019 5K Fun Run route and your location on it", + "icon": "nceu-funrun.png", + "tags": "health", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"ncfrun.app.js","url":"nceu-funrun.js"}, + {"name":"ncfrun.img","url":"nceu-funrun-icon.js","evaluate":true} + ] + }, + { + "id": "widnceu", + "name": "NCEU Logo Widget", + "version": "0.02", + "description": "Show the NodeConf EU logo in the top left", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"widnceu.wid.js","url":"widget.js"} + ] + }, + { + "id": "sclock", + "name": "Simple Clock", + "version": "0.07", + "description": "A Simple Digital Clock", + "icon": "clock-simple.png", + "screenshots": [{"url":"screenshot_simplec.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"sclock.app.js","url":"clock-simple.js"}, + {"name":"sclock.img","url":"clock-simple-icon.js","evaluate":true} + ] + }, + { + "id": "s7clk", + "name": "Simple 7 segment Clock", + "version": "0.03", + "description": "A simple 7 segment Clock with date", + "icon": "icon.png", + "screenshots": [{"url":"screenshot_s7segment.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"s7clk.app.js","url":"app.js"}, + {"name":"s7clk.img","url":"icon.js","evaluate":true} + ] + }, + { + "id": "vibrclock", + "name": "Vibrate Clock", + "version": "0.03", + "description": "When BTN1 is pressed, vibrate out the time as a series of buzzes, one digit at a time. Hours, then Minutes. Zero is signified by one long buzz. Otherwise a simple digital clock.", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-vibrate-clock-screenshot.png"}], + "storage": [ + {"name":"vibrclock.app.js","url":"app.js"}, + {"name":"vibrclock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "svclock", + "name": "Simple V-Clock", + "version": "0.04", + "description": "Modification of Simple Clock 0.04 to use Vectorfont", + "icon": "vclock-simple.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle2-simple-v-clock-screenshot.png"}], + "storage": [ + {"name":"svclock.app.js","url":"vclock-simple.js"}, + {"name":"svclock.img","url":"vclock-simple-icon.js","evaluate":true} + ] + }, + { + "id": "dclock", + "name": "Dev Clock", + "version": "0.10", + "description": "A Digital Clock including timestamp (tst), beats(@), days in current month (dm) and days since new moon (l)", + "icon": "clock-dev.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle2-dev-clock-screenshot.png"},{"url":"bangle1-dev-clock-screenshot.png"}], + "storage": [ + {"name":"dclock.app.js","url":"clock-dev.js"}, + {"name":"dclock.img","url":"clock-dev-icon.js","evaluate":true} + ] + }, + { + "id": "gesture", + "name": "Gesture Test", + "version": "0.01", + "description": "BETA! Uploads a basic Tensorflow Gesture model, and then outputs each gesture as a message", + "icon": "gesture.png", + "type": "app", + "tags": "gesture,ai", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"gesture.app.js","url":"gesture.js"}, + {"name":".tfnames","url":"gesture-tfnames.js","evaluate":true}, + {"name":".tfmodel","url":"gesture-tfmodel.js","evaluate":true}, + {"name":"gesture.img","url":"gesture-icon.js","evaluate":true} + ] + }, + { + "id": "pparrot", + "name": "Party Parrot", + "version": "0.01", + "description": "Party with a parrot on your wrist", + "icon": "party-parrot.png", + "type": "app", + "tags": "party,parrot,lol", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-party-parrot-screenshot.png"}], + "storage": [ + {"name":"pparrot.app.js","url":"party-parrot.js"}, + {"name":"pparrot.img","url":"party-parrot-icon.js","evaluate":true} + ] + }, + { + "id": "hrings", + "name": "Hypno Rings", + "version": "0.01", + "description": "Experiment with trippy rings, press buttons for change", + "icon": "hypno-rings.png", + "type": "app", + "tags": "rings,hypnosis,psychadelic", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-hypno-rings-screenshot.png"}], + "storage": [ + {"name":"hrings.app.js","url":"hypno-rings.js"}, + {"name":"hrings.img","url":"hypno-rings-icon.js","evaluate":true} + ] + }, + { + "id": "morse", + "name": "Morse Code", + "version": "0.01", + "description": "Learn morse code by hearing/seeing/feeling the code. Tap to toggle buzz!", + "icon": "morse-code.png", + "type": "app", + "tags": "morse,sound,visual,input", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"morse.app.js","url":"morse-code.js"}, + {"name":"morse.img","url":"morse-code-icon.js","evaluate":true} + ] + }, + { + "id": "blescan", + "name": "BLE Scanner", + "version": "0.01", + "description": "Scan for advertising BLE devices", + "icon": "blescan.png", + "tags": "bluetooth", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"blescan.app.js","url":"blescan.js"}, + {"name":"blescan.img","url":"blescan-icon.js","evaluate":true} + ] + }, + { + "id": "mmonday", + "name": "Manic Monday Tone", + "version": "0.02", + "description": "The Bangles make a comeback", + "icon": "manic-monday-icon.png", + "tags": "sound", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"mmonday.app.js","url":"manic-monday.js"}, + {"name":"mmonday.img","url":"manic-monday-icon.js","evaluate":true} + ] + }, + { + "id": "jbells", + "name": "Jingle Bells", + "version": "0.01", + "description": "Play Jingle Bells", + "icon": "jbells.png", + "type": "app", + "tags": "sound", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"jbells.app.js","url":"jbells.js"}, + {"name":"jbells.img","url":"jbells-icon.js","evaluate":true} + ] + }, + { + "id": "scolor", + "name": "Show Color", + "version": "0.01", + "description": "Display all available Colors and Names", + "icon": "show-color.png", + "type": "app", + "tags": "tool", + "screenshots": [{"url":"bangle1-view-color-screenshot.png"}], + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"scolor.app.js","url":"show-color.js"}, + {"name":"scolor.img","url":"show-color-icon.js","evaluate":true} + ] + }, + { + "id": "miclock", + "name": "Mixed Clock", + "version": "0.05", + "description": "A mix of analog and digital Clock", + "icon": "clock-mixed.png", + "type": "clock", + "tags": "clock", + "screenshots": [{"url":"bangle1-mixed-clock-screenshot.png"}], + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"miclock.app.js","url":"clock-mixed.js"}, + {"name":"miclock.img","url":"clock-mixed-icon.js","evaluate":true} + ] + }, + { + "id": "bclock", + "name": "Binary Clock", + "version": "0.03", + "description": "A simple binary clock watch face", + "icon": "clock-binary.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-binary-clock-screenshot.png"}], + "storage": [ + {"name":"bclock.app.js","url":"clock-binary.js"}, + {"name":"bclock.img","url":"clock-binary-icon.js","evaluate":true} + ] + }, + { + "id": "clotris", + "name": "Clock-Tris", + "version": "0.01", + "description": "A fully functional clone of a classic game of falling blocks", + "icon": "clock-tris.png", + "tags": "game", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-clock-tris-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"clotris.app.js","url":"clock-tris.js"}, + {"name":"clotris.img","url":"clock-tris-icon.js","evaluate":true}, + {"name":".trishig","url":"clock-tris-high"} + ] + }, + { + "id": "flappy", + "name": "Flappy Bird", + "version": "0.05", + "description": "A Flappy Bird game clone", + "icon": "app.png", + "screenshots": [{"url":"screenshot1_flappy.png"},{"url":"screenshot2_flappy.png"}], + "tags": "game", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"flappy.app.js","url":"app.js"}, + {"name":"flappy.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "gpsinfo", + "name": "GPS Info", + "version": "0.05", + "description": "An application that displays information about altitude, lat/lon, satellites and time", + "icon": "gps-info.png", + "type": "app", + "tags": "gps", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"gpsinfo.app.js","url":"gps-info.js"}, + {"name":"gpsinfo.img","url":"gps-info-icon.js","evaluate":true} + ] + }, + { + "id": "assistedgps", + "name": "Assisted GPS Update (AGPS)", + "version": "0.01", + "description": "Downloads assisted GPS (AGPS) data to Bangle.js 1 for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", + "icon": "app.png", + "type": "RAM", + "tags": "tool,outdoors,agps", + "supports": ["BANGLEJS"], + "custom": "custom.html", + "storage": [] + }, + { + "id": "pomodo", + "name": "Pomodoro", + "version": "0.02", + "description": "A simple pomodoro timer.", + "icon": "pomodoro.png", + "type": "app", + "tags": "pomodoro,cooking,tools", + "supports": ["BANGLEJS", "BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle2-pomodoro-screenshot.png"}], + "storage": [ + {"name":"pomodo.app.js","url":"pomodoro.js"}, + {"name":"pomodo.img","url":"pomodoro-icon.js","evaluate":true} + ] + }, + { + "id": "blobclk", + "name": "Large Digit Blob Clock", + "shortName": "Blob Clock", + "version": "0.06", + "description": "A clock with big digits", + "icon": "clock-blob.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle2-large-digit-blob-clock-screenshot.png"},{"url":"bangle1-large-digit-blob-clock-screenshot.png"}], + "storage": [ + {"name":"blobclk.app.js","url":"clock-blob.js"}, + {"name":"blobclk.img","url":"clock-blob-icon.js","evaluate":true} + ] + }, + { + "id": "boldclk", + "name": "Bold Clock", + "version": "0.05", + "description": "Simple, readable and practical clock", + "icon": "bold_clock.png", + "screenshots": [{"url":"screenshot_bold.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"boldclk.app.js","url":"bold_clock.js"}, + {"name":"boldclk.img","url":"bold_clock-icon.js","evaluate":true} + ] + }, + { + "id": "widclk", + "name": "Digital clock widget", + "version": "0.06", + "description": "A simple digital clock widget", + "icon": "widget.png", + "type": "widget", + "tags": "widget,clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widclk.wid.js","url":"widget.js"} + ] + }, + { + "id": "widpedom", + "name": "Pedometer widget", + "version": "0.20", + "description": "Daily pedometer widget", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widpedom.wid.js","url":"widget.js"}, + {"name":"widpedom.settings.js","url":"settings.js"} + ] + }, + { + "id": "berlinc", + "name": "Berlin Clock", + "version": "0.05", + "description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)", + "icon": "berlin-clock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"berlin-clock-screenshot.png"}], + "storage": [ + {"name":"berlinc.app.js","url":"berlin-clock.js"}, + {"name":"berlinc.img","url":"berlin-clock-icon.js","evaluate":true} + ] + }, + { + "id": "ctrclk", + "name": "Centerclock", + "version": "0.03", + "description": "Watch-centered digital 24h clock with date in dd.mm.yyyy format.", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-center-clock-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"ctrclk.app.js","url":"app.js"}, + {"name":"ctrclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "demoapp", + "name": "Demo Loop", + "version": "0.02", + "description": "Simple demo app - displays Bangle.js, JS logo, graphics, and Bangle.js information", + "icon": "app.png", + "type": "app", + "tags": "", + "screenshots": [{"url":"bangle1-demo-loop-screenshot1.png"},{"url":"bangle1-demo-loop-screenshot2.png"},{"url":"bangle1-demo-loop-screenshot3.png"},{"url":"bangle1-demo-loop-screenshot4.png"}], + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"demoapp.app.js","url":"app.js"}, + {"name":"demoapp.img","url":"app-icon.js","evaluate":true} + ], + "sortorder": -9 + }, + { + "id": "flagrse", + "name": "Espruino Flag Raiser", + "version": "0.01", + "description": "App to send a command to another Espruino to cause it to raise a flag", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"flagrse.app.js","url":"app.js"}, + {"name":"flagrse.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "pipboy", + "name": "Pipboy", + "version": "0.04", + "description": "Pipboy themed clock", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-pipboy-themed-clock-screenshot.png"}], + "storage": [ + {"name":"pipboy.app.js","url":"app.js"}, + {"name":"pipboy.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "torch", + "name": "Torch", + "shortName": "Torch", + "version": "0.02", + "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets", + "icon": "app.png", + "tags": "tool,torch", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"torch.app.js","url":"app.js"}, + {"name":"torch.wid.js","url":"widget.js"}, + {"name":"torch.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "rtorch", + "name": "Red Torch", + "shortName": "RedTorch", + "version": "0.02", + "description": "Turns screen RED to help you see in the dark without breaking your night vision. Select from the launcher or on Bangle 1 press BTN3,BTN1,BTN3,BTN1 quickly to start when in any app that shows widgets", + "icon": "app.png", + "tags": "tool,torch", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"rtorch.app.js","url":"app.js"}, + {"name":"rtorch.wid.js","url":"widget.js", "supports": ["BANGLEJS"]}, + {"name":"rtorch.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "wohrm", + "name": "Workout HRM", + "version": "0.08", + "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", + "icon": "app.png", + "type": "app", + "tags": "hrm,workout", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-workout-HRM-screenshot.png"}], + "storage": [ + {"name":"wohrm.app.js","url":"app.js"}, + {"name":"wohrm.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widid", + "name": "Bluetooth ID Widget", + "version": "0.03", + "description": "Display the last two tuple of your Bangle.js MAC address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!", + "icon": "widget.png", + "type": "widget", + "tags": "widget,address,mac", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widid.wid.js","url":"widget.js"} + ] + }, + { + "id": "grocery", + "name": "Grocery", + "version": "0.02", + "description": "Simple grocery (shopping) list - Display a list of product and track if you already put them in your cart.", + "icon": "grocery.png", + "type": "app", + "tags": "tool,outdoors,shopping,list", + "supports": ["BANGLEJS"], + "custom": "grocery.html", + "storage": [ + {"name":"grocery.app.js","url":"app.js"}, + {"name":"grocery.img","url":"grocery-icon.js","evaluate":true} + ] + }, + { + "id": "marioclock", + "name": "Mario Clock", + "version": "0.15", + "description": "Animated retro Mario clock, with Gameboy style 8-bit grey-scale graphics.", + "icon": "marioclock.png", + "type": "clock", + "tags": "clock,mario,retro", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": false, + "screenshots": [{"url":"bangle1-mario-clock-screenshot.png"}], + "storage": [ + {"name":"marioclock.app.js","url":"marioclock-app.js"}, + {"name":"marioclock.img","url":"marioclock-icon.js","evaluate":true} + ] + }, + { + "id": "cliock", + "name": "Commandline-Clock", + "shortName": "CLI-Clock", + "version": "0.15", + "description": "Simple CLI-Styled Clock", + "icon": "app.png", + "screenshots": [{"url":"screenshot_cli.png"}], + "type": "clock", + "tags": "clock,cli,command,bash,shell", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"cliock.app.js","url":"app.js"}, + {"name":"cliock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widver", + "name": "Firmware Version Widget", + "version": "0.03", + "description": "Display the version of the installed firmware in the top widget section.", + "icon": "widget.png", + "type": "widget", + "tags": "widget,tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widver.wid.js","url":"widget.js"} + ] + }, + { + "id": "barclock", + "name": "Bar Clock", + "version": "0.09", + "description": "A simple digital clock showing seconds as a bar", + "icon": "clock-bar.png", + "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"barclock.app.js","url":"clock-bar.js"}, + {"name":"barclock.img","url":"clock-bar-icon.js","evaluate":true} + ] + }, + { + "id": "dotclock", + "name": "Dot Clock", + "version": "0.03", + "description": "A Minimal Dot Analog Clock", + "icon": "clock-dot.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle2-dot-clcok-screenshot.png"},{"url":"bangle1-dot-clock-screenshot.png"}], + "storage": [ + {"name":"dotclock.app.js","url":"clock-dot.js"}, + {"name":"dotclock.img","url":"clock-dot-icon.js","evaluate":true} + ] + }, + { + "id": "widtbat", + "name": "Tiny Battery Widget", + "version": "0.02", + "description": "Tiny blueish battery widget, vibs and changes level color when charging", + "icon": "widget.png", + "type": "widget", + "tags": "widget,tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widtbat.wid.js","url":"widget.js"} + ] + }, + { + "id": "chrono", + "name": "Chrono", + "shortName": "Chrono", + "version": "0.01", + "description": "Single click BTN1 to add 5 minutes. Single click BTN2 to add 30 seconds. Single click BTN3 to add 5 seconds. Tap to pause or play to timer. Double click BTN1 to reset. When timer finishes the watch vibrates.", + "icon": "chrono.png", + "tags": "tool", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"chrono.app.js","url":"chrono.js"}, + {"name":"chrono.img","url":"chrono-icon.js","evaluate":true} + ] + }, + { + "id": "astrocalc", + "name": "Astrocalc", + "version": "0.02", + "description": "Calculates interesting information on the sun and moon cycles for the current day based on your location.", + "icon": "astrocalc.png", + "tags": "app,sun,moon,cycles,tool,outdoors", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"astrocalc.app.js","url":"astrocalc-app.js"}, + {"name":"suncalc.js","url":"suncalc.js"}, + {"name":"astrocalc.img","url":"astrocalc-icon.js","evaluate":true}, + {"name":"first-quarter.img","url":"first-quarter-icon.js","evaluate":true}, + {"name":"last-quarter.img","url":"last-quarter-icon.js","evaluate":true}, + {"name":"waning-crescent.img","url":"waning-crescent-icon.js","evaluate":true}, + {"name":"waning-gibbous.img","url":"waning-gibbous-icon.js","evaluate":true}, + {"name":"full.img","url":"full-icon.js","evaluate":true}, + {"name":"new.img","url":"new-icon.js","evaluate":true}, + {"name":"waxing-gibbous.img","url":"waxing-gibbous-icon.js","evaluate":true}, + {"name":"waxing-crescent.img","url":"waxing-crescent-icon.js","evaluate":true} + ] + }, + { + "id": "widhwt", + "name": "Hand Wash Timer", + "version": "0.01", + "description": "Swipe your wrist over the watch face to start your personal Bangle.js hand wash timer for 35 sec. Start washing after the short buzz and stop after the long buzz.", + "icon": "widget.png", + "type": "widget", + "tags": "widget,tool", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"widhwt.wid.js","url":"widget.js"} + ] + }, + { + "id": "toucher", + "name": "Touch Launcher", + "shortName": "Toucher", + "version": "0.07", + "description": "Touch enable left to right launcher.", + "icon": "app.png", + "type": "launch", + "tags": "tool,system,launcher", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"toucher.app.js","url":"app.js"}, + {"name":"toucher.settings.js","url":"settings.js"} + ], + "data": [{"name":"toucher.json"}] + }, + { + "id": "balltastic", + "name": "Balltastic", + "version": "0.02", + "description": "Simple but fun ball eats dots game.", + "icon": "app.png", + "type": "app", + "tags": "game,fun", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"balltastic.app.js","url":"app.js"}, + {"name":"balltastic.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "rpgdice", + "name": "RPG dice", + "version": "0.02", + "description": "Simple RPG dice rolling app.", + "icon": "rpgdice.png", + "type": "app", + "tags": "game,fun", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-rpg-dice-screenshot.png"}], + "storage": [ + {"name":"rpgdice.app.js","url":"app.js"}, + {"name":"rpgdice.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widmp", + "name": "Moon Phase Widget", + "version": "0.02", + "description": "Display the current moon phase in blueish for the northern hemisphere in eight phases", + "icon": "widget.png", + "type": "widget", + "tags": "widget,tools", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widmp.wid.js","url":"widget.js"} + ] + }, + { + "id": "widmpsh", + "name": "Moon Phase Widget Southern Hemisphere", + "version": "0.01", + "description": "Display the current moon phase in blueish for the southern hemisphere in eight phases", + "icon": "widget.png", + "type": "widget", + "tags": "widget,tools", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widmpsh.wid.js","url":"widget.js"} + ] + }, + { + "id": "minionclk", + "name": "Minion clock", + "version": "0.05", + "description": "Minion themed clock.", + "icon": "minionclk.png", + "type": "clock", + "tags": "clock,minion", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-minion-clock-screenshot.png"}], + "storage": [ + {"name":"minionclk.app.js","url":"app.js"}, + {"name":"minionclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "openstmap", + "name": "OpenStreetMap", + "shortName": "OpenStMap", + "version": "0.11", + "description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps", + "icon": "app.png", + "tags": "outdoors,gps,osm", + "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"screenshot.png"}], + "custom": "custom.html", + "customConnect": true, + "storage": [ + {"name":"openstmap","url":"openstmap.js"}, + {"name":"openstmap.app.js","url":"app.js"}, + {"name":"openstmap.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "activepedom", + "name": "Active Pedometer", + "shortName": "Active Pedometer", + "version": "0.09", + "description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.", + "icon": "app.png", + "tags": "outdoors,widget", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"activepedom.wid.js","url":"widget.js"}, + {"name":"activepedom.settings.js","url":"settings.js"}, + {"name":"activepedom.img","url":"app-icon.js","evaluate":true}, + {"name":"activepedom.app.js","url":"app.js"} + ] + }, + { + "id": "chronowid", + "name": "Chrono Widget", + "shortName": "Chrono Widget", + "version": "0.04", + "description": "Chronometer (timer) which runs as widget.", + "icon": "app.png", + "tags": "tool,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"screenshot.png"}], + "readme": "README.md", + "storage": [ + {"name":"chronowid.wid.js","url":"widget.js"}, + {"name":"chronowid.app.js","url":"app.js"}, + {"name":"chronowid.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "tabata", + "name": "Tabata", + "shortName": "Tabata - Control High-Intensity Interval Training", + "version": "0.01", + "description": "Control high-intensity interval training (according to tabata: https://en.wikipedia.org/wiki/Tabata_method).", + "icon": "tabata.png", + "tags": "workout,health", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"tabata.app.js","url":"tabata.js"}, + {"name":"tabata.img","url":"tabata-icon.js","evaluate":true} + ] + }, + { + "id": "custom", + "name": "Custom Boot Code ", + "version": "0.01", + "description": "Add code you want to run at boot time", + "icon": "custom.png", + "type": "bootloader", + "tags": "tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "custom": "custom.html", + "storage": [ + {"name":"custom"} + ] + }, + { + "id": "devstopwatch", + "name": "Dev Stopwatch", + "shortName": "Dev Stopwatch", + "version": "0.03", + "description": "Stopwatch with 5 laps supported (cyclically replaced)", + "icon": "app.png", + "tags": "stopwatch,chrono,timer,chronometer", + "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"bangle1-dev-stopwatch-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"devstopwatch.app.js","url":"app.js"}, + {"name":"devstopwatch.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "batchart", + "name": "Battery Chart", + "shortName": "Battery Chart", + "version": "0.10", + "description": "A widget and an app for recording and visualizing battery percentage over time.", + "icon": "app.png", + "tags": "app,widget,battery,time,record,chart,tool", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"batchart.wid.js","url":"widget.js"}, + {"name":"batchart.app.js","url":"app.js"}, + {"name":"batchart.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "nato", + "name": "NATO Alphabet", + "shortName": "NATOAlphabet", + "version": "0.01", + "description": "Learn the NATO Phonetic alphabet plus some numbers.", + "icon": "nato.png", + "type": "app", + "tags": "app,learn,visual", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-NATO-alphabet-screenshot.png"},{"url":"bangle1-NATO-alphabet-screenshot2.png"}], + "storage": [ + {"name":"nato.app.js","url":"nato.js"}, + {"name":"nato.img","url":"nato-icon.js","evaluate":true} + ] + }, + { + "id": "numerals", + "name": "Numerals Clock", + "shortName": "Numerals Clock", + "version": "0.10", + "description": "A simple big numerals clock", + "icon": "numerals.png", + "type": "clock", + "tags": "numerals,clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-numerals-screenshot.png"}], + "storage": [ + {"name":"numerals.app.js","url":"numerals.app.js"}, + {"name":"numerals.img","url":"numerals-icon.js","evaluate":true}, + {"name":"numerals.settings.js","url":"numerals.settings.js"} + ], + "data": [{"name":"numerals.json"}] + }, + { + "id": "bledetect", + "name": "BLE Detector", + "shortName": "BLE Detector", + "version": "0.03", + "description": "Detect BLE devices and show some informations.", + "icon": "bledetect.png", + "tags": "app,bluetooth,tool", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"bledetect.app.js","url":"bledetect.js"}, + {"name":"bledetect.img","url":"bledetect-icon.js","evaluate":true} + ] + }, + { + "id": "snake", + "name": "Snake", + "shortName": "Snake", + "version": "0.02", + "description": "The classic snake game. Eat apples and don't bite your tail.", + "icon": "snake.png", + "tags": "game,fun", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"snake.app.js","url":"snake.js"}, + {"name":"snake.img","url":"snake-icon.js","evaluate":true} + ] + }, + { "id": "snek", + "name": "The snek game", + "shortName":"Snek", + "version": "0.02", + "description": "A snek game where you control a snek to eat all the apples!", + "screenshots": [{"url":"screenshot_snek.png"}], + "icon": "snek.png", + "supports": ["BANGLEJS2"], + "tags": "game,fun", + "storage": [ + {"name":"snek.app.js","url":"snek.js"}, + {"name":"snek.img","url":"snek.icon.js","evaluate":true} + ] + }, + { + "id": "calculator", + "name": "Calculator", + "shortName": "Calculator", + "version": "0.04", + "description": "Basic calculator reminiscent of MacOs's one. Handy for small calculus.", + "icon": "calculator.png", + "screenshots": [{"url":"screenshot_calculator.png"}], + "tags": "app,tool", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"calculator.app.js","url":"app.js"}, + {"name":"calculator.img","url":"calculator-icon.js","evaluate":true} + ] + }, + { + "id": "dane", + "name": "Digital Assistant, not EDITH", + "shortName": "DANE", + "version": "0.16", + "description": "A Watchface inspired by Tony Stark's EDITH and based on https://arwes.dev/", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"dane.app.js","url":"app.js"}, + {"name":"dane.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "dane_tcr", + "name": "DANE Touch Launcher", + "shortName": "DANE Toucher", + "version": "0.07", + "description": "Touch enable left to right launcher in the style of the DANE Watchface", + "icon": "app.png", + "type": "launch", + "tags": "tool,system,launcher", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"dane_tcr.app.js","url":"app.js"}, + {"name":"dane_tcr.settings.js","url":"settings.js"} + ], + "data": [{"name":"dane_tcr.json"}] + }, + { + "id": "buffgym", + "name": "BuffGym", + "version": "0.02", + "description": "BuffGym is the famous 5x5 workout program for the BangleJS", + "icon": "buffgym.png", + "type": "app", + "tags": "tool,outdoors,gym,exercise", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "buffgym.html", + "allow_emulator": false, + "storage": [ + {"name":"buffgym.app.js","url":"buffgym.app.js"}, + {"name":"buffgym-set.js","url":"buffgym-set.js"}, + {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, + {"name":"buffgym-workout.js","url":"buffgym-workout.js"}, + {"name":"buffgym-workout-a.json","url":"buffgym-workout-a.json"}, + {"name":"buffgym-workout-b.json","url":"buffgym-workout-b.json"}, + {"name":"buffgym-workout-index.json","url":"buffgym-workout-index.json"}, + {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} + ] + }, + { + "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} + ] + }, + { + "id": "metronome", + "name": "Metronome", + "version": "0.07", + "readme": "README.md", + "description": "Makes the watch blinking and vibrating with a given rate", + "icon": "metronome_icon.png", + "tags": "tool", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-metronome-screenshot.png"}], + "storage": [ + {"name":"metronome.app.js","url":"metronome.js"}, + {"name":"metronome.img","url":"metronome-icon.js","evaluate":true}, + {"name":"metronome.settings.js","url":"settings.js"} + ] + }, + { + "id": "blackjack", + "name": "Black Jack game", + "shortName": "Black Jack game", + "version": "0.02", + "description": "Simple implementation of card game Black Jack", + "icon": "blackjack.png", + "tags": "game", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-black-jack-game-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"blackjack.app.js","url":"blackjack.app.js"}, + {"name":"blackjack.img","url":"blackjack-icon.js","evaluate":true} + ] + }, + { + "id": "hidcam", + "name": "Camera shutter", + "shortName": "Cam shutter", + "version": "0.03", + "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle", + "icon": "app.png", + "tags": "bluetooth,tool", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"hidcam.app.js","url":"app.js"}, + {"name":"hidcam.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "swlclk", + "name": "SWL Clock / Short Wave Listner Clock", + "shortName": "SWL Clock", + "version": "0.02", + "description": "Display Local, UTC time and some programs on the shorts waves along the day, with the frequencies", + "icon": "swlclk.png", + "type": "clock", + "tags": "tool,clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-SWL-clock-screenshot.png"}], + "storage": [ + {"name":"swlclk.app.js","url":"app.js"}, + {"name":"swlclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "rclock", + "name": "Round clock with seconds, minutes and date", + "shortName": "Round Clock", + "version": "0.06", + "description": "Designed round clock with ticks for minutes and seconds and heart rate indication", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"rclock.app.js","url":"rclock.app.js"}, + {"name":"rclock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "fclock", + "name": "fclock", + "shortName": "F Clock", + "version": "0.02", + "description": "Simple design of a digital clock", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"fclock.app.js","url":"fclock.app.js"}, + {"name":"fclock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "hamloc", + "name": "QTH Locator / Maidenhead Locator System", + "shortName": "QTH Locator", + "version": "0.01", + "description": "Convert your current GPS location to the Maidenhead locator system used by HAM amateur radio operators", + "icon": "app.png", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"hamloc.app.js","url":"app.js"}, + {"name":"hamloc.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "osmpoi", + "name": "POI Compass", + "version": "0.03", + "description": "Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.", + "icon": "app.png", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS"], + "readme": "README.md", + "custom": "custom.html", + "storage": [ + {"name":"osmpoi.app.js"}, + {"name":"osmpoi.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "pong", + "name": "Pong", + "shortName": "Pong", + "version": "0.03", + "description": "A clone of the Atari game Pong", + "icon": "pong.png", + "type": "app", + "tags": "game", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-pong-screenshot.png"}], + "storage": [ + {"name":"pong.app.js","url":"app.js"}, + {"name":"pong.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "ballmaze", + "name": "Ball Maze", + "version": "0.02", + "description": "Navigate a ball through a maze by tilting your watch.", + "icon": "icon.png", + "type": "app", + "tags": "game", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"ballmaze.app.js","url":"app.js"}, + {"name":"ballmaze.img","url":"icon.js","evaluate":true} + ], + "data": [{"name":"ballmaze.json"}] + }, + { + "id": "calendar", + "name": "Calendar", + "version": "0.04", + "description": "Simple calendar", + "icon": "calendar.png", + "screenshots": [{"url":"screenshot_calendar.png"}], + "tags": "calendar", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"calendar.app.js","url":"calendar.js"}, + {"name":"calendar.settings.js","url":"settings.js"}, + {"name":"calendar.img","url":"calendar-icon.js","evaluate":true} + ], + "data": [{"name":"calendar.json"}] + }, + { + "id": "hidjoystick", + "name": "Bluetooth Joystick", + "shortName": "Joystick", + "version": "0.01", + "description": "Emulates a 2 axis/5 button Joystick using the accelerometer as stick input and buttons 1-3, touch left as button 4 and touch right as button 5.", + "icon": "app.png", + "tags": "bluetooth", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"hidjoystick.app.js","url":"app.js"}, + {"name":"hidjoystick.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "largeclock", + "name": "Large Clock", + "version": "0.10", + "description": "A readable and informational digital watch, with date, seconds and moon phase", + "icon": "largeclock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-large-clock-screenshot.png"}], + "storage": [ + {"name":"largeclock.app.js","url":"largeclock.js"}, + {"name":"largeclock.img","url":"largeclock-icon.js","evaluate":true}, + {"name":"largeclock.settings.js","url":"settings.js"} + ], + "data": [{"name":"largeclock.json"}] + }, + { + "id": "smtswch", + "name": "Smart Switch", + "shortName": "Smart Switch", + "version": "0.01", + "description": "Using EspruinoHub, control your smart devices on and off via Bluetooth Low Energy!", + "icon": "app.png", + "type": "app", + "tags": "bluetooth,btle,smart,switch", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"smtswch.app.js","url":"app.js"}, + {"name":"smtswch.img","url":"app-icon.js","evaluate":true}, + {"name":"light-on.img","url":"light-on.js","evaluate":true}, + {"name":"light-off.img","url":"light-off.js","evaluate":true}, + {"name":"switch-on.img","url":"switch-on.js","evaluate":true}, + {"name":"switch-off.img","url":"switch-off.js","evaluate":true} + ] + }, + { + "id": "miplant", + "name": "Xiaomi Plant Sensor", + "shortName": "Mi Plant", + "version": "0.02", + "description": "Reads and displays data from Xiaomi bluetooth plant moisture sensors", + "icon": "app.png", + "tags": "xiaomi,mi,plant,ble,bluetooth", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"miplant.app.js","url":"app.js"}, + {"name":"miplant.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "simpletimer", + "name": "Timer", + "version": "0.07", + "description": "Simple timer, useful when playing board games or cooking", + "icon": "app.png", + "tags": "timer", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-timer-screenshot.png"}], + "storage": [ + {"name":"simpletimer.app.js","url":"app.js"}, + {"name":".tfnames","url":"gesture-tfnames.js","evaluate":true}, + {"name":".tfmodel","url":"gesture-tfmodel.js","evaluate":true}, + {"name":"simpletimer.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"simpletimer.json"}] + }, + { + "id": "beebclock", + "name": "Beeb Clock", + "version": "0.05", + "description": "Clock face that may be coincidentally familiar to BBC viewers", + "icon": "beebclock.png", + "type": "clock", + "tags": "clock", + "screenshots": [{"url":"bangle1-beeb-clock-screenshot.png"}], + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"beebclock.app.js","url":"beebclock.js"}, + {"name":"beebclock.img","url":"beebclock-icon.js","evaluate":true} + ] + }, + { + "id": "findphone", + "name": "Find Phone", + "shortName": "Find Phone", + "version": "0.03", + "description": "Find your phone via Gadgetbridge. Click any button to let your phone ring. 📳 Note: The functionality is available even without this app, just go to Settings, App Settings, Gadgetbridge, Find Phone.", + "icon": "app.png", + "tags": "tool,android", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"findphone.app.js","url":"app.js"}, + {"name":"findphone.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "getup", + "name": "Get Up", + "shortName": "Get Up", + "version": "0.01", + "description": "Reminds you to getup every x minutes. Sitting to long is dangerous!", + "icon": "app.png", + "tags": "tools,health", + "supports": ["BANGLEJS"], + "readme": "README.md", + "screenshots": [{"url":"bangle1-get-up-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"getup.app.js","url":"app.js"}, + {"name":"getup.settings.js","url":"settings.js"}, + {"name":"getup.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "gallifr", + "name": "Time Traveller's Chronometer", + "shortName": "Time Travel Clock", + "version": "0.02", + "description": "A clock for time travellers. The light pie segment shows the minutes, the black circle, the hour. The dial itself reads 'time' just in case you forget.", + "icon": "gallifr.png", + "screenshots": [{"url":"screenshot_time.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"gallifr.app.js","url":"app.js"}, + {"name":"gallifr.img","url":"app-icon.js","evaluate":true}, + {"name":"gallifr.settings.js","url":"settings.js"} + ], + "data": [{"name":"gallifr.json"}] + }, + { + "id": "rndmclk", + "name": "Random Clock Loader", + "version": "0.03", + "description": "Load a different clock whenever the LCD is switched on.", + "icon": "rndmclk.png", + "type": "widget", + "tags": "widget,clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"rndmclk.wid.js","url":"widget.js"} + ] + }, + { + "id": "dotmatrixclock", + "name": "Dotmatrix Clock", + "version": "0.01", + "description": "A clear white-on-blue dotmatrix simulated clock", + "icon": "dotmatrixclock.png", + "type": "clock", + "tags": "clock,dotmatrix,retro", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"dotmatrixclock.app.js","url":"app.js"}, + {"name":"dotmatrixclock.img","url":"dotmatrixclock-icon.js","evaluate":true} + ] + }, + { + "id": "jbm8b", + "name": "Magic 8 Ball", + "shortName": "Magic 8 Ball", + "version": "0.03", + "description": "A simple fortune telling app", + "icon": "app.png", + "tags": "game", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"jbm8b.app.js","url":"app.js"}, + {"name":"jbm8b.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "jbm8b_IT", + "name": "Magic 8 Ball Italiano", + "shortName": "Magic 8 Ball IT", + "version": "0.01", + "description": "La palla predice il futuro", + "icon": "app.png", + "screenshots": [{"url":"bangle1-magic-8-ball-italiano-screenshot.png"}], + "tags": "game", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"jbm8b_IT.app.js","url":"app.js"}, + {"name":"jbm8b_IT.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "BLEcontroller", + "name": "BLE Customisable Controller with Joystick", + "shortName": "BLE Controller", + "version": "0.01", + "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", + "icon": "BLEcontroller.png", + "tags": "tool,bluetooth", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": false, + "storage": [ + {"name":"BLEcontroller.app.js","url":"app.js"}, + {"name":"BLEcontroller.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widviz", + "name": "Widget Visibility Widget", + "shortName": "Viz Widget", + "version": "0.03", + "description": "Swipe left to hide top bar widgets, swipe right to redisplay.", + "icon": "eye.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widviz.wid.js","url":"widget.js"} + ] + }, + { + "id": "binclock", + "name": "Binary Clock", + "shortName": "Binary Clock", + "version": "0.03", + "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", + "icon": "app.png", + "type": "clock", + "tags": "clock,binary", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"binclock.app.js","url":"app.js"}, + {"name":"binclock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "pizzatimer", + "name": "Pizza Timer", + "shortName": "Pizza Timer", + "version": "0.01", + "description": "A timer app for when you cook Pizza. Some say it can also time other things", + "icon": "pizza.png", + "tags": "timer,tool,pizza", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"pizzatimer.app.js","url":"app.js"}, + {"name":"pizzatimer.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "animclk", + "name": "Animated Clock", + "shortName": "Anim Clock", + "version": "0.03", + "description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art", + "icon": "app.png", + "type": "clock", + "tags": "clock,animated", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"animclk.app.js","url":"app.js"}, + {"name":"animclk.pixels1","url":"animclk.pixels1"}, + {"name":"animclk.pixels2","url":"animclk.pixels2"}, + {"name":"animclk.pal","url":"animclk.pal"}, + {"name":"animclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "analogimgclk", + "name": "Analog Clock (Image background)", + "shortName": "Analog Clock", + "version": "0.03", + "description": "An analog clock with an image background", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"analogimgclk.app.js","url":"app.js"}, + {"name":"analogimgclk.bg.img","url":"bg.img"}, + {"name":"analogimgclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "verticalface", + "name": "Vertical watch face", + "shortName": "Vertical Face", + "version": "0.09", + "description": "A simple vertical watch face with the date. Heart rate monitor is toggled with BTN1", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "screenshots": [{"url":"bangle1-vertical-watch-face-screenshot.png"}], + "storage": [ + {"name":"verticalface.app.js","url":"app.js"}, + {"name":"verticalface.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "sleepphasealarm", + "name": "SleepPhaseAlarm", + "shortName": "SleepPhaseAlarm", + "version": "0.02", + "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", + "icon": "app.png", + "tags": "alarm", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"sleepphasealarm.app.js","url":"app.js"}, + {"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "life", + "name": "Game of Life", + "version": "0.04", + "description": "Conway's Game of Life - 16x16 board", + "icon": "life.png", + "tags": "game", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-game-of-life-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"life.app.js","url":"life.min.js"}, + {"name":"life.img","url":"life-icon.js","evaluate":true} + ] + }, + { + "id": "magnav", + "name": "Navigation Compass", + "version": "0.05", + "description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.", + "screenshots": [{"url":"screenshot-b2.png"},{"url":"screenshot-light-b2.png"}], + "icon": "magnav.png", + "tags": "tool,outdoors", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"magnav.app.js","url":"magnav_b1.js","supports":["BANGLEJS"]}, + {"name":"magnav.app.js","url":"magnav_b2.js","supports":["BANGLEJS2"]}, + {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} + ], + "data": [{"name":"magnav.json"}] + }, + { + "id": "gpspoilog", + "name": "GPS POI Logger", + "shortName": "GPS POI Log", + "version": "0.01", + "description": "A simple app to log points of interest with their GPS coordinates and read them back onto your PC. Based on the https://www.espruino.com/Bangle.js+Storage tutorial", + "icon": "app.png", + "tags": "outdoors", + "supports": ["BANGLEJS"], + "interface": "interface.html", + "storage": [ + {"name":"gpspoilog.app.js","url":"app.js"}, + {"name":"gpspoilog.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "miclock2", + "name": "Mixed Clock 2", + "version": "0.01", + "description": "White color variant of the Mixed Clock with thicker clock hands for better readability in the bright sunlight, extra space under the clock for widgets and seconds in the digital clock.", + "icon": "clock-mixed.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-mixed-clock-2-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"miclock2.app.js","url":"clock-mixed.js"}, + {"name":"miclock2.img","url":"clock-mixed-icon.js","evaluate":true} + ] + }, + { + "id": "1button", + "name": "One-Button-Tracker", + "version": "0.01", + "description": "A widget that turns BTN1 into a tracker, records time of button press/release.", + "icon": "widget.png", + "type": "widget", + "tags": "tool,quantifiedself,widget", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"1button.wid.js","url":"widget.js"} + ], + "data": [{"name":"one_button_presses.csv","storageFile":true}] + }, + { + "id": "gpsautotime", + "name": "GPS auto time", + "shortName": "GPS auto time", + "version": "0.01", + "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"], + "storage": [ + {"name":"gpsautotime.wid.js","url":"widget.js"} + ] + }, + { + "id": "espruinoctrl", + "name": "Espruino Control", + "shortName": "Espruino Ctrl", + "version": "0.01", + "description": "Send commands to other Espruino devices via the Bluetooth UART interface. Customisable commands!", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "readme": "README.md", + "custom": "custom.html", + "storage": [ + {"name":"espruinoctrl.app.js"}, + {"name":"espruinoctrl.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "multiclock", + "name": "Multi Clock", + "version": "0.09", + "description": "Clock with multiple faces. Switch between faces with BTN1 & BTN3 (Bangle 2 touch top-right, bottom right). For best display set theme Background 2 to cyan or some other bright colour in settings.", + "screenshots": [{"url":"screen-ana.png"},{"url":"screen-big.png"},{"url":"screen-td.png"},{"url":"screen-nifty.png"},{"url":"screen-word.png"},{"url":"screen-sec.png"}], + "icon": "multiclock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"multiclock.app.js","url":"multiclock.app.js"}, + {"name":"big.face.js","url":"big.face.js"}, + {"name":"ana.face.js","url":"ana.face.js"}, + {"name":"digi.face.js","url":"digi.face.js"}, + {"name":"txt.face.js","url":"txt.face.js"}, + {"name":"dk.face.js","url":"dk.face.js"}, + {"name":"nifty.face.js","url":"nifty.face.js"}, + {"name":"multiclock.img","url":"multiclock-icon.js","evaluate":true} + ] + }, + { + "id": "widancs", + "name": "Apple Notification Widget", + "shortName": "ANCS Widget", + "version": "0.07", + "description": "Displays call, message etc notifications from a paired iPhone. Read README before installation as it only works with compatible apps", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"widancs.wid.js","url":"ancs.min.js"}, + {"name":"widancs.settings.js","url":"settings.js"} + ] + }, + { + "id": "accelrec", + "name": "Acceleration Recorder", + "shortName": "Accel Rec", + "version": "0.02", + "description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"accelrec.app.js","url":"app.js"}, + {"name":"accelrec.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"wildcard":"accelrec.?.csv"}] + }, + { + "id": "accellog", + "name": "Acceleration Logger", + "shortName": "Accel Log", + "version": "0.03", + "description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC", + "icon": "app.png", + "tags": "outdoor", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"accellog.app.js","url":"app.js"}, + {"name":"accellog.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"wildcard":"accellog.?.csv"}] + }, + { + "id": "cprassist", + "name": "CPR Assist", + "version": "0.01", + "description": "Provides assistance while performing a CPR", + "icon": "cprassist-icon.png", + "tags": "tool,firstaid", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-CPR-assist-screenshot.png"}], + "storage": [ + {"name":"cprassist.app.js","url":"cprassist.js"}, + {"name":"cprassist.img","url":"cprassist-icon.js","evaluate":true}, + {"name":"cprassist.settings.js","url":"settings.js"} + ] + }, + { + "id": "osgridref", + "name": "Ordnance Survey Grid Reference", + "shortName": "OS Grid ref", + "version": "0.01", + "description": "Displays the UK Ordnance Survey grid reference of your current GPS location. Useful when in the United Kingdom with an Ordnance Survey map", + "icon": "app.png", + "tags": "outdoors,gps", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"osgridref.app.js","url":"app.js"}, + {"name":"osgridref.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "openseizure", + "name": "OpenSeizureDetector Widget", + "shortName": "Short Name", + "version": "0.01", + "description": "[BETA!] A widget to work alongside [OpenSeizureDetector](https://www.openseizuredetector.org.uk/)", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"openseizure.wid.js","url":"widget.js"} + ] + }, + { + "id": "counter", + "name": "Counter", + "version": "0.03", + "description": "Simple counter", + "icon": "counter_icon.png", + "tags": "tool", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-counter-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"counter.app.js","url":"counter.js"}, + {"name":"counter.img","url":"counter-icon.js","evaluate":true} + ] + }, + { + "id": "bootgattbat", + "name": "BLE GATT Battery Service", + "shortName": "BLE Battery Service", + "version": "0.01", + "description": "Adds the GATT Battery Service to advertise the percentage of battery currently remaining over Bluetooth.\n", + "icon": "bluetooth.png", + "type": "bootloader", + "tags": "battery,ble,bluetooth,gatt", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"gattbat.boot.js","url":"boot.js"} + ] + }, + { + "id": "viewstl", + "name": "STL file viewer", + "shortName": "ViewSTL", + "version": "0.02", + "description": "This app allows you to view STL 3D models on your watch", + "icon": "icons8-octahedron-48.png", + "tags": "tool", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"viewstl.app.js","url":"viewstl.min.js"}, + {"name":"viewstl.img","url":"viewstl-icon.js","evaluate":true}, + {"name":"tetra.stl","url":"tetra.stl"}, + {"name":"cube.stl","url":"cube.stl"}, + {"name":"icosa.stl","url":"icosa.stl"} + ] + }, + { + "id": "cscsensor", + "name": "Cycling speed sensor", + "shortName": "CSCSensor", + "version": "0.06", + "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", + "icon": "icons8-cycling-48.png", + "tags": "outdoors,exercise,ble,bluetooth", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, + {"name":"cscsensor.settings.js","url":"settings.js"}, + {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} + ] + }, + { + "id": "fileman", + "name": "File manager", + "shortName": "FileManager", + "version": "0.03", + "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"], + "readme": "README.md", + "storage": [ + {"name":"fileman.app.js","url":"fileman.app.js"}, + {"name":"fileman.img","url":"fileman-icon.js","evaluate":true} + ] + }, + { + "id": "worldclock", + "name": "World Clock - 4 time zones", + "shortName": "World Clock", + "version": "0.05", + "description": "Current time zone plus up to four others", + "icon": "app.png", + "screenshots": [{"url":"screenshot_world.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "custom": "custom.html", + "storage": [ + {"name":"worldclock.app.js","url":"app.js"}, + {"name":"worldclock.img","url":"worldclock-icon.js","evaluate":true} + ], + "data": [{"name":"worldclock.settings.json"}] + }, + { + "id": "digiclock", + "name": "Digital Clock Face", + "shortName": "Digi Clock", + "version": "0.02", + "description": "A simple digital clock with the time, day, month, and year", + "icon": "digiclock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"digiclock.app.js","url":"digiclock.js"}, + {"name":"digiclock.img","url":"digiclock-icon.js","evaluate":true} + ] + }, + { + "id": "dsdrelay", + "name": "DSD BLE Relay controller", + "shortName": "DSDRelay", + "version": "0.01", + "description": "Control BLE relay board from the watch", + "icon": "icons8-relay-48.png", + "tags": "ble,bluetooth", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"dsdrelay.app.js","url":"dsdrelay.app.js"}, + {"name":"dsdrelay.img","url":"dsdrelay-icon.js","evaluate":true} + ] + }, + { + "id": "mandel", + "name": "Mandelbrot", + "shortName": "Mandel", + "version": "0.01", + "description": "Draw a zoomable Mandelbrot set", + "icon": "mandel.png", + "tags": "game", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"mandel.app.js","url":"mandel.min.js"}, + {"name":"mandel.img","url":"mandel-icon.js","evaluate":true} + ] + }, + { + "id": "petrock", + "name": "Pet rock", + "version": "0.02", + "description": "A virtual pet rock with wobbly eyes", + "icon": "petrock.png", + "type": "app", + "tags": "game", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"petrock.app.js","url":"app.js"}, + {"name":"petrock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "smartibot", + "name": "Smartibot controller", + "shortName": "Smartibot", + "version": "0.01", + "description": "Control a [Smartibot Robot](https://thecraftyrobot.net/) straight from your Bangle.js", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"smartibot.app.js","url":"app.js"}, + {"name":"smartibot.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widncr", + "name": "NCR Logo Widget", + "version": "0.01", + "description": "Show the NodeConf Remote logo in the top left", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"widncr.wid.js","url":"widget.js"} + ] + }, + { + "id": "ncrclk", + "name": "NCR Clock", + "shortName": "NCR Clock", + "version": "0.02", + "description": "NodeConf Remote clock", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"ncrclk.app.js","url":"app.js"}, + {"name":"ncrclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "isoclock", + "name": "ISO Compliant Clock Face", + "shortName": "ISO Clock", + "version": "0.02", + "description": "Tweaked fork of digiclock for ISO date and time", + "icon": "isoclock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"isoclock.app.js","url":"isoclock.js"}, + {"name":"isoclock.img","url":"isoclock-icon.js","evaluate":true} + ] + }, + { + "id": "gpstimeserver", + "name": "GPS Time Server", + "version": "0.01", + "description": "A widget which automatically starts the GPS and turns Bangle.js into a Bluetooth time server.", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"gpstimeserver.wid.js","url":"widget.js"} + ] + }, + { + "id": "tilthydro", + "name": "Tilt Hydrometer Display", + "shortName": "Tilt Hydro", + "version": "0.01", + "description": "A display for the [Tilt Hydrometer](https://tilthydrometer.com/) - [more info here](http://www.espruino.com/Tilt+Hydrometer+Display)", + "icon": "app.png", + "tags": "tools,bluetooth", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"tilthydro.app.js","url":"app.js"}, + {"name":"tilthydro.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "supmariodark", + "name": "Super mario clock night mode", + "shortName": "supmariodark", + "version": "0.01", + "description": "Super mario clock in night mode", + "icon": "supmariodark.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"supmariodark.app.js","url":"supmariodark.js"}, + {"name":"supmariodark.img","url":"supmariodark-icon.js","evaluate":true}, + {"name":"supmario30x24.bin","url":"supmario30x24.bin.js"}, + {"name":"supmario30x24.wdt","url":"supmario30x24.wdt.js"}, + {"name":"banner-up.img","url":"banner-up.js","evaluate":true}, + {"name":"banner-down.img","url":"banner-down.js","evaluate":true}, + {"name":"brick2.img","url":"brick2.js","evaluate":true}, + {"name":"enemy.img","url":"enemy.js","evaluate":true}, + {"name":"flower.img","url":"flower.js","evaluate":true}, + {"name":"flower_b.img","url":"flower_b.js","evaluate":true}, + {"name":"mario_wh.img","url":"mario_wh.js","evaluate":true}, + {"name":"pipe.img","url":"pipe.js","evaluate":true} + ] + }, + { + "id": "gmeter", + "name": "G-Meter", + "shortName": "G-Meter", + "version": "0.01", + "description": "Simple G-Meter", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"gmeter.app.js","url":"app.js"}, + {"name":"gmeter.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "dtlaunch", + "name": "Desktop Launcher", + "version": "0.07", + "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", + "type": "launch", + "tags": "tool,system,launcher", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"dtlaunch.app.js","url":"app-b1.js", "supports": ["BANGLEJS"]}, + {"name":"dtlaunch.app.js","url":"app-b2.js", "supports": ["BANGLEJS2"]}, + {"name":"dtlaunch.settings.js","url":"settings-b1.js", "supports": ["BANGLEJS"]}, + {"name":"dtlaunch.settings.js","url":"settings-b2.js", "supports": ["BANGLEJS2"]}, + {"name":"dtlaunch.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"dtlaunch.json"}] + }, + { + "id": "HRV", + "name": "Heart Rate Variability monitor", + "shortName": "HRV monitor", + "version": "0.04", + "description": "Heart Rate Variability monitor, see Readme for more info", + "icon": "hrv.png", + "tags": "", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"HRV.app.js","url":"app.js"}, + {"name":"HRV.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "hardalarm", + "name": "Hard Alarm", + "shortName": "HardAlarm", + "version": "0.02", + "description": "Make sure you wake up! Count to the right number to turn off the alarm", + "icon": "app.png", + "tags": "tool,alarm,widget", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"hardalarm.app.js","url":"app.js"}, + {"name":"hardalarm.boot.js","url":"boot.js"}, + {"name":"hardalarm.js","url":"hardalarm.js"}, + {"name":"hardalarm.img","url":"app-icon.js","evaluate":true}, + {"name":"hardalarm.wid.js","url":"widget.js"} + ], + "data": [{"name":"hardalarm.json"}] + }, + { + "id": "edisonsball", + "name": "Edison's Ball", + "shortName": "Edison's Ball", + "version": "0.01", + "description": "Hypnagogia/Micro-Sleep alarm for experimental use in exploring sleep transition and combating drowsiness", + "icon": "app-icon.png", + "tags": "", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"edisonsball.app.js","url":"app.js"}, + {"name":"edisonsball.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "hrrawexp", + "name": "HRM Data Exporter", + "shortName": "HRM Data Exporter", + "version": "0.01", + "description": "export raw hrm signal data to a csv file", + "icon": "app-icon.png", + "tags": "", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "interface.html", + "storage": [ + {"name":"hrrawexp.app.js","url":"app.js"}, + {"name":"hrrawexp.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "breath", + "name": "Breathing App", + "shortName": "Breathing App", + "version": "0.01", + "description": "app to aid relaxation and train breath syncronicity using haptics and visualisation, also displays HR", + "icon": "app-icon.png", + "tags": "tools,health", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"breath.app.js","url":"app.js"}, + {"name":"breath.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"breath.settings.json","url":"settings.json"}] + }, + { + "id": "lazyclock", + "name": "Lazy Clock", + "version": "0.03", + "description": "Tells the time, roughly", + "icon": "lazyclock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "screenshots": [{"url":"bangle1-lazy-clock-screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"lazyclock.app.js","url":"lazyclock-app.js"}, + {"name":"lazyclock.img","url":"lazyclock-icon.js","evaluate":true} + ] + }, + { + "id": "astral", + "name": "Astral Clock", + "version": "0.03", + "description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.", + "icon": "app-icon.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"astral.app.js","url":"app.js"}, + {"name":"astral.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "alpinenav", + "name": "Alpine Nav", + "version": "0.01", + "description": "App that performs GPS monitoring to track and display position relative to a given origin in realtime", + "icon": "app-icon.png", + "tags": "outdoors,gps", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"alpinenav.app.js","url":"app.js"}, + {"name":"alpinenav.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "lifeclk", + "name": "Game of Life Clock", + "shortName": "Conway's Clock", + "version": "0.06", + "description": "Modification and clockification of Conway's Game of Life", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"lifeclk.app.js","url":"app.min.js"}, + {"name":"lifeclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "speedalt", + "name": "GPS Adventure Sports", + "shortName": "GPS Adv Sport", + "version": "1.02", + "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", + "icon": "app.png", + "type": "app", + "tags": "tool,outdoors", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"speedalt.app.js","url":"app.js"}, + {"name":"speedalt.img","url":"app-icon.js","evaluate":true}, + {"name":"speedalt.settings.js","url":"settings.js"} + ], + "data": [{"name":"speedalt.json"}] + }, + { + "id": "speedalt2", + "name": "GPS Adventure Sports II", + "shortName":"GPS Adv Sport II", + "version":"1.10", + "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", + "icon": "app.png", + "type": "app", + "tags": "tool,outdoors", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"speedalt2.app.js","url":"app.js"}, + {"name":"speedalt2.img","url":"app-icon.js","evaluate":true}, + {"name":"speedalt2.settings.js","url":"settings.js"} + ], + "data": [{"name":"speedalt2.json"}] + }, + { + "id": "slomoclock", + "name": "SloMo Clock", + "shortName": "SloMo Clock", + "version": "0.10", + "description": "Simple 24h clock face with large digits, hour above minute. Uses Layout library.", + "icon": "watch.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-slow-mo-clock-screenshot.png"}], + "storage": [ + {"name":"slomoclock.app.js","url":"app.js"}, + {"name":"slomoclock.img","url":"app-icon.js","evaluate":true}, + {"name":"slomoclock.settings.js","url":"settings.js"} + ], + "data": [{"name":"slomoclock.json"}] + }, + { + "id": "de-stress", + "name": "De-Stress", + "shortName": "De-Stress", + "version": "0.02", + "description": "Simple haptic heartbeat", + "icon": "app.png", + "tags": "", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"de-stress.app.js","url":"app.js"}, + {"name":"de-stress.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "mclockplus", + "name": "Morph Clock+", + "shortName": "Morph Clock+", + "version": "0.02", + "description": "Morphing Clock with more readable seconds and date and additional stopwatch", + "icon": "mclockplus.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"mclockplus.app.js","url":"mclockplus.app.js"}, + {"name":"mclockplus.img","url":"mclockplus-icon.js","evaluate":true} + ] + }, + { + "id": "intervals", + "name": "Intervals App", + "shortName": "Intervals", + "version": "0.01", + "description": "Intervals for training. It is possible to configure work time and rest time and number of sets.", + "icon": "intervals.png", + "tags": "", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"intervals.app.js","url":"intervals.app.js"}, + {"name":"intervals.img","url":"intervals-icon.js","evaluate":true} + ] + }, + { + "id": "planetarium", + "name": "Planetarium", + "shortName": "Planetarium", + "version": "0.03", + "description": "Planetarium showing up to 500 stars using the watch location and time", + "icon": "planetarium.png", + "tags": "", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"planetarium.app.js","url":"planetarium.app.js"}, + {"name":"planetarium.data.csv","url":"planetarium.data.csv"}, + {"name":"planetarium.const.csv","url":"planetarium.const.csv"}, + {"name":"planetarium.extra.csv","url":"planetarium.extra.csv"}, + {"name":"planetarium.settings.js","url":"settings.js"}, + {"name":"planetarium.img","url":"planetarium-icon.js","evaluate":true} + ], + "data": [{"name":"planetarium.json"}] + }, + { + "id": "tapelauncher", + "name": "Tape Launcher", + "version": "0.02", + "description": "An App launcher, icons displayed in a horizontal tape, swipe or use buttons", + "icon": "icon.png", + "type": "launch", + "tags": "tool,system,launcher", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"tapelauncher.app.js","url":"app.js"}, + {"name":"tapelauncher.img","url":"icon.js","evaluate":true} + ] + }, + { + "id": "oblique", + "name": "Oblique Strategies", + "version": "0.01", + "description": "Oblique Strategies for creativity. Copied from Brian Eno.", + "icon": "eno.png", + "tags": "tool", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"oblique.app.js","url":"app.js"}, + {"name":"oblique.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "testuserinput", + "name": "Test User Input", + "shortName": "Test User Input", + "version": "0.06", + "description": "App to test the bangle.js input interface. It displays the user action in text, circle buttons or on/off switch UI elements.", + "icon": "app.png", + "tags": "input,interface,buttons,touch,UI", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"testuserinput.app.js","url":"app.js"}, + {"name":"testuserinput.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "gpssetup", + "name": "GPS Setup", + "shortName": "GPS Setup", + "version": "0.02", + "description": "Configure the GPS power options and store them in the GPS nvram", + "icon": "gpssetup.png", + "tags": "gps,tools,outdoors", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"gpssetup","url":"gpssetup.js"}, + {"name":"gpssetup.settings.js","url":"settings.js"}, + {"name":"gpssetup.app.js","url":"app.js"}, + {"name":"gpssetup.img","url":"icon.js","evaluate":true} + ], + "data": [{"name":"gpssetup.settings.json","url":"settings.json"}] + }, + { + "id": "walkersclock", + "name": "Walkers Clock", + "shortName": "Walkers Clock", + "version": "0.04", + "description": "A large font watch, displays steps, can switch GPS on/off, displays grid reference", + "icon": "walkersclock48.png", + "type": "clock", + "tags": "clock,gps,tools,outdoors", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"walkersclock.app.js","url":"app.js"}, + {"name":"walkersclock.img","url":"icon.js","evaluate":true} + ] + }, + { + "id": "widgps", + "name": "GPS Widget", + "version": "0.03", + "description": "Tiny widget to show the power on/off status of the GPS", + "icon": "widget.png", + "type": "widget", + "tags": "widget,gps", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widgps.wid.js","url":"widget.js"} + ] + }, + { + "id": "widhrt", + "name": "HRM Widget", + "version": "0.03", + "description": "Tiny widget to show the power on/off status of the Heart Rate Monitor", + "icon": "widget.png", + "type": "widget", + "tags": "widget,hrm", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widhrt.wid.js","url":"widget.js"} + ] + }, + { + "id": "countdowntimer", + "name": "Countdown Timer", + "version": "0.01", + "description": "A simple countdown timer with a focus on usability", + "icon": "countdowntimer.png", + "tags": "timer,tool", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"countdowntimer.app.js","url":"countdowntimer.js"}, + {"name":"countdowntimer.img","url":"countdowntimer-icon.js","evaluate":true} + ] + }, + { + "id": "helloworld", + "name": "hello, world!", + "shortName": "hello world", + "version": "0.02", + "description": "A cross cultural hello world!/hola mundo! app with colors and languages", + "icon": "app.png", + "tags": "input,interface,buttons,touch", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"helloworld.app.js","url":"app.js"}, + {"name":"helloworld.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widcom", + "name": "Compass Widget", + "version": "0.02", + "description": "Tiny widget to show the power on/off status of the Compass", + "icon": "widget.png", + "type": "widget", + "tags": "widget,compass", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widcom.wid.js","url":"widget.js"} + ] + }, + { + "id": "arrow", + "name": "Arrow Compass", + "version": "0.05", + "description": "Moving arrow compass that points North, shows heading, with tilt correction. Based on jeffmer's Navigation Compass", + "icon": "arrow.png", + "type": "app", + "tags": "tool,outdoors", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"arrow.app.js","url":"app.js"}, + {"name":"arrow.img","url":"icon.js","evaluate":true} + ] + }, + { + "id": "waypointer", + "name": "Way Pointer", + "version": "0.01", + "description": "Navigate to a waypoint using the GPS for bearing and compass to point way, uses the same waypoint interface as GPS Navigation", + "icon": "waypointer.png", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "waypoints.html", + "storage": [ + {"name":"waypointer.app.js","url":"app.js"}, + {"name":"waypointer.img","url":"icon.js","evaluate":true} + ], + "data": [{"name":"waypoints.json","url":"waypoints.json"}] + }, + { + "id": "color_catalog", + "name": "Colors Catalog", + "shortName": "Colors Catalog", + "version": "0.01", + "description": "Displays RGB565 and RGB888 colors, its name and code in screen.", + "icon": "app.png", + "tags": "Color,input,buttons,touch,UI", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"color_catalog.app.js","url":"app.js"}, + {"name":"color_catalog.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "UI4swatch", + "name": "UI 4 swatch", + "shortName": "UI 4 swatch", + "version": "0.01", + "description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.", + "icon": "app.png", + "tags": "Color,input,buttons,touch,UI", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"UI4swatch.app.js","url":"app.js"}, + {"name":"UI4swatch.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "simplest", + "name": "Simplest Clock", + "version": "0.03", + "description": "The simplest working clock, acts as a tutorial piece", + "icon": "simplest.png", + "screenshots": [{"url":"screenshot_simplest.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"simplest.app.js","url":"app.js"}, + {"name":"simplest.img","url":"icon.js","evaluate":true} + ] + }, + { + "id": "stepo", + "name": "Stepometer Clock", + "version": "0.03", + "description": "A large font watch, displays step count in a doughnut guage and warns of low battery, requires one of the steps widgets to be installed", + "icon": "stepo.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"stepo.app.js","url":"app.js"}, + {"name":"stepo.img","url":"icon.js","evaluate":true} + ] + }, + { + "id": "gbmusic", + "name": "Gadgetbridge Music Controls", + "shortName": "Music Controls", + "version": "0.08", + "description": "Control the music on your Gadgetbridge-connected phone", + "icon": "icon.png", + "screenshots": [{"url":"screenshot_v1.png"},{"url":"screenshot_v2.png"}], + "type": "app", + "tags": "tools,bluetooth,gadgetbridge,music", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"gbmusic.app.js","url":"app.js"}, + {"name":"gbmusic.settings.js","url":"settings.js"}, + {"name":"gbmusic.wid.js","url":"widget.js"}, + {"name":"gbmusic.img","url":"icon.js","evaluate":true} + ], + "data": [{"name":"gbmusic.json"},{"name":"gbmusic.load.json"}] + }, + { + "id": "battleship", + "name": "Battleship", + "version": "0.01", + "description": "The classic game of battleship", + "icon": "battleship-icon.png", + "tags": "game", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-battle-ship-screenshot.png"}], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"battleship.app.js","url":"battleship.js"}, + {"name":"battleship.img","url":"battleship-icon.js","evaluate":true} + ] + }, + { + "id": "kitchen", + "name": "Kitchen Combo", + "version": "0.13", + "description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'", + "icon": "kitchen.png", + "type": "clock", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS"], + "readme": "README.md", + "interface": "waypoints.html", + "storage": [ + {"name":"kitchen.app.js","url":"kitchen.app.js"}, + {"name":"stepo2.kit.js","url":"stepo2.kit.js"}, + {"name":"swatch.kit.js","url":"swatch.kit.js"}, + {"name":"gps.kit.js","url":"gps.kit.js"}, + {"name":"compass.kit.js","url":"compass.kit.js"}, + {"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true} + ], + "data": [{"name":"waypoints.json","url":"waypoints.json"}] + }, + { + "id": "banglebridge", + "name": "BangleBridge", + "shortName": "BangleBridge", + "version": "0.01", + "description": "Widget that allows Bangle Js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"banglebridge.wid.js","url":"widget.js"}, + {"name":"banglebridge.watch.img","url":"watch.img"}, + {"name":"banglebridge.heart.img","url":"heart.img"} + ] + }, + { + "id": "qmsched", + "name": "Quiet Mode Schedule and Widget", + "shortName": "Quiet Mode", + "version": "0.06", + "description": "Automatically turn Quiet Mode on or off at set times, and change LCD options while Quiet Mode is active.", + "icon": "app.png", + "screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"}, + {"url":"screenshot_b2_main.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_lcd.png"}], + "tags": "tool,widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"qmsched","url":"lib.js"}, + {"name":"qmsched.app.js","url":"app.js"}, + {"name":"qmsched.boot.js","url":"boot.js"}, + {"name":"qmsched.img","url":"icon.js","evaluate":true}, + {"name":"qmsched.wid.js","url":"widget.js"} + ], + "data": [{"name":"qmsched.json"}] + }, + { + "id": "hourstrike", + "name": "Hour Strike", + "shortName": "Hour Strike", + "version": "0.08", + "description": "Strike the clock on the hour. A great tool to remind you an hour has passed!", + "icon": "app-icon.png", + "tags": "tool,alarm", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"hourstrike.app.js","url":"app.js"}, + {"name":"hourstrike.boot.js","url":"boot.js"}, + {"name":"hourstrike.img","url":"app-icon.js","evaluate":true}, + {"name":"hourstrike.json","url":"hourstrike.json"} + ] + }, + { + "id": "whereworld", + "name": "Where in the World?", + "shortName": "Where World", + "version": "0.01", + "description": "Shows your current location on the world map", + "icon": "app.png", + "tags": "gps", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"whereworld.app.js","url":"app.js"}, + {"name":"whereworld.img","url":"app-icon.js","evaluate":true}, + {"name":"whereworld.worldmap","url":"worldmap"} + ] + }, + { + "id": "omnitrix", + "name": "Omnitrix", + "version": "0.01", + "description": "An Omnitrix Showpiece", + "icon": "omnitrix.png", + "screenshots": [{"url":"screenshot.png"}], + "tags": "game", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"omnitrix.app.js","url":"omnitrix.app.js"}, + {"name":"omnitrix.img","url":"omnitrix.icon.js","evaluate":true} + ] + }, + { + "id": "batclock", + "name": "Bat Clock", + "shortName": "Bat Clock", + "version": "0.02", + "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", + "icon": "bat-clock.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"batclock.app.js","url":"bat-clock.app.js"}, + {"name":"batclock.img","url":"bat-clock.icon.js","evaluate":true} + ] + }, + { + "id": "doztime", + "name": "Dozenal Time", + "shortName": "Dozenal Time", + "version": "0.04", + "description": "A dozenal Holocene calendar and dozenal diurnal clock", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"doztime.app.js","url":"app.js"}, + {"name":"doztime.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "gbtwist", + "name": "Gadgetbridge Twist Control", + "shortName": "Twist Control", + "version": "0.01", + "description": "Shake your wrist to control your music app via Gadgetbridge", + "icon": "app.png", + "type": "app", + "tags": "tools,bluetooth,gadgetbridge,music", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": false, + "storage": [ + {"name":"gbtwist.app.js","url":"app.js"}, + {"name":"gbtwist.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "thermom", + "name": "Thermometer", + "version": "0.05", + "description": "Displays the current temperature in degree Celsius/Fahrenheit (depending on locale), updates every 10 seconds with average of last 5 readings.", + "icon": "app.png", + "tags": "tool", + "supports": ["BANGLEJS", "BANGLEJS2"], + "screenshots": [{"url":"screenshot.png"}], + "allow_emulator": true, + "storage": [ + {"name":"thermom.app.js","url":"app.js"}, + {"name":"thermom.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "mysticdock", + "name": "Mystic Dock", + "version": "1.00", + "description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.", + "icon": "mystic-dock.png", + "type": "dock", + "tags": "dock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"mysticdock.app.js","url":"mystic-dock-app.js"}, + {"name":"mysticdock.boot.js","url":"mystic-dock-boot.js"}, + {"name":"mysticdock.settings.js","url":"mystic-dock-settings.js"}, + {"name":"mysticdock.img","url":"mystic-dock-icon.js","evaluate":true} + ] + }, + { + "id": "mysticclock", + "name": "Mystic Clock", + "version": "1.01", + "description": "A retro-inspired watchface featuring time, date, and an interactive data display line.", + "icon": "mystic-clock.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"bangle1-mystic-clock-screenshot.png"}], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"mysticclock.app.js","url":"mystic-clock-app.js"}, + {"name":"mysticclock.settings.js","url":"mystic-clock-settings.js"}, + {"name":"mysticclock.img","url":"mystic-clock-icon.js","evaluate":true} + ] + }, + { + "id": "hcclock", + "name": "Hi-Contrast Clock", + "version": "0.02", + "description": "Hi-Contrast Clock : A simple yet very bold clock that aims to be readable in high luninosity environments. Uses big 10x5 pixel digits. Use BTN 1 to switch background and foreground colors.", + "icon": "hcclock-icon.png", + "type": "clock", + "tags": "clock", + "screenshots": [{"url":"bangle1-high-contrast-clock-screenshot.png"}], + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"hcclock.app.js","url":"hcclock.app.js"}, + {"name":"hcclock.img","url":"hcclock-icon.js","evaluate":true} + ] + }, + { + "id": "thermomF", + "name": "Fahrenheit Temp", + "version": "0.01", + "description": "[NOT RECOMMENDED] A modification of the Thermometer App to display temprature in Fahrenheit. Please use the 'Thermometer App' and install 'Languages' to get the temperature in the correct format for your locale.", + "icon": "thermf.png", + "tags": "tool", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"thermomF.app.js","url":"app.js"}, + {"name":"thermomF.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "nixie", + "name": "Nixie Clock", + "shortName": "Nixie", + "version": "0.01", + "description": "A nixie tube clock for both Bangle 1 and 2.", + "icon": "nixie.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"nixie.app.js","url":"app.js"}, + {"name":"nixie.img","url":"app-icon.js","evaluate":true}, + {"name":"m_vatch.js","url":"m_vatch.js"} + ] + }, + { + "id": "carcrazy", + "name": "Car Crazy", + "shortName": "Car Crazy", + "version": "0.03", + "description": "A simple car game where you try to avoid the other cars by tilting your wrist left and right. Hold down button 2 to start.", + "icon": "carcrash.png", + "tags": "game", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"carcrazy.app.js","url":"app.js"}, + {"name":"carcrazy.img","url":"app-icon.js","evaluate":true}, + {"name":"carcrazy.settings.js","url":"settings.js"} + ], + "data": [{"name":"CarCrazy.csv"}] + }, + { + "id": "shortcuts", + "name": "Shortcuts", + "shortName": "Shortcuts", + "version": "0.01", + "description": "Quickly load your favourite apps from (almost) any watch face.", + "icon": "app.png", + "type": "bootloader", + "tags": "tool", + "supports": ["BANGLEJS"], + "readme": "README.md", + "storage": [ + {"name":"shortcuts.boot.js","url":"boot.js"}, + {"name":"shortcuts.settings.js","url":"settings.js"} + ], + "data": [{"name":"shortcuts.json"}] + }, + { + "id": "vectorclock", + "name": "Vector Clock", + "version": "0.03", + "description": "A digital clock that uses the built-in vector font.", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS", "BANGLEJS2"], + "allow_emulator": true, + "screenshots": [ + {"url":"bangle2-vector-clock-screenshot.png"}, + {"url":"bangle1-vector-clock-screenshot.png"} + ], + "storage": [ + {"name":"vectorclock.app.js","url":"app.js"}, + {"name":"vectorclock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "fd6fdetect", + "name": "fd6fdetect", + "shortName": "fd6fdetect", + "version": "0.2", + "description": "Allows you to see 0xFD6F beacons near you.", + "icon": "app.png", + "tags": "tool", + "readme": "README.md", + "supports": ["BANGLEJS"], + "storage": [ + {"name":"fd6fdetect.app.js","url":"app.js"}, + {"name":"fd6fdetect.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "choozi", + "name": "Choozi", + "version": "0.01", + "description": "Choose people or things at random using Bangle.js.", + "icon": "app.png", + "tags": "tool", + "supports": ["BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "screenshots": [{"url":"bangle1-choozi-screenshot1.png"},{"url":"bangle1-choozi-screenshot2.png"}], + "storage": [ + {"name":"choozi.app.js","url":"app.js"}, + {"name":"choozi.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "widclkbttm", + "name": "Digital clock (Bottom) widget", + "shortName": "Digital clock Bottom Widget", + "version": "0.03", + "description": "Displays time in the bottom area.", + "icon": "widclkbttm.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widclkbttm.wid.js","url":"widclkbttm.wid.js"} + ] + }, + { + "id": "pastel", + "name": "Pastel Clock", + "shortName": "Pastel", + "version": "0.09", + "description": "A Configurable clock with custom fonts and background. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", + "icon": "pastel.png", + "dependencies": {"mylocation":"app", "widpedom":"app"}, + "screenshots": [{"url":"screenshot_pastel.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"f_architect","url":"f_architect.js"}, + {"name":"f_gochihand","url":"f_gochihand.js"}, + {"name":"f_cabin","url":"f_cabin.js"}, + {"name":"f_orbitron","url":"f_orbitron.js"}, + {"name":"f_monoton","url":"f_monoton.js"}, + {"name":"f_elite","url":"f_elite.js"}, + {"name":"f_lato","url":"f_lato.js"}, + {"name":"f_latosmall","url":"f_latosmall.js"}, + {"name":"pastel.app.js","url":"pastel.app.js"}, + {"name":"pastel.img","url":"pastel.icon.js","evaluate":true}, + {"name":"pastel.settings.js","url":"pastel.settings.js"} + ], + "data": [{"name":"pastel.json"}] + }, + { + "id": "antonclk", + "name": "Anton Clock", + "version": "0.03", + "description": "A simple clock using the bold Anton font.", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"antonclk.app.js","url":"app.js"}, + {"name":"antonclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "waveclk", + "name": "Wave Clock", + "version": "0.02", + "description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: Works on any Bangle.js 2, but requires firmware 2v11 or later on Bangle.js 1**", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"waveclk.app.js","url":"app.js"}, + {"name":"waveclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "floralclk", + "name": "Floral Clock", + "version": "0.01", + "description": "A clock with a flower background by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: Works on any Bangle.js 2 but requires firmware 2v11 or later on Bangle.js 1**", + "icon": "app.png", + "screenshots": [{"url":"screenshot_floral.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"floralclk.app.js","url":"app.js"}, + {"name":"floralclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "score", + "name": "Score Tracker", + "version": "0.01", + "description": "Score Tracker for sports that use plain numbers (e.g. Badminton, Volleyball, Soccer, Table Tennis, ...). Also supports tennis scoring.", + "icon": "score.app.png", + "screenshots": [{"url":"screenshot_score.png"}], + "type": "app", + "tags": "", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"score.app.js","url":"score.app.js"}, + {"name":"score.settings.js","url":"score.settings.js"}, + {"name":"score.presets.json","url":"score.presets.json"}, + {"name":"score.img","url":"score.app-icon.js","evaluate":true} + ], + "data": [{"name":"score.json"}] + }, + { + "id": "menusmall", + "name": "Small Menus", + "version": "0.02", + "description": "Replace Bangle.js 2's menus with a version that contains smaller text", + "icon": "app.png", + "type": "boot", + "tags": "system", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"menusmall.boot.js","url":"boot.js"} + ] + }, + { + "id": "ffcniftya", + "name": "Nifty-A Clock", + "version": "0.01", + "description": "A nifty clock with time and date", + "icon": "app.png", + "screenshots": [{"url":"screenshot_nifty.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"ffcniftya.app.js","url":"app.js"}, + {"name":"ffcniftya.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "ffcniftyb", + "name": "Nifty-B Clock", + "version": "0.02", + "description": "A nifty clock (series B) with time, date and color configuration", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"ffcniftyb.app.js","url":"app.js"}, + {"name":"ffcniftyb.img","url":"app-icon.js","evaluate":true}, + {"name":"ffcniftyb.settings.js","url":"settings.js"} + ], + "data": [{"name":"ffcniftyb.json"}] + }, + { + "id": "stopwatch", + "name": "Stopwatch Touch", + "version": "0.01", + "description": "A touch based stop watch for Bangle JS 2", + "icon": "stopwatch.png", + "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"}], + "tags": "tools,app", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"stopwatch.app.js","url":"stopwatch.app.js"}, + {"name":"stopwatch.img","url":"stopwatch.icon.js","evaluate":true} + ] + }, + { + "id": "vernierrespirate", + "name": "Vernier Go Direct Respiration Belt", + "shortName": "Respiration Belt", + "version": "0.01", + "description": "Connects to a Go Direct Respiration Belt and shows respiration rate", + "icon": "app.png", + "tags": "health,bluetooth", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"vernierrespirate.app.js","url":"app.js"}, + {"name":"vernierrespirate.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"vernierrespirate.json"}] + }, + { + "id": "gpstouch", + "name": "GPS Touch", + "version": "0.01", + "description": "A touch based GPS watch, shows OS map reference", + "icon": "gpstouch.png", + "screenshots": [{"url":"screenshot4.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot1.png"}], + "tags": "tools,app", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"geotools","url":"geotools.js"}, + {"name":"gpstouch.app.js","url":"gpstouch.app.js"}, + {"name":"gpstouch.img","url":"gpstouch.icon.js","evaluate":true} + ] + }, + { + "id": "swiperclocklaunch", + "name": "Swiper Clock Launch", + "version": "0.02", + "description": "Navigate between clock and launcher with Swipe action", + "icon": "swiperclocklaunch.png", + "type": "bootloader", + "tags": "tools, system", + "supports": ["BANGLEJS", "BANGLEJS2"], + "storage": [ + {"name":"swiperclocklaunch.boot.js","url":"boot.js"}, + {"name":"swiperclocklaunch.img","url":"icon.js","evaluate":true} + ] + }, + { + "id": "qalarm", + "name": "Q Alarm and Timer", + "shortName": "Q Alarm", + "icon": "app.png", + "version": "0.03", + "description": "Alarm and timer app with days of week and 'hard' option.", + "tags": "tool,alarm,widget", + "supports": ["BANGLEJS", "BANGLEJS2"], + "storage": [ + { "name": "qalarm.app.js", "url": "app.js" }, + { "name": "qalarm.boot.js", "url": "boot.js" }, + { "name": "qalarm.js", "url": "qalarm.js" }, + { "name": "qalarmcheck.js", "url": "qalarmcheck.js" }, + { "name": "qalarm.img", "url": "app-icon.js", "evaluate": true }, + { "name": "qalarm.wid.js", "url": "widget.js" } + ], + "data": [{ "name": "qalarm.json" }] + }, + { + "id": "emojuino", + "name": "Emojuino", + "shortName": "Emojuino", + "version": "0.03", + "description": "Emojis & Espruino: broadcast Unicode emojis via Bluetooth Low Energy.", + "icon": "emojuino.png", + "screenshots": [ + { "url": "screenshot-tx.png" }, + { "url": "screenshot-swipe.png" }, + { "url": "screenshot-welcome.png" } + ], + "type": "app", + "tags": "emoji", + "supports" : [ "BANGLEJS2" ], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + { "name": "emojuino.app.js", "url": "emojuino.js" }, + { "name": "emojuino.img", "url": "emojuino-icon.js", "evaluate": true } + ] + }, + { + "id": "cliclockJS2Enhanced", + "name": "Commandline-Clock JS2 Enhanced", + "shortName": "CLI-Clock JS2", + "version": "0.03", + "description": "Simple CLI-Styled Clock with enhancements. Modes that are hard to use and unneded are removed (BPM, battery info, memory ect) credit to hughbarney for the original code and design. Also added HID media controlls, just swipe on the clock face to controll the media! Gadgetbride support coming soon(hopefully) Thanks to t0m1o1 for media controls!", + "icon": "app.png", + "screenshots": [{"url":"screengrab.png"}], + "type": "clock", + "tags": "clock,cli,command,bash,shell", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"cliclockJS2Enhanced.app.js","url":"app.js"}, + {"name":"cliclockJS2Enhanced.img","url":"app.icon.js","evaluate":true} + ] + }, + { + "id": "wid_a_battery_widget", + "name": "A Battery Widget (with percentage)", + "shortName":"A Battery Widget", + "icon": "widget.png", + "version":"1.02", + "type": "widget", + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "description": "Simple and slim battery widget with charge status and percentage", + "tags": "widget,battery", + "storage": [ + {"name":"wid_a_battery_widget.wid.js","url":"widget.js"} + ] + }, + { + "id": "lcars", + "name": "LCARS Clock", + "shortName":"LCARS", + "icon": "lcars.png", + "version":"0.07", + "readme": "README.md", + "supports": ["BANGLEJS2"], + "description": "Library Computer Access Retrieval System (LCARS) clock.", + "type": "clock", + "tags": "clock", + "screenshots": [{"url":"screenshot.png"}], + "storage": [ + {"name":"lcars.app.js","url":"lcars.app.js"}, + {"name":"lcars.img","url":"lcars.icon.js","evaluate":true}, + {"name":"lcars.settings.js","url":"lcars.settings.js"} + ] + }, + { "id": "binwatch", + "name": "Binary Watch", + "shortName":"BinWatch", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "version":"0.04", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "allow_emulator":true, + "description": "Famous binary watch", + "tags": "clock", + "type": "clock", + "storage": [ + {"name":"binwatch.app.js","url":"app.js"}, + {"name":"binwatch.bg176.img","url":"Background176_center.img"}, + {"name":"binwatch.bg240.img","url":"Background240_center.img"}, + {"name":"binwatch.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "hidmsicswipe", + "name": "Bluetooth Music Swipe Controls", + "shortName": "Swipe Control", + "version": "0.01", + "description": "Based on the original Bluetooth Music Controls. Swipe up/down for volume, left/right for previous and next, tap for play/pause and btn1 to lock and unlock the controls. Enable HID in settings, pair with your phone, then use this app to control music from your watch!", + "icon": "hidmsicswipe.png", + "tags": "bluetooth", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"hidmsicswipe.app.js","url":"hidmsicswipe.js"}, + {"name":"hidmsicswipe.img","url":"hidmsicswipe-icon.js","evaluate":true} + ] + }, + { + "id": "authentiwatch", + "name": "2FA Authenticator", + "shortName": "AuthWatch", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "version": "0.04", + "description": "Google Authenticator compatible tool.", + "tags": "tool", + "interface": "interface.html", + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"authentiwatch.app.js","url":"app.js"}, + {"name":"authentiwatch.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"authentiwatch.json"}] + }, + { "id": "schoolCalendar", + "name": "School Calendar", + "shortName":"SCalendar", + "icon": "CalenderLogo.png", + "version": "0.01", + "description": "A simple calendar that you can see your upcoming events that you create in the customizer. Keep in note that your events reapeat weekly.(Beta)", + "tags": "tool", + "readme":"README.md", + "custom":"custom.html", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"screenshot_basic.png"},{"url":"screenshot_info.png"}], + "storage": [ + {"name":"schoolCalendar.app.js"}, + {"name":"schoolCalendar.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"calendarItems.csv"} + ] + }, + { "id": "timecal", + "name": "TimeCal", + "shortName":"TimeCal", + "icon": "icon.png", + "version":"0.01", + "description": "TimeCal shows the Time along with a 3 week calendar", + "tags": "clock", + "type": "clock", + "supports":["BANGLEJS2"], + "storage": [ + {"name":"timecal.app.js","url":"timecal.app.js"} + ] + }, + { + "id": "a_clock_timer", + "name": "A Clock with Timer", + "version": "0.01", + "description": "A Clock with Timer, Map and Time Zones", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + {"name":"a_clock_timer.app.js","url":"app.js"}, + {"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id":"intervalTimer", + "name":"Interval Timer", + "shortName":"Interval Timer", + "icon": "app.png", + "version":"0.01", + "description": "Interval Timer for workouts, HIIT, or whatever else.", + "tags": "timer, interval, hiit, workout", + "readme":"README.md", + "supports":["BANGLEJS2"], + "storage": [ + {"name":"intervalTimer.app.js","url":"app.js"}, + {"name":"intervalTimer.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "93dub", + "name": "93 Dub", + "shortName":"93 Dub", + "icon": "93dub.png", + "screenshots": [{"url":"screenshot.png"}], + "version":"0.05", + "description": "Fan recreation of orviwan's 91 Dub app for the Pebble smartwatch. Uses assets from his 91-Dub-v2.0 repo", + "tags": "clock", + "type": "clock", + "supports":["BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"93dub.app.js","url":"app.js"}, + {"name":"93dub.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "poweroff", + "name": "Poweroff", + "shortName":"Poweroff", + "version":"0.01", + "description": "Simple app to power off your Bangle.js", + "icon": "app.png", + "tags": "tool, poweroff, shutdown", + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"poweroff.app.js","url":"app.js"}, + {"name":"poweroff.img","url":"app-icon.js","evaluate":true} + ] +}, +{ + "id": "sensible", + "name": "SensiBLE", + "shortName": "SensiBLE", + "version": "0.04", + "description": "Collect, display and advertise real-time sensor data.", + "icon": "sensible.png", + "screenshots": [ + { "url": "screenshot-top.png" }, + { "url": "screenshot-acc.png" }, + { "url": "screenshot-bar.png" }, + { "url": "screenshot-gps.png" }, + { "url": "screenshot-hrm.png" }, + { "url": "screenshot-mag.png" } + ], + "type": "app", + "tags": "tool,sensors", + "supports" : [ "BANGLEJS2" ], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + { "name": "sensible.app.js", "url": "sensible.js" }, + { "name": "sensible.img", "url": "sensible-icon.js", "evaluate": true } + ] +}, + { + "id": "widbars", + "name": "Bars Widget", + "version": "0.01", + "description": "Display several measurements as vertical bars.", + "icon": "icon.png", + "screenshots": [{"url":"screenshot.png"}], + "readme": "README.md", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widbars.wid.js","url":"widget.js"} + ] +}, +{ + "id":"a_speech_timer", + "name":"Speech Timer", + "icon": "app.png", + "version":"1.01", + "description": "A timer designed to help keeping your speeches and presentations to time.", + "tags": "tool,timer", + "readme":"README.md", + "supports":["BANGLEJS2"], + "storage": [ + {"name":"a_speech_timer.app.js","url":"app.js"}, + {"name":"a_speech_timer.img","url":"app-icon.js","evaluate":true} + ] +}, + { "id": "mylocation", + "name": "My Location", + "shortName":"My Location", + "icon": "mylocation.png", + "type": "app", + "screenshots": [{"url":"screenshot_1.png"}], + "version":"0.01", + "description": "Sets and stores the lat and long of your preferred City or it can be set from the GPS. mylocation.json can be used by other apps that need your main location lat and lon. See README", + "readme": "README.md", + "tags": "tool,utility", + "supports": ["BANGLEJS", "BANGLEJS2"], + "storage": [ + {"name":"mylocation.app.js","url":"mylocation.app.js"}, + {"name":"mylocation.img","url":"mylocation.icon.js","evaluate": true } + ], + "data": [ + {"name":"mylocation.json"} + ] + }, + { + "id": "pebble", + "name": "Pebble Clock", + "shortName": "Pebble", + "version": "0.06", + "description": "A pebble style clock to keep the rebellion going", + "dependencies": {"widpedom":"app"}, + "readme": "README.md", + "icon": "pebble.png", + "screenshots": [{"url":"pebble_screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"pebble.app.js","url":"pebble.app.js"}, + {"name":"pebble.settings.js","url":"pebble.settings.js"}, + {"name":"pebble.img","url":"pebble.icon.js","evaluate":true} + ] + }, + { "id": "pooqroman", + "name": "pooq Roman watch face", + "shortName":"pooq Roman", + "version":"0.03", + "description": "A classic watch face with a certain dynamicity. Most amusing in 24h mode. Slide up to show more hands, down for less(!). By design does not support standard widgets, sorry!", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"pooqroman.app.js","url":"app.js"}, + {"name":"pooqroman.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"pooqroman.json"} + ] + }, + { + "id": "widbata", + "name": "Battery Level Widget (Themed)", + "shortName":"Battery Theme", + "icon": "widbata.png", + "screenshots": [{"url":"screenshot_widbata_1.png"}], + "version":"0.01", + "type": "widget", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "description": "Shows the current battery level status in the top right using the clocks colour theme", + "tags": "widget,battery", + "storage": [ + {"name":"widbata.wid.js","url":"widbata.wid.js"} + ] + }, + { + "id": "weatherClock", + "name": "Weather Clock", + "version": "0.04", + "description": "A clock which displays current weather conditions (requires Gadgetbridge and Weather apps).", + "icon": "app.png", + "screenshots": [{"url":"screens/screen1.png"}], + "type": "clock", + "tags": "clock, weather", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + {"name":"weatherClock.app.js","url":"app.js"}, + {"name":"weatherClock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "menuwheel", + "name": "Wheel Menus", + "version": "0.01", + "description": "Replace Bangle.js 2's menus with a version that contains variable-size text and a back button", + "readme": "README.md", + "icon": "icon.png", + "screenshots": [ + {"url":"screenshot_b1_dark.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_light.png"}, + {"url":"screenshot_b2_dark.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_light.png"} + ], + "type": "boot", + "tags": "system", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"menuwheel.boot.js","url":"boot.js"} + ] + }, + { "id": "widChargingStatus", + "name": "Charging Status", + "shortName":"ChargingStatus", + "icon": "widget.png", + "version":"0.1", + "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", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"widChargingStatus.wid.js","url":"widget.js"} + ] + }, + { + "id": "flow", + "name": "FLOW", + "shortName": "FLOW", + "version": "0.01", + "description": "A game where you have to help a flow avoid white obstacles thing by tapping! This is a demake of an app which I forgot the name of. Press BTN(1) to restart. See if you can get to 2500 score!", + "icon": "app.png", + "tags": "game", + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name": "flow.app.js", "url": "app.js" }, + {"name": "flow.img", "url": "app-icon.js","evaluate": true } + ] + }, + { "id": "scribble", + "name": "Scribble", + "shortName":"Scribble", + "version":"0.01", + "type": "app", + "description": "A keyboard on your wrist! Swipe right for space, left for delete.", + "icon": "app.png", + "allow_emulator": true, + "tags": "tools, keyboard, text, scribble", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"scribble.app.js","url":"app.js"}, + {"name":"scribble.img","url":"app-icon.js","evaluate":true} + ], + "screenshots":[ + { "url":"screenshot.png" } + ] + }, + { + "id": "ptlaunch", + "name": "Pattern Launcher", + "shortName": "Pattern Launcher", + "version": "0.11", + "description": "Directly launch apps from the clock screen with custom patterns.", + "icon": "app.png", + "screenshots": [{"url":"manage_patterns_light.png"}], + "tags": "tools", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + { "name": "ptlaunch.app.js", "url": "app.js" }, + { "name": "ptlaunch.boot.js", "url": "boot.js" }, + { "name": "ptlaunch.img", "url": "app-icon.js", "evaluate": true } + ], + "data": [{"name":"ptlaunch.patterns.json"}] + }, + { + "id": "rebble", + "name": "Rebble Clock", + "shortName": "Rebble", + "version": "0.03", + "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", + "readme": "README.md", + "icon": "rebble.png", + "dependencies": {"mylocation":"app", "widpedom":"app"}, + "screenshots": [{"url":"screenshot_rebble.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"rebble.app.js","url":"rebble.app.js"}, + {"name":"rebble.settings.js","url":"rebble.settings.js"}, + {"name":"rebble.img","url":"rebble.icon.js","evaluate":true} + ] + }, + { "id": "snaky", + "name": "Snaky", + "shortName":"Snaky", + "version":"0.01", + "description": "The classic snake game. Eat apples and don't bite your tail. Control the snake with the touch screen.", + "tags": "game,fun", + "icon": "snaky.png", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"snaky.app.js","url":"snaky.js"}, + {"name":"snaky.img","url":"snaky-icon.js","evaluate":true} + ] + }, + { + "id": "clicompleteclk", + "name": "CLI complete clock", + "shortName":"CLI cmplt clock", + "version":"0.03", + "description": "Command line styled clock with lots of information", + "icon": "app.png", + "allow_emulator": true, + "type": "clock", + "tags": "clock,cli,command,bash,shell,weather,hrt", + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"clicompleteclk.app.js","url":"app.js"}, + {"name":"clicompleteclk.img","url":"app-icon.js","evaluate":true}, + {"name":"clicompleteclk.settings.js","url":"settings.js"} + ], + "data": [{"name":"clicompleteclk.json"}] + }, + { + "id":"awairmonitor", + "name":"Awair Monitor", + "icon": "app.png", + "allow_emulator": true, + "version":"0.01", + "description": "Displays the level of CO2, VOC, PM 2.5, Humidity and Temperature, from your Awair device.", + "tags": "tool,health", + "readme":"README.md", + "supports":["BANGLEJS2"], + "storage": [ + {"name":"awairmonitor.app.js","url":"app.js"}, + {"name":"awairmonitor.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "pooqround", + "name": "pooq Round watch face", + "shortName":"pooq Round", + "version":"0.01", + "description": "A 24 hour analogue watchface with high legibility and a novel style.", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"pooqround.app.js","url":"app.js"}, + {"name":"pooqround.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"pooqround.json"} + ] + }, + { + "id": "coretemp", + "name": "Core Temp Display", + "version": "0.01", + "description": "Display CoreTemp device sensor data", + "icon": "coretemp.png", + "type": "app", + "tags": "health", + "readme": "README.md", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"coretemp.boot.js","url":"boot.js"}, + {"name":"coretemp.app.js","url":"coretemp.js"}, + {"name":"coretemp.img","url":"coretemp-icon.js","evaluate":true} + ] + }, + { + "id": "showimg", + "name": "simple image viewer", + "shortName":"showImage", + "version":"0.2", + "description": "Displays the image in \"showimg.user.img\". The file has to be uploaded via the espruino IDE. Returns to watch face after 60s or button push. I use it to display my vaccination certificate.", + "icon": "app.png", + "tags": "tool", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"showimg.app.js","url":"app.js"}, + {"name":"showimg.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "lapcounter", + "name": "Lap Counter", + "version": "0.01", + "description": "Click button to count laps. Shows count and total time snapshot (like a stopwatch, but laid back).", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "app", + "tags": "tool,outdoors", + "readme":"README.md", + "supports": ["BANGLEJS", "BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"lapcounter.app.js","url":"app.js"}, + {"name":"lapcounter.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "pebbled", + "name": "Pebble Clock with distance", + "shortName": "Pebble + distance", + "version": "0.1", + "description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).", + "readme": "README.md", + "icon": "pebbled.png", + "screenshots": [{"url":"pebble_screenshot.png"}], + "type": "clock", + "tags": "clock,distance", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"pebbled.app.js","url":"pebbled.app.js"}, + {"name":"pebbled.settings.js","url":"pebbled.settings.js"}, + {"name":"pebbled.img","url":"pebbled.icon.js","evaluate":true} + ] + }, + { "id": "circlesclock", + "name": "Circles clock", + "shortName":"Circles clock", + "version":"0.02", + "description": "A clock with circles for different data at the bottom in a probably familiar style", + "icon": "app.png", + "dependencies": {"widpedom":"app"}, + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"circlesclock.app.js","url":"app.js"}, + {"name":"circlesclock.img","url":"app-icon.js","evaluate":true}, + {"name":"circlesclock.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"circlesclock.json"} + ] + }, + { + "id": "ltherm", + "name": "Localized Thermometer", + "shortName": "Thermometer", + "version": "0.01", + "description": "Displays the current temperature in localized units.", + "icon": "thermf.png", + "tags": "tool", + "supports": ["BANGLEJS2"], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + {"name":"ltherm.app.js","url":"app.js"}, + {"name":"ltherm.img","url":"icon.js","evaluate":true} + ] + } ] From f3c0dfcdcaf1cee6a3f397cdb5f9fea771be01be Mon Sep 17 00:00:00 2001 From: Marco H Date: Thu, 24 Feb 2022 11:19:35 +0100 Subject: [PATCH 267/447] Change threema icon to 24x24px 1bit color --- apps/messages/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 512659c40..282a2b125 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -92,7 +92,7 @@ function getMessageImage(msg) { if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA=="); if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA=="); if (s=="sms message") return getNotificationImage(); - if (s=="threema") return atob("ICCDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//+AAAAAAAAAAAP/////wAAAAAAAAB//////+AAAAAAAAP///////wAAAAAAB////////+AAAAAAP///wAP///wAAAAAP/////////wAAAAAP//+P/x///wAAAAAP//+P/x///+AAAAB///+AAB///+AAAAAP//+AAB///+AAAAAP//+AAB///wAAAAAP//+AAB///wAAAAAB/////////wAAAAAB////////+AAAAAAB////////wAAAAAAB///////+AAAAAAAP//////+AAAAAAAAP+AAP/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEkAAkAAkgAAAAAAAEkAEkgAkgAAAAAAAEkAAkAAkgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); + if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA"); if (s=="telegram") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA=="); From 4143a5f105cfd2b5eb8a84d93e77cd9d2ea65542 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 24 Feb 2022 11:01:37 +0000 Subject: [PATCH 268/447] 0.05: Don't poll for GPS status, override setGPSPower handler (fix #1456) --- apps/widgps/ChangeLog | 1 + apps/widgps/metadata.json | 2 +- apps/widgps/widget.js | 27 +++++++++------------------ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/apps/widgps/ChangeLog b/apps/widgps/ChangeLog index 3d47b8a0c..f68fc701c 100644 --- a/apps/widgps/ChangeLog +++ b/apps/widgps/ChangeLog @@ -2,3 +2,4 @@ 0.02: Don't break if running on 2v08 firmware (just don't display anything) 0.03: Fix positioning 0.04: Show GPS fix status +0.05: Don't poll for GPS status, override setGPSPower handler (fix #1456) diff --git a/apps/widgps/metadata.json b/apps/widgps/metadata.json index 2f59aa82a..39bff2fad 100644 --- a/apps/widgps/metadata.json +++ b/apps/widgps/metadata.json @@ -1,7 +1,7 @@ { "id": "widgps", "name": "GPS Widget", - "version": "0.04", + "version": "0.05", "description": "Tiny widget to show the power and fix status of the GPS", "icon": "widget.png", "type": "widget", diff --git a/apps/widgps/widget.js b/apps/widgps/widget.js index 25df2178a..bfdb89d33 100644 --- a/apps/widgps/widget.js +++ b/apps/widgps/widget.js @@ -1,7 +1,13 @@ (function(){ - if (!Bangle.isGPSOn) return; // old firmware + // override setGPSPower so we know if GPS is on or off + var oldSetGPSPower = Bangle.setGPSPower; + Bangle.setGPSPower = function(on,id) { + var isGPSon = oldSetGPSPower(on,id); + WIDGETS.gps.draw(); + return isGPSon; + } - function draw() { + WIDGETS.gps={area:"tr",width:24,draw:function() { g.reset(); if (Bangle.isGPSOn()) { const gpsObject = Bangle.getGPSFix(); @@ -14,20 +20,5 @@ g.setColor("#888"); // off = grey } g.drawImage(atob("GBiBAAAAAAAAAAAAAA//8B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+A//8AAAAAAAAAAAAA=="), this.x, 2+this.y); - } - - var timerInterval; - Bangle.on('lcdPower', function(on) { - if (on) { - WIDGETS.gps.draw(); - if (!timerInterval) timerInterval = setInterval(()=>WIDGETS.gps.draw(), 2000); - } else { - if (timerInterval) { - clearInterval(timerInterval); - timerInterval = undefined; - } - } - }); - - WIDGETS.gps={area:"tr",width:24,draw:draw}; + }}; })(); From 14b6004f1c0bfa7d579c8bab9271d111853fab0a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 24 Feb 2022 11:33:05 +0000 Subject: [PATCH 269/447] Update setUI to work with new Bangle.js 2v13 menu style --- apps/ptlaunch/ChangeLog | 3 ++- apps/ptlaunch/boot.js | 1 + apps/ptlaunch/metadata.json | 2 +- apps/shortcuts/ChangeLog | 3 ++- apps/shortcuts/boot.js | 2 +- apps/shortcuts/metadata.json | 2 +- apps/swiperclocklaunch/ChangeLog | 1 + apps/swiperclocklaunch/boot.js | 1 + apps/swiperclocklaunch/metadata.json | 2 +- 9 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/ptlaunch/ChangeLog b/apps/ptlaunch/ChangeLog index 68b7d3e1c..eec3610ed 100644 --- a/apps/ptlaunch/ChangeLog +++ b/apps/ptlaunch/ChangeLog @@ -4,4 +4,5 @@ 0.10: Improve the management of existing patterns: Draw the linked pattern on the left hand side of the app name within a scroller, similar to the default launcher. Slighlty clean up the code to make it less horrible. 0.11: Respect theme colors. Fix: Do not pollute global space with internal variables ans functions in boot.js 0.12: Improve pattern detection code readability by PaddeK http://forum.espruino.com/profiles/117930/ -0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/ \ No newline at end of file +0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/ +0.14: Update setUI to work with new Bangle.js 2v13 menu style diff --git a/apps/ptlaunch/boot.js b/apps/ptlaunch/boot.js index 19a8f16cb..748d564f3 100644 --- a/apps/ptlaunch/boot.js +++ b/apps/ptlaunch/boot.js @@ -76,6 +76,7 @@ var sui = Bangle.setUI; Bangle.setUI = function (mode, cb) { sui(mode, cb); + if ("object"==typeof mode) mode = mode.mode; if (!mode) { Bangle.removeListener("drag", dragHandler); storedPatterns = {}; diff --git a/apps/ptlaunch/metadata.json b/apps/ptlaunch/metadata.json index 6c3870d24..0b6dce3d1 100644 --- a/apps/ptlaunch/metadata.json +++ b/apps/ptlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "ptlaunch", "name": "Pattern Launcher", "shortName": "Pattern Launcher", - "version": "0.13", + "version": "0.14", "description": "Directly launch apps from the clock screen with custom patterns.", "icon": "app.png", "screenshots": [{"url":"manage_patterns_light.png"}], diff --git a/apps/shortcuts/ChangeLog b/apps/shortcuts/ChangeLog index 2286a7f70..0e4a98065 100644 --- a/apps/shortcuts/ChangeLog +++ b/apps/shortcuts/ChangeLog @@ -1 +1,2 @@ -0.01: New App! \ No newline at end of file +0.01: New App! +0.02: Update setUI to work with new Bangle.js 2v13 menu style diff --git a/apps/shortcuts/boot.js b/apps/shortcuts/boot.js index f71f6d6ca..58ce2d067 100644 --- a/apps/shortcuts/boot.js +++ b/apps/shortcuts/boot.js @@ -1,6 +1,7 @@ (function() { var sui = Bangle.setUI; Bangle.setUI = function(mode, cb) { + if ("object"==typeof mode) mode = mode.mode; if (mode!="clock") return sui(mode,cb); return sui("clockupdown", (dir) => { let settings = require("Storage").readJSON("shortcuts.json", 1)||{}; @@ -12,4 +13,3 @@ }); }; })(); - \ No newline at end of file diff --git a/apps/shortcuts/metadata.json b/apps/shortcuts/metadata.json index 2351a102f..922d5ae11 100644 --- a/apps/shortcuts/metadata.json +++ b/apps/shortcuts/metadata.json @@ -2,7 +2,7 @@ "id": "shortcuts", "name": "Shortcuts", "shortName": "Shortcuts", - "version": "0.01", + "version": "0.02", "description": "Quickly load your favourite apps from (almost) any watch face.", "icon": "app.png", "type": "bootloader", diff --git a/apps/swiperclocklaunch/ChangeLog b/apps/swiperclocklaunch/ChangeLog index c1b4a5fbb..244b602b5 100644 --- a/apps/swiperclocklaunch/ChangeLog +++ b/apps/swiperclocklaunch/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Fix issue with mode being undefined +0.03: Update setUI to work with new Bangle.js 2v13 menu style diff --git a/apps/swiperclocklaunch/boot.js b/apps/swiperclocklaunch/boot.js index e9b203eee..bb285ea94 100644 --- a/apps/swiperclocklaunch/boot.js +++ b/apps/swiperclocklaunch/boot.js @@ -4,6 +4,7 @@ Bangle.setUI = function(mode, cb) { sui(mode,cb); if(!mode) return; + if ("object"==typeof mode) mode = mode.mode; if (!mode.startsWith("clock")) return; Bangle.swipeHandler = dir => { if (dir<0) Bangle.showLauncher(); }; Bangle.on("swipe", Bangle.swipeHandler); diff --git a/apps/swiperclocklaunch/metadata.json b/apps/swiperclocklaunch/metadata.json index 733aaa032..5e4a0d648 100644 --- a/apps/swiperclocklaunch/metadata.json +++ b/apps/swiperclocklaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "swiperclocklaunch", "name": "Swiper Clock Launch", - "version": "0.02", + "version": "0.03", "description": "Navigate between clock and launcher with Swipe action", "icon": "swiperclocklaunch.png", "type": "bootloader", From 2353191df4fc566803c7596639745a4b9f7246e5 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 24 Feb 2022 15:03:13 +0100 Subject: [PATCH 270/447] messages: Remove left-over debug statement --- apps/messages/ChangeLog | 1 + apps/messages/metadata.json | 2 +- apps/messages/widget.js | 3 +-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 1e6ac71d7..bd40868a5 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -36,3 +36,4 @@ Also gave the widget a pixel more room to the right 0.23: Change message colors to match current theme instead of using green Now attempt to use Large/Big/Medium fonts, and allow minimum font size to be configured +0.24: Remove left-over debug statement diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index e8ed83099..0387c1972 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.23", + "version": "0.24", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/widget.js b/apps/messages/widget.js index 4a247b917..d9363573a 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -6,7 +6,6 @@ draw:function() { g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+this.iconwidth); g.drawImage((c&1) ? atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+DAADDAADDAADDwAPD8A/DOBzDDn/DA//DAHvDAPvjAPvjAPvjAPvh///gf/vAAD+AAB8AAAAA==") : atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+D///D///A//8CP/xDj/HD48DD+B8D/D+D/3vD/vvj/vvj/vvj/vvh/v/gfnvAAD+AAB8AAAAA=="), this.x, this.y); let settings = require('Storage').readJSON("messages.settings.json", true) || {}; - console.log("dingen ", typeof(settings.repeat), settings.repeat) if (settings.repeat===undefined) settings.repeat = 4; if (c<120 && (Date.now()-this.l)>settings.repeat*1000) { this.l = Date.now(); @@ -47,4 +46,4 @@ want to buzz but should still show that there are unread messages. */ if (global.MESSAGES===undefined) (function() { var messages = require("Storage").readJSON("messages.json",1)||[]; if (messages.some(m=>m.new)) WIDGETS["messages"].show(true); -})(); \ No newline at end of file +})(); From 300bde3034e42d468c2d7be4c9241a52c42b5f38 Mon Sep 17 00:00:00 2001 From: Andrew <45957548+midnight4577@users.noreply.github.com> Date: Thu, 24 Feb 2022 08:45:31 -0800 Subject: [PATCH 271/447] Made "Supports" an array --- apps/aptsciclk/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/aptsciclk/metadata.json b/apps/aptsciclk/metadata.json index 15d8ec4e3..c450d926e 100644 --- a/apps/aptsciclk/metadata.json +++ b/apps/aptsciclk/metadata.json @@ -7,7 +7,7 @@ "icon": "app.png", "type": "clock", "tags": "clock", - "supports": "BANGLEJS2", + "supports": ["BANGLEJS2"], "allow_emulator": false, "readme":"README.md", "storage": [ From 8424cc91503ec8c5235b6843e368e79f16f8e321 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 24 Feb 2022 18:22:32 +0000 Subject: [PATCH 272/447] Daisy - fixed metadata --- apps/daisy/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index f2624a0f3..c35bfefa3 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -11,7 +11,7 @@ "storage": [ {"name":"daisy.app.js","url":"app.js"}, {"name":"daisy.img","url":"app-icon.js","evaluate":true}, - {"name":"daisy.settings.js","url":"daisy.settings.js"} + {"name":"daisy.settings.js","url":"settings.js"} ], "data": [{"name":"daisy.json"}] } From 8535b50a0ddf89a7b9e26a0e7369e3cdbeae15f5 Mon Sep 17 00:00:00 2001 From: Marco H Date: Fri, 25 Feb 2022 09:44:34 +0100 Subject: [PATCH 273/447] Messages: icon for alarms --- apps/messages/app.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/messages/app.js b/apps/messages/app.js index fdcad7469..3f3b80080 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -75,9 +75,13 @@ function getPosImage() { function getNegImage() { return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA="); } +/* +* icons should be 24x24px with 1bpp colors and transparancy +*/ function getMessageImage(msg) { if (msg.img) return atob(msg.img); var s = (msg.src||"").toLowerCase(); + if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA="); if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA=="); if (s=="facebook") return getFBIcon(); if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA="); @@ -104,6 +108,7 @@ function getMessageImage(msg) { function getMessageImageCol(msg,def) { return { // generic colors, using B2-safe colors + "alarm": "#fff", "calendar": "#f00", "mail": "#ff0", "music": "#f0f", From 0e850f38028a29d994406f719caad56722f29ff2 Mon Sep 17 00:00:00 2001 From: Marco H Date: Fri, 25 Feb 2022 09:46:03 +0100 Subject: [PATCH 274/447] Bump version to 0.11 --- apps/circlesclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/metadata.json b/apps/circlesclock/metadata.json index 3279ec2cf..b16f14c06 100644 --- a/apps/circlesclock/metadata.json +++ b/apps/circlesclock/metadata.json @@ -1,7 +1,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.10", + "version":"0.11", "description": "A clock with three or four circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}], From bef3c32a9abd4030fa7b3d65e093e83d721c8759 Mon Sep 17 00:00:00 2001 From: Markus Laire Date: Fri, 25 Feb 2022 17:51:31 +0200 Subject: [PATCH 275/447] widadjust: add metadata.json --- apps/widadjust/metadata.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 apps/widadjust/metadata.json diff --git a/apps/widadjust/metadata.json b/apps/widadjust/metadata.json new file mode 100644 index 000000000..30670fd83 --- /dev/null +++ b/apps/widadjust/metadata.json @@ -0,0 +1,18 @@ +{ + "id": "widadjust", + "name": "Adjust Clock", + "version": "0.01", + "description": "Adjusts clock continually in the background to counter clock drift", + "type": "widget", + "tags": "widget", + "supports": [ "BANGLEJS", "BANGLEJS2" ], + "readme": "README.md", + "storage": [ + { "name": "widadjust.wid.js", "url": "widget.js" }, + { "name": "widadjust.settings.js", "url": "settings.js" } + ], + "data": [ + { "name": "widadjust.json" }, + { "name": "widadjust.state" } + ] +} From 38d6a95303cd72e56f9e041d4da1f571b1198851 Mon Sep 17 00:00:00 2001 From: Markus Laire Date: Fri, 25 Feb 2022 17:53:04 +0200 Subject: [PATCH 276/447] widadjust: add other files for v0.01 --- apps/widadjust/README.md | 52 ++++++++ apps/widadjust/settings.js | 120 ++++++++++++++++++ apps/widadjust/widget.js | 244 +++++++++++++++++++++++++++++++++++++ 3 files changed, 416 insertions(+) create mode 100644 apps/widadjust/README.md create mode 100644 apps/widadjust/settings.js create mode 100644 apps/widadjust/widget.js diff --git a/apps/widadjust/README.md b/apps/widadjust/README.md new file mode 100644 index 000000000..1b51440f5 --- /dev/null +++ b/apps/widadjust/README.md @@ -0,0 +1,52 @@ +# Adjust Clock + +Adjusts clock continually in the background to counter clock drift. + +## Usage + +First you need to determine the clock drift of your watch in PPM (parts per million). + +For example if you measure that your watch clock is too fast by 5 seconds in 24 hours, +then PPM is `5 / (24*60*60) * 1000000 = 57.9`. + +Then set PPM in settings and this widget will continually adjust the clock by that amount. + +## Settings + +See **Basic logic** below for more details. + +- **PPM x 10** - change PPM in steps of 10 +- **PPM x 1** - change PPM in steps of 1 +- **PPM x 0.1** - change PPM in steps of 0.1 +- **Update Interval** - How often to update widget and clock error. +- **Threshold** - Threshold for adjusting clock. + When clock error exceeds this threshold, clock is adjusted with `setTime`. +- **Save State** - If `On` clock error state is saved to file when widget exits, if needed. + That is recommended and default setting. + If `Off` clock error state is forgotten and reset to 0 whenever widget is restarted, + for example when going to Launcher. This can cause significant inaccuracy especially + with large **Update Interval** or **Threshold**. +- **Debug Log** - If `On` some debug information is logged to file `widadjust.log`. + +## Display + +Widget shows clock error in milliseconds and PPM. + +## Basic logic + +- When widget starts, clock error state is loaded from file `widadjust.state`. +- While widget is running, widget display and clock error is updated + periodically (**Update Interval**) according to **PPM**. +- When clock error exceeds **Threshold** clock is adjusted with `setTime`. +- When widget exists, clock error state is saved to file `widadjust.state` if needed. + +## Services + +Other apps/widgets can use `WIDGETS.adjust.now()` to request current adjusted time. +To support also case where this widget isn't present, the following code can be used: + +``` +function adjustedNow() { + return WIDGETS.adjust ? WIDGETS.adjust.now() : Date.now(); +} +``` diff --git a/apps/widadjust/settings.js b/apps/widadjust/settings.js new file mode 100644 index 000000000..5791d763b --- /dev/null +++ b/apps/widadjust/settings.js @@ -0,0 +1,120 @@ +(function(back) { + const SETTINGS_FILE = 'widadjust.json'; + const STATE_FILE = 'widadjust.state'; + + const DEFAULT_ADJUST_THRESHOLD = 100; + let thresholdV = [ 10, 25, 50, 100, 250, 500, 1000 ]; + + const DEFAULT_UPDATE_INTERVAL = 60000; + let intervalV = [ 10000, 30000, 60000, 180000, 600000, 1800000, 3600000 ]; + let intervalN = [ "10 s", "30 s", "1 m", "3 m", "10 m", "30 m", "1 h" ]; + + let stateFileErased = false; + + let settings = Object.assign({ + advanced: false, + saveState: true, + debugLog: false, + ppm: 0, + adjustThreshold: DEFAULT_ADJUST_THRESHOLD, + updateInterval: DEFAULT_UPDATE_INTERVAL, + }, require('Storage').readJSON(SETTINGS_FILE, true) || {}); + + if (thresholdV.indexOf(settings.adjustThreshold) == -1) { + settings.adjustThreshold = DEFAULT_ADJUST_THRESHOLD; + } + + if (intervalV.indexOf(settings.updateInterval) == -1) { + settings.updateInterval = DEFAULT_UPDATE_INTERVAL; + } + + function onPpmChange(v) { + settings.ppm = v; + mainMenu['PPM x 10' ].value = v; + mainMenu['PPM x 1' ].value = v; + mainMenu['PPM x 0.1'].value = v; + } + + let mainMenu = { + '': { 'title' : 'Adjust Clock' }, + + '< Back': () => { + require('Storage').writeJSON(SETTINGS_FILE, settings); + back(); + }, + + /* + // NOT FULLY WORKING YET + 'Mode': { + value: settings.advanced, + format: v => v ? 'Advanced' : 'Basic', + onchange: () => { + settings.advanced = !settings.advanced; + } + }, + */ + + 'PPM x 10' : { + value: settings.ppm, + format: v => v.toFixed(1), + step: 10, + onchange : onPpmChange, + }, + + 'PPM x 1' : { + value: settings.ppm, + format: v => v.toFixed(1), + step: 1, + onchange : onPpmChange, + }, + + 'PPM x 0.1' : { + value: settings.ppm, + format: v => v.toFixed(1), + step: 0.1, + onchange : onPpmChange, + }, + + 'Update Interval': { + value: intervalV.indexOf(settings.updateInterval), + min: 0, + max: intervalV.length - 1, + format: v => intervalN[v], + onchange: v => { + settings.updateInterval = intervalV[v]; + }, + }, + + 'Threshold': { + value: thresholdV.indexOf(settings.adjustThreshold), + min: 0, + max: thresholdV.length - 1, + format: v => thresholdV[v] + " ms", + onchange: v => { + settings.adjustThreshold = thresholdV[v]; + }, + }, + + 'Save State': { + value: settings.saveState, + format: v => v ? 'On' : 'Off', + onchange: () => { + settings.saveState = !settings.saveState; + if (!settings.saveState && !stateFileErased) { + stateFileErased = true; + require("Storage").erase(STATE_FILE); + } + }, + }, + + 'Debug Log': { + value: settings.debugLog, + format: v => v ? 'On' : 'Off', + onchange: () => { + settings.debugLog = !settings.debugLog; + }, + }, + }; + + E.showMenu(mainMenu); +}) diff --git a/apps/widadjust/widget.js b/apps/widadjust/widget.js new file mode 100644 index 000000000..ce1fee022 --- /dev/null +++ b/apps/widadjust/widget.js @@ -0,0 +1,244 @@ +(() => { + // ====================================================================== + // CONST + + const DEBUG_LOG_FILE = 'widadjust.log'; + const SETTINGS_FILE = 'widadjust.json'; + const STATE_FILE = 'widadjust.state'; + + const DEFAULT_ADJUST_THRESHOLD = 100; + const DEFAULT_UPDATE_INTERVAL = 60 * 1000; + const MIN_INTERVAL = 10 * 1000; + + const MAX_CLOCK_ERROR_FROM_SAVED_STATE = 2000; + + const SAVE_STATE_CLOCK_ERROR_DELTA_THRESHOLD = 1; + const SAVE_STATE_CLOCK_ERROR_DELTA_IN_PPM_THRESHOLD = 1; + const SAVE_STATE_PPM_DELTA_THRESHOLD = 1; + + // Widget width. + const WIDTH = 22; + + // ====================================================================== + // VARIABLES + + let settings; + let saved; + + let lastClockCheckTime = Date.now();; + let lastClockErrorUpdateTime; + + let clockError; + let currentUpdateInterval; + let lastPpm = null; + + let debugLogFile = null; + + // ====================================================================== + // FUNCTIONS + + function clockCheck() { + let now = Date.now(); + let elapsed = now - lastClockCheckTime; + lastClockCheckTime = now; + + let prevUpdateInterval = currentUpdateInterval; + currentUpdateInterval = settings.updateInterval; + setTimeout(clockCheck, lastClockCheckTime + currentUpdateInterval - Date.now()); + + // If elapsed time differs a lot from expected, + // some other app probably used setTime to change clock significantly. + // -> reset clock error since elapsed time can't be trusted + if (Math.abs(elapsed - prevUpdateInterval) > 10 * 1000) { + // RESET CLOCK ERROR + + clockError = 0; + lastClockErrorUpdateTime = now; + + debug( + 'Looks like some other app used setTime, so reset clockError. (elapsed = ' + + elapsed.toFixed(0) + ')' + ); + WIDGETS.adjust.draw(); + + } else if (!settings.advanced) { + // UPDATE CLOCK ERROR WITHOUT TEMPERATURE COMPENSATION + + updateClockError(settings.ppm); + } else { + // UPDATE CLOCK ERROR WITH TEMPERATURE COMPENSATION + + Bangle.getPressure().then(d => { + let temp = d.temperature; + updateClockError(settings.ppm0 + settings.ppm1 * temp + settings.ppm2 * temp * temp); + }).catch(e => { + WIDGETS.adjust.draw(); + }); + } + } + + function debug(line) { + console.log(line); + if (debugLogFile !== null) { + debugLogFile.write(line + '\n'); + } + } + + function draw() { + g.reset().setFont('6x8').setFontAlign(0, 0); + g.clearRect(this.x, this.y, this.x + WIDTH - 1, this.y + 23); + g.drawString(Math.round(clockError), this.x + WIDTH/2, this.y + 9); + + if (lastPpm !== null) { + g.setFont('4x6').setFontAlign(0, 1); + g.drawString(lastPpm.toFixed(1), this.x + WIDTH/2, this.y + 23); + } + } + + function loadSettings() { + settings = Object.assign({ + advanced: false, + saveState: true, + debugLog: false, + ppm: 0, + ppm0: 0, + ppm1: 0, + ppm2: 0, + adjustThreshold: DEFAULT_ADJUST_THRESHOLD, + updateInterval: DEFAULT_UPDATE_INTERVAL, + }, require('Storage').readJSON(SETTINGS_FILE, true) || {}); + + if (settings.debugLog) { + if (debugLogFile === null) { + debugLogFile = require('Storage').open(DEBUG_LOG_FILE, 'a'); + } + } else { + debugLogFile = null; + } + + settings.updateInterval = Math.max(settings.updateInterval, MIN_INTERVAL); + } + + function onQuit() { + let now = Date.now(); + // WIP + let ppm = (lastPpm !== null) ? lastPpm : settings.ppm; + let updatedClockError = clockError + (now - lastClockErrorUpdateTime) * ppm / 1000000; + let save = false; + + if (! settings.saveState) { + debug(new Date(now).toISOString() + ' QUIT'); + + } else if (saved === undefined) { + save = true; + debug(new Date(now).toISOString() + ' QUIT & SAVE STATE'); + + } else { + let elapsedSaved = now - saved.time; + let estimatedClockError = saved.clockError + elapsedSaved * saved.ppm / 1000000; + + let clockErrorDelta = updatedClockError - estimatedClockError; + let clockErrorDeltaInPpm = clockErrorDelta / elapsedSaved * 1000000; + let ppmDelta = ppm - saved.ppm; + + let debugA = new Date(now).toISOString() + ' QUIT'; + let debugB = + '\n> ' + updatedClockError.toFixed(2) + ' - ' + estimatedClockError.toFixed(2) + ' = ' + + clockErrorDelta.toFixed(2) + ' (' + + clockErrorDeltaInPpm.toFixed(1) + ' PPM) ; ' + + ppm.toFixed(1) + ' - ' + saved.ppm.toFixed(1) + ' = ' + ppmDelta.toFixed(1); + + if ((Math.abs(clockErrorDelta) >= SAVE_STATE_CLOCK_ERROR_DELTA_THRESHOLD + && Math.abs(clockErrorDeltaInPpm) >= SAVE_STATE_CLOCK_ERROR_DELTA_IN_PPM_THRESHOLD + ) || Math.abs(ppmDelta) >= SAVE_STATE_PPM_DELTA_THRESHOLD + ) + { + save = true; + debug(debugA + ' & SAVE STATE' + debugB); + } else { + debug(debugA + debugB); + } + } + + if (save) { + require('Storage').writeJSON(STATE_FILE, { + counter: (saved === undefined) ? 1 : saved.counter + 1, + time: Math.round(now), + clockError: Math.round(updatedClockError * 1000) / 1000, + ppm: Math.round(ppm * 1000) / 1000, + }); + } + } + + function updateClockError(ppm) { + let now = Date.now(); + let elapsed = now - lastClockErrorUpdateTime; + let drift = elapsed * ppm / 1000000; + clockError += drift; + lastClockErrorUpdateTime = now; + lastPpm = ppm; + + if (Math.abs(clockError) >= settings.adjustThreshold) { + let now = Date.now(); + // Shorter variables are faster to look up and this part is time sensitive. + let e = clockError / 1000; + setTime(getTime() - e); + debug( + new Date(now).toISOString() + ' -> ' + ((now / 1000 - e) % 60).toFixed(3) + + ' SET TIME (' + clockError.toFixed(2) + ')' + ); + clockError = 0; + } + + WIDGETS.adjust.draw(); + } + + // ====================================================================== + // MAIN + + loadSettings(); + + WIDGETS.adjust = { + area: 'tr', + draw: draw, + now: () => { + let now = Date.now(); + // WIP + let ppm = (lastPpm !== null) ? lastPpm : settings.ppm; + let updatedClockError = clockError + (now - lastClockErrorUpdateTime) * ppm / 1000000; + return now - updatedClockError; + }, + width: WIDTH, + }; + + if (settings.saveState) { + saved = require('Storage').readJSON(STATE_FILE, true); + } + + let now = Date.now(); + lastClockErrorUpdateTime = now; + if (saved === undefined) { + clockError = 0; + debug(new Date().toISOString() + ' START'); + } else { + clockError = saved.clockError + (now - saved.time) * saved.ppm / 1000000; + + if (Math.abs(clockError) <= MAX_CLOCK_ERROR_FROM_SAVED_STATE) { + debug( + new Date().toISOString() + ' START & LOAD STATE (' + + clockError.toFixed(2) + ')' + ); + } else { + debug( + new Date().toISOString() + ' START & IGNORE STATE (' + + clockError.toFixed(2) + ')' + ); + clockError = 0; + } + } + + clockCheck(); + + E.on('kill', onQuit); + +})() From 76363b8dc6c860f125c0e2e1c76c51f8de786ccd Mon Sep 17 00:00:00 2001 From: Markus Laire Date: Fri, 25 Feb 2022 18:43:48 +0200 Subject: [PATCH 277/447] widadjust: add icon --- apps/widadjust/README.md | 5 +++++ apps/widadjust/icon.png | Bin 0 -> 1430 bytes apps/widadjust/metadata.json | 1 + 3 files changed, 6 insertions(+) create mode 100644 apps/widadjust/icon.png diff --git a/apps/widadjust/README.md b/apps/widadjust/README.md index 1b51440f5..4f89af54b 100644 --- a/apps/widadjust/README.md +++ b/apps/widadjust/README.md @@ -50,3 +50,8 @@ function adjustedNow() { return WIDGETS.adjust ? WIDGETS.adjust.now() : Date.now(); } ``` + +## Acknowledgment + +Uses [Clock Settings](https://icons8.com/icon/tQvI71EfIWy3/clock-settings) +icon by [Icons8](https://icons8.com). diff --git a/apps/widadjust/icon.png b/apps/widadjust/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f97394618038813954dd332a92bcec1d7eb2a620 GIT binary patch literal 1430 zcmV;H1!?+;P)ZCf45&BTELc~!J-LK5hZlhsKHPXAqokP7!wyL z#ZaRmEQp$Fal^)ilCY4tP*O1_KB5URnh-VwG>Q>HN=&VfY84CwdhrFRTH0Ga7w1f7 z?$`VH9@DP;CzE@>nKNh3nK@_X%o+F}7169^%8>KKXCAN;SO&BKw*j*wG=BhtKtJ#) za0oc(Y5Y{E2Q~qRfe9dV$~ce*hP33h&ZU_^l;{NNrc>|$*b4mW2y-5I9oPumjwlyJ zJ+Me=_5#CB|I@%0&}!SFi)w0n^>f*kNPa9IcX3b;E) zznipFLkG~Oye|XW@aLb@0&ghuF`%3HOMMnN6O%Roda%CIn_!%>s0BVyhQq*;g#G{4 zk_1Z;rw@UBWKbf9o%vJ1ttoh&I>uHcy0e}U_?iM0GkqCDn z&NN1HvvH9{0T6Q<14c=(I|bMsp*zFikX-=~$2L1(EPvRVv_l2>P$0mbJx^96uE(CR zarXIY@Sy;}J=o2pV%V_>d&2sFF9kqit`G@DsuHd7G^kGn)>CD2=OGc|dD6u;rQlP6 zI%G?q0Op#?8i!z|e(whgo(A=aao_+V;|f#hDzHp{Kb}URlH#!bE;kjf0&V(xV%o$> z4kO#*QjNbO%T($zk_MX*Q!Ef;|Bi_U<#!?4Py<{+B2FLJO!4(G1fKB3+c>goJzS%M z{N!nnBTQD{s3+b-%5N4#wD5>he0|-pOn8%X2O7cADkGYa6^)|T18;z95m`r~4Zo4y ziJO7rIzT`08So|X?SD3Kvs30o+Uv0?n@RXW2VRs^YDE(wtjR94q~NiKV!wI21kGJ# z>ggp$uv7-_%pW6OIxz>Vrr0-*Dvxim6JZbl_v`OWm*J0uZbFT2mQwVR$FtUY*!1qemuit}+f4cN#l`vVd zwJ{ZVIic_Xs~kbrA@*#(2Y|y!eIO}`ZeSNhfyfKd%*bIp|Tpt16LJr-6ww1*;Y-(|# zM+F9fTPQxj9@Dnnkv<=3{c@-7Y9!5ai7E=@u&48BvMXT}Fy#_9=h==`&IE!tASP1) zuGhMqh*h|JDk4Da)T~4nbD9Y}hh)5skNt>UiFdT_EHd-P-gjyHEZ`#cuzMGHHqO8S zb|uCU$IiMt)gTWaA@G3KH3F|-A2>#V7qHQBx7L51X22Y>+~$etBw~kY(Sd|5W5~Ok zizeiua7LuQ3mbN{k`nFMF zfMgj?VHL>(Zz8$X#U%s*YYHo{@5((Czk23@r<86dVn(Lz2=J2geQ#O?4C;VKk=cko zbQh2aatPVMMiARJn?P5j&w%o|g0=B8PTRQ%|E%v8lQ0)KWcDDZ?S;sIW_I7lE`1l` z11}<{EWpo5cwz3ne Date: Fri, 25 Feb 2022 18:49:13 +0200 Subject: [PATCH 278/447] fix(widadjust): remove extra semicolon --- apps/widadjust/widget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widadjust/widget.js b/apps/widadjust/widget.js index ce1fee022..138833783 100644 --- a/apps/widadjust/widget.js +++ b/apps/widadjust/widget.js @@ -25,7 +25,7 @@ let settings; let saved; - let lastClockCheckTime = Date.now();; + let lastClockCheckTime = Date.now(); let lastClockErrorUpdateTime; let clockError; From 812c8ba7c1a228ca33eb162b80f7ed85b22acc01 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Fri, 25 Feb 2022 21:54:38 +0100 Subject: [PATCH 279/447] Introduce settings --- apps/smclock/README.md | 18 +++++++ apps/smclock/app.js | 20 ++++--- apps/smclock/metadata.json | 1 + apps/smclock/settings.js | 108 +++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 apps/smclock/settings.js 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. + +![](screenshot.png) + +## 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..9b0ec85d0 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -1,13 +1,17 @@ +const SETTINGSFILE = "smclock.json"; const background = { - width : 176, height : 176, bpp : 3, - transparent : 1, + 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"]; -var level = -1; -function ISO8601_week_no(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 +// dynamic variables +var batLevel = -1; +var batColor = [0,0,0]; + +// 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); @@ -24,8 +28,8 @@ function d02(value) { } function pollBattery() { - level = E.getBattery(); - return level; + batLevel = E.getBattery(); + return batLevel; } function getBatteryColor(level) { @@ -100,7 +104,7 @@ Bangle.on('lcdPower',on=>{ drawInterval = setInterval(draw, 10000); pollBattery(); - draw(); // draw immediately + draw(); } }); diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index febbdd01c..79d996f2c 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -12,6 +12,7 @@ "allow_emulator": true, "storage": [ {"name":"smclock.app.js","url":"app.js"}, + {"name":"smclock.settings.js","url":"settings.js"}, {"name":"smclock.img","url":"app-icon.js","evaluate":true} ] } diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js new file mode 100644 index 000000000..bfc738e19 --- /dev/null +++ b/apps/smclock/settings.js @@ -0,0 +1,108 @@ +// Settings menu for Monogram Watch Face +// Anton Clock settings were used as template + +(function(back) { + var FILE = "smclock.json"; + // Load settings + var settings = Object.assign({ + secondsOnUnlock: false, + }, require('Storage').readJSON(FILE, true) || {}); + + 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); + } + + var mainmenu = { + "": { + "title": "Monogram Clock" + }, + "< Back": () => back(), + "Seconds...": () => E.showMenu(secmenu), + "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), + "Show Weekday": { + value: (settings.weekDay !== undefined ? settings.weekDay : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.weekDay = v; + writeSettings(); + } + }, + "Show CalWeek": { + value: (settings.calWeek !== undefined ? settings.calWeek : false), + format: v => v ? "On" : "Off", + onchange: v => { + settings.calWeek = v; + writeSettings(); + } + }, + "Uppercase": { + value: (settings.upperCase !== undefined ? settings.upperCase : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.upperCase = v; + writeSettings(); + } + }, + "Vector font": { + value: (settings.vectorFont !== undefined ? settings.vectorFont : false), + format: v => v ? "On" : "Off", + onchange: v => { + settings.vectorFont = v; + writeSettings(); + } + }, + }; + + // Submenu + var secmenu = { + "": { + "title": "Show seconds..." + }, + "< Back": () => E.showMenu(mainmenu), + "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), + "With \":\"": { + value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.secondsWithColon = v; + writeSettings(); + } + }, + "Color": { + value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.secondsColoured = v; + writeSettings(); + } + }, + "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) + }; + + // Actually display the menu + E.showMenu(mainmenu); + +}); + +// end of file From b7035afa2f6790636766d2235fa8574007ac3d8c Mon Sep 17 00:00:00 2001 From: Andreas Holley Date: Fri, 25 Feb 2022 21:10:11 +0000 Subject: [PATCH 280/447] Fix Daisy Clock `"type": "clock"` was missing from metadata.json so the app couldn't be set as the clock through settings --- apps/daisy/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index c35bfefa3..1fd95806d 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -4,6 +4,7 @@ "dependencies": {"mylocation":"app"}, "description": "A clock based on the Pastel clock with large ring guage for steps", "icon": "app.png", + "type": "clock", "tags": "clock", "supports" : ["BANGLEJS2"], "screenshots": [{"url":"screenshot_daisy2.jpg"}], From 1af14f3f2c9d7f76c09f38e273e0045eda3366a6 Mon Sep 17 00:00:00 2001 From: copoer Date: Fri, 25 Feb 2022 17:11:08 -0400 Subject: [PATCH 281/447] Updated to use suggested function --- apps/contourclock/ChangeLog | 2 +- apps/contourclock/lib.js | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/contourclock/ChangeLog b/apps/contourclock/ChangeLog index aed7baf64..032edc9b5 100644 --- a/apps/contourclock/ChangeLog +++ b/apps/contourclock/ChangeLog @@ -5,4 +5,4 @@ 0.23: Customizer! Unused fonts no longer take up precious memory. 0.24: Added previews to the customizer. 0.25: Fixed a bug that would let widgets change the color of the clock. -0.26: Time now works with locale formatting +0.26: Time formatted to locale diff --git a/apps/contourclock/lib.js b/apps/contourclock/lib.js index aa83fca26..c4f927953 100644 --- a/apps/contourclock/lib.js +++ b/apps/contourclock/lib.js @@ -1,3 +1,11 @@ +var is12; +function getHours(d) { + var h = d.getHours(); + if (is12===undefined) is12 = (require('Storage').readJSON('setting.json',1)||{})["12hour"]; + if (!is12) return h; + return (h%12==0) ? 12 : h%12; +} + exports.drawClock = function(fontIndex) { var digits = []; fontFile=require("Storage").read("contourclock-"+Math.abs(parseInt(fontIndex+0.5))+".json"); @@ -13,15 +21,13 @@ exports.drawClock = function(fontIndex) { if (n!=10) return (false); //font file seems to be invalid var x=0; var y = g.getHeight()/2-digits[0].height/2; - var date = require('locale').time(new Date(),1); - var hours = date.split(":")[0]; - var minutes = date.split(":")[1]; + var date = new Date(); g.clearRect(0,38,g.getWidth()-1,138); - d1=parseInt(hours/10); - d2=parseInt(hours%10); + d1=parseInt(getHours(date)/10); + d2=parseInt(getHours(date)%10); d3=10; - d4=parseInt(minutes/10); - d5=parseInt(minutes%10); + d4=parseInt(date.getMinutes()/10); + d5=parseInt(date.getMinutes()%10); w1=digits[d1].width; w2=digits[d2].width; w3=digits[d3].width; From b31bc88351d69d2b5ceadfd6d89f103eb983be06 Mon Sep 17 00:00:00 2001 From: Andreas Holley Date: Fri, 25 Feb 2022 21:11:59 +0000 Subject: [PATCH 282/447] Bump version --- apps/daisy/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index 1fd95806d..f4a9fcbbe 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.02", + "version":"0.03", "dependencies": {"mylocation":"app"}, "description": "A clock based on the Pastel clock with large ring guage for steps", "icon": "app.png", From faf7cb8d6c815ab8ac2a2e0821429ba2fff3fcc2 Mon Sep 17 00:00:00 2001 From: Andreas Holley Date: Fri, 25 Feb 2022 21:13:17 +0000 Subject: [PATCH 283/447] Update changelog --- apps/daisy/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index 4fdf333e4..254124d4e 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -1,2 +1,3 @@ 0.01: first release 0.02: added settings menu to change color +0.03: fix metadata.json to allow setting as clock From fc740bbb1ce4f3d6011ffab1e5b665d547623207 Mon Sep 17 00:00:00 2001 From: copoer Date: Fri, 25 Feb 2022 17:14:20 -0400 Subject: [PATCH 284/447] Added version --- apps/contourclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/contourclock/metadata.json b/apps/contourclock/metadata.json index 54d799127..ec29c390b 100644 --- a/apps/contourclock/metadata.json +++ b/apps/contourclock/metadata.json @@ -1,7 +1,7 @@ { "id": "contourclock", "name": "Contour Clock", "shortName" : "Contour Clock", - "version":"0.25", + "version":"0.26", "icon": "app.png", "description": "A Minimalist clockface with large Digits. Now with more fonts!", "screenshots" : [{"url":"cc-screenshot-1.png"},{"url":"cc-screenshot-2.png"}], From f2f2a271ec6b29cb7748fb4f02a083cb78832681 Mon Sep 17 00:00:00 2001 From: tjsilver Date: Sat, 26 Feb 2022 14:56:05 +0000 Subject: [PATCH 285/447] fix typo in Time and Life shortName --- apps/timeandlife/metadata.json | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/timeandlife/metadata.json b/apps/timeandlife/metadata.json index 86800f16f..acd6b0086 100644 --- a/apps/timeandlife/metadata.json +++ b/apps/timeandlife/metadata.json @@ -1,18 +1,26 @@ { "id": "timeandlife", "name": "Time and Life", - "shortName":"Time and Lfie", + "shortName": "Time and Life", "icon": "app.png", - "version":"0.01", + "version": "0.01", "description": "A simple watchface which displays the time when the screen is tapped and decay according to the rules of Conway's game of life.", "type": "clock", "tags": "clock", - "supports": ["BANGLEJS2"], - "allow_emulator":true, + "supports": [ + "BANGLEJS2" + ], + "allow_emulator": true, "readme": "README.md", "storage": [ - {"name":"timeandlife.app.js","url":"app.js"}, - {"name":"timeandlife.img","url":"app-icon.js","evaluate":true} + { + "name": "timeandlife.app.js", + "url": "app.js" + }, + { + "name": "timeandlife.img", + "url": "app-icon.js", + "evaluate": true + } ] -} - +} \ No newline at end of file From d09e3c2ce13e69548cfc667fd5baba0a50a263fc Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sat, 26 Feb 2022 19:45:35 +0100 Subject: [PATCH 286/447] Use Bangle.appRect --- apps/terminalclock/app.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index fb7bd16cc..012aab5d5 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -1,6 +1,5 @@ -var locale = require("locale"); +​var locale = require("locale"); var fontColor = g.theme.dark ? "#0f0" : "#000"; -var startY = 24; var paddingY = 2; var font6x8At4Size = 32; var font6x8At2Size = 18; @@ -15,25 +14,25 @@ function setFontSize(pos){ } function clearField(pos){ - var yStartPos = startY + + var yStartPos = Bangle.appRect.y + paddingY * (pos - 1) + font6x8At4Size * Math.min(1, pos-1) + font6x8At2Size * Math.max(0, pos-2); - var yEndPos = startY + + var yEndPos = Bangle.appRect.y + paddingY * (pos - 1) + font6x8At4Size * Math.min(1, pos) + font6x8At2Size * Math.max(0, pos-1); - g.clearRect(0, yStartPos, 240, yEndPos); + g.clearRect(Bangle.appRect.x, yStartPos, Bangle.appRect.x2, yEndPos); } function clearWatchIfNeeded(now){ if(now.getMinutes() % 10 == 0) - g.clearRect(0, startY, 240, 240); + g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); } function drawLine(line, pos){ setFontSize(pos); - var yPos = startY + + var yPos = Bangle.appRect.y + paddingY * (pos - 1) + font6x8At4Size * Math.min(1, pos-1) + font6x8At2Size * Math.max(0, pos-2); @@ -127,12 +126,12 @@ var settings = Object.assign({ showActivity: true, showStepCount: true, }, require('Storage').readJSON("terminalclock.json", true) || {}); -// draw immediately at first -draw(); // Show launcher when middle button pressed Bangle.setUI("clock"); // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); +// draw immediately at first +draw(); var secondInterval = setInterval(draw, 10000); From 31277cd20a802bab3cbb448ba3e27ca559a36007 Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sat, 26 Feb 2022 19:51:43 +0100 Subject: [PATCH 287/447] Replace 'Activity' with 'Motion' to be able to display motion true values --- apps/terminalclock/app.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index 012aab5d5..ab83a696f 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -1,4 +1,4 @@ -​var locale = require("locale"); +var locale = require("locale"); var fontColor = g.theme.dark ? "#0f0" : "#000"; var paddingY = 2; var font6x8At4Size = 32; @@ -75,11 +75,10 @@ function drawHRM(pos){ function drawActivity(pos){ clearField(pos); var health = Bangle.getHealthStatus('last'); - var steps_formated = ">Activity: " + parseInt(health.movement/10); + var steps_formated = ">Motion: " + parseInt(health.movement); drawLine(steps_formated, pos); } - function draw(){ var curPos = 1; g.reset(); @@ -108,7 +107,6 @@ function draw(){ drawInput(now, curPos); } - Bangle.on('HRM',function(hrmInfo) { if(hrmInfo.confidence >= settings.HRMinConfidence) heartRate = hrmInfo.bpm; From 35cad73a9c742b3093590053a12f8ef95d1e0c2a Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Sat, 26 Feb 2022 20:01:53 +0100 Subject: [PATCH 288/447] Update terminalclock version --- apps/terminalclock/ChangeLog | 1 + apps/terminalclock/README.md | 2 +- apps/terminalclock/screenshot1.png | Bin 2938 -> 2878 bytes apps/terminalclock/screenshot2.png | Bin 3072 -> 2935 bytes 4 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/terminalclock/ChangeLog b/apps/terminalclock/ChangeLog index 5560f00bc..6515ab627 100644 --- a/apps/terminalclock/ChangeLog +++ b/apps/terminalclock/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Rename "Activity" in "Motion" and display the true values for it diff --git a/apps/terminalclock/README.md b/apps/terminalclock/README.md index 2a2bc1204..5a54583d2 100644 --- a/apps/terminalclock/README.md +++ b/apps/terminalclock/README.md @@ -5,5 +5,5 @@ It can display : - time - date - hrm -- activity +- motion - steps diff --git a/apps/terminalclock/screenshot1.png b/apps/terminalclock/screenshot1.png index a0d41f4957fa8bd96572d2e126ed2aba38d68250..c0f472102e693991580127d67665cf9774a69440 100644 GIT binary patch literal 2878 zcmd5;_gjxZnP8pXdGw_lI-lIWzM-bLPxD@0nZ|EJj*FLjnK* z>66Y5Zjhw>v&2!*-az{+01~iRH;g?{&(xX$0Evy04#(XS0_KZYk7oBtWf3QK%FlEX z3dXWbO4Lu{oq2vLy1A@^j7Hi-U|?Wc$JT%Zfy|)6#+zfXLJSPiW+t8{s#`;BZg1ON z_}CdVuX;p!>4}fS8#PX6U)*jH(nx{8m&xBq#+FPkihCy3)f_9fL%{VBe%vOkfqxWA5t%SZbT$LSU&HXIbjcJ*2%1WsEqHqeKk3V=KdXcfxN`ie#79 z^PU`n=~VKP=DZKmON^MmZ=RH&4LEXn5k>GZfE4H70~RM1rb8NTU+4g&xyvWt5R89b z>-*4=yJ|Aps)hUcm)P#)Ea364TNMXpYxbq#EIGo)OB7uhyU z$9>6w79Lb{eQZ@R>Dp{cP4?|ym`s#fZo=w@2jF=rj+I#8f};Ce5k4k^uo44WChi~} ztW~CV)<~#vYGN$CsBp;a`ak9OSI~nAz)Z{;Yv@kjZ6Plyw^`$-@LM! zneCmDaW1(XwfL5`t5QlT>Rhj+Uq0`+GYh?Ox{i>(P+|zk{n}q|sPvO`8+MFgfgOY8 zG3(g2%iihZmpiUM^pX9`ws!wYsoD<<3heVa=p@9rg>n~<**-S>7|Wr<#=ooBZzEmO z-RH&NHLb@OsEzd>kNMfIH3yqbp#uV_7v=VL7+fwtfj*I+vsEq=LkkEOu{ZamNW5*4 z@oTqJ)^EnU8<}XYK4F92hji3A)9@tK1svM=k*egyqdU{> z<~{|F3c@FnGly#*@B^u#vp<80DU#(GrWWVimq5VqY{jM~Cw8hbNg}Sz#-75U#J8g- zMCm(~bC&fB@Ep^|!$^+ZEf%J=?5}@3P&F#Vr;(@Lrsts^&ksGV|L?yWKO=yp_d>`T=(7@?X6h$K0YjcZKYZ})Y9m2TC*NmgiC&b zMbRsj4knnCiR&Z2I=uptpYbkR%B<+$`x3mm1k$6simo-K4iQ04RPU!;;0W=$BomZxiKVb6VRns0SV zx8%?rfHPFMp0W``k4;_t4%P0vf+fQls;_h0d@>!5N}zYi7`ed^R&M@6?RvX@6OGpU zGbwo$9SpU@Zzq7cTEDxpNpG(5lC=!*;K1Hr8FEE9sql`g*W&R%ubW$F<5ZtNh-g2^Hi@imdz%c;ZCr21# z5%MzlD}oc~Mxx{qVcyumJCAG)OjmMv$weNJ2a!XT4goI$&$G1{)w}uh@QHebeox$S zk;e|w^^4F+fHM1-j^j*-KV;vZywv>sQuB-7roHh65CzIzL3a-JQjPrTPg{TDVh z6iS%Mj$N?b5t?1ekNl&K(F8q3$SH1@8dA!r^7iHX(3K2*HTL)DQ&bt#Nc+fcR$^Yp zixwOVL8{%7DZ!QTG^FFqjxy^j`eZdDJuN+|#8fxtT6<%b0hb<`v~<&JFcn{dr-wmGy;4ov?4V(>;zsWKPn+JZ28k8A)4v zA3NcW))mgCslSojO55`#UEYq2 zCtF`H$hy{J%xLJlpcCL)4CiVwY5{O%dKbv6;gYwf^|JW3k2^ICfqjnQ`R=mms{jhFKjJuGQJ-7rb5`O~yAb)q&M`?;U=R z%a`{N2~@^3A!+0B(}G87uRD0Sm_0BEkLpONC@1TIc7ND{?tGhN5d)jeGJ7Z9+<= zp$EK4odbq_s;agl3nImgUhZbsQx^-t0M?7uVb3RT+v;|Xr7Ed4D~@9SOx4SnOI~}I zDm?OAfnqz4B*{8Rhjlm&1C@ucqKN||=>v?y*n+{98mI?N%1RRp#UifiUc; zFfpP*nSbTCKWc(}(-k4kZ~QOkx517fe4#&`cDVG8DdPhE5^{W19yklRH2>&On91zqNZN}D-Kcz6I<^tBAdrVXY#PhkmRDrdo21}dSk z$-MXkOa@O3P<&nuF%avu*&!?}urk_WB-|Bh)QYRoK1J}zzIWHSWx9OZ-!4v~c@f_^2M5JPx-YJRo{H$Zl@<|1j?W?;^!dr?pZ(LIW{y M(h=)WZ;#LT50cG;Bme*a literal 2938 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 diff --git a/apps/terminalclock/screenshot2.png b/apps/terminalclock/screenshot2.png index 21d7aadbf31906cf0316459a9b21bc3ae32e0bc8..8bd552a730e49cc84db62211d36b351a26ee6b60 100644 GIT binary patch literal 2935 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 literal 3072 zcmd5;c{JNu8~#NkC8g9(5xSsK%e311ip1KeE)pdvT4JmfYptymob%rMJoi543R)Vb1_J;< z`hvZ!lPJFWXG%atE3NUHhbVv|oY2<5%a7`F0IDi|Lr{w@tzR@`g#Hl28fFjRX%caO?+yaDno7`yh}9BkaAt|1em(4_BCAA zQ*!c>%e7f5P;mAjI){JG;FND?gH+hwv5p__UgMIb!;(x@WgNv#efN8jR9km`+*V`q zizRks@uT2SS@NdfX8g-E4uBjzQ^y~4J5x+!$(B?0evjRFvh4yOTMWIK$oL*yt4j6T z`!=Mf|1GBit-iA_(g!C7OI^OL_Ko4cGz$MF(izJ8cA#F)>w)Uif+)CuLH2ES3&FD@ z(+Ul#!aM6_ag`2Fd6#hu0@{WG-sl9kghSZx<$lD5R7}g_`A*X94!qL6V$-8jW19$2 zNiExTdT%`9&}7g^aA>8N;PRL~gNL{Q0+$$8OJ_MVfo$i|x1SV^nRB_^NqdOY@_*oD z8&VIom}O*eo)7046}2zKa;VKL^O8AVQd`nxzToOczFcHp>q4w_7`;+qs$M?z{UM%A zdkVLH>NL|n{I!LdRo7lXlAb2JOk;@$7(#lLq(+QJ>)~^HUf86OJHDONjshOs0Q0Q0 z`5s31h4?ZjhHm+0&-Z)222IVgAt_>Q*JKhi$BSyL1&mNa*eQRh$ zDdw%@Cd2e{=J@QswG&qQa8bJL_Za@I%`DZ{SZ=Q8ERN*8T zNzUuDTLG;B@pOxGDBo7lA|^RsoW5>H(k>R|G`9PL&N89H?h^E$If}}Rsw_O8y4Jl2 z&s5ILZt(B_(d%&)a$f$y6|KNFb$F&OzsyX{F*IQyo-81*eaSw{OfAx@7)iq@I4Nk+ znJiJ7wJYLsiE>XakhI-)7TskK^%FDoI&|wsWsl3`0*Q6x0b#y219ojGU6n(mBWv0y z6M>0;q%{Rt%NnyJ?I1i0)M=!mUL|~$wqvu2F)!q?m7d1jCCjJ7xN(Vr@%k8h)HlzK zw1tY;lcUmMY09cBNQKxvk|ncRkYl0X=*Q1RQTt2EgU3ZrK7MI;A~71ewR!yQ4{_<` zH*0bH5o}u1D0NcO11Ew<*#BBKf*49JNAv1GMO_iE;>^^$ng4Y*{NcBCmAGTch1;|< zPdHy6f^fP_k5tcRKi93%`ie_+SIJyFzku*UNrthNE$CG$vJd{+rCof@rz*zGOxOZS znW_DV=Y7c?`fOobG%%CH!+-C8d&ig0kXT93(h^n>O+49Ikq444cBWd4Vh#V-Ls~VQ1EVEW{?xD>FHrdi^&o}sjLsD0g>ura3*y~-$ z^nID3qGZ;~P;+C9x6ImnuQFGG{FaHKGk#(ARmWoahG%yC zGEQ`Ksdw*ip{7#calh3VMEaoAP~4sBO^zT)Ak!Go3Vr)3kGeNv&H|{`XtCJ$!<_Z&24xc9sHC@%za*Yl^C?Cs<~nOMsgm}B+}q2U**}E z7S>SAe0vMGElvr(zy#pCc@hREz^xzCRaXscYsKnO*yGdIiYRvv&J!-mY(jVB6w|iB zMT;Y_l~{DblFogoNTp;uv*EmCthwt5ZjZ88|24i&100{5plHt!K6=+vWCmHDdGS~) zuW7*|Z15W~dLZ6!sXMM;=&&ihY}FvO93}f4I4|ik$`O$DHPeaC>O=4R6Dy&y1z@l_ z-2SwfCs~z{U-)e25CPn(kP~QpoR;fSwHOMiQ!r+_I&eQKKqxk2d0h)^m@G_%V0|>k z6)*C-kPvm%3KB@i_EtfZVv_=MKI50mn}gv&+-v+G)F6$2V?jovL2Te$79^F?zv;c# z>QOuI|COx{Y)n>wgRN$N|a zme1NGMklLG3SmBm#`8*dqq+pEcNs&?#_VvtvVfKy+l(EXseD+BxH|Dk!uy()1^ywz z)5GPd717|`tbiXj*MsfKZC@h}jNIISYjh&5*f5mZq`jSY$J1TA(L$BP)4l@siDCe} zd%MQM;YCe^-?2yK+uP*X5r5b*s3hTND>rKgjkt-s=QGv2h&M}pycP(dK=K+Bsz68q zb=Llxk^*?_xzQ)ocS%-JCwa^1B@1J@a5~S;3zHOmQ68e%j;*I<^@#ln$xo0A+8h4f z-&>mvLU!r6<>?Yuo$5?aaB;W{!Waz# zo1h-@4>3VANp>w!Pk$MFlHkU(#}oSv9GV-rm_xSfhy>Zfu2 zZf&3LtdB~bDSNoTOJsfS>+NFRB*gnV#atf#Ev$B0-Ua6Dim@hdUKGyn9_;MW4D_Eu zL|HeNhiVKUB2AVaZ)$(BW{aO@cEYqQu`M7&1p>qye%trhd4%$|$l&rqPk91WHzhZ{dqeM>}o_8e*DCf=`-0@(4g!77rUxLF+xT%z-9PI~%RTb@3> z%cE8!)5g&>az7S1=e9q?3_%-Q~OHpBhG19;u;E$Fp_asG8_0r^RG)n${Vtee9+z9{ft@ghNg< zVOYGbS!L3iu;qCV|&*iekW3CeS!HgU!$* zkd!Z^{_(%}VLe2;9X(0~ENUUxwjm=CR{7RpQTe%nd$Kn~>Q#3WU5u^$k>+PqI_17E zloVPz!FS9Oi+%Jie@kF_J@^;sR-kG`YbXo@w5%2txrn5T>emsDg>9*2=609jT$li@ zNVU`M_$0nN@6sZ@MhqIu=`}TU0L{yyU2o|kjIBgh$ttp?SH$@5n>R1Yi+IS}Huji{ jM6c{|gUSB|JP8lDilHZiwbMjjdf Date: Sun, 27 Feb 2022 12:15:35 +0100 Subject: [PATCH 289/447] Better usage of available space --- apps/circlesclock/app.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index d5df2fe44..a6aa1a8b1 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -52,7 +52,7 @@ const colorGreen = '#008000'; const colorBlue = '#0000ff'; const colorYellow = '#ffff00'; const widgetOffset = showWidgets ? 24 : 0; -const dowOffset = circleCount == 3 ? 22 : 24; // dow offset relative to date +const dowOffset = circleCount == 3 ? 20 : 22; // dow offset relative to date const h = g.getHeight() - widgetOffset; const w = g.getWidth(); const hOffset = (circleCount == 3 ? 34 : 30) - widgetOffset; @@ -88,21 +88,24 @@ const circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:12"; const iconOffset = circleCount == 3 ? 6 : 8; const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; +function hideWidgets() { + /* + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ + if (WIDGETS && typeof WIDGETS === "object") { + for (let wd of WIDGETS) { + wd.draw = () => {}; + wd.area = ""; + } + } +} function draw() { g.clear(true); if (!showWidgets) { - /* - * we are not drawing the widgets as we are taking over the whole screen - * so we will blank out the draw() functions of each widget and change the - * area to the top bar doesn't get cleared. - */ - if (WIDGETS && typeof WIDGETS === "object") { - for (let wd of WIDGETS) { - wd.draw = () => {}; - wd.area = ""; - } - } + hideWidgets(); } else { Bangle.drawWidgets(); } @@ -114,7 +117,7 @@ function draw() { g.setFontRobotoRegular50NumericOnly(); g.setFontAlign(0, -1); g.setColor(colorFg); - g.drawString(locale.time(new Date(), 1), w / 2, h1 + 8); + g.drawString(locale.time(new Date(), 1), w / 2, h1 + 6); now = Math.round(new Date().getTime() / 1000); // date & dow @@ -840,7 +843,6 @@ if (isCircleEnabled("hr")) { enableHRMSensor(); } - Bangle.setUI("clock"); Bangle.loadWidgets(); From 73aac6feabb7fe06c0f0447370588c8b9f7473ba Mon Sep 17 00:00:00 2001 From: copoer Date: Sun, 27 Feb 2022 09:36:36 -0400 Subject: [PATCH 290/447] Updated Edisons ball app to work on Bangle JS 2 --- apps/edisonsball/ChangeLog | 2 ++ apps/edisonsball/README.md | 2 +- apps/edisonsball/app.js | 21 +++++++++++++++++---- apps/edisonsball/metadata.json | 6 +++--- 4 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 apps/edisonsball/ChangeLog diff --git a/apps/edisonsball/ChangeLog b/apps/edisonsball/ChangeLog new file mode 100644 index 000000000..b71b8bb0d --- /dev/null +++ b/apps/edisonsball/ChangeLog @@ -0,0 +1,2 @@ +0.01: Initial version +0.02: Added BangleJS Two diff --git a/apps/edisonsball/README.md b/apps/edisonsball/README.md index b8e9ec106..a3b013b6d 100644 --- a/apps/edisonsball/README.md +++ b/apps/edisonsball/README.md @@ -1,4 +1,4 @@ -The application is based on a technique that Thomas Edison used to prevent falling asleep using a steel ball. Essentially the app starts with a display that shows the current HR value that the watch alarm is set to and this can be adjusted with buttons 1 and 3. This HR settng should be the approximate value you want the alarm to trigger and so you should ideally know both what your HR is currently and what your heartrate normally is during sleep. For your current HR according to the watch, you can simply use the HR monitor available in the Espruino app loader, and then from that you can choose a lower value as the target for the alarm and adjust as required. +The application is based on a technique that Thomas Edison used to prevent falling asleep using a steel ball. Essentially the app starts with a display that shows the current HR value that the watch alarm is set to and this can be adjusted with buttons 1 and 3 (Mapped to top touch and bottom touch on Bangle 2). This HR settng should be the approximate value you want the alarm to trigger and so you should ideally know both what your HR is currently and what your heartrate normally is during sleep. For your current HR according to the watch, you can simply use the HR monitor available in the Espruino app loader, and then from that you can choose a lower value as the target for the alarm and adjust as required. When you press the middle button on the side, the HR monitor starts, the alarm will trigger when your heart rate average drops to the limit you’ve set and has a certain level of steadiness that is determined by a assessing the variance over several readings - the sensitivity of this variance can be adjusted in a variable in the app's code under 'ADVANCED SETTINGS' if needed. The code also has a basic logging function which shows, in a CSV file, when you started the HR tracker and when the alarm was triggered. diff --git a/apps/edisonsball/app.js b/apps/edisonsball/app.js index 557155c9a..ab5def2f6 100644 --- a/apps/edisonsball/app.js +++ b/apps/edisonsball/app.js @@ -130,10 +130,23 @@ function checkHR() { } update_target_HR(); - -setWatch(btn1Pressed, BTN1, {repeat:true}); -setWatch(btn2Pressed, BTN2, {repeat:true}); -setWatch(btn3Pressed, BTN3, {repeat:true}); +if (process.env.HWVERSION==1) { + // Bangle 1 + setWatch(btn1Pressed, BTN1, {repeat:true}); + setWatch(btn2Pressed, BTN2, {repeat:true}); + setWatch(btn3Pressed, BTN3, {repeat:true}); +} else { + setWatch(btn2Pressed, BTN2, { repeat: true }); + // Bangle 2 + Bangle.on('touch', function(zone, e) { + if (e.y < g.getHeight() / 2) { + btn1Pressed(); + } + if (e.y > g.getHeight() / 2) { + btn3Pressed(); + } + }); +} Bangle.on('HRM',function(hrm) { diff --git a/apps/edisonsball/metadata.json b/apps/edisonsball/metadata.json index f429c7b67..dfeb4451e 100644 --- a/apps/edisonsball/metadata.json +++ b/apps/edisonsball/metadata.json @@ -2,11 +2,11 @@ "id": "edisonsball", "name": "Edison's Ball", "shortName": "Edison's Ball", - "version": "0.01", + "version": "0.02", "description": "Hypnagogia/Micro-Sleep alarm for experimental use in exploring sleep transition and combating drowsiness", "icon": "app-icon.png", - "tags": "", - "supports": ["BANGLEJS"], + "tags": "sleep,hyponagogia,quick,nap", + "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", "storage": [ {"name":"edisonsball.app.js","url":"app.js"}, From 505872f0b84c86a4e45051a5625c11d7cbd6745c Mon Sep 17 00:00:00 2001 From: copoer Date: Sun, 27 Feb 2022 10:10:28 -0400 Subject: [PATCH 291/447] Fixed graphics --- apps/edisonsball/app.js | 66 +++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/apps/edisonsball/app.js b/apps/edisonsball/app.js index ab5def2f6..c0a4d27c6 100644 --- a/apps/edisonsball/app.js +++ b/apps/edisonsball/app.js @@ -3,6 +3,8 @@ var lower_limit_BPM = 49; var upper_limit_BPM = 140; var deviation_threshold = 3; +var ISBANGLEJS1 = process.env.HWVERSION==1; + var target_heartrate = 70; var heartrate_set; @@ -33,25 +35,39 @@ function btn2Pressed() { } function update_target_HR(){ - g.clear(); - g.setColor("#00ff7f"); - g.setFont("6x8", 4); - g.setFontAlign(0,0); // center font + if (process.env.HWVERSION==1) { + g.setColor("#00ff7f"); + g.setFont("6x8", 4); + g.setFontAlign(0,0); // center font - g.drawString(target_heartrate, 120,120); - g.setFont("6x8", 2); - g.setFontAlign(-1,-1); - g.drawString("-", 220, 200); - g.drawString("+", 220, 40); - g.drawString("GO", 210, 120); - - g.setColor("#ffffff"); - g.setFontAlign(0,0); // center font - g.drawString("target HR", 120,90); - - g.setFont("6x8", 1); - g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 120,170); + g.drawString(target_heartrate, 120,120); + g.setFont("6x8", 2); + g.setFontAlign(-1,-1); + g.drawString("-", 220, 200); + g.drawString("+", 220, 40); + g.drawString("GO", 210, 120); + + g.setColor("#ffffff"); + g.setFontAlign(0,0); // center font + g.drawString("target HR", 120,90); + + g.setFont("6x8", 1); + g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 120,170); + } else { + g.setFont("6x8", 4); + g.setFontAlign(0,0); // center font + g.drawString(target_heartrate, 88,88); + g.setFont("6x8", 2); + g.setFontAlign(-1,-1); + g.drawString("-", 160, 160); + g.drawString("+", 160, 10); + g.drawString("GO", 150, 88); + g.setFontAlign(0,0); // center font + g.drawString("target HR", 88,120); + g.setFont("6x8", 1); + g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 88,150); + } g.setFont("6x8",3); g.flip(); @@ -105,8 +121,13 @@ function checkHR() { average_HR = average(HR_samples).toFixed(0); stdev_HR = getStandardDeviation (HR_samples).toFixed(1); - g.drawString("HR: " + average_HR, 120,100); - g.drawString("STDEV: " + stdev_HR, 120,160); + if (ISBANGLEJS1) { + g.drawString("HR: " + average_HR, 120,100); + g.drawString("STDEV: " + stdev_HR, 120,160); + } else { + g.drawString("HR: " + average_HR, 60,70); + g.drawString("STDEV: " + stdev_HR, 80,70); + } HR_samples = []; if(average_HR < target_heartrate && stdev_HR < deviation_threshold){ @@ -130,14 +151,15 @@ function checkHR() { } update_target_HR(); -if (process.env.HWVERSION==1) { + +if (ISBANGLEJS1) { // Bangle 1 setWatch(btn1Pressed, BTN1, {repeat:true}); setWatch(btn2Pressed, BTN2, {repeat:true}); setWatch(btn3Pressed, BTN3, {repeat:true}); } else { - setWatch(btn2Pressed, BTN2, { repeat: true }); // Bangle 2 + setWatch(btn2Pressed, BTN1, { repeat: true }); Bangle.on('touch', function(zone, e) { if (e.y < g.getHeight() / 2) { btn1Pressed(); @@ -148,8 +170,8 @@ if (process.env.HWVERSION==1) { }); } -Bangle.on('HRM',function(hrm) { +Bangle.on('HRM',function(hrm) { if(trigger_count < 2){ if (firstBPM) firstBPM=false; // ignore the first one as it's usually rubbish From 866cfb8c6bbb3aa82e919108e724f33f5cd7ed61 Mon Sep 17 00:00:00 2001 From: copoer Date: Sun, 27 Feb 2022 10:13:07 -0400 Subject: [PATCH 292/447] Fixed graphics --- apps/edisonsball/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/edisonsball/app.js b/apps/edisonsball/app.js index c0a4d27c6..a600d8fc8 100644 --- a/apps/edisonsball/app.js +++ b/apps/edisonsball/app.js @@ -64,7 +64,7 @@ function update_target_HR(){ g.drawString("+", 160, 10); g.drawString("GO", 150, 88); g.setFontAlign(0,0); // center font - g.drawString("target HR", 88,120); + g.drawString("target HR", 88,70); g.setFont("6x8", 1); g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 88,150); } From 21dc7a074db98c9b8bfabde67873316ba863771a Mon Sep 17 00:00:00 2001 From: copoer Date: Sun, 27 Feb 2022 10:19:07 -0400 Subject: [PATCH 293/447] Fixed graphics --- apps/edisonsball/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/edisonsball/app.js b/apps/edisonsball/app.js index a600d8fc8..2aa317829 100644 --- a/apps/edisonsball/app.js +++ b/apps/edisonsball/app.js @@ -64,7 +64,7 @@ function update_target_HR(){ g.drawString("+", 160, 10); g.drawString("GO", 150, 88); g.setFontAlign(0,0); // center font - g.drawString("target HR", 88,70); + g.drawString("target HR", 88,65); g.setFont("6x8", 1); g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 88,150); } @@ -125,8 +125,8 @@ function checkHR() { g.drawString("HR: " + average_HR, 120,100); g.drawString("STDEV: " + stdev_HR, 120,160); } else { - g.drawString("HR: " + average_HR, 60,70); - g.drawString("STDEV: " + stdev_HR, 80,70); + g.drawString("HR: " + average_HR, 88,60); + g.drawString("STDEV: " + stdev_HR, 88,90); } HR_samples = []; if(average_HR < target_heartrate && stdev_HR < deviation_threshold){ From 8513f34f2ac81550b4c1dbd8211fd986fc900202 Mon Sep 17 00:00:00 2001 From: Marco H Date: Sun, 27 Feb 2022 18:23:47 +0100 Subject: [PATCH 294/447] Update changelog for v0.11 --- apps/circlesclock/ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 7165f8521..46eddd32b 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -20,3 +20,6 @@ Color depending on value (green -> red, red -> green) option Good HRM value will not be overwritten so fast anymore 0.10: Use roboto font for time, date and day of week and center align them +0.11: New color option: foreground color + Improve performance, reduce memory usage + Small optical adjustments From 4cff0792f604e19b710605d9cc4d3507c42eeee2 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 16 Feb 2022 22:44:36 +0100 Subject: [PATCH 295/447] Buzz on every measurement and longer if all are done --- apps/bthrv/ChangeLog | 1 + apps/bthrv/app.js | 6 +++++- apps/bthrv/metadata.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/bthrv/ChangeLog b/apps/bthrv/ChangeLog index e144fd8f9..eefadac78 100644 --- a/apps/bthrv/ChangeLog +++ b/apps/bthrv/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Write available data on reset or kill +0.03: Buzz short on every finished measurement and longer if all are done diff --git a/apps/bthrv/app.js b/apps/bthrv/app.js index 067c84f56..fbd0e2d05 100644 --- a/apps/bthrv/app.js +++ b/apps/bthrv/app.js @@ -75,7 +75,6 @@ function write(){ data += "," + rrMax + "," + rrMin + ","+rrNumberOfValues; data += "\n"; file.write(data); - Bangle.buzz(500); } function onBtHrm(e) { @@ -87,6 +86,11 @@ function onBtHrm(e) { if (currentSlot <= hrvSlots.length && (Date.now() - startingTime) > (hrvSlots[currentSlot] * 1000) && !hrvValues[hrvSlots[currentSlot]]){ hrvValues[hrvSlots[currentSlot]] = hrv; currentSlot++; + if (currentSlot == hrvSlots.length){ + Bangle.buzz(500) + } else { + Bangle.buzz(50); + } } } diff --git a/apps/bthrv/metadata.json b/apps/bthrv/metadata.json index 183008034..7c57be682 100644 --- a/apps/bthrv/metadata.json +++ b/apps/bthrv/metadata.json @@ -2,7 +2,7 @@ "id": "bthrv", "name": "Bluetooth Heart Rate variance calculator", "shortName": "BT HRV", - "version": "0.02", + "version": "0.03", "description": "Calculates HRV from a a BT HRM with interval data", "icon": "app.png", "type": "app", From ac29a4f5a54aad523f8cf68047103dd46be1f17a Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Sun, 27 Feb 2022 23:22:32 +0100 Subject: [PATCH 296/447] Fix battery color --- apps/smclock/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 9b0ec85d0..b900e4d9e 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -29,13 +29,13 @@ function d02(value) { function pollBattery() { batLevel = E.getBattery(); - return batLevel; } function getBatteryColor(level) { var color; if (level < 0) { - level = pollBattery(); + pollBattery(); + level = batLevel; } if(level>80) { color = [0,0,1]; @@ -54,7 +54,7 @@ function getBatteryColor(level) { function draw() { g.drawImage(background); - const color = getBatteryColor(); + const color = getBatteryColor(batLevel); const bat = d02(E.getBattery()) + "%"; const d = new Date(); const day = d.getDate(); From 48d8fae37c04b19dfae172316b4a721e7c881463 Mon Sep 17 00:00:00 2001 From: DC959 Date: Mon, 28 Feb 2022 22:07:33 +1300 Subject: [PATCH 297/447] Fix date alignment and change font to closer match Rolex --- apps/rolex/ChangeLog | 3 ++- apps/rolex/README.md | 4 +++- apps/rolex/app.js | 17 +++++++++++------ apps/rolex/app.js:Zone.Identifier | 3 +++ apps/rolex/screenshot1.png | Bin 0 -> 3905 bytes apps/rolex/screenshot1.png:Zone.Identifier | 3 +++ 6 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 apps/rolex/app.js:Zone.Identifier create mode 100644 apps/rolex/screenshot1.png create mode 100644 apps/rolex/screenshot1.png:Zone.Identifier diff --git a/apps/rolex/ChangeLog b/apps/rolex/ChangeLog index 3bfed4a4e..a1e2cee0a 100644 --- a/apps/rolex/ChangeLog +++ b/apps/rolex/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial Release 0.02: Minor tweaks for light theme -0.03: Made images 2 bit and fixed theme honoring \ No newline at end of file +0.03: Made images 2 bit and fixed theme honoring +0.04: Fixed date font alignment and changed date font to match a real Rolex diff --git a/apps/rolex/README.md b/apps/rolex/README.md index 4c24aad0c..5339f1d0e 100644 --- a/apps/rolex/README.md +++ b/apps/rolex/README.md @@ -1,11 +1,13 @@ # Rolex -![](screenshot.png) +![](screenshot.png) ![](screenshot1.png) Created with the aid of the Espruino documentation and looking through many of the wonderful exising watchfaces that have been made. This has not been tested on a watch yet as I haven't aquired one but has been tested in the emulator. The hands don't rotate dead on center but they're as close as I could get them to. +Colour switches based on watch theme so if you want a white on black change your watch theme to dark, and for black on white change it to light. + Special thanks to: * rozek (for his updated widget draw code for utilization with background images) * Gordon Williams (Bangle.js, watchapps for reference code and documentation) diff --git a/apps/rolex/app.js b/apps/rolex/app.js index e409704fc..124cb6fee 100644 --- a/apps/rolex/app.js +++ b/apps/rolex/app.js @@ -28,6 +28,14 @@ var imgSec = { buffer : E.toArrayBuffer(atob("v/q//r/+v/qv+q/qq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qv+v/6/D/wD8PDw8PwD/w///6v+qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqr+r//v///X/1X/Vf9V/1X/1///+//q/qq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq6qrqg==")) }; +/* use font closer to Rolex */ + +Graphics.prototype.setFontRolexFont = function(scale) { + // Actual height 12 (12 - 1) + this.setFontCustom(atob("AAAABAACAAAAAYAHgA4AOABgAAAAA/gD/gMBgQBAwGA/4A/gAAAAAAIBAQCB/8D/4AAQAAAAAAAAAwEDAYEBQIEgYxA/CA4MAAAAAAAAgIBAhCBCEDOYHvgCOAAAAAAABgANAAyAHEAf/A/+AAgABAAAAAAADBAcCBsECYIEYgIeAAAAAAAHwAfwB5wGggZBAjGBH4CDgAAACAAYAAgABAMCDwE+APgAYAAAAAAABxwH3wJwgRhA3iB54AhgAAAAAAPhA/iBDMCCQGHgH+AHwAAAAAAAQIAgQAAAAAA="), 46, atob("BAUJCQkJCQkJCQkJBQ=="), 17+(scale<<8)+(1<<16)); + return this; +}; + /* Set variables to get screen width, height and center points */ let W = g.getWidth(); @@ -36,10 +44,6 @@ let cx = W/2; let cy = H/2; let Timeout; -/* set font */ - -require("Font4x5Numeric").add(Graphics); - Bangle.loadWidgets(); /* Custom version of Bangle.drawWidgets (does not clear the widget areas) Thanks to rozek */ @@ -106,9 +110,10 @@ function drawHands() { g.drawImage(imgHour,cx-22*hourSin,cy+22*hourCos,{rotate:hourAngle}); g.drawImage(imgMin,cx-34*minSin,cy+34*minCos,{rotate:minAngle}); g.drawImage(imgSec,cx-25*secSin,cy+25*secCos,{rotate:secAngle}); - g.setFont("4x5Numeric:3"); + g.setFontRolexFont(); g.setColor(g.theme.bg); - g.drawString(d.getDate(),157,81); + g.setFontAlign(0,0,0); + g.drawString(d.getDate(),165,89); } function drawBackground() { diff --git a/apps/rolex/app.js:Zone.Identifier b/apps/rolex/app.js:Zone.Identifier new file mode 100644 index 000000000..053d1127c --- /dev/null +++ b/apps/rolex/app.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +HostUrl=about:internet diff --git a/apps/rolex/screenshot1.png b/apps/rolex/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..f84b0ef5c3ef50356dc790e36e51d0a99cabe16f GIT binary patch literal 3905 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 literal 0 HcmV?d00001 diff --git a/apps/rolex/screenshot1.png:Zone.Identifier b/apps/rolex/screenshot1.png:Zone.Identifier new file mode 100644 index 000000000..053d1127c --- /dev/null +++ b/apps/rolex/screenshot1.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +HostUrl=about:internet From 08c9e519b99982c57a3f53c16693b33f503a6f4b Mon Sep 17 00:00:00 2001 From: DC959 Date: Mon, 28 Feb 2022 22:11:19 +1300 Subject: [PATCH 298/447] Fix date alignment and change font to closer match Rolex --- apps/rolex/app.js:Zone.Identifier | 3 --- apps/rolex/screenshot1.png:Zone.Identifier | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 apps/rolex/app.js:Zone.Identifier delete mode 100644 apps/rolex/screenshot1.png:Zone.Identifier diff --git a/apps/rolex/app.js:Zone.Identifier b/apps/rolex/app.js:Zone.Identifier deleted file mode 100644 index 053d1127c..000000000 --- a/apps/rolex/app.js:Zone.Identifier +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=about:internet diff --git a/apps/rolex/screenshot1.png:Zone.Identifier b/apps/rolex/screenshot1.png:Zone.Identifier deleted file mode 100644 index 053d1127c..000000000 --- a/apps/rolex/screenshot1.png:Zone.Identifier +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=about:internet From 6ed617949b1317274aefe7e5bcc8e58003c3792f Mon Sep 17 00:00:00 2001 From: Daniel Cox Date: Mon, 28 Feb 2022 22:22:26 +1300 Subject: [PATCH 299/447] Update metadata.json --- apps/rolex/metadata.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/rolex/metadata.json b/apps/rolex/metadata.json index e24344dad..f307e60c4 100644 --- a/apps/rolex/metadata.json +++ b/apps/rolex/metadata.json @@ -2,8 +2,8 @@ "name": "rolex", "shortName":"rolex", "icon": "rolex.png", - "screenshots": [{"url":"screenshot.png"}], - "version":"0.03", + "screenshots": [{"url":"screenshot1.png"}], + "version":"0.04", "description": "A rolex like watch face", "tags": "clock", "type": "clock", @@ -14,4 +14,4 @@ {"name":"rolex.app.js","url":"app.js"}, {"name":"rolex.img","url":"app-icon.js","evaluate":true} ] - } \ No newline at end of file + } From 52d54c9234d158a27eb9212daf63500d1d03e76d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Feb 2022 13:10:55 +0000 Subject: [PATCH 300/447] Remove BangleRun as it's unmaintained and no longer works nicely with PR #1052 for Typescript support Remove Travis builds as we're now switching to GitHub actions --- .travis.yml | 3 - apps/banglerun/ChangeLog | 13 -- apps/banglerun/activity.js | 40 ------- apps/banglerun/activity.ts | 41 ------- apps/banglerun/app-icon.js | 1 - apps/banglerun/app.js | 15 --- apps/banglerun/app.ts | 20 ---- apps/banglerun/banglerun.png | Bin 10456 -> 0 bytes apps/banglerun/display.js | 106 ----------------- apps/banglerun/display.ts | 123 ------------------- apps/banglerun/gps.js | 71 ----------- apps/banglerun/gps.ts | 90 -------------- apps/banglerun/hrm.js | 19 --- apps/banglerun/hrm.ts | 29 ----- apps/banglerun/interface.html | 217 ---------------------------------- apps/banglerun/log.js | 37 ------ apps/banglerun/log.ts | 47 -------- apps/banglerun/metadata.json | 16 --- apps/banglerun/state.js | 37 ------ apps/banglerun/state.ts | 93 --------------- apps/banglerun/step.js | 14 --- apps/banglerun/step.ts | 15 --- 22 files changed, 1047 deletions(-) delete mode 100644 .travis.yml delete mode 100644 apps/banglerun/ChangeLog delete mode 100644 apps/banglerun/activity.js delete mode 100644 apps/banglerun/activity.ts delete mode 100644 apps/banglerun/app-icon.js delete mode 100644 apps/banglerun/app.js delete mode 100644 apps/banglerun/app.ts delete mode 100644 apps/banglerun/banglerun.png delete mode 100644 apps/banglerun/display.js delete mode 100644 apps/banglerun/display.ts delete mode 100644 apps/banglerun/gps.js delete mode 100644 apps/banglerun/gps.ts delete mode 100644 apps/banglerun/hrm.js delete mode 100644 apps/banglerun/hrm.ts delete mode 100644 apps/banglerun/interface.html delete mode 100644 apps/banglerun/log.js delete mode 100644 apps/banglerun/log.ts delete mode 100644 apps/banglerun/metadata.json delete mode 100644 apps/banglerun/state.js delete mode 100644 apps/banglerun/state.ts delete mode 100644 apps/banglerun/step.js delete mode 100644 apps/banglerun/step.ts 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/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/activity.js b/apps/banglerun/activity.js deleted file mode 100644 index 94512094c..000000000 --- a/apps/banglerun/activity.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.stopActivity = exports.startActivity = exports.clearActivity = void 0; -const display_1 = require("./display"); -const log_1 = require("./log"); -const state_1 = require("./state"); -function startActivity(state) { - if (state.status === state_1.ActivityStatus.Stopped) { - (0, log_1.initLog)(state); - } - if (state.status === state_1.ActivityStatus.Running) { - state.status = state_1.ActivityStatus.Paused; - } - else { - state.status = state_1.ActivityStatus.Running; - } - (0, display_1.draw)(state); -} -exports.startActivity = startActivity; -function stopActivity(state) { - if (state.status === state_1.ActivityStatus.Paused) { - clearActivity(state); - } - if (state.status === state_1.ActivityStatus.Running) { - state.status = state_1.ActivityStatus.Paused; - } - else { - state.status = state_1.ActivityStatus.Stopped; - } - (0, display_1.draw)(state); -} -exports.stopActivity = stopActivity; -function clearActivity(state) { - state.duration = 0; - state.distance = 0; - state.speed = 0; - state.steps = 0; - state.cadence = 0; -} -exports.clearActivity = clearActivity; diff --git a/apps/banglerun/activity.ts b/apps/banglerun/activity.ts deleted file mode 100644 index c1a01f30b..000000000 --- a/apps/banglerun/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/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 84d03820a..000000000 --- a/apps/banglerun/app.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const activity_1 = require("./activity"); -const display_1 = require("./display"); -const gps_1 = require("./gps"); -const hrm_1 = require("./hrm"); -const state_1 = require("./state"); -const step_1 = require("./step"); -const appState = (0, state_1.initState)(); -(0, gps_1.initGps)(appState); -(0, hrm_1.initHrm)(appState); -(0, step_1.initStep)(appState); -(0, display_1.initDisplay)(appState); -setWatch(() => (0, activity_1.startActivity)(appState), BTN1, { repeat: true, edge: 'falling' }); -setWatch(() => (0, activity_1.stopActivity)(appState), BTN3, { repeat: true, edge: 'falling' }); diff --git a/apps/banglerun/app.ts b/apps/banglerun/app.ts deleted file mode 100644 index 7093e24e0..000000000 --- a/apps/banglerun/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/banglerun.png b/apps/banglerun/banglerun.png deleted file mode 100644 index bf2cd8af3ef5f9711d18df1656a03a98283bcc67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10456 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 O0000 { - state.drawing = on; - if (on) { - drawAll(state); - } - }); - drawAll(state); -} -exports.initDisplay = initDisplay; -function drawBackground() { - 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); -} -exports.drawBackground = drawBackground; -function drawValue(value, x, y) { - g.setColor(0x0000); - g.fillRect(x - 60, y, x + 60, y + 30); - g.setColor(0xFFFF); - g.drawString(value, x, y); -} -exports.drawValue = drawValue; -function draw(state) { - 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 === state_1.ActivityStatus.Paused) { - g.drawString("START", 236, 60, 1).drawString(" CLEAR ", 236, 180, 1); - } - else if (state.status === state_1.ActivityStatus.Running) { - g.drawString(" PAUSE ", 236, 60, 1).drawString(" PAUSE ", 236, 180, 1); - } - else { - g.drawString("START", 236, 60, 1).drawString(" ", 236, 180, 1); - } -} -exports.draw = draw; -function drawAll(state) { - drawBackground(); - draw(state); - Bangle.drawWidgets(); -} -exports.drawAll = drawAll; -function formatClock(date) { - return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2); -} -exports.formatClock = formatClock; -function formatDistance(meters) { - return (meters / 1000).toFixed(2); -} -exports.formatDistance = formatDistance; -function formatPace(speed) { - 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) + `"`; -} -exports.formatPace = formatPace; -function formatTime(time) { - 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); -} -exports.formatTime = formatTime; diff --git a/apps/banglerun/display.ts b/apps/banglerun/display.ts deleted file mode 100644 index 528890c35..000000000 --- a/apps/banglerun/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/gps.js b/apps/banglerun/gps.js deleted file mode 100644 index 35e0f8769..000000000 --- a/apps/banglerun/gps.js +++ /dev/null @@ -1,71 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.updateGps = exports.readGps = exports.initGps = void 0; -const display_1 = require("./display"); -const log_1 = require("./log"); -const state_1 = require("./state"); -const EARTH_RADIUS = 6371008.8; -function initGps(state) { - Bangle.on('GPS', (gps) => readGps(state, gps)); - Bangle.setGPSPower(1); -} -exports.initGps = initGps; -function readGps(state, gps) { - 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); - (0, display_1.draw)(state); - /* Only log GPS data every 5 secs if we - have a fix and we're running. */ - if (state.gpsValid && - state.status === state_1.ActivityStatus.Running && - state.timeSinceLog > 5) { - state.timeSinceLog = 0; - (0, log_1.updateLog)(state); - } -} -exports.readGps = readGps; -function updateGps(state) { - const t = Date.now(); - let dt = (t - state.t) / 1000; - if (!isFinite(dt)) - dt = 0; - state.t = t; - state.timeSinceLog += dt; - if (state.status === state_1.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 === state_1.ActivityStatus.Running) { - state.distance += dpMag; - state.speed = (state.distance / state.duration) || 0; - state.cadence = (60 * state.steps / state.duration) || 0; - } -} -exports.updateGps = updateGps; diff --git a/apps/banglerun/gps.ts b/apps/banglerun/gps.ts deleted file mode 100644 index 1886ecfb2..000000000 --- a/apps/banglerun/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/hrm.js b/apps/banglerun/hrm.js deleted file mode 100644 index c002de2f6..000000000 --- a/apps/banglerun/hrm.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.updateHrm = exports.initHrm = void 0; -function initHrm(state) { - Bangle.on('HRM', (hrm) => updateHrm(state, hrm)); - Bangle.setHRMPower(1); -} -exports.initHrm = initHrm; -function updateHrm(state, hrm) { - 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; -} -exports.updateHrm = updateHrm; diff --git a/apps/banglerun/hrm.ts b/apps/banglerun/hrm.ts deleted file mode 100644 index 08dd237a7..000000000 --- a/apps/banglerun/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/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/log.js b/apps/banglerun/log.js deleted file mode 100644 index 0cdeaa964..000000000 --- a/apps/banglerun/log.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.updateLog = exports.initLog = void 0; -function initLog(state) { - const datetime = new Date().toISOString().replace(/[-:]/g, ''); - const date = datetime.substr(2, 6); - const time = datetime.substr(9, 6); - const filename = `banglerun_${date}_${time}`; - return Object.assign(Object.assign({}, state), { file: require('Storage').open(filename, 'w'), fileWritten: false }); -} -exports.initLog = initLog; -function updateLog(state) { - 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'); -} -exports.updateLog = updateLog; diff --git a/apps/banglerun/log.ts b/apps/banglerun/log.ts deleted file mode 100644 index ba1c1f00e..000000000 --- a/apps/banglerun/log.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { AppState, AppStateWithLog } from './state'; - -declare var require: any; - -function initLog(state: AppState): AppStateWithLog { - const datetime = new Date().toISOString().replace(/[-:]/g, ''); - const date = datetime.substr(2, 6); - const time = datetime.substr(9, 6); - const filename = `banglerun_${date}_${time}`; - return { - ...state, - file: require('Storage').open(filename, 'w'), - fileWritten: false, - } as AppStateWithLog; -} - -function updateLog(state: AppStateWithLog): 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/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/state.js b/apps/banglerun/state.js deleted file mode 100644 index 349ef1954..000000000 --- a/apps/banglerun/state.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.initState = exports.ActivityStatus = void 0; -var ActivityStatus; -(function (ActivityStatus) { - ActivityStatus["Stopped"] = "STOP"; - ActivityStatus["Paused"] = "PAUSE"; - ActivityStatus["Running"] = "RUN"; -})(ActivityStatus || (ActivityStatus = {})); -exports.ActivityStatus = ActivityStatus; -function initState() { - 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, - fileWritten: false, - drawing: false, - status: ActivityStatus.Stopped, - duration: 0, - distance: 0, - speed: 0, - steps: 0, - cadence: 0, - }; -} -exports.initState = initState; diff --git a/apps/banglerun/state.ts b/apps/banglerun/state.ts deleted file mode 100644 index 1ba9bca26..000000000 --- a/apps/banglerun/state.ts +++ /dev/null @@ -1,93 +0,0 @@ -enum ActivityStatus { - Stopped = 'STOP', - Paused = 'PAUSE', - Running = 'RUN', -} - -interface BasicAppState { - // 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 - fileWritten: boolean; - - // Drawing data - drawing: boolean; - - // Activity data - duration: number; - distance: number; - speed: number; - steps: number; - cadence: number; -} - -interface AppStateWithoutLog extends BasicAppState { - status: 'STOP'; -} - -interface AppStateWithLog extends BasicAppState { - file: File; - status: ActivityStatus; -} - -type AppState = AppStateWithLog | AppStateWithoutLog; - -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, - - fileWritten: false, - - drawing: false, - - status: ActivityStatus.Stopped, - duration: 0, - distance: 0, - speed: 0, - steps: 0, - cadence: 0, - } -} - -export { ActivityStatus, AppState, AppStateWithLog, File, initState }; diff --git a/apps/banglerun/step.js b/apps/banglerun/step.js deleted file mode 100644 index e4acfd66a..000000000 --- a/apps/banglerun/step.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.updateStep = exports.initStep = void 0; -const state_1 = require("./state"); -function initStep(state) { - Bangle.on('step', () => updateStep(state)); -} -exports.initStep = initStep; -function updateStep(state) { - if (state.status === state_1.ActivityStatus.Running) { - state.steps += 1; - } -} -exports.updateStep = updateStep; diff --git a/apps/banglerun/step.ts b/apps/banglerun/step.ts deleted file mode 100644 index c7fcb61ea..000000000 --- a/apps/banglerun/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 }; From 955acf2696634490ca200930c02a919d57530dc7 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Mon, 28 Feb 2022 22:10:00 +0100 Subject: [PATCH 301/447] gpsautotime: Set Bangle.js 2 compatible --- apps/gpsautotime/ChangeLog | 1 + apps/gpsautotime/metadata.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) 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"} ] From bc8eecf998a8d380485139ce4016e888b648ffb6 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 1 Mar 2022 08:12:53 +0000 Subject: [PATCH 302/447] fix lint warnings --- .eslintignore | 1 + apps/pooqroman/app.js | 6 ++++-- apps/pooqroman/resourcer.js | 3 ++- apps/pooqround/resourcer.js | 3 ++- apps/speedalt2/app.js | 3 ++- apps/weatherClock/app.js | 1 - 6 files changed, 11 insertions(+), 6 deletions(-) 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/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/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; } } From 7ce68ff66cd84996d4bef974fe17a407aa8fc460 Mon Sep 17 00:00:00 2001 From: BartS23 <10829389+BartS23@users.noreply.github.com> Date: Sun, 27 Feb 2022 08:35:17 +0100 Subject: [PATCH 303/447] Make links to github absolute otherwise they will not work in the apploader --- apps/run/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) From 87cfd379e8c92177c40cfe3df7ba94a872559c6f Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 1 Mar 2022 22:02:13 +0800 Subject: [PATCH 304/447] Update app.js Fix #12 Optimize graphics calls a bit --- apps/authentiwatch/app.js | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/authentiwatch/app.js b/apps/authentiwatch/app.js index b2c8f857b..73b8bdeea 100644 --- a/apps/authentiwatch/app.js +++ b/apps/authentiwatch/app.js @@ -94,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; } @@ -122,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--); @@ -139,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 @@ -161,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() { @@ -229,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); @@ -323,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(); From ad911cdb02d8bd51748b11160a6623eab0bf9565 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 1 Mar 2022 22:06:49 +0800 Subject: [PATCH 305/447] Update ChangeLog v0.06 --- apps/authentiwatch/ChangeLog | 1 + 1 file changed, 1 insertion(+) 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) From 5fc057f943cb7e3a0392a3e64f5119769918f7f8 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 1 Mar 2022 22:07:23 +0800 Subject: [PATCH 306/447] Update metadata.json v0.06 --- apps/authentiwatch/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/authentiwatch/metadata.json b/apps/authentiwatch/metadata.json index 676d8da9f..309a47b78 100644 --- a/apps/authentiwatch/metadata.json +++ b/apps/authentiwatch/metadata.json @@ -4,7 +4,7 @@ "shortName": "AuthWatch", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], - "version": "0.05", + "version": "0.06", "description": "Google Authenticator compatible tool.", "tags": "tool", "interface": "interface.html", From edf8204ab82fdce7a0bfb9199118876c1371e4cf Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 1 Mar 2022 22:13:52 +0800 Subject: [PATCH 307/447] Add files via upload New screenshots --- apps/authentiwatch/screenshot1.png | Bin 0 -> 2708 bytes apps/authentiwatch/screenshot2.png | Bin 0 -> 2914 bytes apps/authentiwatch/screenshot3.png | Bin 0 -> 2656 bytes apps/authentiwatch/screenshot4.png | Bin 0 -> 2951 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/authentiwatch/screenshot1.png create mode 100644 apps/authentiwatch/screenshot2.png create mode 100644 apps/authentiwatch/screenshot3.png create mode 100644 apps/authentiwatch/screenshot4.png diff --git a/apps/authentiwatch/screenshot1.png b/apps/authentiwatch/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ca744b497c2098743be85b15d16878f7196a54 GIT binary patch literal 2708 zcmbuBX*iS%8^@pLVHhKfi3w>+V_&jG#xnNZA=}74LRqH5R3_^nq3n{K98|K5veg+h zB1<{SE{Z9GETcIk%W=}{e1AW@*Y$q5@BfG2eO>pL`~Sc0w6pe>0tg8N0008kR%T8I z+VpS1c@8?Qo#k^NAlb>%1ZW(VTmb-ty|tOK3&n?Bc8Of2cIalwuU}PUQx9EyNQV;k z#lYOΞ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 literal 0 HcmV?d00001 diff --git a/apps/authentiwatch/screenshot2.png b/apps/authentiwatch/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..8156dd3e8a8070e3b57b93163f8cd44ca5e90e85 GIT binary patch literal 2914 zcmbtW`#;l<_kV4+#oT6cO>CLTb&>o1I`=4&TL@vKmc)9yG(}Y85>rGI-YWOExs!!1 zQtoC}*gMtGTb8?#KKlL(-yhC7kH_zq@7i^<$3u6`KdNz)x_-afx|Zl(vJ;?#o`D$nyt}Z63@p0XS=9($-rPxb zej-W6eN_AP<#PzsU&Z=xBAR~qRmDOqG&3zudfN#ll1Oza*2@Pn5|v_nXIfw6*UZF+)=;jv6^$6!iar5Kxz7+#;f6x6+zPD=@d&O8WgwNifk zei&@xWcETTh_WKM@$sLO2NEKnl8Rk&(#X5`jvx@pLfTEr&&oo3X*wNPE}mT~8w2Dl zgmB7^xa949m8Wq$zDtb}d zYV{`cGjCIv=07{UF!YX)m0<%4xOL5j=*hNTfb@ufjunVmU`3;>$f7R0n&)tQ#2;(u zUkU|c9VpHrJ85#xd7A;$(?lX7XV;KfK4&qY51?;)8PEIbSjQ|(hdPj#Z5$9LuPjUL zEyJe`e0ZI^_+_WyYLH)JSeNKhhkm*4juYU=ciR1=x|{vyc#OGzyjOz8_6=r4+a`nm zAqZpIRhI_#^1-8SkHhD4wn~7=pur^dv)kuyRath*(Or{u2GaesbG}-^AB4=w1M}7A zp7|G^&wMRM+<9(FU&AvGN@ILD%-~xvbEYD;aSDAx60Ae;3C;|f4PI2J!V;W zkz^R*csn>!4cBgBfwEh(V1=typ4rI;3Q+hIJSzjjgyX=JZHxidfIZ$ zA1oxK3(*OAm-pPqNxK~Wh?hn`x($DeP0~Ynw~tfKYZL|d{g#jV`!rkrOhH?QP(emu5sx|!RVuJkp1zVUwc>`LQ~>k=q-h^yFx7ztDUHV8II)lD_xNn`0J zde5CcUIAGKYk~apO_aMM1d{wClMl-vn)KQ#P7q>;X;*VE+aBj=qJLaK0gCk`nx%eG zc!$L8D;u`~CxD~6vflmaFWz22?K=vu4aw`QTicwFY?u@3fA@|57@SyWJJ4@SK#c=~ zIX9W!4-LX*2Vv6B@`fs2|B9;t`@Xc+3x;eJv~$3IEN6o1KRWA*12-A)j0f-E3^gTdAhH1FXQ|wS8Zo-&o=vIqffvT40%LqyYR}eDH6pvjlF$M_*Md*`ri%zi z@xaxW--8=GE)TmNA7`{kb`Q74vud~5Q+1UZ9xdgEK@ag(#S&R@~<;bYB~CnNwi__RqVnrG0}vsB!(tfpEkf!mBSf}t z!-R6pMTZ?N31;wO4*t3e#D+N<^Wz~`0-$V&`8@b*k#9>|G!UZt!Gj4WF6@;Ej4~Ot zd}Q}?jsE5L>w7@iA&LI&8Hopglg!(IO*tW$=xe^}n$AM1n^w(|W`N1B%|9J4+?8Q% zK$%s%C&{G_HjL!5gn|UdR>N}*o$I$^=Ro*knun1}a!q8!UDs2clnODPrt!07R>tQA zsn2N*AKLa=fLNDF&65*WA4U00P|A~k@}_{FR92}LC zAgOX!ZPW59sAQe9?yU>^JmCF(X5ravF9_^Rw!ZI779d_AZ%3^^p4|C0J+KmIa(F9h zJw<pd(@N=iOMHTkX^y8jJ zJ`_ESW1g^v2EFjts_F(O432EL-yOTRZVggT-bvx5gdo`{Z$?j1j~vEkEan86FQf%J zQ*;M7hYY+49>Ad^xZkKIHAjjim+$|~29|wXgrV~s4Qi!&K{QWYm{`k0&dd@pbU|?~ zB%6k-!kAvLCp%95E{eW?Cn|GH+kLHF*#r6m-5Q%&T>M&tN{I_o@1p7KV9Ce*@Ce;6AZ%Vsvdrs*?f7stY#nFfYeWH=mAc*M=|oxA_}-o zv8ESDz@tSnj|ul4+R1`QJ3Jc4w`+p#`Ps2(B1bUyN`Ph-mi~~?Ch^Ev1t~YW?rC1` zt#TlX_U#gMa3|?cm%9;2IQx@qz0Q+(*P5=XN;`=#=tk`(ES~@9+o|f<)g$X_XD=1+ z2^@nBj7k_BNL~-W3;ezgNkjh=TlE!GYxzi1rFG|(yki5p|`@L+q@mTj%qBy%>#vYXa{QJG4de3bEV$}`dO~vnF zA&N}4)t0XS_shWu6r*-PIZdxT9&BP0+IC;|Eu^Jd0YsUSWj$%e$}iey5AqYUZALzH zf*}t=Qas5(+6jeXWqJsT28I~K@a9cGSiaKzm!)*fjw5hPhQEd`N}v39dp$z*x_er< z9QWg*At_i2moybOFSADCw86~elbK)yo4IW~6Aw->0XINV^oG^A&P~V`2@)h|K@R3D zla>XzKl%G4sWO3C97&oPTsIaTM9NAS@4pGHk^KP#h=iM^95vMly>-+_Ebb!it8!){ zzLuXmxTgEslUJ_8qguJ38{1jXKpI>T{6TucQ!B1Rw10>q!4zjtQ`3=Ip$o(}I%UjV Z(A4{6$wZuM;{MYNIM|-BskI8c@jt}ERJ#BG literal 0 HcmV?d00001 diff --git a/apps/authentiwatch/screenshot3.png b/apps/authentiwatch/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..6d14e0b965efa1b522d034bc0fee2f8415a950d5 GIT binary patch literal 2656 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 literal 0 HcmV?d00001 From 4a7244601ade976aa077cd2dcdce69201d7834bd Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 1 Mar 2022 22:14:44 +0800 Subject: [PATCH 308/447] Delete screenshot.png Remove obsolete screenshot --- apps/authentiwatch/screenshot.png | Bin 2939 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/authentiwatch/screenshot.png diff --git a/apps/authentiwatch/screenshot.png b/apps/authentiwatch/screenshot.png deleted file mode 100644 index 2a7bcbd9a4f1881dd9dfff40dc7c643cf6aea5a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2939 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 From b811d6524b142185f53bb6fc9ebfa109f0c14390 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 1 Mar 2022 22:16:45 +0800 Subject: [PATCH 309/447] Update metadata.json Add screenshots --- apps/authentiwatch/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/authentiwatch/metadata.json b/apps/authentiwatch/metadata.json index 309a47b78..b4ed34a12 100644 --- a/apps/authentiwatch/metadata.json +++ b/apps/authentiwatch/metadata.json @@ -3,7 +3,7 @@ "name": "2FA Authenticator", "shortName": "AuthWatch", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot1.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot4.png"}], "version": "0.06", "description": "Google Authenticator compatible tool.", "tags": "tool", From b2ebc7f29efd3aebb663bfa65a9eb7ff1ae1d986 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Tue, 1 Mar 2022 22:18:20 +0800 Subject: [PATCH 310/447] Update README.md Update screenshots --- apps/authentiwatch/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. -![Screenshot](screenshot.png) +![Screenshot](screenshot1.png) ![Screenshot](screenshot2.png) ![Screenshot](screenshot3.png) ![Screenshot](screenshot4.png) ## Creator From dd906e076f9fbdf382248c493b780245eedc3b93 Mon Sep 17 00:00:00 2001 From: Rarder44 Date: Tue, 1 Mar 2022 19:03:09 +0100 Subject: [PATCH 311/447] added clear for fix the trasparent widget bar if there are no widgets --- apps/dtlaunch/app-b2.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index 96e562add..35cec3da9 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -125,5 +125,6 @@ Bangle.on("touch",(_,p)=>{ }); Bangle.loadWidgets(); +g.clear(); Bangle.drawWidgets(); drawPage(0); From ef815f230c7df50d9e4541253866b34aac2cb0bd Mon Sep 17 00:00:00 2001 From: Rarder44 Date: Tue, 1 Mar 2022 19:13:49 +0100 Subject: [PATCH 312/447] added option to exit the launcher with one click --- apps/dtlaunch/app-b2.js | 4 ++++ apps/dtlaunch/settings-b2.js | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index 35cec3da9..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); 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(); + } } }); }) From d476f530a8e728ae5eab18947a706f397a365602 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 2 Mar 2022 08:42:39 +0000 Subject: [PATCH 313/447] fix #1533 --- apps/snek/snek.icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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=")) From f0e6190c16550be503b8ab38ae346542b0a7a21d Mon Sep 17 00:00:00 2001 From: Rarder44 Date: Wed, 2 Mar 2022 11:23:18 +0100 Subject: [PATCH 314/447] edit version and changelog --- apps/dtlaunch/ChangeLog | 2 ++ apps/dtlaunch/metadata.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) 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/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", From 4150874534ee5830e713d86855726793567b6255 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Wed, 2 Mar 2022 16:34:35 +0100 Subject: [PATCH 315/447] Write settings file --- apps/smclock/settings.js | 117 ++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 70 deletions(-) diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index bfc738e19..9d747a910 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -1,108 +1,85 @@ -// Settings menu for Monogram Watch Face +// settings menu for Monogram Watch Face // Anton Clock settings were used as template +// helper functions taken from Anton Clock -(function(back) { +(function (back) { var FILE = "smclock.json"; - // Load settings - var settings = Object.assign({ - secondsOnUnlock: false, - }, require('Storage').readJSON(FILE, true) || {}); + // load settings from the file + // assign default values if it doesn't exist + var settings = Object.assign( + { + dateFormat: "short", + showAnalogFace: false, + showWeekInfo: false, + useVectorFont: true, + }, + require("Storage").readJSON(FILE, true) || {} + ); + // write the new settings to the file function writeSettings() { - require('Storage').writeJSON(FILE, settings); + require("Storage").writeJSON(FILE, settings); } - // Helper method which uses int-based menu item for set of string values + // 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], + value: startvalue === undefined ? 0 : values.indexOf(startvalue), + format: (v) => values[v], min: 0, max: values.length - 1, wrap: true, step: 1, - onchange: v => { + onchange: (v) => { writer(values[v]); writeSettings(); - } + }, }; } - // Helper method which breaks string set settings down to local settings object + // 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); + return stringItems(settings[name], (v) => (settings[name] = v), values); } + // settings menu var mainmenu = { "": { - "title": "Monogram Clock" + title: "Monogram Clock", }, "< Back": () => back(), - "Seconds...": () => E.showMenu(secmenu), - "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), - "Show Weekday": { - value: (settings.weekDay !== undefined ? settings.weekDay : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.weekDay = v; + "Analog Face": { + value: + settings.showAnalogFace !== undefined ? settings.showAnalogFace : false, + format: (v) => (v ? "On" : "Off"), + onchange: (v) => { + settings.showAnalogFace = v; writeSettings(); - } + }, }, - "Show CalWeek": { - value: (settings.calWeek !== undefined ? settings.calWeek : false), - format: v => v ? "On" : "Off", - onchange: v => { - settings.calWeek = v; + Date: stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), + "Week Info": { + value: + settings.showWeekInfo !== undefined ? settings.showWeekInfo : false, + format: (v) => (v ? "On" : "Off"), + onchange: (v) => { + settings.showWeekInfo = v; writeSettings(); - } + }, }, - "Uppercase": { - value: (settings.upperCase !== undefined ? settings.upperCase : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.upperCase = v; + "Vector Font": { + value: + settings.useVectorFont !== undefined ? settings.useVectorFont : false, + format: (v) => (v ? "On" : "Off"), + onchange: (v) => { + settings.useVectorFont = v; writeSettings(); - } + }, }, - "Vector font": { - value: (settings.vectorFont !== undefined ? settings.vectorFont : false), - format: v => v ? "On" : "Off", - onchange: v => { - settings.vectorFont = v; - writeSettings(); - } - }, - }; - - // Submenu - var secmenu = { - "": { - "title": "Show seconds..." - }, - "< Back": () => E.showMenu(mainmenu), - "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), - "With \":\"": { - value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.secondsWithColon = v; - writeSettings(); - } - }, - "Color": { - value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.secondsColoured = v; - writeSettings(); - } - }, - "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) }; // Actually display the menu E.showMenu(mainmenu); - }); // end of file From 4ddf8a94fbb36bd663fbc018c5f92c9e0d2e2e8b Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 2 Mar 2022 09:36:11 -0800 Subject: [PATCH 316/447] Update ChangeLog --- apps/smclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/smclock/ChangeLog b/apps/smclock/ChangeLog index b029d805d..77098b0ad 100644 --- a/apps/smclock/ChangeLog +++ b/apps/smclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: Initial version 0.02: Add battery level +0.03: fix battery level displaying From d64f945eff1ecbdc4507dfdcef4c6039cc2f1e75 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 2 Mar 2022 09:36:31 -0800 Subject: [PATCH 317/447] Update app.js --- apps/smclock/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 6aff72a46..84942e0ef 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -51,7 +51,7 @@ function draw() { g.drawImage(background); const color = getBatteryColor(); - const bat = d02(E.getBattery()) + "%"; + const bat = E.getBattery() + "%"; const d = new Date(); const day = d.getDate(); const month = (d.getMonth() + 1); @@ -78,7 +78,7 @@ function draw() { g.setFont("Vector", 16); g.drawString("Bat:", 12, 22, false); g.setColor(color[0], color[1], color[2]); - g.drawString(bat, 52, 22, false); + g.drawString(bat, 46, 22, false); } g.clear(); From 136cbe28e12b78f4a45b838ecfc3c357784c2d53 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 2 Mar 2022 09:36:46 -0800 Subject: [PATCH 318/447] Update metadata.json --- apps/smclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 1783ca7bf..e2fbeace1 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -3,7 +3,7 @@ "name":"Monogram Watch Face", "shortName":"MonoClock", "icon":"app.png", - "version":"0.02", + "version":"0.03", "description": "A simple watchface based on my stylised monogram.", "tags":"clock", "readme":"README.md", From 4521873a53e65a51699fc3dbfb9d533690c48ff6 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 2 Mar 2022 19:21:41 +0000 Subject: [PATCH 319/447] Daisy: added heart rate, update steps on each step --- apps/daisy/ChangeLog | 1 + apps/daisy/README.md | 15 +-- apps/daisy/app.js | 198 ++++++++++++++++++++++++++------------- apps/daisy/metadata.json | 2 +- 4 files changed, 142 insertions(+), 74 deletions(-) diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index 4fdf333e4..989704054 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -1,2 +1,3 @@ 0.01: first release 0.02: added settings menu to change color +0.03: 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 ![](app.png) *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/) ![](screenshot_daisy1.png) 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) -![](screenshot_daisy2.jpg) 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 c35bfefa3..695e4a85e 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.02", + "version":"0.03", "dependencies": {"mylocation":"app"}, "description": "A clock based on the Pastel clock with large ring guage for steps", "icon": "app.png", From e124aa91c0b47e041619a0ac288eb3ea408daca8 Mon Sep 17 00:00:00 2001 From: Jeroen Peters Date: Thu, 3 Mar 2022 09:29:47 +0100 Subject: [PATCH 320/447] Dutch translations --- lang/nl_NL.json | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) 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" }, From 9bf6f1f20b8fd5b83b767aedc3f75634311bf3dc Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 13:36:56 +0100 Subject: [PATCH 321/447] Add testing variables --- apps/smclock/app.js | 107 +++++++++++++++++++++++++++++---------- apps/smclock/settings.js | 28 ++++++++-- 2 files changed, 103 insertions(+), 32 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index b900e4d9e..19044883e 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -1,30 +1,74 @@ 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 monthName = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +]; +const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; // dynamic variables var batLevel = -1; -var batColor = [0,0,0]; +var batColor = [0, 0, 0]; + +// 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); + 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() { @@ -37,16 +81,16 @@ function getBatteryColor(level) { 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; } @@ -58,7 +102,7 @@ function draw() { const bat = d02(E.getBattery()) + "%"; 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); @@ -69,7 +113,12 @@ function draw() { g.reset(); g.setColor(0, 0, 0); - g.setFont("Vector", 20); + console.log(useVectorFont, dateFormat); + if (useVectorFont == true && dateFormat == "Short") { + g.setFont("Vector", 20); + } else { + g.setFont("6x8", 2); + } g.drawString(date1, 105, 20, false); g.setFont("Vector", 16); g.drawString(date2, 105, 55, false); @@ -85,6 +134,8 @@ function draw() { g.drawString(bat, 52, 22, false); } +loadSettings(); + g.clear(); pollBattery(); @@ -94,7 +145,7 @@ var batInterval = setInterval(pollBattery, 60000); var drawInterval = setInterval(draw, 10000); // 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); @@ -102,7 +153,7 @@ Bangle.on('lcdPower',on=>{ if (on) { batInterval = setInterval(pollBattery, 60000); drawInterval = setInterval(draw, 10000); - + pollBattery(); draw(); } diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index 9d747a910..22314b764 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -8,10 +8,12 @@ // assign default values if it doesn't exist var settings = Object.assign( { - dateFormat: "short", + dateFormat: "Short", + drawInterval: 10, + pollInterval: 60, showAnalogFace: false, showWeekInfo: false, - useVectorFont: true, + useVectorFont: false, }, require("Storage").readJSON(FILE, true) || {} ); @@ -57,7 +59,21 @@ writeSettings(); }, }, - Date: stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), + Date: stringInSettings("dateFormat", ["Long", "Short", "ISO8601"]), + "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, @@ -72,7 +88,11 @@ settings.useVectorFont !== undefined ? settings.useVectorFont : false, format: (v) => (v ? "On" : "Off"), onchange: (v) => { - settings.useVectorFont = v; + if (v == "On") { + settings.useVectorFont = true; + } else { + settings.useVectorFont = false; + } writeSettings(); }, }, From 3486dc6401ecbe4dd8040e79e5c3657d105674f1 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 16:38:29 +0100 Subject: [PATCH 322/447] Add true/false values for toggles --- apps/smclock/settings.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index 22314b764..0fa0340d5 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -55,11 +55,15 @@ settings.showAnalogFace !== undefined ? settings.showAnalogFace : false, format: (v) => (v ? "On" : "Off"), onchange: (v) => { - settings.showAnalogFace = v; + if (v == "On") { + settings.showAnalogFace = true; + } else { + settings.showAnalogFace = false; + } writeSettings(); }, }, - Date: stringInSettings("dateFormat", ["Long", "Short", "ISO8601"]), + Date: stringInSettings("dateFormat", ["Long", "Short"]), "Draw Interval": { value: settings.drawInterval, onchange: (v) => { @@ -79,7 +83,11 @@ settings.showWeekInfo !== undefined ? settings.showWeekInfo : false, format: (v) => (v ? "On" : "Off"), onchange: (v) => { - settings.showWeekInfo = v; + if (v == "On") { + settings.showWeekInfo = true; + } else { + settings.showWeekInfo = false; + } writeSettings(); }, }, From cdb4ed5f16600316abae23878c12087c6daa7c42 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 16:38:56 +0100 Subject: [PATCH 323/447] Fix battery display when full --- apps/smclock/app.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 19044883e..0294f070b 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -99,7 +99,7 @@ function draw() { g.drawImage(background); const color = getBatteryColor(batLevel); - const bat = d02(E.getBattery()) + "%"; + const bat; const d = new Date(); const day = d.getDate(); const month = d.getMonth() + 1; @@ -110,6 +110,12 @@ function draw() { 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); @@ -131,7 +137,11 @@ function draw() { g.setFont("Vector", 16); g.drawString("Bat:", 12, 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); + } } loadSettings(); From 9abde22f8e1276c74929e378956e067d246bcad3 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Wed, 23 Feb 2022 09:24:33 +0100 Subject: [PATCH 324/447] Add screenshot --- apps/smclock/metadata.json | 5 +++++ apps/smclock/screenshot.png | Bin 0 -> 2845 bytes 2 files changed, 5 insertions(+) create mode 100644 apps/smclock/screenshot.png diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index e2fbeace1..0cbf0b261 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -3,7 +3,12 @@ "name":"Monogram Watch Face", "shortName":"MonoClock", "icon":"app.png", +<<<<<<< HEAD "version":"0.03", +======= + "screenshots": [{"url":"screenshot.png"}], + "version":"0.02", +>>>>>>> 29432bb9 (Add screenshot) "description": "A simple watchface based on my stylised monogram.", "tags":"clock", "readme":"README.md", diff --git a/apps/smclock/screenshot.png b/apps/smclock/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e0bd0eed06e2c77e0ad737b1ecd4814a8e4f65 GIT binary patch literal 2845 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 YUdx_>rDxQ4@7%ip9M&0AYD0|sC!%XI-v9sr literal 0 HcmV?d00001 From 4f5fb38d73989c2a6867b61260f9d311b6724b0e Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 19:59:20 +0100 Subject: [PATCH 325/447] Update changelog --- apps/smclock/ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/smclock/ChangeLog b/apps/smclock/ChangeLog index b029d805d..ec7e245ac 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 \ No newline at end of file From 95884d4df8407f893124001b181231277be708eb Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 20:09:56 +0100 Subject: [PATCH 326/447] Update changelog --- apps/smclock/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/ChangeLog b/apps/smclock/ChangeLog index ec7e245ac..0300d5ceb 100644 --- a/apps/smclock/ChangeLog +++ b/apps/smclock/ChangeLog @@ -1,4 +1,4 @@ 0.01: Initial version 0.02: Add battery level 0.03: Fix battery display when full -0.04: Add support for settings \ No newline at end of file +0.04: Add support for settings From 7a8f3d9bd985fe65e14f12f62ff2845333dff57b Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 20:12:40 +0100 Subject: [PATCH 327/447] Update metadata file --- apps/smclock/metadata.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 79d996f2c..4a3effe71 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -1,18 +1,18 @@ { - "id":"smclock", - "name":"Monogram Watch Face", - "shortName":"MonoClock", - "icon":"app.png", - "screenshots": [{"url":"screenshot.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"], + "tags": "clock", + "readme": "README.md", + "supports": ["BANGLEJS2"], "allow_emulator": true, "storage": [ - {"name":"smclock.app.js","url":"app.js"}, - {"name":"smclock.settings.js","url":"settings.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 } ] } From fd9fb6cba4014ec1cd4f68bb72e7746a452fab21 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 20:15:32 +0100 Subject: [PATCH 328/447] Fix battery ...again --- apps/smclock/app.js | 8 +++++--- apps/smclock/settings.js | 12 +----------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 0294f070b..9309cf508 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -99,7 +99,7 @@ function draw() { g.drawImage(background); const color = getBatteryColor(batLevel); - const bat; + const bat = ""; const d = new Date(); const day = d.getDate(); const month = d.getMonth() + 1; @@ -111,9 +111,9 @@ function draw() { const time = d02(h) + ":" + d02(m); if (E.getBattery() < 100) { - bat = d02(E.getBattery()) + "%" + bat = d02(E.getBattery()) + "%"; } else { - bat = E.getBattery() + "%" + bat = E.getBattery() + "%"; } g.reset(); @@ -146,6 +146,8 @@ function draw() { loadSettings(); +console.log(settings); + g.clear(); pollBattery(); diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index 0fa0340d5..6ff95c72e 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -6,17 +6,7 @@ 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) || {} - ); + var settings = Object.assign(require("Storage").readJSON(FILE, true) || {}); // write the new settings to the file function writeSettings() { From 515d1ea229b46007f6da5f649813d6b6b31b8a61 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 20:17:04 +0100 Subject: [PATCH 329/447] Fix battery ...again --- apps/smclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 9309cf508..7fa5eae77 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -99,7 +99,7 @@ function draw() { g.drawImage(background); const color = getBatteryColor(batLevel); - const bat = ""; + let bat = ""; const d = new Date(); const day = d.getDate(); const month = d.getMonth() + 1; From 7b91d21bde19c398297ae881e9c34389191642fb Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 21:46:26 +0100 Subject: [PATCH 330/447] Fix settings, hopefully --- apps/smclock/app.js | 20 +++++++++----------- apps/smclock/metadata.json | 3 ++- apps/smclock/settings.js | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 7fa5eae77..b417c6976 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -27,16 +27,16 @@ const monthName = [ const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; // dynamic variables -var batLevel = -1; -var batColor = [0, 0, 0]; +let batLevel = -1; +let batColor = [0, 0, 0]; // settings variables -var dateFormat; -var drawInterval; -var pollInterval; -var showAnalogFace; -var showWeekInfo; -var useVectorFont; +let dateFormat; +let drawInterval; +let pollInterval; +let showAnalogFace; +let showWeekInfo; +let useVectorFont; // load settings function loadSettings() { @@ -44,7 +44,7 @@ function loadSettings() { function def(value, def) { return value !== undefined ? value : def; } - var settings = require("Storage").readJSON(SETTINGSFILE, true) || {}; + let settings = require("Storage").readJSON(SETTINGSFILE, true) || {}; dateFormat = def(settings.dateFormat, "Short"); drawInterval = def(settings.drawInterval, 10); @@ -146,8 +146,6 @@ function draw() { loadSettings(); -console.log(settings); - g.clear(); pollBattery(); diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 4a3effe71..cce18a648 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -14,5 +14,6 @@ { "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/settings.js b/apps/smclock/settings.js index 6ff95c72e..81c0a0af1 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -3,10 +3,20 @@ // helper functions taken from Anton Clock (function (back) { - var FILE = "smclock.json"; + const FILE = "smclock.json"; // load settings from the file // assign default values if it doesn't exist - var settings = Object.assign(require("Storage").readJSON(FILE, true) || {}); + let 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() { From 57f7d489209a9304076bf88b781d453b903fd3e2 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 22:23:57 +0100 Subject: [PATCH 331/447] Fix drawInterval --- apps/smclock/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index b417c6976..223dd053a 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -152,17 +152,17 @@ pollBattery(); draw(); var batInterval = setInterval(pollBattery, 60000); -var drawInterval = setInterval(draw, 10000); +let actualDrawInterval = setInterval(draw, drawInterval * 1000); // Stop updates when LCD is off, restart when 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); + actualDrawInterval = setInterval(draw, drawInterval * 1000); pollBattery(); draw(); From 968707d76153151f07ed2414ea27e1f909023b09 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 23:02:05 +0100 Subject: [PATCH 332/447] Update metajason file --- apps/smclock/metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index cce18a648..cc995d587 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -6,9 +6,10 @@ "screenshots": [{ "url": "screenshot.png" }], "version": "0.04", "description": "A simple watchface based on my stylised monogram.", + "type": "clock", "tags": "clock", "readme": "README.md", - "supports": ["BANGLEJS2"], + "supports": ["BANGLEJS", "BANGLEJS2"], "allow_emulator": true, "storage": [ { "name": "smclock.app.js", "url": "app.js" }, From bd8c89b538e86096ab0ae093b55888265215ddfa Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Thu, 3 Mar 2022 23:30:34 +0100 Subject: [PATCH 333/447] Fix issue with evaluating arrow output --- apps/smclock/app.js | 26 +++++++++++------------- apps/smclock/settings.js | 43 +++++++++++++++------------------------- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 223dd053a..4516ca9e5 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -27,24 +27,22 @@ const monthName = [ const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; // dynamic variables -let batLevel = -1; -let batColor = [0, 0, 0]; +var batLevel = -1; +var batColor = [0, 0, 0]; // settings variables -let dateFormat; -let drawInterval; -let pollInterval; -let showAnalogFace; -let showWeekInfo; -let useVectorFont; +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; - } - let settings = require("Storage").readJSON(SETTINGSFILE, true) || {}; + 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); @@ -99,7 +97,7 @@ function draw() { g.drawImage(background); const color = getBatteryColor(batLevel); - let bat = ""; + var bat = ""; const d = new Date(); const day = d.getDate(); const month = d.getMonth() + 1; @@ -152,7 +150,7 @@ pollBattery(); draw(); var batInterval = setInterval(pollBattery, 60000); -let actualDrawInterval = setInterval(draw, drawInterval * 1000); +var actualDrawInterval = setInterval(draw, drawInterval * 1000); // Stop updates when LCD is off, restart when on Bangle.on("lcdPower", (on) => { diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index 81c0a0af1..53ff974f3 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -3,36 +3,31 @@ // helper functions taken from Anton Clock (function (back) { - const FILE = "smclock.json"; + var FILE = "smclock.json"; // load settings from the file // assign default values if it doesn't exist - let settings = Object.assign( - { + var settings = Object.assign({ dateFormat: "Short", drawInterval: 10, pollInterval: 60, showAnalogFace: false, showWeekInfo: false, useVectorFont: false, - }, - require("Storage").readJSON(FILE, true) || {} - ); + }, require("Storage").readJSON(FILE, true) || {}); // write the new settings to the file - function writeSettings() { - require("Storage").writeJSON(FILE, settings); - } + 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], + format: v => values[v], min: 0, max: values.length - 1, wrap: true, step: 1, - onchange: (v) => { + onchange: v => { writer(values[v]); writeSettings(); }, @@ -46,15 +41,13 @@ // settings menu var mainmenu = { - "": { - title: "Monogram Clock", - }, + "": {title: "Monogram Clock",}, "< Back": () => back(), "Analog Face": { value: settings.showAnalogFace !== undefined ? settings.showAnalogFace : false, - format: (v) => (v ? "On" : "Off"), - onchange: (v) => { + format: v => v ? "On" : "Off", + onchange: v => { if (v == "On") { settings.showAnalogFace = true; } else { @@ -66,14 +59,14 @@ Date: stringInSettings("dateFormat", ["Long", "Short"]), "Draw Interval": { value: settings.drawInterval, - onchange: (v) => { + onchange: v => { settings.drawInterval = v; writeSettings(); }, }, "Poll Interval": { value: settings.pollInterval, - onchange: (v) => { + onchange: v => { settings.pollInterval = v; writeSettings(); }, @@ -81,8 +74,8 @@ "Week Info": { value: settings.showWeekInfo !== undefined ? settings.showWeekInfo : false, - format: (v) => (v ? "On" : "Off"), - onchange: (v) => { + format: v => v ? "On" : "Off", + onchange: v => { if (v == "On") { settings.showWeekInfo = true; } else { @@ -94,13 +87,9 @@ "Vector Font": { value: settings.useVectorFont !== undefined ? settings.useVectorFont : false, - format: (v) => (v ? "On" : "Off"), - onchange: (v) => { - if (v == "On") { - settings.useVectorFont = true; - } else { - settings.useVectorFont = false; - } + format: v => v ? "On" : "Off", + onchange: v => { + settings.useVectorFont = v; writeSettings(); }, }, From 46717acb3c1d764d3e2c4afde869434b442eeff6 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Fri, 4 Mar 2022 00:05:17 +0100 Subject: [PATCH 334/447] Add font support for battery info --- apps/smclock/app.js | 46 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 4516ca9e5..9630bb42e 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -10,20 +10,7 @@ const background = { ) ), }; -const monthName = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", -]; +const monthName = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; // dynamic variables @@ -116,8 +103,23 @@ function draw() { g.reset(); + // draw battery info + g.setColor(1, 1, 1); + 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]); + if (batLevel < 100) { + g.drawString(bat, 52, 22, false); + } else { + g.drawString(bat, 46, 22, false); + } + g.setColor(0, 0, 0); - console.log(useVectorFont, dateFormat); if (useVectorFont == true && dateFormat == "Short") { g.setFont("Vector", 20); } else { @@ -130,16 +132,6 @@ function draw() { 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); - g.setColor(color[0], color[1], color[2]); - if (batLevel < 100) { - g.drawString(bat, 52, 22, false); - } else { - g.drawString(bat, 46, 22, false); - } } loadSettings(); @@ -149,7 +141,7 @@ g.clear(); pollBattery(); draw(); -var batInterval = setInterval(pollBattery, 60000); +var batInterval = setInterval(pollBattery, pollInterval * 1000); var actualDrawInterval = setInterval(draw, drawInterval * 1000); // Stop updates when LCD is off, restart when on @@ -159,7 +151,7 @@ Bangle.on("lcdPower", (on) => { if (actualDrawInterval) clearInterval(actualDrawInterval); actualDrawInterval = undefined; if (on) { - batInterval = setInterval(pollBattery, 60000); + batInterval = setInterval(pollBattery, pollInterval * 1000); actualDrawInterval = setInterval(draw, drawInterval * 1000); pollBattery(); From 9664368caa3f76da80855cb2d67fc7416155d0f0 Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Fri, 4 Mar 2022 00:14:20 +0100 Subject: [PATCH 335/447] Add font support for time display --- apps/smclock/app.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 9630bb42e..cb7d2e3e9 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -129,9 +129,15 @@ function draw() { g.setFont("Vector", 16); g.drawString(date2, 105, 55, false); + // draw time g.setColor(1, 1, 1); - g.setFont("Vector", 60); - g.drawString(time, 10, 108, false); + 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(); From f89579ad6d98973e3daaf34a2a068ebd736c690b Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Fri, 4 Mar 2022 00:52:33 +0100 Subject: [PATCH 336/447] Add font support for date and week info --- apps/smclock/app.js | 37 +++++++++++++++++++++++++++++++------ apps/smclock/settings.js | 12 ++---------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index cb7d2e3e9..099fcad74 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -89,8 +89,8 @@ function draw() { const day = d.getDate(); 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); + const date1 = ""; + const date2 = ""; const h = d.getHours(); const m = d.getMinutes(); const time = d02(h) + ":" + d02(m); @@ -119,15 +119,40 @@ function draw() { g.drawString(bat, 46, 22, false); } + // draw date info g.setColor(0, 0, 0); - if (useVectorFont == true && dateFormat == "Short") { + if (useVectorFont == true) { g.setFont("Vector", 20); } else { g.setFont("6x8", 2); } - g.drawString(date1, 105, 20, false); - g.setFont("Vector", 16); - g.drawString(date2, 105, 55, false); + 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); diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index 53ff974f3..a6c7d1b98 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -48,11 +48,7 @@ settings.showAnalogFace !== undefined ? settings.showAnalogFace : false, format: v => v ? "On" : "Off", onchange: v => { - if (v == "On") { - settings.showAnalogFace = true; - } else { - settings.showAnalogFace = false; - } + settings.showAnalogFace = v; writeSettings(); }, }, @@ -76,11 +72,7 @@ settings.showWeekInfo !== undefined ? settings.showWeekInfo : false, format: v => v ? "On" : "Off", onchange: v => { - if (v == "On") { - settings.showWeekInfo = true; - } else { - settings.showWeekInfo = false; - } + settings.showWeekInfo = v; writeSettings(); }, }, From 0a798aa5e7e54403c417783ab11f3bb7b04837da Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Fri, 4 Mar 2022 01:03:49 +0100 Subject: [PATCH 337/447] Fix date variables --- apps/smclock/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index ebc3efde1..44037a7a7 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -94,8 +94,8 @@ function draw() { const day = d.getDate(); const month = d.getMonth() + 1; const week = d02(ISO8601_week_no(d)); - const date1 = ""; - const date2 = ""; + var date1 = ""; + var date2 = ""; const h = d.getHours(); const m = d.getMinutes(); const time = d02(h) + ":" + d02(m); From 7c46d95119a225302ed6cff17ae08e7e2819de7b Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Fri, 4 Mar 2022 01:06:14 +0100 Subject: [PATCH 338/447] Remove unnecessary merge info from changelog and metadata file --- apps/smclock/ChangeLog | 4 ---- apps/smclock/metadata.json | 13 ------------- 2 files changed, 17 deletions(-) diff --git a/apps/smclock/ChangeLog b/apps/smclock/ChangeLog index b09db0145..0300d5ceb 100644 --- a/apps/smclock/ChangeLog +++ b/apps/smclock/ChangeLog @@ -1,8 +1,4 @@ 0.01: Initial version 0.02: Add battery level -<<<<<<< HEAD -0.03: fix battery level displaying -======= 0.03: Fix battery display when full 0.04: Add support for settings ->>>>>>> feature/introduce_settings diff --git a/apps/smclock/metadata.json b/apps/smclock/metadata.json index 5918406d6..cc995d587 100644 --- a/apps/smclock/metadata.json +++ b/apps/smclock/metadata.json @@ -1,23 +1,10 @@ { -<<<<<<< HEAD - "id":"smclock", - "name":"Monogram Watch Face", - "shortName":"MonoClock", - "icon":"app.png", -<<<<<<< HEAD - "version":"0.03", -======= - "screenshots": [{"url":"screenshot.png"}], - "version":"0.02", ->>>>>>> 29432bb9 (Add screenshot) -======= "id": "smclock", "name": "Monogram Watch Face", "shortName": "MonoClock", "icon": "app.png", "screenshots": [{ "url": "screenshot.png" }], "version": "0.04", ->>>>>>> feature/introduce_settings "description": "A simple watchface based on my stylised monogram.", "type": "clock", "tags": "clock", From a4c76e3d3aaad674b35abe2efff809d7db2e612d Mon Sep 17 00:00:00 2001 From: Stergios Mekras Date: Fri, 4 Mar 2022 01:09:11 +0100 Subject: [PATCH 339/447] Remove unnecessary merge info from main app file --- apps/smclock/app.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/smclock/app.js b/apps/smclock/app.js index 44037a7a7..350c0dd07 100644 --- a/apps/smclock/app.js +++ b/apps/smclock/app.js @@ -83,13 +83,8 @@ function getBatteryColor(level) { function draw() { g.drawImage(background); -<<<<<<< HEAD - const color = getBatteryColor(); - const bat = E.getBattery() + "%"; -======= const color = getBatteryColor(batLevel); var bat = ""; ->>>>>>> feature/introduce_settings const d = new Date(); const day = d.getDate(); const month = d.getMonth() + 1; @@ -118,9 +113,6 @@ function draw() { g.drawString("Bat:", 10, 22, false); } g.setColor(color[0], color[1], color[2]); -<<<<<<< HEAD - g.drawString(bat, 46, 22, false); -======= if (batLevel < 100) { g.drawString(bat, 52, 22, false); } else { @@ -171,7 +163,6 @@ function draw() { g.setFont("6x8", 5); g.drawString(time, 14, 112, false); } ->>>>>>> feature/introduce_settings } loadSettings(); From 8dc3e8f8fcad22e379c7d8b59959c0c55d3fc6ed Mon Sep 17 00:00:00 2001 From: Joseph Paul Date: Fri, 4 Mar 2022 10:16:32 +0100 Subject: [PATCH 340/447] Ratchet Launcher: Initial version --- apps/ratchet_launch/ChangeLog | 1 + apps/ratchet_launch/README.md | 15 ++++ apps/ratchet_launch/app.js | 123 ++++++++++++++++++++++++++++++ apps/ratchet_launch/app.png | Bin 0 -> 9788 bytes apps/ratchet_launch/metadata.json | 16 ++++ 5 files changed, 155 insertions(+) create mode 100644 apps/ratchet_launch/ChangeLog create mode 100644 apps/ratchet_launch/README.md create mode 100644 apps/ratchet_launch/app.js create mode 100644 apps/ratchet_launch/app.png create mode 100644 apps/ratchet_launch/metadata.json diff --git a/apps/ratchet_launch/ChangeLog b/apps/ratchet_launch/ChangeLog new file mode 100644 index 000000000..af7f83942 --- /dev/null +++ b/apps/ratchet_launch/ChangeLog @@ -0,0 +1 @@ +0.01: Initial release diff --git a/apps/ratchet_launch/README.md b/apps/ratchet_launch/README.md new file mode 100644 index 000000000..15df463d0 --- /dev/null +++ b/apps/ratchet_launch/README.md @@ -0,0 +1,15 @@ +# Rachet Launcher + +Ratchet Launcher is a fork of the default Launcher with modified user interaction. Instead of free scrolling, apps are selected by swiping up and down, but in discrete "ticks", just like in the settings menus. + +**WARNING: Untested on Bangle.js v1! Please test and give feedback.** + +## Usage +- Choose app: Swipe up/down (top/bottom button on Bangle.js v1) +- Launch app: Tap screen (center button on Bangle.js v1) +- Return to clock: Swipe three ticks beyond first/last app in list + +## Installation +1. Install Ratchet Launcher using App Loader +2. Uninstall default Launcher +3. Reload diff --git a/apps/ratchet_launch/app.js b/apps/ratchet_launch/app.js new file mode 100644 index 000000000..626b8e4f8 --- /dev/null +++ b/apps/ratchet_launch/app.js @@ -0,0 +1,123 @@ +var Storage = require("Storage"); +var Layout = require("Layout"); + +var font = "6x15"; +var largeFont = "12x20"; +var currentApp = 0; +var overscroll = 0; +var blankImage = Graphics.createImage(` `); +var rowHeight = g.getHeight()/3; + +// Load apps list +var apps = Storage.list(/\.info$/).map(app=>{ + var a=Storage.readJSON(app,1); + return a&&{ + name:a.name, + type:a.type, + icon:a.icon ? Storage.read(a.icon) : a.icon, + sortorder:a.sortorder, + src:a.src + }; +}).filter(app=>app && ( + app.type=="app" +// || (app.type=="clock" && settings.showClocks) + || !app.type +)); +apps.sort((a,b)=>{ + var n=(0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.nameb.name) return 1; + return 0; +}); + +// Initialize layout +var layout = new Layout({ + type:"v", c:[ + // A row for the previous app + { type:"h", height:rowHeight, c:[ + {type: "img", id:"prev_icon", src:blankImage, width:48, height:48, scale:0.8, pad:8}, + {type: "txt", id:"prev_name", label:"", font:font, fillx:1, wrap:1}, + ]}, + // A row for the current app + { type:"h", height:rowHeight, c:[ + {type: "img", id:"cur_icon", src:apps[currentApp].icon, width:48, height:48}, + {type: "txt", id:"cur_name", label:apps[currentApp].name, font:largeFont, fillx:1, wrap:1}, + ]}, + // A row for the next app + { type:"h", height:rowHeight, c:[ + {type: "img", id:"next_icon", src:blankImage, width:48, height:48, scale:0.8, pad:8}, + {type: "txt", id:"next_name", label:"", font:font, fillx:1, wrap:1}, + ]}, + ] +}); + +// Drawing logic +function render() { + // Previous app + if (currentApp > 0) { + layout.prev_icon.src = apps[currentApp-1].icon; + layout.prev_name.label = apps[currentApp-1].name; + } else { + layout.prev_icon.src = blankImage; + layout.prev_name.label = ""; + } + + // Current app + layout.cur_icon.src = apps[currentApp].icon; + layout.cur_name.label = apps[currentApp].name; + + // Next app + if (currentApp < apps.length-1) { + layout.next_icon.src = apps[currentApp+1].icon; + layout.next_name.label = apps[currentApp+1].name; + } else { + layout.next_icon.src = blankImage; + layout.next_name.label = ""; + } + + g.clear(); + layout.render(); +} + +// Launch the currently selected app +function launch() { + var app = apps[currentApp]; + if (!app) return; + if (!app.src || Storage.read(app.src)===undefined) { + E.showMessage(/*LANG*/"App Source\nNot found"); + setTimeout(drawMenu, 2000); + } else { + E.showMessage(/*LANG*/"Loading..."); + load(app.src); + } +} + +// Select previous/next app +function move(step) { + if ((currentApp == 0 && step < 0) || (currentApp >= apps.length-1 && step > 0)) { + // When we hit the end of the list (top or bottom), the step is + // counted towards the overscroll value. When the overscroll + // threshold is exceeded, we return to the clock face. + overscroll += step; + } else { + // This is the default case: the step is countedf towards the currentApp index + currentApp += step; + overscroll = 0; + return render(); + } + + // Overscroll threshold reached, return to clock + if (Math.abs(overscroll) > 3) { + Bangle.buzz(500, 1); + return load(); + } +} + +// Wire up user input +Bangle.setUI('updown', dir => { + if (dir) move(-1*dir); + else launch(); +}); + +render(); diff --git a/apps/ratchet_launch/app.png b/apps/ratchet_launch/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a27ab48eda4d78d88a5d958e540b9bc822e2131c GIT binary patch literal 9788 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 cggb Date: Fri, 4 Mar 2022 12:31:30 +0100 Subject: [PATCH 341/447] Ratchet Launcher: Fix fonts and scrolling behaviour on Bangle.js 1 --- apps/ratchet_launch/app.js | 40 +++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/apps/ratchet_launch/app.js b/apps/ratchet_launch/app.js index 626b8e4f8..11018080a 100644 --- a/apps/ratchet_launch/app.js +++ b/apps/ratchet_launch/app.js @@ -1,8 +1,8 @@ var Storage = require("Storage"); var Layout = require("Layout"); -var font = "6x15"; -var largeFont = "12x20"; +var font = g.getFonts().includes("6x15") ? "6x15" : "6x8:2"; +var largeFont = g.getFonts().includes("12x20") ? "12x20" : "6x8:3"; var currentApp = 0; var overscroll = 0; var blankImage = Graphics.createImage(` `); @@ -31,6 +31,24 @@ apps.sort((a,b)=>{ return 0; }); +// Uncomment for testing in the emulator without apps: +// apps = [ +// { +// name:"Test", +// type:"app", +// icon:blankImage, +// sortorder:undefined, +// src:"" +// }, +// { +// name:"Test 2", +// type:"app", +// icon:blankImage, +// sortorder:undefined, +// src:"" +// }, +// ]; + // Initialize layout var layout = new Layout({ type:"v", c:[ @@ -41,8 +59,8 @@ var layout = new Layout({ ]}, // A row for the current app { type:"h", height:rowHeight, c:[ - {type: "img", id:"cur_icon", src:apps[currentApp].icon, width:48, height:48}, - {type: "txt", id:"cur_name", label:apps[currentApp].name, font:largeFont, fillx:1, wrap:1}, + {type: "img", id:"cur_icon", src:blankImage, width:48, height:48}, + {type: "txt", id:"cur_name", label:"", font:largeFont, fillx:1, wrap:1}, ]}, // A row for the next app { type:"h", height:rowHeight, c:[ @@ -54,6 +72,11 @@ var layout = new Layout({ // Drawing logic function render() { + if (!apps.length) { + E.showMessage(/*LANG*/"No apps"); + return load(); + } + // Previous app if (currentApp > 0) { layout.prev_icon.src = apps[currentApp-1].icon; @@ -86,7 +109,7 @@ function launch() { if (!app) return; if (!app.src || Storage.read(app.src)===undefined) { E.showMessage(/*LANG*/"App Source\nNot found"); - setTimeout(drawMenu, 2000); + setTimeout(render, 2000); } else { E.showMessage(/*LANG*/"Loading..."); load(app.src); @@ -116,8 +139,11 @@ function move(step) { // Wire up user input Bangle.setUI('updown', dir => { - if (dir) move(-1*dir); - else launch(); + if (!dir) launch(); + else { + if (process.env.HWVERSION==2) dir *= -1; // "natural scrolling" on touch screen + move(dir); + } }); render(); From 371d78c49b18ac0e09c3734735f1c3dd97db8103 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 09:24:59 +0100 Subject: [PATCH 342/447] Create ChangeLog --- apps/clockcal/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/clockcal/ChangeLog diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/clockcal/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From 9ed37056234a169ed85aff0cf25891ae713b3807 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 09:26:40 +0100 Subject: [PATCH 343/447] Add files via upload --- apps/clockcal/ChangeLog | 10 ++ apps/clockcal/README.md | 79 ++++++++++++ apps/clockcal/app-icon.js | 1 + apps/clockcal/app.js | 230 +++++++++++++++++++++++++++++++++++ apps/clockcal/app.png | Bin 0 -> 1989 bytes apps/clockcal/metadata.json | 19 +++ apps/clockcal/screenshot.png | Bin 0 -> 1617 bytes apps/clockcal/settings.js | 107 ++++++++++++++++ 8 files changed, 446 insertions(+) create mode 100644 apps/clockcal/README.md create mode 100644 apps/clockcal/app-icon.js create mode 100644 apps/clockcal/app.js create mode 100644 apps/clockcal/app.png create mode 100644 apps/clockcal/metadata.json create mode 100644 apps/clockcal/screenshot.png create mode 100644 apps/clockcal/settings.js diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index 5560f00bc..ac49dcbd7 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -1 +1,11 @@ 0.01: New App! +0.02: Load widgets after setUI so widclk knows when to hide +0.03: Clock now shows day of week under date. +0.04: Clock can optionally show seconds, date optionally in ISO-8601 format, weekdays and uppercase configurable, too. +0.05: Clock can optionally show ISO-8601 calendar weeknumber (default: Off) + when weekday name "Off": week #: + when weekday name "On": weekday name is cut at 6th position and .# is added +0.06: fixes #1271 - wrong settings name + when weekday name and calendar weeknumber are on then display is # + week is buffered until date or timezone changes +0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) \ No newline at end of file diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md new file mode 100644 index 000000000..28a38f5fd --- /dev/null +++ b/apps/clockcal/README.md @@ -0,0 +1,79 @@ +# Anton Clock - Large font digital watch with seconds and date + +Anton clock uses the "Anton" bold font to show the time in a clear, easily readable manner. On the Bangle.js 2, the time can be read easily even if the screen is locked and unlit. + +## Features + +The basic time representation only shows hours and minutes of the current time. However, Anton clock can show additional information: + +* Seconds can be shown, either always or only if the screen is unlocked. +* To help easy recognition, the seconds can be coloured in blue on the Bangle.js 2. +* Date can be shown in three different formats: + * ISO-8601: 2021-12-19 + * short local format: 19/12/2021, 19.12.2021 + * long local format: DEC 19 2021 +* Weekday can be shown (on seconds screen only instead of year) + +## Usage + +Install Anton clock through the Bangle.js app loader. +Configure it through the default Bangle.js configuration mechanism +(Settings app, "Apps" menu, "Anton clock" submenu). +If you like it, make it your default watch face +(Settings app, "System" menu, "Clock" submenu, select "Anton clock"). + +## Configuration + +Anton clock is configured by the standard settings mechanism of Bangle.js's operating system: +Open the "Settings" app, then the "Apps" submenu and below it the "Anton clock" menu. +You configure Anton clock through several "on/off" switches in two menus. + +### The main menu + +The main menu contains several settings covering Anton clock in general. + +* **Seconds...** - Opens the submenu for configuring the presentation of the current time's seconds. +* **Date** - Format of the date representation. Possible values are + * **Long** - "Long" date format in the current locale. Usually with the month as name, not number. + * **Short** - "Short" date format in the current locale. Usually with the month as number. + * **ISO8601** - Show the date in ISO-8601 format (YYYY-MM-DD), irrespective of the current locale. +* **Show Weekday** - Weekday is shown in the time presentation without seconds. +Weekday name depends on the current locale. +If seconds are shown, the weekday is never shown as there is not enough space on the watch face. +* **Show CalWeek** - Week-number (ISO-8601) is shown. (default: Off) +If "Show Weekday" is "Off" displays the week-number as "week #". +If "Show Weekday" is "On" displays "weekday name short" with " #" . +If seconds are shown, the week number is never shown as there is not enough space on the watch face. +* **Vector font** - Use the built-in vector font for dates and weekday. +This can improve readability. +Otherwise, a scaled version of the built-in 6x8 pixels font is used. + +### The "Seconds" submenu + +The "Seconds" submenu configures how (and if) seconds are shown on the "Anton" watch face. + +* **Show** - Configure when the seconds should be shown at all: + * **Never** - Seconds are never shown. +In this case, hour and minute are a bit more centered on the screen and the clock will always only update every minute. +This saves battery power. + * **Unlocked** - Seconds are shown if the display is unlocked. +On locked displays, only hour, minutes, date and optionally the weekday are shown. +_This option is highly recommended on the Bangle.js 2!_ + * **Always** - Seconds are _always_ shown, irrespective of the display's unlock state. +_Enabling this option increases power consumption as the watch face will update once per second instead of once per minute._ +* **With ":"** - If enabled, a colon ":" is prepended to the seconds. +This resembles the usual time representation "hh:mm:ss", even though the seconds are printed on a separate line. +* **Color** - If enabled, seconds are shown in blue instead of black. +If the date is shown on the seconds screen, it is colored read instead of black. +This make the visual orientation much easier on the watch face. +* **Date** - It is possible to show the date together with the seconds: + * **No** - Date is _not_ shown in the seconds screen. +In this case, the seconds are centered below hour and minute. + * **Year** - Date is shown with day, month, and year. If "Date" in the main settings is configured to _ISO8601_, this is used here, too. Otherwise, the short local format is used. + * **Weekday** - Date is shown with day, month, and weekday. + +The date is coloured in red if the "Coloured" option is chosen. + +## Compatibility + +Anton clock makes use of core Bangle.js 2 features (coloured display, display lock state). It also runs on the Bangle.js 1 but these features are not available there due to hardware restrictions. diff --git a/apps/clockcal/app-icon.js b/apps/clockcal/app-icon.js new file mode 100644 index 000000000..fad03d50f --- /dev/null +++ b/apps/clockcal/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js new file mode 100644 index 000000000..356e067f2 --- /dev/null +++ b/apps/clockcal/app.js @@ -0,0 +1,230 @@ +// Clock with large digits using the "Anton" bold font + +const SETTINGSFILE = "clockcal.json"; + +Graphics.prototype.setFontAnton = function(scale) { + // Actual height 69 (68 - 0) + g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16)); +}; + +Graphics.prototype.setFontAntonSmall = function(scale) { + // Actual height 53 (52 - 0) + g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAAAAAAAAAAAAAMAAAAAAAAD8AAAAAAAA/8AAAAAAAf/8AAAAAAH//8AAAAAB///8AAAAA////8AAAAP////8AAAD/////8AAB//////8AAf//////8AH///////4A///////+AA///////AAA//////wAAA/////8AAAA////+AAAAA////gAAAAA///4AAAAAA//8AAAAAAA//AAAAAAAA/wAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/////wAAA//////8AAB//////+AAH///////gAH///////gAP///////wAf///////4Af///////4A////////8A////////8A////////8A//AAAAD/8A/8AAAAA/8A/8AAAAA/8A/8AAAAA/8A/+AAAAB/8A////////8A////////8A////////8Af///////4Af///////4AP///////wAP///////wAH///////gAD///////AAA//////8AAAP/////wAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAAA/4AAAAAAAA/4AAAAAAAB/wAAAAAAAB/wAAAAAAAD/wAAAAAAAD/gAAAAAAAH///////8AP///////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAP8AA//4AAA/8AB//4AAH/8AH//4AAP/8AP//4AA//8AP//4AB//8Af//4AD//8Af//4AP//8A///4Af//8A///4A///8A///4D///8A//AAH///8A/8AAP///8A/8AA//+/8A/8AD//8/8A/+Af//w/8A//////g/8A/////+A/8A/////8A/8Af////4A/8Af////wA/8AP////AA/8AP///+AA/8AH///8AA/8AD///wAA/8AA///AAA/8AAP/4AAA/8AAAAAAAAAAAAAAAAAAAAAAH4AAf/gAAA/4AAf/8AAD/4AAf//AAH/4AAf//gAP/4AAf//wAP/4AAf//wAf/4AAf//4Af/4AAf//4A//4AAf//8A//4AAf//8A//4AAP//8A//A/8AB/8A/8A/8AA/8A/8B/8AA/8A/8B/8AA/8A/+D//AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////gAH//9////gAD//4///+AAB//wf//4AAAP/AH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAB//wAAAAAAP//wAAAAAD///wAAAAA////wAAAAH////wAAAB/////wAAAf/////wAAD//////wAA///////wAA/////h/wAA////wB/wAA///8AB/wAA///AAB/wAA//gAAB/wAA////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AA////4P/+AA////4P//AA////4P//gA////4P//wA////4P//wA////4P//4A////4P//4A////4P//8A////4P//8A////4P//8A/8H/AAB/8A/8H+AAA/8A/8P+AAA/8A/8P+AAA/8A/8P/gAD/8A/8P/////8A/8P/////8A/8P/////8A/8P/////4A/8H/////4A/8H/////wA/8D/////wA/8B/////gA/8A////+AA/8AP///4AAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////wAAAf/////8AAB///////AAH///////gAP///////wAP///////wAf///////4Af///////4A////////8A////////8A////////8A/+AH/AB/8A/8AP+AA/8A/4Af+AA/8A/8Af+AA/8A/8Af/gH/8A//4f////8A//4f////8A//4f////8Af/4f////4Af/4f////4AP/4P////wAP/4P////gAH/4H////AAD/4D///+AAB/4B///4AAAP4AP//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAA/8AAAAAAAA/8AAAAAB8A/8AAAAB/8A/8AAAAf/8A/8AAAH//8A/8AAA///8A/8AAH///8A/8AA////8A/8AD////8A/8Af////8A/8B/////8A/8P/////8A/8//////8A////////AA///////AAA//////gAAA/////4AAAA/////AAAAA////4AAAAA////AAAAAA///8AAAAAA///gAAAAAA//+AAAAAAA//wAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gD//gAAA//4P//8AAD//8f///AAH//+////gAH///////wAP///////4AP///////8Af///////8Af///////+Af///////+A////////+A//B//AB/+A/+A/+AA/+A/8Af+AA/+A/+Af+AA/+A//A//AB/+A////////+Af///////+Af///////+Af///////8Af///////8AP///////4AH///////4AH//+////wAD//+////AAA//4P//+AAAP/gH//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAfgAAA///8A/8AAB///+A//AAH////A//gAH////g//wAP////g//wAf////w//4Af////w//4A/////w//8A/////w//8A/////w//8A//gP/wA/8A/8AD/wA/8A/8AD/wAf8A/8AD/gA/8A/+AH/AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////wAH///////gAD//////+AAA//////4AAAP/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DhgeFB4eHh4eHh4eDw=="), 60 + (scale << 8) + (1 << 16)); +}; + +// variables defined from settings +var secondsMode; +var secondsColoured; +var secondsWithColon; +var dateOnMain; +var dateOnSecs; +var weekDay; +var calWeek; +var upperCase; +var vectorFont; + +// dynamic variables +var drawTimeout; +var queueMillis = 1000; +var secondsScreen = true; + +var isBangle1 = (process.env.HWVERSION == 1); + +//For development purposes +/* +require('Storage').writeJSON(SETTINGSFILE, { + secondsMode: "Unlocked", // "Never", "Unlocked", "Always" + secondsColoured: true, + secondsWithColon: true, + dateOnMain: "Long", // "Short", "Long", "ISO8601" + dateOnSecs: "Year", // "No", "Year", "Weekday", LEGACY: true/false + weekDay: true, + calWeek: true, + upperCase: true, + vectorFont: true, +}); +*/ + +// OR (also for development purposes) +/* +require('Storage').erase(SETTINGSFILE); +*/ + +// Load settings +function loadSettings() { + // Helper function default setting + function def (value, def) {return value !== undefined ? value : def;} + + var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; + secondsMode = def(settings.secondsMode, "Never"); + secondsColoured = def(settings.secondsColoured, true); + secondsWithColon = def(settings.secondsWithColon, true); + dateOnMain = def(settings.dateOnMain, "Long"); + dateOnSecs = def(settings.dateOnSecs, "Year"); + weekDay = def(settings.weekDay, true); + calWeek = def(settings.calWeek, false); + upperCase = def(settings.upperCase, true); + vectorFont = def(settings.vectorFont, false); + + // Legacy + if (dateOnSecs === true) + dateOnSecs = "Year"; + if (dateOnSecs === false) + dateOnSecs = "No"; +} + +// schedule a draw for the next second or minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, queueMillis - (Date.now() % queueMillis)); +} + +function updateState() { + if (Bangle.isLCDOn()) { + if ((secondsMode === "Unlocked" && !Bangle.isLocked()) || secondsMode === "Always") { + secondsScreen = true; + queueMillis = 1000; + } else { + secondsScreen = false; + queueMillis = 60000; + } + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +} + +function isoStr(date) { + return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).substr(-2) + "-" + ("0" + date.getDate()).substr(-2); +} + +var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) +function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 + dateNoTime = date; dateNoTime.setHours(0,0,0,0); + if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2]; + calWeekBuffer[0] = date.getTimezoneOffset(); + calWeekBuffer[1] = dateNoTime; + 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); + } + calWeekBuffer[2] = 1 + Math.ceil((firstThursday - tdt) / 604800000); + return calWeekBuffer[2]; +} + +function doColor() { + return !isBangle1 && !Bangle.isLocked() && secondsColoured; +} + +// Actually draw the watch face +function draw() { + var x = g.getWidth() / 2; + var y = g.getHeight() / 2 - (secondsMode !== "Never" ? 24 : (vectorFont ? 12 : 0)); + g.reset(); + /* This is to mark the widget areas during development. + g.setColor("#888") + .fillRect(0, 0, g.getWidth(), 23) + .fillRect(0, g.getHeight() - 23, g.getWidth(), g.getHeight()).reset(); + /* */ + g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24); // clear whole background (w/o widgets) + var date = new Date(); // Actually the current date, this one is shown + var timeStr = require("locale").time(date, 1); // Hour and minute + g.setFontAlign(0, 0).setFont("Anton").drawString(timeStr, x, y); // draw time + if (secondsScreen) { + y += 65; + var secStr = (secondsWithColon ? ":" : "") + ("0" + date.getSeconds()).substr(-2); + if (doColor()) + g.setColor(0, 0, 1); + g.setFont("AntonSmall"); + if (dateOnSecs !== "No") { // A bit of a complex drawing with seconds on the right and date on the left + g.setFontAlign(1, 0).drawString(secStr, g.getWidth() - (isBangle1 ? 32 : 2), y); // seconds + y -= (vectorFont ? 15 : 13); + x = g.getWidth() / 4 + (isBangle1 ? 12 : 4) + (secondsWithColon ? 0 : g.stringWidth(":") / 2); + var dateStr2 = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, 1)); + var year; + var md; + var yearfirst; + if (dateStr2.match(/\d\d\d\d$/)) { // formatted date ends with year + year = (dateOnSecs === "Year" ? dateStr2.slice(-4) : require("locale").dow(date, 1)); + md = dateStr2.slice(0, -4); + if (!md.endsWith(".")) // keep separator before the year only if it is a dot (31.12. but 31/12) + md = md.slice(0, -1); + yearfirst = false; + } else { // formatted date begins with year + if (!dateStr2.match(/^\d\d\d\d/)) // if year position cannot be detected... + dateStr2 = isoStr(date); // ...use ISO date format instead + year = (dateOnSecs === "Year" ? dateStr2.slice(0, 4) : require("locale").dow(date, 1)); + md = dateStr2.slice(5); // never keep separator directly after year + yearfirst = true; + } + if (dateOnSecs === "Weekday" && upperCase) + year = year.toUpperCase(); + g.setFontAlign(0, 0); + if (vectorFont) + g.setFont("Vector", 24); + else + g.setFont("6x8", 2); + if (doColor()) + g.setColor(1, 0, 0); + g.drawString(md, x, (yearfirst ? y + (vectorFont ? 26 : 16) : y)); + g.drawString(year, x, (yearfirst ? y : y + (vectorFont ? 26 : 16))); + } else { + g.setFontAlign(0, 0).drawString(secStr, x, y); // Just the seconds centered + } + } else { // No seconds screen: Show date and optionally day of week + y += (vectorFont ? 50 : (secondsMode !== "Never") ? 52 : 40); + var dateStr = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, (dateOnMain === "Long" ? 0 : 1))); + if (upperCase) + dateStr = dateStr.toUpperCase(); + g.setFontAlign(0, 0); + if (vectorFont) + g.setFont("Vector", 24); + else + g.setFont("6x8", 2); + g.drawString(dateStr, x, y); + if (calWeek || weekDay) { + var dowcwStr = ""; + if (calWeek) + dowcwStr = " #" + ("0" + ISO8601calWeek(date)).substring(-2); + if (weekDay) + dowcwStr = require("locale").dow(date, calWeek ? 1 : 0) + dowcwStr; //weekDay e.g. Monday or weekDayShort # e.g. Mon #01 + else //week #01 + dowcwStr = /*LANG*/"week" + dowcwStr; + if (upperCase) + dowcwStr = dowcwStr.toUpperCase(); + g.drawString(dowcwStr, x, y + (vectorFont ? 26 : 16)); + } + } + + // queue next draw + queueDraw(); +} + +// Init the settings of the app +loadSettings(); +// Clear the screen once, at startup +g.clear(); +// Set dynamic state and perform initial drawing +updateState(); +// Register hooks for LCD on/off event and screen lock on/off event +Bangle.on('lcdPower', on => { + updateState(); +}); +Bangle.on('lock', on => { + updateState(); +}); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// end of file \ No newline at end of file diff --git a/apps/clockcal/app.png b/apps/clockcal/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a38093c5f3b6f88dbc9b75017422dbe237d4407f GIT binary patch literal 1989 zcmV;$2RitPP)jLx_$n|!#a_+a7!4?Zj*KoBI+mq8Z8#{*+o z7DHwNZgKLU(NGK;MJHm2(2Z3wlN9^G$Dl3PLZR*L$JxWF_g-#q5pXO%?4OgH|2gM( z&iUPY&i~`w2to*6Cz0Salm7|*Pv});Rk#kH&o?nKVKf?JV`CKxgR&1SYr2-&`UyG$k%PDI4SU@#m$e3%a_DJdBl84(40z238D&kClk zs;Y82oqX8o)29U(i^UQ;n+PGB&6b*)8u|?i3JT`t=0fr3&YhD;M7F-UxtYZ<46||L z#$^(^di83!ed+D(C4@{&Ojs-yi^VcGH|KCTl9H16n23l7R(HGIbWWX4$8TSNkjR^L zcXzY8Ua#-%?PaT@qoV@@0~H&dOV(ykrCQkT3X65OnG@Zi=UX7pvt31 zj}{pcL)2{nR~LU?!AoakWJE?r@;{iv;h@Tm8#ky@Q&Y1{D-)+L zk?;ux0)h4G*YjJ(#>Q^nzRiCh09LE@!i5U}3JVKgYOOCJ6uR+Sw{CU2-NC`D<_&Lc zZ7nJ)ve|63T3A>ZA0H23aBz^e?A^OJbi$<(>ged0o}Lzbr0D2qQLxA3VcF#5df&c%%k%pC z_wR3NYGVEE(W6Hhh8Y?fqAfC+OyD3EODH`({lS9=J9q8`AeBm6T3YzMGcz-7ZEYHj zMx)V~&1Q$gG4w*>jhws#}m#f8yXryC+C~U z`1tsuqP^K{Rw|XD3shHEi{?XpeSM+eoSYo1)w(dD#ik#GkY~@Hm6eqVUYB7Q5=Ndr zeOgynw`b2D8Znxin?>0WLatxGUQtm|QBiU7#}wE{v` zE79qQ-%ki34hQ+;590L_Ldfha>Fp)d!~y~G@F9PBpO089!Qyrkhl5){BH^9@$<8K( zknwSGHUObsMZ!iMoIj7rNmN(E>qSis+-{VX!tckAKO!Om1qJYW@$I*me+7H^5OR62 z3=ZN&Qctf5g8}2?{1^qN6CZvUtlqoFPd{WbR8}H06H+N04!rjsKKcl1 zHT-^*mm?zsDJcj9aOMowuALuH=N;9*{^ImQhp>7z6pDG^{(i2SkbpPdKwMlnD;pTV zci*9=hFgSsgt0MHSEIZfVy=i!h!F4{kf=Wi^-z~Cfu=;}wcszLg7?YD27=Y7B$L-n$w>wz2ZCjda2n2$gD3L&|#yjuu z2}MPrp#d%zrl%1bi`-l|95{0Zk&&pa4elc$u-j2t3A-JBKOHBPB04%)Buo62QdtSL z8t=akwHjq*n3-7tKg75Bwl+ctsi@#u^m@|L64uIo{WZ*0`actu3LkvHRe$=4-LlzP zG&h4@(OoVyHR0!>Q z7SEqkLVx}VyB!`6&AgGFjjSwOzRV5%{dYK>@c97X&K-RDB~&Whx&>fx5P5mX%|&i5 zES9AaijKycZ{po|gH^j7J|8vvUAr(f#a_qZa-p>qnVHb*(cO)YKgK7YfW2`_r7##U zGXuN*KZ*8JQ)q0&kt0Y?hs%Wn2Ovn)Km8PaeXKu8NC11$U9)D%%lmw+13^*}qN6FH z-+sfTOGr$_fdjDHVKCt4O^lA>^Up#50d{oY$`u$4$j*jDf}1ztbmFV80BqTUEnC3* z|HA1lEy&D-(a5<(Lh$z69KdWwOblM!|B#xBHEXEZd%eW%CT=(JdO4k+urdq>AVk>9 z6Q`5N<>FSIpHBh-Vlss_`<9lKNk2L}#ngwjPIdq7ye|T3ar}q0{vjtPwx88zODg-bLj7E4oP%5!@EeCk*lKg)F X^{k9p7{Urq00000NkvXXu0mjf6Vk;2 literal 0 HcmV?d00001 diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json new file mode 100644 index 000000000..9c20dca22 --- /dev/null +++ b/apps/clockcal/metadata.json @@ -0,0 +1,19 @@ +{ + "id": "clockcal", + "name": "clockcal Clock", + "version": "0.07", + "description": "A clockcal.", + "readme":"README.md", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"clockcal.app.js","url":"app.js"}, + {"name":"clockcal.settings.js","url":"settings.js"}, + {"name":"clockcal.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"clockcal.json"}] +} diff --git a/apps/clockcal/screenshot.png b/apps/clockcal/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e949b8a24a4eac5cbd8f8a01ffdd57b3660b939c GIT binary patch literal 1617 zcmV-X2Cn&uP)Q+S zK~#9!?VZUMqaYAPh2#JKvc1UZv~4tDs0p}l)q??3Tx$R!={SxJp})$Q0G+jC0!O8^ zZQJ(gqtoj@Omqnmc!(%iMD!3(V3KEOKA>AlTS_;6Lfh=O!<|dqR0_rLj7-Gw6Z=mp zp~2Trq^-sN$JXdw$RVuLh2YN@K!k`6Pvr(ctjI(h8vf-F??mA#V@N4cYlvqI5okD% z_;DP$JZ&Vq6!#OKe-2k=TnY^!SWV;*Zso@9p8;ZB8eWb#)U4Ef$av?E#0za2E;*)4 zGQr|jEE>MgPlWIg$fmf6shtWlvgg=3Rwde#%EB2ZCZ_CZaPtrhc0d|j{4_}=iN*gE z;u{bi0>vmhZ-Zhq7gZR!WpBGPT@bvP-QB*I3%vNK9g^4e^95YR9HNJMOGEc3^PP9= zeghUcMCX@GDcKZVBE6X1?T|^OpmnsZEZhDZOytNWR<$zI^OT+HG&D3DjmtcxmFGik zJRnpJL9i!eED?_aqL~>jBoBmvl^IAI?bAQ&EayfCLS!S5jl)pgvlP?kIp+`qJ-$`9 zI&Of=#-z_m07)eU0ze=`xV`)nKp=oXp~_BD#mLDJ9wK5fE z#1PK_NhKK)K)?h*keQkSK^pPXNsQt-Sls%7_-cz=S=@s2k+GEj%NkD=(Y+yF1hHNY zWjJb$33G_!II4DCYVYQgVzm5w4K066RQR$vmhmvwd4`4jP#6?u^o~J0xM5rioBqe!IzMMdoTw=&lVajkJ9GY z9%3vj6NW58##mMs+_FIqF^QG?w{A|BqPlI=31#Jm8=kdPNzu*-4r1ur+g_nwO_pDB zSt|nsBB?|GfdB#l1Of;I5C{PT`Vi+s2Euz_W#>-KgN-VUDq z#UUT`_r2FnJ@tTi{%rF%-L<}@?8QSJM06gQ<1o7S3rWrW=F(^C@-1(NO7CJ^d6bax zGyqiu-d<&OgG88Z zc)oUMn41Z;kO2*Z3{U_Fzw*!ML@7qRGi00};%0N+<~AZNBToysfdB#l1d`Ps5P#0|K}m9Y P00000NkvXXu0mjfUbx{% literal 0 HcmV?d00001 diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js new file mode 100644 index 000000000..a69cab556 --- /dev/null +++ b/apps/clockcal/settings.js @@ -0,0 +1,107 @@ +// Settings menu for the enhanced Anton clock + +(function(back) { + var FILE = "clockcal.json"; + // Load settings + var settings = Object.assign({ + secondsOnUnlock: false, + }, require('Storage').readJSON(FILE, true) || {}); + + 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); + } + + var mainmenu = { + "": { + "title": "clockcal clock" + }, + "< Back": () => back(), + "Seconds...": () => E.showMenu(secmenu), + "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), + "Show Weekday": { + value: (settings.weekDay !== undefined ? settings.weekDay : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.weekDay = v; + writeSettings(); + } + }, + "Show CalWeek": { + value: (settings.calWeek !== undefined ? settings.calWeek : false), + format: v => v ? "On" : "Off", + onchange: v => { + settings.calWeek = v; + writeSettings(); + } + }, + "Uppercase": { + value: (settings.upperCase !== undefined ? settings.upperCase : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.upperCase = v; + writeSettings(); + } + }, + "Vector font": { + value: (settings.vectorFont !== undefined ? settings.vectorFont : false), + format: v => v ? "On" : "Off", + onchange: v => { + settings.vectorFont = v; + writeSettings(); + } + }, + }; + + // Submenu + var secmenu = { + "": { + "title": "Show seconds..." + }, + "< Back": () => E.showMenu(mainmenu), + "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), + "With \":\"": { + value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.secondsWithColon = v; + writeSettings(); + } + }, + "Color": { + value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.secondsColoured = v; + writeSettings(); + } + }, + "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) + }; + + // Actually display the menu + E.showMenu(mainmenu); + +}); + +// end of file From a9f857cd7f9b80729562d9af5f1b191bfe87b3eb Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:37:35 +0100 Subject: [PATCH 344/447] Update app.js --- apps/clockcal/app.js | 345 +++++++++++++++---------------------------- 1 file changed, 117 insertions(+), 228 deletions(-) diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js index 356e067f2..fc299912f 100644 --- a/apps/clockcal/app.js +++ b/apps/clockcal/app.js @@ -1,230 +1,119 @@ -// Clock with large digits using the "Anton" bold font - -const SETTINGSFILE = "clockcal.json"; - -Graphics.prototype.setFontAnton = function(scale) { - // Actual height 69 (68 - 0) - g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16)); -}; - -Graphics.prototype.setFontAntonSmall = function(scale) { - // Actual height 53 (52 - 0) - g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAAAAAAAAAAAAAMAAAAAAAAD8AAAAAAAA/8AAAAAAAf/8AAAAAAH//8AAAAAB///8AAAAA////8AAAAP////8AAAD/////8AAB//////8AAf//////8AH///////4A///////+AA///////AAA//////wAAA/////8AAAA////+AAAAA////gAAAAA///4AAAAAA//8AAAAAAA//AAAAAAAA/wAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/////wAAA//////8AAB//////+AAH///////gAH///////gAP///////wAf///////4Af///////4A////////8A////////8A////////8A//AAAAD/8A/8AAAAA/8A/8AAAAA/8A/8AAAAA/8A/+AAAAB/8A////////8A////////8A////////8Af///////4Af///////4AP///////wAP///////wAH///////gAD///////AAA//////8AAAP/////wAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAAA/4AAAAAAAA/4AAAAAAAB/wAAAAAAAB/wAAAAAAAD/wAAAAAAAD/gAAAAAAAH///////8AP///////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAP8AA//4AAA/8AB//4AAH/8AH//4AAP/8AP//4AA//8AP//4AB//8Af//4AD//8Af//4AP//8A///4Af//8A///4A///8A///4D///8A//AAH///8A/8AAP///8A/8AA//+/8A/8AD//8/8A/+Af//w/8A//////g/8A/////+A/8A/////8A/8Af////4A/8Af////wA/8AP////AA/8AP///+AA/8AH///8AA/8AD///wAA/8AA///AAA/8AAP/4AAA/8AAAAAAAAAAAAAAAAAAAAAAH4AAf/gAAA/4AAf/8AAD/4AAf//AAH/4AAf//gAP/4AAf//wAP/4AAf//wAf/4AAf//4Af/4AAf//4A//4AAf//8A//4AAf//8A//4AAP//8A//A/8AB/8A/8A/8AA/8A/8B/8AA/8A/8B/8AA/8A/+D//AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////gAH//9////gAD//4///+AAB//wf//4AAAP/AH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAB//wAAAAAAP//wAAAAAD///wAAAAA////wAAAAH////wAAAB/////wAAAf/////wAAD//////wAA///////wAA/////h/wAA////wB/wAA///8AB/wAA///AAB/wAA//gAAB/wAA////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AA////4P/+AA////4P//AA////4P//gA////4P//wA////4P//wA////4P//4A////4P//4A////4P//8A////4P//8A////4P//8A/8H/AAB/8A/8H+AAA/8A/8P+AAA/8A/8P+AAA/8A/8P/gAD/8A/8P/////8A/8P/////8A/8P/////8A/8P/////4A/8H/////4A/8H/////wA/8D/////wA/8B/////gA/8A////+AA/8AP///4AAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////wAAAf/////8AAB///////AAH///////gAP///////wAP///////wAf///////4Af///////4A////////8A////////8A////////8A/+AH/AB/8A/8AP+AA/8A/4Af+AA/8A/8Af+AA/8A/8Af/gH/8A//4f////8A//4f////8A//4f////8Af/4f////4Af/4f////4AP/4P////wAP/4P////gAH/4H////AAD/4D///+AAB/4B///4AAAP4AP//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAA/8AAAAAAAA/8AAAAAB8A/8AAAAB/8A/8AAAAf/8A/8AAAH//8A/8AAA///8A/8AAH///8A/8AA////8A/8AD////8A/8Af////8A/8B/////8A/8P/////8A/8//////8A////////AA///////AAA//////gAAA/////4AAAA/////AAAAA////4AAAAA////AAAAAA///8AAAAAA///gAAAAAA//+AAAAAAA//wAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gD//gAAA//4P//8AAD//8f///AAH//+////gAH///////wAP///////4AP///////8Af///////8Af///////+Af///////+A////////+A//B//AB/+A/+A/+AA/+A/8Af+AA/+A/+Af+AA/+A//A//AB/+A////////+Af///////+Af///////+Af///////8Af///////8AP///////4AH///////4AH//+////wAD//+////AAA//4P//+AAAP/gH//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAfgAAA///8A/8AAB///+A//AAH////A//gAH////g//wAP////g//wAf////w//4Af////w//4A/////w//8A/////w//8A/////w//8A//gP/wA/8A/8AD/wA/8A/8AD/wAf8A/8AD/gA/8A/+AH/AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////wAH///////gAD//////+AAA//////4AAAP/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DhgeFB4eHh4eHh4eDw=="), 60 + (scale << 8) + (1 << 16)); -}; - -// variables defined from settings -var secondsMode; -var secondsColoured; -var secondsWithColon; -var dateOnMain; -var dateOnSecs; -var weekDay; -var calWeek; -var upperCase; -var vectorFont; - -// dynamic variables -var drawTimeout; -var queueMillis = 1000; -var secondsScreen = true; - -var isBangle1 = (process.env.HWVERSION == 1); - -//For development purposes -/* -require('Storage').writeJSON(SETTINGSFILE, { - secondsMode: "Unlocked", // "Never", "Unlocked", "Always" - secondsColoured: true, - secondsWithColon: true, - dateOnMain: "Long", // "Short", "Long", "ISO8601" - dateOnSecs: "Year", // "No", "Year", "Weekday", LEGACY: true/false - weekDay: true, - calWeek: true, - upperCase: true, - vectorFont: true, -}); -*/ - -// OR (also for development purposes) -/* -require('Storage').erase(SETTINGSFILE); -*/ - -// Load settings -function loadSettings() { - // Helper function default setting - function def (value, def) {return value !== undefined ? value : def;} - - var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; - secondsMode = def(settings.secondsMode, "Never"); - secondsColoured = def(settings.secondsColoured, true); - secondsWithColon = def(settings.secondsWithColon, true); - dateOnMain = def(settings.dateOnMain, "Long"); - dateOnSecs = def(settings.dateOnSecs, "Year"); - weekDay = def(settings.weekDay, true); - calWeek = def(settings.calWeek, false); - upperCase = def(settings.upperCase, true); - vectorFont = def(settings.vectorFont, false); - - // Legacy - if (dateOnSecs === true) - dateOnSecs = "Year"; - if (dateOnSecs === false) - dateOnSecs = "No"; -} - -// schedule a draw for the next second or minute -function queueDraw() { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - draw(); - }, queueMillis - (Date.now() % queueMillis)); -} - -function updateState() { - if (Bangle.isLCDOn()) { - if ((secondsMode === "Unlocked" && !Bangle.isLocked()) || secondsMode === "Always") { - secondsScreen = true; - queueMillis = 1000; - } else { - secondsScreen = false; - queueMillis = 60000; - } - draw(); // draw immediately, queue redraw - } else { // stop draw timer - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; - } -} - -function isoStr(date) { - return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).substr(-2) + "-" + ("0" + date.getDate()).substr(-2); -} - -var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) -function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 - dateNoTime = date; dateNoTime.setHours(0,0,0,0); - if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2]; - calWeekBuffer[0] = date.getTimezoneOffset(); - calWeekBuffer[1] = dateNoTime; - 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); - } - calWeekBuffer[2] = 1 + Math.ceil((firstThursday - tdt) / 604800000); - return calWeekBuffer[2]; -} - -function doColor() { - return !isBangle1 && !Bangle.isLocked() && secondsColoured; -} - -// Actually draw the watch face -function draw() { - var x = g.getWidth() / 2; - var y = g.getHeight() / 2 - (secondsMode !== "Never" ? 24 : (vectorFont ? 12 : 0)); - g.reset(); - /* This is to mark the widget areas during development. - g.setColor("#888") - .fillRect(0, 0, g.getWidth(), 23) - .fillRect(0, g.getHeight() - 23, g.getWidth(), g.getHeight()).reset(); - /* */ - g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24); // clear whole background (w/o widgets) - var date = new Date(); // Actually the current date, this one is shown - var timeStr = require("locale").time(date, 1); // Hour and minute - g.setFontAlign(0, 0).setFont("Anton").drawString(timeStr, x, y); // draw time - if (secondsScreen) { - y += 65; - var secStr = (secondsWithColon ? ":" : "") + ("0" + date.getSeconds()).substr(-2); - if (doColor()) - g.setColor(0, 0, 1); - g.setFont("AntonSmall"); - if (dateOnSecs !== "No") { // A bit of a complex drawing with seconds on the right and date on the left - g.setFontAlign(1, 0).drawString(secStr, g.getWidth() - (isBangle1 ? 32 : 2), y); // seconds - y -= (vectorFont ? 15 : 13); - x = g.getWidth() / 4 + (isBangle1 ? 12 : 4) + (secondsWithColon ? 0 : g.stringWidth(":") / 2); - var dateStr2 = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, 1)); - var year; - var md; - var yearfirst; - if (dateStr2.match(/\d\d\d\d$/)) { // formatted date ends with year - year = (dateOnSecs === "Year" ? dateStr2.slice(-4) : require("locale").dow(date, 1)); - md = dateStr2.slice(0, -4); - if (!md.endsWith(".")) // keep separator before the year only if it is a dot (31.12. but 31/12) - md = md.slice(0, -1); - yearfirst = false; - } else { // formatted date begins with year - if (!dateStr2.match(/^\d\d\d\d/)) // if year position cannot be detected... - dateStr2 = isoStr(date); // ...use ISO date format instead - year = (dateOnSecs === "Year" ? dateStr2.slice(0, 4) : require("locale").dow(date, 1)); - md = dateStr2.slice(5); // never keep separator directly after year - yearfirst = true; - } - if (dateOnSecs === "Weekday" && upperCase) - year = year.toUpperCase(); - g.setFontAlign(0, 0); - if (vectorFont) - g.setFont("Vector", 24); - else - g.setFont("6x8", 2); - if (doColor()) - g.setColor(1, 0, 0); - g.drawString(md, x, (yearfirst ? y + (vectorFont ? 26 : 16) : y)); - g.drawString(year, x, (yearfirst ? y : y + (vectorFont ? 26 : 16))); - } else { - g.setFontAlign(0, 0).drawString(secStr, x, y); // Just the seconds centered - } - } else { // No seconds screen: Show date and optionally day of week - y += (vectorFont ? 50 : (secondsMode !== "Never") ? 52 : 40); - var dateStr = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, (dateOnMain === "Long" ? 0 : 1))); - if (upperCase) - dateStr = dateStr.toUpperCase(); - g.setFontAlign(0, 0); - if (vectorFont) - g.setFont("Vector", 24); - else - g.setFont("6x8", 2); - g.drawString(dateStr, x, y); - if (calWeek || weekDay) { - var dowcwStr = ""; - if (calWeek) - dowcwStr = " #" + ("0" + ISO8601calWeek(date)).substring(-2); - if (weekDay) - dowcwStr = require("locale").dow(date, calWeek ? 1 : 0) + dowcwStr; //weekDay e.g. Monday or weekDayShort # e.g. Mon #01 - else //week #01 - dowcwStr = /*LANG*/"week" + dowcwStr; - if (upperCase) - dowcwStr = dowcwStr.toUpperCase(); - g.drawString(dowcwStr, x, y + (vectorFont ? 26 : 16)); - } - } - - // queue next draw - queueDraw(); -} - -// Init the settings of the app -loadSettings(); -// Clear the screen once, at startup -g.clear(); -// Set dynamic state and perform initial drawing -updateState(); -// Register hooks for LCD on/off event and screen lock on/off event -Bangle.on('lcdPower', on => { - updateState(); -}); -Bangle.on('lock', on => { - updateState(); -}); -// Show launcher when middle button pressed -Bangle.setUI("clock"); -// Load widgets Bangle.loadWidgets(); -Bangle.drawWidgets(); -// end of file \ No newline at end of file +var s = Object.assign({ + CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. Will be extra widget eventually + MODE24: true, //24h mode vs 12h mode + FIRSTDAYOFFSET: 6, //First day of the week: 0-6: Sun, Sat, Fri, Thu, Wed, Tue, Mon + REDSUN: true, // Use red color for sunday? + REDSAT: true, // Use red color for saturday? +}, require('Storage').readJSON("clockcal.json", true) || {}); + +const h = g.getHeight(); +const w = g.getWidth(); +const CELL_W = w / 7; +const CELL_H = 15; +const CAL_Y = h - s.CAL_ROWS * CELL_H; +const DEBUG = false; + +function drawMinutes() { + if (DEBUG) console.log("|-->minutes"); + var d = new Date(); + var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' '); + var minutes = d.getMinutes().toString().padStart(2, '0'); + var textColor = NRF.getSecurityStatus().connected ? '#fff' : '#f00'; + var size = 50; + var clock_x = (w - 20) / 2; + if (dimSeconds) { + size = 65; + clock_x = 4 + (w / 2); + } + g.setBgColor(0); + g.setColor(textColor); + g.setFont("Vector", size); + g.setFontAlign(0, 1); + g.drawString(hours + ":" + minutes, clock_x, CAL_Y - 10, 1); + var nextminute = (61 - d.getSeconds()); + if (typeof minuteInterval !== "undefined") clearTimeout(minuteInterval); + minuteInterval = setTimeout(drawMinutes, nextminute * 1000); +} + +function drawSeconds() { + if (DEBUG) console.log("|--->seconds"); + var d = new Date(); + g.setColor(); + g.fillRect(w - 31, CAL_Y - 36, w - 3, CAL_Y - 19); + g.setBgColor(0); + g.setColor('#fff'); + g.setFont("Vector", 24); + g.setFontAlign(1, 1); + g.drawString(" " + d.getSeconds().toString().padStart(2, '0'), w, CAL_Y - 13); + if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); + if (!dimSeconds) secondInterval = setTimeout(drawSeconds, 1000); +} + +function drawCalendar() { + if (DEBUG) console.log("CALENDAR"); + var d = new Date(); + g.reset(); + g.setBgColor(0); + g.clear(); + drawMinutes(); + if (!dimSeconds) drawSeconds(); + const dow = (s.FIRSTDAYOFFSET + d.getDay()) % 7; //MO=0, SU=6 + const today = d.getDate(); + var rD = new Date(d.getTime()); + rD.setDate(rD.getDate() - dow); + var rDate = rD.getDate(); + g.setFontAlign(1, 1); + for (var y = 1; y <= s.CAL_ROWS; y++) { + for (var x = 1; x <= 7; x++) { + bottomrightX = x * CELL_W - 2; + bottomrightY = y * CELL_H + CAL_Y; + g.setFont("Vector", 16); + var fg = ((s.REDSUN && rD.getDay() == 0) || (s.REDSAT && rD.getDay() == 6)) ? '#f00' : '#fff'; + if (y == 1 && today == rDate) { + g.setColor('#0f0'); + g.fillRect(bottomrightX - CELL_W + 1, bottomrightY - CELL_H - 1, bottomrightX, bottomrightY - 2); + g.setColor('#000'); + g.drawString(rDate, bottomrightX, bottomrightY); + } + else { + g.setColor(fg); + g.drawString(rDate, bottomrightX, bottomrightY); + } + rD.setDate(rDate + 1); + rDate = rD.getDate(); + } + } + Bangle.drawWidgets(); + + var nextday = (3600 * 24) - (d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds() + 1); + if (DEBUG) console.log("Next Day:" + (nextday / 3600)); + if (typeof dayInterval !== "undefined") clearTimeout(dayInterval); + dayInterval = setTimeout(drawCalendar, nextday * 1000); +} + +function BTevent() { + drawMinutes(); + if (s.BUZZ_ON_BT) { + var interval = (NRF.getSecurityStatus().connected) ? 100 : 500; + Bangle.buzz(interval); + setTimeout(function () { Bangle.buzz(interval); }, interval * 3); + } +} + +//register events +Bangle.on('lock', locked => { + if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); + dimSeconds = locked; //dim seconds if lock=on + drawCalendar(); +}); +NRF.on('connect', BTevent); +NRF.on('disconnect', BTevent); + + +dimSeconds = Bangle.isLocked(); +drawCalendar(); + +Bangle.setUI("clock"); From d1c6f59c28a1008ea0a62c9c5e54e798af2a635a Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:39:09 +0100 Subject: [PATCH 345/447] Add files via upload --- apps/clockcal/app.png | Bin 1989 -> 3396 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/clockcal/app.png b/apps/clockcal/app.png index a38093c5f3b6f88dbc9b75017422dbe237d4407f..2e2e4461e0ed2e9c7052ab5347e8cc771792b650 100644 GIT binary patch literal 3396 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 KMNUMnLSTaLT**rS From 6ccbe2e030d7ba58bce6019772dce0903a03b42e Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:42:07 +0100 Subject: [PATCH 346/447] Add files via upload --- apps/clockcal/screenshot.png | Bin 1617 -> 2826 bytes apps/clockcal/screenshot2.png | Bin 0 -> 2811 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/clockcal/screenshot2.png diff --git a/apps/clockcal/screenshot.png b/apps/clockcal/screenshot.png index e949b8a24a4eac5cbd8f8a01ffdd57b3660b939c..fcfde0c4abced61bbca0643cedfb597925db3b34 100644 GIT binary patch literal 2826 zcmb`J_gfNb8^xK*aS+Pc0I_Q#~wXXLM-NG1PBSAy{N8Uc+82jJGW}iVzdN5 zw7vv@m%>tmjo$XY?=Tt-0F_0_7K?m7c=UNtxbo@j70K$hgh;n^faMWUXiH@C;SOV= zt3~Kf?#R}|JY~^kA$?=jHF)0#Lfmc5$uigELm9w}{2;#t0+|X3q`vxnc=i9?vJdcF zs!?3?C z?5NEBD={xWzhJZ#9uY~c{T6Vh(O_{fR?UC8=tlGd>4Dyfdt3tiM?Y$xYfG;&~YpQR43>=r_8eUTr=twbe2(qhpP;l{F zrUB>3ZEP{y{pK~LZG~$eLG>c-a%p z8@^H!4N_6WFSc*KA(?rlV|f8s>bV#_)nu5N^sJu?5uHqeFr<0DI-5DSC=xCSz-A4F z!Wdok&2#kfSP=-pv2FTc_I|^%oT)@%{w%I1J6ni%VubP7n(Z?x3V#@f#LhNo5hpMdYelbFk(~(~Q|jj{|_h ze1(KJ1pZGr|5G_p;+mKFJn4`={=;tL@druknD?QAwHm8$7hN_|hj8?0iPUQQ&uepN ze9*!Pw(5R3(MrHJ8zb2t-zycf?z6H$pKmL~_*%2ds8=^`UGs~&m%O|>n*_5W6+ih; z9k2hC&QDbyS@m*BYXr(*oPb#2L~>3$96SWt^xKfDY|GjycO)XLE%xgC?l8%nAG^S_ zr#tR1SBtiwU%%R8YpM)`>AXCjF6Q9ZAl!_9>2xiWwp*UlSG7M^*q!~ke=X65ByR6C zx+my7To9QheD%eBwCP4nX)H2JQp?P_j;s>~f0RJ^cFTwJPO)BdW7n1SdJa;(UcnZ# zbJVN-iUG|PjXlbw3}4)_E@R>>JwXQfHauL*pW@4MByHVq&1GMwm_v>Kv8t9UuDa>K zF0D7*=r{}~V^&uE1V_aNsJ(@1}74&$ab6tl6slOROp?w)9XVRqq{30Y0Y*&u+ycCH`PX#H&q{1bn9^5 z%^8g0Na#K(y4Z?JpWX2M5*~pHd645S)GpkR{wPB0G--i5_6m|o^1r}E?z@Qxd?9{6 zl_Hxj4bjMc;4$VtkWX^E@*Y}9Hm&-^9Mhh(J3c%yq&Pkz9Ml$x0gWNO{wOf0HN5cG z7;pzS(|&j~Jwl&gx5+D z8}gJPMRPtMH$1*djmlyoIp-a-PJ4tJN&$jVHCpNbCH`A(yLaT=;;Fz%+?$;+ln;j_ zQa*3_v~phH*4R~px85{|7F%7Ec$5~eS&c|m#R<MY zsdOkSRzp3M)^Rwf33sgzQ&&2D?_es{eSZo!)al1=@|Def`zFiR=%$Uw$204Mx(WU& zO+~e(I1ZGtP>sTp##+5DW_X)2m*<)d_Wim!->VLuE#VJ5LG%l*7GUf4U}*H~FWv~V zp4^wK(z^wHE?q`t zzdpM}fsRHSc6f5$u@oa+uqpZdq%G?NoZ=1hsd9mU-^cP(cg+d@i`FNt$qUikzhZYK#K3#6&8W}xxZxcebL&16|WoY(NffDJ} z9-IaBS{#1%tMc&Yl+vCmKZIFbH#rTVucy^=Ri$&rqM-mHO-ThE6sHQnD6SI9y{h}4 zn6JOEu;B;cYZd46c$u?5h|aLL_D3h>Ek~TTqeA+`w3sJ%dx{lM(6iqcU<9#s1GC|- zKT;b}amxx0q&)6}57XP(UwNK^%T#VqZ{`jtA+y-xSV*5#cVITNp~{5kyIQH6|7}=z z;0vJ)hm{ZvWox2IdCvlw4iqF+7uqnu#flc@=KeZV(qPKk?WDl?|5pIg+z!!TicR@1x`9ZN delta 1611 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 T<=j3=!wNvyyV}**;%@v0LX%Et literal 0 HcmV?d00001 From 9a451d2b5521492d565f0fb708a610de56aefb45 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:43:48 +0100 Subject: [PATCH 347/447] Add files via upload --- apps/clockcal/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/clockcal/app-icon.js b/apps/clockcal/app-icon.js index fad03d50f..5bab7853e 100644 --- a/apps/clockcal/app-icon.js +++ b/apps/clockcal/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) +require("heatshrink").decompress(atob("mEwwkECqMCkQACiEDkIXQuUnkUBkESiYXPgN/u8jgEx/8vC6E3k9xiH//8/C6BHCPQMSL6EDO4cgaf4A/ACEC+YFDl4FEAAM/+ISHbIIECh4FB+QWEA4PwCQsfC4gVBkYGDgP/mQ4CCQk/iAXEAQTiCgMiDQQSFiATDBgQXCgILBEQkQBwYrEC4sPLQRpCBwoXECgUCC4oSBAggXHNQRfDV4X/JgQXJBIIXFgYuDC5QKBiE/C4f/bwgXJmanGJgoSDiTQBmQMBE4JYBfwJ5BBYMiYQISEB4IAB+KdCAgfwAwTrCn4SDiczAAMwGwMTmR0CmECBgRSBCQwA/AGsBgEQAgYABAwcHu93s4GBqAXEmLrCiYICmICBj4XEgvABIMMqECiIXCgQXCegLYBC4NwF4VcAQNV4EPkEhF4REBgYXCiQvCu4UCAQMFJYRfKgxGBuxfGLgkjFgMCkMBmEjgEigZaBI4XFMYcRC4kBmRhBkMQgI5DF4MFgAXCLARfCFoIvDkZmBhnF4sA5gvDYghfEHIQJDAAhQBIAPwVQMTgQvCNIMhAwJfBR4MMU4JRB+RJBiUQgUDVwMgYwMBgcwX4amBqBQBiTqBgUQh8RmJhCL4IvC4HMR4ZaEAgIBBL4LBDL5EBmI5BkQvBXwIGBmMPMwMvkEFR4VcR4UgU4MSC4UQmIJBn7dBiQNBqoXBPYNQh8Q+MB+MvgEvG4JyBj8A+RkBhlQd4ZHBiBYCL4bBELxEAA==")) \ No newline at end of file From feb78c0704f1f9d7aa0a2b0ccf3e99d9c846a62d Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:44:45 +0100 Subject: [PATCH 348/447] Update ChangeLog --- apps/clockcal/ChangeLog | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index ac49dcbd7..e874c8c67 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -1,11 +1 @@ -0.01: New App! -0.02: Load widgets after setUI so widclk knows when to hide -0.03: Clock now shows day of week under date. -0.04: Clock can optionally show seconds, date optionally in ISO-8601 format, weekdays and uppercase configurable, too. -0.05: Clock can optionally show ISO-8601 calendar weeknumber (default: Off) - when weekday name "Off": week #: - when weekday name "On": weekday name is cut at 6th position and .# is added -0.06: fixes #1271 - wrong settings name - when weekday name and calendar weeknumber are on then display is # - week is buffered until date or timezone changes -0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) \ No newline at end of file +0.01: Initial upload From 7027baea542ddc3687f9a16c5f17ab5ee3a5b01c Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:45:41 +0100 Subject: [PATCH 349/447] Update README.md --- apps/clockcal/README.md | 92 ++++++++--------------------------------- 1 file changed, 17 insertions(+), 75 deletions(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index 28a38f5fd..cf6fa6ed9 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -1,79 +1,21 @@ -# Anton Clock - Large font digital watch with seconds and date +# Clock & Calendar by Michael -Anton clock uses the "Anton" bold font to show the time in a clear, easily readable manner. On the Bangle.js 2, the time can be read easily even if the screen is locked and unlit. +This is my "Hello World". I first made this watchface almost 10 years ago for my original Pebble and Pebble Time and I missed this so much, that I had to write it for the BangleJS2. +I know that it seems redundant because there already **is** a *time&cal*-app, but it didn't fit my style. -## Features +- locked screen with only one minimal update/minute +- ![locked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot.png) +- unlocked screen (twist?) with seconds +- ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot2.png) -The basic time representation only shows hours and minutes of the current time. However, Anton clock can show additional information: +## Configurable Features +- Number of calendar rows (weeks) +- Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is a configurable setting) +- Clock Mode (24h/12h). Doesn't have an am/pm indicator, because I don't really care. It's configurable because it was easy. +- First day of the week +- Red Saturday +- Red Sunday -* Seconds can be shown, either always or only if the screen is unlocked. -* To help easy recognition, the seconds can be coloured in blue on the Bangle.js 2. -* Date can be shown in three different formats: - * ISO-8601: 2021-12-19 - * short local format: 19/12/2021, 19.12.2021 - * long local format: DEC 19 2021 -* Weekday can be shown (on seconds screen only instead of year) - -## Usage - -Install Anton clock through the Bangle.js app loader. -Configure it through the default Bangle.js configuration mechanism -(Settings app, "Apps" menu, "Anton clock" submenu). -If you like it, make it your default watch face -(Settings app, "System" menu, "Clock" submenu, select "Anton clock"). - -## Configuration - -Anton clock is configured by the standard settings mechanism of Bangle.js's operating system: -Open the "Settings" app, then the "Apps" submenu and below it the "Anton clock" menu. -You configure Anton clock through several "on/off" switches in two menus. - -### The main menu - -The main menu contains several settings covering Anton clock in general. - -* **Seconds...** - Opens the submenu for configuring the presentation of the current time's seconds. -* **Date** - Format of the date representation. Possible values are - * **Long** - "Long" date format in the current locale. Usually with the month as name, not number. - * **Short** - "Short" date format in the current locale. Usually with the month as number. - * **ISO8601** - Show the date in ISO-8601 format (YYYY-MM-DD), irrespective of the current locale. -* **Show Weekday** - Weekday is shown in the time presentation without seconds. -Weekday name depends on the current locale. -If seconds are shown, the weekday is never shown as there is not enough space on the watch face. -* **Show CalWeek** - Week-number (ISO-8601) is shown. (default: Off) -If "Show Weekday" is "Off" displays the week-number as "week #". -If "Show Weekday" is "On" displays "weekday name short" with " #" . -If seconds are shown, the week number is never shown as there is not enough space on the watch face. -* **Vector font** - Use the built-in vector font for dates and weekday. -This can improve readability. -Otherwise, a scaled version of the built-in 6x8 pixels font is used. - -### The "Seconds" submenu - -The "Seconds" submenu configures how (and if) seconds are shown on the "Anton" watch face. - -* **Show** - Configure when the seconds should be shown at all: - * **Never** - Seconds are never shown. -In this case, hour and minute are a bit more centered on the screen and the clock will always only update every minute. -This saves battery power. - * **Unlocked** - Seconds are shown if the display is unlocked. -On locked displays, only hour, minutes, date and optionally the weekday are shown. -_This option is highly recommended on the Bangle.js 2!_ - * **Always** - Seconds are _always_ shown, irrespective of the display's unlock state. -_Enabling this option increases power consumption as the watch face will update once per second instead of once per minute._ -* **With ":"** - If enabled, a colon ":" is prepended to the seconds. -This resembles the usual time representation "hh:mm:ss", even though the seconds are printed on a separate line. -* **Color** - If enabled, seconds are shown in blue instead of black. -If the date is shown on the seconds screen, it is colored read instead of black. -This make the visual orientation much easier on the watch face. -* **Date** - It is possible to show the date together with the seconds: - * **No** - Date is _not_ shown in the seconds screen. -In this case, the seconds are centered below hour and minute. - * **Year** - Date is shown with day, month, and year. If "Date" in the main settings is configured to _ISO8601_, this is used here, too. Otherwise, the short local format is used. - * **Weekday** - Date is shown with day, month, and weekday. - -The date is coloured in red if the "Coloured" option is chosen. - -## Compatibility - -Anton clock makes use of core Bangle.js 2 features (coloured display, display lock state). It also runs on the Bangle.js 1 but these features are not available there due to hardware restrictions. +## Feedback +The clock works for me in a 24h/MondayFirst/WeekendFree environment but is not well-tested with other settings. +So if something isn't working, please tell me. From ae221a9cd7cd890d00e33b0beb0b1b4828363f7b Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:46:56 +0100 Subject: [PATCH 350/447] Update settings.js --- apps/clockcal/settings.js | 191 ++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 103 deletions(-) diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index a69cab556..cc2a78181 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -1,107 +1,92 @@ -// Settings menu for the enhanced Anton clock +(function (back) { + var FILE = "clockcal.json"; -(function(back) { - var FILE = "clockcal.json"; - // Load settings - var settings = Object.assign({ - secondsOnUnlock: false, - }, require('Storage').readJSON(FILE, true) || {}); + settings = Object.assign({ + CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. Will be extra widget eventually + MODE24: true, //24h mode vs 12h mode + FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su + REDSUN: true, // Use red color for sunday? + REDSAT: true, // Use red color for saturday? + }, require('Storage').readJSON(FILE, true) || {}); - 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(); - } - }; - } + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } - // 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); - } - - var mainmenu = { - "": { - "title": "clockcal clock" - }, - "< Back": () => back(), - "Seconds...": () => E.showMenu(secmenu), - "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), - "Show Weekday": { - value: (settings.weekDay !== undefined ? settings.weekDay : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.weekDay = v; - writeSettings(); - } - }, - "Show CalWeek": { - value: (settings.calWeek !== undefined ? settings.calWeek : false), - format: v => v ? "On" : "Off", - onchange: v => { - settings.calWeek = v; - writeSettings(); - } - }, - "Uppercase": { - value: (settings.upperCase !== undefined ? settings.upperCase : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.upperCase = v; - writeSettings(); - } - }, - "Vector font": { - value: (settings.vectorFont !== undefined ? settings.vectorFont : false), - format: v => v ? "On" : "Off", - onchange: v => { - settings.vectorFont = v; - writeSettings(); - } - }, - }; - - // Submenu - var secmenu = { - "": { - "title": "Show seconds..." - }, - "< Back": () => E.showMenu(mainmenu), - "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), - "With \":\"": { - value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.secondsWithColon = v; - writeSettings(); - } - }, - "Color": { - value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.secondsColoured = v; - writeSettings(); - } - }, - "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) - }; - - // Actually display the menu - E.showMenu(mainmenu); - -}); - -// end of file + menu = { + "": { "title": "Clock & Calendar" }, + "< Back": () => back(), + 'Buzz(dis)conn.?': { + value: settings.BUZZ_ON_BT, + format: v => v ? "On" : "Off", + onchange: v => { + settings.BUZZ_ON_BT = v; + writeSettings(); + } + }, + '#Calendar Rows': { + value: settings.CAL_ROWS, + min: 0, max: 6, + onchange: v => { + settings.CAL_ROWS = v; + writeSettings(); + } + }, + 'Clock mode': { + value: settings.MODE24, + format: v => v ? "24h" : "12h", + onchange: v => { + settings.MODE24 = v; + writeSettings(); + } + }, + 'First Day': { + value: settings.FIRSTDAY, + min: 0, max: 6, + format: v => ["Sun", "Sat", "Fri", "Thu", "Wed", "Tue", "Mon"][v], + onchange: v => { + settings.FIRSTDAY = v; + writeSettings(); + } + }, + 'Red Saturday?': { + value: settings.REDSAT, + format: v => v ? "On" : "Off", + onchange: v => { + settings.REDSAT = v; + writeSettings(); + } + }, + 'Red Sunday?': { + value: settings.REDSUN, + format: v => v ? "On" : "Off", + onchange: v => { + settings.REDSUN = v; + writeSettings(); + } + }, + 'Load deafauls?': { + value: 0, + min: 0, max: 1, + format: v => ["No", "Yes"][v], + onchange: v => { + if (v == 1) { + settings = { + CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. + MODE24: true, //24h mode vs 12h mode + FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su + REDSUN: true, // Use red color for sunday? + REDSAT: true, // Use red color for saturday? + }; + writeSettings(); + load() + } + } + }, + } + // Show the menu + E.showMenu(menu); +}) From 2f47070e11d6ad5ee7213dae9b072348a3b25416 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:48:42 +0100 Subject: [PATCH 351/447] Update metadata.json --- apps/clockcal/metadata.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index 9c20dca22..ccc84a980 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,11 +1,11 @@ { "id": "clockcal", - "name": "clockcal Clock", - "version": "0.07", - "description": "A clockcal.", + "name": "Clock & Calendar", + "version": "0.01", + "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"}], "type": "clock", "tags": "clock", "supports": ["BANGLEJS","BANGLEJS2"], From 6ae1498eac545d563e50ade6841d905cc73e160c Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:53:17 +0100 Subject: [PATCH 352/447] Update README.md --- apps/clockcal/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index cf6fa6ed9..b37fbeaa4 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -18,4 +18,4 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu ## Feedback The clock works for me in a 24h/MondayFirst/WeekendFree environment but is not well-tested with other settings. -So if something isn't working, please tell me. +So if something isn't working, please tell me: https://github.com/foostuff/BangleApps/issues From d91a7a68e44f57bdb7a39076f6d0913f82b7871d Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 12:04:47 +0100 Subject: [PATCH 353/447] Update README.md --- apps/clockcal/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index b37fbeaa4..c19ee54a6 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -10,8 +10,8 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu ## Configurable Features - Number of calendar rows (weeks) -- Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is a configurable setting) -- Clock Mode (24h/12h). Doesn't have an am/pm indicator, because I don't really care. It's configurable because it was easy. +- Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is included) +- Clock Mode (24h/12h). Doesn't have an am/pm indicator. It's only there because it was easy. - First day of the week - Red Saturday - Red Sunday From aebc8bb3d505c5ebe78891865c8e647733ca5513 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 28 Feb 2022 23:54:27 -0600 Subject: [PATCH 354/447] Initial commit --- apps/locale/locales.js | 1 + apps/run/ChangeLog | 1 + apps/run/README.md | 8 +++----- apps/run/app.js | 14 ++++++++------ apps/run/metadata.json | 5 +++-- apps/run/settings.js | 24 +++++++++++++++--------- modules/Layout.js | 2 +- modules/exstats.js | 18 +++++++++--------- 8 files changed, 41 insertions(+), 32 deletions(-) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 073f4903f..dd650d7d7 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -110,6 +110,7 @@ var locales = { int_curr_symbol: "INR", speed: 'kmh', distance: { "0": "m", "1": "km" }, + paceLength: 1000, temperature: '°C', ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index 0d61aa789..bd478c12e 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -6,3 +6,4 @@ 0.05: exstats updated so update 'distance' label is updated, option for 'speed' 0.06: Add option to record a run using the recorder app automatically 0.07: Fix crash if an odd number of active boxes are configured (fix #1473) +0.08: Support all stats from exstats \ No newline at end of file diff --git a/apps/run/README.md b/apps/run/README.md index 5b3bb635a..11d41d4bd 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -13,7 +13,7 @@ the red `STOP` in the bottom right turns to a green `RUN`. the GPS updates your position as it gets more satellites your position changes and the distance shown will increase, even if you are standing still. * `TIME` - the elapsed time for your run -* `PACE` - the number of minutes it takes you to run a kilometer **based on your run so far** +* `PACE` - the number of minutes it takes you to run a given distance, configured in settings (default 1km) **based on your run so far** * `HEART` - Your heart rate * `STEPS` - Steps since you started exercising * `CADENCE` - Steps per second based on your step rate *over the last minute* @@ -24,9 +24,8 @@ so if you have no GPS lock you just need to wait. ## Recording Tracks -`Run` doesn't directly allow you to record your tracks at the moment. -However you can just install the `Recorder` app, turn recording on in -that, and then start the `Run` app. +`Run` depends on the `Recorder` app and it will be installed automatically. +Starting and stopping a run will automatically start and stop recordings with the `Recorder` app. ## Settings @@ -41,7 +40,6 @@ record GPS/HRM/etc data every time you start a run? ## TODO -* Allow this app to trigger the `Recorder` app on and off directly. * Keep a log of each run's stats (distance/steps/etc) ## Development diff --git a/apps/run/app.js b/apps/run/app.js index bc1d54de2..fc8869fa7 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -1,5 +1,5 @@ var ExStats = require("exstats"); -var B2 = process.env.HWVERSION==2; +var B2 = process.env.HWVERSION===2; var Layout = require("Layout"); var locale = require("locale"); var fontHeading = "6x8:2"; @@ -18,12 +18,14 @@ let settings = Object.assign({ B1 : "dist", B2 : "time", B3 : "pacea", - B4 : "bpm", - B5 : "step", - B6 : "caden", + B4 : "pacec", + B5 : "bpm", + B6 : "step", + B7 : "caden", + B8 : "speed", paceLength : 1000 }, require("Storage").readJSON("run.json", 1) || {}); -var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!=""); +var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); // --------------------------- @@ -88,7 +90,7 @@ layout.render(); Bangle.on("GPS", function(fix) { layout.gps.bgCol = fix.fix ? "#0f0" : "#f00"; if (!fix.fix) return; // only process actual fixes - if (fixCount++ == 0) { + if (fixCount++ === 0) { Bangle.buzz(); // first fix, does not need to respect quiet mode } }); diff --git a/apps/run/metadata.json b/apps/run/metadata.json index 7aabf8b53..f256aefa4 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.07", + "version":"0.08", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", @@ -12,5 +12,6 @@ {"name":"run.img","url":"app-icon.js","evaluate":true}, {"name":"run.settings.js","url":"settings.js"} ], - "data": [{"name":"run.json"}] + "data": [{"name":"run.json"}], + "dependencies" : { "messages":"recorder" } } diff --git a/apps/run/settings.js b/apps/run/settings.js index 7eb8a8611..aaf834214 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -9,14 +9,18 @@ // This way saved values are preserved if a new version adds more settings const storage = require('Storage') let settings = Object.assign({ - record : true, - B1 : "dist", - B2 : "time", - B3 : "pacea", - B4 : "bpm", - B5 : "step", - B6 : "caden", - paceLength : 1000 + record: true, + B1: "dist", + B2: "time", + B3: "pacea", + B4: "pacec", + B5: "bpm", + B6: "step", + B7: "caden", + B8: "speed", + paceLength: 1000, + notify: false, + }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -24,7 +28,7 @@ function getBoxChooser(boxID) { return { - min :0, max: statsIDs.length-1, + min: 0, max: statsIDs.length-1, value: Math.max(statsIDs.indexOf(settings[boxID]),0), format: v => statsList[v].name, onchange: v => { @@ -55,6 +59,8 @@ 'Box 4': getBoxChooser("B4"), 'Box 5': getBoxChooser("B5"), 'Box 6': getBoxChooser("B6"), + 'Box 7': getBoxChooser("B7"), + 'Box 8': getBoxChooser("B8"), }); E.showMenu(menu); }) diff --git a/modules/Layout.js b/modules/Layout.js index 4223867a4..20fa2be8b 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2022 Bangle.js contibutors. See the file LICENSE for copying permission. */ +/* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */ /* Take a look at README.md for hints on developing with this library. diff --git a/modules/exstats.js b/modules/exstats.js index b72ee6584..c2a4bfb9e 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2022 Bangle.js contibutors. See the file LICENSE for copying permission. */ +/* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */ /* Exercise Stats module Take a look at README.md for hints on developing with this library. @@ -69,10 +69,10 @@ var stats = {}; // distance between 2 lat and lons, in meters, Mean Earth Radius = 6371km // https://www.movable-type.co.uk/scripts/latlong.html +// (Equirectangular approximation) function calcDistance(a,b) { - function radians(a) { return a*Math.PI/180; } - var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2)); - var y = radians(b.lat-a.lat); + var x = b.lon-a.lon * Math.cos((a.lat+b.lat)/2); + var y = b.lat-a.lat; return Math.sqrt(x*x + y*y) * 6371000; } @@ -126,7 +126,7 @@ Bangle.on("HRM", function(h) { if (h.confidence>=60) { state.BPM = h.bpm; state.BPMage = 0; - stats["bpm"].emit("changed",stats["bpm"]); + if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } }); @@ -137,13 +137,13 @@ exports.getList = function() { {name: "Distance", id:"dist"}, {name: "Steps", id:"step"}, {name: "Heart (BPM)", id:"bpm"}, - {name: "Pace (avr)", id:"pacea"}, - {name: "Pace (current)", id:"pacec"}, + {name: "Pace (avg)", id:"pacea"}, + {name: "Pace (curr)", id:"pacec"}, {name: "Speed", id:"speed"}, {name: "Cadence", id:"caden"}, ]; }; -/** Instatiate the given list of statistic IDs (see comments at top) +/** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over } @@ -159,7 +159,7 @@ exports.getStats = function(statIDs, options) { getValue : function() { return Date.now()-state.startTime; }, getString : function() { return formatTime(this.getValue()) }, }; - }; + } if (statIDs.includes("dist")) { needGPS = true; stats["dist"]={ From f307101aad064e35667e57aad4bfe526d47a4d28 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 28 Feb 2022 23:58:45 -0600 Subject: [PATCH 355/447] Remove recorder dependency --- apps/run/metadata.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/run/metadata.json b/apps/run/metadata.json index f256aefa4..8f139c2d5 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -12,6 +12,5 @@ {"name":"run.img","url":"app-icon.js","evaluate":true}, {"name":"run.settings.js","url":"settings.js"} ], - "data": [{"name":"run.json"}], - "dependencies" : { "messages":"recorder" } + "data": [{"name":"run.json"}] } From 7cd78bfd17204eefa23d21827bf648d2691a2ea7 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 1 Mar 2022 00:16:24 -0600 Subject: [PATCH 356/447] Cleanup --- apps/run/app.js | 18 ++++++++---------- apps/run/settings.js | 13 ++++--------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index fc8869fa7..287d60969 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -14,16 +14,14 @@ Bangle.drawWidgets(); // --------------------------- let settings = Object.assign({ - record : true, - B1 : "dist", - B2 : "time", - B3 : "pacea", - B4 : "pacec", - B5 : "bpm", - B6 : "step", - B7 : "caden", - B8 : "speed", - paceLength : 1000 + record: true, + B1: "dist", + B2: "time", + B3: "pacea", + B4: "bpm", + B5: "step", + B6: "caden", + paceLength: 1000 }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); diff --git a/apps/run/settings.js b/apps/run/settings.js index aaf834214..6718a381b 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -13,14 +13,11 @@ B1: "dist", B2: "time", B3: "pacea", - B4: "pacec", - B5: "bpm", - B6: "step", - B7: "caden", - B8: "speed", - paceLength: 1000, + B4: "bpm", + B5: "step", + B6: "caden", + paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale notify: false, - }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -59,8 +56,6 @@ 'Box 4': getBoxChooser("B4"), 'Box 5': getBoxChooser("B5"), 'Box 6': getBoxChooser("B6"), - 'Box 7': getBoxChooser("B7"), - 'Box 8': getBoxChooser("B8"), }); E.showMenu(menu); }) From 5e3e7a0c0fd0a119ce51efe0e608f2d778711afc Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:15:35 -0600 Subject: [PATCH 357/447] Testing exstats notifications --- apps/locale/ChangeLog | 2 +- apps/locale/locales.js | 1 - apps/recorder/app.js | 2 +- apps/run/README.md | 4 +- apps/run/app.js | 6 +- apps/run/settings.js | 4 +- modules/exstats.js | 32 +- yarn.lock | 864 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 906 insertions(+), 9 deletions(-) create mode 100644 yarn.lock diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index 39b825e02..2dbb4febb 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -7,7 +7,7 @@ 0.06: Remove translations if not required Ensure 'on' is always supplied for translations 0.07: Improve handling of non-ASCII characters (fix #469) -0.08: Added Mavigation units and en_NAV +0.08: Added Navigation units and en_NAV 0.09: Added New Zealand en_NZ 0.10: Apply 12hour setting to time 0.11: Added translations for nl_NL and changes one formatting diff --git a/apps/locale/locales.js b/apps/locale/locales.js index dd650d7d7..073f4903f 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -110,7 +110,6 @@ var locales = { int_curr_symbol: "INR", speed: 'kmh', distance: { "0": "m", "1": "km" }, - paceLength: 1000, temperature: '°C', ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 7075563aa..d28cef585 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -305,7 +305,7 @@ function viewTrack(filename, info) { g.drawString(require("locale").distance(dist),g.getWidth() / 2, g.getHeight() - 20); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); + g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); // TODO: this position depends on Bangle1 vs 2 setWatch(function() { viewTrack(info.fn, info); }, global.BTN3||BTN1); diff --git a/apps/run/README.md b/apps/run/README.md index 11d41d4bd..67d62185d 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -24,8 +24,8 @@ so if you have no GPS lock you just need to wait. ## Recording Tracks -`Run` depends on the `Recorder` app and it will be installed automatically. -Starting and stopping a run will automatically start and stop recordings with the `Recorder` app. +When the `Recorder` app is installed, `Run` will automatically start and stop tracks +as needed, prompting you to overwrite or begin a new track, if necessary. ## Settings diff --git a/apps/run/app.js b/apps/run/app.js index 287d60969..06340526f 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -7,6 +7,8 @@ var fontValue = B2 ? "6x15:2" : "6x8:3"; var headingCol = "#888"; var fixCount = 0; var isMenuDisplayed = false; +var nextNotifyTime = 0; +var nextNotifyDist = 0; g.clear(); Bangle.loadWidgets(); @@ -21,7 +23,9 @@ let settings = Object.assign({ B4: "bpm", B5: "step", B6: "caden", - paceLength: 1000 + paceLength: 1000, + notifyDistance: false, + notifyTime: false, }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); diff --git a/apps/run/settings.js b/apps/run/settings.js index 6718a381b..1ac16e734 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -17,7 +17,8 @@ B5: "step", B6: "caden", paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale - notify: false, + notifyDistance: false, + notifyTime: false, }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -48,6 +49,7 @@ saveSettings(); } }; + ExStats.appendMenuItems(menu, settings, saveSettings); Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), diff --git a/modules/exstats.js b/modules/exstats.js index c2a4bfb9e..da32ffa12 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -63,6 +63,9 @@ var state = { // cadence // steps per minute adjusted if <1 minute // BPM // beats per minute // BPMage // how many seconds was BPM set? + // Notifies: 0 for disabled, otherwise how often to notify in meters and seconds + notifyDistance: 0, notifyTime: 0, notifySteps: 0, + nextNotifyDistance: 0, nextNotifyTime: 0, nextNotifySteps: 0, }; // list of active stats (indexed by ID) var stats = {}; @@ -71,8 +74,9 @@ var stats = {}; // https://www.movable-type.co.uk/scripts/latlong.html // (Equirectangular approximation) function calcDistance(a,b) { - var x = b.lon-a.lon * Math.cos((a.lat+b.lat)/2); - var y = b.lat-a.lat; + function radians(a) { return a*Math.PI/180; } + var x = radians(b.lon-a.lon) * Math.cos(radians((a.lat+b.lat)/2)); + var y = radians(b.lat-a.lat); return Math.sqrt(x*x + y*y) * 6371000; } @@ -114,6 +118,10 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); + if (state.notifyDistance > 0 && state.nextNotifyDist < stats["dist"]) { + stats["dist"].emit("notify",stats["dist"]); + state.nextNotifyDist = stats["dist"] + state.notifyDistance; + } }); Bangle.on("step", function(steps) { @@ -121,6 +129,10 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; + if (state.notifySteps > 0 && state.nextNotifySteps < steps) { + stats["step"].emit("notify",stats["step"]); + state.nextNotifySteps = steps + state.notifySteps; + } }); Bangle.on("HRM", function(h) { if (h.confidence>=60) { @@ -146,6 +158,9 @@ exports.getList = function() { /** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over + notifyDistance : meters to notify have elapsed (repeats) + notifyTime : ms to notify have elapsed (repeats) + notifySteps : number of steps to notify have elapsed (repeats) } */ exports.getStats = function(statIDs, options) { @@ -235,6 +250,10 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } + if (state.notifyTime > 0 && state.nextNotifyTime < stats["time"]) { + stats["time"].emit("notify",stats["time"]); + state.nextNotifyTime = stats["time"] + state.notifyDistance; + } }, 1000); function reset() { state.startTime = Date.now(); @@ -273,4 +292,13 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + menu['Ntfy Dist'] = { + min :0, max: paceNames.length-1, + value: Math.max(paceAmts.indexOf(settings.paceLength),0), + format: v => paceNames[v], + onchange: v => { + state.notifyDistance = paceAmts[v]; + saveSettings(); + }, + }; }; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..f3224947f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,864 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.2.0, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.0.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-scope@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" + integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + eslint-visitor-keys "^1.1.0" + espree "^7.0.0" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.14" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.0.0: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +glob-parent@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +import-fresh@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lodash@^4.17.14, lodash@^4.17.19: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^7.2.1: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From 35d1cf85e8d549bb56740ec8fbc1f97f19c6712e Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:32:07 -0600 Subject: [PATCH 358/447] More notification testing --- apps/run/app.js | 8 ++++++++ modules/exstats.js | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 06340526f..8a5d84142 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -74,6 +74,14 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); + if (sa) sa.on('notify', (e)=>{ + Bangle.buzz(); + console.log(`notify from ${JSON.stringify(e)}`); + }); + if (sb) sa.on('notify', (e)=>{ + Bangle.buzz(); + console.log(`notify from ${JSON.stringify(e)}`); + }); } // At the bottom put time/GPS state/etc lc.push({ type:"h", filly:1, c:[ diff --git a/modules/exstats.js b/modules/exstats.js index da32ffa12..7a01e9aec 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -166,6 +166,9 @@ exports.getList = function() { exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; + options.notifyDistance = options.notifyDistance||0; + options.notifyTime = options.notifyTime||0; + options.notifySteps = options.notifySteps||0; var needGPS,needHRM; // ====================== if (statIDs.includes("time")) { @@ -266,6 +269,18 @@ exports.getStats = function(statIDs, options) { state.curSpeed = 0; state.BPM = 0; state.BPMage = 0; + state.notifyTime = options.notifyTime; + state.notifyDistance = options.notifyDistance; + state.notifySteps = options.notifySteps; + if (options.notifyTime) { + state.nextNotifyTime = state.startTime + options.notifyTime; + } + if (options.notifyDistance) { + state.nextNotifyDist = state.distance + options.notifyDistance; + } + if (options.notifySteps) { + state.nextNotifySteps = state.lastSteps + options.notifySteps; + } } reset(); return { @@ -292,12 +307,35 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + var distNames = ['Off', ...paceNames]; + var distAmts = [0, ...paceAmts]; menu['Ntfy Dist'] = { - min :0, max: paceNames.length-1, - value: Math.max(paceAmts.indexOf(settings.paceLength),0), - format: v => paceNames[v], + min :0, max: distNames.length-1, + value: Math.max(distAmts.indexOf(settings.notifyDistance),0), + format: v => distNames[v], onchange: v => { - state.notifyDistance = paceAmts[v]; + settings.notifyDistance = distAmts[v]; + saveSettings(); + }, + }; + var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; + var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; + menu['Ntfy Time'] = { + min :0, max: timeNames.length-1, + value: Math.max(timeAmts.indexOf(settings.notifyTime),0), + format: v => timeNames[v], + onchange: v => { + settings.notifyTime = timeAmts[v]; + saveSettings(); + }, + }; + var stepAmts = [0, 100, 500, 1000, 5000, 10000]; + menu['Ntfy Steps'] = { + min :0, max: stepAmts.length-1, + value: Math.max(stepAmts.indexOf(settings.notifySteps),0), + format: v => stepAmts[v], + onchange: v => { + settings.notifySteps = stepAmts[v]; saveSettings(); }, }; From b923423238540380794e08be2c1615e2ea1cdf1d Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:40:23 -0600 Subject: [PATCH 359/447] Cleanup --- apps/run/app.js | 5 +++-- apps/run/settings.js | 6 +++--- modules/exstats.js | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 8a5d84142..31fd3336c 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -24,8 +24,9 @@ let settings = Object.assign({ B5: "step", B6: "caden", paceLength: 1000, - notifyDistance: false, - notifyTime: false, + notifyDist: 0, + notifyTime: 0, + notifySteps: 0, }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); diff --git a/apps/run/settings.js b/apps/run/settings.js index 1ac16e734..9a8259f85 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -17,8 +17,9 @@ B5: "step", B6: "caden", paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale - notifyDistance: false, - notifyTime: false, + notifyDist: 0, + notifyTime: 0, + notifySteps: 0, }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -49,7 +50,6 @@ saveSettings(); } }; - ExStats.appendMenuItems(menu, settings, saveSettings); Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), diff --git a/modules/exstats.js b/modules/exstats.js index 7a01e9aec..d42fa1517 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -64,8 +64,8 @@ var state = { // BPM // beats per minute // BPMage // how many seconds was BPM set? // Notifies: 0 for disabled, otherwise how often to notify in meters and seconds - notifyDistance: 0, notifyTime: 0, notifySteps: 0, - nextNotifyDistance: 0, nextNotifyTime: 0, nextNotifySteps: 0, + notifyDist: 0, notifyTime: 0, notifySteps: 0, + nextNotifyDist: 0, nextNotifyTime: 0, nextNotifySteps: 0, }; // list of active stats (indexed by ID) var stats = {}; @@ -118,9 +118,9 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); - if (state.notifyDistance > 0 && state.nextNotifyDist < stats["dist"]) { + if (state.notifyDist > 0 && state.nextNotifyDist < stats["dist"]) { stats["dist"].emit("notify",stats["dist"]); - state.nextNotifyDist = stats["dist"] + state.notifyDistance; + state.nextNotifyDist = stats["dist"] + state.notifyDist; } }); @@ -158,7 +158,7 @@ exports.getList = function() { /** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over - notifyDistance : meters to notify have elapsed (repeats) + notifyDist : meters to notify have elapsed (repeats) notifyTime : ms to notify have elapsed (repeats) notifySteps : number of steps to notify have elapsed (repeats) } @@ -166,7 +166,7 @@ exports.getList = function() { exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; - options.notifyDistance = options.notifyDistance||0; + options.notifyDist = options.notifyDist||0; options.notifyTime = options.notifyTime||0; options.notifySteps = options.notifySteps||0; var needGPS,needHRM; @@ -255,7 +255,7 @@ exports.getStats = function(statIDs, options) { } if (state.notifyTime > 0 && state.nextNotifyTime < stats["time"]) { stats["time"].emit("notify",stats["time"]); - state.nextNotifyTime = stats["time"] + state.notifyDistance; + state.nextNotifyTime = stats["time"] + state.notifyTime; } }, 1000); function reset() { @@ -270,13 +270,13 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; state.BPMage = 0; state.notifyTime = options.notifyTime; - state.notifyDistance = options.notifyDistance; + state.notifyDist = options.notifyDist; state.notifySteps = options.notifySteps; if (options.notifyTime) { state.nextNotifyTime = state.startTime + options.notifyTime; } - if (options.notifyDistance) { - state.nextNotifyDist = state.distance + options.notifyDistance; + if (options.notifyDist) { + state.nextNotifyDist = state.distance + options.notifyDist; } if (options.notifySteps) { state.nextNotifySteps = state.lastSteps + options.notifySteps; @@ -311,10 +311,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var distAmts = [0, ...paceAmts]; menu['Ntfy Dist'] = { min :0, max: distNames.length-1, - value: Math.max(distAmts.indexOf(settings.notifyDistance),0), + value: Math.max(distAmts.indexOf(settings.notifyDist),0), format: v => distNames[v], onchange: v => { - settings.notifyDistance = distAmts[v]; + settings.notifyDist = distAmts[v]; saveSettings(); }, }; From c3fc12dfa2086d342fbd4e4164a7ff4f27fca661 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:52:46 -0600 Subject: [PATCH 360/447] Chasing down a settings bug --- modules/exstats.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index d42fa1517..8469fab78 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -299,7 +299,7 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var paceNames = ["1000m","1 mile","1/2 Mthn", "Marathon",]; var paceAmts = [1000,1609,21098,42195]; menu['Pace'] = { - min :0, max: paceNames.length-1, + min: 0, max: paceNames.length-1, value: Math.max(paceAmts.indexOf(settings.paceLength),0), format: v => paceNames[v], onchange: v => { @@ -310,7 +310,7 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var distNames = ['Off', ...paceNames]; var distAmts = [0, ...paceAmts]; menu['Ntfy Dist'] = { - min :0, max: distNames.length-1, + min: 0, max: distNames.length-1, value: Math.max(distAmts.indexOf(settings.notifyDist),0), format: v => distNames[v], onchange: v => { @@ -321,7 +321,7 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; menu['Ntfy Time'] = { - min :0, max: timeNames.length-1, + min: 0, max: timeNames.length-1, value: Math.max(timeAmts.indexOf(settings.notifyTime),0), format: v => timeNames[v], onchange: v => { @@ -331,9 +331,9 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { }; var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { - min :0, max: stepAmts.length-1, + min: 0, max: stepAmts.length-1, value: Math.max(stepAmts.indexOf(settings.notifySteps),0), - format: v => stepAmts[v], + format: v => stepAmts[v].toString(), onchange: v => { settings.notifySteps = stepAmts[v]; saveSettings(); From 4b371e1f1817fc7afed5103a3f20705309631dbe Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:02:00 -0600 Subject: [PATCH 361/447] Don't use spread operator --- modules/exstats.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index 8469fab78..fcee51f5e 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -307,8 +307,8 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; - var distNames = ['Off', ...paceNames]; - var distAmts = [0, ...paceAmts]; + var distNames = ['Off', "1000m","1 mile","1/2 Mthn", "Marathon",]; + var distAmts = [0, 1000,1609,21098,42195]; menu['Ntfy Dist'] = { min: 0, max: distNames.length-1, value: Math.max(distAmts.indexOf(settings.notifyDist),0), From 1cf5a077619ee5e75623cba22c857595480ab282 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:11:42 -0600 Subject: [PATCH 362/447] Debug --- modules/exstats.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index fcee51f5e..f3a2ced9f 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -272,6 +272,8 @@ exports.getStats = function(statIDs, options) { state.notifyTime = options.notifyTime; state.notifyDist = options.notifyDist; state.notifySteps = options.notifySteps; + console.log("options:"); + console.log(JSON.stringify(options)); if (options.notifyTime) { state.nextNotifyTime = state.startTime + options.notifyTime; } @@ -281,6 +283,8 @@ exports.getStats = function(statIDs, options) { if (options.notifySteps) { state.nextNotifySteps = state.lastSteps + options.notifySteps; } + console.log("state:"); + console.log(JSON.stringify(state)); } reset(); return { @@ -329,11 +333,12 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + var stepNames = ['Off', '100', '500', '1000', '5000', '10000']; var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { - min: 0, max: stepAmts.length-1, + min: 0, max: stepNames.length-1, value: Math.max(stepAmts.indexOf(settings.notifySteps),0), - format: v => stepAmts[v].toString(), + format: v => stepNames[v], onchange: v => { settings.notifySteps = stepAmts[v]; saveSettings(); From d0cb22e7df1badec000332930f5217a1e6041b0b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:21:21 -0600 Subject: [PATCH 363/447] Bug fixes --- modules/exstats.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index f3a2ced9f..7055b5b35 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -239,7 +239,8 @@ exports.getStats = function(statIDs, options) { setInterval(function() { // run once a second.... if (!state.active) return; // called once a second - var duration = Date.now() - state.startTime; // in ms + var now = Date.now(); + var duration = now - state.startTime; // in ms // set cadence -> steps over last minute state.stepsPerMin = Math.round(60000 * E.sum(state.stepHistory) / Math.min(duration,60000)); if (stats["caden"]) stats["caden"].emit("changed",stats["caden"]); @@ -253,7 +254,7 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - if (state.notifyTime > 0 && state.nextNotifyTime < stats["time"]) { + if (state.notifyTime > 0 && state.nextNotifyTime < now) { stats["time"].emit("notify",stats["time"]); state.nextNotifyTime = stats["time"] + state.notifyTime; } @@ -281,7 +282,7 @@ exports.getStats = function(statIDs, options) { state.nextNotifyDist = state.distance + options.notifyDist; } if (options.notifySteps) { - state.nextNotifySteps = state.lastSteps + options.notifySteps; + state.nextNotifySteps = state.startSteps + options.notifySteps; } console.log("state:"); console.log(JSON.stringify(state)); From 3a6009a96376b985f25b87e33093197486fe0f30 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:58:46 -0600 Subject: [PATCH 364/447] Add vibration settings and reorg to use object for settings --- apps/run/app.js | 23 ++++++++---- apps/run/settings.js | 46 ++++++++++++++++++++++-- modules/exstats.js | 83 +++++++++++++++++++++++++++----------------- 3 files changed, 111 insertions(+), 41 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 31fd3336c..f689daebe 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -7,8 +7,6 @@ var fontValue = B2 ? "6x15:2" : "6x8:3"; var headingCol = "#888"; var fixCount = 0; var isMenuDisplayed = false; -var nextNotifyTime = 0; -var nextNotifyDist = 0; g.clear(); Bangle.loadWidgets(); @@ -24,9 +22,20 @@ let settings = Object.assign({ B5: "step", B6: "caden", paceLength: 1000, - notifyDist: 0, - notifyTime: 0, - notifySteps: 0, + notify: { + dist: { + value: 0, + notification: [], + }, + steps: { + value: 0, + notification: [], + }, + time: { + value: 0, + notification: [], + }, + }, }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); @@ -76,11 +85,11 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); if (sa) sa.on('notify', (e)=>{ - Bangle.buzz(); + settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); console.log(`notify from ${JSON.stringify(e)}`); }); if (sb) sa.on('notify', (e)=>{ - Bangle.buzz(); + settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); console.log(`notify from ${JSON.stringify(e)}`); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index 9a8259f85..8606ef304 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -17,9 +17,20 @@ B5: "step", B6: "caden", paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale - notifyDist: 0, - notifyTime: 0, - notifySteps: 0, + notify: { + dist: { + increment: 0, + notification: [], + }, + steps: { + increment: 0, + notification: [], + }, + time: { + increment: 0, + notification: [], + }, + }, }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -50,6 +61,35 @@ saveSettings(); } }; + var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; + var vibTimes = [[], [100], [500],[500,500],[500,100,500],[500,500,500]]; + menu[/*LANG*/"Time Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.timeNotification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.time.notification = vibTimes[v]; + saveSettings(); + } + } + menu[/*LANG*/"Dist Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.distNotification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.dist.notification = vibTimes[v]; + saveSettings(); + } + } + menu[/*LANG*/"Step Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.stepNotification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.steps.notification = vibTimes[v]; + saveSettings(); + } + } ExStats.appendMenuItems(menu, settings, saveSettings); Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), diff --git a/modules/exstats.js b/modules/exstats.js index 7055b5b35..c9fa54224 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -63,9 +63,24 @@ var state = { // cadence // steps per minute adjusted if <1 minute // BPM // beats per minute // BPMage // how many seconds was BPM set? - // Notifies: 0 for disabled, otherwise how often to notify in meters and seconds - notifyDist: 0, notifyTime: 0, notifySteps: 0, - nextNotifyDist: 0, nextNotifyTime: 0, nextNotifySteps: 0, + // Notifies: 0 for disabled, otherwise how often to notify in meters, seconds, or steps + notify: { + dist: { + increment: 0, + notification: [], + next: 0, + }, + steps: { + increment: 0, + notification: [], + next: 0, + }, + time: { + increment: 0, + notification: [], + next: 0, + }, + }, }; // list of active stats (indexed by ID) var stats = {}; @@ -118,9 +133,9 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); - if (state.notifyDist > 0 && state.nextNotifyDist < stats["dist"]) { + if (state.notify.dist.increment > 0 && state.notify.dist.next < stats["dist"]) { stats["dist"].emit("notify",stats["dist"]); - state.nextNotifyDist = stats["dist"] + state.notifyDist; + state.notify.dist.next = stats["dist"] + state.notify.dist.increment; } }); @@ -129,9 +144,9 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; - if (state.notifySteps > 0 && state.nextNotifySteps < steps) { - stats["step"].emit("notify",stats["step"]); - state.nextNotifySteps = steps + state.notifySteps; + if (state.notify.steps.increment > 0 && state.notify.steps.next < steps) { + stats["steps"].emit("notify",stats["steps"]); + state.notify.steps.next = steps + state.notify.steps.increment; } }); Bangle.on("HRM", function(h) { @@ -158,17 +173,25 @@ exports.getList = function() { /** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over - notifyDist : meters to notify have elapsed (repeats) - notifyTime : ms to notify have elapsed (repeats) - notifySteps : number of steps to notify have elapsed (repeats) + notify: { + dist: { + increment: 0 to not notify on distance milestones, otherwise the number of meters to notify after, repeating + }, + steps: { + increment: 0 to not notify on step milestones, otherwise the number of steps to notify after, repeating + }, + time: { + increment: 0 to not notify on time milestones, otherwise the number of milliseconds to notify after, repeating + } + } } */ exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; - options.notifyDist = options.notifyDist||0; - options.notifyTime = options.notifyTime||0; - options.notifySteps = options.notifySteps||0; + options.notify.dist.increment = options.notify.dist.increment||0; + options.notify.steps.increment = options.notify.steps.increment||0; + options.notify.time.increment = options.notify.time.increment||0; var needGPS,needHRM; // ====================== if (statIDs.includes("time")) { @@ -254,9 +277,9 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - if (state.notifyTime > 0 && state.nextNotifyTime < now) { + if (state.notify.time.increment > 0 && state.notify.time.next < now) { stats["time"].emit("notify",stats["time"]); - state.nextNotifyTime = stats["time"] + state.notifyTime; + state.notify.time.next = stats["time"] + state.notify.time.increment; } }, 1000); function reset() { @@ -270,19 +293,17 @@ exports.getStats = function(statIDs, options) { state.curSpeed = 0; state.BPM = 0; state.BPMage = 0; - state.notifyTime = options.notifyTime; - state.notifyDist = options.notifyDist; - state.notifySteps = options.notifySteps; + state.notify = options.notify; console.log("options:"); console.log(JSON.stringify(options)); - if (options.notifyTime) { - state.nextNotifyTime = state.startTime + options.notifyTime; + if (options.notify.dist.increment > 0) { + state.notify.dist.next = state.distance + options.notify.dist.increment; } - if (options.notifyDist) { - state.nextNotifyDist = state.distance + options.notifyDist; + if (options.notify.steps.increment > 0) { + state.notify.steps.next = state.startTime + options.notify.steps.increment; } - if (options.notifySteps) { - state.nextNotifySteps = state.startSteps + options.notifySteps; + if (options.notify.time.increment > 0) { + state.notify.time.next = state.startTime + options.notify.time.increment; } console.log("state:"); console.log(JSON.stringify(state)); @@ -316,10 +337,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var distAmts = [0, 1000,1609,21098,42195]; menu['Ntfy Dist'] = { min: 0, max: distNames.length-1, - value: Math.max(distAmts.indexOf(settings.notifyDist),0), + value: Math.max(distAmts.indexOf(settings.notify.dist.increment),0), format: v => distNames[v], onchange: v => { - settings.notifyDist = distAmts[v]; + settings.notify.dist.increment = distAmts[v]; saveSettings(); }, }; @@ -327,10 +348,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; menu['Ntfy Time'] = { min: 0, max: timeNames.length-1, - value: Math.max(timeAmts.indexOf(settings.notifyTime),0), + value: Math.max(timeAmts.indexOf(settings.notify.time.increment),0), format: v => timeNames[v], onchange: v => { - settings.notifyTime = timeAmts[v]; + settings.notify.time.increment = timeAmts[v]; saveSettings(); }, }; @@ -338,10 +359,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { min: 0, max: stepNames.length-1, - value: Math.max(stepAmts.indexOf(settings.notifySteps),0), + value: Math.max(stepAmts.indexOf(settings.notify.steps.increment),0), format: v => stepNames[v], onchange: v => { - settings.notifySteps = stepAmts[v]; + settings.notify.steps.increment = stepAmts[v]; saveSettings(); }, }; From dc154ade90bf41474410883ee392a2251ea8a4c0 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:00:46 -0600 Subject: [PATCH 365/447] Preview vibrations in settings --- apps/run/settings.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/run/settings.js b/apps/run/settings.js index 8606ef304..8daa4533f 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -69,6 +69,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.time.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); saveSettings(); } } @@ -78,6 +79,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.dist.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); saveSettings(); } } @@ -87,6 +89,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.steps.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); saveSettings(); } } From 63426d9b97b8c1da975b6573076f8abdf370d79c Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:08:22 -0600 Subject: [PATCH 366/447] Correct initial step notification increment --- modules/exstats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exstats.js b/modules/exstats.js index c9fa54224..fd6ca9042 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -300,7 +300,7 @@ exports.getStats = function(statIDs, options) { state.notify.dist.next = state.distance + options.notify.dist.increment; } if (options.notify.steps.increment > 0) { - state.notify.steps.next = state.startTime + options.notify.steps.increment; + state.notify.steps.next = state.startSteps + options.notify.steps.increment; } if (options.notify.time.increment > 0) { state.notify.time.next = state.startTime + options.notify.time.increment; From 4d83a4ce98e8aeef5d22e07b97505fda6e0b3de1 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:22:14 -0600 Subject: [PATCH 367/447] Bug fixes --- apps/run/app.js | 12 ++++++++++-- apps/run/settings.js | 26 +++++++++++++------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index f689daebe..5577c3151 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -85,11 +85,19 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); if (sa) sa.on('notify', (e)=>{ - settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); + settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve()); console.log(`notify from ${JSON.stringify(e)}`); }); if (sb) sa.on('notify', (e)=>{ - settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); + settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve());g console.log(`notify from ${JSON.stringify(e)}`); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index 8daa4533f..a75cc33c1 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -61,20 +61,11 @@ saveSettings(); } }; + ExStats.appendMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var vibTimes = [[], [100], [500],[500,500],[500,100,500],[500,500,500]]; - menu[/*LANG*/"Time Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.timeNotification)), - min: 0, max: vibPatterns.length, - format: v => vibPatterns[v]||"Off", - onchange: v => { - settings.notify.time.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); - saveSettings(); - } - } menu[/*LANG*/"Dist Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.distNotification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -84,7 +75,7 @@ } } menu[/*LANG*/"Step Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.stepNotification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.steps.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -93,7 +84,16 @@ saveSettings(); } } - ExStats.appendMenuItems(menu, settings, saveSettings); + menu[/*LANG*/"Time Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.time.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); + saveSettings(); + } + } Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), 'Box 2': getBoxChooser("B2"), From afd4bc697dd8fac9b060051367ad51c7873c36a6 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:22:33 -0600 Subject: [PATCH 368/447] Typo fix --- apps/run/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/run/app.js b/apps/run/app.js index 5577c3151..0f8969e70 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -97,7 +97,7 @@ for (var i=0;i Date: Sat, 5 Mar 2022 02:40:40 -0600 Subject: [PATCH 369/447] Fix for step notification, debug for time notification, better buzzes --- apps/run/settings.js | 16 ++++++++++++---- modules/exstats.js | 6 ++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index a75cc33c1..6dcbb05c0 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -48,6 +48,14 @@ } } + function sampleBuzz(buzzTimes) { + buzzTimes.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve()); + } + var menu = { '': { 'title': 'Run' }, '< Back': back, @@ -63,14 +71,14 @@ }; ExStats.appendMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; - var vibTimes = [[], [100], [500],[500,500],[500,100,500],[500,500,500]]; + var vibTimes = [[], [[100, 1]], [[500, 1]],[[500, 1], [50, 0], [500, 1]],[[500, 1],[50, 0], [100, 1], [50, 0], [500, 1]],[[500, 1],[50,0],[500, 1],[50,0],[500, 1]]]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.dist.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); + sampleBuzz(vibTimes[v]); saveSettings(); } } @@ -80,7 +88,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.steps.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); + sampleBuzz(vibTimes[v]); saveSettings(); } } @@ -90,7 +98,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.time.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); + sampleBuzz(vibTimes[v]); saveSettings(); } } diff --git a/modules/exstats.js b/modules/exstats.js index fd6ca9042..2a22f9974 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -145,7 +145,7 @@ Bangle.on("step", function(steps) { state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; if (state.notify.steps.increment > 0 && state.notify.steps.next < steps) { - stats["steps"].emit("notify",stats["steps"]); + stats["step"].emit("notify",stats["step"]); state.notify.steps.next = steps + state.notify.steps.increment; } }); @@ -277,9 +277,11 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } + console.log(now); + console.log(state.notify.time.next); if (state.notify.time.increment > 0 && state.notify.time.next < now) { stats["time"].emit("notify",stats["time"]); - state.notify.time.next = stats["time"] + state.notify.time.increment; + state.notify.time.next = now + state.notify.time.increment; } }, 1000); function reset() { From f5c50a7e1e916065ec353f33cc6d053002450341 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:54:08 -0600 Subject: [PATCH 370/447] Fix for step notification --- apps/run/settings.js | 4 ++-- modules/exstats.js | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index 6dcbb05c0..fe54ac6fd 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -83,11 +83,11 @@ } } menu[/*LANG*/"Step Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.steps.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.steps.notification = vibTimes[v]; + settings.notify.step.notification = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } diff --git a/modules/exstats.js b/modules/exstats.js index 2a22f9974..9e7c87e4c 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -144,9 +144,9 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; - if (state.notify.steps.increment > 0 && state.notify.steps.next < steps) { + if (state.notify.step.increment > 0 && state.notify.step.next < steps) { stats["step"].emit("notify",stats["step"]); - state.notify.steps.next = steps + state.notify.steps.increment; + state.notify.step.next = steps + state.notify.step.increment; } }); Bangle.on("HRM", function(h) { @@ -190,7 +190,7 @@ exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; options.notify.dist.increment = options.notify.dist.increment||0; - options.notify.steps.increment = options.notify.steps.increment||0; + options.notify.step.increment = options.notify.step.increment||0; options.notify.time.increment = options.notify.time.increment||0; var needGPS,needHRM; // ====================== @@ -301,8 +301,8 @@ exports.getStats = function(statIDs, options) { if (options.notify.dist.increment > 0) { state.notify.dist.next = state.distance + options.notify.dist.increment; } - if (options.notify.steps.increment > 0) { - state.notify.steps.next = state.startSteps + options.notify.steps.increment; + if (options.notify.step.increment > 0) { + state.notify.step.next = state.startSteps + options.notify.step.increment; } if (options.notify.time.increment > 0) { state.notify.time.next = state.startTime + options.notify.time.increment; @@ -361,10 +361,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { min: 0, max: stepNames.length-1, - value: Math.max(stepAmts.indexOf(settings.notify.steps.increment),0), + value: Math.max(stepAmts.indexOf(settings.notify.step.increment),0), format: v => stepNames[v], onchange: v => { - settings.notify.steps.increment = stepAmts[v]; + settings.notify.step.increment = stepAmts[v]; saveSettings(); }, }; From efb136e194b6cd22d4fe205e52ff2783a64da3c0 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:59:13 -0600 Subject: [PATCH 371/447] Potential fix for time notification --- apps/run/app.js | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 0f8969e70..bf45a196b 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -84,22 +84,6 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); - if (sa) sa.on('notify', (e)=>{ - settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { - return promise.then(function () { - return Bangle.buzz(buzzTime); - }); - }, Promise.resolve()); - console.log(`notify from ${JSON.stringify(e)}`); - }); - if (sb) sa.on('notify', (e)=>{ - settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { - return promise.then(function () { - return Bangle.buzz(buzzTime); - }); - }, Promise.resolve()); - console.log(`notify from ${JSON.stringify(e)}`); - }); } // At the bottom put time/GPS state/etc lc.push({ type:"h", filly:1, c:[ @@ -114,6 +98,30 @@ var layout = new Layout( { delete lc; layout.render(); +function configureNotification(stat) { + stat.on('notify', (e)=>{ + settings.notify[stat.id].notifications.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve()); + console.log(`notify from ${JSON.stringify(e)}`); + }); +} + +// TODO: Should really loop over Object.keys(settings.notify) +if (settings.notify.dist.increment > 0) { + configureNotification(exs.stats.dist); +} + +if (settings.notify.step.increment > 0) { + configureNotification(exs.stats.step); +} + +if (settings.notify.time.increment > 0) { + configureNotification(exs.stats.time); +} + // Handle GPS state change for icon Bangle.on("GPS", function(fix) { layout.gps.bgCol = fix.fix ? "#0f0" : "#f00"; From 9c17fe8c5dd66ca9f62f345e3c0fb4f84cbda87c Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:01:02 -0600 Subject: [PATCH 372/447] More pause in vibration times --- apps/run/settings.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index fe54ac6fd..d50bc4889 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -71,7 +71,13 @@ }; ExStats.appendMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; - var vibTimes = [[], [[100, 1]], [[500, 1]],[[500, 1], [50, 0], [500, 1]],[[500, 1],[50, 0], [100, 1], [50, 0], [500, 1]],[[500, 1],[50,0],[500, 1],[50,0],[500, 1]]]; + var vibTimes = [ + [], + [[100, 1]], + [[500, 1]],[[500, 1], [100, 0], [500, 1]], + [[500, 1],[100, 0], [100, 1], [100, 0], [500, 1]], + [[500, 1],[100, 0],[500, 1],[100, 0],[500, 1]], + ]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, From 50ca281500c61b9725d0ed86a0cbaa29f50fb496 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:07:10 -0600 Subject: [PATCH 373/447] Settings fix --- apps/run/app.js | 2 +- apps/run/settings.js | 2 +- modules/exstats.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index bf45a196b..fa1d41729 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -27,7 +27,7 @@ let settings = Object.assign({ value: 0, notification: [], }, - steps: { + step: { value: 0, notification: [], }, diff --git a/apps/run/settings.js b/apps/run/settings.js index d50bc4889..67f5e3d83 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -22,7 +22,7 @@ increment: 0, notification: [], }, - steps: { + step: { increment: 0, notification: [], }, diff --git a/modules/exstats.js b/modules/exstats.js index 9e7c87e4c..5eb0dc2be 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -177,7 +177,7 @@ exports.getList = function() { dist: { increment: 0 to not notify on distance milestones, otherwise the number of meters to notify after, repeating }, - steps: { + step: { increment: 0 to not notify on step milestones, otherwise the number of steps to notify after, repeating }, time: { From e823ae8496cd7e5c9fae084a79f9d679600dbc4b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:15:58 -0600 Subject: [PATCH 374/447] Fix for nested options not set yet --- modules/exstats.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index 5eb0dc2be..82bb40c2f 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -189,9 +189,9 @@ exports.getList = function() { exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; - options.notify.dist.increment = options.notify.dist.increment||0; - options.notify.step.increment = options.notify.step.increment||0; - options.notify.time.increment = options.notify.time.increment||0; + options.notify.dist.increment = (options.notify && options.notify.dist && options.notify.dist.increment)||0; + options.notify.step.increment = (options.notify && options.notify.step && options.notify.step.increment)||0; + options.notify.time.increment = (options.notify && options.notify.time && options.notify.time.increment)||0; var needGPS,needHRM; // ====================== if (statIDs.includes("time")) { From 8a7b30cf6cb1d5c6265f3f4784a4e701d9377efc Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:28:23 -0600 Subject: [PATCH 375/447] Cleanup --- apps/run/app.js | 6 +++--- apps/run/settings.js | 15 ++++++++------- modules/exstats.js | 9 --------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index fa1d41729..2f4c44f17 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -25,15 +25,15 @@ let settings = Object.assign({ notify: { dist: { value: 0, - notification: [], + notifications: [], }, step: { value: 0, - notification: [], + notifications: [], }, time: { value: 0, - notification: [], + notifications: [], }, }, }, require("Storage").readJSON("run.json", 1) || {}); diff --git a/apps/run/settings.js b/apps/run/settings.js index 67f5e3d83..e0b03256c 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -20,15 +20,15 @@ notify: { dist: { increment: 0, - notification: [], + notifications: [], }, step: { increment: 0, - notification: [], + notifications: [], }, time: { increment: 0, - notification: [], + notifications: [], }, }, }, storage.readJSON(SETTINGS_FILE, 1) || {}); @@ -48,10 +48,10 @@ } } - function sampleBuzz(buzzTimes) { - buzzTimes.reduce(function (promise, buzzTime) { + function sampleBuzz(buzzPatterns) { + buzzPatterns.reduce(function (promise, buzzPattern) { return promise.then(function () { - return Bangle.buzz(buzzTime); + return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()); } @@ -74,7 +74,8 @@ var vibTimes = [ [], [[100, 1]], - [[500, 1]],[[500, 1], [100, 0], [500, 1]], + [[500, 1]], + [[500, 1], [100, 0], [500, 1]], [[500, 1],[100, 0], [100, 1], [100, 0], [500, 1]], [[500, 1],[100, 0],[500, 1],[100, 0],[500, 1]], ]; diff --git a/modules/exstats.js b/modules/exstats.js index 82bb40c2f..e5a1acd7d 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -67,17 +67,14 @@ var state = { notify: { dist: { increment: 0, - notification: [], next: 0, }, steps: { increment: 0, - notification: [], next: 0, }, time: { increment: 0, - notification: [], next: 0, }, }, @@ -277,8 +274,6 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - console.log(now); - console.log(state.notify.time.next); if (state.notify.time.increment > 0 && state.notify.time.next < now) { stats["time"].emit("notify",stats["time"]); state.notify.time.next = now + state.notify.time.increment; @@ -296,8 +291,6 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; state.BPMage = 0; state.notify = options.notify; - console.log("options:"); - console.log(JSON.stringify(options)); if (options.notify.dist.increment > 0) { state.notify.dist.next = state.distance + options.notify.dist.increment; } @@ -307,8 +300,6 @@ exports.getStats = function(statIDs, options) { if (options.notify.time.increment > 0) { state.notify.time.next = state.startTime + options.notify.time.increment; } - console.log("state:"); - console.log(JSON.stringify(state)); } reset(); return { From 96ad9b3e01e27b6e22e5816a449746fb4359d950 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:29:42 -0600 Subject: [PATCH 376/447] Obey buzz intensity --- apps/run/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 2f4c44f17..cb9beac5f 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -100,9 +100,9 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - settings.notify[stat.id].notifications.reduce(function (promise, buzzTime) { + settings.notify[stat.id].notifications.reduce(function (promise, buzzPattern) { return promise.then(function () { - return Bangle.buzz(buzzTime); + return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()); console.log(`notify from ${JSON.stringify(e)}`); From 4810eefe08cb6c7ebc7c979a1b7aafa0520c12a4 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:42:07 -0600 Subject: [PATCH 377/447] More tweaks --- apps/run/app.js | 3 +-- apps/run/settings.js | 8 ++++---- modules/exstats.js | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index cb9beac5f..e0eaf00af 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -100,12 +100,11 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - settings.notify[stat.id].notifications.reduce(function (promise, buzzPattern) { + settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { return promise.then(function () { return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()); - console.log(`notify from ${JSON.stringify(e)}`); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index e0b03256c..e386106e0 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -49,7 +49,7 @@ } function sampleBuzz(buzzPatterns) { - buzzPatterns.reduce(function (promise, buzzPattern) { + return buzzPatterns.reduce(function (promise, buzzPattern) { return promise.then(function () { return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); @@ -75,9 +75,9 @@ [], [[100, 1]], [[500, 1]], - [[500, 1], [100, 0], [500, 1]], - [[500, 1],[100, 0], [100, 1], [100, 0], [500, 1]], - [[500, 1],[100, 0],[500, 1],[100, 0],[500, 1]], + [[500, 1], [200, 0], [500, 1]], + [[500, 1],[200, 0], [100, 1], [200, 0], [500, 1]], + [[500, 1],[200, 0],[500, 1],[200, 0],[500, 1]], ]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), diff --git a/modules/exstats.js b/modules/exstats.js index e5a1acd7d..8b097a198 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -130,7 +130,7 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); - if (state.notify.dist.increment > 0 && state.notify.dist.next < stats["dist"]) { + if (state.notify.dist.increment > 0 && state.notify.dist.next <= stats["dist"]) { stats["dist"].emit("notify",stats["dist"]); state.notify.dist.next = stats["dist"] + state.notify.dist.increment; } @@ -141,7 +141,7 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; - if (state.notify.step.increment > 0 && state.notify.step.next < steps) { + if (state.notify.step.increment > 0 && state.notify.step.next <= steps) { stats["step"].emit("notify",stats["step"]); state.notify.step.next = steps + state.notify.step.increment; } @@ -274,7 +274,7 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - if (state.notify.time.increment > 0 && state.notify.time.next < now) { + if (state.notify.time.increment > 0 && state.notify.time.next <= now) { stats["time"].emit("notify",stats["time"]); state.notify.time.next = now + state.notify.time.increment; } From 2bd1da264fa4bbe9971ed297d647e69016e24a81 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 12:35:39 -0600 Subject: [PATCH 378/447] Debug --- apps/run/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/run/app.js b/apps/run/app.js index e0eaf00af..ba8090f51 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -101,10 +101,12 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { + console.log(buzzPattern); return promise.then(function () { return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); - }, Promise.resolve()); + }, Promise.resolve()) + .then(console.log); }); } From 6ffa4b28b3ef399607fcef767c02fefb2806d8f9 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:05:48 -0600 Subject: [PATCH 379/447] Menu fixes and tweaking vibe options --- apps/run/settings.js | 9 +++++---- modules/exstats.js | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index e386106e0..405cb03b8 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -70,14 +70,15 @@ } }; ExStats.appendMenuItems(menu, settings, saveSettings); + ExStats.appendNotifyMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var vibTimes = [ [], [[100, 1]], - [[500, 1]], - [[500, 1], [200, 0], [500, 1]], - [[500, 1],[200, 0], [100, 1], [200, 0], [500, 1]], - [[500, 1],[200, 0],[500, 1],[200, 0],[500, 1]], + [[300, 1]], + [[300, 1], [200, 0], [300, 1]], + [[300, 1],[200, 0], [100, 1], [200, 0], [300, 1]], + [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], ]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), diff --git a/modules/exstats.js b/modules/exstats.js index 8b097a198..b106622d0 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -48,6 +48,15 @@ var menu = { ... }; ExStats.appendMenuItems(menu, settings, saveSettingsFunction); E.showMenu(menu); +// Additionally, if your app makes use of the stat notifications, you can display additional menu +// settings for configuring when to notify (note the added line in the example below)W + +var menu = { ... }; +ExStats.appendMenuItems(menu, settings, saveSettingsFunction); +ExStats.appendNotifyMenuItems(menu, settings, saveSettingsFunction); +E.showMenu(menu); + + */ var state = { active : false, // are we working or not? @@ -315,17 +324,19 @@ exports.getStats = function(statIDs, options) { }; exports.appendMenuItems = function(menu, settings, saveSettings) { - var paceNames = ["1000m","1 mile","1/2 Mthn", "Marathon",]; - var paceAmts = [1000,1609,21098,42195]; + var paceNames = ["1000m", "1 mile", "1/2 Mthn", "Marathon",]; + var paceAmts = [1000, 1609, 21098, 42195]; menu['Pace'] = { - min: 0, max: paceNames.length-1, - value: Math.max(paceAmts.indexOf(settings.paceLength),0), + min: 0, max: paceNames.length - 1, + value: Math.max(paceAmts.indexOf(settings.paceLength), 0), format: v => paceNames[v], onchange: v => { settings.paceLength = paceAmts[v]; saveSettings(); }, }; +} +exports.appendNotifyMenuItems = function(menu, settings, saveSettings) { var distNames = ['Off', "1000m","1 mile","1/2 Mthn", "Marathon",]; var distAmts = [0, 1000,1609,21098,42195]; menu['Ntfy Dist'] = { @@ -337,17 +348,6 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; - var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; - var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; - menu['Ntfy Time'] = { - min: 0, max: timeNames.length-1, - value: Math.max(timeAmts.indexOf(settings.notify.time.increment),0), - format: v => timeNames[v], - onchange: v => { - settings.notify.time.increment = timeAmts[v]; - saveSettings(); - }, - }; var stepNames = ['Off', '100', '500', '1000', '5000', '10000']; var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { @@ -359,4 +359,15 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; + var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; + menu['Ntfy Time'] = { + min: 0, max: timeNames.length-1, + value: Math.max(timeAmts.indexOf(settings.notify.time.increment),0), + format: v => timeNames[v], + onchange: v => { + settings.notify.time.increment = timeAmts[v]; + saveSettings(); + }, + }; }; From a2a16443d69e67c13a49bc0cd84571a476b2297e Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:07:35 -0600 Subject: [PATCH 380/447] Tweak menu option labels --- apps/run/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index 405cb03b8..cc2ba46b8 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -80,7 +80,7 @@ [[300, 1],[200, 0], [100, 1], [200, 0], [300, 1]], [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], ]; - menu[/*LANG*/"Dist Notifctn"] = { + menu[/*LANG*/"Dist Ntfy Ptrn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -90,7 +90,7 @@ saveSettings(); } } - menu[/*LANG*/"Step Notifctn"] = { + menu[/*LANG*/"Step Ntfy Ptrn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -100,7 +100,7 @@ saveSettings(); } } - menu[/*LANG*/"Time Notifctn"] = { + menu[/*LANG*/"Time Ntfy Ptrn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", From 525980d7f7884e96a484a34a842d7dac24d406f5 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:30:58 -0600 Subject: [PATCH 381/447] Cleanup, fix for starting time before track, and some debug --- apps/run/app.js | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index ba8090f51..deeaec45e 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -44,18 +44,10 @@ var exs = ExStats.getStats(statIDs, settings); // Called to start/stop running function onStartStop() { var running = !exs.state.active; - if (running) { - exs.start(); - } else { - exs.stop(); - } - layout.button.label = running ? "STOP" : "START"; - layout.status.label = running ? "RUN" : "STOP"; - layout.status.bgCol = running ? "#0f0" : "#f00"; - // if stopping running, don't clear state - // so we can at least refer to what we've done - layout.render(); + // start/stop recording + // Do this first in case recorder needs to prompt for + // an overwrite before we begin things like the total time if (settings.record && WIDGETS["recorder"]) { if (running) { isMenuDisplayed = true; @@ -68,6 +60,18 @@ function onStartStop() { WIDGETS["recorder"].setRecording(false); } } + + if (running) { + exs.start(); + } else { + exs.stop(); + } + layout.button.label = running ? "STOP" : "START"; + layout.status.label = running ? "RUN" : "STOP"; + layout.status.bgCol = running ? "#0f0" : "#f00"; + // if stopping running, don't clear state + // so we can at least refer to what we've done + layout.render(); } var lc = []; @@ -100,28 +104,23 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ + console.log(`Got notify from ${e}`); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { console.log(buzzPattern); return promise.then(function () { - return Bangle.buzz(buzzPattern[0], buzzPattern[1]); + console.log('Should buzz now'); + return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()) .then(console.log); }); } -// TODO: Should really loop over Object.keys(settings.notify) -if (settings.notify.dist.increment > 0) { - configureNotification(exs.stats.dist); -} - -if (settings.notify.step.increment > 0) { - configureNotification(exs.stats.step); -} - -if (settings.notify.time.increment > 0) { - configureNotification(exs.stats.time); -} +Object.keys(settings.notify).forEach((statType) => { + if (settings.notify[statType].increment > 0) { + configureNotification(exs.stats[statType]); + } +}); // Handle GPS state change for icon Bangle.on("GPS", function(fix) { From 2edad3887f734af66464636117ecb671e070fda7 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:38:23 -0600 Subject: [PATCH 382/447] Menu and typo fixes --- apps/run/app.js | 45 ++++++++++++++++++++++++++------------------ apps/run/settings.js | 12 ++++++------ 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index deeaec45e..c717e12fd 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -44,6 +44,7 @@ var exs = ExStats.getStats(statIDs, settings); // Called to start/stop running function onStartStop() { var running = !exs.state.active; + var prepPromises = []; // start/stop recording // Do this first in case recorder needs to prompt for @@ -51,27 +52,34 @@ function onStartStop() { if (settings.record && WIDGETS["recorder"]) { if (running) { isMenuDisplayed = true; - WIDGETS["recorder"].setRecording(true).then(() => { - isMenuDisplayed = false; - layout.forgetLazyState(); - layout.render(); - }); + prepPromises.push( + WIDGETS["recorder"].setRecording(true).then(() => { + isMenuDisplayed = false; + layout.forgetLazyState(); + layout.render(); + }) + ); } else { - WIDGETS["recorder"].setRecording(false); + prepPromises.push( + WIDGETS["recorder"].setRecording(false) + ); } } - if (running) { - exs.start(); - } else { - exs.stop(); - } - layout.button.label = running ? "STOP" : "START"; - layout.status.label = running ? "RUN" : "STOP"; - layout.status.bgCol = running ? "#0f0" : "#f00"; - // if stopping running, don't clear state - // so we can at least refer to what we've done - layout.render(); + Promise.all(prepPromises) + .then(() => { + if (running) { + exs.start(); + } else { + exs.stop(); + } + layout.button.label = running ? "STOP" : "START"; + layout.status.label = running ? "RUN" : "STOP"; + layout.status.bgCol = running ? "#0f0" : "#f00"; + // if stopping running, don't clear state + // so we can at least refer to what we've done + layout.render(); + }); } var lc = []; @@ -104,7 +112,8 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - console.log(`Got notify from ${e}`); + console.log(`Got notify from ${JSON.stringify(e)}`); + console.log(JSON.stringify(settings.notify[e.id])); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { console.log(buzzPattern); return promise.then(function () { diff --git a/apps/run/settings.js b/apps/run/settings.js index cc2ba46b8..a5faece9d 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -81,31 +81,31 @@ [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], ]; menu[/*LANG*/"Dist Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notifications)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.dist.notification = vibTimes[v]; + settings.notify.dist.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } } menu[/*LANG*/"Step Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notifications)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.step.notification = vibTimes[v]; + settings.notify.step.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } } menu[/*LANG*/"Time Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notifications)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.time.notification = vibTimes[v]; + settings.notify.time.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } From 191dd52747a533df41b1bc3303a616e144f1d268 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:47:42 -0600 Subject: [PATCH 383/447] Debug --- apps/run/app.js | 2 ++ apps/run/settings.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/apps/run/app.js b/apps/run/app.js index c717e12fd..a595ab477 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -113,6 +113,8 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ console.log(`Got notify from ${JSON.stringify(e)}`); + console.log(`Got notify from ${JSON.stringify(e.id)}`); + console.log(JSON.stringify(settings.notify)); console.log(JSON.stringify(settings.notify[e.id])); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { console.log(buzzPattern); diff --git a/apps/run/settings.js b/apps/run/settings.js index a5faece9d..a810ef107 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -88,6 +88,7 @@ settings.notify.dist.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); + console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Step Ntfy Ptrn"] = { @@ -98,6 +99,7 @@ settings.notify.step.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); + console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Time Ntfy Ptrn"] = { @@ -108,6 +110,7 @@ settings.notify.time.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); + console.log(JSON.stringify(settings)); } } Object.assign(menu,{ From 447b896a1402e0fa8f82e45fb84f99a48861216b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:58:34 -0600 Subject: [PATCH 384/447] Remove debug --- apps/run/app.js | 9 +-------- apps/run/settings.js | 3 --- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index a595ab477..01ae22987 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -112,18 +112,11 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - console.log(`Got notify from ${JSON.stringify(e)}`); - console.log(`Got notify from ${JSON.stringify(e.id)}`); - console.log(JSON.stringify(settings.notify)); - console.log(JSON.stringify(settings.notify[e.id])); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { - console.log(buzzPattern); return promise.then(function () { - console.log('Should buzz now'); return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); - }, Promise.resolve()) - .then(console.log); + }, Promise.resolve()); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index a810ef107..a5faece9d 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -88,7 +88,6 @@ settings.notify.dist.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); - console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Step Ntfy Ptrn"] = { @@ -99,7 +98,6 @@ settings.notify.step.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); - console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Time Ntfy Ptrn"] = { @@ -110,7 +108,6 @@ settings.notify.time.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); - console.log(JSON.stringify(settings)); } } Object.assign(menu,{ From 5dca4a8b1e029294a2cc7f402dd19a8696d4924e Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 16:02:48 -0600 Subject: [PATCH 385/447] Notifications submenu and fix for displaying vibTimes in settings --- apps/run/settings.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index a5faece9d..b4073008d 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -69,19 +69,23 @@ saveSettings(); } }; + var notificationsMenu = { + '< Back': function() { E.showMenu(menu) }, + } + menu[/*LANG*/"Notifications"] = function() { E.showMenu(notificationsMenu)}; ExStats.appendMenuItems(menu, settings, saveSettings); - ExStats.appendNotifyMenuItems(menu, settings, saveSettings); + ExStats.appendNotifyMenuItems(notificationsMenu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var vibTimes = [ [], [[100, 1]], [[300, 1]], - [[300, 1], [200, 0], [300, 1]], - [[300, 1],[200, 0], [100, 1], [200, 0], [300, 1]], - [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], + [[300, 1], [300, 0], [300, 1]], + [[300, 1],[300, 0], [100, 1], [300, 0], [300, 1]], + [[300, 1],[300, 0],[300, 1],[300, 0],[300, 1]], ]; menu[/*LANG*/"Dist Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notifications)), + value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.dist.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -91,7 +95,7 @@ } } menu[/*LANG*/"Step Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notifications)), + value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.step.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -101,7 +105,7 @@ } } menu[/*LANG*/"Time Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notifications)), + value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.time.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { From 93dedd9015e671389af131e3c899eea9c73d2142 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 16:14:07 -0600 Subject: [PATCH 386/447] Consolidating menus --- apps/run/settings.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index b4073008d..29a2f43cc 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -84,7 +84,7 @@ [[300, 1],[300, 0], [100, 1], [300, 0], [300, 1]], [[300, 1],[300, 0],[300, 1],[300, 0],[300, 1]], ]; - menu[/*LANG*/"Dist Ntfy Ptrn"] = { + notificationsMenu[/*LANG*/"Dist Pattern"] = { value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.dist.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -94,7 +94,7 @@ saveSettings(); } } - menu[/*LANG*/"Step Ntfy Ptrn"] = { + notificationsMenu[/*LANG*/"Step Pattern"] = { value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.step.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -104,7 +104,7 @@ saveSettings(); } } - menu[/*LANG*/"Time Ntfy Ptrn"] = { + notificationsMenu[/*LANG*/"Time Pattern"] = { value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.time.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -114,7 +114,10 @@ saveSettings(); } } - Object.assign(menu,{ + var boxMenu = { + '< Back': function() { E.showMenu(menu) }, + } + Object.assign(boxMenu,{ 'Box 1': getBoxChooser("B1"), 'Box 2': getBoxChooser("B2"), 'Box 3': getBoxChooser("B3"), @@ -122,5 +125,6 @@ 'Box 5': getBoxChooser("B5"), 'Box 6': getBoxChooser("B6"), }); + menu[/*LANG*/"Boxes"] = function() { E.showMenu(boxMenu)}; E.showMenu(menu); }) From e1e9b6e96a1d5cd96bd48dd9cb04ffefea1ec5bd Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 17:01:53 -0600 Subject: [PATCH 387/447] Better comment --- apps/run/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/run/app.js b/apps/run/app.js index 01ae22987..45daf878e 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -48,7 +48,7 @@ function onStartStop() { // start/stop recording // Do this first in case recorder needs to prompt for - // an overwrite before we begin things like the total time + // an overwrite before we start tracking exstats if (settings.record && WIDGETS["recorder"]) { if (running) { isMenuDisplayed = true; From 4253f7db260b9d7a09b5b86198b20b70e4fd7fe3 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 17:26:07 -0600 Subject: [PATCH 388/447] Update README.md --- apps/run/README.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/run/README.md b/apps/run/README.md index 67d62185d..89750eb7d 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -25,7 +25,7 @@ so if you have no GPS lock you just need to wait. ## Recording Tracks When the `Recorder` app is installed, `Run` will automatically start and stop tracks -as needed, prompting you to overwrite or begin a new track, if necessary. +as needed, prompting you to overwrite or begin a new track if necessary. ## Settings @@ -34,9 +34,26 @@ Under `Settings` -> `App` -> `Run` you can change settings for this app. * `Record Run` (only displayed if `Recorder` app installed) should the Run app automatically record GPS/HRM/etc data every time you start a run? * `Pace` is the distance that pace should be shown over - 1km, 1 mile, 1/2 Marathon or 1 Marathon -* `Box 1/2/3/4/5/6` are what should be shown in each of the 6 boxes on the display. From the top left, down. - If you set it to `-` nothing will be displayed, so you can display only 4 boxes of information - if you wish by setting the last 2 boxes to `-`. +* `Boxes` leads to a submenu where you can configure what is shown in each of the 6 boxes on the display. + Available stats are "Time", "Distance", "Steps", "Heart (BPM)", "Pace (avg)", "Pace (curr)", "Speed", and "Cadence". + Any box set to "-" will display no information. + * Box 1 is the top left (defaults to "Distance") + * Box 2 is the top right (defaults to "Time") + * Box 3 is the middle left (defaults to "Pace (avg)") + * Box 4 is the middle right (defaults to "Heart (BPM)") + * Box 5 is the bottom left (defaults to "Steps") + * Box 6 is the bottom right (defaults to "Cadence") +* `Notifications` leads to a submenu where you can configure if the app will notify you after +your distance, steps, or time repeatedly pass your configured thresholds + * `Ntfy Dist`: The distance that you must pass before you are notified. Follows the `Pace` options + * "Off" (default), "1km", "1 mile", "1/2 Marathon", "1 Marathon" + * `Ntfy Steps`: The number of steps that must pass before you are notified. + * "Off" (default), 100, 500, 1000, 5000, 10000 + * `Ntfy Time`: The amount of time that must pass before you are notified. + * "Off" (default), "30 sec", "1 min", "2 min", "5 min", "10 min", "30 min", "1 hour" + * `Dist Pattern`: The vibration pattern to use to notify you about meeting your distance threshold + * `Step Pattern`: The vibration pattern to use to notify you about meeting your step threshold + * `Time Pattern`: The vibration pattern to use to notify you about meeting your time threshold ## TODO From 539ea98a29c1043fe455aa5aedf702c0ad2a8344 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 17:27:21 -0600 Subject: [PATCH 389/447] Update CHANGELOG --- apps/run/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index bd478c12e..0a697ecb9 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -6,4 +6,4 @@ 0.05: exstats updated so update 'distance' label is updated, option for 'speed' 0.06: Add option to record a run using the recorder app automatically 0.07: Fix crash if an odd number of active boxes are configured (fix #1473) -0.08: Support all stats from exstats \ No newline at end of file +0.08: Added support for notifications from exstats. Support all stats from exstats \ No newline at end of file From 9414d785dd878b7dad775e580bcd93969723b1b5 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 21:12:53 -0600 Subject: [PATCH 390/447] Removing yarn.lock --- yarn.lock | 864 ------------------------------------------------------ 1 file changed, 864 deletions(-) delete mode 100644 yarn.lock diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index f3224947f..000000000 --- a/yarn.lock +++ /dev/null @@ -1,864 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^7.2.0, acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -ajv@^6.10.0, ajv@^6.10.2: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^4.0.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-scope@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" - integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" - esquery "^1.2.0" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.14" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.0.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -glob-parent@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -import-fresh@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lodash@^4.17.14, lodash@^4.17.19: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver@^7.2.1: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-json-comments@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From 73b493bb86891d572c05260c54be8a24b105b1f1 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 7 Mar 2022 15:54:53 +0000 Subject: [PATCH 391/447] recorder 0.12: Fix 'Back' label positioning on track/graph display, make translateable --- apps/recorder/ChangeLog | 1 + apps/recorder/app.js | 52 +++++++++++++++++++------------------ apps/recorder/metadata.json | 2 +- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 60477ae97..963944144 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -15,3 +15,4 @@ 0.09: Show correct number for log in overwrite prompt 0.10: Fix broken recorder settings (when launched from settings app) 0.11: Fix KML and GPX export when there is no GPS data +0.12: Fix 'Back' label positioning on track/graph display, make translateable diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 7075563aa..d900c12c1 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -49,11 +49,11 @@ function showMainMenu() { }; } const mainmenu = { - '': { 'title': 'Recorder' }, + '': { 'title': /*LANG*/'Recorder' }, '< Back': ()=>{load();}, - 'RECORD': { + /*LANG*/'RECORD': { value: !!settings.recording, - format: v=>v?"On":"Off", + format: v=>v?/*LANG*/"On":/*LANG*/"Off", onchange: v => { setTimeout(function() { E.showMenu(); @@ -66,7 +66,7 @@ function showMainMenu() { }, 1); } }, - 'File #': { + /*LANG*/'File #': { value: getTrackNumber(settings.file), min: 0, max: 99, @@ -77,8 +77,8 @@ function showMainMenu() { updateSettings(); } }, - 'View Tracks': ()=>{viewTracks();}, - 'Time Period': { + /*LANG*/'View Tracks': ()=>{viewTracks();}, + /*LANG*/'Time Period': { value: settings.period||10, min: 1, max: 120, @@ -103,15 +103,15 @@ function showMainMenu() { function viewTracks() { const menu = { - '': { 'title': 'Tracks' } + '': { 'title': /*LANG*/'Tracks' } }; var found = false; require("Storage").list(/^recorder\.log.*\.csv$/,{sf:true}).forEach(filename=>{ found = true; - menu["Track "+getTrackNumber(filename)] = ()=>viewTrack(filename,false); + menu[/*LANG*/"Track "+getTrackNumber(filename)] = ()=>viewTrack(filename,false); }); if (!found) - menu["No Tracks found"] = function(){}; + menu[/*LANG*/"No Tracks found"] = function(){}; menu['< Back'] = () => { showMainMenu(); }; return E.showMenu(menu); } @@ -175,38 +175,38 @@ function asTime(v){ function viewTrack(filename, info) { if (!info) { - E.showMessage("Loading...","Track "+getTrackNumber(filename)); + E.showMessage(/*LANG*/"Loading...",/*LANG*/"Track "+getTrackNumber(filename)); info = getTrackInfo(filename); } //console.log(info); const menu = { - '': { 'title': 'Track '+info.fn } + '': { 'title': /*LANG*/'Track '+info.fn } }; if (info.time) menu[info.time.toISOString().substr(0,16).replace("T"," ")] = function(){}; menu["Duration"] = { value : asTime(info.duration)}; menu["Records"] = { value : ""+info.records }; if (info.fields.includes("Latitude")) - menu['Plot Map'] = function() { + menu[/*LANG*/'Plot Map'] = function() { info.qOSTM = false; plotTrack(info); }; if (osm && info.fields.includes("Latitude")) - menu['Plot OpenStMap'] = function() { + menu[/*LANG*/'Plot OpenStMap'] = function() { info.qOSTM = true; plotTrack(info); } if (info.fields.includes("Altitude")) - menu['Plot Alt.'] = function() { + menu[/*LANG*/'Plot Alt.'] = function() { plotGraph(info, "Altitude"); }; if (info.fields.includes("Latitude")) - menu['Plot Speed'] = function() { + menu[/*LANG*/'Plot Speed'] = function() { plotGraph(info, "Speed"); }; // TODO: steps, heart rate? - menu['Erase'] = function() { - E.showPrompt("Delete Track?").then(function(v) { + menu[/*LANG*/'Erase'] = function() { + E.showPrompt(/*LANG*/"Delete Track?").then(function(v) { if (v) { settings.recording = false; updateSettings(); @@ -238,7 +238,7 @@ function viewTrack(filename, info) { } E.showMenu(); // remove menu - E.showMessage("Drawing...","Track "+info.fn); + E.showMessage(/*LANG*/"Drawing...",/*LANG*/"Track "+info.fn); g.flip(); // on buffered screens, draw a not saying we're busy g.clear(1); var s = require("Storage"); @@ -305,17 +305,18 @@ function viewTrack(filename, info) { g.drawString(require("locale").distance(dist),g.getWidth() / 2, g.getHeight() - 20); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); + var isBTN3 = "BTN3" in global; + g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2)); setWatch(function() { viewTrack(info.fn, info); - }, global.BTN3||BTN1); + }, isBTN3?BTN3:BTN1); Bangle.drawWidgets(); g.flip(); } function plotGraph(info, style) { "ram" E.showMenu(); // remove menu - E.showMessage("Calculating...","Track "+info.fn); + E.showMessage(/*LANG*/"Calculating...",/*LANG*/"Track "+info.fn); var filename = info.filename; var infn = new Float32Array(80); var infc = new Uint16Array(80); @@ -334,7 +335,7 @@ function viewTrack(filename, info) { strt = c[timeIdx]; } if (style=="Altitude") { - title = "Altitude (m)"; + title = /*LANG*/"Altitude (m)"; var altIdx = info.fields.indexOf("Altitude"); while(l!==undefined) { ++nl;c=l.split(",");l = f.readLine(f); @@ -344,7 +345,7 @@ function viewTrack(filename, info) { infc[i]++; } } else if (style=="Speed") { - title = "Speed (m/s)"; + title = /*LANG*/"Speed (m/s)"; var latIdx = info.fields.indexOf("Latitude"); var lonIdx = info.fields.indexOf("Longitude"); // skip until we find our first data @@ -404,10 +405,11 @@ function viewTrack(filename, info) { }); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); + var isBTN3 = "BTN3" in global; + g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2)); setWatch(function() { viewTrack(info.filename, info); - }, global.BTN3||BTN1); + }, isBTN3?BTN3:BTN1); g.flip(); } diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 56865e885..09873dada 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.11", + "version": "0.12", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget", From 09dc646415facd7d854629553306f5e0a8612778 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 7 Mar 2022 10:14:51 -0600 Subject: [PATCH 392/447] Removing unneeded message --- apps/recorder/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/recorder/app.js b/apps/recorder/app.js index d28cef585..7075563aa 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -305,7 +305,7 @@ function viewTrack(filename, info) { g.drawString(require("locale").distance(dist),g.getWidth() / 2, g.getHeight() - 20); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); // TODO: this position depends on Bangle1 vs 2 + g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); setWatch(function() { viewTrack(info.fn, info); }, global.BTN3||BTN1); From 40db573458e17543221c7d2699f3224a5e8b3ab8 Mon Sep 17 00:00:00 2001 From: Marco H Date: Mon, 7 Mar 2022 17:59:18 +0100 Subject: [PATCH 393/447] Initial version of Barometer Alarm Widget --- apps/widbaroalarm/ChangeLog | 1 + apps/widbaroalarm/README.md | 24 ++++ apps/widbaroalarm/default.json | 10 ++ apps/widbaroalarm/metadata.json | 19 +++ apps/widbaroalarm/screenshot.png | Bin 0 -> 2707 bytes apps/widbaroalarm/settings.js | 85 +++++++++++++ apps/widbaroalarm/widget.js | 199 +++++++++++++++++++++++++++++++ apps/widbaroalarm/widget.png | Bin 0 -> 9872 bytes apps/widbaroalarm/widget24.png | Bin 0 -> 10100 bytes 9 files changed, 338 insertions(+) create mode 100644 apps/widbaroalarm/ChangeLog create mode 100644 apps/widbaroalarm/README.md create mode 100644 apps/widbaroalarm/default.json create mode 100644 apps/widbaroalarm/metadata.json create mode 100644 apps/widbaroalarm/screenshot.png create mode 100644 apps/widbaroalarm/settings.js create mode 100644 apps/widbaroalarm/widget.js create mode 100644 apps/widbaroalarm/widget.png create mode 100644 apps/widbaroalarm/widget24.png diff --git a/apps/widbaroalarm/ChangeLog b/apps/widbaroalarm/ChangeLog new file mode 100644 index 000000000..ec66c5568 --- /dev/null +++ b/apps/widbaroalarm/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version diff --git a/apps/widbaroalarm/README.md b/apps/widbaroalarm/README.md new file mode 100644 index 000000000..6708b1e2b --- /dev/null +++ b/apps/widbaroalarm/README.md @@ -0,0 +1,24 @@ +# Barometer alarm widget + +Get a notification when the pressure reaches defined thresholds. + +![Screenshot](screenshot.png) + +## Settings + +* Interval: check interval of sensor data in minutes. 0 to disable automatic check. +* Low alarm: Toggle low alarm + * Low threshold: Warn when pressure drops below this value +* High alarm: Toggle high alarm + * High threshold: Warn when pressure exceeds above this value +* Change alarm: Warn when pressure changes more than this value in the recent 3 hours (having at least 30 min of data) + 0 to disable this alarm. +* Show widget: Enable/disable widget visibility +* Buzz on alarm: Enable/disable buzzer on alarm + + +## Widget +The widget shows two rows: pressure value of last measurement and pressure average of the the last three hours. + +## Creator +Marco ([myxor](https://github.com/myxor)) diff --git a/apps/widbaroalarm/default.json b/apps/widbaroalarm/default.json new file mode 100644 index 000000000..7dbe6fc17 --- /dev/null +++ b/apps/widbaroalarm/default.json @@ -0,0 +1,10 @@ +{ + "buzz": true, + "lowalarm": false, + "min": 950, + "highalarm": false, + "max": 1030, + "changeIn3h": 2, + "show": true, + "interval": 15 +} diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json new file mode 100644 index 000000000..3dd02019d --- /dev/null +++ b/apps/widbaroalarm/metadata.json @@ -0,0 +1,19 @@ +{ + "id": "widbaroalarm", + "name": "Barometer alarm widget", + "shortName": "Barometer alarm", + "version": "0.01", + "description": "A widget that can alarm on when the pressure reaches defined thresholds.", + "icon": "widget.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "widget", + "tags": "tool,barometer", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widbaroalarm.wid.js","url":"widget.js"}, + {"name":"widbaroalarm.settings.js","url":"settings.js"}, + {"name":"widbaroalarm.default.json","url":"default.json"} + ], + "data": [{"name":"widbaroalarm.json"}, {"name":"widbaroalarm.log"}] +} diff --git a/apps/widbaroalarm/screenshot.png b/apps/widbaroalarm/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..c398b0aa875007e1d4f9d3b8aa0eaafad35a3b1a GIT binary patch literal 2707 zcmd6p`#0448pl8188bAEXey+HjdB}NWN*i%CJu7Tq)CRM+Dy4e7}xoZ5@L5z$caYb z*fxW&lg4Ej(~Zb9Be}<%**~7Y;GEA|pXXVh^;zqAp7lJR^?rS_k9#^R z<1}#q0A*JfN3z`4|FxB{a$DE(fhKoQEZLa^YG3W1mLC*iNv=Lh@|B|Wa~1$NJ6Fde zJ`9?;gjGWHO zt6a&(0jYJFRFe3WOVmi&_--QJ*Z+wx-3EIRidC)o@F9`Qruq+;!ggHA;+3Xh)L`}K zzZJFCt7^>?9fSw!6{5UNlSmuSONP1$mz^fK%zGgeK-&^}xL8fJr<7iF)5s;;Mv~EN z?`ikZ3Q^8-c(-m^Br~$EjdZ9UUA_NFu!}|}S<-_5MbEtB9P1ICk&s;N4n%L~)w_?PGTxm;_DJk~bi=1ruiwOvp7IjslLHC*^TDN-0J?KaYq zeeF1z6B%B{Jy7{OHZo*#kupDSFg+St9p5P-`M$-x%Q<2?_S|JtbU z6jb16BA6#UTC@B6a{s6dp;<{p0a-RPo0;QyJYtda;U>qDzDd^zjpUKkBOJC1V-#P- z?DI_AdJ1hSCb_&F3qTi|b|j$vVsaO~Fdf0&lXD9+X?aBBX^@~jc?;x^LKkyUncZuK zG1@%R9X3uXENMNp^h)b-k~%4M$}`#Gab9w)dOF?~>z8v4aW%JSlRjTCag?$#S>{ZHF(M1cokLWnV4Qpmk`^btfo4ll5gXmH( zl;kw?2&WUL&emh?VpA$U={(@}FmxBMv!@xI+X{{RmRBDDfOZPSfFI+QqxZmPbed40 z*e2yi6~z3e9|SzL?28qHG+a0URBq9Jg*L~RQviG-Q)LR$z>-Y>Qq_|=5Af)!9Y8er zwkHu>Wews$^o;baE$BJ?zXxLDG?n>)#{~fy8L{s#Wuy)10EV%ooC3 zBcd&bxguQ`%^P0r}v%;&F@@%Bb}y;ExeqQ^`;`cqneU4$~@|IMmd&$XVB9WEU*#Qf*jug9`Sj)~)AV zs=lC=ui8lW{9Ne5nHyNOIQ!;Mn5Y4}9d0>Vi&2EDr`#&=`oZ-!ru>b8xq)L7?Lj&6 zAqu%0em7cBVQ(e`f!BDHwLkH;CZ&WRKJ2%qtqfb0=Gi;1MJ+tDnTV5lz{yuDa`k@F zFPSONDCOuj8DyS}u3|>9T-s(i83xRnoiT%`!dgttd_>7Kv~2C?3;{$1qtB(<5T7*? zrfLb@Z6xk`1wzF<3egXfjm$TVvc+9K56|=NQZHgf`8I!Lr9!vWejPL;ibgh=T8M!T znK&jmRX}Ov*EUhc*8&|*Pnkf1u%TB}lrVH6*`vIq?lG3HHd2PE+W)SRHJAQSi@uoB z1lher+2TY6X109|g=*J78`meW+^oz2dR!OR2NDl-u)*4UboeHoDBieWy~8}EZXW=*Cl*U z@4Hav0k9(OZ1KBRAFvd;5E_-Zw7n%nUre0p-&*i}a7J%rr+CRd8Fc8O(NcH)h~^W( zG#FnMkoOcPxTnjZL?DranuHb^$xl z?ulu|h-@x@8-1xT6JNzl_2+rkvA;d0_!6H|Qky5EAotsbNkwU&V>$MEYaSTi%|0eQ zX3zLVXA}@l-wC>CVVFy(*yvcn{VMpO?zFCeut<{jdPj2dpv2EceMwB zr>PT$6%vL~66=|BtP`&jj1f)6+QDZiN&ckPPwL>h5Bt$L4%Ew4$5GzQTQdinsSt>F z%VN36F-T7BjhAyRa+8H>6#&k^@rENYV3??j{XwodE(<#aaul{3JUv{F0=uj1&$Y|P z&~im1%Ll-EZ|LDIC@@=~ioPXhVEJmUSkB6E!dV?M^#7g|VG86z?C9gyC;wOiS0_)$ JT2fH@e*hao { + return x != 0 ? x + ' min' : 'off'; + }, + onchange: x => save("interval", x) + }, + "Low alarm": { + value: settings.lowalarm, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save("lowalarm", x), + }, + "Low threshold": { + value: settings.min, + min: 600, + max: 1000, + step: 10, + onchange: x => save("min", x), + }, + "High alarm": { + value: settings.highalarm, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save("highalarm", x), + }, + "High threshold": { + value: settings.max, + min: 1000, + max: 1100, + step: 10, + onchange: x => save("max", x), + }, + "Change alarm": { + value: settings.changeIn3h, + min: 0, + max: 10, + step: 1, + format: x => { + return x != 0 ? x + ' hPa/3h' : 'off'; + }, + onchange: x => save("changeIn3h", x) + }, + "Show widget": { + value: settings.show, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save('show', x) + }, + "Buzz on alarm": { + value: settings.buzz, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save('buzz', x) + }, + }; + E.showMenu(menu); + } + + showMainMenu(); +}); diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js new file mode 100644 index 000000000..b0a8f110c --- /dev/null +++ b/apps/widbaroalarm/widget.js @@ -0,0 +1,199 @@ +(function() { + let lastPressure; + let avrPressure; + let threeHourAvrPressure; + + const LOG_FILE = "widbaroalarm.log.json"; + const SETTINGS_FILE = "widbaroalarm.json"; + const storage = require('Storage'); + let settings = Object.assign( + storage.readJSON("widbaroalarm.default.json", true) || {}, + storage.readJSON(SETTINGS_FILE, true) || {} + ); + + function setting(key) { + return settings[key]; + } + const interval = setting("interval"); + + let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours + + function showAlarm(text, value, value2, icon) { + if (text == undefined || value == undefined) return; + const Layout = require("Layout"); + layout = new Layout({ + type: "v", + c: [{ + type: "h", + c: [{ + type: "img", + pad: 0, + src: function() { + return icon || require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")); + } + }, + { + type: "txt", + id: "title", + font: "6x8:2", + label: "Alarm", + pad: 2 + }, + ] + }, + { + type: "txt", + id: "text", + font: "6x8:2", + label: text, + pad: 3 + }, + { + type: "txt", + id: "value", + font: "6x8:2", + label: value, + halign: 0, + pad: 3 + }, + { + type: "txt", + id: "value2", + font: "6x8:1", + label: value2 || "", + halign: 0, + pad: 3 + }, + ] + }, { + btns: [{ + label: "OK", + cb: function() { + load(); // close + } + }], + lazy: false + }); + + g.clear(); + layout.render(); + + if (setting("buzz") && + !(storage.readJSON('setting.json', 1) || {}).quiet) { + Bangle.buzz(); + } + } + + let alreadyWarned = false; + + function baroHandler(data) { + if (data === undefined) { + setTimeout(() => Bangle.getPressure().then(baroHandler), 500); + } else { + lastPressure = Math.round(data.pressure); + if (lastPressure == undefined || lastPressure <= 0) return; + + const ts = Math.round(Date.now() / 1000); // seconds + const d = { + "ts": ts, + "p": lastPressure + }; + + // delete entries older than 3h + for (let i = 0; i < history3.length; i++) { + if (history3[i]["ts"] < ts - (3 * 60 * 60)) { + history3.shift(); + } + } + // delete oldest entries until we have max 50 + while (history3.length > 50) { + history3.shift(); + } + + history3.push(d); + // write data to storage + storage.writeJSON(LOG_FILE, history3); + + // we need at least three entries for reliable detection + if (history3.length >= 3) { + + // calculate average of recent three entries + avrPressure = (history3[history3.length - 1]["p"] + history3[history3.length - 2]["p"] + history3[history3.length - 3]["p"]) / 3; + + if (setting("lowalarm") && avrPressure <= setting("min")) { + showAlarm("Pressure low", Math.round(avrPressure) + " hPa"); + alreadyWarned = true; + } + if (setting("highalarm") && avrPressure >= setting("max")) { + showAlarm("Pressure high", Math.round(avrPressure) + " hPa"); + alreadyWarned = true; + } + + if (!alreadyWarned) { + // 3h change detection + const threeHourChange = setting("changeIn3h"); + if (threeHourChange > 0) { + // we need at least 30min of data for reliable detection + if (history3[0]["ts"] > ts - (30 * 60)) { + return; + } + + // Average of oldest three entries + const oldestAvgPressure = (history3[0]["p"] + history3[1]["p"] + history3[2]["p"]) / 3; + if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { + const diff = oldestAvgPressure - avrPressure; + if (Math.abs(diff) > threeHourChange) { + showAlarm("Pressure " + (diff > 0 ? "drop" : "raise"), (Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h", + Math.round(oldestAvgPressure) + " hPa -> " + Math.round(avrPressure) + " hPa"); + } + } + } + } + } + + // calculate 3h average for widget + let sum = 0; + for (let i = 0; i < history3.length; i++) { + sum += history3[i]["p"]; + } + threeHourAvrPressure = sum / history3.length; + } + } + + function check() { + Bangle.getPressure().then(baroHandler); + } + + function reload() { + check(); + } + + function draw() { + g.reset(); + if (setting("show") && lastPressure != undefined) { + g.setFont("6x8", 1).setFontAlign(1, 0); + g.drawString(Math.round(lastPressure), this.x + 24, this.y + 6); + if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { + g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); + } + } + } + + if (global.WIDGETS != undefined && typeof WIDGETS === "object") { + WIDGETS["baroalarm"] = { + width: setting("show") ? 24 : 0, + reload: reload, + area: "tr", + draw: draw + }; + } + + // Let's delay check a bit + setTimeout(function() { + check(); + if (interval > 0) { + setInterval(check, interval * 60000); + } + }, 10000); + +})(); diff --git a/apps/widbaroalarm/widget.png b/apps/widbaroalarm/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..5be2921432b2d43167309be3ca50e52e3216dc71 GIT binary patch literal 9872 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 am%74g<61aCeHq`{01Xvg Date: Mon, 7 Mar 2022 21:37:41 +0100 Subject: [PATCH 394/447] Use notify module to show notification --- apps/widbaroalarm/metadata.json | 2 +- apps/widbaroalarm/screenshot.png | Bin 2707 -> 0 bytes apps/widbaroalarm/widget.js | 76 ++++++------------------------- 3 files changed, 14 insertions(+), 64 deletions(-) delete mode 100644 apps/widbaroalarm/screenshot.png diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json index 3dd02019d..0976df531 100644 --- a/apps/widbaroalarm/metadata.json +++ b/apps/widbaroalarm/metadata.json @@ -5,10 +5,10 @@ "version": "0.01", "description": "A widget that can alarm on when the pressure reaches defined thresholds.", "icon": "widget.png", - "screenshots": [{"url":"screenshot.png"}], "type": "widget", "tags": "tool,barometer", "supports": ["BANGLEJS2"], + "dependencies": {"notify":"type"}, "readme": "README.md", "storage": [ {"name":"widbaroalarm.wid.js","url":"widget.js"}, diff --git a/apps/widbaroalarm/screenshot.png b/apps/widbaroalarm/screenshot.png deleted file mode 100644 index c398b0aa875007e1d4f9d3b8aa0eaafad35a3b1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2707 zcmd6p`#0448pl8188bAEXey+HjdB}NWN*i%CJu7Tq)CRM+Dy4e7}xoZ5@L5z$caYb z*fxW&lg4Ej(~Zb9Be}<%**~7Y;GEA|pXXVh^;zqAp7lJR^?rS_k9#^R z<1}#q0A*JfN3z`4|FxB{a$DE(fhKoQEZLa^YG3W1mLC*iNv=Lh@|B|Wa~1$NJ6Fde zJ`9?;gjGWHO zt6a&(0jYJFRFe3WOVmi&_--QJ*Z+wx-3EIRidC)o@F9`Qruq+;!ggHA;+3Xh)L`}K zzZJFCt7^>?9fSw!6{5UNlSmuSONP1$mz^fK%zGgeK-&^}xL8fJr<7iF)5s;;Mv~EN z?`ikZ3Q^8-c(-m^Br~$EjdZ9UUA_NFu!}|}S<-_5MbEtB9P1ICk&s;N4n%L~)w_?PGTxm;_DJk~bi=1ruiwOvp7IjslLHC*^TDN-0J?KaYq zeeF1z6B%B{Jy7{OHZo*#kupDSFg+St9p5P-`M$-x%Q<2?_S|JtbU z6jb16BA6#UTC@B6a{s6dp;<{p0a-RPo0;QyJYtda;U>qDzDd^zjpUKkBOJC1V-#P- z?DI_AdJ1hSCb_&F3qTi|b|j$vVsaO~Fdf0&lXD9+X?aBBX^@~jc?;x^LKkyUncZuK zG1@%R9X3uXENMNp^h)b-k~%4M$}`#Gab9w)dOF?~>z8v4aW%JSlRjTCag?$#S>{ZHF(M1cokLWnV4Qpmk`^btfo4ll5gXmH( zl;kw?2&WUL&emh?VpA$U={(@}FmxBMv!@xI+X{{RmRBDDfOZPSfFI+QqxZmPbed40 z*e2yi6~z3e9|SzL?28qHG+a0URBq9Jg*L~RQviG-Q)LR$z>-Y>Qq_|=5Af)!9Y8er zwkHu>Wews$^o;baE$BJ?zXxLDG?n>)#{~fy8L{s#Wuy)10EV%ooC3 zBcd&bxguQ`%^P0r}v%;&F@@%Bb}y;ExeqQ^`;`cqneU4$~@|IMmd&$XVB9WEU*#Qf*jug9`Sj)~)AV zs=lC=ui8lW{9Ne5nHyNOIQ!;Mn5Y4}9d0>Vi&2EDr`#&=`oZ-!ru>b8xq)L7?Lj&6 zAqu%0em7cBVQ(e`f!BDHwLkH;CZ&WRKJ2%qtqfb0=Gi;1MJ+tDnTV5lz{yuDa`k@F zFPSONDCOuj8DyS}u3|>9T-s(i83xRnoiT%`!dgttd_>7Kv~2C?3;{$1qtB(<5T7*? zrfLb@Z6xk`1wzF<3egXfjm$TVvc+9K56|=NQZHgf`8I!Lr9!vWejPL;ibgh=T8M!T znK&jmRX}Ov*EUhc*8&|*Pnkf1u%TB}lrVH6*`vIq?lG3HHd2PE+W)SRHJAQSi@uoB z1lher+2TY6X109|g=*J78`meW+^oz2dR!OR2NDl-u)*4UboeHoDBieWy~8}EZXW=*Cl*U z@4Hav0k9(OZ1KBRAFvd;5E_-Zw7n%nUre0p-&*i}a7J%rr+CRd8Fc8O(NcH)h~^W( zG#FnMkoOcPxTnjZL?DranuHb^$xl z?ulu|h-@x@8-1xT6JNzl_2+rkvA;d0_!6H|Qky5EAotsbNkwU&V>$MEYaSTi%|0eQ zX3zLVXA}@l-wC>CVVFy(*yvcn{VMpO?zFCeut<{jdPj2dpv2EceMwB zr>PT$6%vL~66=|BtP`&jj1f)6+QDZiN&ckPPwL>h5Bt$L4%Ew4$5GzQTQdinsSt>F z%VN36F-T7BjhAyRa+8H>6#&k^@rENYV3??j{XwodE(<#aaul{3JUv{F0=uj1&$Y|P z&~im1%Ll-EZ|LDIC@@=~ioPXhVEJmUSkB6E!dV?M^#7g|VG86z?C9gyC;wOiS0_)$ JT2fH@e*hao= setting("max")) { - showAlarm("Pressure high", Math.round(avrPressure) + " hPa"); + showAlarm("Pressure high: " + Math.round(avrPressure) + " hPa"); alreadyWarned = true; } @@ -143,8 +92,9 @@ if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { const diff = oldestAvgPressure - avrPressure; if (Math.abs(diff) > threeHourChange) { - showAlarm("Pressure " + (diff > 0 ? "drop" : "raise"), (Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h", - Math.round(oldestAvgPressure) + " hPa -> " + Math.round(avrPressure) + " hPa"); + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", + "Pressure " + (diff > 0 ? "drop" : "raise")); } } } @@ -188,7 +138,7 @@ }; } - // Let's delay check a bit + // Let's delay the first check a bit setTimeout(function() { check(); if (interval > 0) { From 9ff42c928e3fb18141886040b110cf02d2f7c33f Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 7 Mar 2022 22:46:57 +0100 Subject: [PATCH 395/447] messages: auto-open music --- apps/messages/ChangeLog | 1 + apps/messages/README.md | 5 ++-- apps/messages/app.js | 58 +++++++++++++++++++++++++++---------- apps/messages/lib.js | 18 ++++++++++-- apps/messages/metadata.json | 2 +- apps/messages/settings.js | 6 ++++ apps/messages/widget.js | 2 +- 7 files changed, 70 insertions(+), 22 deletions(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index bd40868a5..f39b75c4d 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -37,3 +37,4 @@ 0.23: Change message colors to match current theme instead of using green Now attempt to use Large/Big/Medium fonts, and allow minimum font size to be configured 0.24: Remove left-over debug statement +0.25: Setting to auto-open music diff --git a/apps/messages/README.md b/apps/messages/README.md index cce4391e7..655c549b9 100644 --- a/apps/messages/README.md +++ b/apps/messages/README.md @@ -13,12 +13,13 @@ and `Messages`: * `Vibrate` - This is the pattern of buzzes that should be made when a new message is received * `Repeat` - How often should buzzes repeat - the default of 4 means the Bangle will buzz every 4 seconds -* `Unread Timer` - when a new message is received we go into the Messages app. +* `Unread Timer` - When a new message is received we go into the Messages app. If there is no user input for this amount of time then the app will exit and return to the clock where a ringing bell will be shown in the Widget bar. -* `Min Font` - the minimum font size used when displaying messages on the screen. A bigger font +* `Min Font` - The minimum font size used when displaying messages on the screen. A bigger font is chosen if there isn't much message text, but this specifies the smallest the font should get before it starts getting clipped. +* `Auto-Open Music` - Should the app automatically open when the phone starts playing music? ## New Messages diff --git a/apps/messages/app.js b/apps/messages/app.js index 3f3b80080..403f9b5d8 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -26,6 +26,8 @@ var fontSmall = "6x8"; var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2"; var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2"; var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4"; +var active; // active screen +var openMusic = false; // go back to music screen after we handle something else? // hack for 2v10 firmware's lack of ':size' font handling try { g.setFont("6x8:2"); @@ -50,10 +52,14 @@ var MESSAGES = require("Storage").readJSON("messages.json",1)||[]; if (!Array.isArray(MESSAGES)) MESSAGES=[]; var onMessagesModified = function(msg) { // TODO: if new, show this new one - if (msg && msg.new && !((require('Storage').readJSON('setting.json', 1) || {}).quiet)) { + if (msg && msg.id!=="music" && msg.new && !((require('Storage').readJSON('setting.json', 1) || {}).quiet)) { if (WIDGETS["messages"]) WIDGETS["messages"].buzz(); else Bangle.buzz(); } + if (msg && msg.id=="music") { + if (msg.state && msg.state!="play") openMusic = false; // no longer playing music to go back to + if (active!="music") return; // don't open music over other screens + } showMessage(msg&&msg.id); }; function saveMessages() { @@ -135,6 +141,7 @@ function getMessageImageCol(msg,def) { } function showMapMessage(msg) { + active = "map"; var m; var distance, street, target, eta; m=msg.title.match(/(.*) - (.*)/); @@ -168,12 +175,14 @@ function showMapMessage(msg) { msg.new = false; saveMessages(); layout = undefined; - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); + checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:0}); }); } +var updateLabelsInterval; function showMusicMessage(msg) { - var updateLabelsInterval; + active = "music"; + openMusic = msg.state=="play"; var trackScrollOffset = 0; var artistScrollOffset = 0; var albumScrollOffset = 0; @@ -194,10 +203,14 @@ function showMusicMessage(msg) { function back() { clearInterval(updateLabelsInterval); + updateLabelsInterval = undefined; + openMusic = false; + var wasNew = msg.new; msg.new = false; saveMessages(); layout = undefined; - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); + if (wasNew) checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:0,openMusic:0}); + else checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); } function updateLabels() { trackName = reduceStringAndPad(msg.track, trackScrollOffset, 13); @@ -243,6 +256,7 @@ function showMusicMessage(msg) { } function showMessageScroller(msg) { + active = "scroller"; var bodyFont = fontBig; g.setFont(bodyFont); var lines = []; @@ -272,6 +286,7 @@ function showMessageScroller(msg) { } function showMessageSettings(msg) { + active = "settings"; E.showMenu({"":{"title":/*LANG*/"Message"}, "< Back" : () => showMessage(msg.id), /*LANG*/"View Message" : () => { @@ -280,12 +295,12 @@ function showMessageSettings(msg) { /*LANG*/"Delete" : () => { MESSAGES = MESSAGES.filter(m=>m.id!=msg.id); saveMessages(); - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0}); + checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }, /*LANG*/"Mark Unread" : () => { msg.new = true; saveMessages(); - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0}); + checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }, /*LANG*/"Delete all messages" : () => { E.showPrompt(/*LANG*/"Are you sure?", {title:/*LANG*/"Delete All Messages"}).then(isYes => { @@ -293,7 +308,7 @@ function showMessageSettings(msg) { MESSAGES = []; saveMessages(); } - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0}); + checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }); }, }); @@ -301,15 +316,20 @@ function showMessageSettings(msg) { function showMessage(msgid) { var msg = MESSAGES.find(m=>m.id==msgid); - if (!msg) return checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0}); // go home if no message found - if (msg.src=="Maps") { - cancelReloadTimeout(); // don't auto-reload to clock now - return showMapMessage(msg); + if (updateLabelsInterval) { + clearInterval(updateLabelsInterval); + updateLabelsInterval=undefined; } + if (!msg) return checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0,openMusic:openMusic}); // go home if no message found if (msg.id=="music") { cancelReloadTimeout(); // don't auto-reload to clock now return showMusicMessage(msg); } + if (msg.src=="Maps") { + cancelReloadTimeout(); // don't auto-reload to clock now + return showMapMessage(msg); + } + active = "message"; // Normal text message display var title=msg.title, titleFont = fontLarge, lines; if (title) { @@ -342,7 +362,7 @@ function showMessage(msgid) { function goBack() { msg.new = false; saveMessages(); // read mail cancelReloadTimeout(); // don't auto-reload to clock now - checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0}); + checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0,openMusic:openMusic}); } var buttons = [ {type:"btn", src:getBackImage(), cb:goBack} // back @@ -353,7 +373,7 @@ function showMessage(msgid) { msg.new = false; saveMessages(); cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,true); - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); + checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:openMusic}); }}); } if (msg.negative) { @@ -362,7 +382,7 @@ function showMessage(msgid) { msg.new = false; saveMessages(); cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,false); - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1}); + checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:openMusic}); }}); } @@ -411,15 +431,19 @@ function checkMessages(options) { return load(); } // we have >0 messages - var newMessages = MESSAGES.filter(m=>m.new); + var newMessages = MESSAGES.filter(m=>m.new&&m.id!="music"); // If we have a new message, show it if (options.showMsgIfUnread && newMessages.length) return showMessage(newMessages[0].id); + // no new messages: show playing music? (only if we have playing music to show) + if (options.openMusic && MESSAGES.some(m=>m.id=="music" && m.track && m.state=="play")) + return showMessage('music'); // no new messages - go to clock? if (options.clockIfAllRead && newMessages.length==0) return load(); // we don't have to time out of this screen... cancelReloadTimeout(); + active = "main"; // Otherwise show a menu E.showScroller({ h : 48, @@ -482,5 +506,7 @@ setTimeout(() => { print("Message not seen - reloading"); load(); }, unreadTimeoutSecs*1000); - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:1}); + // only openMusic on launch if music is new + var newMusic = MESSAGES.some(m=>m.id==="music"&&m.new); + checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:1,openMusic:newMusic&&settings.openMusic}); },10); // if checkMessages wants to 'load', do that diff --git a/apps/messages/lib.js b/apps/messages/lib.js index 32dff78ba..0f514a73d 100644 --- a/apps/messages/lib.js +++ b/apps/messages/lib.js @@ -1,3 +1,10 @@ +function openMusic() { + // only read settings file for first music message + if ("undefined"==typeof exports._openMusic) { + exports._openMusic = !!((require('Storage').readJSON("messages.settings.json", true) || {}).openMusic); + } + return exports._openMusic; +} /* Push a new message onto messages queue, event is: {t:"add",id:int, src,title,subject,body,sender,tel, important:bool, new:bool} {t:"add",id:int, id:"music", state, artist, track, etc} // add new @@ -26,6 +33,9 @@ exports.pushMessage = function(event) { messages.unshift(event); // add new messages to the beginning } else Object.assign(messages[mIdx], event); + if (event.id=="music" && messages[mIdx].state=="play") { + messages[mIdx].new = true; // new track, or playback (re)started + } } require("Storage").writeJSON("messages.json",messages); // if in app, process immediately @@ -34,8 +44,12 @@ exports.pushMessage = function(event) { if (event.t=="remove" && !messages.some(m=>m.new)) { if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.hide(); } - // ok, saved now - we only care if it's new - if (event.t!="add") { + // ok, saved now + if (event.id=="music" && Bangle.CLOCK && messages[mIdx].new && openMusic()) { + // just load the app to display music: no buzzing + load("messages.app.js"); + } else if (event.t!="add") { + // we only care if it's new return; } else if(event.new == false) { return; diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 0387c1972..ff6a078a5 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.24", + "version": "0.25", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/settings.js b/apps/messages/settings.js index 622177440..99843602b 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -4,6 +4,7 @@ if (settings.vibrate===undefined) settings.vibrate="."; if (settings.repeat===undefined) settings.repeat=4; if (settings.unreadTimeout===undefined) settings.unreadTimeout=60; + settings.openMusic=!!settings.openMusic; settings.maxUnreadTimeout=240; return settings; } @@ -43,6 +44,11 @@ format: v => [/*LANG*/"Small",/*LANG*/"Medium"][v], onchange: v => updateSetting("fontSize", v) }, + /*LANG*/'Auto-Open Music': { + value: !!settings().openMusic, + format: v => v?/*LANG*/'Yes':/*LANG*/'No', + onchange: v => updateSetting("openMusic", v) + }, }; E.showMenu(mainmenu); }) diff --git a/apps/messages/widget.js b/apps/messages/widget.js index d9363573a..03a44a4ab 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -45,5 +45,5 @@ message but then the watch was never viewed. In that case we don't want to buzz but should still show that there are unread messages. */ if (global.MESSAGES===undefined) (function() { var messages = require("Storage").readJSON("messages.json",1)||[]; - if (messages.some(m=>m.new)) WIDGETS["messages"].show(true); + if (messages.some(m=>m.new&&m.id!="music")) WIDGETS["messages"].show(true); })(); From c235a22c1661bad84ff2d07d11bb5b84b1683424 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 7 Mar 2022 23:19:35 +0100 Subject: [PATCH 396/447] qmsched: unbreak app for new Bangle.j2 2 menu --- apps/qmsched/ChangeLog | 3 +- apps/qmsched/app.js | 59 ++++++++++++++++---------------------- apps/qmsched/metadata.json | 2 +- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/apps/qmsched/ChangeLog b/apps/qmsched/ChangeLog index c868b6668..94fcffe1a 100644 --- a/apps/qmsched/ChangeLog +++ b/apps/qmsched/ChangeLog @@ -5,4 +5,5 @@ 0.05: Avoid immediately redrawing widgets on load 0.06: Fix: don't try to redraw widget when widgets not loaded 0.07: Option to switch theme - Changed time selection to 5-minute intervals \ No newline at end of file + Changed time selection to 5-minute intervals +0.08: Support new Bangle.js 2 menu \ No newline at end of file diff --git a/apps/qmsched/app.js b/apps/qmsched/app.js index e05eff6a2..f80cfcf4d 100644 --- a/apps/qmsched/app.js +++ b/apps/qmsched/app.js @@ -2,7 +2,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); const modeNames = ["Off", "Alarms", "Silent"]; - +const B2 = process.env.HWVERSION===2; // load global settings let bSettings = require('Storage').readJSON('setting.json',true)||{}; let current = 0|bSettings.quiet; @@ -109,26 +109,19 @@ function setAppQuietMode(mode) { let m; function showMainMenu() { - let menu = { - "": {"title": "Quiet Mode"}, - "< Exit": () => load() - }; + let menu = {"": {"title": "Quiet Mode"},}; + menu[B2 ? "< Back" : "< Exit"] = () => {load();}; // "Current Mode""Silent" won't fit on Bangle.js 2 menu["Current"+((process.env.HWVERSION===2) ? "" : " Mode")] = { value: current, min:0, max:2, wrap: true, - format: () => modeNames[current], + format: v => modeNames[v], onchange: require("qmsched").setMode, // library calls setAppMode(), which updates `current` }; scheds.sort((a, b) => (a.hr-b.hr)); scheds.forEach((sched, idx) => { - menu[formatTime(sched.hr)] = { - format: () => modeNames[sched.mode], // abuse format to right-align text - onchange: () => { - m.draw = ()=> {}; // prevent redraw of main menu over edit menu (needed because we abuse format/onchange) - showEditMenu(idx); - } - }; + menu[formatTime(sched.hr)] = () => { showEditMenu(idx); }; + menu[formatTime(sched.hr)].format = () => modeNames[sched.mode]+' >'; // this does nothing :-( }); menu["Add Schedule"] = () => showEditMenu(-1); menu["Switch Theme"] = { @@ -150,25 +143,23 @@ function showEditMenu(index) { mins = Math.round((s.hr-hrs)*60); mode = s.mode; } - const menu = { - "": {"title": (isNew ? "Add" : "Edit")+" Schedule"}, - "< Cancel": () => showMainMenu(), - "Hours": { - value: hrs, - min:0, max:23, wrap:true, - onchange: v => {hrs = v;}, - }, - "Minutes": { - value: mins, - min:0, max:55, step:5, wrap:true, - onchange: v => {mins = v;}, - }, - "Switch to": { - value: mode, - min:0, max:2, wrap:true, - format: v => modeNames[v], - onchange: v => {mode = v;}, - }, + let menu = {"": {"title": (isNew ? "Add" : "Edit")+" Schedule"}}; + menu[B2 ? "< Back" : "< Cancel"] = () => showMainMenu(); + menu["Hours"] = { + value: hrs, + min:0, max:23, wrap:true, + onchange: v => {hrs = v;}, + }; + menu["Minutes"] = { + value: mins, + min:0, max:55, step:5, wrap:true, + onchange: v => {mins = v;}, + }; + menu["Switch to"] = { + value: mode, + min:0, max:2, wrap:true, + format: v => modeNames[v], + onchange: v => {mode = v;}, }; function getSched() { return { @@ -176,7 +167,7 @@ function showEditMenu(index) { mode: mode, }; } - menu["> Save"] = function() { + menu[B2 ? "Save" : "> Save"] = function() { if (isNew) { scheds.push(getSched()); } else { @@ -186,7 +177,7 @@ function showEditMenu(index) { showMainMenu(); }; if (!isNew) { - menu["> Delete"] = function() { + menu[B2 ? "Delete" : "> Delete"] = function() { scheds.splice(index, 1); save(); showMainMenu(); diff --git a/apps/qmsched/metadata.json b/apps/qmsched/metadata.json index daeaad624..326a8fc4f 100644 --- a/apps/qmsched/metadata.json +++ b/apps/qmsched/metadata.json @@ -2,7 +2,7 @@ "id": "qmsched", "name": "Quiet Mode Schedule and Widget", "shortName": "Quiet Mode", - "version": "0.07", + "version": "0.08", "description": "Automatically turn Quiet Mode on or off at set times, change theme and LCD options while Quiet Mode is active.", "icon": "app.png", "screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"}, From 9c7e5fa06861c1226f81571a0995c723151835ca Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 7 Mar 2022 23:22:23 +0100 Subject: [PATCH 397/447] qmsched: add /*LANG*/ translation hints --- apps/qmsched/app.js | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/qmsched/app.js b/apps/qmsched/app.js index f80cfcf4d..8cd0fa8d9 100644 --- a/apps/qmsched/app.js +++ b/apps/qmsched/app.js @@ -1,7 +1,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); -const modeNames = ["Off", "Alarms", "Silent"]; +const modeNames = [/*LANG*/"Off", /*LANG*/"Alarms", /*LANG*/"Silent"]; const B2 = process.env.HWVERSION===2; // load global settings let bSettings = require('Storage').readJSON('setting.json',true)||{}; @@ -109,10 +109,9 @@ function setAppQuietMode(mode) { let m; function showMainMenu() { - let menu = {"": {"title": "Quiet Mode"},}; - menu[B2 ? "< Back" : "< Exit"] = () => {load();}; - // "Current Mode""Silent" won't fit on Bangle.js 2 - menu["Current"+((process.env.HWVERSION===2) ? "" : " Mode")] = { + let menu = {"": {"title": /*LANG*/"Quiet Mode"},}; + menu[B2 ? /*LANG*/"< Back" : /*LANG*/"< Exit"] = () => {load();}; + menu[/*LANG*/"Current Mode"] = { value: current, min:0, max:2, wrap: true, format: v => modeNames[v], @@ -123,13 +122,13 @@ function showMainMenu() { menu[formatTime(sched.hr)] = () => { showEditMenu(idx); }; menu[formatTime(sched.hr)].format = () => modeNames[sched.mode]+' >'; // this does nothing :-( }); - menu["Add Schedule"] = () => showEditMenu(-1); - menu["Switch Theme"] = { + menu[/*LANG*/"Add Schedule"] = () => showEditMenu(-1); + menu[/*LANG*/"Switch Theme"] = { value: !!get("switchTheme"), format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: v => v ? set("switchTheme", v) : unset("switchTheme"), }; - menu["LCD Settings"] = () => showOptionsMenu(); + menu[/*LANG*/"LCD Settings"] = () => showOptionsMenu(); m = E.showMenu(menu); } @@ -143,19 +142,19 @@ function showEditMenu(index) { mins = Math.round((s.hr-hrs)*60); mode = s.mode; } - let menu = {"": {"title": (isNew ? "Add" : "Edit")+" Schedule"}}; - menu[B2 ? "< Back" : "< Cancel"] = () => showMainMenu(); - menu["Hours"] = { + let menu = {"": {"title": (isNew ? /*LANG*/"Add Schedule" : /*LANG*/"Edit Schedule")}}; + menu[B2 ? /*LANG*/"< Back" : /*LANG*/"< Cancel"] = () => showMainMenu(); + menu[/*LANG*/"Hours"] = { value: hrs, min:0, max:23, wrap:true, onchange: v => {hrs = v;}, }; - menu["Minutes"] = { + menu[/*LANG*/"Minutes"] = { value: mins, min:0, max:55, step:5, wrap:true, onchange: v => {mins = v;}, }; - menu["Switch to"] = { + menu[/*LANG*/"Switch to"] = { value: mode, min:0, max:2, wrap:true, format: v => modeNames[v], @@ -167,7 +166,7 @@ function showEditMenu(index) { mode: mode, }; } - menu[B2 ? "Save" : "> Save"] = function() { + menu[B2 ? /*LANG*/"Save" : /*LANG*/"> Save"] = function() { if (isNew) { scheds.push(getSched()); } else { @@ -177,7 +176,7 @@ function showEditMenu(index) { showMainMenu(); }; if (!isNew) { - menu[B2 ? "Delete" : "> Delete"] = function() { + menu[B2 ? /*LANG*/"Delete" : /*LANG*/"> Delete"] = function() { scheds.splice(index, 1); save(); showMainMenu(); @@ -187,7 +186,7 @@ function showEditMenu(index) { } function showOptionsMenu() { - const disabledFormat = v => v ? "Off" : "-"; + const disabledFormat = v => v ? /*LANG*/"Off" : "-"; function toggle(option) { // we disable wakeOn* events by setting them to `false` in options // not disabled = not present in options at all @@ -200,9 +199,9 @@ function showOptionsMenu() { } let resetTimeout; const oMenu = { - "": {"title": "LCD Settings"}, - "< Back": () => showMainMenu(), - "LCD Brightness": { + "": {"title": /*LANG*/"LCD Settings"}, + /*LANG*/"< Back": () => showMainMenu(), + /*LANG*/"LCD Brightness": { value: get("brightness", 0), min: 0, // 0 = use default max: 1, @@ -224,7 +223,7 @@ function showOptionsMenu() { } }, }, - "LCD Timeout": { + /*LANG*/"LCD Timeout": { value: get("timeout", 0), min: 0, // 0 = use default (no constant on for quiet mode) max: 60, @@ -237,17 +236,17 @@ function showOptionsMenu() { }, // we disable wakeOn* events by overwriting them as false in options // not disabled = not present in options at all - "Wake on FaceUp": { + /*LANG*/"Wake on FaceUp": { value: "wakeOnFaceUp" in options, format: disabledFormat, onchange: () => {toggle("wakeOnFaceUp");}, }, - "Wake on Touch": { + /*LANG*/"Wake on Touch": { value: "wakeOnTouch" in options, format: disabledFormat, onchange: () => {toggle("wakeOnTouch");}, }, - "Wake on Twist": { + /*LANG*/"Wake on Twist": { value: "wakeOnTwist" in options, format: disabledFormat, onchange: () => {toggle("wakeOnTwist");}, From 1e7b9f1b65dceed11c8f3ae46b79a864d4f56324 Mon Sep 17 00:00:00 2001 From: Marco H Date: Tue, 8 Mar 2022 09:54:16 +0100 Subject: [PATCH 398/447] Allow configuration of drop and raise alarm independently --- apps/widbaroalarm/README.md | 4 +++- apps/widbaroalarm/default.json | 3 ++- apps/widbaroalarm/settings.js | 16 +++++++++++++--- apps/widbaroalarm/widget.js | 26 ++++++++++++++++++++------ 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/apps/widbaroalarm/README.md b/apps/widbaroalarm/README.md index 6708b1e2b..b92a51050 100644 --- a/apps/widbaroalarm/README.md +++ b/apps/widbaroalarm/README.md @@ -11,7 +11,9 @@ Get a notification when the pressure reaches defined thresholds. * Low threshold: Warn when pressure drops below this value * High alarm: Toggle high alarm * High threshold: Warn when pressure exceeds above this value -* Change alarm: Warn when pressure changes more than this value in the recent 3 hours (having at least 30 min of data) +* Drop alarm: Warn when pressure drops more than this value in the recent 3 hours (having at least 30 min of data) + 0 to disable this alarm. +* Raise alarm: Warn when pressure raises more than this value in the recent 3 hours (having at least 30 min of data) 0 to disable this alarm. * Show widget: Enable/disable widget visibility * Buzz on alarm: Enable/disable buzzer on alarm diff --git a/apps/widbaroalarm/default.json b/apps/widbaroalarm/default.json index 7dbe6fc17..3d81baa81 100644 --- a/apps/widbaroalarm/default.json +++ b/apps/widbaroalarm/default.json @@ -4,7 +4,8 @@ "min": 950, "highalarm": false, "max": 1030, - "changeIn3h": 2, + "drop3halarm": 2, + "raise3halarm": 0, "show": true, "interval": 15 } diff --git a/apps/widbaroalarm/settings.js b/apps/widbaroalarm/settings.js index d3d2df0ae..1455072e4 100644 --- a/apps/widbaroalarm/settings.js +++ b/apps/widbaroalarm/settings.js @@ -53,15 +53,25 @@ step: 10, onchange: x => save("max", x), }, - "Change alarm": { - value: settings.changeIn3h, + "Drop alarm": { + value: settings.drop3halarm, min: 0, max: 10, step: 1, format: x => { return x != 0 ? x + ' hPa/3h' : 'off'; }, - onchange: x => save("changeIn3h", x) + onchange: x => save("drop3halarm", x) + }, + "Raise alarm": { + value: settings.raise3halarm, + min: 0, + max: 10, + step: 1, + format: x => { + return x != 0 ? x + ' hPa/3h' : 'off'; + }, + onchange: x => save("raise3halarm", x) }, "Show widget": { value: settings.show, diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 443b6c68c..9b65ffe5b 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -80,8 +80,9 @@ if (!alreadyWarned) { // 3h change detection - const threeHourChange = setting("changeIn3h"); - if (threeHourChange > 0) { + const drop3halarm = setting("drop3halarm"); + const raise3halarm = setting("raise3halarm"); + if (drop3halarm > 0 || raise3halarm > 0) { // we need at least 30min of data for reliable detection if (history3[0]["ts"] > ts - (30 * 60)) { return; @@ -91,10 +92,23 @@ const oldestAvgPressure = (history3[0]["p"] + history3[1]["p"] + history3[2]["p"]) / 3; if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { const diff = oldestAvgPressure - avrPressure; - if (Math.abs(diff) > threeHourChange) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", - "Pressure " + (diff > 0 ? "drop" : "raise")); + + // drop alarm + if (drop3halarm > 0 && oldestAvgPressure > avrPressure) { + if (Math.abs(diff) > drop3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", + "Pressure drop")); + } + } + + // raise alarm + if (raise3halarm > 0 && oldestAvgPressure < avrPressure) { + if (Math.abs(diff) > raise3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", + "Pressure raise")); + } } } } From cf365dc451822a15997e13bab147d97077c701fa Mon Sep 17 00:00:00 2001 From: Marco H Date: Tue, 8 Mar 2022 11:27:13 +0100 Subject: [PATCH 399/447] Use median calculation instead of average to get valid measurements --- apps/widbaroalarm/widget.js | 256 ++++++++++++++++++++---------------- 1 file changed, 139 insertions(+), 117 deletions(-) diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 9b65ffe5b..7279a963a 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -1,51 +1,47 @@ (function() { - let lastPressure; - let avrPressure; - let threeHourAvrPressure; + let medianPressure; + let threeHourAvrPressure; + let currentPressures = []; - const LOG_FILE = "widbaroalarm.log.json"; - const SETTINGS_FILE = "widbaroalarm.json"; - const storage = require('Storage'); - let settings = Object.assign( - storage.readJSON("widbaroalarm.default.json", true) || {}, - storage.readJSON(SETTINGS_FILE, true) || {} - ); + const LOG_FILE = "widbaroalarm.log.json"; + const SETTINGS_FILE = "widbaroalarm.json"; + const storage = require('Storage'); + let settings = Object.assign( + storage.readJSON("widbaroalarm.default.json", true) || {}, + storage.readJSON(SETTINGS_FILE, true) || {} + ); - function setting(key) { - return settings[key]; - } - const interval = setting("interval"); - - let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours - - function showAlarm(body, title) { - if (body == undefined) return; - - require("notify").show({ - title: title || "Pressure", - body: body, - icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) - }); - - if (setting("buzz") && - !(storage.readJSON('setting.json', 1) || {}).quiet) { - Bangle.buzz(); + function setting(key) { + return settings[key]; } - } + const interval = setting("interval"); - let alreadyWarned = false; + let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours - function baroHandler(data) { - if (data === undefined) { - setTimeout(() => Bangle.getPressure().then(baroHandler), 500); - } else { - lastPressure = Math.round(data.pressure); - if (lastPressure == undefined || lastPressure <= 0) return; + function showAlarm(body, title) { + if (body == undefined) return; + + require("notify").show({ + title: title || "Pressure", + body: body, + icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) + }); + + if (setting("buzz") && + !(storage.readJSON('setting.json', 1) || {}).quiet) { + Bangle.buzz(); + } + } + + let alreadyWarned = false; + + function checkForAlarms(pressure) { + if (pressure == undefined || pressure <= 0) return; const ts = Math.round(Date.now() / 1000); // seconds const d = { "ts": ts, - "p": lastPressure + "p": pressure }; // delete entries older than 3h @@ -63,101 +59,127 @@ // write data to storage storage.writeJSON(LOG_FILE, history3); - // we need at least three entries for reliable detection - if (history3.length >= 3) { + if (setting("lowalarm") && pressure <= setting("min")) { + showAlarm("Pressure low: " + Math.round(pressure) + " hPa"); + alreadyWarned = true; + } + if (setting("highalarm") && pressure >= setting("max")) { + showAlarm("Pressure high: " + Math.round(pressure) + " hPa"); + alreadyWarned = true; + } - // calculate average of recent three entries - avrPressure = (history3[history3.length - 1]["p"] + history3[history3.length - 2]["p"] + history3[history3.length - 3]["p"]) / 3; + if (!alreadyWarned) { + // 3h change detection + const drop3halarm = setting("drop3halarm"); + const raise3halarm = setting("raise3halarm"); + if (drop3halarm > 0 || raise3halarm > 0) { + // we need at least 30min of data for reliable detection + if (history3[0]["ts"] > ts - (30 * 60)) { + return; + } - if (setting("lowalarm") && avrPressure <= setting("min")) { - showAlarm("Pressure low: " + Math.round(avrPressure) + " hPa"); - alreadyWarned = true; - } - if (setting("highalarm") && avrPressure >= setting("max")) { - showAlarm("Pressure high: " + Math.round(avrPressure) + " hPa"); - alreadyWarned = true; - } + // Get oldest entry: + const oldestPressure = history3[0]["p"]; + if (oldestPressure != undefined && oldestPressure > 0) { + const diff = oldestPressure - pressure; - if (!alreadyWarned) { - // 3h change detection - const drop3halarm = setting("drop3halarm"); - const raise3halarm = setting("raise3halarm"); - if (drop3halarm > 0 || raise3halarm > 0) { - // we need at least 30min of data for reliable detection - if (history3[0]["ts"] > ts - (30 * 60)) { - return; + // drop alarm + if (drop3halarm > 0 && oldestPressure > pressure) { + if (Math.abs(diff) > drop3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); } + } - // Average of oldest three entries - const oldestAvgPressure = (history3[0]["p"] + history3[1]["p"] + history3[2]["p"]) / 3; - if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { - const diff = oldestAvgPressure - avrPressure; - - // drop alarm - if (drop3halarm > 0 && oldestAvgPressure > avrPressure) { - if (Math.abs(diff) > drop3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", - "Pressure drop")); - } - } - - // raise alarm - if (raise3halarm > 0 && oldestAvgPressure < avrPressure) { - if (Math.abs(diff) > raise3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", - "Pressure raise")); - } - } - } + // raise alarm + if (raise3halarm > 0 && oldestPressure < pressure) { + if (Math.abs(diff) > raise3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure raise"); } } } - - // calculate 3h average for widget - let sum = 0; - for (let i = 0; i < history3.length; i++) { - sum += history3[i]["p"]; - } - threeHourAvrPressure = sum / history3.length; } } - function check() { - Bangle.getPressure().then(baroHandler); + // calculate 3h average for widget + let sum = 0; + for (let i = 0; i < history3.length; i++) { + sum += history3[i]["p"]; } + threeHourAvrPressure = sum / history3.length; +} - function reload() { - check(); + + +function baroHandler(data) { + if (data) { + const pressure = Math.round(data.pressure); + if (pressure == undefined || pressure <= 0) return; + currentPressures.push(pressure); } +} - function draw() { - g.reset(); - if (setting("show") && lastPressure != undefined) { - g.setFont("6x8", 1).setFontAlign(1, 0); - g.drawString(Math.round(lastPressure), this.x + 24, this.y + 6); - if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { - g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); - } - } - } - - if (global.WIDGETS != undefined && typeof WIDGETS === "object") { - WIDGETS["baroalarm"] = { - width: setting("show") ? 24 : 0, - reload: reload, - area: "tr", - draw: draw - }; - } - - // Let's delay the first check a bit +/* + turn on barometer power + take 5 measurements + sort the results + take the middle one (median) + turn off barometer power +*/ +function check() { + Bangle.setBarometerPower(true, "widbaroalarm"); setTimeout(function() { - check(); - if (interval > 0) { - setInterval(check, interval * 60000); + currentPressures = []; + + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + + setTimeout(function() { + Bangle.setBarometerPower(false, "widbaroalarm"); + + currentPressures.sort(); + + // take median value + medianPressure = currentPressures[3]; + checkForAlarms(medianPressure); + }, 1000); + }, 500); +} + +function reload() { + check(); +} + +function draw() { + g.reset(); + if (setting("show") && medianPressure != undefined) { + g.setFont("6x8", 1).setFontAlign(1, 0); + g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6); + if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { + g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); } - }, 10000); + } +} + +if (global.WIDGETS != undefined && typeof WIDGETS === "object") { + WIDGETS["baroalarm"] = { + width: setting("show") ? 24 : 0, + reload: reload, + area: "tr", + draw: draw + }; +} + +// Let's delay the first check a bit +setTimeout(function() { +check(); +if (interval > 0) { + setInterval(check, interval * 60000); +} +}, 5000); })(); From 401f197d1e7ecd14f0848ebfc4f1a4a84c86eca7 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Mar 2022 11:43:04 +0000 Subject: [PATCH 400/447] fix #1548 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9cf30065a..38ce09f75 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ and which gives information about the app for the Launcher. "screenshots" : [ { url:"screenshot.png" } ], // optional screenshot for app "type":"...", // optional(if app) - // 'app' - an application + // 'clock' - a clock - required for clocks to automatically start // 'widget' - a widget // 'launch' - replacement launcher app // 'bootloader' - code that runs at startup only From eca40798282f5ebde99238c4581bc458835c793f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Mar 2022 13:00:31 +0000 Subject: [PATCH 401/447] Fix issue with code uploader where it'd silently refuse to upload code with warnings in --- apps/custom/custom.html | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/apps/custom/custom.html b/apps/custom/custom.html index 684f813ae..307f2fd2f 100644 --- a/apps/custom/custom.html +++ b/apps/custom/custom.html @@ -16,12 +16,12 @@

Type your javascript code here

-

Then click

+

Then click  

From 30ade21eac2e17476d05fe2c94ce49be6ea528ef Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Tue, 8 Mar 2022 20:16:00 +0100 Subject: [PATCH 402/447] New power management app for setting a charging alarm and voltage offset --- apps/powermanager/ChangeLog | 1 + apps/powermanager/README.md | 15 ++++ apps/powermanager/app.png | Bin 0 -> 1202 bytes apps/powermanager/boot.js | 29 ++++++++ apps/powermanager/default.json | 4 + apps/powermanager/metadata.json | 17 +++++ apps/powermanager/settings.js | 125 ++++++++++++++++++++++++++++++++ 7 files changed, 191 insertions(+) create mode 100644 apps/powermanager/ChangeLog create mode 100644 apps/powermanager/README.md create mode 100644 apps/powermanager/app.png create mode 100644 apps/powermanager/boot.js create mode 100644 apps/powermanager/default.json create mode 100644 apps/powermanager/metadata.json create mode 100644 apps/powermanager/settings.js diff --git a/apps/powermanager/ChangeLog b/apps/powermanager/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/powermanager/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/powermanager/README.md b/apps/powermanager/README.md new file mode 100644 index 000000000..f2cfcdf3e --- /dev/null +++ b/apps/powermanager/README.md @@ -0,0 +1,15 @@ +# Power manager + +Manages settings for charging. You can set a warning threshold to be able to disconnect the charger at a given percentage. Also allows to set the battery calibration offset. + +## Internals + +Battery calibration offset is set by writing `batFullVoltage` in setting.json + +## TODO + +* Optionally keep battery history and show as graph + +## Creator + +[halemmerich](https://github.com/halemmerich) diff --git a/apps/powermanager/app.png b/apps/powermanager/app.png new file mode 100644 index 0000000000000000000000000000000000000000..dc51aa01b227a901238a89efea92b9fea499c80a GIT binary patch literal 1202 zcmV;j1Wo&iP)r6rLSW%NLZf}TW{iIbICYNK}hu=e5Hx!##M_nv!a z><=66J$tXU|7)MU*IIiW+Jk9Wg2T@6_C$;SV{b|fzi#r9;-!T^> zQ@av>q`t*N#%=&i#ZGL)DRuf!#r8C2>LBtegkktZtnj>k#?4D(K20)v4Q>#`KF5fD z#tp~1H1_&I;8h3*p<9qTtHAg(@GmxFY#VtM#?ylQvIb<9C7Gw%!l(h9C=TUT9NvK3 zA=rXlIJphH3gaEIk_(%VU6^FwH$<^vP9pFXI-8L1OtKYRQPVdQ&tZHSg8g9>eoB*H zSVGVAq~mAohsh%C$RhWgay0wKII-_vY=N%jg6v0nryUg$&D)02$_Jwk+#x5t4fo&~ zgJ3{eoQ4nO!K5j@RxY4x3@@dhgkW{o9z(yg)th~LIdG^xv$Pzk$iqE-o#rq?Y25&_r(Lk zfQm3^t&#>DftRXCufeko7_eAxqbv9allqaFgcVA<(c10uOH$H-`2`K=#D+QsJX(;$ z41Aqr&TEAHSbUiTcj5^gP}N`5fUE3Dep8LEfzXMQiVUpwLI+|(`rR!OwJi-ynqhvO zXGNMP6}Psm z?cX-mRXAN-`?d=2Q4yDq{tTF$WNHnlZo9S1A2)fl3hFfr~sIp}w7WE;w1mD%P zT7zzCg8crX&a|SaKvrQ`C#nb;W+f$syo0C>Rg=H3D1jP`!1qbV?12V1T4Cr9Ps+(J zRqon2GwE3`B6pu?rovDUox=B5#9M2H7kVw}d#JAg%~lxd;S%{RYfMR98IHo=g5w_B zxI?)LLoJqzbf6WfcQx*o=VraOBxRN` zs%CJJ{6KfXb?L#X7ERFVZBq|fT)LLHcvM6lGgz1+Tz0cKS8!fQe8bwIx$0V@m>{nM zJzqjkmq>BC2?Mrk?+1r{aF?k2WWnu?68eUTMel}plfsM3aqJT_@U8r#-z&-+kVWP- zM1D~b9~>^zy4-yNUX`!-+c-h&|7HyskvRUAbj;3z!6R6Zes306%Wmv0sCcueIBZM* zZxp4GQR05Q057DzDI(k5i1!NWA1>m{@i;g=dst1-oi0irwFTB9ZMXd9M(>j0JiX7? zlmhztYCXbhUXUrPmm!W8Rk-nrd!`NItz|eAkIAFuTHK7!FWH?L&uU5o?A;sCkrCu}CMD_~&2coHWFPlaz QHUIzs07*qoM6N<$g5tA6ga7~l literal 0 HcmV?d00001 diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js new file mode 100644 index 000000000..ff4ba8932 --- /dev/null +++ b/apps/powermanager/boot.js @@ -0,0 +1,29 @@ +(function() { + var settings = Object.assign( + require('Storage').readJSON("powermanager.default.json", true) || {}, + require('Storage').readJSON("powermanager.json", true) || {} + ); + + if (settings.warnEnabled){ + print("Charge warning enabled"); + var chargingInterval; + + function handleCharging(charging){ + if (charging){ + if (chargingInterval) clearInterval(chargingInterval); + chargingInterval = setInterval(()=>{ + if (E.getBattery() > settings.warn){ + Bangle.buzz(1000); + } + }, 10000); + } + if (chargingInterval && !charging){ + clearInterval(chargingInterval); + chargingInterval = undefined; + } + } + + Bangle.on("charging",handleCharging); + handleCharging(Bangle.isCharging()); + } +})(); diff --git a/apps/powermanager/default.json b/apps/powermanager/default.json new file mode 100644 index 000000000..a6d8412b2 --- /dev/null +++ b/apps/powermanager/default.json @@ -0,0 +1,4 @@ +{ + "warnEnabled": false, + "warn": 96 +} diff --git a/apps/powermanager/metadata.json b/apps/powermanager/metadata.json new file mode 100644 index 000000000..3ad31ba1e --- /dev/null +++ b/apps/powermanager/metadata.json @@ -0,0 +1,17 @@ +{ + "id": "powermanager", + "name": "Power Manager", + "shortName": "Power Manager", + "version": "0.01", + "description": "Allow configuration of warnings and thresholds for battery charging and display.", + "icon": "app.png", + "type": "bootloader", + "tags": "tool", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"powermanager.boot.js","url":"boot.js"}, + {"name":"powermanager.settings.js","url":"settings.js"}, + {"name":"powermanager.default.json","url":"default.json"} + ] +} diff --git a/apps/powermanager/settings.js b/apps/powermanager/settings.js new file mode 100644 index 000000000..c8aa057fa --- /dev/null +++ b/apps/powermanager/settings.js @@ -0,0 +1,125 @@ +(function(back) { + var systemsettings = require("Storage").readJSON("setting.json") || {}; + + function writeSettings(key, value) { + var s = require('Storage').readJSON(FILE, true) || {}; + s[key] = value; + require('Storage').writeJSON(FILE, s); + readSettings(); + } + + function readSettings() { + settings = Object.assign( + require('Storage').readJSON("powermanager.default.json", true) || {}, + require('Storage').readJSON(FILE, true) || {} + ); + } + + var FILE = "powermanager.json"; + var settings; + readSettings(); + + var mainmenu = { + '': { + 'title': 'Power Manager' + }, + '< Back': back, + 'Charge warning': function() { + E.showMenu(submenu_chargewarn); + }, + 'Calibrate': function() { + E.showMenu(submenu_calibrate); + } + }; + + + function roundToDigits(number, stepsize) { + return Math.round(number / stepsize) * stepsize; + } + + function getCurrentVoltageDirect() { + return (analogRead(D3) + analogRead(D3) + analogRead(D3) + analogRead(D3)) / 4; + } + + var stepsize = 0.0002; + var full = 0.32; + + function getInitialCalibrationOffset() { + return roundToDigits(systemsettings.batFullVoltage - full, stepsize) || 0; + } + + + var submenu_calibrate = { + '': { + title: "Calibrate" + }, + '< Back': function() { + E.showMenu(mainmenu); + }, + 'Offset': { + min: -0.05, + max: 0.05, + step: stepsize, + value: getInitialCalibrationOffset(), + format: v => roundToDigits(v, stepsize).toFixed((""+stepsize).length - 2), + onchange: v => { + print(typeof v); + systemsettings.batFullVoltage = v + full; + require("Storage").writeJSON("setting.json", systemsettings); + } + }, + 'Auto': function() { + var newVoltage = getCurrentVoltageDirect(); + E.showAlert("Please charge fully before auto setting").then(() => { + E.showPrompt("Set current charge as full").then((r) => { + if (r) { + systemsettings.batFullVoltage = newVoltage; + require("Storage").writeJSON("setting.json", systemsettings); + //reset value shown in menu to the newly set one + submenu_calibrate.Offset.value = getInitialCalibrationOffset(); + E.showMenu(mainmenu); + } + }); + }); + }, + 'Clear': function() { + E.showPrompt("Clear charging offset?").then((r) => { + if (r) { + delete systemsettings.batFullVoltage; + require("Storage").writeJSON("setting.json", systemsettings); + //reset value shown in menu to the newly set one + submenu_calibrate.Offset.value = getInitialCalibrationOffset(); + E.showMenu(mainmenu); + } + }); + } + }; + + var submenu_chargewarn = { + '': { + title: "Charge warning" + }, + '< Back': function() { + E.showMenu(mainmenu); + }, + 'Enabled': { + value: !!settings.warnEnabled, + format: v => settings.warnEnabled ? "On" : "Off", + onchange: v => { + writeSettings("warnEnabled", v); + } + }, + 'Percentage': { + min: 80, + max: 100, + step: 2, + value: settings.warn, + format: v => v + "%", + onchange: v => { + writeSettings("warn", v); + } + } + }; + + E.showMenu(mainmenu); +}) From d92fa8fb1a3af44a59ad6e57d03f61332c4916ef Mon Sep 17 00:00:00 2001 From: Nicholas Onorato Date: Tue, 8 Mar 2022 20:45:19 -0700 Subject: [PATCH 403/447] Added my countdown widget --- apps/widmnth/ChangeLog | 1 + apps/widmnth/README.md | 22 +++++++++++++++++++ apps/widmnth/metadata.json | 14 +++++++++++++ apps/widmnth/widget.js | 42 +++++++++++++++++++++++++++++++++++++ apps/widmnth/widget.png | Bin 0 -> 470 bytes 5 files changed, 79 insertions(+) create mode 100644 apps/widmnth/ChangeLog create mode 100644 apps/widmnth/README.md create mode 100644 apps/widmnth/metadata.json create mode 100644 apps/widmnth/widget.js create mode 100644 apps/widmnth/widget.png diff --git a/apps/widmnth/ChangeLog b/apps/widmnth/ChangeLog new file mode 100644 index 000000000..370f41e8a --- /dev/null +++ b/apps/widmnth/ChangeLog @@ -0,0 +1 @@ +0.01: Simple new widget! diff --git a/apps/widmnth/README.md b/apps/widmnth/README.md new file mode 100644 index 000000000..ef912c739 --- /dev/null +++ b/apps/widmnth/README.md @@ -0,0 +1,22 @@ +# Widget Name + +The days left in month widget is simple and just prints the number of days left in the month in the top left corner. +The idea is to encourage people to keep track of time and keep goals they may have for the month. + +## Usage + +Hopefully you just have to Install it and it'll work. Customizing the location would just be changing tl to tr. + +## Features + +* Shows days left in month +* Only updates at midnight. + + +## Requests + +Complaints,compliments,problems,suggestions,annoyances,bugs, and all other feedback can be filed at [this repo](https://github.com/N-Onorato/BangleApps) + +## Creator + +Nick diff --git a/apps/widmnth/metadata.json b/apps/widmnth/metadata.json new file mode 100644 index 000000000..25f3a8126 --- /dev/null +++ b/apps/widmnth/metadata.json @@ -0,0 +1,14 @@ +{ "id": "widmnth", + "name": "Days left in month widget", + "shortName":"Month Countdown", + "version":"0.01", + "description": "A simple widget that displays the number of days left in the month.", + "icon": "widget.png", + "type": "widget", + "tags": "widget,date,time,countdown,month", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widmnth.wid.js","url":"widget.js"} + ] +} diff --git a/apps/widmnth/widget.js b/apps/widmnth/widget.js new file mode 100644 index 000000000..c4eca155a --- /dev/null +++ b/apps/widmnth/widget.js @@ -0,0 +1,42 @@ + +(() => { + var days_left; + var clearCode; + + function getDaysLeft(day) { + let year = day.getMonth() == 11 ? day.getFullYear() + 1 : day.getFullYear(); // rollover if december. + next_month = new Date(year, (day.getMonth() + 1) % 12, 1, 0, 0, 0); + let days_left = Math.floor((next_month - day) / 86400000); // ms left in month divided by ms in a day + return days_left; + } + + function getTimeTilMidnight(now) { + let midnight = new Date(now.getTime()); + midnight.setHours(23); + midnight.setMinutes(59); + midnight.setSeconds(59); + midnight.setMilliseconds(999); + return (midnight - now) + 1; + } + + function update() { + let now = new Date(); + days_left = getDaysLeft(now); + let ms_til_midnight = getTimeTilMidnight(now); + clearCode = setTimeout(update, ms_til_midnight); + } + + function draw() { + g.reset(); + g.setFont("4x6", 3); + if(!clearCode) update(); // On first run calculate days left and setup interval to update state. + g.drawString(days_left < 10 ? "0" + days_left : days_left.toString(), this.x + 2, this.y + 4); + } + + // add your widget + WIDGETS.widmonthcountdown={ + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: 24, + draw:draw + }; +})(); \ No newline at end of file diff --git a/apps/widmnth/widget.png b/apps/widmnth/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..4a042ec05559285fa9ea28f8050432e3110adb5f GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvg8-ip*Uk#h-Aht{yyNS#ERE!1 z1C1m^c@L~eJGwU0KuhY#>Wp9y9ZeOn#r@$N>?|i;)!H{|fm92W1o;L3M+FQIlw&1< za-0Pok;M!Q+#5icQOZJ~h=GC8z|+MsL}OxdK#*Ib7taw6iNy?TA?pNpaUEh3Fcy0= z=WJfi25Am69j28AB|$+!f@YyiOraYZwoXc$6x3oG!H{!Ib?NIxUR~SD-`^{}#5()n zlGv?bp5;eBePUXgFoA1r>z-r0UR_6z9s3@laBZE@wh4i=?rqJQI=QJ(IKW}?;++@$ zUxvAFKDfB2FKvRP?Ah`uLTkcGO0-y`9YRc0R&qp_tl6=oL{ewL9ns~-_bpnySlMrR z1#3j>iN(xKPoIh%YY*uO*I}ELD9Tc__)wRdYG}9KhOGjP>*7>HleITUD(X2rxSja= zQNo=@4*u1m-PW@j&o#7bUYN$m{kTtU2G{D))w>*$3Up=9ipd_66)Rv|Evjv$qvJ4Z yL0U;kgK0^_*#IM^L#|%F4ni#pnK(KW85k1fyG8kLhC~1Zl)=;0&t;ucLK6TlqO}$P literal 0 HcmV?d00001 From 028aee5d1158a0eb7cbe9c7bc89cd419607124c5 Mon Sep 17 00:00:00 2001 From: Marco H Date: Wed, 9 Mar 2022 09:32:43 +0100 Subject: [PATCH 404/447] Try not to warn multiple times for the same exceedance --- apps/widbaroalarm/ChangeLog | 1 + apps/widbaroalarm/README.md | 2 - apps/widbaroalarm/metadata.json | 2 +- apps/widbaroalarm/settings.js | 6 +- apps/widbaroalarm/widget.js | 334 ++++++++++++++++++-------------- 5 files changed, 197 insertions(+), 148 deletions(-) diff --git a/apps/widbaroalarm/ChangeLog b/apps/widbaroalarm/ChangeLog index ec66c5568..c12cc0d65 100644 --- a/apps/widbaroalarm/ChangeLog +++ b/apps/widbaroalarm/ChangeLog @@ -1 +1,2 @@ 0.01: Initial version +0.02: Do not warn multiple times for the same exceedance diff --git a/apps/widbaroalarm/README.md b/apps/widbaroalarm/README.md index b92a51050..fdc239170 100644 --- a/apps/widbaroalarm/README.md +++ b/apps/widbaroalarm/README.md @@ -2,10 +2,8 @@ Get a notification when the pressure reaches defined thresholds. -![Screenshot](screenshot.png) ## Settings - * Interval: check interval of sensor data in minutes. 0 to disable automatic check. * Low alarm: Toggle low alarm * Low threshold: Warn when pressure drops below this value diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json index 0976df531..82aaab65a 100644 --- a/apps/widbaroalarm/metadata.json +++ b/apps/widbaroalarm/metadata.json @@ -2,7 +2,7 @@ "id": "widbaroalarm", "name": "Barometer alarm widget", "shortName": "Barometer alarm", - "version": "0.01", + "version": "0.02", "description": "A widget that can alarm on when the pressure reaches defined thresholds.", "icon": "widget.png", "type": "widget", diff --git a/apps/widbaroalarm/settings.js b/apps/widbaroalarm/settings.js index 1455072e4..bea6319d1 100644 --- a/apps/widbaroalarm/settings.js +++ b/apps/widbaroalarm/settings.js @@ -36,7 +36,7 @@ value: settings.min, min: 600, max: 1000, - step: 10, + step: 5, onchange: x => save("min", x), }, "High alarm": { @@ -48,9 +48,9 @@ }, "High threshold": { value: settings.max, - min: 1000, + min: 700, max: 1100, - step: 10, + step: 5, onchange: x => save("max", x), }, "Drop alarm": { diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 7279a963a..a78f0a05c 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -1,185 +1,235 @@ (function() { - let medianPressure; - let threeHourAvrPressure; - let currentPressures = []; + let medianPressure; + let threeHourAvrPressure; + let currentPressures = []; - const LOG_FILE = "widbaroalarm.log.json"; - const SETTINGS_FILE = "widbaroalarm.json"; - const storage = require('Storage'); - let settings = Object.assign( + const LOG_FILE = "widbaroalarm.log.json"; + const SETTINGS_FILE = "widbaroalarm.json"; + const storage = require('Storage'); + + let settings; + + function loadSettings() { + settings = Object.assign( storage.readJSON("widbaroalarm.default.json", true) || {}, storage.readJSON(SETTINGS_FILE, true) || {} ); + } - function setting(key) { - return settings[key]; + loadSettings(); + + + function setting(key) { + return settings[key]; + } + + function saveSetting(key, value) { + settings[key] = value; + storage.write(SETTINGS_FILE, settings); + } + + const interval = setting("interval"); + + let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours + + function showAlarm(body, title) { + if (body == undefined) return; + + require("notify").show({ + title: title || "Pressure", + body: body, + icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) + }); + + if (setting("buzz") && + !(storage.readJSON('setting.json', 1) || {}).quiet) { + Bangle.buzz(); } - const interval = setting("interval"); + } - let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours - function showAlarm(body, title) { - if (body == undefined) return; + function didWeAlreadyWarn(key) { + return setting(key) == undefined || setting(key) > 0; + } - require("notify").show({ - title: title || "Pressure", - body: body, - icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) - }); - - if (setting("buzz") && - !(storage.readJSON('setting.json', 1) || {}).quiet) { - Bangle.buzz(); - } - } + function checkForAlarms(pressure) { + if (pressure == undefined || pressure <= 0) return; let alreadyWarned = false; - function checkForAlarms(pressure) { - if (pressure == undefined || pressure <= 0) return; + const ts = Math.round(Date.now() / 1000); // seconds + const d = { + "ts": ts, + "p": pressure + }; - const ts = Math.round(Date.now() / 1000); // seconds - const d = { - "ts": ts, - "p": pressure - }; - - // delete entries older than 3h - for (let i = 0; i < history3.length; i++) { - if (history3[i]["ts"] < ts - (3 * 60 * 60)) { - history3.shift(); - } - } - // delete oldest entries until we have max 50 - while (history3.length > 50) { + // delete entries older than 3h + for (let i = 0; i < history3.length; i++) { + if (history3[i]["ts"] < ts - (3 * 60 * 60)) { history3.shift(); } + } + // delete oldest entries until we have max 50 + while (history3.length > 50) { + history3.shift(); + } - history3.push(d); - // write data to storage - storage.writeJSON(LOG_FILE, history3); - - if (setting("lowalarm") && pressure <= setting("min")) { - showAlarm("Pressure low: " + Math.round(pressure) + " hPa"); - alreadyWarned = true; + if (setting("lowalarm")) { + // Is below the alarm threshold? + if (pressure <= setting("min")) { + if (!didWeAlreadyWarn("lastLowWarningTs")) { + showAlarm("Pressure low: " + Math.round(pressure) + " hPa"); + saveSetting("lastLowWarningTs", ts); + alreadyWarned = true; + } + } else { + saveSetting("lastLowWarningTs", 0); } - if (setting("highalarm") && pressure >= setting("max")) { - showAlarm("Pressure high: " + Math.round(pressure) + " hPa"); - alreadyWarned = true; + } else { + saveSetting("lastLowWarningTs", 0); + } + + if (setting("highalarm")) { + // Is above the alarm threshold? + if (pressure >= setting("max")) { + if (!didWeAlreadyWarn("lastHighWarningTs")) { + showAlarm("Pressure high: " + Math.round(pressure) + " hPa"); + saveSetting("lastHighWarningTs", ts); + alreadyWarned = true; + } + } else { + saveSetting("lastHighWarningTs", 0); } + } else { + saveSetting("lastHighWarningTs", 0); + } - if (!alreadyWarned) { - // 3h change detection - const drop3halarm = setting("drop3halarm"); - const raise3halarm = setting("raise3halarm"); - if (drop3halarm > 0 || raise3halarm > 0) { - // we need at least 30min of data for reliable detection - if (history3[0]["ts"] > ts - (30 * 60)) { - return; - } + if (!alreadyWarned) { + // 3h change detection + const drop3halarm = setting("drop3halarm"); + const raise3halarm = setting("raise3halarm"); + if (drop3halarm > 0 || raise3halarm > 0) { + // we need at least 30min of data for reliable detection + if (history3[0]["ts"] > ts - (30 * 60)) { + return; + } - // Get oldest entry: - const oldestPressure = history3[0]["p"]; - if (oldestPressure != undefined && oldestPressure > 0) { - const diff = oldestPressure - pressure; + // Get oldest entry: + const oldestPressure = history3[0]["p"]; + if (oldestPressure != undefined && oldestPressure > 0) { + const diff = oldestPressure - pressure; - // drop alarm - if (drop3halarm > 0 && oldestPressure > pressure) { - if (Math.abs(diff) > drop3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); + // drop alarm + if (drop3halarm > 0 && oldestPressure > pressure && !didWeAlreadyWarn("lastHighWarningTs")) { + if (Math.abs(diff) > drop3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); + saveSetting("lastDropWarningTs", ts); + } else { + saveSetting("lastDropWarningTs", ts); } + } else { + saveSetting("lastDropWarningTs", ts); } // raise alarm - if (raise3halarm > 0 && oldestPressure < pressure) { + if (raise3halarm > 0 && oldestPressure < pressure && !didWeAlreadyWarn("lastRaiseWarningTs")) { if (Math.abs(diff) > raise3halarm) { showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure raise"); + saveSetting("lastRaiseWarningTs", ts); + } else { + saveSetting("lastRaiseWarningTs", ts); + } + } else { + saveSetting("lastRaiseWarningTs", ts); } } } } + + history3.push(d); + // write data to storage + storage.writeJSON(LOG_FILE, history3); + + // calculate 3h average for widget + let sum = 0; + for (let i = 0; i < history3.length; i++) { + sum += history3[i]["p"]; + } + threeHourAvrPressure = sum / history3.length; } - // calculate 3h average for widget - let sum = 0; - for (let i = 0; i < history3.length; i++) { - sum += history3[i]["p"]; - } - threeHourAvrPressure = sum / history3.length; -} - -function baroHandler(data) { - if (data) { - const pressure = Math.round(data.pressure); - if (pressure == undefined || pressure <= 0) return; - currentPressures.push(pressure); - } -} - -/* - turn on barometer power - take 5 measurements - sort the results - take the middle one (median) - turn off barometer power -*/ -function check() { - Bangle.setBarometerPower(true, "widbaroalarm"); - setTimeout(function() { - currentPressures = []; - - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - - setTimeout(function() { - Bangle.setBarometerPower(false, "widbaroalarm"); - - currentPressures.sort(); - - // take median value - medianPressure = currentPressures[3]; - checkForAlarms(medianPressure); - }, 1000); - }, 500); -} - -function reload() { - check(); -} - -function draw() { - g.reset(); - if (setting("show") && medianPressure != undefined) { - g.setFont("6x8", 1).setFontAlign(1, 0); - g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6); - if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { - g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); + function baroHandler(data) { + if (data) { + const pressure = Math.round(data.pressure); + if (pressure == undefined || pressure <= 0) return; + currentPressures.push(pressure); } } -} -if (global.WIDGETS != undefined && typeof WIDGETS === "object") { - WIDGETS["baroalarm"] = { - width: setting("show") ? 24 : 0, - reload: reload, - area: "tr", - draw: draw - }; -} + /* + turn on barometer power + take 5 measurements + sort the results + take the middle one (median) + turn off barometer power + */ + function check() { + Bangle.setBarometerPower(true, "widbaroalarm"); + setTimeout(function() { + currentPressures = []; -// Let's delay the first check a bit -setTimeout(function() { -check(); -if (interval > 0) { - setInterval(check, interval * 60000); -} -}, 5000); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + + setTimeout(function() { + Bangle.setBarometerPower(false, "widbaroalarm"); + + currentPressures.sort(); + + // take median value + medianPressure = currentPressures[3]; + checkForAlarms(medianPressure); + }, 1000); + }, 500); + } + + function reload() { + check(); + } + + function draw() { + g.reset(); + if (setting("show") && medianPressure != undefined) { + g.setFont("6x8", 1).setFontAlign(1, 0); + g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6); + if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { + g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); + } + } + } + + if (global.WIDGETS != undefined && typeof WIDGETS === "object") { + WIDGETS["baroalarm"] = { + width: setting("show") ? 24 : 0, + reload: reload, + area: "tr", + draw: draw + }; + } + + // Let's delay the first check a bit + setTimeout(function() { + check(); + if (interval > 0) { + setInterval(check, interval * 60000); + } + }, 1000); })(); From ac652282ca54552f74ffcc0dd060041e3460c7c3 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Wed, 9 Mar 2022 10:22:23 +0100 Subject: [PATCH 405/447] cscsensor: Test enable on Bangle2 --- apps/cscsensor/ChangeLog | 1 + apps/cscsensor/metadata.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index 8f23fa9f3..a98be5c0f 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -5,3 +5,4 @@ 0.05: Add cadence sensor support 0.06: Now read wheel rev as well as cadence sensor Improve connection code +0.07: Make Bangle.js 2 compatible diff --git a/apps/cscsensor/metadata.json b/apps/cscsensor/metadata.json index af338c59e..4006789ef 100644 --- a/apps/cscsensor/metadata.json +++ b/apps/cscsensor/metadata.json @@ -2,11 +2,11 @@ "id": "cscsensor", "name": "Cycling speed sensor", "shortName": "CSCSensor", - "version": "0.06", + "version": "0.07", "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", "icon": "icons8-cycling-48.png", "tags": "outdoors,exercise,ble,bluetooth", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", "storage": [ {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, From 731c134cde83eabee52d037619741f0a328059f3 Mon Sep 17 00:00:00 2001 From: Marco H Date: Wed, 9 Mar 2022 10:24:39 +0100 Subject: [PATCH 406/447] Try not to warn multiple times for the same exceedance (2nd part) --- apps/widbaroalarm/widget.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index a78f0a05c..42e234fc7 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -120,29 +120,33 @@ const diff = oldestPressure - pressure; // drop alarm - if (drop3halarm > 0 && oldestPressure > pressure && !didWeAlreadyWarn("lastHighWarningTs")) { + if (drop3halarm > 0 && oldestPressure > pressure) { if (Math.abs(diff) > drop3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); - saveSetting("lastDropWarningTs", ts); + if (!didWeAlreadyWarn("lastHighWarningTs")) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); + saveSetting("lastDropWarningTs", ts); + } } else { - saveSetting("lastDropWarningTs", ts); + saveSetting("lastDropWarningTs", 0); } } else { - saveSetting("lastDropWarningTs", ts); + saveSetting("lastDropWarningTs", 0); } // raise alarm - if (raise3halarm > 0 && oldestPressure < pressure && !didWeAlreadyWarn("lastRaiseWarningTs")) { + if (raise3halarm > 0 && oldestPressure < pressure) { if (Math.abs(diff) > raise3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure raise"); - saveSetting("lastRaiseWarningTs", ts); + if (!didWeAlreadyWarn("lastRaiseWarningTs")) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure raise"); + saveSetting("lastRaiseWarningTs", ts); + } } else { - saveSetting("lastRaiseWarningTs", ts); + saveSetting("lastRaiseWarningTs", 0); } } else { - saveSetting("lastRaiseWarningTs", ts); + saveSetting("lastRaiseWarningTs", 0); } } } From e0937a942b216dd41fa574a39ed2186f34603398 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 9 Mar 2022 13:39:19 +0000 Subject: [PATCH 407/447] messages 0.25: Fix widget memory usage issues if message received and watch repeatedly calls Bangle.drawWidgets (fix #1550) --- apps/gbridge/metadata.json | 2 +- apps/messages/ChangeLog | 3 ++- apps/messages/metadata.json | 2 +- apps/messages/widget.js | 7 ++++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/gbridge/metadata.json b/apps/gbridge/metadata.json index 0c46aa852..db7119758 100644 --- a/apps/gbridge/metadata.json +++ b/apps/gbridge/metadata.json @@ -2,7 +2,7 @@ "id": "gbridge", "name": "Gadgetbridge", "version": "0.26", - "description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android' Bangle.js app instead.", + "description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android Integration' Bangle.js app instead.", "icon": "app.png", "type": "widget", "tags": "tool,system,android,widget", diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index bd40868a5..02492d5ea 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -35,5 +35,6 @@ Allow repeat to be switched Off, so there is no buzzing repetition. Also gave the widget a pixel more room to the right 0.23: Change message colors to match current theme instead of using green - Now attempt to use Large/Big/Medium fonts, and allow minimum font size to be configured + Now attempt to use Large/Big/Medium fonts, and allow minimum font size to be configured 0.24: Remove left-over debug statement +0.25: Fix widget memory usage issues if message received and watch repeatedly calls Bangle.drawWidgets (fix #1550) diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 0387c1972..ff6a078a5 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.24", + "version": "0.25", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/widget.js b/apps/messages/widget.js index d9363573a..ad8d58c40 100644 --- a/apps/messages/widget.js +++ b/apps/messages/widget.js @@ -1,5 +1,10 @@ WIDGETS["messages"]={area:"tl", width:0, iconwidth:24, draw:function() { + // If we had a setTimeout queued from the last time we were called, remove it + if (WIDGETS["messages"].i) { + clearTimeout(WIDGETS["messages"].i); + delete WIDGETS["messages"].i; + } Bangle.removeListener('touch', this.touch); if (!this.width) return; var c = (Date.now()-this.t)/1000; @@ -11,7 +16,7 @@ draw:function() { this.l = Date.now(); WIDGETS["messages"].buzz(); // buzz every 4 seconds } - setTimeout(()=>WIDGETS["messages"].draw(), 1000); + WIDGETS["messages"].i=setTimeout(()=>WIDGETS["messages"].draw(), 1000); if (process.env.HWVERSION>1) Bangle.on('touch', this.touch); },show:function(quiet) { WIDGETS["messages"].t=Date.now(); // first time From 7250f4f23013fe901d86c7cb21b8456b60ab1c4c Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 9 Mar 2022 20:30:39 +0100 Subject: [PATCH 408/447] bthrm - Allow scanning for sensors in settings --- apps/bthrm/ChangeLog | 1 + apps/bthrm/boot.js | 27 ++++++-- apps/bthrm/metadata.json | 2 +- apps/bthrm/settings.js | 142 ++++++++++++++++++++++++++------------- 4 files changed, 118 insertions(+), 54 deletions(-) diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog index 58d002f22..41eec666a 100644 --- a/apps/bthrm/ChangeLog +++ b/apps/bthrm/ChangeLog @@ -20,3 +20,4 @@ 0.07: Recorder icon only blue if values actually arive Adds some preset modes and a custom one Restructure the settings menu +0.08: Allow scanning for devices in settings diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 339f6f8c6..3a1f1cc4c 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -23,7 +23,10 @@ } function getCache(){ - return require('Storage').readJSON("bthrm.cache.json", true) || {}; + var cache = require('Storage').readJSON("bthrm.cache.json", true) || {}; + if (settings.btname && settings.btname == cache.name) return cache; + clearCache(); + return {}; } function addNotificationHandler(characteristic){ @@ -361,7 +364,13 @@ var promise; if (!device){ - promise = NRF.requestDevice({ filters: serviceFilters }); + var filters = serviceFilters; + if (settings.btname){ + log("Configured device name", settings.btname); + filters = [{name: settings.btname}]; + } + log("Requesting device with filters", filters); + promise = NRF.requestDevice({ filters: filters }); if (settings.gracePeriodRequest){ log("Add " + settings.gracePeriodRequest + "ms grace period after request"); @@ -488,11 +497,15 @@ if (gatt) { if (gatt.connected){ log("Disconnect with gatt: ", gatt); - gatt.disconnect().then(()=>{ - log("Successful disconnect"); - }).catch((e)=>{ - log("Error during disconnect", e); - }); + try{ + gatt.disconnect().then(()=>{ + log("Successful disconnect"); + }).catch((e)=>{ + log("Error during disconnect promise", e); + }); + } catch (e){ + log("Error during disconnect attempt", e); + } } } } diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index 1c21269e2..b35ebd6af 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -2,7 +2,7 @@ "id": "bthrm", "name": "Bluetooth Heart Rate Monitor", "shortName": "BT HRM", - "version": "0.07", + "version": "0.08", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js index beefb00e9..4b564d670 100644 --- a/apps/bthrm/settings.js +++ b/apps/bthrm/settings.js @@ -17,54 +17,73 @@ var settings; readSettings(); - var mainmenu = { - '': { 'title': 'Bluetooth HRM' }, - '< Back': back, - 'Mode': { - value: 0 | settings.mode, - min: 0, - max: 3, - format: v => ["Off", "Default", "Both", "Custom"][v], - onchange: v => { - settings.mode = v; - switch (v){ - case 0: - writeSettings("enabled",false); - break; - case 1: - writeSettings("enabled",true); - writeSettings("replace",true); - writeSettings("debuglog",false); - writeSettings("startWithHrm",true); - writeSettings("allowFallback",true); - writeSettings("fallbackTimeout",10); - break; - case 2: - writeSettings("enabled",true); - writeSettings("replace",false); - writeSettings("debuglog",false); - writeSettings("startWithHrm",false); - writeSettings("allowFallback",false); - break; - case 3: - writeSettings("enabled",true); - writeSettings("replace",settings.custom_replace); - writeSettings("debuglog",settings.custom_debuglog); - writeSettings("startWithHrm",settings.custom_startWithHrm); - writeSettings("allowFallback",settings.custom_allowFallback); - writeSettings("fallbackTimeout",settings.custom_fallbackTimeout); - break; + function buildMainMenu(){ + var mainmenu = { + '': { 'title': 'Bluetooth HRM' }, + '< Back': back, + 'Mode': { + value: 0 | settings.mode, + min: 0, + max: 3, + format: v => ["Off", "Default", "Both", "Custom"][v], + onchange: v => { + settings.mode = v; + switch (v){ + case 0: + writeSettings("enabled",false); + break; + case 1: + writeSettings("enabled",true); + writeSettings("replace",true); + writeSettings("debuglog",false); + writeSettings("startWithHrm",true); + writeSettings("allowFallback",true); + writeSettings("fallbackTimeout",10); + break; + case 2: + writeSettings("enabled",true); + writeSettings("replace",false); + writeSettings("debuglog",false); + writeSettings("startWithHrm",false); + writeSettings("allowFallback",false); + break; + case 3: + writeSettings("enabled",true); + writeSettings("replace",settings.custom_replace); + writeSettings("debuglog",settings.custom_debuglog); + writeSettings("startWithHrm",settings.custom_startWithHrm); + writeSettings("allowFallback",settings.custom_allowFallback); + writeSettings("fallbackTimeout",settings.custom_fallbackTimeout); + break; + } + writeSettings("mode",v); } - writeSettings("mode",v); } - }, - 'Custom Mode': function() { E.showMenu(submenu_custom); }, - 'Debug': function() { E.showMenu(submenu_debug); } - }; + }; + + if (settings.btname){ + var name = "Clear " + settings.btname; + mainmenu[name] = function() { + E.showPrompt("Clear current device name?").then((r)=>{ + if (r) { + writeSettings("btname",undefined); + } + E.showMenu(buildMainMenu()); + }); + }; + } + + mainmenu["BLE Scan"] = ()=> createMenuFromScan(); + mainmenu["Custom Mode"] = function() { E.showMenu(submenu_custom); }; + mainmenu.Debug = function() { E.showMenu(submenu_debug); }; + return mainmenu; + } + + var submenu_debug = { '' : { title: "Debug"}, - '< Back': function() { E.showMenu(mainmenu); }, + '< Back': function() { E.showMenu(buildMainMenu()); }, 'Alert on disconnect': { value: !!settings.warnDisconnect, format: v => settings.warnDisconnect ? "On" : "Off", @@ -81,10 +100,41 @@ }, 'Grace periods': function() { E.showMenu(submenu_grace); } }; + + function createMenuFromScan(){ + E.showMenu(); + E.showMessage("Scanning"); + + var submenu_scan = { + '' : { title: "Scan"}, + '< Back': function() { E.showMenu(buildMainMenu()); } + }; + var packets=10; + var scanStart=Date.now(); + NRF.setScan(function(d) { + packets--; + if (packets<=0 || Date.now() - scanStart > 5000){ + NRF.setScan(); + E.showMenu(submenu_scan); + } else if (d.name){ + print("Found device", d); + submenu_scan[d.name] = function(){ + E.showPrompt("Set "+d.name+"?").then((r)=>{ + if (r) { + writeSettings("btname",d.name); + } + E.showMenu(buildMainMenu()); + }); + }; + } + }, { filters: [{services: [ "180d" ]}]}); + } + + var submenu_custom = { '' : { title: "Custom mode"}, - '< Back': function() { E.showMenu(mainmenu); }, + '< Back': function() { E.showMenu(buildMainMenu()); }, 'Replace HRM': { value: !!settings.custom_replace, format: v => settings.custom_replace ? "On" : "Off", @@ -165,7 +215,7 @@ var submenu = { '' : { title: "Grace periods"}, - '< Back': function() { E.showMenu(mainmenu); }, + '< Back': function() { E.showMenu(buildMainMenu()); }, 'Request': { value: settings.gracePeriodRequest, min: 0, @@ -208,5 +258,5 @@ } }; - E.showMenu(mainmenu); + E.showMenu(buildMainMenu()); }) From 10892718cdf3192d3deb7abd5b755f072ec23ae4 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Wed, 9 Mar 2022 22:53:31 +0100 Subject: [PATCH 409/447] cscsensor Fix button mapping --- apps/cscsensor/README.md | 6 +++--- apps/cscsensor/cscsensor.app.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index 9740fd9cf..3828e8e3e 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -11,9 +11,9 @@ Currently the app displays the following data: - total distance traveled - an icon with the battery status of the remote sensor -Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.1 miles and upon exiting the app. -If the watch app has not received an update from the sensor for at least 10 seconds, pushing button 3 will attempt to reconnect to the sensor. -Button 2 switches between the display for cycling speed and cadence. +Button 1 (swipe up on Bangle.js 2) resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.1 miles and upon exiting the app. +If the watch app has not received an update from the sensor for at least 10 seconds, pushing button 3 (swipe down on Bangle.js 2) will attempt to reconnect to the sensor. +Button 2 (tap on Bangle.js 2) switches between the display for cycling speed and cadence. Values displayed are imperial or metric (depending on locale), cadence is in RPM, the wheel circumference can be adjusted in the global settings app. diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index e2af0db16..14403dd8d 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -254,8 +254,8 @@ E.on('kill',()=>{ NRF.on('disconnect', connection_setup); // restart if disconnected Bangle.setUI("updown", d=>{ if (d<0) { mySensor.reset(); g.clearRect(0, 48, W, H); mySensor.updateScreen(); } - if (d==0) { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); } - if (d>0) { mySensor.toggleDisplayCadence(); g.clearRect(0, 48, W, H); mySensor.updateScreen(); } + else if (d>0) { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); } + else { mySensor.toggleDisplayCadence(); g.clearRect(0, 48, W, H); mySensor.updateScreen(); } }); Bangle.loadWidgets(); From ea3e7ff7b93315ef121e42cf970889829d8f4cb5 Mon Sep 17 00:00:00 2001 From: Marco H Date: Thu, 10 Mar 2022 09:15:41 +0100 Subject: [PATCH 410/447] Fix multiple drop warnings --- apps/widbaroalarm/widget.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 42e234fc7..5d62156eb 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -122,7 +122,7 @@ // drop alarm if (drop3halarm > 0 && oldestPressure > pressure) { if (Math.abs(diff) > drop3halarm) { - if (!didWeAlreadyWarn("lastHighWarningTs")) { + if (!didWeAlreadyWarn("lastDropWarningTs")) { showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); saveSetting("lastDropWarningTs", ts); @@ -209,6 +209,15 @@ } function draw() { + if (global.WIDGETS != undefined && typeof WIDGETS === "object") { + WIDGETS["baroalarm"] = { + width: setting("show") ? 24 : 0, + reload: reload, + area: "tr", + draw: draw + }; + } + g.reset(); if (setting("show") && medianPressure != undefined) { g.setFont("6x8", 1).setFontAlign(1, 0); @@ -219,15 +228,6 @@ } } - if (global.WIDGETS != undefined && typeof WIDGETS === "object") { - WIDGETS["baroalarm"] = { - width: setting("show") ? 24 : 0, - reload: reload, - area: "tr", - draw: draw - }; - } - // Let's delay the first check a bit setTimeout(function() { check(); From c1c7d2b484e16064939324aa700806f77b547e39 Mon Sep 17 00:00:00 2001 From: fparri Date: Thu, 10 Mar 2022 11:36:11 +0100 Subject: [PATCH 411/447] Update metadata.json I only changed the name of the app so that it shows the initials in uppercase. --- apps/widbaroalarm/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json index 0976df531..0953f4f1b 100644 --- a/apps/widbaroalarm/metadata.json +++ b/apps/widbaroalarm/metadata.json @@ -1,7 +1,7 @@ { "id": "widbaroalarm", - "name": "Barometer alarm widget", - "shortName": "Barometer alarm", + "name": "Barometer Alarm Widget", + "shortName": "Barometer Alarm", "version": "0.01", "description": "A widget that can alarm on when the pressure reaches defined thresholds.", "icon": "widget.png", From d748bcd6bfe3121161c5e29fe6ab66e3114ce910 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 10 Mar 2022 13:39:06 +0000 Subject: [PATCH 412/447] https://github.com/espruino/BangleApps/issues/1553Ensure we figure out what device is connected and what apps we have installed before uploading custom app - fix https://github.com/espruino/BangleApps/issues/1553 --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index a7a80a13f..affb0b15b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit a7a80a13fa187a4ff5f89669992babca2d95812c +Subproject commit affb0b15b41eb35a1548373831af7001bad64435 From b5bc96a2294644950a1e2cb2cbe4679f3ac945a5 Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Thu, 10 Mar 2022 21:18:55 +0100 Subject: [PATCH 413/447] update forgoten metadata.json --- apps/terminalclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json index 6907da84d..de0244318 100644 --- a/apps/terminalclock/metadata.json +++ b/apps/terminalclock/metadata.json @@ -3,7 +3,7 @@ "name": "Terminal Clock", "shortName":"Terminal Clock", "description": "A terminal cli like clock displaying multiple sensor data", - "version":"0.01", + "version":"0.02", "icon": "app.png", "type": "clock", "tags": "clock", From 43094112d1ed47d63f2c414e85e9369b7892a7b8 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 10 Mar 2022 22:00:40 +0000 Subject: [PATCH 414/447] Daisy: changed text to uppercase, just looks better --- apps/daisy/ChangeLog | 1 + apps/daisy/app.js | 10 +++++----- apps/daisy/metadata.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index 115c8f2ff..26396b75c 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -2,3 +2,4 @@ 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 +0.05: changed text to uppercase, just looks better, removed colons on text diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 01d177a32..cf0287616 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -109,10 +109,10 @@ function updateSunRiseSunSet(now, lat, lon, line){ const infoData = { ID_DATE: { calc: () => {var d = (new Date()).toString().split(" "); return d[2] + ' ' + d[1] + ' ' + d[3];} }, ID_DAY: { calc: () => {var d = require("locale").dow(new Date()).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} }, - ID_SR: { calc: () => 'Sunrise: ' + sunRise }, - ID_SS: { calc: () => 'Sunset: ' + sunSet }, - ID_STEP: { calc: () => 'Steps: ' + getSteps() }, - ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' }, + ID_SR: { calc: () => 'Sunrise ' + sunRise }, + ID_SS: { calc: () => 'Sunset ' + sunSet }, + ID_STEP: { calc: () => 'Steps ' + getSteps() }, + ID_BATT: { calc: () => 'Battery ' + E.getBattery() + '%' }, ID_HRM: { calc: () => hrmCurrent } }; @@ -158,7 +158,7 @@ function drawInfo() { g.setColor('#f00'); // red drawHeartIcon(); } else { - g.drawString((infoData[infoMode].calc()), w/2, infoLine); + g.drawString((infoData[infoMode].calc().toUpperCase()), w/2, infoLine); } } diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index 5e53f2d5e..15a24592c 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.04", + "version":"0.05", "dependencies": {"mylocation":"app"}, "description": "A clock based on the Pastel clock with large ring guage for steps", "icon": "app.png", From 2f2f6f0b0d7bcd8d0eb64c1d4edccb6e188cc560 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 11 Mar 2022 11:39:29 +0000 Subject: [PATCH 415/447] 0.43: Fix Gadgetbridge handling with Programmable:off --- apps/boot/ChangeLog | 1 + apps/boot/bootupdate.js | 2 +- apps/boot/metadata.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 4c3d3b930..e75c9cc7b 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -46,3 +46,4 @@ 0.40: Bootloader now rebuilds for new firmware versions 0.41: Add Keyboard and Mouse Bluetooth HID option 0.42: Sort *.boot.js files lexically and by optional numeric priority, e.g. appname..boot.js +0.43: Fix Gadgetbridge handling with Programmable:off diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 63424bfbf..e5a8cff51 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -38,7 +38,7 @@ LoopbackA.setConsole(true);\n`; boot += ` Bluetooth.line=""; Bluetooth.on('data',function(d) { - var l = (Bluetooth.line + d).split("\n"); + var l = (Bluetooth.line + d).split(/[\\n\\r]/); Bluetooth.line = l.pop(); l.forEach(n=>Bluetooth.emit("line",n)); }); diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index 4cbfd9c59..edddc6b41 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -1,7 +1,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.42", + "version": "0.43", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", From 7335289abfc7a333dcc6b6e960812915a94055a9 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Sat, 12 Mar 2022 07:10:48 +0100 Subject: [PATCH 416/447] cscsensor Scale layout on BangleJS2 --- apps/cscsensor/cscsensor.app.js | 155 +++++++++++++++++--------------- 1 file changed, 81 insertions(+), 74 deletions(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 14403dd8d..4ebe7d57e 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -7,6 +7,11 @@ const SETTINGS_FILE = 'cscsensor.json'; const storage = require('Storage'); const W = g.getWidth(); const H = g.getHeight(); +const yStart = 48; +const rowHeight = (H-yStart)/6; +const yCol1 = W/2.7586; +const fontSizeLabel = W/12.632; +const fontSizeValue = W/9.2308; class CSCSensor { constructor() { @@ -22,7 +27,6 @@ class CSCSensor { this.speed = 0; this.maxSpeed = 0; this.lastSpeed = 0; - this.qUpdateScreen = true; this.lastRevsStart = -1; this.qMetric = !require("locale").speed(1).toString().endsWith("mph"); this.speedUnit = this.qMetric ? "km/h" : "mph"; @@ -49,6 +53,7 @@ class CSCSensor { toggleDisplayCadence() { this.showCadence = !this.showCadence; this.screenInit = true; + g.setBgColor(0, 0, 0); } setBatteryLevel(level) { @@ -63,14 +68,16 @@ class CSCSensor { } drawBatteryIcon() { - g.setColor(1, 1, 1).drawRect(10, 55, 20, 75).fillRect(14, 53, 16, 55).setColor(0).fillRect(11, 56, 19, 74); + g.setColor(1, 1, 1).drawRect(10*W/240, yStart+0.029167*H, 20*W/240, yStart+0.1125*H) + .fillRect(14*W/240, yStart+0.020833*H, 16*W/240, yStart+0.029167*H) + .setColor(0).fillRect(11*W/240, yStart+0.033333*H, 19*W/240, yStart+0.10833*H); if (this.batteryLevel!=-1) { if (this.batteryLevel<25) g.setColor(1, 0, 0); else if (this.batteryLevel<50) g.setColor(1, 0.5, 0); else g.setColor(0, 1, 0); - g.fillRect(11, 74-18*this.batteryLevel/100, 19, 74); + g.fillRect(11*W/240, (yStart+0.10833*H)-18*this.batteryLevel/100, 19*W/240, yStart+0.10833*H); } - else g.setFontVector(14).setFontAlign(0, 0, 0).setColor(0xffff).drawString("?", 16, 66); + else g.setFontVector(W/17.143).setFontAlign(0, 0, 0).setColor(0xffff).drawString("?", 16*W/240, yStart+0.075*H); } updateScreenRevs() { @@ -88,36 +95,36 @@ class CSCSensor { for (var i=0; i<6; ++i) { if ((i&1)==0) g.setColor(0, 0, 0); else g.setColor(0x30cd); - g.fillRect(0, 48+i*32, 86, 48+(i+1)*32); + g.fillRect(0, yStart+i*rowHeight, yCol1-1, yStart+(i+1)*rowHeight); if ((i&1)==1) g.setColor(0); else g.setColor(0x30cd); - g.fillRect(87, 48+i*32, 239, 48+(i+1)*32); - g.setColor(0.5, 0.5, 0.5).drawRect(87, 48+i*32, 239, 48+(i+1)*32).drawLine(0, 239, 239, 239);//.drawRect(0, 48, 87, 239); - g.moveTo(0, 80).lineTo(30, 80).lineTo(30, 48).lineTo(87, 48).lineTo(87, 239).lineTo(0, 239).lineTo(0, 80); + g.fillRect(yCol1, yStart+i*rowHeight, H-1, yStart+(i+1)*rowHeight); + g.setColor(0.5, 0.5, 0.5).drawRect(yCol1, yStart+i*rowHeight, H-1, yStart+(i+1)*rowHeight).drawLine(0, H-1, W-1, H-1); + g.moveTo(0, yStart+0.13333*H).lineTo(30*W/240, yStart+0.13333*H).lineTo(30*W/240, yStart).lineTo(yCol1, yStart).lineTo(yCol1, H-1).lineTo(0, H-1).lineTo(0, yStart+0.13333*H); } - g.setFontAlign(1, 0, 0).setFontVector(19).setColor(1, 1, 0); - g.drawString("Time:", 87, 66); - g.drawString("Speed:", 87, 98); - g.drawString("Ave spd:", 87, 130); - g.drawString("Max spd:", 87, 162); - g.drawString("Trip:", 87, 194); - g.drawString("Total:", 87, 226); + g.setFontAlign(1, 0, 0).setFontVector(fontSizeLabel).setColor(1, 1, 0); + g.drawString("Time:", yCol1, yStart+rowHeight/2+0*rowHeight); + g.drawString("Speed:", yCol1, yStart+rowHeight/2+1*rowHeight); + g.drawString("Avg spd:", yCol1, yStart+rowHeight/2+2*rowHeight); + g.drawString("Max spd:", yCol1, yStart+rowHeight/2+3*rowHeight); + g.drawString("Trip:", yCol1, yStart+rowHeight/2+4*rowHeight); + g.drawString("Total:", yCol1, yStart+rowHeight/2+5*rowHeight); this.drawBatteryIcon(); this.screenInit = false; } - g.setFontAlign(-1, 0, 0).setFontVector(26); - g.setColor(0x30cd).fillRect(88, 49, 238, 79); - g.setColor(0xffff).drawString(dmins+":"+dsecs, 92, 66); - g.setColor(0).fillRect(88, 81, 238, 111); - g.setColor(0xffff).drawString(dspeed+" "+this.speedUnit, 92, 98); - g.setColor(0x30cd).fillRect(88, 113, 238, 143); - g.setColor(0xffff).drawString(avespeed + " " + this.speedUnit, 92, 130); - g.setColor(0).fillRect(88, 145, 238, 175); - g.setColor(0xffff).drawString(maxspeed + " " + this.speedUnit, 92, 162); - g.setColor(0x30cd).fillRect(88, 177, 238, 207); - g.setColor(0xffff).drawString(ddist + " " + this.distUnit, 92, 194); - g.setColor(0).fillRect(88, 209, 238, 238); - g.setColor(0xffff).drawString(tdist + " " + this.distUnit, 92, 226); + g.setFontAlign(-1, 0, 0).setFontVector(fontSizeValue); + g.setColor(0x30cd).fillRect(yCol1+1, 49+rowHeight*0, 238, 47+1*rowHeight); + g.setColor(0xffff).drawString(dmins+":"+dsecs, yCol1+5, 50+rowHeight/2+0*rowHeight); + g.setColor(0).fillRect(yCol1+1, 49+rowHeight*1, 238, 47+2*rowHeight); + g.setColor(0xffff).drawString(dspeed+" "+this.speedUnit, yCol1+5, 50+rowHeight/2+1*rowHeight); + g.setColor(0x30cd).fillRect(yCol1+1, 49+rowHeight*2, 238, 47+3*rowHeight); + g.setColor(0xffff).drawString(avespeed + " " + this.speedUnit, yCol1+5, 50+rowHeight/2+2*rowHeight); + g.setColor(0).fillRect(yCol1+1, 49+rowHeight*3, 238, 47+4*rowHeight); + g.setColor(0xffff).drawString(maxspeed + " " + this.speedUnit, yCol1+5, 50+rowHeight/2+3*rowHeight); + g.setColor(0x30cd).fillRect(yCol1+1, 49+rowHeight*4, 238, 47+5*rowHeight); + g.setColor(0xffff).drawString(ddist + " " + this.distUnit, yCol1+5, 50+rowHeight/2+4*rowHeight); + g.setColor(0).fillRect(yCol1+1, 49+rowHeight*5, 238, 47+6*rowHeight); + g.setColor(0xffff).drawString(tdist + " " + this.distUnit, yCol1+5, 50+rowHeight/2+5*rowHeight); } updateScreenCadence() { @@ -125,21 +132,21 @@ class CSCSensor { for (var i=0; i<2; ++i) { if ((i&1)==0) g.setColor(0, 0, 0); else g.setColor(0x30cd); - g.fillRect(0, 48+i*32, 86, 48+(i+1)*32); + g.fillRect(0, yStart+i*rowHeight, yCol1-1, yStart+(i+1)*rowHeight); if ((i&1)==1) g.setColor(0); else g.setColor(0x30cd); - g.fillRect(87, 48+i*32, 239, 48+(i+1)*32); - g.setColor(0.5, 0.5, 0.5).drawRect(87, 48+i*32, 239, 48+(i+1)*32).drawLine(0, 239, 239, 239);//.drawRect(0, 48, 87, 239); - g.moveTo(0, 80).lineTo(30, 80).lineTo(30, 48).lineTo(87, 48).lineTo(87, 239).lineTo(0, 239).lineTo(0, 80); + g.fillRect(yCol1, yStart+i*rowHeight, H-1, yStart+(i+1)*rowHeight); + g.setColor(0.5, 0.5, 0.5).drawRect(yCol1, yStart+i*rowHeight, H-1, yStart+(i+1)*rowHeight).drawLine(0, H-1, W-1, H-1); + g.moveTo(0, yStart+0.13333*H).lineTo(30*W/240, yStart+0.13333*H).lineTo(30*W/240, yStart).lineTo(yCol1, yStart).lineTo(yCol1, H-1).lineTo(0, H-1).lineTo(0, yStart+0.13333*H); } - g.setFontAlign(1, 0, 0).setFontVector(19).setColor(1, 1, 0); - g.drawString("Cadence:", 87, 98); + g.setFontAlign(1, 0, 0).setFontVector(fontSizeLabel).setColor(1, 1, 0); + g.drawString("Cadence:", yCol1, yStart+rowHeight/2+1*rowHeight); this.drawBatteryIcon(); this.screenInit = false; } - g.setFontAlign(-1, 0, 0).setFontVector(26); - g.setColor(0).fillRect(88, 81, 238, 111); - g.setColor(0xffff).drawString(Math.round(this.cadence), 92, 98); + g.setFontAlign(-1, 0, 0).setFontVector(fontSizeValue); + g.setColor(0).fillRect(yCol1+1, 49+rowHeight*1, 238, 47+2*rowHeight); + g.setColor(0xffff).drawString(Math.round(this.cadence), yCol1+5, 50+rowHeight/2+1*rowHeight); } updateScreen() { @@ -163,45 +170,45 @@ class CSCSensor { } this.lastCrankRevs = crankRevs; this.lastCrankTime = crankTime; - } - // wheel revolution - var wheelRevs = event.target.value.getUint32(1, true); - var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); - if (dRevs>0) { - qChanged = true; - this.totaldist += dRevs*this.wheelCirc/63360.0; - if ((this.totaldist-this.settings.totaldist)>0.1) { - this.settings.totaldist = this.totaldist; - storage.writeJSON(SETTINGS_FILE, this.settings); + } else { + // wheel revolution + var wheelRevs = event.target.value.getUint32(1, true); + var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); + if (dRevs>0) { + qChanged = true; + this.totaldist += dRevs*this.wheelCirc/63360.0; + if ((this.totaldist-this.settings.totaldist)>0.1) { + this.settings.totaldist = this.totaldist; + storage.writeJSON(SETTINGS_FILE, this.settings); + } } - } - this.lastRevs = wheelRevs; - if (this.lastRevsStart<0) this.lastRevsStart = wheelRevs; - var wheelTime = event.target.value.getUint16(5, true); - var dT = (wheelTime-this.lastTime)/1024; - var dBT = (Date.now()-this.lastBangleTime)/1000; - this.lastBangleTime = Date.now(); - if (dT<0) dT+=64; - if (Math.abs(dT-dBT)>3) dT = dBT; - this.lastTime = wheelTime; - this.speed = this.lastSpeed; - if (dRevs>0 && dT>0) { - this.speed = (dRevs*this.wheelCirc/63360.0)*3600/dT; - this.speedFailed = 0; - this.movingTime += dT; - } - else { - this.speedFailed++; - qChanged = false; - if (this.speedFailed>3) { - this.speed = 0; - qChanged = (this.lastSpeed>0); + this.lastRevs = wheelRevs; + if (this.lastRevsStart<0) this.lastRevsStart = wheelRevs; + var wheelTime = event.target.value.getUint16(5, true); + var dT = (wheelTime-this.lastTime)/1024; + var dBT = (Date.now()-this.lastBangleTime)/1000; + this.lastBangleTime = Date.now(); + if (dT<0) dT+=64; + if (Math.abs(dT-dBT)>3) dT = dBT; + this.lastTime = wheelTime; + this.speed = this.lastSpeed; + if (dRevs>0 && dT>0) { + this.speed = (dRevs*this.wheelCirc/63360.0)*3600/dT; + this.speedFailed = 0; + this.movingTime += dT; + } else if (!this.showCadence) { + this.speedFailed++; + qChanged = false; + if (this.speedFailed>3) { + this.speed = 0; + qChanged = (this.lastSpeed>0); + } } + this.lastSpeed = this.speed; + if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed; } - this.lastSpeed = this.speed; - if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed; } - if (qChanged && this.qUpdateScreen) this.updateScreen(); + if (qChanged) this.updateScreen(); } } @@ -253,9 +260,9 @@ E.on('kill',()=>{ }); NRF.on('disconnect', connection_setup); // restart if disconnected Bangle.setUI("updown", d=>{ - if (d<0) { mySensor.reset(); g.clearRect(0, 48, W, H); mySensor.updateScreen(); } + if (d<0) { mySensor.reset(); g.clearRect(0, yStart, W, H); mySensor.updateScreen(); } else if (d>0) { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); } - else { mySensor.toggleDisplayCadence(); g.clearRect(0, 48, W, H); mySensor.updateScreen(); } + else { mySensor.toggleDisplayCadence(); g.clearRect(0, yStart, W, H); mySensor.updateScreen(); } }); Bangle.loadWidgets(); From 5a546780c276e02698c9882e001155e18fe13933 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:06:30 +0100 Subject: [PATCH 417/447] Update ChangeLog --- apps/speedalt/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/speedalt/ChangeLog b/apps/speedalt/ChangeLog index 0550f9b86..78c14594b 100644 --- a/apps/speedalt/ChangeLog +++ b/apps/speedalt/ChangeLog @@ -9,3 +9,4 @@ 0.09: Add third screen mode with large clock and waypoint selection display to ease visibility in bright daylight. 0.10: Add Kalman filter to smooth the speed and altitude values. Can be disabled in settings. 0.11: Now also runs on Bangle.js 2 with basic functionality +0.12: Full functionality on Bangle.js 2: Bangle.js 1 buttons mapped to touch areas. From defc6206fff1226081c4234c48e94e0d56b54ce9 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:06:58 +0100 Subject: [PATCH 418/447] Update metadata.json --- apps/speedalt/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/speedalt/metadata.json b/apps/speedalt/metadata.json index 617ac4b8e..e03d23c8b 100644 --- a/apps/speedalt/metadata.json +++ b/apps/speedalt/metadata.json @@ -2,7 +2,7 @@ "id": "speedalt", "name": "GPS Adventure Sports", "shortName": "GPS Adv Sport", - "version": "0.11", + "version": "0.12", "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", "icon": "app.png", "type": "app", From 35cf7630b33b522ef72195df42a63b86c58f350f Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:12:51 +0100 Subject: [PATCH 419/447] Update app.js --- apps/speedalt/app.js | 117 ++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 67 deletions(-) diff --git a/apps/speedalt/app.js b/apps/speedalt/app.js index f979762f1..79db932db 100644 --- a/apps/speedalt/app.js +++ b/apps/speedalt/app.js @@ -349,7 +349,7 @@ function drawSecondary(n,u) { s = 30; // Font size if (BANGLEJS2) s *= fontFactorB2; buf.setFontVector(s); - buf.drawString(u,xu - (BANGLEJS2*20),screenH_TwoThirds-25); + buf.drawString(u,xu - (BANGLEJS2*xu/5),screenH_TwoThirds-25); } function drawTime() { @@ -391,7 +391,7 @@ function drawWP() { // from waypoints.json - see README.md buf.setFontAlign(-1,1); //left, bottom if (BANGLEJS2) s *= fontFactorB2; buf.setFontVector(s); - buf.drawString(nm.substring(0,6),72,screenH_TwoThirds-(BANGLEJS2 * 20)); + buf.drawString(nm.substring(0,6),72,screenH_TwoThirds-(BANGLEJS2 * 15)); } if ( cfg.modeA == 2 ) { // clock/large mode @@ -421,7 +421,7 @@ function drawSats(sats) { buf.drawString('A',screenW,140-(BANGLEJS2 * 40)); if ( showMax ) { buf.setFontAlign(0,1); //centre, bottom - buf.drawString('MAX',120,164); + buf.drawString('MAX',screenW_Half,screenH_TwoThirds + 4); } } if ( cfg.modeA == 0 ) buf.drawString('D',screenW,140-(BANGLEJS2 * 40)); @@ -536,22 +536,18 @@ function onGPS(fix) { } -function setButtons(){ -if (!BANGLEJS2) { // Buttons for Bangle.js - // Spd+Dist : Select next waypoint - setWatch(function(e) { - var dur = e.time - e.lastTime; - if ( cfg.modeA == 1 ) { - // Spd+Alt mode - Switch between fix and MAX - if ( dur < 2 ) showMax = !showMax; // Short press toggle fix/max display - else { max.spd = 0; max.alt = 0; } // Long press resets max values. - } - else nxtWp(1); // Spd+Dist or Clock mode - Select next waypoint - onGPS(lf); - }, BTN1, { edge:"falling",repeat:true}); - // Power saving on/off - setWatch(function(e){ +function btn1press(longpress) { + if(emulator) console.log("Btn1, long="+longpress); + if ( cfg.modeA == 1 ) { // Spd+Alt mode - Switch between fix and MAX + if ( !longpress ) showMax = !showMax; // Short press toggle fix/max display + else { max.spd = 0; max.alt = 0; } // Long press resets max values. + } + else nxtWp(1); // Spd+Dist or Clock mode - Select next waypoint + onGPS(lf); + } +function btn2press(){ + if(emulator) console.log("Btn2"); pwrSav=!pwrSav; if ( pwrSav ) { LED1.reset(); @@ -564,52 +560,51 @@ if (!BANGLEJS2) { // Buttons for Bangle.js Bangle.setLCDPower(1); LED1.set(); } - }, BTN2, {repeat:true,edge:"falling"}); - - // Toggle between alt or dist - setWatch(function(e){ - cfg.modeA = cfg.modeA+1; - if ( cfg.modeA > 2 ) cfg.modeA = 0; - savSettings(); - onGPS(lf); - }, BTN3, {repeat:true,edge:"falling"}); - - // Touch left screen to toggle display - setWatch(function(e){ - cfg.primSpd = !cfg.primSpd; - savSettings(); - onGPS(lf); // Update display - }, BTN4, {repeat:true,edge:"falling"}); - -} else { // Buttons for Bangle.js 2 - setWatch(function(e){ // Bangle.js BTN3 + } +function btn3press(){ + if(emulator) console.log("Btn3"); cfg.modeA = cfg.modeA+1; if ( cfg.modeA > 2 ) cfg.modeA = 0; if(emulator)console.log("cfg.modeA="+cfg.modeA); savSettings(); onGPS(lf); - }, BTN1, {repeat:true,edge:"falling"}); - -/* Bangle.on('tap', function(data) { // data - {dir, double, x, y, z} + } +function btn4press(){ + if(emulator) console.log("Btn4"); cfg.primSpd = !cfg.primSpd; - if(emulator)console.log("!cfg.primSpd"); - }); */ + savSettings(); + onGPS(lf); // Update display + } -/* Bangle.on('swipe', function(dir) { - if (dir < 0) { // left: Bangle.js BTN3 - cfg.modeA = cfg.modeA+1; - if ( cfg.modeA > 2 ) cfg.modeA = 0; - if(emulator)console.log("cfg.modeA="+cfg.modeA); - } + +function setButtons(){ +if (!BANGLEJS2) { // Buttons for Bangle.js 1 + setWatch(function(e) { + btn1press(( e.time - e.lastTime) > 2); // > 2 sec. is long press + }, BTN1, { edge:"falling",repeat:true}); + + // Power saving on/off (red dot visible if off) + setWatch(btn2press, BTN2, {repeat:true,edge:"falling"}); + + // Toggle between alt or dist + setWatch(btn3press, BTN3, {repeat:true,edge:"falling"}); + + // Touch left screen to toggle display + setWatch(btn4press, BTN4, {repeat:true,edge:"falling"}); + +} else { // Buttons for Bangle.js 2 + setWatch(function(e) { + btn1press(( e.time - e.lastTime) > 0.4); // > 0.4 sec. is long press + }, BTN1, { edge:"falling",repeat:true}); + + Bangle.on('touch', function(btn_l_r, e) { + if(e.x < screenW_Half) btn4press(); else - { // right: Bangle.js BTN4 - cfg.primSpd = !cfg.primSpd; - if(emulator)console.log("!cfg.primSpd"); - } + if (e.y < screenH_Half) + btn2press(); + else + btn3press(); }); -*/ - savSettings(); - onGPS(lf); } } @@ -700,18 +695,6 @@ Bangle.on('lcdPower',function(on) { else stopDraw(); }); -/* -function onGPSraw(nmea) { - var nofGP = 0, nofBD = 0, nofGL = 0; - if (nmea.slice(3,6) == "GSV") { - // console.log(nmea.slice(1,3) + " " + nmea.slice(11,13)); - if (nmea.slice(0,7) == "$GPGSV,") nofGP = Number(nmea.slice(11,13)); - if (nmea.slice(0,7) == "$BDGSV,") nofBD = Number(nmea.slice(11,13)); - if (nmea.slice(0,7) == "$GLGSV,") nofGL = Number(nmea.slice(11,13)); - SATinView = nofGP + nofBD + nofGL; - } } -if(BANGLEJS2) Bangle.on('GPS-raw', onGPSraw); -*/ var gpssetup; try { From a5c024b4b49f6873e4012b2ae0071a9a17dd38da Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:33:07 +0100 Subject: [PATCH 420/447] Update README.md --- apps/speedalt/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/speedalt/README.md b/apps/speedalt/README.md index c21828aff..6f0d4efe5 100644 --- a/apps/speedalt/README.md +++ b/apps/speedalt/README.md @@ -2,23 +2,21 @@ You can switch between three display modes. One showing speed and altitude (A), one showing speed and distance to waypoint (D) and a large dispay of time and selected waypoint. -*Note for **Bangle.js 2:** Currently only the BTN3 functionality is working with the Bangle.js 2 button.* - Within the [A]ltitude and [D]istance displays modes one figure is displayed on the watch face using the largest possible characters depending on the number of digits. The other is in a smaller characters below that. Both are always visible. You can display the current or maximum observed speed/altitude values. Current time is always displayed. The waypoints list is the same as that used with the [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app so the same set of waypoints can be used across both apps. Refer to that app for waypoint file information. ## Buttons and Controls -BTN3 : Cycles the modes between Speed+[A]ltitude, Speed+[D]istance and large Time/Waypoint +*(Mapping for **Bangle.js 2**: BTN2 = Touch upper right side; BTN3 = Touch lower right side; BTN4 = Touch left side)* -***Bangle.js 2:** Currently only this button function is working* +BTN3 : Cycles the modes between Speed+[A]ltitude, Speed+[D]istance and large Time/Waypoint ### [A]ltitude mode BTN1 : Short press < 2 secs toggles the displays between showing the current speed/alt values or the maximum speed/alt values recorded. -BTN1 : Long press > 2 secs resets the recorded maximum values. +BTN1 : Long press > 2 secs resets the recorded maximum values. *(Bangle.js 2: Long press > 0.4 secs)* ### [D]istance mode @@ -32,7 +30,7 @@ BTN1 : Select next waypoint. BTN2 : Disables/Restores power saving timeout. Locks the screen on and GPS in SuperE mode to enable reading for longer periods but uses maximum battery drain. Red LED (dot) at top of screen when screen is locked on. Press again to restore power saving timeouts. -BTN3 : Long press exit and return to watch. +BTN3 : Long press exit and return to watch. *(Bangle.js 2: Long press BTN > 2 secs)* BTN4 : Left Display Tap : Swaps which figure is in the large display. You can have either speed or [A]ltitude/[D]istance on the large primary display. From 5d1d155ad8e16a8391647f967d835b9c3a8e5ea7 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:56:39 +0100 Subject: [PATCH 421/447] Update ChangeLog --- apps/vectorclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/vectorclock/ChangeLog b/apps/vectorclock/ChangeLog index abbfcbb99..02831edde 100644 --- a/apps/vectorclock/ChangeLog +++ b/apps/vectorclock/ChangeLog @@ -5,3 +5,4 @@ 0.05: "Chime the time" (buzz or beep) with up/down swipe added 0.06: Redraw widgets when time is updated 0.07: Fix problem with "Bangle.CLOCK": github.com/espruino/BangleApps/issues/1437 +0.08: Redraw widgets only once per minute From 6eb7e3f8af506ce137dec33aa13981b2aa5716a1 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:57:17 +0100 Subject: [PATCH 422/447] Update metadata.json --- apps/vectorclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vectorclock/metadata.json b/apps/vectorclock/metadata.json index 0f558e3ee..541766fa2 100644 --- a/apps/vectorclock/metadata.json +++ b/apps/vectorclock/metadata.json @@ -1,7 +1,7 @@ { "id": "vectorclock", "name": "Vector Clock", - "version": "0.07", + "version": "0.08", "description": "A digital clock that uses the built-in vector font.", "icon": "app.png", "type": "clock", From 16863635ec703b2f0856c424a678ac7e857035aa Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:58:37 +0100 Subject: [PATCH 423/447] Update app.js --- apps/vectorclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vectorclock/app.js b/apps/vectorclock/app.js index 8d2961c4a..18b4378b2 100644 --- a/apps/vectorclock/app.js +++ b/apps/vectorclock/app.js @@ -81,7 +81,7 @@ function draw() { executeCommands(); - Bangle.drawWidgets(); + if (!showSeconds) Bangle.drawWidgets(); } var timeout; From fc37036bff63a81104675e4338f96d7009812140 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sat, 12 Mar 2022 13:14:23 +0100 Subject: [PATCH 424/447] Update app.js --- apps/vectorclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vectorclock/app.js b/apps/vectorclock/app.js index 18b4378b2..663a4c84f 100644 --- a/apps/vectorclock/app.js +++ b/apps/vectorclock/app.js @@ -81,7 +81,7 @@ function draw() { executeCommands(); - if (!showSeconds) Bangle.drawWidgets(); + if (process.env.HWVERSION==2) Bangle.drawWidgets(); } var timeout; From 1349e75cb39688dee480f80016c3d73446184e8a Mon Sep 17 00:00:00 2001 From: Rarder44 Date: Sat, 12 Mar 2022 18:44:34 +0100 Subject: [PATCH 425/447] added charging icon --- apps/rebble/ChangeLog | 1 + apps/rebble/metadata.json | 2 +- apps/rebble/rebble.app.js | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/rebble/ChangeLog b/apps/rebble/ChangeLog index b9c26b4e3..b80dfef94 100644 --- a/apps/rebble/ChangeLog +++ b/apps/rebble/ChangeLog @@ -2,3 +2,4 @@ 0.02: Fix typo to Purple 0.03: Added dependancy on Pedometer Widget 0.04: Fixed icon and png to 48x48 pixels +0.05: added charging icon \ No newline at end of file diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json index 212a7b5b3..b26fb6a27 100644 --- a/apps/rebble/metadata.json +++ b/apps/rebble/metadata.json @@ -2,7 +2,7 @@ "id": "rebble", "name": "Rebble Clock", "shortName": "Rebble", - "version": "0.04", + "version": "0.05", "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", "readme": "README.md", "icon": "rebble.png", diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js index d186ea8ec..7c7d57939 100644 --- a/apps/rebble/rebble.app.js +++ b/apps/rebble/rebble.app.js @@ -204,6 +204,14 @@ function drawBattery(x,y,wi,hi) { g.setColor(g.theme.fg); g.fillRect(x+wi-3,y+2+(((hi - 1)/2)-1),x+wi-2,y+2+(((hi - 1)/2)-1)+4); // contact g.fillRect(x+3, y+5, x +4 + E.getBattery()*(wi-12)/100, y+hi-1); // the level + + if( Bangle.isCharging() ) + { + g.setBgColor(settings.bg); + image = ()=> { return require("heatshrink").decompress(atob("j8OwMB/4AD94DC44DCwP//n/gH//EOgE/+AdBh/gAYMH4EAvkDAYP/+/AFAX+FgfzGAnAA=="));} + g.drawImage(image(),x+3,y+4); + } + } function getSteps() { @@ -270,3 +278,14 @@ for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} loadSettings(); loadLocation(); draw(); // queues the next draw for a minutes time +Bangle.on('charging', function(charging) { + //redraw the sidebar ( with the battery ) + switch(sideBar) { + case 0: + drawSideBar1(); + break; + case 1: + drawSideBar2(); + break; + } +}); \ No newline at end of file From a438fe0a65962f688a3c1af104a2eff8e098c86b Mon Sep 17 00:00:00 2001 From: Francois Lancelot <16709438+francoislanc@users.noreply.github.com> Date: Sun, 13 Mar 2022 16:52:39 +0100 Subject: [PATCH 426/447] Create Todo List app --- apps/todolist/ChangeLog | 1 + apps/todolist/README.md | 40 +++++++++++ apps/todolist/app-icon.js | 1 + apps/todolist/app.js | 129 ++++++++++++++++++++++++++++++++++ apps/todolist/app.png | Bin 0 -> 1833 bytes apps/todolist/metadata.json | 23 ++++++ apps/todolist/screenshot1.png | Bin 0 -> 1671 bytes apps/todolist/screenshot2.png | Bin 0 -> 2510 bytes apps/todolist/screenshot3.png | Bin 0 -> 2286 bytes 9 files changed, 194 insertions(+) create mode 100644 apps/todolist/ChangeLog create mode 100644 apps/todolist/README.md create mode 100644 apps/todolist/app-icon.js create mode 100644 apps/todolist/app.js create mode 100644 apps/todolist/app.png create mode 100644 apps/todolist/metadata.json create mode 100644 apps/todolist/screenshot1.png create mode 100644 apps/todolist/screenshot2.png create mode 100644 apps/todolist/screenshot3.png diff --git a/apps/todolist/ChangeLog b/apps/todolist/ChangeLog new file mode 100644 index 000000000..2e979ec12 --- /dev/null +++ b/apps/todolist/ChangeLog @@ -0,0 +1 @@ +0.01: Initial release \ No newline at end of file diff --git a/apps/todolist/README.md b/apps/todolist/README.md new file mode 100644 index 000000000..27c7cfb63 --- /dev/null +++ b/apps/todolist/README.md @@ -0,0 +1,40 @@ +Todo List +======== + +This is a simple Todo List application. + +![](screenshot2.png) + +The content is loaded from a JSON file. +You can mark a task as completed. + +JSON file content example: +```javascript +[ + { + name: "Pro", + children: [ + { + name: "Read doc", + done: true, + children: [], + } + ], + }, + { + name: "Pers", + children: [ + { + name: "Grocery", + children: [ + { name: "Milk", done: false, children: [] }, + { name: "Eggs", done: false, children: [] }, + { name: "Cheese", done: false, children: [] }, + ], + }, + { name: "Workout", done: false, children: [] }, + { name: "Learn Rust", done: false, children: [] }, + ], + }, +] +``` \ No newline at end of file diff --git a/apps/todolist/app-icon.js b/apps/todolist/app-icon.js new file mode 100644 index 000000000..9d9019c70 --- /dev/null +++ b/apps/todolist/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("AEURiMQCycBC6gVDDKAPBAAYXDA4gWMiUhAgUiDBYmBiUiCAMjmQQBiczBQkRFw0T/4ABC4MzkUSmYXBl4KB+QXHBYQXDAAYLFJAsRn4LDIYIXIkIXGBQQLBRYojEmIXKmIWFiQLEC5X/IwkzFwYXNABQX/C6kxXIYXR+cRj4XTkUyaIPzbYcSVIQXJFoLRC+LZEGwQvKFQIPBDgQACF5gTBkLpEX/6/Z/6/VmfyX4UiAAa/kC4UT/4yBAAZmCX5bPDX/4MEmRIJX8sv+czAAa/PAoK/rmQPDI4h3OB4bX/aJIAFkIXGOQQALTgIXGiQwNmMRCwkAgK3EABQuFGAQAOCwwAU") \ No newline at end of file diff --git a/apps/todolist/app.js b/apps/todolist/app.js new file mode 100644 index 000000000..58cd3783c --- /dev/null +++ b/apps/todolist/app.js @@ -0,0 +1,129 @@ +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// Const +let TODOLIST_FILE = "todolist.json"; +let MAX_DESCRIPTION_LEN = 14; + +// Clear todolist file +// require("Storage").erase(TODOLIST_FILE); + +let DEFAULT_TODOLIST = [ + { + name: "Pro", + children: [ + { + name: "Read doc", + done: true, + children: [], + }, + ], + }, + { + name: "Pers", + children: [ + { + name: "Grocery", + children: [ + { name: "Milk", done: false, children: [] }, + { name: "Eggs", done: false, children: [] }, + { name: "Cheese", done: false, children: [] }, + ], + }, + { name: "Workout", done: false, children: [] }, + { name: "Learn Rust", done: false, children: [] }, + ], + }, +]; + +// Load todolist +let todolist = + require("Storage").readJSON(TODOLIST_FILE, true) || DEFAULT_TODOLIST; +let menus = {}; + +function writeData() { + require("Storage").writeJSON(TODOLIST_FILE, todolist); +} + +function getChild(todolist, indexes) { + let childData = todolist; + for (let i = 0; i < indexes.length; i++) { + childData = childData[indexes[i]]; + childData = childData.children; + } + + return childData; +} + +function getName(item) { + let title = item.name.substr(0, MAX_DESCRIPTION_LEN); + return title; +} +function getParentTitle(todolist, indexes) { + let parentIndexes = indexes.slice(0, indexes.length - 1); + let lastIndex = indexes[indexes.length - 1]; + let item = getItem(todolist, parentIndexes, lastIndex); + return getName(item); +} + +function getItem(todolist, parentIndexes, index) { + let childData = getChild(todolist, parentIndexes, index); + return childData[index]; +} + +function toggleableStatus(todolist, indexes, index) { + const reminder = getItem(todolist, indexes, index); + return { + value: !!reminder.done, // !! converts undefined to false + format: (val) => (val ? "[X]" : "[-]"), + onchange: (val) => { + reminder.done = val; + writeData(); + }, + }; +} + +function showSubMenu(key) { + const sub_menu = menus[key]; + return E.showMenu(sub_menu); +} + +function createListItem(todolist, indexes, index) { + let reminder = getItem(todolist, indexes, index); + if (reminder.children.length > 0) { + let childIndexes = []; + for (let i = 0; i < indexes.length; i++) { + childIndexes.push(indexes[i]); + } + childIndexes.push(index); + createMenus(todolist, childIndexes); + return () => showSubMenu(childIndexes); + } else { + return toggleableStatus(todolist, indexes, index); + } +} + +function showMainMenu() { + const mainmenu = menus[""]; + return E.showMenu(mainmenu); +} + +function createMenus(todolist, indexes) { + const menuItem = {}; + if (indexes.length == 0) { + menuItem[""] = { title: "todolist" }; + } else { + menuItem[""] = { title: getParentTitle(todolist, indexes) }; + menuItem["< Back"] = () => + showSubMenu(indexes.slice(0, indexes.length - 1)); + } + for (let i = 0; i < getChild(todolist, indexes).length; i++) { + const item = getItem(todolist, indexes, i); + const name = getName(item); + menuItem[name] = createListItem(todolist, indexes, i); + } + menus[indexes] = menuItem; +} + +createMenus(todolist, []); +showMainMenu(); diff --git a/apps/todolist/app.png b/apps/todolist/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a93fc14ad2bcf0a5d8f9686ba0203e985089c20e GIT binary patch literal 1833 zcmV+^2iEwBP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H12DV8= zK~!jg?V4*)l-C``e`oKk5)oMiq+ApeEg~(*O{ljf6LWEfQ6{Y^p{D7Sc818LmvjQn z*p5l3Hj`*=E_PxxF_Oemjb=>JO2!)PAlQ+{L~1}}xk;p4gar|I***P0K*44A<=vO~ zCC{gK&-?uU=Xv&A_nZ|>9Yknsdb)r)ZlV9A$6nDiC6!D?(pgcNbA?{M2PA)4d-t8V{bLuBOw+0;$}uf#A7mvn&Q(frQmSBnb0ZhBN_D-eNsEd2hG9 z>S$O@Mk(;H7m5=^tCvUzLevS5EbC~lI)IOE=hJ{KHgk=X@-1MdFCM`Bh4G}X$^ziS zvLjsS?80gda?Y7!b2K)#gh?q$&Prq9l0~?jE)JLe4dJ(smV$iZT<0C3{NW3;zjCN(vQrAw2>RkWEd^ zEsiHNpp)W7z#JMH!nSRjiI0!-$~%1cC=N&en6d>4cd_Yrzv9fls_5_OBWhkW$yrM= zna#JvCoWk;Uf#M}%B7T)mcGj?uj~a$s;w`$pacG_$UtaxY66e~P*n8TgyMa{7H(rr z?t_z#8-Wmlyu5W(SD&M*sv0RoK3)vyyanrZ`o#b`osP`R6rUBD%|-zFdL4?z4LMz0 z8yFalAJ-+vBRf0w%O|-QFJsng3rI;YfW=~F+BB=r3KA0+VYjzXQGSw&@{@kWk4Msy zMLyq$g^kY477`MS`fW|bN#>I~@hI-YpqCv5nB4tw7`KyB?sN=i0iG>lERVtEEDmS?CErW66K#NiRM zdGg7hX{ALKzFr4L(9qCKVc~BmSFxoI1e$E-Tth=_{_XQLTpT`pyXT(oXpvSCR2w+{ z@hOZ3Bg>Yh@cN#=j*8!~A!n4+*w{)%#lP`*d>_W?^*XY$(uj_ZoU{&A23lG!QBu4W zfO&DzG__m;;Qsqok(IS{l=sXt+c|%}UQy2DA6N31oqw3L7F7mpwlI>u^-a!x@?RS4 z&A{+azfDCy9>ZI?av2UsKhn=>s7@zXxkBA^tIB}IV&>(Seotj(HG6jN=R&=ml9I;> z4xToKmzTHB>ye3;2xt&zWF(W3k&N5zL9f3(GqNVN-Y)T=;X2UW-NTL@yE#`=t5r%x z(8Pe0k}X^Q#Qy#7vGe7k?@Gw969n4r%(R}fbZUY<6fix>Q!n# zzvy=z(CGvV7smTNMDqq!2HOAE$q)03@JJ7Pi1c(_e*&WMQFYNV)Z zff+M`dHb!GC_C^z@4S78-rhb63m+vSa?TiDaq;666+Nb?3#sWo5WpA+vRcT0WIYe% zKEUPnPGV!d-ZH5crW66sLY5%QgyO#ncr_q|bOX5EZlu4B%oM}pc8@$tYHXhI@4dHx zq#fY;bti3Y?NcUB3F;e0FZes*_$}u%UJbZJPzB%w*thTCl!^0)-rhbAA38exLGVv+ z9IrR^gFTIdK{KOl0@Ca18tCf0!uMqdeG1ClzPSGf X`~f40OX#!|00000NkvXXu0mjf51oTh literal 0 HcmV?d00001 diff --git a/apps/todolist/metadata.json b/apps/todolist/metadata.json new file mode 100644 index 000000000..0833a86bd --- /dev/null +++ b/apps/todolist/metadata.json @@ -0,0 +1,23 @@ +{ + "id": "todolist", + "name": "TodoList", + "shortName": "TodoList", + "version": "0.01", + "type": "app", + "description": "Simple Todo List", + "icon": "app.png", + "allow_emulator": true, + "tags": "tool,todo", + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + { "name": "todolist.app.js", "url": "app.js" }, + { "name": "todolist.img", "url": "app-icon.js", "evaluate": true } + ], + "data": [{ "name": "todolist.json" }], + "screenshots": [ + { "url": "screenshot1.png" }, + { "url": "screenshot2.png" }, + { "url": "screenshot3.png" } + ] +} diff --git a/apps/todolist/screenshot1.png b/apps/todolist/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..523d60307e3e9805676205a6a9d34688ce7a3e4b GIT binary patch literal 1671 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(Y4M?uv{v-}aF%}28J29*~C-ahlfz8p=#WAEJ z?(N*SMYA0QSQdY;&seJC9y)`ex;p7P&*h(z2k&0EY$yNg)8n5tcK<){Gc96~#{EUmvyJD=WHdUd`y%e;(d!G?Y3{+GOY`gD%v zHI`-5f(0s=J}*yF_`vdIE|A@ny7Yi>VVVC=ljk!dR~?%qUa@z5OmozGvE{c9XXlj%$?6`yvF1SF%*{b*$6OzLp6m9Y-be69 z%}y&fmjuSf>A&wxls+|a>OSXneU<_dE)SF?HSecSuQcH4}bjPH_tTfAHP<;`|_71x7Y9@Ka)JC z&8Dp<>auzNIw&|Rh*(4w_J>{c`0(Q6nbv|e>WyD6XPnk`-oo0!(ku6UP0Q+Y0vzEF zz9vY%T$H@{xUu-5jq_LpZfyR3JI0jh{xYxg+>Qz7@8uU?<*1phWvjm=x+HV2_Y_6zlP`0uTNkFur2(+=xZshf%0NN*e>y`GCiBP763ZI340R zL6WK8-iFuUaBs1m6GNkZ5R2h6jvDSiKYm5)v;Uv>M|Otgo;jhu50)Q@UbOG2+oM-{ z67@|EIv>7k3*L8D{>YN#w^F6yz|<1S-E$7?IZ*xk*;B2(aXS|m-{_t$Ubmg|8Oy!f zL2o#JtCnuz{rTnNZqvhGc?3IH?IsmvcRl_1TJ&oMzbvOsiKWaFH--NuQ7X6Q9k|Gw zV6raSIOe@TV+Cs*zi{U^)dCg$^Cdh}k2?Mro*{0r$a2&ByT2dakgk5hu6XL`7tETFVdQ&MBb@0G(G0>Hq)$ literal 0 HcmV?d00001 diff --git a/apps/todolist/screenshot2.png b/apps/todolist/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..0337f9000378268ccf6e771ce0c46a7c5b1875f4 GIT binary patch literal 2510 zcmeHJS5%V=5)QwC1QbXVrC%U`s31taQY3&C3amhaVCX0vqM}HZ7A`F)Vhe-- zDU=9A_acY^L?H-Las@+|q7)-#vk&{WPy4)c&dhgaUcPhYoNvCl?}V}y7n2hMfk5K+ zb{AX(*zoU!iU=yDdB#@&LeVa^R-pQRg?SK2G{gRa<>ffv<;uSkrcWIbZeH1c-|p8o za-{^YeQl9jIGXDHj|a8^*^1piw|4~bPb74_hy?+rXi+u0)*!qR%-p=qB%)yboEL0c zE#lJ9`7pK3A{l%-%kSBXeQdDWW}yuJz%4{WRg0|+)a*n==tL6n$;Gu{qq?r|5HUa! zI$oCV{o1?+P2C=j>-a%w6b3YOzUWmK>xYDklljTw6TB6{DE#rs!TvQWYXNZDFzx(7 z8B_%z1lX*L=3oe*8Q=O*H|31V>O+=TeBgxl<}2%pYQAYM>o%}LbQ@+@>FkDH$FrbG zp@nc6Jbar2E&yr|*1JhZYN;#`bPq^ElL#$$H$0TEPo@#t$fJk|qO7+J+`|9y)dvnl z5HMTXm=4ExyTi9p70#A+>b7aJXS=gF7%=QpopMc~Y8uPfmu4gYjIc_jf)KcWt(qPmJiXAdBsUvEypAlf zaOGyhNaW0cPfrvB*gb{jyu;7MDvB-X?rXA4T0pjJ{D*EIpcDKX+!E*dCNY#ZDM>D3 zPA1CpTgkoQ+Aay7?YZ|@kJE{Ck@}5~3(Q!jA_!~Fd|3+!$T_loY}?@xb~3%^Wtly_ zy~%OfZZt{*uY;!?OW+*Z`4p)hbPyF|Gbviq$T{+-$${p{($C&Up=Zp}Hbji_So z6oUyA{5wzj<~~Q*oyT_44nXKU^c5v^Y{5RINL$$(n-u1THAD0t*C85q%~vJx!&;qU z$9KPJH0&0(lmfM$?m2X&-&OmMuNGld^lqMRku+n@P==>I5^dg%n}*T97PgEOL-TY6B&qF2!(!pAl-&E3AiD&hD5dcznFK&l-@#~aE z=K*R4a>7?_)scIC(uKpB(ve{EV1HV2DJ%z-@p;K}6OVeJjcvzqOe~ika1avvlBm&ZVS-_{4)|=X(eB-w@W%WFXR5&^m?2+$meG+hPQmaqO~s zN$N4HD;68ypeH;r;}C6~bXZm&0_`mYp5ZTo=sI%juG-ge;JJ|A8+ z7aq8DVlG#=`fEh5dKuM~Ip=Mi>UV2MBNvkj_0cf}{7e<}DDThN$c>2zBwI#`Pf?|Q zFOZF!X>V`GHQ91|w%c9Nyvi=k%sq!>lD>!R0Ars>x5aYjoNH1fl@4QT*fg?e9qObQ3X=r(jdltOkush(T)eEU;?<>8Y_$y4UzNiXCu&KFF|E%D za!3M>p(@nethRjXbPWP?+w!0WEq++ZK)mr1^f&sgH7zzAKw|0etqy4d;Z$9bEoz%!PUHRETVo_!8nmZ5; zJ$NS)(cbFWnFIZaTXEFyI={->kx(BPI?XMK0b+KSSMD!^b5pWEdxvhCM}6Bs2JDjV z7m-yiBYG-f)C z6{C!i;*4uao1<|vX^NhkCwQpHF0Jy#82s?Hl&>$`UpcRNg_Rnv9sN16xB4M@`xE>_O*7w7a`wZQ$szbK~x2so_Lu;}5b-#k09d>L2&6*P4VTgD2x<|H9? z&JcUUgYLGrWF9zH+gOV4mZ*8aA}#hvn5f00F%8)D<_Py$P`&S)_d0yDHF-<|}Zbx?To@iZ3atBSGU w1vskmg(J{^o0-}(fz2T<{GaT9SR)td07g`e?B&e~9yE}>HR?jWmH(}O0Ylf7a{vGU literal 0 HcmV?d00001 diff --git a/apps/todolist/screenshot3.png b/apps/todolist/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..e5a4a85acd3d4298f930359725df1de07f21175a GIT binary patch literal 2286 zcmeHJ`BT$*68+@Ma2O696jm{Eh&qHIDu>(<7$phO2mv7k0&zSz0)leHEQBEn!w6!; zXjnkdaI@wDIcC8?R2CUAtbl||E-#22i6DoA$}&H1ZPoq(`$PAu_o}<9tLs%)U-czm zbm2yD0DvwIdxW@w;y*)6VW;D0syUQ+!4=!OJQ@xlg(w8I!CLN z>n|jCi)-_rz-~qc=*zzp{g`n^xp#Nt@={vc_|L0Zkf*^VSiJ8PcC8F;nI0|*>I<~C zVMLu!Q|ZO&(v(WZe#-s2Z2*76XO0$Ja-R&k-%VZYw}QnhqTP1V z)<@)Tl;JQJsPN@fgmPg#Is8Cl(oZo@am+_li!Yu8k1T>8k?X9l_z?-6iu zM(5<4x|2XvC!exFq$jNY7GnS&@|T?8niB|j>kxHtfX2N380MJ8?h1rSyU2IT;z9TS z-eLyvKbs~hQ>ZO}r>AP-Ia77kKUk+~i4C*;?liI=7>(O^54k#x1+lE9hNk7Dn$fay zmkw1Y$34{`5{k+6%+4Qn^JzYpeYHfdV@#C;RRaa$MFuw$-8d%NF+w#x5P6VZ)s_RO{XPB}@j>UcOWioWnFt!9zm z6J{IFu(`u@m>()c@B0N3+KS)b{@h|!7(4>;>~=mCU$GLvLt8b35&iP@u5$Ke(%mg| zSJ&F?;}6@QCZ!kl!H3{<0e#J<{9YSY1lyDmrB$*eQ#PxF|I&bA+!=ux+uTB^}ahm7H*ZGf6X zZYNX$a3W&Urr`fVrJ575MYzQwmh<^fpGPIcxxj(MXE$CT)yX5}g-^c-vi#5Pwyz3L zZ@Tw=yEzFnUJ54s5gBf)(^vM+T<`$%o}nej$)*BnR#J9*5u8-gIKKA9Rte`GUsli>F0!Pc|B|C&m&`B*Jeyyh_jy9>oJo|`$CtWXI4}i*HOu&7?v5l6*oUQSOZ={g z8E1niFn^(!h?8i{<7RcmjnX8mf1Rx97#G`$lQ8D_4YUArSd7HTR!#IsW_PkubFl7P zL5G39A4)aouAqdmV$1sJ?03ftDv!6s z&6e&db}dEcTk{>8ue8`%Dx$Pc88 zdTxis5vhMouSiN@C|-0#zd653bKb>uf zm{m9GdzT5vj)i0e!d}hPHz1}*DUi6o@XklK^op~uh2FA!I90~YN<0UPCzuLO;_f&u zMT~oM^j+Zbaf>Zh0ST9bGtIsksqZ21%LpE7cy)&M?p(~8llsH2&_qI7e7zqG2)|o2 zY@gPg^xhCJ7O}b-qLqXTIYT3M^skMjFLB!SKr$#mfSQsej)FIZQCbY$8y&KwxXI}q$bep4wDpKIwTzmg$ zgYc^1p-h`4xJqzF5_p7Az2WIdI8tG-3R6u>&ZXq{ri3s3xV0ddHP+H&Wl#HK72-2d zrXa+Mw3@ zOTwDhn+EMXX3i+`NfHR~2R;P7?cq$f-$0O&@hIuLLSpk8NB_a>ka4cWMicwV553Uo z{7kh^7?ve3&iBP%Z5YNl5G7kHPf}6rk}a6E1~@)7gvFgIOySAv>b{H|2ycqDJBDUe zZ`gXdx;t+L0|OcvFW?|Pat&*oe#*2S0*GPvo0`<^S^@yF8rg4Q+cmsUK+2mlXMkT= g|1bT|4XkfIp&ff88rdGY@xTDwQNj_S7xnVL0pPJ6_5c6? literal 0 HcmV?d00001 From ab9013956cddc314fa2b4c68890c574bb42d0ebd Mon Sep 17 00:00:00 2001 From: Francois Lancelot <16709438+francoislanc@users.noreply.github.com> Date: Sun, 13 Mar 2022 17:09:02 +0100 Subject: [PATCH 427/447] Update todolist app icon --- apps/todolist/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/todolist/app-icon.js b/apps/todolist/app-icon.js index 9d9019c70..229852134 100644 --- a/apps/todolist/app-icon.js +++ b/apps/todolist/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("AEURiMQCycBC6gVDDKAPBAAYXDA4gWMiUhAgUiDBYmBiUiCAMjmQQBiczBQkRFw0T/4ABC4MzkUSmYXBl4KB+QXHBYQXDAAYLFJAsRn4LDIYIXIkIXGBQQLBRYojEmIXKmIWFiQLEC5X/IwkzFwYXNABQX/C6kxXIYXR+cRj4XTkUyaIPzbYcSVIQXJFoLRC+LZEGwQvKFQIPBDgQACF5gTBkLpEX/6/Z/6/VmfyX4UiAAa/kC4UT/4yBAAZmCX5bPDX/4MEmRIJX8sv+czAAa/PAoK/rmQPDI4h3OB4bX/aJIAFkIXGOQQALTgIXGiQwNmMRCwkAgK3EABQuFGAQAOCwwAU") \ No newline at end of file +require("heatshrink").decompress(atob("mEwwgmjiMRiAWTgIXUCoYZQB4IADC4YHECxkSkIECkQYLEwMSkQQBkcyCAMTmYKEiIuGif/AAIXBmciiUzC4MvBQPyC44LCC4YADBYpIFiM/BYZDBC5EhC4wKCBYKLFEYkxC5UxCwsSBYgXK/5GEmYuDC5oAKC/4XUmK5DC6PziMfC6cimTRB+bbDiSpCC5ItBaIXxbIg2CF5QqBB4IcCAAQvMCYMhdIi//X7P/X6sz+S/CkQADX8gXCif/GQIADMwS/LZ4a//BgkyJBK/ll/zmYADX54FBX9cyB4ZHEO5wPDa/7RJAAshC4xyCABacBC40SGBsxiIWEgEBW4gAKFwowCABwWGACgA==")) \ No newline at end of file From 9f8ec28c20390c9de726d2ae25b9ec85d37061fe Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Sun, 13 Mar 2022 20:30:10 +0100 Subject: [PATCH 428/447] Update README.md --- apps/info/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/info/README.md b/apps/info/README.md index 007a9794e..32920cb75 100644 --- a/apps/info/README.md +++ b/apps/info/README.md @@ -7,7 +7,7 @@ screen. Very useful if combined with pattern launcher ;) ![](screenshot_1.png) ![](screenshot_2.png) -![](screenshot_2.png) +![](screenshot_3.png) ## Contributors From aa53046f594a84ee9663829c3c3419aa51dbe055 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 13 Mar 2022 20:54:06 +0100 Subject: [PATCH 429/447] powermanager - Allow forcing monotonic battery voltage/percentage --- apps/powermanager/ChangeLog | 1 + apps/powermanager/README.md | 6 +++++- apps/powermanager/boot.js | 22 ++++++++++++++++++++++ apps/powermanager/default.json | 4 +++- apps/powermanager/metadata.json | 2 +- apps/powermanager/settings.js | 14 ++++++++++++++ 6 files changed, 46 insertions(+), 3 deletions(-) diff --git a/apps/powermanager/ChangeLog b/apps/powermanager/ChangeLog index 5560f00bc..8ccf678de 100644 --- a/apps/powermanager/ChangeLog +++ b/apps/powermanager/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Allow forcing monotonic battery voltage/percentage diff --git a/apps/powermanager/README.md b/apps/powermanager/README.md index f2cfcdf3e..434ec814e 100644 --- a/apps/powermanager/README.md +++ b/apps/powermanager/README.md @@ -1,6 +1,10 @@ # Power manager -Manages settings for charging. You can set a warning threshold to be able to disconnect the charger at a given percentage. Also allows to set the battery calibration offset. +Manages settings for charging. +Features: +* Warning threshold to be able to disconnect the charger at a given percentage +* Set the battery calibration offset. +* Force monotonic battery percentage or voltage ## Internals diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js index ff4ba8932..1f6ec332a 100644 --- a/apps/powermanager/boot.js +++ b/apps/powermanager/boot.js @@ -26,4 +26,26 @@ Bangle.on("charging",handleCharging); handleCharging(Bangle.isCharging()); } + + if (settings.forceMonoPercentage){ + var p = (E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery())/4; + var op = E.getBattery; + E.getBattery = function() { + var current = (op()+op()+op()+op())/4; + if (Bangle.isCharging() && current > p) p = current; + if (!Bangle.isCharging() && current < p) p = current; + return p; + }; + } + + if (settings.forceMonoVoltage){ + var v = (NRF.getBattery()+NRF.getBattery()+NRF.getBattery()+NRF.getBattery())/4; + var ov = NRF.getBattery; + NRF.getBattery = function() { + var current = (ov()+ov()+ov()+ov())/4; + if (Bangle.isCharging() && current > v) v = current; + if (!Bangle.isCharging() && current < v) v = current; + return v; + }; + } })(); diff --git a/apps/powermanager/default.json b/apps/powermanager/default.json index a6d8412b2..6c929dc38 100644 --- a/apps/powermanager/default.json +++ b/apps/powermanager/default.json @@ -1,4 +1,6 @@ { "warnEnabled": false, - "warn": 96 + "warn": 96, + "forceMonoVoltage": false, + "forceMonoPercentage": false } diff --git a/apps/powermanager/metadata.json b/apps/powermanager/metadata.json index 3ad31ba1e..2bb531099 100644 --- a/apps/powermanager/metadata.json +++ b/apps/powermanager/metadata.json @@ -2,7 +2,7 @@ "id": "powermanager", "name": "Power Manager", "shortName": "Power Manager", - "version": "0.01", + "version": "0.02", "description": "Allow configuration of warnings and thresholds for battery charging and display.", "icon": "app.png", "type": "bootloader", diff --git a/apps/powermanager/settings.js b/apps/powermanager/settings.js index c8aa057fa..8af873e5f 100644 --- a/apps/powermanager/settings.js +++ b/apps/powermanager/settings.js @@ -24,6 +24,20 @@ 'title': 'Power Manager' }, '< Back': back, + 'Monotonic percentage': { + value: !!settings.forceMonoPercentage, + format: v => settings.forceMonoPercentage ? "On" : "Off", + onchange: v => { + writeSettings("forceMonoPercentage", v); + } + }, + 'Monotonic voltage': { + value: !!settings.forceMonoVoltage, + format: v => settings.forceMonoVoltage ? "On" : "Off", + onchange: v => { + writeSettings("forceMonoVoltage", v); + } + }, 'Charge warning': function() { E.showMenu(submenu_chargewarn); }, From 45cbb6a006d70c0bfdfb3ff4bb3b6aac2fae429a Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sun, 13 Mar 2022 22:20:32 +0100 Subject: [PATCH 430/447] boot: fix alphabetic sorting of *.boot.js files No version bump: assuming that where it really matters we already set a priority, which worked fine. --- apps/boot/bootupdate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 63424bfbf..7a69bbaeb 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -196,7 +196,7 @@ if (!Bangle.appRect) { // added in 2v11 - polyfill for older firmwares // Append *.boot.js files // These could change bleServices/bleServiceOptions if needed var getPriority = /.*\.(\d+)\.boot\.js$/; -require('Storage').list(/\.boot\.js/).sort((a,b)=>{ +require('Storage').list(/\.boot\.js$/).sort((a,b)=>{ var aPriority = a.match(getPriority); var bPriority = b.match(getPriority); if (aPriority && bPriority){ @@ -206,7 +206,7 @@ require('Storage').list(/\.boot\.js/).sort((a,b)=>{ } else if (!aPriority && bPriority){ return 1; } - return a > b; + return a==b ? 0 : (a>b ? 1 : -1); }).forEach(bootFile=>{ // we add a semicolon so if the file is wrapped in (function(){ ... }() // with no semicolon we don't end up with (function(){ ... }()(function(){ ... }() From 82c80fb39c40b445222a358ac85d77dd57ca9269 Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 08:35:26 +0100 Subject: [PATCH 431/447] Add files via upload --- apps/clockcal/screenshot3.png | Bin 0 -> 5870 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/clockcal/screenshot3.png diff --git a/apps/clockcal/screenshot3.png b/apps/clockcal/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..ab34f43068b7eff781948a549d173fd72e73e122 GIT binary patch literal 5870 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 t&S zybYetV~-wy$Z<;TdSrL63f$e!+fE!BM6{jM&5`6_b#~SdPbMv&A$HNsifUz6MoF0W z1Msd!wS>48;PxBZRiVEvc-W~EZI8CoWPs;y z3yf@6xf6zhX=NYl4UD$E>Ti(FEY167SFw@VpqKzVogq7~7kG5H41pfew!{1-0A2@~ zXm4p%7T`PKJxPcW8fDs?5f~YPu2+giIyP<32p|!d03%VFZ5|te3GidPW;%vMU;>Op zX|{Q61SY_b?V9Nr5`hUY5~bPZu@RU6KelV8V@L%413pc(4_0-?OaK4?07*qoM6N<$ Ef=_ZI`v3p{ literal 0 HcmV?d00001 From 89351bd6957b61cdd65d53609c380861059e1aac Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 08:41:01 +0100 Subject: [PATCH 432/447] Update README.md --- apps/clockcal/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index c19ee54a6..8fe0485f8 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -7,7 +7,9 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu - ![locked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot.png) - unlocked screen (twist?) with seconds - ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot2.png) - +- swipe up for big calendar (up down to scroll, left/right to exit) +- ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot3.png) +- ## Configurable Features - Number of calendar rows (weeks) - Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is included) @@ -15,6 +17,14 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu - First day of the week - Red Saturday - Red Sunday +- Swipes (to disable all gestures) +- Swipes: music (swipe down) +- Spipes: messages (swipe right) + +## Auto detects your message/music apps: +- swiping down will search your files for an app with the string "music" in its filename and launch it +- swiping right will search your files for an app with the string "message" in its filename and launch it. +- Configurable apps coming soon. ## Feedback The clock works for me in a 24h/MondayFirst/WeekendFree environment but is not well-tested with other settings. From 0992edfbb428cebbbe21f0a3decdc3eb2f3dbd25 Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 08:41:57 +0100 Subject: [PATCH 433/447] Update README.md --- apps/clockcal/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index 8fe0485f8..eeb23c35e 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -8,7 +8,7 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu - unlocked screen (twist?) with seconds - ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot2.png) - swipe up for big calendar (up down to scroll, left/right to exit) -- ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot3.png) +- ![big calendar](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot3.png) - ## Configurable Features - Number of calendar rows (weeks) From 511ddd56bd46d0fbf5eaff7b853f3f3e1cfbe155 Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 08:58:53 +0100 Subject: [PATCH 434/447] Update README.md --- apps/clockcal/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index eeb23c35e..da6887177 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -3,13 +3,15 @@ This is my "Hello World". I first made this watchface almost 10 years ago for my original Pebble and Pebble Time and I missed this so much, that I had to write it for the BangleJS2. I know that it seems redundant because there already **is** a *time&cal*-app, but it didn't fit my style. -- locked screen with only one minimal update/minute -- ![locked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot.png) -- unlocked screen (twist?) with seconds -- ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot2.png) -- swipe up for big calendar (up down to scroll, left/right to exit) -- ![big calendar](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot3.png) -- +|Screenshot|description| +|:--:|:-| +|![locked screen](screenshot.png)|locked: triggers only one minimal update/min| +|![unlocked screen](screenshot2.png)|unlocked: smaller clock, but with seconds| +|![big calendar](screenshot3.png)|swipe up for big calendar, (up down to scroll, left/right to exit)| + + + + ## Configurable Features - Number of calendar rows (weeks) - Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is included) From 98968d9a92ff522fa2f473b79684d744b082cbb4 Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 09:01:42 +0100 Subject: [PATCH 435/447] Update app.js --- apps/clockcal/app.js | 185 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 6 deletions(-) diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js index fc299912f..86fa0815a 100644 --- a/apps/clockcal/app.js +++ b/apps/clockcal/app.js @@ -7,15 +7,116 @@ var s = Object.assign({ FIRSTDAYOFFSET: 6, //First day of the week: 0-6: Sun, Sat, Fri, Thu, Wed, Tue, Mon REDSUN: true, // Use red color for sunday? REDSAT: true, // Use red color for saturday? + DRAGENABLED: true, + DRAGMUSIC: true, + DRAGMESSAGES: true }, require('Storage').readJSON("clockcal.json", true) || {}); const h = g.getHeight(); const w = g.getWidth(); const CELL_W = w / 7; +const CELL2_W = w / 8;//full calendar const CELL_H = 15; const CAL_Y = h - s.CAL_ROWS * CELL_H; const DEBUG = false; +var state = "watch"; +var monthOffset = 0; +/* + * Calendar features + */ +function drawFullCalendar(monthOffset) { + addMonths = function (_d, _am) { + var ay = 0, m = _d.getMonth(), y = _d.getFullYear(); + while ((m + _am) > 11) { ay++; _am -= 12; } + while ((m + _am) < 0) { ay--; _am += 12; } + n = new Date(_d.getTime()); + n.setMonth(m + _am); + n.setFullYear(y + ay); + return n; + }; + monthOffset = (typeof monthOffset == "undefined") ? 0 : monthOffset; + state = "calendar"; + var start = Date().getTime(); + const months = ['Jan.', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec.']; + const monthclr = ['#0f0', '#f0f', '#00f', '#ff0', '#0ff', '#fff']; + if (typeof dayInterval !== "undefined") clearTimeout(dayInterval); + if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); + if (typeof minuteInterval !== "undefined") clearTimeout(minuteInterval); + d = addMonths(Date(), monthOffset); + tdy = Date().getDate() + "." + Date().getMonth(); + newmonth=false; + c_y = 0; + g.reset(); + g.setBgColor(0); + g.clear(); + var prevmonth = addMonths(d, -1) + const today = prevmonth.getDate(); + var rD = new Date(prevmonth.getTime()); + rD.setDate(rD.getDate() - (today - 1)); + const dow = (s.FIRSTDAYOFFSET + rD.getDay()) % 7; + rD.setDate(rD.getDate() - dow); + var rDate = rD.getDate(); + bottomrightY = c_y - 3; + clrsun=s.REDSUN?'#f00':'#fff'; + clrsat=s.REDSUN?'#f00':'#fff'; + var fg=[clrsun,'#fff','#fff','#fff','#fff','#fff',clrsat]; + for (var y = 1; y <= 11; y++) { + bottomrightY += CELL_H; + bottomrightX = -2; + for (var x = 1; x <= 7; x++) { + bottomrightX += CELL2_W; + rMonth = rD.getMonth(); + rDate = rD.getDate(); + if (tdy == rDate + "." + rMonth) { + caldrawToday(rDate); + } else if (rDate == 1) { + caldrawFirst(rDate); + } else { + caldrawNormal(rDate,fg[rD.getDay()]); + } + if (newmonth && x == 7) { + caldrawMonth(rDate,monthclr[rMonth % 6],months[rMonth],rD); + } + rD.setDate(rDate + 1); + } + } + delete addMonths; + if (DEBUG) console.log("Calendar performance (ms):" + (Date().getTime() - start)); +} +function caldrawMonth(rDate,c,m,rD) { + g.setColor(c); + g.setFont("Vector", 18); + g.setFontAlign(-1, 1, 1); + drawyear = ((rMonth % 11) == 0) ? String(rD.getFullYear()).substr(-2) : ""; + g.drawString(m + drawyear, bottomrightX, bottomrightY - CELL_H, 1); + newmonth = false; +} +function caldrawToday(rDate) { + g.setFont("Vector", 16); + g.setFontAlign(1, 1); + g.setColor('#0f0'); + g.fillRect(bottomrightX - CELL2_W + 1, bottomrightY - CELL_H - 1, bottomrightX, bottomrightY - 2); + g.setColor('#000'); + g.drawString(rDate, bottomrightX, bottomrightY); +} +function caldrawFirst(rDate) { + g.flip(); + g.setFont("Vector", 16); + g.setFontAlign(1, 1); + bottomrightY += 3; + newmonth = true; + g.setColor('#0ff'); + g.fillRect(bottomrightX - CELL2_W + 1, bottomrightY - CELL_H - 1, bottomrightX, bottomrightY - 2); + g.setColor('#000'); + g.drawString(rDate, bottomrightX, bottomrightY); +} +function caldrawNormal(rDate,c) { + g.setFont("Vector", 16); + g.setFontAlign(1, 1); + g.setColor(c); + g.drawString(rDate, bottomrightX, bottomrightY);//100 +} function drawMinutes() { if (DEBUG) console.log("|-->minutes"); var d = new Date(); @@ -52,8 +153,10 @@ function drawSeconds() { if (!dimSeconds) secondInterval = setTimeout(drawSeconds, 1000); } -function drawCalendar() { +function drawWatch() { if (DEBUG) console.log("CALENDAR"); + monthOffset = 0; + state = "watch"; var d = new Date(); g.reset(); g.setBgColor(0); @@ -91,7 +194,7 @@ function drawCalendar() { var nextday = (3600 * 24) - (d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds() + 1); if (DEBUG) console.log("Next Day:" + (nextday / 3600)); if (typeof dayInterval !== "undefined") clearTimeout(dayInterval); - dayInterval = setTimeout(drawCalendar, nextday * 1000); + dayInterval = setTimeout(drawWatch, nextday * 1000); } function BTevent() { @@ -103,17 +206,87 @@ function BTevent() { } } +function input(dir) { + if (s.DRAGENABLED) { + Bangle.buzz(100,1); + console.log("swipe:"+dir); + switch (dir) { + case "r": + if (state == "calendar") { + drawWatch(); + } else { + if (s.DRAGMUSIC) { + l=require("Storage").list(RegExp("music.*app")); + if (l.length > 0) { + load(l[0]); + } else Bangle.buzz(3000,1);//not found + } + } + break; + case "l": + if (state == "calendar") { + drawWatch(); + } + break; + case "d": + if (state == "calendar") { + monthOffset--; + drawFullCalendar(monthOffset); + } else { + if (s.DRAGMESSAGES) { + l=require("Storage").list(RegExp("message.*app")); + if (l.length > 0) { + load(l[0]); + } else Bangle.buzz(3000,1);//not found + } + } + break; + case "u": + if (state == "watch") { + state = "calendar"; + drawFullCalendar(0); + } else if (state == "calendar") { + monthOffset++; + drawFullCalendar(monthOffset); + } + break; + default: + if (state == "calendar") { + drawWatch(); + } + break; + } + } +} + +let drag; +Bangle.on("drag", e => { + if (s.DRAGENABLED) { + if (!drag) { + drag = { x: e.x, y: e.y }; + } else if (!e.b) { + const dx = e.x - drag.x, dy = e.y - drag.y; + var dir = "t"; + if (Math.abs(dx) > Math.abs(dy) + 10) { + dir = (dx > 0) ? "r" : "l"; + } else if (Math.abs(dy) > Math.abs(dx) + 10) { + dir = (dy > 0) ? "d" : "u"; + } + drag = null; + input(dir); + } + } +}); + //register events Bangle.on('lock', locked => { if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); dimSeconds = locked; //dim seconds if lock=on - drawCalendar(); + drawWatch(); }); NRF.on('connect', BTevent); NRF.on('disconnect', BTevent); - dimSeconds = Bangle.isLocked(); -drawCalendar(); - +drawWatch(); Bangle.setUI("clock"); From 0146efb99f4147cb72132a1b1c17ce81c2ae858b Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 09:03:37 +0100 Subject: [PATCH 436/447] Added Drag-to-launch-stuff options --- apps/clockcal/settings.js | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index cc2a78181..c4ec764c9 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -8,6 +8,9 @@ FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su REDSUN: true, // Use red color for sunday? REDSAT: true, // Use red color for saturday? + DRAGENABLED: true, //Enable drag gestures (bigger calendar etc) + DRAGMUSIC: true, //Enable drag down for music (looks for "music*app") + DRAGMESSAGES: true //Enable drag right for messages (looks for "message*app") }, require('Storage').readJSON(FILE, true) || {}); @@ -67,6 +70,30 @@ writeSettings(); } }, + 'Swipes (big cal.)?': { + value: settings.DRAGENABLED, + format: v => v ? "On" : "Off", + onchange: v => { + settings.DRAGENABLED = v; + writeSettings(); + } + }, + 'Swipes (music)?': { + value: settings.DRAGMUSIC, + format: v => v ? "On" : "Off", + onchange: v => { + settings.DRAGMUSIC = v; + writeSettings(); + } + }, + 'Swipes (messg)?': { + value: settings.DRAGMESSAGES, + format: v => v ? "On" : "Off", + onchange: v => { + settings.DRAGMESSAGES = v; + writeSettings(); + } + }, 'Load deafauls?': { value: 0, min: 0, max: 1, @@ -80,13 +107,16 @@ FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su REDSUN: true, // Use red color for sunday? REDSAT: true, // Use red color for saturday? + DRAGENABLED: true, + DRAGMUSIC: true, + DRAGMESSAGES: true }; writeSettings(); - load() + load(); } } }, - } + }; // Show the menu E.showMenu(menu); -}) +}); From f573985bdc2646a9be45a49ee0a83b1b592a9b8d Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 09:05:50 +0100 Subject: [PATCH 437/447] Update metadata.json --- apps/clockcal/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index ccc84a980..a42e1ad2e 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,7 +1,7 @@ { "id": "clockcal", "name": "Clock & Calendar", - "version": "0.01", + "version": "0.2", "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", From cde9f59ba3d77b897e96408a9ca7abfbbc55ead5 Mon Sep 17 00:00:00 2001 From: Micha <97034053+foostuff@users.noreply.github.com> Date: Mon, 14 Mar 2022 09:06:48 +0100 Subject: [PATCH 438/447] Update ChangeLog --- apps/clockcal/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index e874c8c67..299b1ec69 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -1 +1,2 @@ 0.01: Initial upload +0.2: Added scrollable calendar and swipe gestures From fe0e19148e9b27e7016d9f85505e758ff5d26a81 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 14 Mar 2022 09:29:35 +0000 Subject: [PATCH 439/447] 0.09: Fix broken start/stop if recording not enabled (fix #1561) --- apps/run/ChangeLog | 3 ++- apps/run/app.js | 3 +++ apps/run/metadata.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index 0a697ecb9..032ebdc1a 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -6,4 +6,5 @@ 0.05: exstats updated so update 'distance' label is updated, option for 'speed' 0.06: Add option to record a run using the recorder app automatically 0.07: Fix crash if an odd number of active boxes are configured (fix #1473) -0.08: Added support for notifications from exstats. Support all stats from exstats \ No newline at end of file +0.08: Added support for notifications from exstats. Support all stats from exstats +0.09: Fix broken start/stop if recording not enabled (fix #1561) diff --git a/apps/run/app.js b/apps/run/app.js index 45daf878e..d066c8b1f 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -66,6 +66,9 @@ function onStartStop() { } } + if (!prepPromises.length) // fix for Promise.all bug in 2v12 + prepPromises.push(Promise.resolve()); + Promise.all(prepPromises) .then(() => { if (running) { diff --git a/apps/run/metadata.json b/apps/run/metadata.json index 8f139c2d5..01a85ed05 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.08", + "version":"0.09", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", From 7adfda340e21c293d975a0a79fa818aca2a2df50 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 14 Mar 2022 11:07:26 -0500 Subject: [PATCH 440/447] Fix for when recorder widget is used before app --- apps/recorder/ChangeLog | 1 + apps/recorder/app-settings.json | 2 +- apps/recorder/app.js | 7 ++++++- apps/recorder/metadata.json | 4 ++-- apps/recorder/widget.js | 14 +++++++++----- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 963944144..90937e160 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -16,3 +16,4 @@ 0.10: Fix broken recorder settings (when launched from settings app) 0.11: Fix KML and GPX export when there is no GPS data 0.12: Fix 'Back' label positioning on track/graph display, make translateable +0.13: Fix for when widget is used before app diff --git a/apps/recorder/app-settings.json b/apps/recorder/app-settings.json index 4a3117a17..7410af213 100644 --- a/apps/recorder/app-settings.json +++ b/apps/recorder/app-settings.json @@ -1,6 +1,6 @@ { "recording":false, - "file":"record.log0.csv", + "file":"recorder.log0.csv", "period":10, "record" : ["gps"] } diff --git a/apps/recorder/app.js b/apps/recorder/app.js index d900c12c1..e5e732fe3 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -31,7 +31,12 @@ function updateSettings() { } function getTrackNumber(filename) { - return parseInt(filename.match(/^recorder\.log(.*)\.csv$/)[1]||0); + var trackNum = 0; + var matches = filename.match(/^recorder\.log(.*)\.csv$/); + if (matches) { + trackNum = parseInt(matches[1]||0); + } + return trackNum; } function showMainMenu() { diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 09873dada..e2400603d 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.12", + "version": "0.13", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget", @@ -15,5 +15,5 @@ {"name":"recorder.wid.js","url":"widget.js"}, {"name":"recorder.settings.js","url":"settings.js"} ], - "data": [{"name":"recorder.json"},{"wildcard":"recorder.log?.csv","storageFile":true}] + "data": [{"name":"recorder.json","url":"app-settings.json"},{"wildcard":"recorder.log?.csv","storageFile":true}] } diff --git a/apps/recorder/widget.js b/apps/recorder/widget.js index e10c99c0c..221bc6c1a 100644 --- a/apps/recorder/widget.js +++ b/apps/recorder/widget.js @@ -11,7 +11,7 @@ settings.recording = false; return settings; } - + function updateSettings(settings) { require("Storage").writeJSON("recorder.json", settings); if (WIDGETS["recorder"]) WIDGETS["recorder"].reload(); @@ -233,7 +233,9 @@ Bangle.drawWidgets(); // relayout all widgets },setRecording:function(isOn) { var settings = loadSettings(); - if (isOn && !settings.recording && require("Storage").list(settings.file).length){ + if (isOn && !settings.recording && !settings.file) { + settings.file = "recorder.log0.csv"; + } else if (isOn && !settings.recording && require("Storage").list(settings.file).length){ var logfiles=require("Storage").list(/recorder.log.*/); var maxNumber=0; for (var c of logfiles){ @@ -247,9 +249,11 @@ var buttons={Yes:"yes",No:"no"}; if (newFileName) buttons["New"] = "new"; var prompt = E.showPrompt("Overwrite\nLog " + settings.file.match(/\d+/)[0] + "?",{title:"Recorder",buttons:buttons}).then(selection=>{ - if (selection=="no") return false; // just cancel - if (selection=="yes") require("Storage").open(settings.file,"r").erase(); - if (selection=="new"){ + if (selection==="no") return false; // just cancel + if (selection==="yes") { + require("Storage").open(settings.file,"r").erase(); + } + if (selection==="new"){ settings.file = newFileName; updateSettings(settings); } From 28e30164149a810384fcf9a102e7d72b64c1175b Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Mon, 14 Mar 2022 18:27:58 +0100 Subject: [PATCH 441/447] powermanager - Round percentage values to get integer values for E.getBattery() --- apps/powermanager/boot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js index 1f6ec332a..077e24413 100644 --- a/apps/powermanager/boot.js +++ b/apps/powermanager/boot.js @@ -31,7 +31,7 @@ var p = (E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery())/4; var op = E.getBattery; E.getBattery = function() { - var current = (op()+op()+op()+op())/4; + var current = Math.round((op()+op()+op()+op())/4); if (Bangle.isCharging() && current > p) p = current; if (!Bangle.isCharging() && current < p) p = current; return p; From 993850ad99047988a0351e8a55fce3fe6010927f Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Mon, 14 Mar 2022 19:53:35 +0100 Subject: [PATCH 442/447] main.cc: Force line break for smaller resolutions --- css/main.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/main.css b/css/main.css index f4850babe..a986df22e 100644 --- a/css/main.css +++ b/css/main.css @@ -81,7 +81,7 @@ a.btn.btn-link.dropdown-toggle { min-height: 8em; } -.tile-content { position: relative; } +.tile-content { position: relative; word-break: break-all; } .link-github { position:absolute; top: 36px; From bd899c7f725c3f9730273f4cb2e3b253eced8697 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 15 Mar 2022 12:47:57 +0000 Subject: [PATCH 443/447] Added backup/restore buttons --- backup.js | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++ core | 2 +- index.html | 4 ++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 backup.js diff --git a/backup.js b/backup.js new file mode 100644 index 000000000..d40121fb2 --- /dev/null +++ b/backup.js @@ -0,0 +1,114 @@ +/* Code to handle Backup/Restore functionality */ + +const BACKUP_STORAGEFILE_DIR = "storage-files"; + +function bangleDownload() { + var zip = new JSZip(); + Progress.show({title:"Scanning...",sticky:true}); + var normalFiles, storageFiles; + console.log("Listing normal files..."); + Comms.listFiles({sf:false}).then(f => { + normalFiles = f; + console.log(" - "+f.join(",")); + console.log("Listing StorageFiles..."); + return Comms.listFiles({sf:true}); + }).then(f => { + storageFiles = f; + console.log(" - "+f.join(",")); + var fileCount = normalFiles.length + storageFiles.length; + var promise = Promise.resolve(); + // Normal files + normalFiles.forEach((filename,n) => { + promise = promise.then(() => { + Progress.hide({sticky: true}); + var percent = n/fileCount; + Progress.show({title:`Download ${filename}`,sticky:true,min:percent,max:percent,percent:0}); + return Comms.readFile(filename).then(data => zip.file(filename,data)); + }); + }); + // Storage files + if (storageFiles.length) { + var zipStorageFiles = zip.folder(BACKUP_STORAGEFILE_DIR); + storageFiles.forEach((filename,n) => { + promise = promise.then(() => { + Progress.hide({sticky: true}); + var percent = (normalFiles.length+n)/fileCount; + Progress.show({title:`Download ${filename}`,sticky:true,min:percent,max:percent,percent:0}); + return Comms.readStorageFile(filename).then(data => zipStorageFiles.file(filename,data)); + }); + }); + } + console.log("Listing StorageFiles..."); + return promise; + }).then(() => { + return zip.generateAsync({type:"blob"}); + }).then(content => { + Progress.hide({ sticky: true }); + showToast('Backup complete!', 'success'); + Espruino.Core.Utils.fileSaveDialog(content, "Banglejs backup.zip"); + }).catch(err => { + Progress.hide({ sticky: true }); + showToast('Backup failed, ' + err, 'error'); + }); +} + +function bangleUpload() { + Espruino.Core.Utils.fileOpenDialog({ + id:"backup", + type:"arraybuffer", + mimeType:".zip,application/zip"}, function(data) { + if (data===undefined) return; + var promise = Promise.resolve(); + var zip = new JSZip(); + var cmds = ""; + zip.loadAsync(data).then(function(zip) { + return showPrompt("Restore from ZIP","Are you sure? This will remove all existing apps"); + }).then(()=>{ + Progress.show({title:`Reading ZIP`}); + zip.forEach(function (path, file){ + console.log("path"); + promise = promise + .then(() => file.async("string")) + .then(data => { + console.log("decoded", path); + if (path.startsWith(BACKUP_STORAGEFILE_DIR)) { + path = path.substr(BACKUP_STORAGEFILE_DIR.length+1); + cmds += AppInfo.getStorageFileUploadCommands(path, data)+"\n"; + } else if (!path.includes("/")) { + cmds += AppInfo.getFileUploadCommands(path, data)+"\n"; + } else console.log("Ignoring "+path); + }); + }); + return promise; + }) + .then(() => { + Progress.hide({sticky:true}); + Progress.show({title:`Erasing...`}); + return Comms.removeAllApps(); }) + .then(() => { + Progress.hide({sticky:true}); + Progress.show({title:`Restoring...`, sticky:true}); + return Comms.showMessage(`Restoring...`); }) + .then(() => Comms.write("\x10"+Comms.getProgressCmd()+"\n")) + .then(() => Comms.uploadCommandList(cmds, 0, cmds.length)) + .then(() => Comms.showMessage(Const.MESSAGE_RELOAD)) + .then(() => { + Progress.hide({sticky:true}); + showToast('Restore complete!', 'success'); + }) + .catch(err => { + Progress.hide({sticky:true}); + showToast('Restore failed, ' + err, 'error'); + }); + return promise; + }); +} + +window.addEventListener('load', (event) => { + document.getElementById("downloadallapps").addEventListener("click",event=>{ + bangleDownload(); + }); + document.getElementById("uploadallapps").addEventListener("click",event=>{ + bangleUpload(); + }); +}); diff --git a/core b/core index affb0b15b..05f97e6ad 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit affb0b15b41eb35a1548373831af7001bad64435 +Subproject commit 05f97e6ade4605ac7a6105def52a34280f4f0c4d diff --git a/index.html b/index.html index 6c9a21bf8..a418b48eb 100644 --- a/index.html +++ b/index.html @@ -131,6 +131,8 @@

+

+

Settings