Merge branch 'master' of github.com:wagnerf42/BangleApps

master
frederic wagner 2024-08-26 10:51:36 +02:00
commit bc43ace665
1529 changed files with 27416 additions and 5570 deletions

View File

@ -1,11 +1,6 @@
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
apps/gipy/pkg/gps.js
apps/health/chart.min.js
*.test.js
# typescript/generated files # Needs to be ignored because it uses ESM export/import
apps/btadv/*.js apps/gipy/pkg/gps.js
# Needs to be ignored because it includes broken JS
apps/health/chart.min.js

View File

@ -1,7 +1,32 @@
{ const lintExemptions = require("./apps/lint_exemptions.js");
const fs = require("fs");
const path = require("path");
function findGeneratedJS(roots) {
function* listFiles(dir, allow) {
for (const f of fs.readdirSync(dir)) {
const filepath = path.join(dir, f);
const stat = fs.statSync(filepath);
if (stat.isDirectory()) {
yield* listFiles(filepath, allow);
} else if(allow(filepath)) {
yield filepath;
}
}
}
return roots.flatMap(root =>
[...listFiles(root, f => f.endsWith(".ts"))]
.map(f => f.replace(/\.ts$/, ".js"))
);
}
module.exports = {
"env": { "env": {
// TODO: "espruino": false // TODO: "espruino": false
// TODO: "banglejs": false // TODO: "banglejs": false
// For a prototype of the above, see https://github.com/espruino/BangleApps/pull/3237
}, },
"extends": "eslint:recommended", "extends": "eslint:recommended",
"globals": { "globals": {
@ -23,10 +48,8 @@
"Flash": "readonly", "Flash": "readonly",
"Float32Array": "readonly", "Float32Array": "readonly",
"Float64Array": "readonly", "Float64Array": "readonly",
"fs": "readonly",
"Function": "readonly", "Function": "readonly",
"Graphics": "readonly", "Graphics": "readonly",
"heatshrink": "readonly",
"I2C": "readonly", "I2C": "readonly",
"Int16Array": "readonly", "Int16Array": "readonly",
"Int32Array": "readonly", "Int32Array": "readonly",
@ -46,11 +69,9 @@
"RegExp": "readonly", "RegExp": "readonly",
"Serial": "readonly", "Serial": "readonly",
"SPI": "readonly", "SPI": "readonly",
"Storage": "readonly",
"StorageFile": "readonly", "StorageFile": "readonly",
"String": "readonly", "String": "readonly",
"SyntaxError": "readonly", "SyntaxError": "readonly",
"tensorflow": "readonly",
"TFMicroInterpreter": "readonly", "TFMicroInterpreter": "readonly",
"TypeError": "readonly", "TypeError": "readonly",
"Uint16Array": "readonly", "Uint16Array": "readonly",
@ -58,8 +79,10 @@
"Uint32Array": "readonly", "Uint32Array": "readonly",
"Uint8Array": "readonly", "Uint8Array": "readonly",
"Uint8ClampedArray": "readonly", "Uint8ClampedArray": "readonly",
"Unistroke": "readonly",
"Waveform": "readonly", "Waveform": "readonly",
// Methods and Fields at https://banglejs.com/reference // Methods and Fields at https://banglejs.com/reference
"__FILE__": "readonly",
"analogRead": "readonly", "analogRead": "readonly",
"analogWrite": "readonly", "analogWrite": "readonly",
"arguments": "readonly", "arguments": "readonly",
@ -129,7 +152,43 @@
"VIBRATE": "readonly", "VIBRATE": "readonly",
// Aliases and not defined at https://banglejs.com/reference // Aliases and not defined at https://banglejs.com/reference
"g": "readonly", "g": "readonly",
"WIDGETS": "readonly" "WIDGETS": "readonly",
"module": "readonly",
"exports": "writable",
"D0": "readonly",
"D1": "readonly",
"D2": "readonly",
"D3": "readonly",
"D4": "readonly",
"D5": "readonly",
"D6": "readonly",
"D7": "readonly",
"D8": "readonly",
"D9": "readonly",
"D10": "readonly",
"D11": "readonly",
"D12": "readonly",
"D13": "readonly",
"D14": "readonly",
"D15": "readonly",
"D16": "readonly",
"D17": "readonly",
"D18": "readonly",
"D19": "readonly",
"D20": "readonly",
"D21": "readonly",
"D22": "readonly",
"D23": "readonly",
"D24": "readonly",
"D25": "readonly",
"D26": "readonly",
"D27": "readonly",
"D28": "readonly",
"D29": "readonly",
"D30": "readonly",
"D31": "readonly",
"bleServiceOptions": "writable", // available in boot.js code that's called ad part of bootupdate
}, },
"parserOptions": { "parserOptions": {
"ecmaVersion": 11 "ecmaVersion": 11
@ -142,22 +201,49 @@
"SwitchCase": 1 "SwitchCase": 1
} }
], ],
"no-case-declarations": "off",
"no-constant-condition": "off", "no-constant-condition": "off",
"no-delete-var": "off", "no-delete-var": "off",
"no-empty": "off", "no-empty": ["warn", { "allowEmptyCatch": true }],
"no-global-assign": "off", "no-global-assign": "off",
"no-inner-declarations": "off", "no-inner-declarations": "off",
"no-octal": "off",
"no-prototype-builtins": "off", "no-prototype-builtins": "off",
"no-redeclare": "off", "no-redeclare": "off",
"no-unreachable": "warn", "no-unreachable": "warn",
"no-cond-assign": "warn", "no-cond-assign": "warn",
"no-useless-catch": "warn", "no-useless-catch": "warn",
// TODO: "no-undef": "warn", "no-undef": "warn",
"no-undef": "off", "no-unused-vars": ["warn", { "args": "none" } ],
"no-unused-vars": "off",
"no-useless-escape": "off", "no-useless-escape": "off",
"no-control-regex" : "off" "no-control-regex" : "off"
},
overrides: [
{
files: ["*.ts"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
rules: {
"no-delete-var": "off",
"no-empty": ["error", { "allowEmptyCatch": true }],
"no-prototype-builtins": "off",
"prefer-const": "off",
"prefer-rest-params": "off",
"no-control-regex" : "off",
"@typescript-eslint/no-delete-var": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
} }
},
...Object.entries(lintExemptions).map(([filePath, {rules}]) => ({
files: [filePath],
rules: Object.fromEntries(rules.map(rule => [rule, "off"])),
})),
],
ignorePatterns: findGeneratedJS(["apps/", "modules/"]),
reportUnusedDisableDirectives: true,
} }

View File

@ -11,10 +11,10 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Use Node.js 16.x - name: Use Node.js 18.x
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 18.x
- name: Install testing dependencies - name: Install testing dependencies
run: npm ci run: npm ci
- name: Test all apps and widgets - name: Test all apps and widgets

9
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,9 @@
Contributing to BangleApps
==========================
https://github.com/espruino/BangleApps?tab=readme-ov-file#getting-started
has some links to tutorials on developing for Bangle.js.
Please check out the Wiki to get an idea what sort of things
we'd like to see for contributed apps: https://github.com/espruino/BangleApps/wiki/App-Contribution

View File

@ -6,6 +6,8 @@ Bangle.js App Loader (and Apps)
* Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps) * Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps)
* Try the **development version** at [espruino.github.io](https://espruino.github.io/BangleApps/) * Try the **development version** at [espruino.github.io](https://espruino.github.io/BangleApps/)
The release version is manually refreshed with regular intervals while the development version is continuously updated as new code is committed to this repository.
**All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By **All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By
submitting code to this repository you confirm that you are happy with it being MIT licensed, submitting code to this repository you confirm that you are happy with it being MIT licensed,
and that it is not licensed in another way that would make this impossible. and that it is not licensed in another way that would make this impossible.
@ -403,7 +405,7 @@ in an iframe.
<link rel="stylesheet" href="../../css/spectre.min.css"> <link rel="stylesheet" href="../../css/spectre.min.css">
</head> </head>
<body> <body>
<script src="../../lib/interface.js"></script> <script src="../../core/lib/interface.js"></script>
<div id="t">Loading...</div> <div id="t">Loading...</div>
<script> <script>
function onInit() { function onInit() {
@ -554,6 +556,30 @@ You can use `g.setColor(r,g,b)` OR `g.setColor(16bitnumber)` - some common 16 bi
| GreenYellow | 0xAFE5 | | GreenYellow | 0xAFE5 |
| Pink | 0xF81F | | Pink | 0xF81F |
## Fonts
A recent addition to Bangle.js is the ability to use extra fonts with support for more characters.
For example [all regions](https://banglejs.com/apps/?id=fontall) or [extended](https://banglejs.com/apps/?id=fontext) fonts.
Once installed, these apps cause a new font, `Intl` to be added to `Graphics`, which can be used with just `g.setFont("Intl")`.
There is also a `font` library - this is not implemented yet, but more information about the planned implementation
is available at https://github.com/espruino/BangleApps/issues/3109
For now, to make your app work with the international font, you can check if `Graphics.prototype.setFontIntl` exists,
and if so you can change the font you plan on using:
```JS
myFont = "6x8:2";
if (Graphics.prototype.setFontIntl)
myFont = "Intl";
```
Any new Font library must contain the metadata `"icon": "app.png", "tags": "font", "type": "module", "provides_modules" : ["fonts"],`
and should provide a `font` library, as well as a `boot.js` that adds `Graphics.prototype.setFontIntl`. If you plan on
making a new library it's best to just copy one of the existing ones for now.
## API Reference ## API Reference
[Reference](http://www.espruino.com/Reference#software) [Reference](http://www.espruino.com/Reference#software)

View File

@ -22,7 +22,7 @@
<body> <body>
<header class="navbar-primary navbar"> <header class="navbar-primary navbar">
<section class="navbar-section" > <section class="navbar-section" >
<a href="https://banglejs.com" target="_blank" class="navbar-brand mr-2" ><img src="img/banglejs-logo-sml.png" alt="Bangle.js"> <a href="https://banglejs.com" target="_blank" class="navbar-brand mr-2"><img src="img/banglejs-logo-small.svg" alt="Bangle.js">
<div>App Loader</div></a> <div>App Loader</div></a>
<!-- <a href="#" class="btn btn-link">...</a> --> <!-- <a href="#" class="btn btn-link">...</a> -->
</section> </section>

View File

@ -1 +1,2 @@
0.01: New Widget! 0.01: New Widget!
0.02: Minor code improvements

View File

@ -1,7 +1,7 @@
{ {
"id": "1button", "id": "1button",
"name": "One-Button-Tracker", "name": "One-Button-Tracker",
"version": "0.01", "version": "0.02",
"description": "A widget that turns BTN1 into a tracker, records time of button press/release.", "description": "A widget that turns BTN1 into a tracker, records time of button press/release.",
"icon": "widget.png", "icon": "widget.png",
"type": "widget", "type": "widget",

View File

@ -22,7 +22,7 @@
console.log("Button let go"); console.log("Button let go");
digitalWrite(LED2,0); digitalWrite(LED2,0);
var unpress_time = new Date(); var unpress_time = new Date();
recFile = require("Storage").open("one_button_presses.csv","a"); const recFile = require("Storage").open("one_button_presses.csv","a");
recFile.write([press_time.getTime(),unpress_time.getTime()].join(",")+"\n"); recFile.write([press_time.getTime(),unpress_time.getTime()].join(",")+"\n");
}, BTN1, { repeat: true, edge: 'falling', debounce: 50 }); }, BTN1, { repeat: true, edge: 'falling', debounce: 50 });

View File

@ -122,13 +122,13 @@
} }
} }
function swipeHandler() { /*function swipeHandler() {
} }*/
function buttonHandler() { /*function buttonHandler() {
} }*/
var twok = new TwoK(); var twok = new TwoK();
twok.addDigit(); twok.addDigit(); twok.addDigit(); twok.addDigit();

View File

@ -1,3 +1,4 @@
0.01: New app! 0.01: New app!
0.02: Better support for watch themes 0.02: Better support for watch themes
0.03: Workaround minifier bug 0.03: Workaround minifier bug
0.04: Minor code improvements

View File

@ -2,7 +2,7 @@
"name": "2047pp", "name": "2047pp",
"shortName":"2047pp", "shortName":"2047pp",
"icon": "app.png", "icon": "app.png",
"version":"0.03", "version": "0.04",
"description": "Bangle version of a tile shifting game", "description": "Bangle version of a tile shifting game",
"supports" : ["BANGLEJS","BANGLEJS2"], "supports" : ["BANGLEJS","BANGLEJS2"],
"allow_emulator": true, "allow_emulator": true,

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.02: Minor code improvements

View File

@ -80,7 +80,7 @@ function refreshBattery() {
} }
// Only update displayed battery level every minute as it fluctuates a lot // Only update displayed battery level every minute as it fluctuates a lot
var batteryInterval = setInterval(refreshBattery, 60000); setInterval(refreshBattery, 60000);
Bangle.setUI("clock"); Bangle.setUI("clock");
Bangle.setLocked(false); Bangle.setLocked(false);

View File

