Merge branch 'master' into development

pull/3590/head
xxDUxx 2024-09-25 10:12:58 +02:00 committed by GitHub
commit 0b194a2cd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2092 changed files with 95432 additions and 9467 deletions

View File

@ -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

View File

@ -1,7 +1,32 @@
{ const lintExemptions = require("./apps/lint_exemptions.js");
const fs = require("fs");
const path = require("path");
function findGeneratedJS(roots) {
function* listFiles(dir, allow) {
for (const f of fs.readdirSync(dir)) {
const filepath = path.join(dir, f);
const stat = fs.statSync(filepath);
if (stat.isDirectory()) {
yield* listFiles(filepath, allow);
} else if(allow(filepath)) {
yield filepath;
}
}
}
return roots.flatMap(root =>
[...listFiles(root, f => f.endsWith(".ts"))]
.map(f => f.replace(/\.ts$/, ".js"))
);
}
module.exports = {
"env": { "env": {
// TODO: "espruino": false // TODO: "espruino": false
// TODO: "banglejs": false // TODO: "banglejs": false
// For a prototype of the above, see https://github.com/espruino/BangleApps/pull/3237
}, },
"extends": "eslint:recommended", "extends": "eslint:recommended",
"globals": { "globals": {
@ -23,10 +48,8 @@
"Flash": "readonly", "Flash": "readonly",
"Float32Array": "readonly", "Float32Array": "readonly",
"Float64Array": "readonly", "Float64Array": "readonly",
"fs": "readonly",
"Function": "readonly", "Function": "readonly",
"Graphics": "readonly", "Graphics": "readonly",
"heatshrink": "readonly",
"I2C": "readonly", "I2C": "readonly",
"Int16Array": "readonly", "Int16Array": "readonly",
"Int32Array": "readonly", "Int32Array": "readonly",
@ -46,11 +69,9 @@
"RegExp": "readonly", "RegExp": "readonly",
"Serial": "readonly", "Serial": "readonly",
"SPI": "readonly", "SPI": "readonly",
"Storage": "readonly",
"StorageFile": "readonly", "StorageFile": "readonly",
"String": "readonly", "String": "readonly",
"SyntaxError": "readonly", "SyntaxError": "readonly",
"tensorflow": "readonly",
"TFMicroInterpreter": "readonly", "TFMicroInterpreter": "readonly",
"TypeError": "readonly", "TypeError": "readonly",
"Uint16Array": "readonly", "Uint16Array": "readonly",
@ -58,8 +79,10 @@
"Uint32Array": "readonly", "Uint32Array": "readonly",
"Uint8Array": "readonly", "Uint8Array": "readonly",
"Uint8ClampedArray": "readonly", "Uint8ClampedArray": "readonly",
"Unistroke": "readonly",
"Waveform": "readonly", "Waveform": "readonly",
// Methods and Fields at https://banglejs.com/reference // Methods and Fields at https://banglejs.com/reference
"__FILE__": "readonly",
"analogRead": "readonly", "analogRead": "readonly",
"analogWrite": "readonly", "analogWrite": "readonly",
"arguments": "readonly", "arguments": "readonly",
@ -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,
} }

View File

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

9
CONTRIBUTING.md Normal file
View File

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

View File

@ -6,6 +6,8 @@ Bangle.js App Loader (and Apps)
* Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps) * Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps)
* Try the **development version** at [espruino.github.io](https://espruino.github.io/BangleApps/) * Try the **development version** at [espruino.github.io](https://espruino.github.io/BangleApps/)
The release version is manually refreshed with regular intervals while the development version is continuously updated as new code is committed to this repository.
**All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By **All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By
submitting code to this repository you confirm that you are happy with it being MIT licensed, submitting code to this repository you confirm that you are happy with it being MIT licensed,
and that it is not licensed in another way that would make this impossible. and that it is not licensed in another way that would make this impossible.
@ -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)

View File

@ -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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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",

View File

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

View File

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

View File

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

BIN
apps/8ball/8ball.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

