1
0
Fork 0

Merge branch 'master' of github.com:espruino/BangleApps

master
Gordon Williams 2023-02-20 15:46:16 +00:00
commit 55d7a893b1
8 changed files with 239 additions and 0 deletions

1
apps/rings/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: First rev. Could use a little optimization love.

11
apps/rings/README.md Normal file
View File

@ -0,0 +1,11 @@
# Rings watchface
Ring based watchface, read from the outside in. When the watch is unlocked the circles shrink to show the date ring.
By Amos Blanton, inspired by and remixed from Rinkulainen by Jukio Kallio.
![](screenshot1.png)
View when watch is locked.
![](screenshot2.png)
Watch unlocked, showing the date.

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

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwxH+CR0GAokMiUMAQQLFAooAYg0SjEYjwAHjA0BGLQXChgrEGIIGCG4wyBLbItFFQYnDFgYREGIRiRCISHIFQgEDMYgCCSoYuPhi1IXg4vFMYI5CSh4uBJwYAEj5bDAAjGCjIzDTwguWFoMShkOgIVFgMOLQMYHwYCDGBZdKiUHisckcOwNWgGBxEkikjkcWhCmBj4sBMJ67GDIMAiojBAANd1lWq2BAAMOo4LCjkBiQWBLwQ0CK4RfGFw0SgJbBAAc51mBles1lPhwMENoMMGAJgDj0MGAoEBBgYuDhAgFkeIFgOBAQN6F40jisGYgQADRpguJL4LtEgE4B48VMIRiDSIxeFjEBDo1HWQMAqgACGIKdFAAUPYYUSSIjsJgAdHh1O1HSAAmovEICY8Id4RTDMAK9GRoMVDIscgGo6YuFAAPT1FOitHCosGFoYpBdwZeFg4uRGIYwHh4sBYIsAS4ZeJFwItKGAiSFjjyBL4aQBdo0MCwlHhxdMYgkAYJApDF48OIotOFw2ov1+NA3TvyRFisYMAJXDgCOEjCOEo8VLwuoqjXCAAIxF1EIJQsSF4RbBhkMXxcO5giEFwMqAAQwBqhkB6ZABqkdYArsBdQUSF4q+FkdUWQwrCAAQFFvzxGg5eCeARfGCYkdF4t+FI0Aq1VleBwNWgAvFFAgvHL4ovOq2swIvB1msgFAF7yPHlesLYNWwIHBR5AvJiUWd4ovE6S6EAQJfB1gyDF4rvCAAcSgwvEjEVCYdHh+o6ZgFAAksq1WlcrGwMHJQkciUfF4kAGwsOCgt4F4jCCqgABv1+SwcBgBKEkcVjAvEhkAjA0DAAIUEkcI1AvFAA+oHAIZGh0YAAQqBFAMSFodWkhFFjlOMAwAH6d+DA0MjESGIYrD1kAwOswMyIwsVGBouBhAXGXwRfCLYYsBAQIDBvUcC4lHGALzFFojHBFw0jcwq+CL4eBgGs1lWgwYFo8cgF+5gpBAAQvB0SlBo4VFh5bBRwIuBRwMGL4QABleBrgHBhxKGPYMIql+AAVUg8VjouGi0Mj7uELwYAGhkZhjZFMQTeCAAYIDdgqNCFoMMLwoABlYFBmJsCj8GGA4yCAAQMIFwJaCdoZeIBwQACj8Mh4jIABUWFwS8Dj0SLwovIGAMShCEBAB8PQ4JbCLoSNBABIwHjEGh4xMjkVDQMZRggEBFxQwIDIUMhEVdQQrDFgMOg0SCIQYFRY4wPj4gBiUMg8MAQS0BCgINBLYguDGBxJCGI4kCA5S7GFxwABa4QAXiQrPAAQ/CSZAANjBaQGA8MGKUYhiLSGJEGcgIsMfQItYGIxlChg0BAAUSFYYtQ"))

210
apps/rings/app.js Normal file
View File