@ -1,7 +1,7 @@
{ {
"id": "2ofthemclk", "id": "2ofthemclk",
"name": "two of them clock", "name": "two of them clock",
"version": "0.01", "version": "0.02",
"description": "You can now wear teh memez on your wrist.", "description": "You can now wear teh memez on your wrist.",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",

View File

@ -282,7 +282,7 @@ function drawWidgeds() {
//print(BluetoothDevice.connected); //print(BluetoothDevice.connected);
var x1Bt = 160; var x1Bt = 160;
var y1Bt = 0; var y1Bt = 0;
var x2Bt = x1Bt + 30; //var x2Bt = x1Bt + 30;
var y2Bt = y2Bt; var y2Bt = y2Bt;
if (NRF.getSecurityStatus().connected) if (NRF.getSecurityStatus().connected)
@ -391,4 +391,4 @@ Bangle.on('lock', function(on) {
SetFull(Bangle.isLocked()); SetFull(Bangle.isLocked());
var secondInterval = setInterval(draw, 1000); /*var secondInterval =*/ setInterval(draw, 1000);

View File

@ -1,3 +1,4 @@
0.01: Initial version for upload 0.01: Initial version for upload
0.02: Better theme support, configurable colors, small improvements 0.02: Better theme support, configurable colors, small improvements
0.03: Use `messages` library to check for new messages 0.03: Use `messages` library to check for new messages
0.04: Minor code improvements

View File

@ -1,7 +1,7 @@
{ "id": "7x7dotsclock", { "id": "7x7dotsclock",
"name": "7x7 Dots Clock", "name": "7x7 Dots Clock",
"shortName":"7x7 Dots Clock", "shortName":"7x7 Dots Clock",
"version":"0.03", "version": "0.04",
"description": "A clock with a big 7x7 dots Font", "description": "A clock with a big 7x7 dots Font",
"icon": "dotsfontclock.png", "icon": "dotsfontclock.png",
"tags": "clock", "tags": "clock",

View File

@ -4,3 +4,4 @@
0.04: Set 00:00 to 12:00 for 12 hour time 0.04: Set 00:00 to 12:00 for 12 hour time
0.05: Display time, even on Thursday 0.05: Display time, even on Thursday
0.06: Fix light theme issue, where widgets would end up on a light strip 0.06: Fix light theme issue, where widgets would end up on a light strip
0.07: Minor code improvements

View File

@ -8,7 +8,7 @@ var imgBg = require("heatshrink").decompress(atob("2GwgJC/AH4A/AH4A/AH4A/AH4A/AC
// reg number first char 48 28 by 41 // reg number first char 48 28 by 41
var fontNum = atob("AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//w//j4//A/+P4/8A/4/4AAAAD/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/wAAAAH/H/gH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wB/4AP/4H/4A//4f/4D//5//4P//h//4//+B//4AAAAAAAAAAAAAAAAAf/+AAAB//4gAAD//jgAAD/+PgABj/4/gAHj/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f88AAfx/8wAAfH/8AAAcf/8AAAR//4AAAH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA4AAAAAD4AAYAAP4AD8AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAHgAH/H/GH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAP//AAAAP//AAAAP//AAAAP/8AAAAP/2AAAAP/eAAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAB/7x/4AH/7H/4Af/4f/4B//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wAAAD//wAAAj//gAADj/+AAAPj/5gAA/j/ngAD/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8AA8f8fwAAx/8fAAAH/8cAAAf/8QAAA//8AAAA//8AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//0//j4//Y/+P4/94/4/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/AAPH/H8AAMf/HwAAB//HAAAH//EAAAH//AAAAH//AAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAGAAAAAAOAAAAAAeAAAAAA+AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB8AAAAADx/4B/4HH/4H/4Mf/4f/4R//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wP/+D//w//4j//z//jj//T/+Pj/9j/4/j/3j/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f+8f8fx/+x/8fH/+H/8cf/+f/8R//4f/8H//gf/8AAAAAAAAAAAAAA//8AAAA//8AAAI//8AAA4//0AAD4//YAAP4/94AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/H/vH/H8f/sf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); var fontNum = atob("AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//w//j4//A/+P4/8A/4/4AAAAD/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/4AAAAP/wAAAAf/gAAAA//AAAAB/+AAAAD/8AAAAH/wAAAAH/H/gH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wB/4AP/4H/4A//4f/4D//5//4P//h//4//+B//4AAAAAAAAAAAAAAAAAf/+AAAB//4gAAD//jgAAD/+PgABj/4/gAHj/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f88AAfx/8wAAfH/8AAAcf/8AAAR//4AAAH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA4AAAAAD4AAYAAP4AD8AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAHgAH/H/GH/H8f/gf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAP//AAAAP//AAAAP//AAAAP/8AAAAP/2AAAAP/eAAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAB/7x/4AH/7H/4Af/4f/4B//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wAAAD//wAAAj//gAADj/+AAAPj/5gAA/j/ngAD/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8AA8f8fwAAx/8fAAAH/8cAAAf/8QAAA//8AAAA//8AAAAAAAAAAAAAA//8D//g//8P/+I//8//44//0//j4//Y/+P4/94/4/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/AAPH/H8AAMf/HwAAB//HAAAH//EAAAH//AAAAH//AAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAGAAAAAAOAAAAAAeAAAAAA+AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB+AAAAAD8AAAAAH4AAAAAPwAAAAAfgAAAAA/AAAAAB8AAAAADx/4B/4HH/4H/4Mf/4f/4R//5//4H//h//4f/+B//4AAAAAAAAAAAAAD//wP/+D//w//4j//z//jj//T/+Pj/9j/4/j/3j/j/gAfgAP/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/AA/AAf8f+8f8fx/+x/8fH/+H/8cf/+f/8R//4f/8H//gf/8AAAAAAAAAAAAAA//8AAAA//8AAAI//8AAA4//0AAD4//YAAP4/94AA/4AH4AD/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/4APwAP/wAfgAf/gA/AA//AB+AB/+AD8AD/8AH4AH/wAPwAH/H/vH/H8f/sf/Hx//h//HH//n//Ef/+H//B//4H//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
// tiny font for percentage first char 48 6 by 8 // tiny font for percentage first char 48 6 by 8
var fontTiny = atob("AH6BgYF+ACFB/wEBAGGDhYlxAEKBkZFuAAx0hP8EAPqRkZGOAH6RkZFOAICHmKDAAG6RkZFuAHKJiYl+AAAAAAAAAAAAAAAA"); //var fontTiny = atob("AH6BgYF+ACFB/wEBAGGDhYlxAEKBkZFuAAx0hP8EAPqRkZGOAH6RkZFOAICHmKDAAG6RkZFuAHKJiYl+AAAAAAAAAAAAAAAA");
// date font first char 48 12 by 15 // date font first char 48 12 by 15
var fontDate = atob("AAAAAfv149wAeADwAeADwAeADvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAPHn9/AAAAAAP0A9wweGDwweGDwweGDvAL8AAAAAAAAAAAgwOGDwweGDwweGDvHp98AAAAA/gB6AAwAGAAwAGAAwAGAPHj9/AAAAAfgF6BwweGDwweGDwweGDgHoB+AAAAAfv169wweGDwweGDwweGDgHoB+AAAAAAAAAAgAGAAwAGAAwAGAAvHh9/AAAAAfv169wweGDwweGDwweGDvHr9+AAAAAfgF6BwweGDwweGDwweGDvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); var fontDate = atob("AAAAAfv149wAeADwAeADwAeADvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAPHn9/AAAAAAP0A9wweGDwweGDwweGDvAL8AAAAAAAAAAAgwOGDwweGDwweGDvHp98AAAAA/gB6AAwAGAAwAGAAwAGAPHj9/AAAAAfgF6BwweGDwweGDwweGDgHoB+AAAAAfv169wweGDwweGDwweGDgHoB+AAAAAAAAAAgAGAAwAGAAwAGAAvHh9/AAAAAfv169wweGDwweGDwweGDvHr9+AAAAAfgF6BwweGDwweGDwweGDvHr9+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
@ -25,7 +25,7 @@ var imgSun = E.toArrayBuffer(atob("Ig8BwHf7D7Ac/MHD/z8wMP/PzMQ/8/M/D/z8z8QPf7f6A
// define icons // define icons
var imgSep = E.toArrayBuffer(atob("BhsBAAAAAA///////////////AAAAAAA")); var imgSep = E.toArrayBuffer(atob("BhsBAAAAAA///////////////AAAAAAA"));
var imgPercent = E.toArrayBuffer(atob("BwcBuq7ffbqugA==")); //var imgPercent = E.toArrayBuffer(atob("BwcBuq7ffbqugA=="));
var img24hr = E.toArrayBuffer(atob("EwgBj7vO53na73tcDtu9uDev7vA93g==")); var img24hr = E.toArrayBuffer(atob("EwgBj7vO53na73tcDtu9uDev7vA93g=="));
var imgPM = E.toArrayBuffer(atob("EwgB+HOfdnPu1X3ar4dV9+q+/bfftg==")); var imgPM = E.toArrayBuffer(atob("EwgB+HOfdnPu1X3ar4dV9+q+/bfftg=="));

View File

@ -3,7 +3,7 @@
"shortName":"93 Dub", "shortName":"93 Dub",
"icon": "93dub.png", "icon": "93dub.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],
"version":"0.06", "version": "0.07",
"description": "Fan recreation of orviwan's 91 Dub app for the Pebble smartwatch. Uses assets from his 91-Dub-v2.0 repo", "description": "Fan recreation of orviwan's 91 Dub app for the Pebble smartwatch. Uses assets from his 91-Dub-v2.0 repo",
"tags": "clock", "tags": "clock",
"type": "clock", "type": "clock",

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.02: Minor code improvements

View File

@ -25,7 +25,7 @@ declare global variables for the toggle button
statuses; if you add an additional toggle button statuses; if you add an additional toggle button
you should declare it and initiase it here */ you should declare it and initiase it here */
var status_spk = {value: true}; //var status_spk = {value: true};
var status_face = {value: true}; var status_face = {value: true};
var status_iris_light = {value: false}; var status_iris_light = {value: false};
var status_iris = {value: false}; var status_iris = {value: false};

View File

@ -2,7 +2,7 @@
"id": "BLEcontroller", "id": "BLEcontroller",
"name": "BLE Customisable Controller with Joystick", "name": "BLE Customisable Controller with Joystick",
"shortName": "BLE Controller", "shortName": "BLE Controller",
"version": "0.01", "version": "0.02",
"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.", "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", "icon": "BLEcontroller.png",
"tags": "tool,bluetooth", "tags": "tool,bluetooth",

View File

@ -1 +1,2 @@
0.01: 1st ver, defining a common UI/UX 0.01: 1st ver, defining a common UI/UX
0.02: Minor code improvements

View File

@ -5,7 +5,7 @@ identify device and dimensions
max printable position max_x-1 i.e 239 max printable position max_x-1 i.e 239
*/ */
var colbackg='#111111';//black //var colbackg='#111111';//black
var colorange='#e56e06'; //RGB format rrggbb var colorange='#e56e06'; //RGB format rrggbb
var v_color_lines=0xFFFF; //White hex format var v_color_lines=0xFFFF; //White hex format
var v_color_b_area='#111111'; var v_color_b_area='#111111';
@ -13,13 +13,13 @@ max printable position max_x-1 i.e 239
var v_font1size=10; //out of quotes var v_font1size=10; //out of quotes
var v_font2size=12; var v_font2size=12;
var v_font_banner_size=30; var v_font_banner_size=30;
var v_clicks=0; //var v_clicks=0;
//pend identify widget area dinamically //pend identify widget area dinamically
var v_model=process.env.BOARD; var v_model=process.env.BOARD;
console.log("device="+v_model); console.log("device="+v_model);
var x_max_screen=g.getWidth();//240; var x_max_screen=g.getWidth();//240;
var y_max_screen=g.getHeight(); //240; //var y_max_screen=g.getHeight(); //240;
var y_wg_bottom=g.getHeight()-25; var y_wg_bottom=g.getHeight()-25;
var y_wg_top=25; var y_wg_top=25;
if (v_model=='BANGLEJS') { if (v_model=='BANGLEJS') {

View File

@ -2,7 +2,7 @@
"id": "UI4swatch", "id": "UI4swatch",
"name": "UI 4 swatch", "name": "UI 4 swatch",
"shortName": "UI 4 swatch", "shortName": "UI 4 swatch",
"version": "0.01", "version": "0.02",
"description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.", "description": "A UI/UX for espruino smartwatches, displays dinamically calc. x,y coordinates.",
"icon": "app.png", "icon": "app.png",
"tags": "Color,input,buttons,touch,UI", "tags": "Color,input,buttons,touch,UI",

View File

@ -1,3 +1,4 @@
0.01: New App! 0.01: New App!
0.02: Increased Legibility, GUI rework 0.02: Increased Legibility, GUI rework
0.03: 13 new chords 0.03: 13 new chords
0.04: Minor code improvements

View File

@ -176,8 +176,6 @@ const b7 = [
var index = 0;
var chords = [];
var menu = { var menu = {
"" : { "title" : "Uke Chords" }, "" : { "title" : "Uke Chords" },
"C" : function() { draw(cc); }, "C" : function() { draw(cc); },

View File

@ -1,7 +1,7 @@
{ "id": "Uke", { "id": "Uke",
"name": "Uke Chords", "name": "Uke Chords",
"shortName":"Uke", "shortName":"Uke",
"version":"0.03", "version": "0.04",
"description": "Wrist mounted ukulele chords", "description": "Wrist mounted ukulele chords",
"icon": "app.png", "icon": "app.png",
"tags": "uke, chords", "tags": "uke, chords",

View File

@ -0,0 +1,48 @@
{
// timeout used to update every minute
let drawTimeout;
// schedule a draw for the next minute
let queueDraw = function() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, 60000 - (Date.now() % 60000));
};
let draw = function() {
// queue next draw in one minute
queueDraw();
// Work out where to draw...
var x = g.getWidth()/2;
var y = g.getHeight()/2;
g.reset();
// work out locale-friendly date/time
var date = new Date();
var timeStr = require("locale").time(date,1);
var dateStr = require("locale").date(date);
// draw time
g.setFontAlign(0,0).setFont("Vector",48);
g.clearRect(0,y-15,g.getWidth(),y+25); // clear the background
g.drawString(timeStr,x,y);
// draw date
y += 35;
g.setFontAlign(0,0).setFont("6x8");
g.clearRect(0,y-4,g.getWidth(),y+4); // clear the background
g.drawString(dateStr,x,y);
};
// Clear the screen once, at startup
g.clear();
// draw immediately at first, queue update
draw();
// Show launcher when middle button pressed
Bangle.setUI({mode:"clock", remove:function() {
// free any memory we allocated to allow fast loading
}});
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
}

View File

@ -1,44 +0,0 @@
// 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() {
// queue next draw in one minute
queueDraw();
// Work out where to draw...
var x = g.getWidth()/2;
var y = g.getHeight()/2;
g.reset();
// work out locale-friendly date/time
var date = new Date();
var timeStr = require("locale").time(date,1);
var dateStr = require("locale").date(date);
// draw time
g.setFontAlign(0,0).setFont("Vector",48);
g.clearRect(0,y-15,g.getWidth(),y+25); // clear the background
g.drawString(timeStr,x,y);
// draw date
y += 35;
g.setFontAlign(0,0).setFont("6x8");
g.clearRect(0,y-4,g.getWidth(),y+4); // clear the background
g.drawString(dateStr,x,y);
}
// Clear the screen once, at startup
g.clear();
// draw immediately at first, queue update
draw();
// Show launcher when middle button pressed
Bangle.setUI("clock");
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();

View File

@ -4,6 +4,7 @@
"version":"0.01", "version":"0.01",
"description": "A detailed description of my clock", "description": "A detailed description of my clock",
"icon": "icon.png", "icon": "icon.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clock", "type": "clock",
"tags": "clock", "tags": "clock",
"supports" : ["BANGLEJS2"], "supports" : ["BANGLEJS2"],

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -2,3 +2,4 @@
0.02: Shows night time on the map (2022/12/28) 0.02: Shows night time on the map (2022/12/28)
0.03: Add 1 minute timer with upper taps (2023/01/05) 0.03: Add 1 minute timer with upper taps (2023/01/05)
1.00: Page to set up custom time zones (2023/01/06) 1.00: Page to set up custom time zones (2023/01/06)
1.01: Minor code improvements

View File

@ -2,7 +2,7 @@
function getImg() { function getImg() {
return require("heatshrink").decompress(atob("2FRgP/ABnxBRP5BJH+gEfBZHghnAv4JFmA+Bj0PBIn3//4h3An4oDAQJWEEIf8AwMEuFOCofAh/QjAWEg4VEwEAnw2DDoKEHEYPwAoUBmgrDhgUHS4XgAwUD/gVC/g+FAAZgEwEf4YqC/EQFQ4NDFgV/4Z3C/EcCo1974VCLAV/V4d7Co9/Co0PCoX+vk4Ko/HCosCRYX5nwTFkEAr/nCokICoL+B/aCGCoMHCoq3EdoraGCosPz4HBcILEJCocBwEHOwQrIgQrHgoHCFYMEgwVJYoMBsEnCofAnkMNQJXH4D4EbQMPkF/xwrEj+/HIkAoAVDj8QueHCoorDCoUDLwd96J0BKwgrHh4VDv+9CosDx6QCCo4HB//8VwvvXgQVDJIYSBCo/sBwaZBgF/NoYVHgH8V4qYDAwUYlAVFEYbFDDgwAGConogf9Zg8DCpP4cIh0Dg0BGAgVE+gVIgUA+AVI+wVE/xAEh5HDEgn+CpEAbgJCCHQoVBn4VJ/ED4ANDAAQVJ4EPPQPAt4VF4BeDColgj/8h/gFYwJBCpF//k//ANDCAYVIcgP+CpH/54VHCAIVB/4VIwYECCocIAwIVBx4VG9+AMITbCYAYJB34VG/UAj4VI7/9Cgw9CJYXAmBtDMAQsIfYhvCCofyvywGB4QFFgYGC/d+agYVLSgf8+ArG/APBD4QVBgh0CAwNwv/fCo4PCCo94s7VDCohnDAoI7Enlv8BZECoRCDAggAB3/3/gzDMAIVFY4IVE4IPBOoZ9DCpXwCoMvCqKxB//3bYywD4BtFAAPfDooVFFYIVGw4VFB4KZFngNE/uPCovgFYgEBuK+Fg4zFCoIrFCovwgQVF+AVFgPxEYzFEbgQVD4EDCoozBYogVCgYVE8bpGCo4HDCoPzBgoVIL4fAg4MGgAIHCofgCszND8BOHK4x2BCofwXgv4h6vGCps/Co6uDAA/7RgIjDDwTaDABPA//9FaAtDCop0FC5YVDLwoAH8//94GD/wVNCYKNECpwPBQggVPNggVBNp4VFFZwAGCquHCqnzCB4")); return require("heatshrink").decompress(atob("2FRgP/ABnxBRP5BJH+gEfBZHghnAv4JFmA+Bj0PBIn3//4h3An4oDAQJWEEIf8AwMEuFOCofAh/QjAWEg4VEwEAnw2DDoKEHEYPwAoUBmgrDhgUHS4XgAwUD/gVC/g+FAAZgEwEf4YqC/EQFQ4NDFgV/4Z3C/EcCo1974VCLAV/V4d7Co9/Co0PCoX+vk4Ko/HCosCRYX5nwTFkEAr/nCokICoL+B/aCGCoMHCoq3EdoraGCosPz4HBcILEJCocBwEHOwQrIgQrHgoHCFYMEgwVJYoMBsEnCofAnkMNQJXH4D4EbQMPkF/xwrEj+/HIkAoAVDj8QueHCoorDCoUDLwd96J0BKwgrHh4VDv+9CosDx6QCCo4HB//8VwvvXgQVDJIYSBCo/sBwaZBgF/NoYVHgH8V4qYDAwUYlAVFEYbFDDgwAGConogf9Zg8DCpP4cIh0Dg0BGAgVE+gVIgUA+AVI+wVE/xAEh5HDEgn+CpEAbgJCCHQoVBn4VJ/ED4ANDAAQVJ4EPPQPAt4VF4BeDColgj/8h/gFYwJBCpF//k//ANDCAYVIcgP+CpH/54VHCAIVB/4VIwYECCocIAwIVBx4VG9+AMITbCYAYJB34VG/UAj4VI7/9Cgw9CJYXAmBtDMAQsIfYhvCCofyvywGB4QFFgYGC/d+agYVLSgf8+ArG/APBD4QVBgh0CAwNwv/fCo4PCCo94s7VDCohnDAoI7Enlv8BZECoRCDAggAB3/3/gzDMAIVFY4IVE4IPBOoZ9DCpXwCoMvCqKxB//3bYywD4BtFAAPfDooVFFYIVGw4VFB4KZFngNE/uPCovgFYgEBuK+Fg4zFCoIrFCovwgQVF+AVFgPxEYzFEbgQVD4EDCoozBYogVCgYVE8bpGCo4HDCoPzBgoVIL4fAg4MGgAIHCofgCszND8BOHK4x2BCofwXgv4h6vGCps/Co6uDAA/7RgIjDDwTaDABPA//9FaAtDCop0FC5YVDLwoAH8//94GD/wVNCYKNECpwPBQggVPNggVBNp4VFFZwAGCquHCqnzCB4"));
} }
var IMAGEWIDTH = 176; //var IMAGEWIDTH = 176;
var IMAGEHEIGHT = 81; var IMAGEHEIGHT = 81;
Graphics.prototype.setFontMichroma36 = function() { Graphics.prototype.setFontMichroma36 = function() {

View File

@ -1,7 +1,7 @@
{ {
"id": "a_clock_timer", "id": "a_clock_timer",
"name": "A Clock with Timer", "name": "A Clock with Timer",
"version": "1.00", "version": "1.01",
"description": "A Clock with Timer, Map and Time Zones", "description": "A Clock with Timer, Map and Time Zones",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot-1.png"}], "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-1.png"}],

View File

@ -1 +1,2 @@
0.01: Initial version 0.01: Initial version
0.02: Add settings page; Add line break to update message

View File

@ -1,10 +1,13 @@
# a_dndtoggle - Toggle Quiet Mode of the watch # a_dndtoggle - Toggle Quiet Mode of the watch
When Quiet mode is off, just start this app to set quiet mode. Start it again to turn off quiet mode. When Quiet mode is off, just start this app to set quiet mode. Start it again to turn off quiet mode.
Use the app settings to choose which quiet mode you prefer ("Alarms" or "Silent"). Default is "Silent".
Work in progress. Work in progress.
#ToDo #ToDo
Settings page, current status indicator. Current status indicator
## Creator ## Creator

View File

@ -6,11 +6,14 @@ let current = 0|bSettings.quiet;
//1 alarms //1 alarms
//2 silent //2 silent
const dndSettings =
require('Storage').readJSON("a_dndtoggle.settings.json", true) || {};
console.log("old: " + current); console.log("old: " + current);
switch (current) { switch (current) {
case 0: case 0:
bSettings.quiet = 2; bSettings.quiet = dndSettings.mode || 2;
Bangle.buzz(); Bangle.buzz();
setTimeout('Bangle.buzz();',500); setTimeout('Bangle.buzz();',500);
break; break;
@ -29,7 +32,7 @@ switch (current) {
console.log("new: " + bSettings.quiet); console.log("new: " + bSettings.quiet);
E.showMessage(modeNames[current] + " -> " + modeNames[bSettings.quiet]); E.showMessage(modeNames[current] + " -> \n" + modeNames[bSettings.quiet]);
setTimeout('exitApp();', 2000); setTimeout('exitApp();', 2000);

View File

@ -2,14 +2,18 @@
"id": "a_dndtoggle", "id": "a_dndtoggle",
"name": "a_dndtoggle - Toggle Quiet Mode of the watch", "name": "a_dndtoggle - Toggle Quiet Mode of the watch",
"shortName": "A_DND Toggle", "shortName": "A_DND Toggle",
"version": "0.01", "version": "0.02",
"description": "Toggle Quiet Mode of the watch just by starting this app.", "description": "Toggle Quiet Mode of the watch just by starting this app.",
"icon": "a_dndtoggle.png", "icon": "a_dndtoggle.png",
"type": "app", "type": "app",
"tags": "tool", "tags": "tool",
"supports": ["BANGLEJS","BANGLEJS2"], "supports": ["BANGLEJS","BANGLEJS2"],
"data" : [
{"name":"a_dndtoggle.settings.json"}
],
"storage": [ "storage": [
{"name":"a_dndtoggle.app.js","url":"a_dndtoggle.app.js"}, {"name":"a_dndtoggle.app.js","url":"a_dndtoggle.app.js"},
{"name":"a_dndtoggle.settings.js","url":"settings.js"},
{"name":"a_dndtoggle.img","url":"app-icon.js","evaluate":true} {"name":"a_dndtoggle.img","url":"app-icon.js","evaluate":true}
], ],
"readme": "README.md" "readme": "README.md"

View File

@ -0,0 +1,33 @@
(function(back) {
const settings =
require('Storage').readJSON("a_dndtoggle.settings.json", true) || {};
function updateSettings() {
require('Storage').writeJSON("a_dndtoggle.settings.json", settings);
}
function buildMainMenu(){
// 0-Noisy is only a placeholder so that the other values map to the Bangle quiet mode options
const modes = [/*LANG*/"Noisy",/*LANG*/"Alarms",/*LANG*/"Silent"];
let mainmenu = {
'': { 'title': 'A_DND Toggle' },
'< Back': back,
/*LANG*/"Quiet Mode": {
value: settings.mode || 2,
min: 1, // don't allow choosing 0-Noisy
max: modes.length - 1,
format: v => modes[v],
onchange: v => {
settings.mode = v;
updateSettings();
}
}
};
return mainmenu;
}
E.showMenu(buildMainMenu());
});

View File

@ -1,3 +1,4 @@
1.00: Release (2021/12/01) 1.00: Release (2021/12/01)
1.01: Grey font when timer is frozen (2021/12/04) 1.01: Grey font when timer is frozen (2021/12/04)
1.02: Force light theme, since the app is not designed for dark theme (2022/12/28) 1.02: Force light theme, since the app is not designed for dark theme (2022/12/28)
1.03: Minor code improvements

View File

@ -124,7 +124,6 @@ Bangle.on('swipe',(swiperight, swipedown)=>{
} }
}); });
var drawTimeout;
var showInstructions = true; var showInstructions = true;
function draw() { function draw() {

View File

@ -2,7 +2,7 @@
"id":"a_speech_timer", "id":"a_speech_timer",
"name":"Speech Timer", "name":"Speech Timer",
"icon": "app.png", "icon": "app.png",
"version":"1.02", "version": "1.03",
"description": "A timer designed to help keeping your speeches and presentations to time.", "description": "A timer designed to help keeping your speeches and presentations to time.",
"tags": "tool,timer", "tags": "tool,timer",
"readme":"README.md", "readme":"README.md",

View File

@ -12,3 +12,4 @@
0.12: Actual pixels as of 29th Nov 2021 0.12: Actual pixels as of 29th Nov 2021
0.13: Bangle.js 2: Use setUI to add software back button 0.13: Bangle.js 2: Use setUI to add software back button
0.14: Add automatic translation of more strings 0.14: Add automatic translation of more strings
0.15: Minor code improvements

View File

@ -20,11 +20,11 @@ function getVersion(name,file) {
return v?(name+" "+(v?"v"+v:"Unknown")):"NO "+name; return v?(name+" "+(v?"v"+v:"Unknown")):"NO "+name;
} }
var versions = [ /*var versions = [
getVersion("Bootloader","boot.info"), getVersion("Bootloader","boot.info"),
getVersion("Launcher","launch.info"), getVersion("Launcher","launch.info"),
getVersion("Settings","setting.info") getVersion("Settings","setting.info")
]; ];*/
var logo = E.toArrayBuffer(atob("PBwBAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAD/w+AAAAQAHA4hAAAAQAMAMhAAAAQAYBmhAAAAQAYBGiAAAAQAQCD/H74+R4wGDhoKJCSEwEDgoKJCT8wFDgoKJCSAwHDhoKJCSEQHj/H6I+R4YHmAAAACAAYEGAAABCAAMEMAAAA8AAHA4AAAAAAAD/wAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/g")); var logo = E.toArrayBuffer(atob("PBwBAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAD/w+AAAAQAHA4hAAAAQAMAMhAAAAQAYBmhAAAAQAYBGiAAAAQAQCD/H74+R4wGDhoKJCSEwEDgoKJCT8wFDgoKJCSAwHDhoKJCSEQHj/H6I+R4YHmAAAACAAYEGAAABCAAMEMAAAA8AAHA4AAAAAAAD/wAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/gAAAAAAAB/g"));
var imageTop = 24; var imageTop = 24;

View File

@ -1,7 +1,7 @@
{ {
"id": "about", "id": "about",
"name": "About", "name": "About",
"version": "0.14", "version": "0.15",
"description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers",
"icon": "app.png", "icon": "app.png",
"tags": "tool,system", "tags": "tool,system",

View File

@ -3,3 +3,5 @@
Calculate the time moving in graph display Calculate the time moving in graph display
Trigger on 1.04g now, and record 10 samples before trigger Trigger on 1.04g now, and record 10 samples before trigger
0.03: Bangle.js 2 compatibility 0.03: Bangle.js 2 compatibility
0.04: Minor code improvements
0.05: Can record 100hz, z-axis color changed to yellow, autosave to file, no need select, delete old records

View File

@ -1,16 +1,20 @@
var acc; //var acc;
var HZ = 100; var HZ = 100;
var SAMPLES = 5*HZ; // 5 seconds var SAMPLES = 6 * HZ; // 6 seconds
var SCALE = 5000; var SCALE = 2000;
var THRESH = 1.04; var THRESH = 1.4;
var accelx = new Int16Array(SAMPLES); var accelx = new Int16Array(SAMPLES);
var accely = new Int16Array(SAMPLES); // North var accely = new Int16Array(SAMPLES); // North
var accelz = new Int16Array(SAMPLES); // Into clock face var accelz = new Int16Array(SAMPLES); // Into clock face
var timestep = new Int16Array(SAMPLES); // Into clock face
var accelIdx = 0; var accelIdx = 0;
var lastAccel; var lastAccel;
function accelHandlerTrigger(a) {"ram" var timestep_start = 0;
function accelHandlerTrigger(a) {
"ram"
if (a.mag * 2 > THRESH) { // *2 because 8g mode if (a.mag * 2 > THRESH) { // *2 because 8g mode
tStart = getTime(); timestep_start = getTime();
g.drawString("Recording", g.getWidth() / 2, g.getHeight() / 2, 1); g.drawString("Recording", g.getWidth() / 2, g.getHeight() / 2, 1);
Bangle.removeListener('accel', accelHandlerTrigger); Bangle.removeListener('accel', accelHandlerTrigger);
Bangle.on('accel', accelHandlerRecord); Bangle.on('accel', accelHandlerRecord);
@ -21,14 +25,19 @@ function accelHandlerTrigger(a) {"ram"
lastAccel.push(a); lastAccel.push(a);
} }
} }
function accelHandlerRecord(a) {"ram"
function accelHandlerRecord(a) {
"ram"
var i = accelIdx++; var i = accelIdx++;
accelx[i] = a.x*SCALE*2; accelx[i] = a.x * SCALE * 2; // *2 because of 8g mode
accely[i] = -a.y * SCALE * 2; accely[i] = -a.y * SCALE * 2;
accelz[i] = a.z * SCALE * 2; accelz[i] = a.z * SCALE * 2;
timestep[i] = (getTime() - timestep_start) * 1000;
if (accelIdx >= SAMPLES) recordStop(); if (accelIdx >= SAMPLES) recordStop();
} }
function recordStart() {"ram"
function recordStart() {
"ram"
Bangle.setLCDTimeout(0); // force LCD on Bangle.setLCDTimeout(0); // force LCD on
accelIdx = 0; accelIdx = 0;
lastAccel = []; lastAccel = [];
@ -44,7 +53,8 @@ function recordStart() {"ram"
} }
function recordStop() {"ram" function recordStop() {
"ram"
//console.log("Length:",getTime()-tStart); //console.log("Length:",getTime()-tStart);
Bangle.setPollInterval(80); // default poll interval Bangle.setPollInterval(80); // default poll interval
Bangle.accelWr(0x18, 0b01101100); // off, +-4g Bangle.accelWr(0x18, 0b01101100); // off, +-4g
@ -52,12 +62,15 @@ function recordStop() {"ram"
Bangle.accelWr(0x18, 0b11101100); // +-4g Bangle.accelWr(0x18, 0b11101100); // +-4g
Bangle.removeListener('accel', accelHandlerRecord); Bangle.removeListener('accel', accelHandlerRecord);
E.showMessage("Finished"); E.showMessage("Finished");
showData(); showData(true);
} }
function showData() { function showData(save_file) {
g.clear(1); g.clear(1);
let csv_files_N = require("Storage").list(/^acc.*\.csv$/).length;
let w_full = g.getWidth();
let h = g.getHeight();
var w = g.getWidth() - 20; // width var w = g.getWidth() - 20; // width
var m = g.getHeight() / 2; // middle var m = g.getHeight() / 2; // middle
var s = 12; // how many pixels per G var s = 12; // how many pixels per G
@ -71,7 +84,7 @@ function showData() {
for (var i = 0; i < SAMPLES; i++) for (var i = 0; i < SAMPLES; i++)
g.lineTo(10 + i * w / SAMPLES, m - a[i] * s / SCALE); g.lineTo(10 + i * w / SAMPLES, m - a[i] * s / SCALE);
} }
g.setColor("#0000ff"); g.setColor("#FFFA5F");
plot(accelz); plot(accelz);
g.setColor("#ff0000"); g.setColor("#ff0000");
plot(accelx); plot(accelx);
@ -80,28 +93,31 @@ function showData() {
// work out stats // work out stats
var maxAccel = 0; var maxAccel = 0;
var tStart = SAMPLES, tEnd = 0; var tStart = SAMPLES,
var vel = 0, maxVel = 0; tEnd = 0;
var max_YZ = 0;
for (var i = 0; i < SAMPLES; i++) { for (var i = 0; i < SAMPLES; i++) {
var a = accely[i]/SCALE; var a = Math.abs(accely[i] / SCALE);
let a_yz = Math.sqrt(Math.pow(accely[i] / SCALE, 2) + Math.pow(accelz[i] / SCALE, 2));
if (a > 0.1) { if (a > 0.1) {
if (i < tStart) tStart = i; if (i < tStart) tStart = i;
if (i > tEnd) tEnd = i; if (i > tEnd) tEnd = i;
} }
if (a > maxAccel) maxAccel = a; if (a > maxAccel) maxAccel = a;
vel += a/HZ; if (a_yz > max_YZ) max_YZ = a_yz;
if (vel>maxVel) maxVel=vel;
} }
g.reset(); g.reset();
g.setFont("6x8").setFontAlign(1, 0); g.setFont("6x8").setFontAlign(1, 0);
g.drawString("Max Y Accel: "+maxAccel.toFixed(2)+" g",g.getWidth()-14,g.getHeight()-50); g.drawString("Max X Accel: " + maxAccel.toFixed(2) + " g", g.getWidth() - 14, g.getHeight() - 50);
g.drawString("Max Y Vel: "+maxVel.toFixed(2)+" m/s",g.getWidth()-14,g.getHeight()-40); g.drawString("Max YZ Accel: " + max_YZ.toFixed(2) + " g", g.getWidth() - 14, g.getHeight() - 40);
g.drawString("Time moving: " + (tEnd - tStart) / HZ + " s", g.getWidth() - 14, g.getHeight() - 30); g.drawString("Time moving: " + (tEnd - tStart) / HZ + " s", g.getWidth() - 14, g.getHeight() - 30);
//console.log("End Velocity "+vel); g.setFont("6x8", 2).setFontAlign(0, 0);
g.drawString("File num: " + (csv_files_N + 1), w_full / 2, h - 20);
g.setFont("6x8").setFontAlign(0, 0, 1); g.setFont("6x8").setFontAlign(0, 0, 1);
g.drawString("FINISH", g.getWidth() - 4, g.getHeight() / 2); g.drawString("FINISH", g.getWidth() - 4, g.getHeight() / 2);
setWatch(function() { setWatch(function() {
showMenu(); if (save_file) showSaveMenu(); // when select only plot, don't ask for save option
else showMenu();
}, global.BTN2 ? BTN2 : BTN); }, global.BTN2 ? BTN2 : BTN);
} }
@ -133,20 +149,23 @@ function showMenu() {
E.showMenu(); E.showMenu();
if (accelIdx == 0) countDown(); if (accelIdx == 0) countDown();
else E.showPrompt("Overwrite Recording?").then(ok => { else E.showPrompt("Overwrite Recording?").then(ok => {
if (ok) countDown(); else showMenu(); if (ok) countDown();
else showMenu();
}); });
}, },
"Plot": function() { "Plot": function() {
E.showMenu(); E.showMenu();
if (accelIdx) showData(); if (accelIdx) showData(false);
else E.showAlert("No Data").then(() => { else E.showAlert("No Data").then(() => {
showMenu(); showMenu();
}); });
}, },
"Save" : function() { "Storage": function() {
E.showMenu(); E.showMenu();
if (accelIdx) showSaveMenu(); if (require("Storage").list(/^acc.*\.csv$/).length)
else E.showAlert("No Data").then(()=>{ StorageMenu();
else
E.showAlert("No Data").then(() => {
showMenu(); showMenu();
}); });
}, },
@ -158,22 +177,77 @@ function showMenu() {
} }
function showSaveMenu() { function showSaveMenu() {
var menu = { E.showPrompt("Save recording?").then(ok => {
"" : { title : "Save" } if (ok)
}; SaveFile();
[1,2,3,4,5,6].forEach(i=>{ else
var fn = "accelrec."+i+".csv"; showMenu();
var exists = require("Storage").read(fn)!==undefined; });
menu["Recording "+i+(exists?" *":"")] = function() { }
var csv = "";
function SaveFile() {
let csv_files_N = require("Storage").list(/^acc.*\.csv$/).length;
//if (csv_files_N > 20)
// E.showMessage("Storage is full");
// showMenu();
let csv = "";
let date = new Date();
let fn = "accelrec_" + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + "_" + (csv_files_N + 1) + ".csv";
E.showMessage("Saveing to file \n" + fn);
for (var i = 0; i < SAMPLES; i++) for (var i = 0; i < SAMPLES; i++)
csv += `${accelx[i]/SCALE},${accely[i]/SCALE},${accelz[i]/SCALE}\n`; csv += `${timestep[i]},${accelx[i]/SCALE},${accely[i]/SCALE},${accelz[i]/SCALE}\n`;
require("Storage").write(fn, csv); require("Storage").write(fn, csv);
showMenu(); showMenu();
}
//Show saved csv files
function StorageMenu() {
var menu = {
"": {
title: "Storage"
}
};
let csv_files = require("Storage").list(/^acc.*\.csv$/);
var inx = 0;
csv_files.forEach(fn => {
inx++;
menu[inx + ". " + fn] = function() {
StorageOptions(fn);
}; };
}); });
menu["< Back"] = function() {showMenu();}; menu["< Back"] = function() {
showMenu();
};
E.showMenu(menu); E.showMenu(menu);
} }
function StorageOptions(file) {
let menu = {
"": {
title: "Options"
},
"Plot": function() {
showMenu();
},
"Delete": function() {
E.showMenu();
E.showPrompt("Delete recording?").then(ok => {
if (ok)
DeleteRecord(file);
else
StorageMenu();
});
},
"< Back": function() {
StorageMenu();
},
};
E.showMenu(menu);
}
function DeleteRecord(file) {
E.showMessage("Deleteing file \n" + file);
require("Storage").erase(file);
StorageMenu();
}
showMenu(); showMenu();

View File

@ -37,7 +37,7 @@ function getData() {
</div>`; </div>`;
promise = promise.then(function() { promise = promise.then(function() {
document.querySelector(`.btn[fn='${fn}'][act='save']`).addEventListener("click", function() { document.querySelector(`.btn[fn='${fn}'][act='save']`).addEventListener("click", function() {
Util.saveCSV(fn.slice(0,-4), "X,Y,Z\n"+fileData[fn]); Util.saveCSV(fn.slice(0,-4), "Time,X,Y,Z\n"+fileData[fn]);
}); });
document.querySelector(`.btn[fn='${fn}'][act='delete']`).addEventListener("click", function() { document.querySelector(`.btn[fn='${fn}'][act='delete']`).addEventListener("click", function() {
Util.showModal("Deleting..."); Util.showModal("Deleting...");

View File

@ -2,7 +2,7 @@
"id": "accelrec", "id": "accelrec",
"name": "Acceleration Recorder", "name": "Acceleration Recorder",
"shortName": "Accel Rec", "shortName": "Accel Rec",
"version": "0.03", "version": "0.05",
"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.", "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", "icon": "app.png",
"tags": "", "tags": "",

View File

@ -0,0 +1 @@
0.01: Initial release.

View File

@ -0,0 +1,19 @@
# Accerleration Data Provider
This app provides acceleration data via Bluetooth, which can be used in Gadgetbridge.
## Usage
This boot code runs in the background and has no user interface.
Currently this app is used to enable Sleep as Android tracking for your Banglejs using Gadgetbridge.
**Please Note**: This app only listens to "accel" events and sends them to your phone using Bluetooth.
## Creator
[Another Stranger](https://github.com/anotherstranger)
## Aknowledgements
Special thanks to [José Rebelo](https://github.com/joserebelo) and [Rob Pilling](https://github.com/bobrippling)
for their Code Reviews and guidance.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

55
apps/accelsender/boot.js Normal file
View File

@ -0,0 +1,55 @@
(() => {
/**
* Sends a message to the gadgetbridge via Bluetooth.
* @param {Object} message - The message to be sent.
*/
function gbSend(message) {
try {
Bluetooth.println("");
Bluetooth.println(JSON.stringify(message));
} catch (error) {
console.error("Failed to send message via Bluetooth:", error);
}
}
var max_acceleration = { x: 0, y: 0, z: 0, diff: 0, td: 0, mag: 0 };
var hasData = false;
/**
* Updates the maximum acceleration if the current acceleration is greater.
* @param {Object} accel - The current acceleration object with x, y, z, and mag properties.
*/
function updateAcceleration(accel) {
hasData = true;
var current_max_raw = accel.mag;
var max_raw = max_acceleration.mag;
if (current_max_raw > max_raw) {
max_acceleration = accel;
}
}
/**
* Updates the acceleration data and sends it to gadgetbridge.
* Resets the maximum acceleration.
* Note: If your interval setting is too short, the last value gets sent again.
*/
function sendAccelerationData() {
var accel = hasData ? max_acceleration : Bangle.getAccel();
var update_data = {
t: "accel", accel: accel
};
gbSend(update_data);
max_acceleration = { x: 0, y: 0, z: 0, mag: 0, diff: 0, td: 0 };
hasData = false;
}
var config = require("Storage").readJSON("accelsender.json") || {};
if (config.enabled) { // Gadgetbridge needs to enable and disable tracking by writing {enabled: true} to "accelsender.json" and reloading
setInterval(sendAccelerationData, config.interval);
Bangle.on("accel", updateAcceleration); // Log all acceleration events
}
})();

1
apps/accelsender/boot.min.js vendored Normal file
View File

@ -0,0 +1 @@
(()=>{function e(a){c=!0;a.mag>b.mag&&(b=a)}function f(){var a={t:"accel",accel:c?b:Bangle.getAccel()};try{Bluetooth.println(""),Bluetooth.println(JSON.stringify(a))}catch(g){console.error("Failed to send message via Bluetooth:",g)}b={x:0,y:0,z:0,mag:0,diff:0,td:0};c=!1}var b={x:0,y:0,z:0,diff:0,td:0,mag:0},c=!1,d=require("Storage").readJSON("accelsender.json")||{};d.enabled&&(setInterval(f,d.interval),Bangle.on("accel",e))})();

View File

@ -0,0 +1,4 @@
{
"enabled": false,
"interval": 10000
}

View File

@ -0,0 +1,27 @@
{
"id": "accelsender",
"name": "Acceleration Data Provider",
"shortName": "Accel Data Provider",
"version": "0.01",
"description": "This app sends accelerometer and heart rate data from your Bangle.js via Bluetooth.",
"icon": "bluetooth.png",
"type": "bootloader",
"tags": "accel",
"supports": [
"BANGLEJS",
"BANGLEJS2"
],
"readme": "README.md",
"storage": [
{
"name": "accelsender.boot.js",
"url": "boot.min.js"
}
],
"data": [
{
"name": "accelsender.json",
"url": "config.json"
}
]
}

View File

@ -1,3 +1,5 @@
0.01: New App! 0.01: New App!
0.02: Faster maze generation 0.02: Faster maze generation
0.03: Avoid clearing bottom widgets 0.03: Avoid clearing bottom widgets
0.04: Minor code improvements
0.05: Minor code improvements

View File

@ -54,7 +54,7 @@ function Maze(n) {
// Abort if BTN1 pressed [grace period for menu] // Abort if BTN1 pressed [grace period for menu]
// (for some reason setWatch() fails inside constructor) // (for some reason setWatch() fails inside constructor)
if (ngroups<n*n-16 && digitalRead(BTN1)) { if (ngroups<n*n-16 && digitalRead(BTN1)) {
aborting = true; //aborting = true;
return; return;
} }
from_group = to_group = -1; from_group = to_group = -1;
@ -206,7 +206,7 @@ function Maze(n) {
return false; return false;
}; };
this.tick = function() { this.tick = function() {
accel = Bangle.getAccel(); let accel = Bangle.getAccel();
if (this.ball_x%this.wall_length) { if (this.ball_x%this.wall_length) {
this.try_move_horizontally(accel.x); this.try_move_horizontally(accel.x);
} else if (this.ball_y%this.wall_length) { } else if (this.ball_y%this.wall_length) {
@ -243,7 +243,7 @@ function timeToText(t) { // Courtesy of stopwatch app
return text; return text;
} }
let aborting = false; //let aborting = false;
let start_time = 0; let start_time = 0;
let duration = 0; let duration = 0;
let maze=null; let maze=null;
@ -261,13 +261,13 @@ Bangle.drawWidgets();
Bangle.setLocked(false); Bangle.setLocked(false);
Bangle.setLCDTimeout(0); Bangle.setLCDTimeout(0);
E.showMenu(mazeMenu); E.showMenu(mazeMenu);
let maze_interval = setInterval( /*let maze_interval =*/ setInterval(
function() { function() {
if (maze) { if (maze) {
if (digitalRead(BTN1) || maze.status==STATUS_ABORTED) { if (digitalRead(BTN1) || maze.status==STATUS_ABORTED) {
maze = null; maze = null;
start_time = duration = 0; start_time = duration = 0;
aborting = false; //aborting = false;
setTimeout(function() {E.showMenu(mazeMenu); }, 100); setTimeout(function() {E.showMenu(mazeMenu); }, 100);
return; return;
} }

View File

@ -1,7 +1,7 @@
{ "id": "acmaze", { "id": "acmaze",
"name": "AccelaMaze", "name": "AccelaMaze",
"shortName":"AccelaMaze", "shortName":"AccelaMaze",
"version":"0.03", "version": "0.05",
"description": "Tilt the watch to roll a ball through a maze.", "description": "Tilt the watch to roll a ball through a maze.",
"icon": "app.png", "icon": "app.png",
"tags": "game", "tags": "game",

View File

@ -7,3 +7,5 @@
0.07: Added settings to be able to hide line1 and line2 so there is no visible widget 0.07: Added settings to be able to hide line1 and line2 so there is no visible widget
0.08: Fixed zero steps issue caused by 0.07 0.08: Fixed zero steps issue caused by 0.07
0.09: Prettied up user interface, decluttered graphs 0.09: Prettied up user interface, decluttered graphs
0.10: Minor code improvements
0.11: Minor code improvements

View File

@ -136,7 +136,7 @@
function drawMenu() { function drawMenu() {
var x = 100; var x = 100;
var y = 24; var y = 24;
var stps ="-"; //var stps ="-";
var y_inc = 25; var y_inc = 25;
g.clear(); g.clear();

View File

@ -2,7 +2,7 @@
"id": "activepedom", "id": "activepedom",
"name": "Active Pedometer", "name": "Active Pedometer",
"shortName": "Active Pedometer", "shortName": "Active Pedometer",
"version": "0.09", "version": "0.11",
"description": "(NOT RECOMMENDED) 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. The `Health` app now provides step logging and graphs.", "description": "(NOT RECOMMENDED) 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. The `Health` app now provides step logging and graphs.",
"icon": "app.png", "icon": "app.png",
"tags": "outdoors,widget", "tags": "outdoors,widget",

View File

@ -3,7 +3,7 @@
var startTimeStep = new Date(); //set start time var startTimeStep = new Date(); //set start time
var stopTimeStep = 0; //Time after one step var stopTimeStep = 0; //Time after one step
var timerResetActive = 0; //timer to reset active var timerResetActive = 0; //timer to reset active
var timerStoreData = 0; //timer to store data //var timerStoreData = 0; //timer to store data
var steps = 0; //steps taken var steps = 0; //steps taken
var stepsCounted = 0; //active steps counted var stepsCounted = 0; //active steps counted
var active = 0; //x steps in y seconds achieved var active = 0; //x steps in y seconds achieved
@ -32,10 +32,10 @@
} }
function storeData() { function storeData() {
now = new Date(); let now = new Date();
month = now.getMonth() + 1; //month is 0-based let month = now.getMonth() + 1; //month is 0-based
if (month < 10) month = "0" + month; //leading 0 if (month < 10) month = "0" + month; //leading 0
filename = filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; //new file for each day let filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; //new file for each day
dataFile = s.open(filename,"a"); dataFile = s.open(filename,"a");
if (dataFile) { //check if filen already exists if (dataFile) { //check if filen already exists
if (dataFile.getLength() == 0) { if (dataFile.getLength() == 0) {
@ -223,6 +223,7 @@
}); });
// Read data from file and set variables // Read data from file and set variables
{ // new scope ensures pedomData gets freed
let pedomData = s.readJSON(PEDOMFILE,1); let pedomData = s.readJSON(PEDOMFILE,1);
if (pedomData) { if (pedomData) {
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate); if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
@ -231,10 +232,10 @@
stepsTooLong = pedomData.stepsTooLong; stepsTooLong = pedomData.stepsTooLong;
stepsOutsideTime = pedomData.stepsOutsideTime; stepsOutsideTime = pedomData.stepsOutsideTime;
} }
pedomdata = 0; //reset pedomdata to save memory }
setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive) setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive)
timerStoreData = setInterval(storeData, storeDataInterval); //store data regularly /*timerStoreData =*/ setInterval(storeData, storeDataInterval); //store data regularly
//Add widget, use: WIDGETS.activepedom.getSteps() inside another App to return todays step count //Add widget, use: WIDGETS.activepedom.getSteps() inside another App to return todays step count
WIDGETS["activepedom"]={area:"tl",width:width,draw:draw, getSteps:()=>stepsCounted}; WIDGETS["activepedom"]={area:"tl",width:width,draw:draw, getSteps:()=>stepsCounted};
})(); })();

View File

@ -9,3 +9,4 @@
0.09: New app screen (instead of showing settings or the alert) and some optimisations 0.09: New app screen (instead of showing settings or the alert) and some optimisations
0.10: Add software back button via setUI 0.10: Add software back button via setUI
0.11: Add setting to unlock screen 0.11: Add setting to unlock screen
0.12: Fix handling that dates can be given as ms since epoch.

View File

@ -29,16 +29,13 @@ exports.loadData = function () {
dismissDate: new Date(1970), dismissDate: new Date(1970),
pauseDate: new Date(1970), pauseDate: new Date(1970),
}, },
require("Storage").readJSON("activityreminder.data.json") || {}); require("Storage").readJSON("activityreminder.data.json") || {});
if (typeof (data.stepsDate) == "string") data.stepsDate = new Date(typeof data.stepsDate === 'string' ? data.stepsDate : data.stepsDate.ms);
data.stepsDate = new Date(data.stepsDate); data.okDate = new Date(typeof data.okDate === 'string' ? data.okDate : data.okDate.ms);
if (typeof (data.okDate) == "string") data.dismissDate = new Date(typeof data.dismissDate === 'string' ? data.dismissDate : data.dismissDate.ms);
data.okDate = new Date(data.okDate); data.pauseDate = new Date(typeof data.pauseDate === 'string' ? data.pauseDate : data.pauseDate.ms);
if (typeof (data.dismissDate) == "string")
data.dismissDate = new Date(data.dismissDate);
if (typeof (data.pauseDate) == "string")
data.pauseDate = new Date(data.pauseDate);
return data; return data;
}; };

View File

@ -3,10 +3,10 @@
"name": "Activity Reminder", "name": "Activity Reminder",
"shortName":"Activity Reminder", "shortName":"Activity Reminder",
"description": "A reminder to take short walks for the ones with a sedentary lifestyle", "description": "A reminder to take short walks for the ones with a sedentary lifestyle",
"version":"0.11", "version":"0.12",
"icon": "app.png", "icon": "app.png",
"type": "app", "type": "app",
"tags": "tool,activity", "tags": "tool,activity,health",
"supports": ["BANGLEJS", "BANGLEJS2"], "supports": ["BANGLEJS", "BANGLEJS2"],
"readme": "README.md", "readme": "README.md",
"storage": [ "storage": [

View File

@ -3,3 +3,4 @@
0.03: Tell clock widgets to hide. 0.03: Tell clock widgets to hide.
0.04: Swipe down to see widgets, step counter now just uses getHealthStatus 0.04: Swipe down to see widgets, step counter now just uses getHealthStatus
0.05: Report latest HRM rather than HRM 10 minutes ago (fix #2395) 0.05: Report latest HRM rather than HRM 10 minutes ago (fix #2395)
0.06: Use watch temperature

View File

@ -3,8 +3,7 @@
<img src="https://user-images.githubusercontent.com/2981891/175355586-1dfc0d66-6555-4385-b124-1605fdb71a11.jpg" width="250" /> <img src="https://user-images.githubusercontent.com/2981891/175355586-1dfc0d66-6555-4385-b124-1605fdb71a11.jpg" width="250" />
An over-engineered clock inspired by Casio watches.<br/> An over-engineered clock inspired by Casio watches.<br/>
It has a dedicated timer, a scratchpad and can display the weather condition 4 days ahead.<br/> It has a dedicated timer, a scratchpad and displays the current temperature.<br/>
It uses a <a target="_blank" href="https://dotgreg.github.io/advCasioBangleClock/">custom web app</a> to update its content.<br/>
Forked from the awesome Cassio Watch.<br/> Forked from the awesome Cassio Watch.<br/>
## Todo ## Todo
@ -21,7 +20,7 @@ Forked from the awesome Cassio Watch.<br/>
- Footsteps - Footsteps
- Battery - Battery
- Simple Timer embedded - Simple Timer embedded
- Weather forecast (7 days) - Current temperature
- Scratchpad - Scratchpad
## Screenshots ## Screenshots
@ -36,14 +35,6 @@ Web interface to update weather & scratchpad <br/>
<img src="https://user-images.githubusercontent.com/2981891/175519121-851bb209-7192-40db-a014-490c344f7597.jpg" width="250" /> <img src="https://user-images.githubusercontent.com/2981891/175519121-851bb209-7192-40db-a014-490c344f7597.jpg" width="250" />
## Usage ## Usage
### How to update the tasks list / weather
- you will need a <a target="_blank" href="https://openweathermap.org/price#weather">free openweathermap.org api key</a>.
- go to https://dotgreg.github.io/advCasioBangleClock/
- Alternatively you can install it on your own server/heroku/service/github pages, the web-app code is <a target="_blank" href="https://github.com/dotgreg/advCasioBangleClock/tree/master/web-app">here</a>
- fill the location and the api key (it will be saved on your browser, no need to do it each time)
- edit the scratchpad with what you want
- click on sync
- reload your clock!
### How to start/stop the timer ### How to start/stop the timer
- swipe up : add time (+5min) - swipe up : add time (+5min)

View File

@ -88,9 +88,9 @@ function drawRocket() {
function getTemperature(){ function getTemperature(){
try { try {
var weatherJson = storage.readJSON('weather.json'); var temperature = E.getTemperature()
var weather = weatherJson.weather; var formatted = require("locale").temp(temperature).replace(/[^\d-]/g, '');
return Math.round(weather.temp-273.15); return formatted;
} catch(ex) { } catch(ex) {
print(ex) print(ex)

View File

@ -1,8 +1,8 @@
{ "id": "advcasio", { "id": "advcasio",
"name": "Advanced Casio Clock", "name": "Advanced Casio Clock",
"shortName":"advcasio", "shortName":"advcasio",
"version":"0.05", "version":"0.06",
"description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.", "description": "An over-engineered clock inspired by Casio watches. It has current temperature, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.",
"icon": "app.png", "icon": "app.png",
"tags": "clock", "tags": "clock",
"type": "clock", "type": "clock",
@ -18,8 +18,5 @@
"storage": [ "storage": [
{"name":"advcasio.app.js","url":"app.js"}, {"name":"advcasio.app.js","url":"app.js"},
{"name":"advcasio.img","url":"app-icon.js","evaluate":true} {"name":"advcasio.img","url":"app-icon.js","evaluate":true}
],
"data": [
{ "name": "advcasio.data.json", "url": "data.json", "storageFile": true }
] ]
} }

View File

@ -14,3 +14,4 @@
0.12: Added color field and updating clkinfo periodically (running events) 0.12: Added color field and updating clkinfo periodically (running events)
0.13: Show day of the week in date 0.13: Show day of the week in date
0.14: Fixed "Today" and "Yesterday" wrongly displayed for allDay events on some time zones 0.14: Fixed "Today" and "Yesterday" wrongly displayed for allDay events on some time zones
0.15: Minor code improvements

View File

@ -15,14 +15,14 @@
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
var FILE = "android.calendar.json"; //var FILE = "android.calendar.json";
var Locale = require("locale"); var Locale = require("locale");
var fontSmall = "6x8"; //var fontSmall = "6x8";
var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2"; var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2";
var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2"; var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2";
var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4"; //var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
//FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?) //FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?)
var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[]; var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[];

View File

@ -1,7 +1,7 @@
{ {
"id": "agenda", "id": "agenda",
"name": "Agenda", "name": "Agenda",
"version": "0.14", "version": "0.15",
"description": "Simple agenda", "description": "Simple agenda",
"icon": "agenda.png", "icon": "agenda.png",
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],

View File

@ -49,3 +49,5 @@
0.44: Add "delete timer after expiration" setting to events. 0.44: Add "delete timer after expiration" setting to events.
0.45: Fix new alarm when selectedAlarm is undefined 0.45: Fix new alarm when selectedAlarm is undefined
0.46: Show alarm groups if the Show Group setting is ON. Scroll alarms menu back to previous position when getting back to it. 0.46: Show alarm groups if the Show Group setting is ON. Scroll alarms menu back to previous position when getting back to it.
0.47: Fix wrap around when snoozed through midnight
0.48: Use datetimeinput for Events, if available. Scroll back when getting out of group. Menu date format setting for shorter dates on current year.

View File

@ -2,7 +2,7 @@
This app allows you to add/modify any alarms, timers and events. This app allows you to add/modify any alarms, timers and events.
Optional: When a keyboard app is detected, you can add a message to display when any of these is triggered. Optional: When a keyboard app is detected, you can add a message to display when any of these is triggered. If a datetime input app (e.g. datetime_picker) is detected, it will be used for the selection of the date+time of events.
It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) to handle the alarm scheduling in an efficient way that can work alongside other apps. It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) to handle the alarm scheduling in an efficient way that can work alongside other apps.

View File

@ -28,6 +28,8 @@ const iconTimerOff = "\0" + (g.theme.dark
// An array of alarm objects (see sched/README.md) // An array of alarm objects (see sched/README.md)
var alarms = require("sched").getAlarms(); var alarms = require("sched").getAlarms();
// Fix possible wrap around in existing alarms #3281, broken alarms still needs to be saved to get fixed
alarms.forEach(e => e.t %= 86400000); // This can probably be removed in the future when we are sure there are no more broken alarms
function handleFirstDayOfWeek(dow) { function handleFirstDayOfWeek(dow) {
if (firstDayOfWeek == 1) { if (firstDayOfWeek == 1) {
@ -48,13 +50,17 @@ function handleFirstDayOfWeek(dow) {
alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow)); alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow));
function getLabel(e) { function getLabel(e) {
const dateStr = e.date && require("locale").date(new Date(e.date), 1); const dateStr = getDateText(e.date);
return (e.timer return (e.timer
? require("time_utils").formatDuration(e.timer) ? require("time_utils").formatDuration(e.timer)
: (dateStr ? `${dateStr}${e.rp?"*":""} ${require("time_utils").formatTime(e.t)}` : require("time_utils").formatTime(e.t) + (e.rp ? ` ${decodeRepeat(e)}` : "")) : (dateStr ? `${dateStr}${e.rp?"*":""} ${require("time_utils").formatTime(e.t)}` : require("time_utils").formatTime(e.t) + (e.rp ? ` ${decodeRepeat(e)}` : ""))
) + (e.msg ? ` ${e.msg}` : ""); ) + (e.msg ? ` ${e.msg}` : "");
} }
function getDateText(d) {
return d && (settings.menuDateFormat === "mmdd" ? d.substring(d.startsWith(new Date().getFullYear()) ? 5 : 0) : require("locale").date(new Date(d), 1));
}
function trimLabel(label, maxLength) { function trimLabel(label, maxLength) {
if(settings.showOverflow) return label; if(settings.showOverflow) return label;
return (label.length > maxLength return (label.length > maxLength
@ -73,10 +79,10 @@ function formatAlarmProperty(msg) {
} }
} }
function showMainMenu(scroll, group) { function showMainMenu(scroll, group, scrollback) {
const menu = { const menu = {
"": { "title": group || /*LANG*/"Alarms & Timers", scroll: scroll }, "": { "title": group || /*LANG*/"Alarms & Timers", scroll: scroll },
"< Back": () => group ? showMainMenu() : load(), "< Back": () => group ? showMainMenu(scrollback) : load(),
/*LANG*/"New...": () => showNewMenu(group) /*LANG*/"New...": () => showNewMenu(group)
}; };
const getGroups = settings.showGroup && !group; const getGroups = settings.showGroup && !group;
@ -96,7 +102,7 @@ function showMainMenu(scroll, group) {
}); });
if (!group) { if (!group) {
Object.keys(groups).sort().forEach(g => menu[g] = () => showMainMenu(null, g)); Object.keys(groups).sort().forEach(g => menu[g] = () => showMainMenu(null, g, scroller.scroll));
menu[/*LANG*/"Advanced"] = () => showAdvancedMenu(); menu[/*LANG*/"Advanced"] = () => showAdvancedMenu();
} }
@ -136,6 +142,8 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate, scroll, group) {
var title = date ? (isNew ? /*LANG*/"New Event" : /*LANG*/"Edit Event") : (isNew ? /*LANG*/"New Alarm" : /*LANG*/"Edit Alarm"); var title = date ? (isNew ? /*LANG*/"New Event" : /*LANG*/"Edit Event") : (isNew ? /*LANG*/"New Alarm" : /*LANG*/"Edit Alarm");
var keyboard = "textinput"; var keyboard = "textinput";
try {keyboard = require(keyboard);} catch(e) {keyboard = null;} try {keyboard = require(keyboard);} catch(e) {keyboard = null;}
var datetimeinput;
try {datetimeinput = require("datetimeinput");} catch(e) {datetimeinput = null;}
const menu = { const menu = {
"": { "title": title }, "": { "title": title },
@ -143,7 +151,28 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate, scroll, group) {
prepareAlarmForSave(alarm, alarmIndex, time, date); prepareAlarmForSave(alarm, alarmIndex, time, date);
saveAndReload(); saveAndReload();
showMainMenu(scroll, group); showMainMenu(scroll, group);
}, }
};
if (alarm.date && datetimeinput) {
menu[`${getDateText(date.toLocalISOString().slice(0,10))} ${require("time_utils").formatTime(time)}`] = {
value: date,
format: v => "",
onchange: v => {
setTimeout(() => {
var datetime = new Date(v.getTime());
datetime.setHours(time.h, time.m);
datetimeinput.input({datetime}).then(result => {
time.h = result.getHours();
time.m = result.getMinutes();
prepareAlarmForSave(alarm, alarmIndex, time, result, true);
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate, scroll, group);
});
}, 100);
}
};
} else {
Object.assign(menu, {
/*LANG*/"Hour": { /*LANG*/"Hour": {
value: time.h, value: time.h,
format: v => ("0" + v).substr(-2), format: v => ("0" + v).substr(-2),
@ -177,7 +206,11 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate, scroll, group) {
min: new Date().getFullYear(), min: new Date().getFullYear(),
max: 2100, max: 2100,
onchange: v => date.setFullYear(v) onchange: v => date.setFullYear(v)
}, }
});
}
Object.assign(menu, {
/*LANG*/"Message": { /*LANG*/"Message": {
value: alarm.msg, value: alarm.msg,
format: formatAlarmProperty, format: formatAlarmProperty,
@ -239,7 +272,7 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate, scroll, group) {
saveAndReload(); saveAndReload();
showMainMenu(scroll, group); showMainMenu(scroll, group);
} }
}; });
if (!keyboard) delete menu[/*LANG*/"Message"]; if (!keyboard) delete menu[/*LANG*/"Message"];
if (!keyboard || !settings.showGroup) delete menu[/*LANG*/"Group"]; if (!keyboard || !settings.showGroup) delete menu[/*LANG*/"Group"];
@ -497,7 +530,7 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
function prepareTimerForSave(timer, timerIndex, time, temp) { function prepareTimerForSave(timer, timerIndex, time, temp) {
timer.timer = require("time_utils").encodeTime(time); timer.timer = require("time_utils").encodeTime(time);
timer.t = require("time_utils").getCurrentTimeMillis() + timer.timer; timer.t = (require("time_utils").getCurrentTimeMillis() + timer.timer) % 86400000;
timer.last = 0; timer.last = 0;
if (!temp) { if (!temp) {

View File

@ -2,7 +2,7 @@
"id": "alarm", "id": "alarm",
"name": "Alarms & Timers", "name": "Alarms & Timers",
"shortName": "Alarms", "shortName": "Alarms",
"version": "0.46", "version": "0.48",
"description": "Set alarms and timers on your Bangle", "description": "Set alarms and timers on your Bangle",
"icon": "app.png", "icon": "app.png",
"tags": "tool,alarm", "tags": "tool,alarm",

View File

@ -1,2 +1,3 @@
0.01: New App! 0.01: New App!
0.02: Added adjustment for Bangle.js magnetometer heading fix 0.02: Added adjustment for Bangle.js magnetometer heading fix
0.03: Minor code improvements

View File

@ -145,7 +145,7 @@ Bangle.setCompassPower(1);
Bangle.setGPSPower(1); Bangle.setGPSPower(1);
g.clear(); g.clear();
process_GPS(); process_GPS();
var poll_GPS = setInterval(process_GPS, 9000); /*var poll_GPS =*/ setInterval(process_GPS, 9000);
setWatch(function () { setWatch(function () {
if (!button_lock) { if (!button_lock) {

View File

@ -1,7 +1,7 @@
{ {
"id": "alpinenav", "id": "alpinenav",
"name": "Alpine Nav", "name": "Alpine Nav",
"version": "0.02", "version": "0.03",
"description": "App that performs GPS monitoring to track and display position relative to a given origin in realtime", "description": "App that performs GPS monitoring to track and display position relative to a given origin in realtime",
"icon": "app-icon.png", "icon": "app-icon.png",
"tags": "outdoors,gps", "tags": "outdoors,gps",

View File

@ -0,0 +1,3 @@
0.01: New Clock!
0.02: Fix fastloading memory leak and clockinfo overwritten by hands
0.03: Use new clockinfo lib with function to render images wirh borders

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEw4X//8HA4IEBgH4C5cFqgJHitQjWpBY9q0gLvI5ar/AAkgBRMC1ALJlX6CxOrBZMq34LJ1f/9QKHhW//2gCxP6wAWHy/+KREqq4WIgGtr+qLhG1vw5IgX1KBALBywWIIwNaHJEAlNqUZOltAuJyouKqwuKrQuhywuJNIIuJlIuJHQLGIBYQ6IgtU1Q6GitQjWplQVGtWkBYIhHBcpHBBY5HBM5IABA"))

247
apps/analogquadclk/app.js Normal file
View File

@ -0,0 +1,247 @@
{
const W = g.getWidth();
const H = g.getHeight();
const background = require("clockbg"); // image backgrounds
let drawTimeout; // timeout used to update every minute
let date = new Date(); // date at last draw
let lastModified = {x1:0,y1:0,x2:W-1,y2:H-1,first:true}; // rect that was covered by hands
const HOUR_LEN = 55; // how far forwards does hand go?
const MIN_LEN = 72;
const HOUR_BACK = 10; // how far backwards dows hand go?
const MIN_BACK = 10;
const HOUR_W = 10; // width of cleared area
const MIN_W = 8;
const get_hand = function(len, w, cornerw, overhang) {
return new Int8Array([
0, overhang+w,
-cornerw, overhang+cornerw,
-w, overhang,
-w, -len,
-cornerw, -len - cornerw,
0, -len - w,
cornerw, -len - cornerw,
w, -len,
w, overhang,
cornerw, overhang+cornerw
]);
};
const hand_hour = get_hand(HOUR_LEN, 6, 4, HOUR_BACK);
const hand_hour_bg = get_hand(HOUR_LEN, HOUR_W, 8, HOUR_BACK);
const hand_minute = get_hand(MIN_LEN, 4, 3, MIN_BACK);
const hand_minute_bg = get_hand(MIN_LEN, MIN_W, 6, MIN_BACK);
// schedule a draw for the next minute
let queueDraw = function() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, 60000 - (Date.now() % 60000));
};
// draw the clock hands
let drawHands = function() {
let h = (date.getHours() + date.getMinutes()/60)*Math.PI/6, m = date.getMinutes()*Math.PI/30;
g.setColor(g.theme.bg).fillPolyAA(g.transformVertices(hand_hour_bg,{x:W/2,y:H/2,rotate:h}));
g.fillPolyAA(g.transformVertices(hand_minute_bg,{x:W/2,y:H/2,rotate:m}));
g.setColor("#f00").fillPolyAA(g.transformVertices(hand_hour,{x:W/2,y:H/2,rotate:h}));
g.setColor(g.theme.fg).fillPolyAA(g.transformVertices(hand_minute,{x:W/2,y:H/2,rotate:m}));
};
// return the screen area covered by clock hands (used for filling in background)
let getHandBounds = function() {
let h = (date.getHours() + date.getMinutes()/60)*Math.PI/6, m = date.getMinutes()*Math.PI/30;
let sh = Math.sin(h), ch = Math.cos(h), sm = Math.sin(m), cm = Math.cos(m);
return {
x1 : Math.round((W/2)+Math.min(sh*HOUR_LEN, sm*MIN_LEN, -sh*HOUR_BACK, -sm*MIN_BACK)-HOUR_W),
y1 : Math.round((H/2)-Math.max(ch*HOUR_LEN, cm*MIN_LEN, -ch*HOUR_BACK, -cm*MIN_BACK)-HOUR_W),
x2 : Math.round((W/2)+Math.max(sh*HOUR_LEN, sm*MIN_LEN, -sh*HOUR_BACK, -sm*MIN_BACK)+HOUR_W),
y2 : Math.round((H/2)-Math.min(ch*HOUR_LEN, cm*MIN_LEN, -ch*HOUR_BACK, -cm*MIN_BACK)+HOUR_W),
};
};
let draw = function() {
// queue next draw in one minute
queueDraw();
// work out locale-friendly date/time
date = new Date();
//var timeStr = require("locale").time(date,1);
//var dateStr = require("locale").date(date);
// fill in area that we changed last time
background.fillRect(lastModified.x1, lastModified.y1, lastModified.x2, lastModified.y2);
if (!lastModified.first) { // first draw we don't have clockInfoMenuA/etc defined
//print(lastModified);
if (lastModified.y1<40) {
if (lastModified.x1 < 40 ||
(lastModified.x1 < W/2 && lastModified.y1 < 16)) clockInfoMenuA.redraw();
if (lastModified.x2 > W-40 ||
(lastModified.x1 > W/2 && lastModified.y1 < 16)) clockInfoMenuB.redraw();
}
if (lastModified.y2>W-40) {
if (lastModified.x1 < 40 ||
(lastModified.x1 < W/2 && lastModified.y2>W-16)) clockInfoMenuD.redraw();
if (lastModified.x2 > W-40 ||
(lastModified.x1 > W/2 && lastModified.y2>W-16)) clockInfoMenuC.redraw();
}
}
// draw hands
drawHands();
lastModified = getHandBounds();
//g.drawRect(lastModified); // debug
};
// Clear the screen once, at startup
background.fillRect(0, 0, W - 1, H - 1);
// draw immediately at first, queue update
draw();
let clockInfoMenuA, clockInfoMenuB, clockInfoMenuC, clockInfoMenuD;
// Show launcher when middle button pressed
Bangle.setUI({
mode: "clock",
redraw : draw,
remove: function() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
if (clockInfoMenuA) clockInfoMenuA.remove();
if (clockInfoMenuB) clockInfoMenuB.remove();
if (clockInfoMenuC) clockInfoMenuC.remove();
if (clockInfoMenuD) clockInfoMenuD.remove();
require("widget_utils").show(); // re-show widgets
}
});
// Load widgets
Bangle.loadWidgets();
require("widget_utils").hide();
// render clockinfos
let clockInfoDraw = function(itm, info, options) {
// itm: the item containing name/hasRange/etc
// info: data returned from itm.get() containing text/img/etc
// options: options passed into addInteractive
const left = options.x < 88,
top = options.y < 88,
imgx = left ? 1 : W - 28, imgy = top ? 19 : H - 42,
textx = left ? 2 : W - 1, texty = top ? 2 : H - 16;
let bg = g.theme.bg, fg = g.theme.fg;
// Clear the background
g.reset();
background.fillRect(imgx, imgy, imgx+25, imgy+25); // erase image
background.fillRect(left?0:W/2, texty-1, left?W/2:W-1, texty+15); // erase text
// indicate focus - change colours
if (options.focus) {
bg = g.theme.fg;
fg = g.toColor("#f00");
}
if (info.img)
require("clock_info").drawBorderedImage(info.img,imgx,imgy);
g.setFont("6x8:2").setFontAlign(left ? -1 : 1, -1);
g.setColor(bg).drawString(info.text, textx-2, texty). // draw the text background
drawString(info.text, textx+2, texty).
drawString(info.text, textx, texty-2).
drawString(info.text, textx, texty+2);
g.setColor(fg).drawString(info.text, textx, texty); // draw the text
// redraw hands if needed
if ((top && lastModified.x1<texty+15) ||
(!top && lastModified.y2>=texty)) {
g.reset();
drawHands();
}
};
// Load the clock infos
let clockInfoItems = require("clock_info").load();
let clockInfoItemsBangle = clockInfoItems.find(i=>i.name=="Bangle");
// Add extra Calendar and digital clock ClockInfos
if (clockInfoItemsBangle) {
if (!clockInfoItemsBangle.items.find(i=>i.name=="Date")) {
clockInfoItemsBangle.items.push({ name : "Date",
get : () => {
let d = new Date();
let g = Graphics.createArrayBuffer(24,24,1,{msb:true});
g.drawImage(atob("FhgBDADAMAMP/////////////////////8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAP///////"),1,0);
g.setFont("6x15").setFontAlign(0,0).drawString(d.getDate(),11,17);
return {
text : require("locale").dow(d,1).toUpperCase(),
img : g.asImage("string")
};
},
show : function() {
this.interval = setTimeout(()=>{
this.emit("redraw");
this.interval = setInterval(()=>{
this.emit("redraw");
}, 86400000);
}, 86400000 - (Date.now() % 86400000));
},
hide : function() {
clearInterval(this.interval);
this.interval = undefined;
}
});
}
if (!clockInfoItemsBangle.items.find(i=>i.name=="Clock")) {
clockInfoItemsBangle.items.push({ name : "Clock",
get : () => {
return {
text : require("locale").time(new Date(),1),
img : atob("GBiBAAAAAAB+AAD/AAD/AAH/gAP/wAP/wAYAYAYAYAYAYAYAYAYAcAYAcAYAYAYAYAYAYAYAYAP/wAP/wAH/gAD/AAD/AAB+AAAAAA==")
};
},
show : function() {
this.interval = setTimeout(()=>{
this.emit("redraw");
this.interval = setInterval(()=>{
this.emit("redraw");
}, 60000);
}, 60000 - (Date.now() % 60000));
},
hide : function() {
clearInterval(this.interval);
this.interval = undefined;
}
});
}
}
// Add the 4 clockinfos
const CLOCKINFOSIZE = 50;
clockInfoMenuA = require("clock_info").addInteractive(clockInfoItems, {
x: 0,
y: 0,
w: CLOCKINFOSIZE,
h: CLOCKINFOSIZE,
draw: clockInfoDraw
});
clockInfoMenuB = require("clock_info").addInteractive(clockInfoItems, {
x: W - CLOCKINFOSIZE,
y: 0,
w: CLOCKINFOSIZE,
h: CLOCKINFOSIZE,
draw: clockInfoDraw
});
clockInfoMenuC = require("clock_info").addInteractive(clockInfoItems, {
x: W - CLOCKINFOSIZE,
y: H - CLOCKINFOSIZE,
w: CLOCKINFOSIZE,
h: CLOCKINFOSIZE,
draw: clockInfoDraw
});
clockInfoMenuD = require("clock_info").addInteractive(clockInfoItems, {
x: 0,
y: H - CLOCKINFOSIZE,
w: CLOCKINFOSIZE,
h: CLOCKINFOSIZE,
draw: clockInfoDraw
});
/*setInterval(function() {
date.ms += 60000; draw();
}, 500);*/
}

BIN
apps/analogquadclk/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,16 @@
{ "id": "analogquadclk",
"name": "Analog Quad Clock",
"shortName":"Quad Clock",
"version":"0.03",
"description": "An analog clock with clockinfos in each of the 4 corners, allowing 4 different data types to be rendered at once",
"icon": "icon.png",
"screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot2.png" } ],
"type": "clock",
"tags": "clock,clkinfo,analog,clockbg",
"supports" : ["BANGLEJS2"],
"dependencies" : { "clock_info":"module", "clockbg":"module" },
"storage": [
{"name":"analogquadclk.app.js","url":"app.js"},
{"name":"analogquadclk.img","url":"app-icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,4 +1,7 @@
0.01: Release 0.01: Release
0.02: Rename app 0.02: Rename app
0.03: Add type "clock" 0.03: Add type "clock"
0.04: changed update cylce, when locked 0.04: Changed update cylce, when locked
0.05: Fix support for dark theme + support widgets +
add settings for widgets, order of drawing and hour hand length
0.06: Fix issue showing widgets when app is fast-loaded into from launcher with widgets disabled

View File

@ -1,10 +1,16 @@
# Analog Clock # Dark Analog Clock
## Features ## Features
* second hand * second hand (only on unlocked screen)
* date * date
* battery percantage * battery percentage (showing charge status with color)
* no widgets * turned off or swipeable widgets (choose in settings)
![logo](andark_screen.png) ![logo](andark_screen.png)
## Settings
* whether to load widgets, or not; if widgets are loaded, they are swipeable from the top; if not, NO ACTIONS of widgets are available
* date and battery can be printed both below hands (as if hands were physical) and above (more readable)
* hour hand can be made slighly shorter to improve readability when minute hand is behind a number

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,5 +1,30 @@
const defaultSettings = {
loadWidgets : false,
textAboveHands : false,
shortHrHand : false
};
const settings = Object.assign(defaultSettings, require('Storage').readJSON('andark.json',1)||{});
const c={"x":g.getWidth()/2,"y":g.getHeight()/2}; const c={"x":g.getWidth()/2,"y":g.getHeight()/2};
let zahlpos=[];
const zahlpos=(function() {
let z=[];
let sk=1;
for(let i=-10;i<50;i+=5){
let win=i*2*Math.PI/60;
let xsk =c.x+2+Math.cos(win)*(c.x-10),
ysk =c.y+2+Math.sin(win)*(c.x-10);
if(sk==3){xsk-=10;}
if(sk==6){ysk-=10;}
if(sk==9){xsk+=10;}
if(sk==12){ysk+=10;}
if(sk==10){xsk+=3;}
z.push([sk,xsk,ysk]);
sk+=1;
}
return z;
})();
let unlock = false; let unlock = false;
function zeiger(len,dia,tim){ function zeiger(len,dia,tim){
@ -11,12 +36,8 @@ function zeiger(len,dia,tim){
} }
function draw(){ function drawHands(d) {
const d=new Date();
let m=d.getMinutes(), h=d.getHours(), s=d.getSeconds(); let m=d.getMinutes(), h=d.getHours(), s=d.getSeconds();
//draw black rectangle in the middle to clear screen from scale and hands
g.setColor(0,0,0);
g.fillRect(10,10,2*c.x-10,2*c.x-10);
g.setColor(1,1,1); g.setColor(1,1,1);
if(h>12){ if(h>12){
@ -29,15 +50,8 @@ function draw(){
m=2*Math.PI/60*(m)-Math.PI/2; m=2*Math.PI/60*(m)-Math.PI/2;
s=2*Math.PI/60*s-Math.PI/2; s=2*Math.PI/60*s-Math.PI/2;
g.setFontAlign(0,0);
g.setFont("Vector",10);
let dateStr = " "+require("locale").date(d)+" ";
g.drawString(dateStr, c.x, c.y+20, true);
// g.drawString(d.getDate(),1.4*c.x,c.y,true);
g.drawString(Math.round(E.getBattery()/5)*5+"%",c.x,c.y+40,true);
drawlet();
//g.setColor(1,0,0); //g.setColor(1,0,0);
const hz = zeiger(100,5,h); const hz = zeiger(settings.shortHrHand?88:100,5,h);
g.fillPoly(hz,true); g.fillPoly(hz,true);
//g.setColor(1,1,1); //g.setColor(1,1,1);
const minz = zeiger(150,5,m); const minz = zeiger(150,5,m);
@ -47,12 +61,53 @@ function draw(){
g.fillPoly(sekz,true); g.fillPoly(sekz,true);
} }
g.fillCircle(c.x,c.y,4); g.fillCircle(c.x,c.y,4);
} }
function drawText(d) {
g.setFont("Vector",10);
g.setBgColor(0,0,0);
g.setColor(1,1,1);
let dateStr = require("locale").date(d);
g.drawString(dateStr, c.x, c.y+20, true);
let batStr = Math.round(E.getBattery()/5)*5+"%";
if (Bangle.isCharging()) {
g.setBgColor(1,0,0);
}
g.drawString(batStr, c.x, c.y+40, true);
}
function drawNumbers() {
//draws the numbers on the screen
g.setFont("Vector",20);
g.setColor(1,1,1);
g.setBgColor(0,0,0);
for(let i = 0;i<12;i++){
g.drawString(zahlpos[i][0],zahlpos[i][1],zahlpos[i][2],true);
}
}
function draw(){
// draw black rectangle in the middle to clear screen from scale and hands
g.setColor(0,0,0);
g.fillRect(10,10,2*c.x-10,2*c.x-10);
// prepare for drawing the text
g.setFontAlign(0,0);
// do drawing
drawNumbers();
const d=new Date();
if (settings.textAboveHands) {
drawHands(d); drawText(d);
} else {
drawText(d); drawHands(d);
}
}
//draws the scale once the app is startet //draws the scale once the app is startet
function drawScale(){ function drawScale(){
// clear the screen
g.setBgColor(0,0,0);
g.clear();
// draw the ticks of the scale
for(let i=-14;i<47;i++){ for(let i=-14;i<47;i++){
const win=i*2*Math.PI/60; const win=i*2*Math.PI/60;
let d=2; let d=2;
@ -64,62 +119,34 @@ function drawScale(){
} }
} }
//draws the numbers on the screen //// main running sequence ////
function drawlet(){ // Show launcher when middle button pressed, and widgets that we're clock
g.setFont("Vector",20); Bangle.setUI("clock");
for(let i = 0;i<12;i++){ // Load widgets if needed, and make them show swipeable
g.drawString(zahlpos[i][0],zahlpos[i][1],zahlpos[i][2]); if (settings.loadWidgets) {
} Bangle.loadWidgets();
} require("widget_utils").swipeOn();
//calcultes the Position of the numbers when app starts and saves them in an array } else if (global.WIDGETS) require("widget_utils").hide();
function setlet(){
let sk=1;
for(let i=-10;i<50;i+=5){
let win=i*2*Math.PI/60;
let xsk =c.x+2+Math.cos(win)*(c.x-10),
ysk =c.y+2+Math.sin(win)*(c.x-10);
if(sk==3){xsk-=10;}
if(sk==6){ysk-=10;}
if(sk==9){xsk+=10;}
if(sk==12){ysk+=10;}
if(sk==10){xsk+=3;}
zahlpos.push([sk,xsk,ysk]);
sk+=1;
}
}
setlet();
// Clear the screen once, at startup // Clear the screen once, at startup
g.setBgColor(0,0,0);
g.clear();
drawScale(); drawScale();
draw(); draw();
let secondInterval = setInterval(draw, 1000); let secondInterval = setInterval(draw, 1000);
// Stop updates when LCD is off, restart when on
// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower',on=>{ Bangle.on('lcdPower',on=>{
if (secondInterval) clearInterval(secondInterval); if (secondInterval) clearInterval(secondInterval);
secondInterval = undefined; secondInterval = undefined;
if (on) { if (on) {
secondInterval = setInterval(draw, 1000); secondInterval = setInterval(draw, 1000);
draw(); // draw immediately draw(); // draw immediately
}else{
} }
}); });
Bangle.on('lock',on=>{ Bangle.on('lock',on=>{
unlock = !on;
if (secondInterval) clearInterval(secondInterval); if (secondInterval) clearInterval(secondInterval);
secondInterval = undefined; secondInterval = setInterval(draw, unlock ? 1000 : 60000);
if (!on) {
secondInterval = setInterval(draw, 1000);
unlock = true;
draw(); // draw immediately draw(); // draw immediately
}else{
secondInterval = setInterval(draw, 60000);
unlock = false;
draw();
}
}); });
Bangle.on('charging',on=>{draw();});
// Show launcher when middle button pressed
Bangle.setUI("clock");

View File

@ -1,15 +1,18 @@
{ "id": "andark", { "id": "andark",
"name": "Analog Dark", "name": "Analog Dark",
"shortName":"AnDark", "shortName":"AnDark",
"version":"0.04", "version":"0.06",
"description": "analog clock face without disturbing widgets", "description": "analog clock face without disturbing widgets",
"icon": "andark_icon.png", "icon": "andark_icon.png",
"type": "clock", "type": "clock",
"tags": "clock", "tags": "clock",
"supports" : ["BANGLEJS2"], "supports" : ["BANGLEJS2"],
"screenshots": [{"url":"andark_screen.png"}],
"readme": "README.md", "readme": "README.md",
"storage": [ "storage": [
{"name":"andark.app.js","url":"app.js"}, {"name":"andark.app.js","url":"app.js"},
{"name":"andark.settings.js","url":"settings.js"},
{"name":"andark.img","url":"app_icon.js","evaluate":true} {"name":"andark.img","url":"app_icon.js","evaluate":true}
] ],
"data": [{"name":"andark.json"}]
} }

28
apps/andark/settings.js Normal file
View File

@ -0,0 +1,28 @@
(function(back) {
const defaultSettings = {
loadWidgets : false,
textAboveHands : false,
shortHrHand : false
}
let settings = Object.assign(defaultSettings, require('Storage').readJSON('andark.json',1)||{});
const save = () => require('Storage').write('andark.json', settings);
const appMenu = {
'': {title: 'andark'}, '< Back': back,
/*LANG*/'Load widgets': {
value : !!settings.loadWidgets,
onchange : v => { settings.loadWidgets=v; save();}
},
/*LANG*/'Text above hands': {
value : !!settings.textAboveHands,
onchange : v => { settings.textAboveHands=v; save();}
},
/*LANG*/'Short hour hand': {
value : !!settings.shortHrHand,
onchange : v => { settings.shortHrHand=v; save();}
},
};
E.showMenu(appMenu);
});

View File

@ -33,3 +33,7 @@
0.31: Implement API for activity fetching 0.31: Implement API for activity fetching
0.32: Added support for loyalty cards from gadgetbridge 0.32: Added support for loyalty cards from gadgetbridge
0.33: Fix alarms created in Gadgetbridge not repeating 0.33: Fix alarms created in Gadgetbridge not repeating
0.34: Implement API for activity tracks fetching (Recorder app logs).
0.35: Implement API to enable/disable acceleration data tracking.
0.36: Move from wrapper function to {} and let - faster execution at boot
Allow `calendar-` to take an array of items to remove

View File

@ -44,6 +44,10 @@ The boot code also provides some useful functions:
* `id` - a custom (string) ID * `id` - a custom (string) ID
* `timeout` - a timeout for the request in milliseconds (default 30000ms) * `timeout` - a timeout for the request in milliseconds (default 30000ms)
* `xpath` an xPath query to run on the request (but right now the URL requested must be XML - HTML is rarely XML compliant) * `xpath` an xPath query to run on the request (but right now the URL requested must be XML - HTML is rarely XML compliant)
* `return` for xpath, if not specified, one result is returned. If `return:"array"` an array of results is returned.
* `method` HTTP method (default is `get`) - `get/post/head/put/patch/delete`
* `body` the body of the HTTP request
* `headers` an object of headers, eg `{HeaderOne : "headercontents"}`
eg: eg:

View File

@ -1,25 +1,28 @@
(function() { /* global GB */
function gbSend(message) { {
let gbSend = function(message) {
Bluetooth.println(""); Bluetooth.println("");
Bluetooth.println(JSON.stringify(message)); Bluetooth.println(JSON.stringify(message));
} }
var lastMsg; // for music messages - may not be needed now... let lastMsg; // for music messages - may not be needed now...
var actInterval; // Realtime activity reporting interval when `act` is true let actInterval; // Realtime activity reporting interval when `act` is true
var actHRMHandler; // For Realtime activity reporting let actHRMHandler; // For Realtime activity reporting
var gpsState = {}; // keep information on GPS via Gadgetbridge let gpsState = {}; // keep information on GPS via Gadgetbridge
// this settings var is deleted after this executes to save memory // this settings var is deleted after this executes to save memory
var settings = require("Storage").readJSON("android.settings.json",1)||{}; let settings = require("Storage").readJSON("android.settings.json",1)||{};
//default alarm settings //default alarm settings
if (settings.rp == undefined) settings.rp = true; if (settings.rp == undefined) settings.rp = true;
if (settings.as == undefined) settings.as = true; if (settings.as == undefined) settings.as = true;
if (settings.vibrate == undefined) settings.vibrate = ".."; if (settings.vibrate == undefined) settings.vibrate = "..";
require('Storage').writeJSON("android.settings.json", settings); require('Storage').writeJSON("android.settings.json", settings);
var _GB = global.GB; let _GB = global.GB;
let fetchRecInterval;
global.GB = (event) => { global.GB = (event) => {
// feed a copy to other handlers if there were any // feed a copy to other handlers if there were any
if (_GB) setTimeout(_GB,0,Object.assign({},event)); if (_GB) setTimeout(_GB,0,Object.assign({},event));
/* TODO: Call handling, fitness */ /* TODO: Call handling, fitness */
var HANDLERS = { var HANDLERS = {
// {t:"notify",id:int, src,title,subject,body,sender,tel:string} add // {t:"notify",id:int, src,title,subject,body,sender,tel:string} add
@ -119,6 +122,9 @@
var cal = require("Storage").readJSON("android.calendar.json",true); var cal = require("Storage").readJSON("android.calendar.json",true);
//if any of those happen we are out of sync! //if any of those happen we are out of sync!
if (!cal || !Array.isArray(cal)) cal = []; if (!cal || !Array.isArray(cal)) cal = [];
if (Array.isArray(event.id))
cal = cal.filter(e=>!event.id.includes(e.id));
else
cal = cal.filter(e=>e.id!=event.id); cal = cal.filter(e=>e.id!=event.id);
require("Storage").writeJSON("android.calendar.json", cal); require("Storage").writeJSON("android.calendar.json", cal);
}, },
@ -230,6 +236,49 @@
} }
gbSend({t: "actfetch", state: "end", count: actCount}); gbSend({t: "actfetch", state: "end", count: actCount});
}, },
//{t:"listRecs", id:"20230616a"}
"listRecs": function() {
let recs = require("Storage").list(/^recorder\.log.*\.csv$/,{sf:true}).map(s => s.slice(12, 21));
if (event.id.length > 2) { // Handle if there was no id supplied. Then we send a list all available recorder logs back.
let firstNonsyncedIdx = recs.findIndex((logId) => logId > event.id);
if (-1 == firstNonsyncedIdx) {
recs = []
} else {
recs = recs.slice(firstNonsyncedIdx);
}
}
gbSend({t:"actTrksList", list: recs}); // TODO: split up in multiple transmissions?
},
//{t:"fetchRec", id:"20230616a"}
"fetchRec": function() {
// TODO: Decide on what names keys should have.
if (fetchRecInterval) {
clearInterval(fetchRecInterval);
fetchRecInterval = undefined;
}
if (event.id=="stop") {
return
} else {
let log = require("Storage").open("recorder.log"+event.id+".csv","r");
let lines = "init";// = log.readLine();
let pkgcnt = 0;
gbSend({t:"actTrk", log:event.id, lines:"erase", cnt:pkgcnt}); // "erase" will prompt Gadgetbridge to erase the contents of a already fetched log so we can rewrite it without keeping lines from the previous (probably failed) fetch.
let sendlines = ()=>{
lines = log.readLine();
for (var i = 0; i < 3; i++) {
let line = log.readLine();
if (line) lines += line;
}
pkgcnt++;
gbSend({t:"actTrk", log:event.id, lines:lines, cnt:pkgcnt});
if (!lines && fetchRecInterval) {
clearInterval(fetchRecInterval);
fetchRecInterval = undefined;
}
}
fetchRecInterval = setInterval(sendlines, 50)
}
},
"nav": function() { "nav": function() {
event.id="nav"; event.id="nav";
if (event.instr) { if (event.instr) {
@ -247,6 +296,10 @@
// we receive all, just override what we have // we receive all, just override what we have
if (Array.isArray(event.d)) if (Array.isArray(event.d))
require("Storage").writeJSON("android.cards.json", event.d); require("Storage").writeJSON("android.cards.json", event.d);
},
"accelsender": function () {
require("Storage").writeJSON("accelsender.json", {enabled: event.enable, interval: event.interval});
load();
} }
}; };
var h = HANDLERS[event.t]; var h = HANDLERS[event.t];
@ -287,7 +340,7 @@
}; };
// Battery monitor // Battery monitor
function sendBattery() { gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); } let sendBattery = function() { gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); }
Bangle.on("charging", sendBattery); Bangle.on("charging", sendBattery);
NRF.on("connect", () => setTimeout(function() { NRF.on("connect", () => setTimeout(function() {
sendBattery(); sendBattery();
@ -382,4 +435,4 @@
// remove settings object so it's not taking up RAM // remove settings object so it's not taking up RAM
delete settings; delete settings;
})(); }

View File

@ -2,7 +2,7 @@
"id": "android", "id": "android",
"name": "Android Integration", "name": "Android Integration",
"shortName": "Android", "shortName": "Android",
"version": "0.33", "version": "0.36",
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
"icon": "app.png", "icon": "app.png",
"tags": "tool,system,messages,notifications,gadgetbridge", "tags": "tool,system,messages,notifications,gadgetbridge",

Some files were not shown because too many files have changed in this diff Show More