1
apps/8ball/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App!

1
apps/8ball/app-icon.js Normal file
View File

@ -0,0 +1 @@
atob("MDCBAAAAAAAAAAAAAAAAAAAAH/AAAAAAf/4AAAAB4AeAAAAHgAHgAAAOAABwAAAcAAA4AAA4AMAcAABwAMAOAABgA/AGAADAAeADAAHAAMADgAGAAAABgAGAAAABgAMAAAAAwAMBAAAAwAMDAAAAwAMHwAAAwAMHwAAAwAMDAACAwAMBAADAwAMAAAPgwAMAAAPgwAMAAADAwAGAAACBgAGAAAABgAHAAAADgADAAAADAADgAAAHAAB////+AAB////+AABgAAAGAABgAAAGAABgAAAGAADAAAADAADAAAADAADAAAADAAGAAAABgAGAAAABgAH/////gAP/////wAYAAAAAYAYAAAAAYAf/////4AP/////wAAAAAAAAAAAAAAAAA==")

92
apps/8ball/app.js Normal file
View File

@ -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(); });

19
apps/8ball/metadata.json Normal file
View File

@ -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}
]
}

BIN
apps/8ball/screenshot-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
apps/8ball/screenshot-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
apps/8ball/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
"id": "BLEcontroller", "id": "BLEcontroller",
"name": "BLE Customisable Controller with Joystick", "name": "BLE Customisable Controller with Joystick",
"shortName": "BLE Controller", "shortName": "BLE Controller",
"version": "0.01", "version": "0.02",
"description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.",
"icon": "BLEcontroller.png", "icon": "BLEcontroller.png",
"tags": "tool,bluetooth", "tags": "tool,bluetooth",

1
apps/Tyreid/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: Change log created

18
apps/Tyreid/README.md Normal file
View File

@ -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.

1
apps/Tyreid/app-icon.js Normal file
View File

@ -0,0 +1 @@
E.toArrayBuffer(atob("MDACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAtAAAAAAAAAAAAAAB/QAAAAAAAAAAAAAD/0AAAAAAAAAAAAAH+9AAAAAAAAAAAAAPtfQAAAAAAAAAAAAudH0AAAAAAAAAAAB8tB9AAAAAAAAAAAD0tAfQAAAAAAAAAAHgtAH0AAAAAAAAAAPAtAB9AAAAAAAAAAtAtAAfQAAAAAAAAB8AtAAH0AAAAAAAAD0AtAAB9AAAAAAAALgAtAAAfQAAAAAAAfAAtAAAH0AAAAAAA9AAtAAAB9AAAAAAC4AAtAAAAfQAAAAADwAAtAAAALwAAAAAAQAAtAAAAvgAAAAAAAAAsAAAC9AAAAAAAAAAsAAAP0AAAAAAAAAAsAAB/AAAAAAAAAAAsAAH4AAAAAAAAAAAsAAvQAAAAAAAAAAAsAD9AAAAAAAAAAAAsAD0AAAAAAAAAAAAsAB8AAAAAAAAAAAAsAAtAAAAAAAAAAAAsAAPQAAAAAAAAAAAsAAHwAAAAAAAAAAAsAAC4AAAAAAAAAAAsAAA9AAAAAAAAAAAsAAAPAAAAAAAAAAAsAAAHgAAAAAAAAAA8AAAC0AAAAAAAAAA8AAAA8AAAAAAAAAA8AAAAEAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))

272
apps/Tyreid/app.js Normal file

File diff suppressed because one or more lines are too long

14
apps/Tyreid/metadata.json Normal file
View File

@ -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}
]
}

BIN
apps/Tyreid/small_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1 +1 @@
0.01: New Widget! 0.01: New Clock Info!

View File

@ -0,0 +1 @@
0.01: New Clock!

View File

@ -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

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,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();

View File

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

View File

