Merge branch 'master' of github.com:wagnerf42/BangleApps
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
28
README.md
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New Widget!
|
0.01: New Widget!
|
||||||
|
0.02: Minor code improvements
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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 });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Minor code improvements
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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=="));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Minor code improvements
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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') {
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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); },
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -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();
|
|
||||||
|
|
@ -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"],
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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"}],
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: Initial version
|
0.01: Initial version
|
||||||
|
0.02: Add settings page; Add line break to update message
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,6 @@ Bangle.on('swipe',(swiperight, swipedown)=>{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var drawTimeout;
|
|
||||||
var showInstructions = true;
|
var showInstructions = true;
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,179 +1,253 @@
|
||||||
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;
|
||||||
if (a.mag*2>THRESH) { // *2 because 8g mode
|
|
||||||
tStart = getTime();
|
|
||||||
g.drawString("Recording",g.getWidth()/2,g.getHeight()/2,1);
|
|
||||||
Bangle.removeListener('accel',accelHandlerTrigger);
|
|
||||||
Bangle.on('accel',accelHandlerRecord);
|
|
||||||
lastAccel.forEach(accelHandlerRecord);
|
|
||||||
accelHandlerRecord(a);
|
|
||||||
} else {
|
|
||||||
if (lastAccel.length>10) lastAccel.shift();
|
|
||||||
lastAccel.push(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function accelHandlerRecord(a) {"ram"
|
|
||||||
var i = accelIdx++;
|
|
||||||
accelx[i] = a.x*SCALE*2;
|
|
||||||
accely[i] = -a.y*SCALE*2;
|
|
||||||
accelz[i] = a.z*SCALE*2;
|
|
||||||
if (accelIdx>=SAMPLES) recordStop();
|
|
||||||
}
|
|
||||||
function recordStart() {"ram"
|
|
||||||
Bangle.setLCDTimeout(0); // force LCD on
|
|
||||||
accelIdx = 0;
|
|
||||||
lastAccel = [];
|
|
||||||
Bangle.accelWr(0x18,0b01110100); // off, +-8g
|
|
||||||
Bangle.accelWr(0x1B,0x03 | 0x40); // 100hz output, ODR/2 filter
|
|
||||||
Bangle.accelWr(0x18,0b11110100); // +-8g
|
|
||||||
Bangle.setPollInterval(10); // 100hz input
|
|
||||||
setTimeout(function() {
|
|
||||||
Bangle.on('accel',accelHandlerTrigger);
|
|
||||||
g.clear(1).setFont("6x8",2).setFontAlign(0,0);
|
|
||||||
g.drawString("Waiting",g.getWidth()/2,g.getHeight()/2);
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function accelHandlerTrigger(a) {
|
||||||
function recordStop() {"ram"
|
"ram"
|
||||||
//console.log("Length:",getTime()-tStart);
|
if (a.mag * 2 > THRESH) { // *2 because 8g mode
|
||||||
Bangle.setPollInterval(80); // default poll interval
|
timestep_start = getTime();
|
||||||
Bangle.accelWr(0x18,0b01101100); // off, +-4g
|
g.drawString("Recording", g.getWidth() / 2, g.getHeight() / 2, 1);
|
||||||
Bangle.accelWr(0x1B,0x0); // default 12.5hz output
|
Bangle.removeListener('accel', accelHandlerTrigger);
|
||||||
Bangle.accelWr(0x18,0b11101100); // +-4g
|
Bangle.on('accel', accelHandlerRecord);
|
||||||
Bangle.removeListener('accel',accelHandlerRecord);
|
lastAccel.forEach(accelHandlerRecord);
|
||||||
E.showMessage("Finished");
|
accelHandlerRecord(a);
|
||||||
showData();
|
} else {
|
||||||
}
|
if (lastAccel.length > 10) lastAccel.shift();
|
||||||
|
lastAccel.push(a);
|
||||||
|
|
||||||
function showData() {
|
|
||||||
g.clear(1);
|
|
||||||
var w = g.getWidth()-20; // width
|
|
||||||
var m = g.getHeight()/2; // middle
|
|
||||||
var s = 12; // how many pixels per G
|
|
||||||
g.fillRect(9,0,9,g.getHeight());
|
|
||||||
g.setFontAlign(0,0);
|
|
||||||
for (var l=-8;l<=8;l++)
|
|
||||||
g.drawString(l, 5, m - l*s);
|
|
||||||
|
|
||||||
function plot(a) {
|
|
||||||
g.moveTo(10,m - a[0]*s/SCALE);
|
|
||||||
for (var i=0;i<SAMPLES;i++)
|
|
||||||
g.lineTo(10+i*w/SAMPLES, m - a[i]*s/SCALE);
|
|
||||||
}
|
|
||||||
g.setColor("#0000ff");
|
|
||||||
plot(accelz);
|
|
||||||
g.setColor("#ff0000");
|
|
||||||
plot(accelx);
|
|
||||||
g.setColor("#00ff00");
|
|
||||||
plot(accely);
|
|
||||||
|
|
||||||
// work out stats
|
|
||||||
var maxAccel = 0;
|
|
||||||
var tStart = SAMPLES, tEnd = 0;
|
|
||||||
var vel = 0, maxVel = 0;
|
|
||||||
for (var i=0;i<SAMPLES;i++) {
|
|
||||||
var a = accely[i]/SCALE;
|
|
||||||
if (a>0.1) {
|
|
||||||
if (i<tStart) tStart=i;
|
|
||||||
if (i>tEnd) tEnd=i;
|
|
||||||
}
|
}
|
||||||
if (a>maxAccel) maxAccel=a;
|
}
|
||||||
vel += a/HZ;
|
|
||||||
if (vel>maxVel) maxVel=vel;
|
function accelHandlerRecord(a) {
|
||||||
}
|
"ram"
|
||||||
g.reset();
|
var i = accelIdx++;
|
||||||
g.setFont("6x8").setFontAlign(1,0);
|
accelx[i] = a.x * SCALE * 2; // *2 because of 8g mode
|
||||||
g.drawString("Max Y Accel: "+maxAccel.toFixed(2)+" g",g.getWidth()-14,g.getHeight()-50);
|
accely[i] = -a.y * SCALE * 2;
|
||||||
g.drawString("Max Y Vel: "+maxVel.toFixed(2)+" m/s",g.getWidth()-14,g.getHeight()-40);
|
accelz[i] = a.z * SCALE * 2;
|
||||||
g.drawString("Time moving: "+(tEnd-tStart)/HZ+" s",g.getWidth()-14,g.getHeight()-30);
|
timestep[i] = (getTime() - timestep_start) * 1000;
|
||||||
//console.log("End Velocity "+vel);
|
if (accelIdx >= SAMPLES) recordStop();
|
||||||
g.setFont("6x8").setFontAlign(0,0,1);
|
}
|
||||||
g.drawString("FINISH",g.getWidth()-4,g.getHeight()/2);
|
|
||||||
setWatch(function() {
|
function recordStart() {
|
||||||
showMenu();
|
"ram"
|
||||||
}, global.BTN2?BTN2:BTN);
|
Bangle.setLCDTimeout(0); // force LCD on
|
||||||
|
accelIdx = 0;
|
||||||
|
lastAccel = [];
|
||||||
|
Bangle.accelWr(0x18, 0b01110100); // off, +-8g
|
||||||
|
Bangle.accelWr(0x1B, 0x03 | 0x40); // 100hz output, ODR/2 filter
|
||||||
|
Bangle.accelWr(0x18, 0b11110100); // +-8g
|
||||||
|
Bangle.setPollInterval(10); // 100hz input
|
||||||
|
setTimeout(function() {
|
||||||
|
Bangle.on('accel', accelHandlerTrigger);
|
||||||
|
g.clear(1).setFont("6x8", 2).setFontAlign(0, 0);
|
||||||
|
g.drawString("Waiting", g.getWidth() / 2, g.getHeight() / 2);
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function recordStop() {
|
||||||
|
"ram"
|
||||||
|
//console.log("Length:",getTime()-tStart);
|
||||||
|
Bangle.setPollInterval(80); // default poll interval
|
||||||
|
Bangle.accelWr(0x18, 0b01101100); // off, +-4g
|
||||||
|
Bangle.accelWr(0x1B, 0x0); // default 12.5hz output
|
||||||
|
Bangle.accelWr(0x18, 0b11101100); // +-4g
|
||||||
|
Bangle.removeListener('accel', accelHandlerRecord);
|
||||||
|
E.showMessage("Finished");
|
||||||
|
showData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showData(save_file) {
|
||||||
|
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 m = g.getHeight() / 2; // middle
|
||||||
|
var s = 12; // how many pixels per G
|
||||||
|
g.fillRect(9, 0, 9, g.getHeight());
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
for (var l = -8; l <= 8; l++)
|
||||||
|
g.drawString(l, 5, m - l * s);
|
||||||
|
|
||||||
|
function plot(a) {
|
||||||
|
g.moveTo(10, m - a[0] * s / SCALE);
|
||||||
|
for (var i = 0; i < SAMPLES; i++)
|
||||||
|
g.lineTo(10 + i * w / SAMPLES, m - a[i] * s / SCALE);
|
||||||
|
}
|
||||||
|
g.setColor("#FFFA5F");
|
||||||
|
plot(accelz);
|
||||||
|
g.setColor("#ff0000");
|
||||||
|
plot(accelx);
|
||||||
|
g.setColor("#00ff00");
|
||||||
|
plot(accely);
|
||||||
|
|
||||||
|
// work out stats
|
||||||
|
var maxAccel = 0;
|
||||||
|
var tStart = SAMPLES,
|
||||||
|
tEnd = 0;
|
||||||
|
var max_YZ = 0;
|
||||||
|
for (var i = 0; i < SAMPLES; i++) {
|
||||||
|
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 (i < tStart) tStart = i;
|
||||||
|
if (i > tEnd) tEnd = i;
|
||||||
|
}
|
||||||
|
if (a > maxAccel) maxAccel = a;
|
||||||
|
if (a_yz > max_YZ) max_YZ = a_yz;
|
||||||
|
}
|
||||||
|
g.reset();
|
||||||
|
g.setFont("6x8").setFontAlign(1, 0);
|
||||||
|
g.drawString("Max X Accel: " + maxAccel.toFixed(2) + " g", g.getWidth() - 14, g.getHeight() - 50);
|
||||||
|
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.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.drawString("FINISH", g.getWidth() - 4, g.getHeight() / 2);
|
||||||
|
setWatch(function() {
|
||||||
|
if (save_file) showSaveMenu(); // when select only plot, don't ask for save option
|
||||||
|
else showMenu();
|
||||||
|
}, global.BTN2 ? BTN2 : BTN);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showBig(txt) {
|
function showBig(txt) {
|
||||||
g.clear(1);
|
g.clear(1);
|
||||||
g.setFontVector(80).setFontAlign(0,0);
|
g.setFontVector(80).setFontAlign(0, 0);
|
||||||
g.drawString(txt,g.getWidth()/2, g.getHeight()/2);
|
g.drawString(txt, g.getWidth() / 2, g.getHeight() / 2);
|
||||||
g.flip();
|
g.flip();
|
||||||
}
|
}
|
||||||
|
|
||||||
function countDown() {
|
function countDown() {
|
||||||
showBig(3);
|
showBig(3);
|
||||||
setTimeout(function() {
|
|
||||||
showBig(2);
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
showBig(1);
|
showBig(2);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
recordStart();
|
showBig(1);
|
||||||
}, 800);
|
setTimeout(function() {
|
||||||
|
recordStart();
|
||||||
|
}, 800);
|
||||||
|
}, 1000);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMenu() {
|
function showMenu() {
|
||||||
Bangle.setLCDTimeout(10); // set timeout for LCD in menu
|
Bangle.setLCDTimeout(10); // set timeout for LCD in menu
|
||||||
var menu = {
|
var menu = {
|
||||||
"" : { title : "Acceleration Rec" },
|
"": { title: "Acceleration Rec" },
|
||||||
"Start" : function() {
|
"Start": function() {
|
||||||
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() {
|
},
|
||||||
E.showMenu();
|
"Plot": function() {
|
||||||
if (accelIdx) showData();
|
E.showMenu();
|
||||||
else E.showAlert("No Data").then(()=>{
|
if (accelIdx) showData(false);
|
||||||
showMenu();
|
else E.showAlert("No Data").then(() => {
|
||||||
});
|
showMenu();
|
||||||
},
|
});
|
||||||
"Save" : function() {
|
},
|
||||||
E.showMenu();
|
"Storage": function() {
|
||||||
if (accelIdx) showSaveMenu();
|
E.showMenu();
|
||||||
else E.showAlert("No Data").then(()=>{
|
if (require("Storage").list(/^acc.*\.csv$/).length)
|
||||||
showMenu();
|
StorageMenu();
|
||||||
});
|
else
|
||||||
},
|
E.showAlert("No Data").then(() => {
|
||||||
"Exit" : function() {
|
showMenu();
|
||||||
load();
|
});
|
||||||
},
|
},
|
||||||
};
|
"Exit": function() {
|
||||||
E.showMenu(menu);
|
load();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = "";
|
|
||||||
for (var i=0;i<SAMPLES;i++)
|
|
||||||
csv += `${accelx[i]/SCALE},${accely[i]/SCALE},${accelz[i]/SCALE}\n`;
|
|
||||||
require("Storage").write(fn,csv);
|
|
||||||
showMenu();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
menu["< Back"] = function() {showMenu();};
|
|
||||||
E.showMenu(menu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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++)
|
||||||
|
csv += `${timestep[i]},${accelx[i]/SCALE},${accely[i]/SCALE},${accelz[i]/SCALE}\n`;
|
||||||
|
require("Storage").write(fn, csv);
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
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();
|
||||||
|
|
@ -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...");
|
||||||
|
|
|
||||||
|
|
@ -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": "",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: Initial release.
|
||||||
|
|
@ -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.
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
@ -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))})();
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"enabled": false,
|
||||||
|
"interval": 10000
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
@ -222,19 +222,20 @@
|
||||||
if (on) WIDGETS["activepedom"].draw();
|
if (on) WIDGETS["activepedom"].draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
//Read data from file and set variables
|
// Read data from file and set variables
|
||||||
let pedomData = s.readJSON(PEDOMFILE,1);
|
{ // new scope ensures pedomData gets freed
|
||||||
if (pedomData) {
|
let pedomData = s.readJSON(PEDOMFILE,1);
|
||||||
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
|
if (pedomData) {
|
||||||
stepsCounted = pedomData.stepsToday|0;
|
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
|
||||||
stepsTooShort = pedomData.stepsTooShort;
|
stepsCounted = pedomData.stepsToday|0;
|
||||||
stepsTooLong = pedomData.stepsTooLong;
|
stepsTooShort = pedomData.stepsTooShort;
|
||||||
stepsOutsideTime = pedomData.stepsOutsideTime;
|
stepsTooLong = pedomData.stepsTooLong;
|
||||||
|
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};
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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") || {});
|
|
||||||
|
|
||||||
if (typeof (data.stepsDate) == "string")
|
require("Storage").readJSON("activityreminder.data.json") || {});
|
||||||
data.stepsDate = new Date(data.stepsDate);
|
|
||||||
if (typeof (data.okDate) == "string")
|
data.stepsDate = new Date(typeof data.stepsDate === 'string' ? data.stepsDate : data.stepsDate.ms);
|
||||||
data.okDate = new Date(data.okDate);
|
data.okDate = new Date(typeof data.okDate === 'string' ? data.okDate : data.okDate.ms);
|
||||||
if (typeof (data.dismissDate) == "string")
|
data.dismissDate = new Date(typeof data.dismissDate === 'string' ? data.dismissDate : data.dismissDate.ms);
|
||||||
data.dismissDate = new Date(data.dismissDate);
|
data.pauseDate = new Date(typeof data.pauseDate === 'string' ? data.pauseDate : data.pauseDate.ms);
|
||||||
if (typeof (data.pauseDate) == "string")
|
|
||||||
data.pauseDate = new Date(data.pauseDate);
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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": [
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)||[];
|
||||||
|
|
|
||||||
|
|
@ -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"}],
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,41 +151,66 @@ 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);
|
||||||
},
|
}
|
||||||
/*LANG*/"Hour": {
|
};
|
||||||
value: time.h,
|
|
||||||
format: v => ("0" + v).substr(-2),
|
if (alarm.date && datetimeinput) {
|
||||||
min: 0,
|
menu[`${getDateText(date.toLocalISOString().slice(0,10))} ${require("time_utils").formatTime(time)}`] = {
|
||||||
max: 23,
|
value: date,
|
||||||
wrap: true,
|
format: v => "",
|
||||||
onchange: v => time.h = v
|
onchange: v => {
|
||||||
},
|
setTimeout(() => {
|
||||||
/*LANG*/"Minute": {
|
var datetime = new Date(v.getTime());
|
||||||
value: time.m,
|
datetime.setHours(time.h, time.m);
|
||||||
format: v => ("0" + v).substr(-2),
|
datetimeinput.input({datetime}).then(result => {
|
||||||
min: 0,
|
time.h = result.getHours();
|
||||||
max: 59,
|
time.m = result.getMinutes();
|
||||||
wrap: true,
|
prepareAlarmForSave(alarm, alarmIndex, time, result, true);
|
||||||
onchange: v => time.m = v
|
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate, scroll, group);
|
||||||
},
|
});
|
||||||
/*LANG*/"Day": {
|
}, 100);
|
||||||
value: date ? date.getDate() : null,
|
}
|
||||||
min: 1,
|
};
|
||||||
max: 31,
|
} else {
|
||||||
wrap: true,
|
Object.assign(menu, {
|
||||||
onchange: v => date.setDate(v)
|
/*LANG*/"Hour": {
|
||||||
},
|
value: time.h,
|
||||||
/*LANG*/"Month": {
|
format: v => ("0" + v).substr(-2),
|
||||||
value: date ? date.getMonth() + 1 : null,
|
min: 0,
|
||||||
format: v => require("date_utils").month(v),
|
max: 23,
|
||||||
onchange: v => date.setMonth((v+11)%12)
|
wrap: true,
|
||||||
},
|
onchange: v => time.h = v
|
||||||
/*LANG*/"Year": {
|
},
|
||||||
value: date ? date.getFullYear() : null,
|
/*LANG*/"Minute": {
|
||||||
min: new Date().getFullYear(),
|
value: time.m,
|
||||||
max: 2100,
|
format: v => ("0" + v).substr(-2),
|
||||||
onchange: v => date.setFullYear(v)
|
min: 0,
|
||||||
},
|
max: 59,
|
||||||
|
wrap: true,
|
||||||
|
onchange: v => time.m = v
|
||||||
|
},
|
||||||
|
/*LANG*/"Day": {
|
||||||
|
value: date ? date.getDate() : null,
|
||||||
|
min: 1,
|
||||||
|
max: 31,
|
||||||
|
wrap: true,
|
||||||
|
onchange: v => date.setDate(v)
|
||||||
|
},
|
||||||
|
/*LANG*/"Month": {
|
||||||
|
value: date ? date.getMonth() + 1 : null,
|
||||||
|
format: v => require("date_utils").month(v),
|
||||||
|
onchange: v => date.setMonth((v+11)%12)
|
||||||
|
},
|
||||||
|
/*LANG*/"Year": {
|
||||||
|
value: date ? date.getFullYear() : null,
|
||||||
|
min: new Date().getFullYear(),
|
||||||
|
max: 2100,
|
||||||
|
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) {
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEw4X//8HA4IEBgH4C5cFqgJHitQjWpBY9q0gLvI5ar/AAkgBRMC1ALJlX6CxOrBZMq34LJ1f/9QKHhW//2gCxP6wAWHy/+KREqq4WIgGtr+qLhG1vw5IgX1KBALBywWIIwNaHJEAlNqUZOltAuJyouKqwuKrQuhywuJNIIuJlIuJHQLGIBYQ6IgtU1Q6GitQjWplQVGtWkBYIhHBcpHBBY5HBM5IABA"))
|
||||||
|
|
@ -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);*/
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -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}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
|
@ -1,22 +1,43 @@
|
||||||
|
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){
|
||||||
const x =c.x+ Math.cos(tim)*len/2,
|
const x=c.x+ Math.cos(tim)*len/2,
|
||||||
y =c.y + Math.sin(tim)*len/2,
|
y=c.y + Math.sin(tim)*len/2,
|
||||||
d={"d":3,"x":dia/2*Math.cos(tim+Math.PI/2),"y":dia/2*Math.sin(tim+Math.PI/2)},
|
d={"d":3,"x":dia/2*Math.cos(tim+Math.PI/2),"y":dia/2*Math.sin(tim+Math.PI/2)},
|
||||||
pol=[c.x-d.x,c.y-d.y,c.x+d.x,c.y+d.y,x+d.x,y+d.y,x-d.x,y-d.y];
|
pol=[c.x-d.x,c.y-d.y,c.x+d.x,c.y+d.y,x+d.x,y+d.y,x-d.x,y-d.y];
|
||||||
return pol;
|
return pol;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,30 +50,64 @@ 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);
|
||||||
g.fillPoly(minz,true);
|
g.fillPoly(minz,true);
|
||||||
if (unlock){
|
if (unlock){
|
||||||
const sekz = zeiger(150,2,s);
|
const sekz = zeiger(150,2,s);
|
||||||
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) {
|
draw(); // draw immediately
|
||||||
secondInterval = setInterval(draw, 1000);
|
});
|
||||||
unlock = true;
|
Bangle.on('charging',on=>{draw();});
|
||||||
draw(); // draw immediately
|
|
||||||
}else{
|
|
||||||
secondInterval = setInterval(draw, 60000);
|
|
||||||
unlock = false;
|
|
||||||
draw();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Show launcher when middle button pressed
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
|
||||||
|
|
@ -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"}]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
});
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,7 +122,10 @@
|
||||||
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 = [];
|
||||||
cal = cal.filter(e=>e.id!=event.id);
|
if (Array.isArray(event.id))
|
||||||
|
cal = cal.filter(e=>!event.id.includes(e.id));
|
||||||
|
else
|
||||||
|
cal = cal.filter(e=>e.id!=event.id);
|
||||||
require("Storage").writeJSON("android.calendar.json", cal);
|
require("Storage").writeJSON("android.calendar.json", cal);
|
||||||
},
|
},
|
||||||
//triggered by GB, send all ids
|
//triggered by GB, send all ids
|
||||||
|
|
@ -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;
|
||||||
})();
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||