forked from FOSS/BangleApps
commit
daf7e745ec
|
@ -0,0 +1 @@
|
|||
0.1: init app
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 Paul Spenke
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,11 @@
|
|||
# Line Clock
|
||||
|
||||
This app displays a simple, different looking, analog clock. It considers the
|
||||
currently configured "theme" (and may therefore look different than shown in
|
||||
the screenshot on your watch depending on which theme you prefer).
|
||||
|
||||

|
||||
|
||||
## License
|
||||
|
||||
[MIT License](LICENSE)
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwgYMJh/4AgUD+AeKgIRDj/+n41O/4RQABcfIJYAEKZgAkL4U/8ARNBwIRP/+AGx6YBPSH/4ASPh/A/hfDAAZAHg/8gP/LguSoARHEwIRFiVJkDCFjgRHgEJkg4CcwQjIAAMEHAUDCoIRB46kIHAkH//xLIw4I8eAnCNKHAYAO/xxEABg4ByASPHAkBKAbUE/5xGhP//wRFv4RDOIYIB//ACQr1FHAIRJAA0TCAP/ZwIALgYRJVowRCj/4BIkBLIgABgRHC/KqFaI4RC5MkJBlPR4UECJizJJwoAKCKImVQAwAJv0HL5S6CbwIjLCKMAn4RDh0/LMKMhWaYAKA="))
|
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,287 @@
|
|||
const handWidth = 6;
|
||||
const hourRadius = 4;
|
||||
const hourWidth = 8;
|
||||
const hourLength = 40;
|
||||
const hourSLength = 20;
|
||||
const radius = 220;
|
||||
const lineOffset = 115;
|
||||
const hourOffset = 32;
|
||||
const numberOffset = 85;
|
||||
const numberSize = 22;
|
||||
|
||||
const storage = require('Storage');
|
||||
|
||||
const SETTINGS_FILE = "line_clock.setting.json";
|
||||
|
||||
let initialSettings = {
|
||||
showLock: true,
|
||||
showMinute: true,
|
||||
};
|
||||
|
||||
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || initialSettings;
|
||||
for (const key in saved_settings) {
|
||||
initialSettings[key] = saved_settings[key];
|
||||
}
|
||||
|
||||
let gWidth = g.getWidth(), gCenterX = gWidth/2;
|
||||
let gHeight = g.getHeight(), gCenterY = gHeight/2;
|
||||
|
||||
let currentTime = new Date();
|
||||
let currentHour = currentTime.getHours();
|
||||
let currentMinute = currentTime.getMinutes();
|
||||
|
||||
let drawTimeout;
|
||||
|
||||
function imgLock() {
|
||||
return {
|
||||
width : 16, height : 16, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : E.toArrayBuffer(atob("A8AH4A5wDDAYGBgYP/w//D/8Pnw+fD58Pnw//D/8P/w="))
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the angle of the hour hand for the current time.
|
||||
*
|
||||
* @returns {number} The angle of the hour hand in degrees.
|
||||
*/
|
||||
function getHourHandAngle() {
|
||||
let hourHandAngle = 30 * currentHour;
|
||||
hourHandAngle += 0.5 * currentMinute;
|
||||
return hourHandAngle;
|
||||
}
|
||||
|
||||
let hourAngle = getHourHandAngle();
|
||||
|
||||
/**
|
||||
* Converts degrees to radians.
|
||||
*
|
||||
* @param {number} degrees - The degrees to be converted to radians.
|
||||
* @return {number} - The equivalent value in radians.
|
||||
*/
|
||||
function degreesToRadians(degrees) {
|
||||
return degrees * (Math.PI / 180);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates an array of points around a given angle and radius.
|
||||
*
|
||||
* @param {Array} points - The array of points to be rotated.
|
||||
* @param {number} angle - The angle in degrees to rotate the points.
|
||||
* @param {number} rad - The radius to offset the rotation.
|
||||
* @returns {Array} - The array of rotated points.
|
||||
*/
|
||||
function rotatePoints(points, angle, rad) {
|
||||
const ang = degreesToRadians(angle);
|
||||
const hAng = degreesToRadians(hourAngle);
|
||||
const rotatedPoints = [];
|
||||
points.map(function(point) {
|
||||
return {
|
||||
x: point.x * Math.cos(ang) - point.y * Math.sin(ang),
|
||||
y: point.x * Math.sin(ang) + point.y * Math.cos(ang)
|
||||
};
|
||||
}).forEach(function(point) {
|
||||
rotatedPoints.push(point.x + gCenterX - (rad * Math.sin(hAng)));
|
||||
rotatedPoints.push(point.y + gCenterY + (rad * Math.cos(hAng)));
|
||||
});
|
||||
return rotatedPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a hand on the canvas.
|
||||
*
|
||||
* @function drawHand
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function drawHand() {
|
||||
g.setColor(0xF800);
|
||||
const halfWidth = handWidth / 2;
|
||||
|
||||
const points = [{
|
||||
x: -halfWidth,
|
||||
y: -gHeight
|
||||
}, {
|
||||
x: halfWidth,
|
||||
y: -gHeight
|
||||
}, {
|
||||
x: halfWidth,
|
||||
y: gHeight
|
||||
}, {
|
||||
x: -halfWidth,
|
||||
y: gHeight
|
||||
}];
|
||||
|
||||
g.fillPolyAA(rotatePoints(points, hourAngle, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the hour coordinates for a given small flag.
|
||||
* @param {boolean} small - Determines if the flag is small.
|
||||
* @returns {Array} - An array of hour coordinates.
|
||||
*/
|
||||
function getHourCoordinates(small) {
|
||||
const dist = small ? (hourSLength - hourLength) : 0;
|
||||
const halfWidth = hourWidth / 2;
|
||||
const gh = gHeight + lineOffset;
|
||||
return [{
|
||||
x: -halfWidth,
|
||||
y: -gh - dist
|
||||
}, {
|
||||
x: halfWidth,
|
||||
y: -gh - dist
|
||||
}, {
|
||||
x: halfWidth,
|
||||
y: -gh + hourLength
|
||||
}, {
|
||||
x: -halfWidth,
|
||||
y: -gh + hourLength
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the given time to the hour dot on the clock face.
|
||||
*
|
||||
* @param {number} a - The time value to assign to the hour dot.
|
||||
* @return {void}
|
||||
*/
|
||||
function hourDot(a) {
|
||||
const h = gHeight + lineOffset;
|
||||
const rotatedPoints = rotatePoints(
|
||||
[{
|
||||
x: 0,
|
||||
y: -h + hourLength - (hourRadius / 2)
|
||||
}], a, radius
|
||||
);
|
||||
g.fillCircle(rotatedPoints[0], rotatedPoints[1], hourRadius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an hour into a number and display it on the clock face.
|
||||
*
|
||||
* @param {number} a - The hour to be converted (between 0 and 360 degrees).
|
||||
*/
|
||||
function hourNumber(a) {
|
||||
const h = gHeight + lineOffset;
|
||||
const rotatedPoints = rotatePoints(
|
||||
[{
|
||||
x: 0,
|
||||
y: -h + hourLength + hourOffset
|
||||
}], a, radius
|
||||
);
|
||||
g.drawString(String(a / 30), rotatedPoints[0], rotatedPoints[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a number on the display.
|
||||
*
|
||||
* @param {number} n - The number to be drawn.
|
||||
* @return {void}
|
||||
*/
|
||||
function drawNumber(n) {
|
||||
const h = gHeight + lineOffset;
|
||||
const halfWidth = handWidth / 2;
|
||||
const rotatedPoints = rotatePoints(
|
||||
[{
|
||||
x: 0,
|
||||
y: -h + hourLength + numberOffset
|
||||
}], hourAngle, radius
|
||||
);
|
||||
g.setColor(0xF800);
|
||||
g.fillCircle(rotatedPoints[0], rotatedPoints[1], numberSize+ halfWidth);
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillCircle(rotatedPoints[0], rotatedPoints[1], numberSize - halfWidth);
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFont("Vector:"+numberSize);
|
||||
g.drawString(String(n), rotatedPoints[0], rotatedPoints[1]);
|
||||
}
|
||||
|
||||
const hourPoints = getHourCoordinates(false);
|
||||
const hourSPoints = getHourCoordinates(true);
|
||||
|
||||
/**
|
||||
* Draws an hour on a clock face.
|
||||
*
|
||||
* @param {number} h - The hour to be drawn on the clock face.
|
||||
* @return {undefined}
|
||||
*/
|
||||
function drawHour(h) {
|
||||
if (h === 0) { h= 12; }
|
||||
if (h === 13) { h= 1; }
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFont("Vector:32");
|
||||
const a = h * 30;
|
||||
g.fillPolyAA(rotatePoints(hourPoints, a, radius));
|
||||
g.fillPolyAA(rotatePoints(hourSPoints, a + 15, radius));
|
||||
hourNumber(a);
|
||||
hourDot(a + 5);
|
||||
hourDot(a + 10);
|
||||
hourDot(a + 20);
|
||||
hourDot(a + 25);
|
||||
}
|
||||
|
||||
function queueDraw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
}
|
||||
|
||||
function lockListenerBw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}
|
||||
Bangle.on('lock', lockListenerBw);
|
||||
|
||||
Bangle.setUI({
|
||||
mode : "clock",
|
||||
// TODO implement https://www.espruino.com/Bangle.js+Fast+Load
|
||||
// remove : function() {
|
||||
// Bangle.removeListener('lock', lockListenerBw);
|
||||
// if (drawTimeout) clearTimeout(drawTimeout);
|
||||
// drawTimeout = undefined;
|
||||
// }
|
||||
});
|
||||
|
||||
/**
|
||||
* Draws a clock on the canvas using the current time.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
function draw() {
|
||||
queueDraw();
|
||||
currentTime = new Date();
|
||||
currentHour = currentTime.getHours();
|
||||
if (currentHour > 12) {
|
||||
currentHour -= 12;
|
||||
}
|
||||
currentMinute = currentTime.getMinutes();
|
||||
|
||||
hourAngle = getHourHandAngle();
|
||||
|
||||
g.clear();
|
||||
g.setFontAlign(0, 0);
|
||||
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(0, 0, gWidth, gHeight);
|
||||
|
||||
if(initialSettings.showLock && Bangle.isLocked()){
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawImage(imgLock(), gWidth-16, 2);
|
||||
}
|
||||
|
||||
drawHour(currentHour);
|
||||
drawHour(currentHour-1);
|
||||
drawHour(currentHour+1);
|
||||
|
||||
|
||||
drawHand();
|
||||
|
||||
if(initialSettings.showMinute){
|
||||
drawNumber(currentMinute);
|
||||
}
|
||||
}
|
||||
|
||||
draw();
|
|
@ -0,0 +1,19 @@
|
|||
{ "id": "line_clock",
|
||||
"name": "Line Clock",
|
||||
"shortName":"Line Clock",
|
||||
"version":"0.1",
|
||||
"description": "a readable analog clock",
|
||||
"icon": "app-icon.png",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"screenshots": [{"url":"app-screenshot.png"}],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"line_clock.app.js","url":"app.js"},
|
||||
{"name":"line_clock.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"line_clock.settings.js","url":"settings.js"}
|
||||
],
|
||||
"data":[{"name":"line_clock.setting.json"}]
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
(function(back) {
|
||||
const SETTINGS_FILE = "line_clock.setting.json";
|
||||
|
||||
// initialize with default settings...
|
||||
const storage = require('Storage')
|
||||
let settings = {
|
||||
showLock: true,
|
||||
showMinute: true,
|
||||
};
|
||||
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
|
||||
for (const key in saved_settings) {
|
||||
settings[key] = saved_settings[key]
|
||||
}
|
||||
|
||||
function save() {
|
||||
storage.write(SETTINGS_FILE, settings)
|
||||
}
|
||||
|
||||
E.showMenu({
|
||||
'': { 'title': 'Line Clock' },
|
||||
'< Back': back,
|
||||
'Show Lock': {
|
||||
value: settings.showLock,
|
||||
onchange: () => {
|
||||
settings.showLock = !settings.showLock;
|
||||
save();
|
||||
},
|
||||
},
|
||||
'Show Minute': {
|
||||
value: settings.showMinute,
|
||||
onchange: () => {
|
||||
settings.showMinute = !settings.showMinute;
|
||||
save();
|
||||
},
|
||||
}
|
||||
});
|
||||
})
|
Loading…
Reference in New Issue