@ -2,7 +2,7 @@
"id": "accelrec", "id": "accelrec",
"name": "Acceleration Recorder", "name": "Acceleration Recorder",
"shortName": "Accel Rec", "shortName": "Accel Rec",
"version": "0.03", "version": "0.05",
"description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.", "description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.",
"icon": "app.png", "icon": "app.png",
"tags": "", "tags": "",

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
"id": "activepedom", "id": "activepedom",
"name": "Active Pedometer", "name": "Active Pedometer",
"shortName": "Active Pedometer", "shortName": "Active Pedometer",
"version": "0.09", "version": "0.11",
"description": "(NOT RECOMMENDED) Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph. The `Health` app now provides step logging and graphs.", "description": "(NOT RECOMMENDED) Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph. The `Health` app now provides step logging and graphs.",
"icon": "app.png", "icon": "app.png",
"tags": "outdoors,widget", "tags": "outdoors,widget",

View File

@ -3,7 +3,7 @@
var startTimeStep = new Date(); //set start time var startTimeStep = new Date(); //set start time
var stopTimeStep = 0; //Time after one step var stopTimeStep = 0; //Time after one step
var timerResetActive = 0; //timer to reset active var timerResetActive = 0; //timer to reset active
var timerStoreData = 0; //timer to store data //var timerStoreData = 0; //timer to store data
var steps = 0; //steps taken var steps = 0; //steps taken
var stepsCounted = 0; //active steps counted var stepsCounted = 0; //active steps counted
var active = 0; //x steps in y seconds achieved var active = 0; //x steps in y seconds achieved
@ -32,10 +32,10 @@
} }
function storeData() { function storeData() {
now = new Date(); let now = new Date();
month = now.getMonth() + 1; //month is 0-based let month = now.getMonth() + 1; //month is 0-based
if (month < 10) month = "0" + month; //leading 0 if (month < 10) month = "0" + month; //leading 0
filename = filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; //new file for each day let filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; //new file for each day
dataFile = s.open(filename,"a"); dataFile = s.open(filename,"a");
if (dataFile) { //check if filen already exists if (dataFile) { //check if filen already exists
if (dataFile.getLength() == 0) { if (dataFile.getLength() == 0) {
@ -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};
})(); })();

View File

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

View File

@ -29,16 +29,13 @@ exports.loadData = function () {
dismissDate: new Date(1970), dismissDate: new Date(1970),
pauseDate: new Date(1970), pauseDate: new Date(1970),
}, },
require("Storage").readJSON("activityreminder.data.json") || {});
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;
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.

View File

@ -2,7 +2,7 @@
This app allows you to add/modify any alarms, timers and events. This app allows you to add/modify any alarms, timers and events.
Optional: When a keyboard app is detected, you can add a message to display when any of these is triggered. Optional: When a keyboard app is detected, you can add a message to display when any of these is triggered. If a datetime input app (e.g. datetime_picker) is detected, it will be used for the selection of the date+time of events.
It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) to handle the alarm scheduling in an efficient way that can work alongside other apps. It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) to handle the alarm scheduling in an efficient way that can work alongside other apps.
@ -13,7 +13,7 @@ It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master
- `Repeat` &rarr; 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` &rarr; 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` &rarr; Configure a new timer (triggered based on amount of time elapsed in hours/minutes/seconds) - `New Timer` &rarr; Configure a new timer (triggered based on amount of time elapsed in hours/minutes/seconds)
- `New Event` &rarr; Configure a new event (triggered based on time and date) - `New Event` &rarr; Configure a new event (triggered based on time and date)
- `Repeat` &rarr; Alarm can be be fired only once or repeated (every X number of _days_, _weeks_, _months_ or _years_) - `Repeat` &rarr; Alarm can be fired only once or repeated (every X number of _days_, _weeks_, _months_ or _years_)
- `Advanced` - `Advanced`
- `Scheduler settings` &rarr; 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` &rarr; 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` &rarr; Enable _all_ disabled alarms & timers - `Enable All` &rarr; Enable _all_ disabled alarms & timers

View File

@ -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) {

View File

@ -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"} ]
} }

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