mirror of https://github.com/espruino/BangleApps
feat: add large clock
parent
51bf1d4ae4
commit
a15a049b94
31
apps.json
31
apps.json
|
@ -1550,5 +1550,36 @@
|
|||
{"name":"hidjoystick.app.js","url":"app.js"},
|
||||
{"name":"hidjoystick.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "largeclock",
|
||||
"name": "Large Clock",
|
||||
"icon": "largeclock.png",
|
||||
"version": "0.01",
|
||||
"description": "A readable and informational digital watch, with date, seconds and moon phase",
|
||||
"readme": "README.md",
|
||||
"tags": "clock",
|
||||
"type": "clock",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{
|
||||
"name": "largeclock.app.js",
|
||||
"url": "largeclock.js"
|
||||
},
|
||||
{
|
||||
"name": "largeclock.img",
|
||||
"url": "largeclock-icon.js",
|
||||
"evaluate": true
|
||||
},
|
||||
{
|
||||
"name": "largeclock.settings.js",
|
||||
"url": "settings.js"
|
||||
},
|
||||
{
|
||||
"name": "largeclock.json",
|
||||
"url": "largeclock.json",
|
||||
"evaluate": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: Init
|
|
@ -0,0 +1,19 @@
|
|||
# Large clock
|
||||
|
||||
A readable and informational digital watch, with date, seconds and moon phase and with programmable BTN1 & BTN3
|
||||
|
||||
## Features
|
||||
|
||||
- Readable
|
||||
- Informative: hours, minutes, secondsa, date, year and moon phase
|
||||
- Pairs nicely with any other apps: in setting > large clock any installed app can be assigned to BTN1 and BTN3 in order to open it easily directly from the watch, without the hassle of passing trough the launcher. For example BTN1 can be assigned to alarm and BTN3 to chronometer.
|
||||
|
||||
## How to use it
|
||||
|
||||
- The clock can be used as any other one, if you like it just set it as the default clock app in settings > select clock
|
||||
- In setting > large clock you can select which app is to be open by BTN1 and BTN3
|
||||
|
||||
## Credits
|
||||
|
||||
- The clock face is heavily inspired by Big Clock byJeffmer https://jeffmer.github.io/JeffsBangleAppsDev/
|
||||
- The moon phase is basically the one from the widget https://github.com/espruino/BangleApps/tree/master/apps/widmp
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwhC/AH4ArmYAQCwkDC6MwFyowFC/4XKnGIAAIQFBAWDC5INCBwggEEIYXdxAODnAYCAYIgDDAQXECoIrDE4YrEBwYX/C/4X/C/4X8BwIKBAAM4DgQDBBAQDBBAIXFE4QOCA4QrCAAQHCC7wODCwYhEEAYXGACAX/C5cDCyMwC4YwSCwgA/AH4AlA="))
|
|
@ -0,0 +1,198 @@
|
|||
const REFRESH_RATE = 1000;
|
||||
|
||||
let interval;
|
||||
let lastMoonPhase;
|
||||
let lastMinutes;
|
||||
|
||||
const moonR = 12;
|
||||
const moonX = 215;
|
||||
const moonY = 50;
|
||||
|
||||
const settings = require("Storage").readJSON("largeclock.json", 1);
|
||||
const BTN1app = settings.BTN1;
|
||||
const BTN3app = settings.BTN3;
|
||||
console.log("BTN1app", BTN1app);
|
||||
console.log("BTN3app", BTN3app);
|
||||
|
||||
function drawMoon(d) {
|
||||
const BLACK = 0,
|
||||
MOON = 0x41f,
|
||||
MC = 29.5305882,
|
||||
NM = 694039.09;
|
||||
|
||||
var moon = {
|
||||
// reset
|
||||
0: () => {
|
||||
g.setColor(BLACK).fillRect(
|
||||
moonX - moonR,
|
||||
moonY - moonR,
|
||||
moonX + moonR,
|
||||
moonY + moonR
|
||||
);
|
||||
},
|
||||
// new moon
|
||||
1: () => {
|
||||
moon[0]();
|
||||
g.setColor(MOON).drawCircle(moonX, moonY, moonR);
|
||||
},
|
||||
// 1/4 ascending
|
||||
2: () => {
|
||||
moon[3]();
|
||||
g.setColor(BLACK).fillEllipse(
|
||||
moonX - moonR / 2,
|
||||
moonY - moonR,
|
||||
moonX + moonR / 2,
|
||||
moonY + moonR
|
||||
);
|
||||
},
|
||||
// 1/2 ascending
|
||||
3: () => {
|
||||
moon[0]();
|
||||
g.setColor(MOON)
|
||||
.fillCircle(moonX, moonY, moonR)
|
||||
.setColor(BLACK)
|
||||
.fillRect(moonX, moonY - moonR, moonX + moonR + moonR, moonY + moonR);
|
||||
},
|
||||
// 3/4 ascending
|
||||
4: () => {
|
||||
moon[7]();
|
||||
g.setColor(MOON).fillEllipse(
|
||||
moonX - moonR / 2,
|
||||
moonY - moonR,
|
||||
moonX + moonR / 2,
|
||||
moonY + moonR
|
||||
);
|
||||
},
|
||||
// Full moon
|
||||
5: () => {
|
||||
moon[0]();
|
||||
g.setColor(MOON).fillCircle(moonX, moonY, moonR);
|
||||
},
|
||||
// 3/4 descending
|
||||
6: () => {
|
||||
moon[3]();
|
||||
g.setColor(MOON).fillEllipse(
|
||||
moonX - moonR / 2,
|
||||
moonY - moonR,
|
||||
moonX + moonR / 2,
|
||||
moonY + moonR
|
||||
);
|
||||
},
|
||||
// 1/2 descending
|
||||
7: () => {
|
||||
moon[0]();
|
||||
g.setColor(MOON)
|
||||
.fillCircle(moonX, moonY, moonR)
|
||||
.setColor(BLACK)
|
||||
.fillRect(moonX - moonR, moonY - moonR, moonX, moonY + moonR);
|
||||
},
|
||||
// 1/4 descending
|
||||
8: () => {
|
||||
moon[7]();
|
||||
g.setColor(BLACK).fillEllipse(
|
||||
moonX - moonR / 2,
|
||||
moonY - moonR,
|
||||
moonX + moonR / 2,
|
||||
moonY + moonR
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function moonPhase(d) {
|
||||
var tmp,
|
||||
month = d.getMonth(),
|
||||
year = d.getFullYear(),
|
||||
day = d.getDate();
|
||||
if (month < 3) {
|
||||
year--;
|
||||
month += 12;
|
||||
}
|
||||
tmp = (365.25 * year + 30.6 * ++month + day - NM) / MC;
|
||||
return Math.round((tmp - (tmp | 0)) * 7 + 1);
|
||||
}
|
||||
|
||||
const currentMoonPhase = moonPhase(d);
|
||||
if (currentMoonPhase != lastMoonPhase) {
|
||||
moon[currentMoonPhase]();
|
||||
lastMoonPhase = currentMoonPhase;
|
||||
}
|
||||
}
|
||||
|
||||
function drawTime(d) {
|
||||
const da = d.toString().split(" ");
|
||||
const time = da[4].substr(0, 5).split(":");
|
||||
const dow = da[0];
|
||||
const month = da[1];
|
||||
const day = da[2];
|
||||
const year = da[3];
|
||||
const hours = time[0];
|
||||
const minutes = time[1];
|
||||
const seconds = d.getSeconds();
|
||||
if (minutes != lastMinutes) {
|
||||
g.clearRect(0, 24, moonX - moonR - 10, 239);
|
||||
g.setColor(1, 1, 1);
|
||||
g.setFontAlign(-1, -1);
|
||||
g.setFont("Vector", 100);
|
||||
g.drawString(hours, 50, 24, true);
|
||||
g.setColor(1, 50, 1);
|
||||
g.drawString(minutes, 50, 135, true);
|
||||
g.setFont("Vector", 20);
|
||||
g.setRotation(3);
|
||||
g.drawString(`${dow} ${day} ${month}`, 50, 15, true);
|
||||
g.drawString(year, 75, 205, true);
|
||||
lastMinutes = minutes;
|
||||
}
|
||||
g.setRotation(0);
|
||||
g.setFont("Vector", 20);
|
||||
g.setColor(1, 1, 1);
|
||||
g.setFontAlign(0, -1);
|
||||
g.clearRect(200, 210, 240, 240);
|
||||
g.drawString(seconds, 215, 215);
|
||||
}
|
||||
|
||||
function drawClockFace() {
|
||||
const d = new Date();
|
||||
drawTime(d);
|
||||
drawMoon(d);
|
||||
}
|
||||
|
||||
Bangle.on("lcdPower", function(on) {
|
||||
if (on) {
|
||||
g.clear();
|
||||
Bangle.drawWidgets();
|
||||
drawClockFace();
|
||||
interval = setInterval(drawClockFace, REFRESH_RATE);
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
lastMinutes = undefined;
|
||||
lastMoonPhase = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
Bangle.setLCDMode();
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
clearWatch();
|
||||
setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });
|
||||
setWatch(
|
||||
function() {
|
||||
load(BTN1app);
|
||||
},
|
||||
BTN1,
|
||||
{ repeat: false, edge: "rising" }
|
||||
);
|
||||
setWatch(
|
||||
function() {
|
||||
load(BTN3app);
|
||||
},
|
||||
BTN3,
|
||||
{ repeat: false, edge: "rising" }
|
||||
);
|
||||
|
||||
g.clear();
|
||||
clearInterval();
|
||||
drawClockFace();
|
||||
interval = setInterval(drawClockFace, REFRESH_RATE);
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"BTN1": "timer.app.js",
|
||||
"BTN3": "calendar.app.js"
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 513 B |
|
@ -0,0 +1,72 @@
|
|||
(function(back) {
|
||||
const s = require("Storage");
|
||||
const apps = s
|
||||
.list(/\.info$/)
|
||||
.map(app => {
|
||||
var a = s.readJSON(app, 1);
|
||||
return (
|
||||
a && {
|
||||
n: a.name,
|
||||
t: a.type,
|
||||
src: a.src
|
||||
}
|
||||
);
|
||||
})
|
||||
.filter(app => app && (app.t == "app" || app.t == "clock" || !app.t))
|
||||
.map(a => {
|
||||
return { n: a.n, src: a.src };
|
||||
});
|
||||
apps.sort((a, b) => {
|
||||
if (a.n < b.n) return -1;
|
||||
if (a.n > b.n) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
const settings = s.readJSON("largeclock.json", 1) || {
|
||||
BTN1: "",
|
||||
BTN3: ""
|
||||
};
|
||||
|
||||
function showApps(btn) {
|
||||
function format(v) {
|
||||
return v === settings[btn] ? "*" : "";
|
||||
}
|
||||
|
||||
function onchange(v) {
|
||||
settings[btn] = v;
|
||||
s.write("largeclock.json", settings);
|
||||
}
|
||||
|
||||
const btnMenu = {
|
||||
"": {
|
||||
title: `Apps for ${btn}`
|
||||
},
|
||||
"< Back": () => E.showMenu(mainMenu)
|
||||
};
|
||||
|
||||
if (apps.length > 0) {
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
btnMenu[apps[i].n] = {
|
||||
value: apps[i].src,
|
||||
format: format,
|
||||
onchange: onchange
|
||||
};
|
||||
}
|
||||
} else {
|
||||
btnMenu["...No Apps..."] = {
|
||||
value: undefined,
|
||||
format: () => "",
|
||||
onchange: () => {}
|
||||
};
|
||||
}
|
||||
return E.showMenu(btnMenu);
|
||||
}
|
||||
|
||||
const mainMenu = {
|
||||
"": { title: "Large Clock Settings" },
|
||||
"< Back": back,
|
||||
"BTN1 app": () => showApps("BTN1"),
|
||||
"BTN3 app": () => showApps("BTN3")
|
||||
};
|
||||
E.showMenu(mainMenu);
|
||||
});
|
Loading…
Reference in New Issue