Merge branch 'master' into development
|
@ -1,11 +1,8 @@
|
||||||
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
|
||||||
|
apps/gipy/pkg/gps.d.ts
|
||||||
|
apps/gipy/pkg/gps_bg.wasm.d.ts
|
||||||
|
|
||||||
|
# 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",
|
||||||
|
@ -89,6 +112,7 @@
|
||||||
"getSerial": "readonly",
|
"getSerial": "readonly",
|
||||||
"getTime": "readonly",
|
"getTime": "readonly",
|
||||||
"global": "readonly",
|
"global": "readonly",
|
||||||
|
"globalThis": "readonly",
|
||||||
"HIGH": "readonly",
|
"HIGH": "readonly",
|
||||||
"I2C1": "readonly",
|
"I2C1": "readonly",
|
||||||
"Infinity": "readonly",
|
"Infinity": "readonly",
|
||||||
|
@ -129,7 +153,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 +202,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
|
||||||
|
|
29
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.
|
||||||
|
@ -278,6 +280,7 @@ and which gives information about the app for the Launcher.
|
||||||
// 'bluetooth' - uses Bluetooth LE
|
// 'bluetooth' - uses Bluetooth LE
|
||||||
// 'system' - used by the system
|
// 'system' - used by the system
|
||||||
// 'clkinfo' - provides or uses clock_info module for data on your clock face or clocks that support it (see apps/clock_info/README.md)
|
// 'clkinfo' - provides or uses clock_info module for data on your clock face or clocks that support it (see apps/clock_info/README.md)
|
||||||
|
// 'health' - e.g. heart rate monitors or step counting
|
||||||
"supports": ["BANGLEJS2"], // List of device IDs supported, either BANGLEJS or BANGLEJS2
|
"supports": ["BANGLEJS2"], // List of device IDs supported, either BANGLEJS or BANGLEJS2
|
||||||
"dependencies" : { "notify":"type" } // optional, app 'types' we depend on (see "type" above)
|
"dependencies" : { "notify":"type" } // optional, app 'types' we depend on (see "type" above)
|
||||||
"dependencies" : { "messages":"app" } // optional, depend on a specific app ID
|
"dependencies" : { "messages":"app" } // optional, depend on a specific app ID
|
||||||
|
@ -402,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() {
|
||||||
|
@ -553,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)
|
||||||
|
|
21
android.html
|
@ -2,7 +2,7 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=0.8,maximum-scale=0.8, minimum-scale=0.8, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
||||||
<link rel="stylesheet" href="css/spectre.min.css">
|
<link rel="stylesheet" href="css/spectre.min.css">
|
||||||
<link rel="stylesheet" href="css/spectre-exp.min.css">
|
<link rel="stylesheet" href="css/spectre-exp.min.css">
|
||||||
<link rel="stylesheet" href="css/spectre-icons.min.css">
|
<link rel="stylesheet" href="css/spectre-icons.min.css">
|
||||||
|
@ -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>
|
||||||
|
@ -84,6 +84,7 @@
|
||||||
<label class="chip tooltip" filterid="outdoors" data-tooltip="For outdoor use">Outdoors</label>
|
<label class="chip tooltip" filterid="outdoors" data-tooltip="For outdoor use">Outdoors</label>
|
||||||
<label class="chip tooltip" filterid="ram" data-tooltip="Apps that don't save anything to flash memory">Online</label>
|
<label class="chip tooltip" filterid="ram" data-tooltip="Apps that don't save anything to flash memory">Online</label>
|
||||||
<label class="chip tooltip" filterid="clkinfo" data-tooltip="Info displayed on clocks, or clocks with info">Clock Info</label>
|
<label class="chip tooltip" filterid="clkinfo" data-tooltip="Info displayed on clocks, or clocks with info">Clock Info</label>
|
||||||
|
<label class="chip tooltip" filterid="health" data-tooltip="Apps for your health">Health</label>
|
||||||
<label class="chip tooltip" filterid="favourites" data-tooltip="Apps that you've liked ❤️">Favourites</label>
|
<label class="chip tooltip" filterid="favourites" data-tooltip="Apps that you've liked ❤️">Favourites</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="sort-nav hidden">
|
<div class="sort-nav hidden">
|
||||||
|
@ -176,9 +177,13 @@
|
||||||
</label>
|
</label>
|
||||||
<label class="form-switch">
|
<label class="form-switch">
|
||||||
<input type="checkbox" id="settings-alwaysAllowUpdate">
|
<input type="checkbox" id="settings-alwaysAllowUpdate">
|
||||||
<i class="form-icon"></i> Always allow to reinstall apps in place regardless of the version
|
<i class="form-icon"></i> Always show "reinstall app" button <i class="icon icon-refresh"></i> regardless of the version
|
||||||
</label>
|
</label>
|
||||||
<button class="btn" id="defaultsettings">Reset to default App Loader settings</button>
|
<label class="form-switch">
|
||||||
|
<input type="checkbox" id="settings-autoReload">
|
||||||
|
<i class="form-icon"></i> Automatically reload watch after app App Loader actions (removes "Hold button" prompt)
|
||||||
|
</label>
|
||||||
|
<button class="btn" id="defaultsettings">Reset App Loader settings to defaults</button>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
<div id="more-deviceinfo" style="display:none">
|
<div id="more-deviceinfo" style="display:none">
|
||||||
|
@ -243,12 +248,14 @@ if (typeof Android!=="undefined") {
|
||||||
hadData : false,
|
hadData : false,
|
||||||
handlers : []
|
handlers : []
|
||||||
}
|
}
|
||||||
|
connection.on("data", function(d) {
|
||||||
|
connection.received += d;
|
||||||
|
connection.hadData = true;
|
||||||
|
if (connection.cb) connection.cb(d);
|
||||||
|
});
|
||||||
|
|
||||||
function bangleRx(data) {
|
function bangleRx(data) {
|
||||||
// document.getElementById("status").innerText = "RX:"+data;
|
// document.getElementById("status").innerText = "RX:"+data;
|
||||||
connection.received += data;
|
|
||||||
connection.hadData = true;
|
|
||||||
if (connection.cb) connection.cb(data);
|
|
||||||
// call data event
|
// call data event
|
||||||
if (connection.handlers["data"])
|
if (connection.handlers["data"])
|
||||||
connection.handlers["data"](data);
|
connection.handlers["data"](data);
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"shortName":"3DClock",
|
"shortName":"3DClock",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.01",
|
"version":"0.01",
|
||||||
"description": "This is a simple 3D scalig demo based on Anton Clock",
|
"description": "This is a simple 3D scaling demo based on Anton Clock",
|
||||||
"screenshots" : [ { "url":"screenshot.png" }],
|
"screenshots" : [ { "url":"screenshot.png" }],
|
||||||
"type":"clock",
|
"type":"clock",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
After Width: | Height: | Size: 983 B |
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
|
@ -0,0 +1 @@
|
||||||
|
atob("MDCBAAAAAAAAAAAAAAAAAAAAH/AAAAAAf/4AAAAB4AeAAAAHgAHgAAAOAABwAAAcAAA4AAA4AMAcAABwAMAOAABgA/AGAADAAeADAAHAAMADgAGAAAABgAGAAAABgAMAAAAAwAMBAAAAwAMDAAAAwAMHwAAAwAMHwAAAwAMDAACAwAMBAADAwAMAAAPgwAMAAAPgwAMAAADAwAGAAACBgAGAAAABgAHAAAADgADAAAADAADgAAAHAAB////+AAB////+AABgAAAGAABgAAAGAABgAAAGAADAAAADAADAAAADAADAAAADAAGAAAABgAGAAAABgAH/////gAP/////wAYAAAAAYAYAAAAAYAf/////4AP/////wAAAAAAAAAAAAAAAAA==")
|
|
@ -0,0 +1,92 @@
|
||||||
|
var keyboard = "textinput";
|
||||||
|
var Name = "";
|
||||||
|
Bangle.setLCDTimeout(0);
|
||||||
|
var menuOpen = 1;
|
||||||
|
var answers = new Array("no", "yes","WHAT????","What do you think", "That was a bad question", "YES!!!", "NOOOOO!!", "nope","100%","yup","why should I answer that?","think for yourself","ask again later, I'm busy", "what Was that horrible question","how dare you?","you wanted to hear yes? okay, yes", "Don't get angry when I say no","you are 100% wrong","totally, for sure","hmmm... I'll ponder it and get back to you later","wow, you really have a lot of questions", "NOPE","is the sky blue, hmmm...","I don't have time to answer","How many more questions before you change my name?","theres this thing called wikipedia","hmm... I don't seem to be able to reach the internet right now","if you phrase it like that, yes","Huh, never thought so hard in my life","The winds of time say no");
|
||||||
|
var consonants = new Array("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z");
|
||||||
|
var vowels = new Array("a","e","i","o","u");
|
||||||
|
try {keyboard = require(keyboard);} catch(e) {keyboard = null;}
|
||||||
|
function generateName()
|
||||||
|
{
|
||||||
|
Name = "";
|
||||||
|
var nameLength = Math.round(Math.random()*5);
|
||||||
|
for(var i = 0; i < nameLength; i++){
|
||||||
|
var cosonant = consonants[Math.round(Math.random()*consonants.length/2)];
|
||||||
|
var vowel = vowels[Math.round(Math.random()*vowels.length/2)];
|
||||||
|
Name = Name + cosonant + vowel;
|
||||||
|
if(Name == "")
|
||||||
|
{
|
||||||
|
generateName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generateName();
|
||||||
|
function menu()
|
||||||
|
{
|
||||||
|
g.clear();
|
||||||
|
E.showMenu();
|
||||||
|
menuOpen = 1;
|
||||||
|
E.showMenu({
|
||||||
|
"" : { title : Name },
|
||||||
|
"< Back" : () => menu(),
|
||||||
|
"Start" : () => {
|
||||||
|
E.showMenu();
|
||||||
|
g.clear();
|
||||||
|
menuOpen = 0;
|
||||||
|
Drawtext("ask " + Name + " a yes or no question");
|
||||||
|
},
|
||||||
|
"regenerate name" : () => {
|
||||||
|
menu();
|
||||||
|
generateName();
|
||||||
|
},
|
||||||
|
"show answers" : () => {
|
||||||
|
var menu = new Array([]);
|
||||||
|
for(var i = 0; i < answers.length; i++){
|
||||||
|
menu.push({title : answers[i]});
|
||||||
|
}
|
||||||
|
E.showMenu(menu);
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
"Add answer" : () => {
|
||||||
|
E.showMenu();
|
||||||
|
keyboard.input({}).then(result => {if(result != ""){answers.push(result);} menu();});
|
||||||
|
},
|
||||||
|
"Edit name" : () => {
|
||||||
|
E.showMenu();
|
||||||
|
keyboard.input({}).then(result => {if(result != ""){Name = result;} menu();});
|
||||||
|
|
||||||
|
},
|
||||||
|
"Exit" : () => load(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
menu();
|
||||||
|
|
||||||
|
var answer;
|
||||||
|
function Drawtext(text)
|
||||||
|
{
|
||||||
|
g.clear();
|
||||||
|
g.setFont("Vector", 20);
|
||||||
|
g.drawString(g.wrapString(text, g.getWidth(), -20).join("\n"));
|
||||||
|
}
|
||||||
|
function WriteAnswer()
|
||||||
|
{
|
||||||
|
if (menuOpen == 0)
|
||||||
|
{
|
||||||
|
var randomnumber = Math.round(Math.random()*answers.length);
|
||||||
|
answer = answers[randomnumber];
|
||||||
|
Drawtext(answer);
|
||||||
|
setTimeout(function() {
|
||||||
|
Drawtext("ask " + Name + " a yes or no question");
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
setWatch(function() {
|
||||||
|
menu();
|
||||||
|
|
||||||
|
}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true, edge:"falling"});
|
||||||
|
|
||||||
|
Bangle.on('touch', function(button, xy) { WriteAnswer(); });
|
|
@ -0,0 +1,19 @@
|
||||||
|
{ "id": "8ball",
|
||||||
|
"name": "Magic 8 ball",
|
||||||
|
"shortName":"8ball",
|
||||||
|
"icon": "8ball.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"screenshots": [
|
||||||
|
{"url":"screenshot.png"},
|
||||||
|
{"url":"screenshot-1.png"},
|
||||||
|
{"url":"screenshot-2.png"}
|
||||||
|
],
|
||||||
|
"allow_emulator": true,
|
||||||
|
"description": "A very sarcastic magic 8ball",
|
||||||
|
"tags": "game",
|
||||||
|
"supports": ["BANGLEJS2"],
|
||||||
|
"storage": [
|
||||||
|
{"name":"8ball.app.js","url":"app.js"},
|
||||||
|
{"name":"8ball.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.7 KiB |
|
@ -21,7 +21,6 @@
|
||||||
'< Back': back,
|
'< Back': back,
|
||||||
'Full Screen': {
|
'Full Screen': {
|
||||||
value: settings.fullscreen,
|
value: settings.fullscreen,
|
||||||
format: () => (settings.fullscreen ? 'Yes' : 'No'),
|
|
||||||
onchange: () => {
|
onchange: () => {
|
||||||
settings.fullscreen = !settings.fullscreen;
|
settings.fullscreen = !settings.fullscreen;
|
||||||
save();
|
save();
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: Change log created
|
|
@ -0,0 +1,18 @@
|
||||||
|
Tyreid
|
||||||
|
|
||||||
|
Tyreid is a Bluetooth war-driving app for the Bangle.js 2.
|
||||||
|
|
||||||
|
Menu options:
|
||||||
|
- Start: This turns on the Bluetooth and starts logging Bluetooth packets with time, latitude, and longitude information to a CSV file.
|
||||||
|
- Pause/Continue: These functions pause the capture and then allow it to resume.
|
||||||
|
- Devices: When paused this menu option will display the MAC addresses of discovered Bluetooth devices. Selecting a device will then display the MAC, Manufacturer code, the time it was first seen, and the RSSI of the first sighting.
|
||||||
|
- Marker: This command adds a 'marker' to the CSV log, which consists of the time and location information, but the Bluetooth packet information is replaced with the word MARKER. Markers can also be added by pressing the watch's button.
|
||||||
|
- Exit: This exits the app.
|
||||||
|
|
||||||
|
The current number of discovered devices is displayed in the top left corner.
|
||||||
|
This value is displayed in green when the GPS has a fix, or red otherwise.
|
||||||
|
|
||||||
|
To retrieve the CSV file, connect to the watch through the Espruino web IDE (https://www.espruino.com/ide/). From there the files stored on the watch can be downloaded by clicking the storage icon in the IDE's central column.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
E.toArrayBuffer(atob("MDACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAtAAAAAAAAAAAAAAB/QAAAAAAAAAAAAAD/0AAAAAAAAAAAAAH+9AAAAAAAAAAAAAPtfQAAAAAAAAAAAAudH0AAAAAAAAAAAB8tB9AAAAAAAAAAAD0tAfQAAAAAAAAAAHgtAH0AAAAAAAAAAPAtAB9AAAAAAAAAAtAtAAfQAAAAAAAAB8AtAAH0AAAAAAAAD0AtAAB9AAAAAAAALgAtAAAfQAAAAAAAfAAtAAAH0AAAAAAA9AAtAAAB9AAAAAAC4AAtAAAAfQAAAAADwAAtAAAALwAAAAAAQAAtAAAAvgAAAAAAAAAsAAAC9AAAAAAAAAAsAAAP0AAAAAAAAAAsAAB/AAAAAAAAAAAsAAH4AAAAAAAAAAAsAAvQAAAAAAAAAAAsAD9AAAAAAAAAAAAsAD0AAAAAAAAAAAAsAB8AAAAAAAAAAAAsAAtAAAAAAAAAAAAsAAPQAAAAAAAAAAAsAAHwAAAAAAAAAAAsAAC4AAAAAAAAAAAsAAA9AAAAAAAAAAAsAAAPAAAAAAAAAAAsAAAHgAAAAAAAAAA8AAAC0AAAAAAAAAA8AAAA8AAAAAAAAAA8AAAAEAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
|
|
@ -0,0 +1,14 @@
|
||||||
|
{ "id": "Tyreid",
|
||||||
|
"name": "Tyreid",
|
||||||
|
"shortName":"Tyreid",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "Bluetooth war-driving app for Bangle.js 2",
|
||||||
|
"icon": "small_logo.png",
|
||||||
|
"tags": "",
|
||||||
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"Tyreid.app.js","url":"app.js"},
|
||||||
|
{"name":"Tyreid.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 8.2 KiB |
|
@ -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",
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.01: New Widget!
|
0.01: New Clock Info!
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New Clock!
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Clock Name
|
||||||
|
|
||||||
|
More info on making Clock Faces: https://www.espruino.com/Bangle.js+Clock
|
||||||
|
|
||||||
|
Describe the Clock...
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Describe how to use it
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Name the function
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
Name the buttons and what they are used for
|
||||||
|
|
||||||
|
## Requests
|
||||||
|
|
||||||
|
Name who should be contacted for support/update requests
|
||||||
|
|
||||||
|
## Creator
|
||||||
|
|
||||||
|
Your name
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))
|
|
@ -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();
|
||||||
|
}
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,16 @@
|
||||||
|
{ "id": "7chname",
|
||||||
|
"name": "My clock human readable name",
|
||||||
|
"shortName":"Short Name",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "A detailed description of my clock",
|
||||||
|
"icon": "icon.png",
|
||||||
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock",
|
||||||
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"7chname.app.js","url":"app.js"},
|
||||||
|
{"name":"7chname.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
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"}],
|
||||||
|
|
|
@ -45,3 +45,9 @@
|
||||||
0.40: Use substring of message when it's longer than fits the designated menu entry.
|
0.40: Use substring of message when it's longer than fits the designated menu entry.
|
||||||
0.41: Fix a menu bug affecting alarms with empty messages.
|
0.41: Fix a menu bug affecting alarms with empty messages.
|
||||||
0.42: Fix date not getting saved in event edit menu when tapping Confirm
|
0.42: Fix date not getting saved in event edit menu when tapping Confirm
|
||||||
|
0.43: New settings: Show confirm, Show Overflow, Show Group.
|
||||||
|
0.44: Add "delete timer after expiration" setting to events.
|
||||||
|
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.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.
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master
|
||||||
- `Repeat` → Select when the alarm will fire. You can select a predefined option (_Once_, _Every Day_, _Workdays_ or _Weekends_ or you can configure the days freely)
|
- `Repeat` → Select when the alarm will fire. You can select a predefined option (_Once_, _Every Day_, _Workdays_ or _Weekends_ or you can configure the days freely)
|
||||||
- `New Timer` → Configure a new timer (triggered based on amount of time elapsed in hours/minutes/seconds)
|
- `New Timer` → Configure a new timer (triggered based on amount of time elapsed in hours/minutes/seconds)
|
||||||
- `New Event` → Configure a new event (triggered based on time and date)
|
- `New Event` → Configure a new event (triggered based on time and date)
|
||||||
- `Repeat` → Alarm can be be fired only once or repeated (every X number of _days_, _weeks_, _months_ or _years_)
|
- `Repeat` → Alarm can be fired only once or repeated (every X number of _days_, _weeks_, _months_ or _years_)
|
||||||
- `Advanced`
|
- `Advanced`
|
||||||
- `Scheduler settings` → Open the [Scheduler](https://github.com/espruino/BangleApps/tree/master/apps/sched) settings page, see its [README](https://github.com/espruino/BangleApps/blob/master/apps/sched/README.md) for details
|
- `Scheduler settings` → Open the [Scheduler](https://github.com/espruino/BangleApps/tree/master/apps/sched) settings page, see its [README](https://github.com/espruino/BangleApps/blob/master/apps/sched/README.md) for details
|
||||||
- `Enable All` → Enable _all_ disabled alarms & timers
|
- `Enable All` → Enable _all_ disabled alarms & timers
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
|
|
||||||
|
const settings = Object.assign({
|
||||||
|
showConfirm : true,
|
||||||
|
showAutoSnooze : true,
|
||||||
|
showHidden : true
|
||||||
|
}, require('Storage').readJSON('alarm.json',1)||{});
|
||||||
// 0 = Sunday (default), 1 = Monday
|
// 0 = Sunday (default), 1 = Monday
|
||||||
const firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0;
|
const firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0;
|
||||||
const WORKDAYS = 62;
|
const WORKDAYS = 62;
|
||||||
|
@ -23,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) {
|
||||||
|
@ -43,20 +50,26 @@ 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;
|
||||||
return (label.length > maxLength
|
return (label.length > maxLength
|
||||||
? label.substring(0,maxLength-3) + "..."
|
? label.substring(0,maxLength-3) + "..."
|
||||||
: label.substring(0,maxLength));
|
: label.substring(0,maxLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatAlarmMessage(msg) {
|
function formatAlarmProperty(msg) {
|
||||||
|
if(settings.showOverflow) return msg;
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
return msg;
|
return msg;
|
||||||
} else if (msg.length > 7) {
|
} else if (msg.length > 7) {
|
||||||
|
@ -66,39 +79,57 @@ function formatAlarmMessage(msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMainMenu() {
|
function showMainMenu(scroll, group, scrollback) {
|
||||||
const menu = {
|
const menu = {
|
||||||
"": { "title": /*LANG*/"Alarms & Timers" },
|
"": { "title": group || /*LANG*/"Alarms & Timers", scroll: scroll },
|
||||||
"< Back": () => load(),
|
"< Back": () => group ? showMainMenu(scrollback) : load(),
|
||||||
/*LANG*/"New...": () => showNewMenu()
|
/*LANG*/"New...": () => showNewMenu(group)
|
||||||
};
|
};
|
||||||
|
const getGroups = settings.showGroup && !group;
|
||||||
|
const groups = getGroups ? {} : undefined;
|
||||||
|
var showAlarm;
|
||||||
|
|
||||||
alarms.forEach((e, index) => {
|
alarms.forEach((e, index) => {
|
||||||
menu[trimLabel(getLabel(e),40)] = {
|
showAlarm = !settings.showGroup || (group ? e.group === group : !e.group);
|
||||||
value: e.on ? (e.timer ? iconTimerOn : iconAlarmOn) : (e.timer ? iconTimerOff : iconAlarmOff),
|
if(showAlarm) {
|
||||||
onchange: () => setTimeout(e.timer ? showEditTimerMenu : showEditAlarmMenu, 10, e, index)
|
menu[trimLabel(getLabel(e),40)] = {
|
||||||
};
|
value: e.on ? (e.timer ? iconTimerOn : iconAlarmOn) : (e.timer ? iconTimerOff : iconAlarmOff),
|
||||||
|
onchange: () => setTimeout(e.timer ? showEditTimerMenu : showEditAlarmMenu, 10, e, index, undefined, scroller.scroll, group)
|
||||||
|
};
|
||||||
|
} else if (getGroups) {
|
||||||
|
groups[e.group] = undefined;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
menu[/*LANG*/"Advanced"] = () => showAdvancedMenu();
|
if (!group) {
|
||||||
|
Object.keys(groups).sort().forEach(g => menu[g] = () => showMainMenu(null, g, scroller.scroll));
|
||||||
|
menu[/*LANG*/"Advanced"] = () => showAdvancedMenu();
|
||||||
|
}
|
||||||
|
|
||||||
E.showMenu(menu);
|
var scroller = E.showMenu(menu).scroller;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNewMenu() {
|
function showNewMenu(group) {
|
||||||
E.showMenu({
|
const newMenu = {
|
||||||
"": { "title": /*LANG*/"New..." },
|
"": { "title": /*LANG*/"New..." },
|
||||||
"< Back": () => showMainMenu(),
|
"< Back": () => showMainMenu(group),
|
||||||
/*LANG*/"Alarm": () => showEditAlarmMenu(undefined, undefined),
|
/*LANG*/"Alarm": () => showEditAlarmMenu(undefined, undefined, false, null, group),
|
||||||
/*LANG*/"Timer": () => showEditTimerMenu(undefined, undefined),
|
/*LANG*/"Timer": () => showEditTimerMenu(undefined, undefined),
|
||||||
/*LANG*/"Event": () => showEditAlarmMenu(undefined, undefined, true)
|
/*LANG*/"Event": () => showEditAlarmMenu(undefined, undefined, true, null, group)
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (group) delete newMenu[/*LANG*/"Timer"];
|
||||||
|
E.showMenu(newMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) {
|
function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate, scroll, group) {
|
||||||
var isNew = alarmIndex === undefined;
|
var isNew = alarmIndex === undefined;
|
||||||
|
|
||||||
var alarm = require("sched").newDefaultAlarm();
|
var alarm = require("sched").newDefaultAlarm();
|
||||||
|
if (isNew && group) alarm.group = group;
|
||||||
|
if (withDate || (selectedAlarm && selectedAlarm.date)) {
|
||||||
|
alarm.del = require("sched").getSettings().defaultDeleteExpiredTimers;
|
||||||
|
}
|
||||||
alarm.dow = handleFirstDayOfWeek(alarm.dow);
|
alarm.dow = handleFirstDayOfWeek(alarm.dow);
|
||||||
|
|
||||||
if (selectedAlarm) {
|
if (selectedAlarm) {
|
||||||
|
@ -111,57 +142,97 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) {
|
||||||
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 },
|
||||||
"< Back": () => {
|
"< Back": () => {
|
||||||
prepareAlarmForSave(alarm, alarmIndex, time, date);
|
prepareAlarmForSave(alarm, alarmIndex, time, date);
|
||||||
saveAndReload();
|
saveAndReload();
|
||||||
showMainMenu();
|
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: formatAlarmMessage,
|
format: formatAlarmProperty,
|
||||||
onchange: () => {
|
onchange: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
keyboard.input({text:alarm.msg}).then(result => {
|
keyboard.input({text:alarm.msg}).then(result => {
|
||||||
alarm.msg = result;
|
alarm.msg = result;
|
||||||
prepareAlarmForSave(alarm, alarmIndex, time, date, true);
|
prepareAlarmForSave(alarm, alarmIndex, time, date, true);
|
||||||
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate);
|
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate, scroll, group);
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/*LANG*/"Group": {
|
||||||
|
value: alarm.group,
|
||||||
|
format: formatAlarmProperty,
|
||||||
|
onchange: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
keyboard.input({text:alarm.group}).then(result => {
|
||||||
|
alarm.group = result;
|
||||||
|
prepareAlarmForSave(alarm, alarmIndex, time, date, true);
|
||||||
|
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate, scroll, group);
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
@ -173,10 +244,13 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) {
|
||||||
/*LANG*/"Repeat": {
|
/*LANG*/"Repeat": {
|
||||||
value: decodeRepeat(alarm),
|
value: decodeRepeat(alarm),
|
||||||
onchange: () => setTimeout(showEditRepeatMenu, 100, alarm.rp, date || alarm.dow, (repeat, dow) => {
|
onchange: () => setTimeout(showEditRepeatMenu, 100, alarm.rp, date || alarm.dow, (repeat, dow) => {
|
||||||
|
if (repeat) {
|
||||||
|
alarm.del = false; // do not auto delete a repeated alarm
|
||||||
|
}
|
||||||
alarm.rp = repeat;
|
alarm.rp = repeat;
|
||||||
alarm.dow = dow;
|
alarm.dow = dow;
|
||||||
prepareAlarmForSave(alarm, alarmIndex, time, date, true);
|
prepareAlarmForSave(alarm, alarmIndex, time, date, true);
|
||||||
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate);
|
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate, scroll, group);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/*LANG*/"Vibrate": require("buzz_menu").pattern(alarm.vibrate, v => alarm.vibrate = v),
|
/*LANG*/"Vibrate": require("buzz_menu").pattern(alarm.vibrate, v => alarm.vibrate = v),
|
||||||
|
@ -184,23 +258,32 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) {
|
||||||
value: alarm.as,
|
value: alarm.as,
|
||||||
onchange: v => alarm.as = v
|
onchange: v => alarm.as = v
|
||||||
},
|
},
|
||||||
|
/*LANG*/"Delete After Expiration": {
|
||||||
|
value: alarm.del,
|
||||||
|
onchange: v => alarm.del = v
|
||||||
|
},
|
||||||
/*LANG*/"Hidden": {
|
/*LANG*/"Hidden": {
|
||||||
value: alarm.hidden || false,
|
value: alarm.hidden || false,
|
||||||
onchange: v => alarm.hidden = v
|
onchange: v => alarm.hidden = v
|
||||||
},
|
},
|
||||||
/*LANG*/"Cancel": () => showMainMenu(),
|
/*LANG*/"Cancel": () => showMainMenu(scroll, group),
|
||||||
/*LANG*/"Confirm": () => {
|
/*LANG*/"Confirm": () => {
|
||||||
prepareAlarmForSave(alarm, alarmIndex, time, date);
|
prepareAlarmForSave(alarm, alarmIndex, time, date);
|
||||||
saveAndReload();
|
saveAndReload();
|
||||||
showMainMenu();
|
showMainMenu(scroll, group);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (!keyboard) delete menu[/*LANG*/"Message"];
|
if (!keyboard) delete menu[/*LANG*/"Message"];
|
||||||
|
if (!keyboard || !settings.showGroup) delete menu[/*LANG*/"Group"];
|
||||||
|
if (!settings.showConfirm) delete menu[/*LANG*/"Confirm"];
|
||||||
|
if (!settings.showAutoSnooze) delete menu[/*LANG*/"Auto Snooze"];
|
||||||
|
if (!settings.showHidden) delete menu[/*LANG*/"Hidden"];
|
||||||
if (!alarm.date) {
|
if (!alarm.date) {
|
||||||
delete menu[/*LANG*/"Day"];
|
delete menu[/*LANG*/"Day"];
|
||||||
delete menu[/*LANG*/"Month"];
|
delete menu[/*LANG*/"Month"];
|
||||||
delete menu[/*LANG*/"Year"];
|
delete menu[/*LANG*/"Year"];
|
||||||
|
delete menu[/*LANG*/"Delete After Expiration"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNew) {
|
if (!isNew) {
|
||||||
|
@ -209,10 +292,10 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) {
|
||||||
if (confirm) {
|
if (confirm) {
|
||||||
alarms.splice(alarmIndex, 1);
|
alarms.splice(alarmIndex, 1);
|
||||||
saveAndReload();
|
saveAndReload();
|
||||||
showMainMenu();
|
showMainMenu(scroll, group);
|
||||||
} else {
|
} else {
|
||||||
alarm.t = require("time_utils").encodeTime(time);
|
alarm.t = require("time_utils").encodeTime(time);
|
||||||
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate);
|
setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate, scroll, group);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -259,7 +342,6 @@ function decodeRepeat(alarm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEditRepeatMenu(repeat, day, dowChangeCallback) {
|
function showEditRepeatMenu(repeat, day, dowChangeCallback) {
|
||||||
var originalRepeat = repeat;
|
|
||||||
var dow;
|
var dow;
|
||||||
|
|
||||||
const menu = {
|
const menu = {
|
||||||
|
@ -292,26 +374,32 @@ function showEditRepeatMenu(repeat, day, dowChangeCallback) {
|
||||||
},
|
},
|
||||||
/*LANG*/"Custom": {
|
/*LANG*/"Custom": {
|
||||||
value: isCustom ? decodeRepeat({ rp: true, dow: dow }) : false,
|
value: isCustom ? decodeRepeat({ rp: true, dow: dow }) : false,
|
||||||
onchange: () => setTimeout(showCustomDaysMenu, 10, dow, dowChangeCallback, originalRepeat, originalDow)
|
onchange: () => setTimeout(showCustomDaysMenu, 10, dow, dowChangeCallback, repeat, originalDow)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// var date = day; // eventually: detect day of date and configure a repeat e.g. 3rd Monday of Month
|
// var date = day; // eventually: detect day of date and configure a repeat e.g. 3rd Monday of Month
|
||||||
dow = EVERY_DAY;
|
dow = EVERY_DAY;
|
||||||
repeat = repeat || {interval: "month", num: 1};
|
const repeatObj = repeat || {interval: "month", num: 1};
|
||||||
|
|
||||||
restOfMenu = {
|
restOfMenu = {
|
||||||
/*LANG*/"Every": {
|
/*LANG*/"Every": {
|
||||||
value: repeat.num,
|
value: repeatObj.num,
|
||||||
min: 1,
|
min: 1,
|
||||||
onchange: v => repeat.num = v
|
onchange: v => {
|
||||||
|
repeat = repeatObj;
|
||||||
|
repeat.num = v;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/*LANG*/"Interval": {
|
/*LANG*/"Interval": {
|
||||||
value: INTERVALS.indexOf(repeat.interval),
|
value: INTERVALS.indexOf(repeatObj.interval),
|
||||||
format: v => INTERVAL_LABELS[v],
|
format: v => INTERVAL_LABELS[v],
|
||||||
min: 0,
|
min: 0,
|
||||||
max: INTERVALS.length - 1,
|
max: INTERVALS.length - 1,
|
||||||
onchange: v => repeat.interval = INTERVALS[v]
|
onchange: v => {
|
||||||
|
repeat = repeatObj;
|
||||||
|
repeat.interval = INTERVALS[v];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -387,7 +475,7 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
|
||||||
},
|
},
|
||||||
/*LANG*/"Message": {
|
/*LANG*/"Message": {
|
||||||
value: timer.msg,
|
value: timer.msg,
|
||||||
format: formatAlarmMessage,
|
format: formatAlarmProperty,
|
||||||
onchange: () => {
|
onchange: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
keyboard.input({text:timer.msg}).then(result => {
|
keyboard.input({text:timer.msg}).then(result => {
|
||||||
|
@ -420,6 +508,8 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!keyboard) delete menu[/*LANG*/"Message"];
|
if (!keyboard) delete menu[/*LANG*/"Message"];
|
||||||
|
if (!settings.showConfirm) delete menu[/*LANG*/"Confirm"];
|
||||||
|
if (!settings.showHidden) delete menu[/*LANG*/"Hidden"];
|
||||||
if (!isNew) {
|
if (!isNew) {
|
||||||
menu[/*LANG*/"Delete"] = () => {
|
menu[/*LANG*/"Delete"] = () => {
|
||||||
E.showPrompt(getLabel(timer) + "\n" + /*LANG*/"Are you sure?", { title: /*LANG*/"Delete Timer" }).then((confirm) => {
|
E.showPrompt(getLabel(timer) + "\n" + /*LANG*/"Are you sure?", { title: /*LANG*/"Delete Timer" }).then((confirm) => {
|
||||||
|
@ -440,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.42",
|
"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",
|
||||||
|
@ -11,7 +11,8 @@
|
||||||
"dependencies": { "scheduler":"type", "alarm":"widget" },
|
"dependencies": { "scheduler":"type", "alarm":"widget" },
|
||||||
"storage": [
|
"storage": [
|
||||||
{ "name": "alarm.app.js", "url": "app.js" },
|
{ "name": "alarm.app.js", "url": "app.js" },
|
||||||
{ "name": "alarm.img", "url": "app-icon.js", "evaluate": true }
|
{ "name": "alarm.img", "url": "app-icon.js", "evaluate": true },
|
||||||
|
{ "name": "alarm.settings.js", "url":"settings.js" }
|
||||||
],
|
],
|
||||||
"screenshots": [
|
"screenshots": [
|
||||||
{ "url": "screenshot-1.png" },
|
{ "url": "screenshot-1.png" },
|
||||||
|
@ -25,5 +26,6 @@
|
||||||
{ "url": "screenshot-9.png" },
|
{ "url": "screenshot-9.png" },
|
||||||
{ "url": "screenshot-10.png" },
|
{ "url": "screenshot-10.png" },
|
||||||
{ "url": "screenshot-11.png" }
|
{ "url": "screenshot-11.png" }
|
||||||
]
|
],
|
||||||
|
"data":[ {"name":"alarm.settings.json"} ]
|
||||||
}
|
}
|
||||||
|
|