@ -0,0 +1,210 @@
// Rings watch face
// for Bangle.js 2
// by Amos Blanton
// Remixed from / inspired by Rinkulainen watch face by Jukio Kallio
// To Do:
// Make Month / year text buffer 1/2 size
// Optimize text positioning transforms
const watch = {
x:0, y:0, w:0, h:0,
color:"#000000",
dateRing : { size:109, weight:20, color:"#00FF00", cursor:14, numbers: true },
hourRing : { size:85, weight:20, color:"#00FFFF", cursor:14, numbers: true },
minuteRing : { size:61, weight:20, color:"#FFFF00", cursor:14, numbers: true },
screen : { width:g.getWidth(), height:g.getHeight(), centerX: g.getWidth() *0.5, centerY: g.getHeight() * 0.5, cursor: 14, font:"6x8:2" },
};
const month= ["JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY",
"AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"];
var wait = 60000; // wait time, normally a minute
// timeout used to update every minute
var drawTimeout;
// Global for use in shrink / unshrink animations
var counter = 1;
// Buffer for month circle text, 1/2 screen size (will be scaled up)
var monthCircleTextBuffer= Graphics.createArrayBuffer(watch.screen.width,watch.screen.height,1,{msb:true});
var monthCircleTextImg = monthCircleTextBuffer.asImage();
monthCircleTextImg.transparent = 1;
var lastMonthCircleImageText = "";
// Calculate number of days in this month / year for date ring
const getDays = (year, thisMonth) => {
return new Date(year, thisMonth, 0).getDate(); // getMonth() Jan = 0.
};
// Schedule a draw for the next minute
function queueDraw() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, wait - (Date.now() % wait));
}
// Draws a time circle (date, hours, minutes)
function drawTimeCircle(color, size, weight, range, value ) {
// variables for vertex transformations and positioning time
var tver, tobj, tran;
var ttime = (value / range) * (Math.PI * 2);
// draw circle and line
g.setColor(color).fillCircle(watch.screen.centerX, watch.screen.centerY, size);
g.setColor("#000000").fillCircle(watch.screen.centerX, watch.screen.centerY, size - weight);
tver = [-watch.screen.cursor, 0, watch.screen.cursor, 0, watch.screen.cursor, -size*1.01, -watch.screen.cursor, -size*1.05];
tobj = { x:watch.screen.centerX, y:watch.screen.centerY, scale:1, rotate:ttime };
tran = g.transformVertices(tver, tobj);
g.fillPoly(tran);
// Draw numbers
g.setFontAlign(0,0).setFont(watch.screen.font, 2).setColor(1,1,1);
// size - 21 is the right offset to get the numbers aligned in the circle.
tver = [-1, 0, 1, 0, 1, -size, -1, -(size -21)];
tran = g.transformVertices(tver, tobj);
g.setColor(1,1,1);
g.drawString(value, (tran[4]+tran[6]) / 2 , (tran[5]+tran[7]) / 2 );
}
// Draws text for month and year in date circle
function drawMonthCircleText( text, circleSize, range, value){
// If the text isn't the same as last time, write it into a graphic object.
if(text != lastMonthCircleImageText){
monthCircleTextBuffer.clear();
monthCircleTextBuffer.fillRect(0,0,watch.screen.width,watch.screen.height);
var tver, tobj, tran;
// From here: https://forum.espruino.com/comments/16781795/
var gr = Graphics.createArrayBuffer(24,16,1,{msb:true});
var grimg = gr.asImage();
grimg.transparent = 1;
monthCircleTextBuffer.setColor(0,0,0);
for(z=0; z < text.length; z++){
tobj = { x:watch.screen.centerX, y:watch.screen.centerY, scale:1, rotate: ((z + 1) / range) * (Math.PI * 2) };
tver = [-1, 0, 1, 0, 1, -circleSize, -1, -(circleSize -21)];
tran = monthCircleTextBuffer.transformVertices(tver, tobj);
gr.clear().setColor(1,1,1).fillRect(0,0,24,16).setColor(0,0,0).setFont(watch.screen.font).setFontAlign(0,0).drawString(text[z],12,8);
monthCircleTextBuffer.drawImage(grimg,
(tran[4]+tran[6]) / 2,
(tran[5]+tran[7]) / 2,
{rotate:((z+1) / range) * (Math.PI * 2) });
}
lastMonthCircleImageText = text;
}
// Determine correct rotation for text in ring ( opposite the date position )
var offset = value + (range / 2) - (text.length / 2);
if(offset > range)
offset = offset - range;
var rotation = (offset / range) * (Math.PI * 2);
// Draw the image of text to the screen at that rotation
g.drawImage(monthCircleTextImg, watch.screen.centerX, watch.screen.centerY, {scale:1, rotate:rotation });
}
// Animate by shrinking or expanding circles
function shrinkCircles(toggle){
// If there's a queued draw operation,removeit so animation isn't interrupted.
if (drawTimeout) clearTimeout(drawTimeout);
var date = new Date();
var delta = 1;
if(counter > 12)
{
counter = 1;
// We're finished, so queue next draw.
queueDraw();
return;
}
if(toggle) // We are shrinking
delta = counter * 2 * -1;
else // We are expanding
delta = counter *2 - 24;
// Clear space on screen.
g.setColor(watch.color);
g.fillRect(0, 0, watch.screen.width, watch.screen.height);
// Draw the date ring (unless it's the last run of an expansion).
if(counter < 11 || toggle){
drawTimeCircle(watch.dateRing.color, watch.dateRing.size + delta, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() );
// Draw month and year in date ring
drawMonthCircleText( month[date.getMonth()]+" "+date.getFullYear(), watch.dateRing.size - 24, getDays(date.getFullYear(), date.getMonth()+1), date.getDate()) ;
}
drawTimeCircle(watch.hourRing.color, watch.hourRing.size + delta, watch.hourRing.weight, 12, date.getHours() );
drawTimeCircle(watch.minuteRing.color, watch.minuteRing.size + delta, watch.minuteRing.weight, 60, date.getMinutes() );
counter += 1;
setTimeout(shrinkCircles, 10, toggle);
}
// main draw function
function draw() {
// make date object
var date = new Date();
var unLockedOffset = 0;
// Reset the state of the graphics library
g.reset();
// Clear the area where we want to draw the time
g.setColor(watch.color);
g.fillRect(0, 0, watch.screen.width, watch.screen.height);
// If unlocked, draw date ring and text and make hour and minute rings smaller
if(!Bangle.isLocked()){
unLockedOffset = 24;
drawTimeCircle(watch.dateRing.color, watch.dateRing.size - unLockedOffset, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() );
drawMonthCircleText( month[date.getMonth()]+" "+date.getFullYear(), watch.dateRing.size - unLockedOffset, getDays(date.getFullYear(), date.getMonth()+1), date.getDate()) ;
}
drawTimeCircle(watch.hourRing.color, watch.hourRing.size - unLockedOffset, watch.hourRing.weight, 12, date.getHours() );
drawTimeCircle(watch.minuteRing.color, watch.minuteRing.size -unLockedOffset , watch.minuteRing.weight, 60, date.getMinutes() );
queueDraw();
}
// Trigger shrink / expand animation on unlock / lock events
Bangle.on('lock', on=>{
if (on) { // locked, expand circles
counter = 1;
shrinkCircles(false);
} else
{ // unlocked, shrink circles and show date ring
counter = 1;
shrinkCircles(true);
}
});
// End function definitions / start of initial execution.
// Clear the screen once, at startup
g.clear();
// draw immediately at first
draw();
// console.log("Whatevs");
// Show launcher when middle button pressed
Bangle.setUI("clock");

BIN
apps/rings/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

16
apps/rings/metadata.json Normal file
View File

@ -0,0 +1,16 @@
{ "id": "rings",
"name": "Rings - an animated watchface",
"shortName":"Rings",
"version":"0.01",
"description": "Ring based watchface that animates to show the date when unlocked. Inspired by / remixed from Rinkulainen.",
"icon": "app.png",
"screenshots": [{"url":"screenshot1.png"}, {"url":"screenshot2.png"}],
"type": "clock",
"tags": "clock",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"rings.app.js","url":"app.js"},
{"name":"rings.img","url":"app-icon.js","evaluate":true}
]
}

BIN
apps/rings/screenshot1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
apps/rings/screenshot2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB