forked from FOSS/BangleApps
Merge branch 'master' of github.com:espruino/BangleApps
commit
507b36b790
|
@ -1,2 +1,5 @@
|
||||||
0.01 Added sonic clock app
|
0.01 [MAJOR] Added sonic clock app
|
||||||
0.02 Fixed text alignment issue; Increased acceleration required to activate twist;
|
0.02 [PATCH] Fixed text alignment issue; Increased acceleration required to activate twist;
|
||||||
|
0.03 [MINOR] Added settings menu to control twist threshold and LCD Activity
|
||||||
|
0.04 [PATCH] Call `Bangle.setUI` when exiting settings menu, settings tap moved to top
|
||||||
|
0.05 [PATCH] Firmware 2v11 - use `wakeOnTwist` rather than manual `setLCDPower`; Reset sonic on `fullReset`
|
||||||
|
|
|
@ -8,6 +8,13 @@ A classic sonic clock featuring run, stop and wait animations.
|
||||||
|
|
||||||
- Sonic will run when the screen is unlocked
|
- Sonic will run when the screen is unlocked
|
||||||
- Sonic will stop when the screen is locked
|
- Sonic will stop when the screen is locked
|
||||||
- Sonic will wait when looking at your watch face (when `Bangle.on("twist", fn)` is fired).
|
- Sonic will wait when looking at your watch face (when `Bangle.on("twist", fn)` is fired). This option is configurable (see below).
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
To access the settings menu, you can **double tap** on the **top** side of the watch. The following options are configurable:
|
||||||
|
|
||||||
|
- `Active Mode` - catering for 'active' behaviour where the `twist` method can be fired undesirably. When `on` this will prevent the LCD from turning on when a `twist` event is fired.
|
||||||
|
- `Twist Thresh` - customise the acceleration needed to activate the twist method (see the [`Bangle.setOptions`](https://www.espruino.com/Reference#:~:text=twisted%3F%20default%20%3D%20true-,twistThreshold,-How%20much%20acceleration) method for more info).
|
||||||
|
|
||||||
### Made with love by [Joseph](https://github.com/Johoseph) 🤗
|
### Made with love by [Joseph](https://github.com/Johoseph) 🤗
|
||||||
|
|
|
@ -109,10 +109,16 @@ let currentSonic = -1;
|
||||||
let drawTimeout, drawInterval, waitTimeout;
|
let drawTimeout, drawInterval, waitTimeout;
|
||||||
let bgScroll = [0, null];
|
let bgScroll = [0, null];
|
||||||
|
|
||||||
const start = () => {
|
const fullReset = () => {
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
if (waitTimeout) clearTimeout(waitTimeout);
|
if (waitTimeout) clearTimeout(waitTimeout);
|
||||||
if (drawInterval) clearInterval(drawInterval);
|
if (drawInterval) clearInterval(drawInterval);
|
||||||
|
currentSonic = -1;
|
||||||
|
currentSpeed = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const start = () => {
|
||||||
|
fullReset();
|
||||||
|
|
||||||
drawInterval = setInterval(() => {
|
drawInterval = setInterval(() => {
|
||||||
draw("start");
|
draw("start");
|
||||||
|
@ -144,7 +150,6 @@ const wait = () => {
|
||||||
currentSpeed = 0;
|
currentSpeed = 0;
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
if (drawInterval) clearInterval(drawInterval);
|
if (drawInterval) clearInterval(drawInterval);
|
||||||
Bangle.setLCDPower(1);
|
|
||||||
|
|
||||||
drawInterval = setInterval(() => draw("wait"), timeout);
|
drawInterval = setInterval(() => draw("wait"), timeout);
|
||||||
|
|
||||||
|
@ -252,22 +257,80 @@ const draw = (action) => {
|
||||||
if (action === "reset") queueDraw();
|
if (action === "reset") queueDraw();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
const settings = require("Storage").readJSON("sonicclk-settings") || {
|
||||||
|
activeMode: false,
|
||||||
|
twistThreshold: 1600,
|
||||||
|
};
|
||||||
|
let isSettings = false;
|
||||||
|
|
||||||
|
const settingsMenu = {
|
||||||
|
"": { title: "Settings" },
|
||||||
|
"Active Mode": {
|
||||||
|
value: settings.activeMode,
|
||||||
|
format: (v) => (v ? "On" : "Off"),
|
||||||
|
onchange: (v) => (settings.activeMode = v),
|
||||||
|
},
|
||||||
|
"Twist Thresh": {
|
||||||
|
value: settings.twistThreshold,
|
||||||
|
min: 800,
|
||||||
|
max: 4000,
|
||||||
|
step: 200,
|
||||||
|
onchange: (v) => (settings.twistThreshold = v),
|
||||||
|
},
|
||||||
|
Exit: () => {
|
||||||
|
isSettings = false;
|
||||||
|
|
||||||
|
require("Storage").writeJSON("sonicclk-settings", settings);
|
||||||
|
Bangle.setOptions({
|
||||||
|
lockTimeout: 10000,
|
||||||
|
backlightTimeout: 12000,
|
||||||
|
twistThreshold: settings.twistThreshold,
|
||||||
|
wakeOnTwist: !settings.activeMode,
|
||||||
|
});
|
||||||
|
|
||||||
|
E.showMenu();
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
draw("reset");
|
||||||
|
start();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
g.setTheme({ bg: "#0099ff", fg: "#fff", dark: true }).clear();
|
g.setTheme({ bg: "#0099ff", fg: "#fff", dark: true }).clear();
|
||||||
|
|
||||||
Bangle.on("lock", (locked) => {
|
Bangle.on("lock", (locked) => {
|
||||||
|
if (!isSettings) {
|
||||||
if (locked) {
|
if (locked) {
|
||||||
stop();
|
stop();
|
||||||
} else {
|
} else {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Bangle.on("twist", () => wait());
|
Bangle.on("twist", () => {
|
||||||
|
if (settings.activeMode) {
|
||||||
|
fullReset();
|
||||||
|
draw("reset");
|
||||||
|
} else {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on("tap", (d) => {
|
||||||
|
if (d.double && d.dir === "top") {
|
||||||
|
fullReset();
|
||||||
|
isSettings = true;
|
||||||
|
Bangle.setLocked(false);
|
||||||
|
E.showMenu(settingsMenu);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Bangle.setOptions({
|
Bangle.setOptions({
|
||||||
lockTimeout: 10000,
|
lockTimeout: 10000,
|
||||||
backlightTimeout: 12000,
|
backlightTimeout: 12000,
|
||||||
twistThreshold: 1600,
|
twistThreshold: settings.twistThreshold,
|
||||||
|
wakeOnTwist: !settings.activeMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
Bangle.setUI("clock");
|
Bangle.setUI("clock");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "sonicclk",
|
"id": "sonicclk",
|
||||||
"name": "Sonic Clock",
|
"name": "Sonic Clock",
|
||||||
"version": "0.02",
|
"version": "0.05",
|
||||||
"description": "A classic sonic clock featuring run, stop and wait animations.",
|
"description": "A classic sonic clock featuring run, stop and wait animations.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [{"url":"screenshot.png"}],
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
0.02: Use Bangle.setUI for button/launcher handling
|
0.02: Use Bangle.setUI for button/launcher handling
|
||||||
0.03: Bangle.js 2 support
|
0.03: Bangle.js 2 support
|
||||||
0.04: Adds costumizable colours and the respective settings menu
|
0.04: Adds costumizable colours and the respective settings menu
|
||||||
|
0.05: "Chime the time" (buzz or beep) with up/down swipe added
|
||||||
|
|
|
@ -4,7 +4,7 @@ var settings = require('Storage').readJSON("vectorclock.json", true) || {};
|
||||||
var dowcol = settings.dowcol || g.theme.fg;
|
var dowcol = settings.dowcol || g.theme.fg;
|
||||||
var timecol = settings.timecol || g.theme.fg;
|
var timecol = settings.timecol || g.theme.fg;
|
||||||
var datecol = settings.datecol || g.theme.fg;
|
var datecol = settings.datecol || g.theme.fg;
|
||||||
|
var chimetype = settings.chimetype;
|
||||||
|
|
||||||
function padNum(n, l) {
|
function padNum(n, l) {
|
||||||
return ("0".repeat(l)+n).substr(-l);
|
return ("0".repeat(l)+n).substr(-l);
|
||||||
|
@ -90,6 +90,57 @@ function tick() {
|
||||||
timeout = setTimeout(tick, period - getTime() * 1000 % period);
|
timeout = setTimeout(tick, period - getTime() * 1000 % period);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================================== Vibration (taken from "Vibrate Clock")
|
||||||
|
// vibrate 0..9
|
||||||
|
function vibrateDigitBuzz(num) {
|
||||||
|
if (num==0) return Bangle.buzz(500);
|
||||||
|
return new Promise(function f(resolve){
|
||||||
|
if (num--<=0) return resolve();
|
||||||
|
Bangle.buzz(100).then(()=>{
|
||||||
|
setTimeout(()=>f(resolve), 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function vibrateDigitBeep(num) {
|
||||||
|
if (num==0) return Bangle.beep(500);
|
||||||
|
return new Promise(function f(resolve){
|
||||||
|
if (num--<=0) return resolve();
|
||||||
|
Bangle.beep(100).then(()=>{
|
||||||
|
setTimeout(()=>f(resolve), 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// vibrate multiple digits (num must be a string)
|
||||||
|
function vibrateNumber(num) {
|
||||||
|
return new Promise(function f(resolve){
|
||||||
|
if (!num.length) return resolve();
|
||||||
|
var digit = num[0];
|
||||||
|
num = num.substr(1);
|
||||||
|
if ("buzz"==chimetype)
|
||||||
|
vibrateDigitBuzz(digit).then(()=>{
|
||||||
|
setTimeout(()=>f(resolve),500);});
|
||||||
|
if ("beep"==chimetype)
|
||||||
|
vibrateDigitBeep(digit).then(()=>{
|
||||||
|
setTimeout(()=>f(resolve),500);});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var vibrateBusy;
|
||||||
|
function vibrateTime() {
|
||||||
|
if (vibrateBusy) return;
|
||||||
|
vibrateBusy = true;
|
||||||
|
var d = new Date();
|
||||||
|
var hours = d.getHours(), minutes = d.getMinutes();
|
||||||
|
if (is12Hour) {
|
||||||
|
if (hours == 0) hours = 12;
|
||||||
|
else if (hours>12) hours -= 12;
|
||||||
|
}
|
||||||
|
vibrateNumber(hours.toString()).
|
||||||
|
then(() => new Promise(resolve=>setTimeout(resolve,500))).
|
||||||
|
then(() => vibrateNumber(minutes.toString())).
|
||||||
|
then(() => vibrateBusy=false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Bangle.on('lcdPower', function(on) {
|
Bangle.on('lcdPower', function(on) {
|
||||||
if (timeout) clearTimeout(timeout);
|
if (timeout) clearTimeout(timeout);
|
||||||
timeout = null;
|
timeout = null;
|
||||||
|
@ -103,6 +154,10 @@ Bangle.on('lock', function(locked) {
|
||||||
tick();
|
tick();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ("buzz"==chimetype || "beep"==chimetype)
|
||||||
|
Bangle.on("swipe",function(direction){
|
||||||
|
if (0==direction) vibrateTime();}); // 0 = swipe up/down
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
tick();
|
tick();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "vectorclock",
|
"id": "vectorclock",
|
||||||
"name": "Vector Clock",
|
"name": "Vector Clock",
|
||||||
"version": "0.04",
|
"version": "0.05",
|
||||||
"description": "A digital clock that uses the built-in vector font.",
|
"description": "A digital clock that uses the built-in vector font.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
|
|
||||||
var colnames = ["white", "yellow", "green", "cyan", "red", "orange", "magenta", "black"];
|
var colnames = ["white", "yellow", "green", "cyan", "red", "orange", "magenta", "black"];
|
||||||
var colvalues = [0xFFFF, 0xFFE0, 0x07E0, 0x07FF, 0xF800, 0xFD20, 0xF81F, 0x0000];
|
var colvalues = [0xFFFF, 0xFFE0, 0x07E0, 0x07FF, 0xF800, 0xFD20, 0xF81F, 0x0000];
|
||||||
|
var chimenames = ["off", "buzz", "beep"];
|
||||||
// Show the menu
|
// Show the menu
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
"" : { "title" : "VectorClock colours" },
|
"" : { "title" : "VectorClock settings" },
|
||||||
"< Back" : () => back(),
|
|
||||||
'Time': {
|
'Time': {
|
||||||
value: Math.max(0 | colvalues.indexOf(settings.timecol),0),
|
value: Math.max(0 | colvalues.indexOf(settings.timecol),0),
|
||||||
min: 0, max: colvalues.length-1,
|
min: 0, max: colvalues.length-1,
|
||||||
|
@ -41,5 +41,15 @@
|
||||||
writeSettings();
|
writeSettings();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'Chimetype': {
|
||||||
|
value: Math.max(0 | chimenames.indexOf(settings.chimetype),0),
|
||||||
|
min: 0, max: chimenames.length-1,
|
||||||
|
format: v => chimenames[v],
|
||||||
|
onchange: v => {
|
||||||
|
settings.chimetype = chimenames[v];
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"< Back" : () => back(),
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue