Merge pull request #3291 from paul-arg/master
Two new apps: Elapsed Time Clock and Vaporwave Sunset Clockmaster
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Elapsed Time Clock
|
||||
A clock that calculates the time difference between now (in blue/cyan) and any given target date (in red/orange).
|
||||
|
||||
The results is show in years, months, days, hours, minutes, seconds. To save battery life, the seconds are shown only when the watch is unlocked, or can be disabled entirely.
|
||||
|
||||
The time difference is positive if the target date is in the past and negative if it is in the future.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# Settings
|
||||
## Time and date formats:
|
||||
- time can be shown in 24h or in AM/PM format
|
||||
- date can be shown in DD/MM/YYYY, MM/DD/YYYY or YYYY-MM-DD format
|
||||
|
||||
## Display years and months
|
||||
You can select if the difference is shown with years, months and days, or just days.
|
||||
|
||||
# TODO
|
||||
- add the option to set an alarm to the target date
|
||||
- add an offset to said alarm (e.g. x hours/days... before/after)
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwcA/4A/AH8kyVJARAQE/YRLn4RD/IRT5cs2QCEEbQgFAQYjIrMlAQwjR5JHIsv2pNkz3JsgjKl/yEAO/I5l/+REBz/7I5f/EYf/I5Vf//2rNlz//8gjJAgIjE/hHIy7xEAAQjIDoIAG+RHHCA///wjHCJIjHMoI1HEY+zCI6zJv4dCFIX9R5PPR4vsEZNJCILXC/77JyXLn4jD/b7KpMnI4fZBARHHpcsEYW2AQIjKARBHIDoICECJIjRpZKCAQYjbCMH/CJVLCAgA/AHYA=="))
|
||||
|
|
@ -0,0 +1,437 @@
|
|||
const APP_NAME = "elapsed_t";
|
||||
|
||||
//const COLOUR_BLACK = 0x0;
|
||||
//const COLOUR_DARK_GREY = 0x4208; // same as: g.setColor(0.25, 0.25, 0.25)
|
||||
const COLOUR_GREY = 0x8410; // same as: g.setColor(0.5, 0.5, 0.5)
|
||||
const COLOUR_LIGHT_GREY = 0xc618; // same as: g.setColor(0.75, 0.75, 0.75)
|
||||
const COLOUR_RED = 0xf800; // same as: g.setColor(1, 0, 0)
|
||||
const COLOUR_BLUE = 0x001f; // same as: g.setColor(0, 0, 1)
|
||||
//const COLOUR_YELLOW = 0xffe0; // same as: g.setColor(1, 1, 0)
|
||||
//const COLOUR_LIGHT_CYAN = 0x87ff; // same as: g.setColor(0.5, 1, 1)
|
||||
//const COLOUR_DARK_YELLOW = 0x8400; // same as: g.setColor(0.5, 0.5, 0)
|
||||
//const COLOUR_DARK_CYAN = 0x0410; // same as: g.setColor(0, 0.5, 0.5)
|
||||
const COLOUR_CYAN = "#00FFFF";
|
||||
const COLOUR_ORANGE = 0xfc00; // same as: g.setColor(1, 0.5, 0)
|
||||
|
||||
const SCREEN_WIDTH = g.getWidth();
|
||||
const SCREEN_HEIGHT = g.getHeight();
|
||||
const BIG_FONT_SIZE = 38;
|
||||
const SMALL_FONT_SIZE = 22;
|
||||
|
||||
var arrowFont = atob("BwA4AcAOAHADgBwA4McfOf3e/+P+D+A+AOA="); // contains only the > character
|
||||
|
||||
var now = new Date();
|
||||
|
||||
var settings = Object.assign({
|
||||
// default values
|
||||
displaySeconds: true,
|
||||
displayMonthsYears: true,
|
||||
dateFormat: 0,
|
||||
time24: true
|
||||
}, require('Storage').readJSON(APP_NAME + ".settings.json", true) || {});
|
||||
|
||||
var temp_displaySeconds = settings.displaySeconds;
|
||||
|
||||
var data = Object.assign({
|
||||
// default values
|
||||
target: {
|
||||
isSet: false,
|
||||
Y: now.getFullYear(),
|
||||
M: now.getMonth() + 1, // Month is zero-based, so add 1
|
||||
D: now.getDate(),
|
||||
h: now.getHours(),
|
||||
m: now.getMinutes(),
|
||||
s: now.getSeconds()
|
||||
}
|
||||
}, require('Storage').readJSON(APP_NAME + ".data.json", true) || {});
|
||||
|
||||
function writeData() {
|
||||
require('Storage').writeJSON(APP_NAME + ".data.json", data);
|
||||
}
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(APP_NAME + ".settings.json", settings);
|
||||
temp_displaySeconds = settings.temp_displaySeconds;
|
||||
}
|
||||
|
||||
let inMenu = false;
|
||||
|
||||
Bangle.on('touch', function (zone, e) {
|
||||
if (!inMenu) {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
E.showMenu(menu);
|
||||
inMenu = true;
|
||||
}
|
||||
});
|
||||
|
||||
function pad2(number) {
|
||||
return (String(number).padStart(2, '0'));
|
||||
}
|
||||
|
||||
function formatDateTime(date, dateFormat, time24, showSeconds) {
|
||||
var formattedDateTime = {
|
||||
date: "",
|
||||
time: ""
|
||||
};
|
||||
|
||||
var DD = pad2(date.getDate());
|
||||
var MM = pad2(date.getMonth() + 1); // Month is zero-based
|
||||
var YYYY = date.getFullYear();
|
||||
var h = date.getHours();
|
||||
var hh = pad2(date.getHours());
|
||||
var mm = pad2(date.getMinutes());
|
||||
var ss = pad2(date.getSeconds());
|
||||
|
||||
switch (dateFormat) {
|
||||
case 0:
|
||||
formattedDateTime.date = `${DD}/${MM}/${YYYY}`;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
formattedDateTime.date = `${MM}/${DD}/${YYYY}`;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
formattedDateTime.date = `${YYYY}-${MM}-${DD}`;
|
||||
break;
|
||||
|
||||
default:
|
||||
formattedDateTime.date = `${YYYY}-${MM}-${DD}`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (time24) {
|
||||
formattedDateTime.time = `${hh}:${mm}${showSeconds ? `:${ss}` : ''}`;
|
||||
} else {
|
||||
var ampm = (h >= 12 ? 'PM' : 'AM');
|
||||
var h_ampm = h % 12;
|
||||
h_ampm = (h_ampm == 0 ? 12 : h_ampm);
|
||||
formattedDateTime.time = `${h_ampm}:${mm}${showSeconds ? `:${ss}` : ''}${ampm}`;
|
||||
}
|
||||
|
||||
return formattedDateTime;
|
||||
}
|
||||
|
||||
function howManyDaysInMonth(month, year) {
|
||||
return new Date(year, month, 0).getDate();
|
||||
}
|
||||
|
||||
function handleExceedingDay() {
|
||||
var maxDays = howManyDaysInMonth(data.target.M, data.target.Y);
|
||||
menu.Day.max = maxDays;
|
||||
if (data.target.D > maxDays) {
|
||||
menu.Day.value = maxDays;
|
||||
data.target.D = maxDays;
|
||||
}
|
||||
}
|
||||
|
||||
function setTarget(set) {
|
||||
if (set) {
|
||||
target = new Date(
|
||||
data.target.Y,
|
||||
data.target.M - 1,
|
||||
data.target.D,
|
||||
data.target.h,
|
||||
data.target.m,
|
||||
data.target.s
|
||||
);
|
||||
data.target.isSet = true;
|
||||
} else {
|
||||
target = new Date();
|
||||
Object.assign(
|
||||
data,
|
||||
{
|
||||
target: {
|
||||
isSet: false,
|
||||
Y: now.getFullYear(),
|
||||
M: now.getMonth() + 1, // Month is zero-based, so add 1
|
||||
D: now.getDate(),
|
||||
h: now.getHours(),
|
||||
m: now.getMinutes(),
|
||||
s: now.getSeconds()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
writeData();
|
||||
}
|
||||
|
||||
var target;
|
||||
setTarget(data.target.isSet);
|
||||
|
||||
var drawTimeout;
|
||||
var queueMillis = 1000;
|
||||
|
||||
var menu = {
|
||||
"": {
|
||||
"title": "Set target",
|
||||
back: function () {
|
||||
E.showMenu();
|
||||
Bangle.setUI("clock");
|
||||
inMenu = false;
|
||||
draw();
|
||||
}
|
||||
},
|
||||
'Day': {
|
||||
value: data.target.D,
|
||||
min: 1, max: 31, wrap: true,
|
||||
onchange: v => {
|
||||
data.target.D = v;
|
||||
}
|
||||
},
|
||||
'Month': {
|
||||
value: data.target.M,
|
||||
min: 1, max: 12, noList: true, wrap: true,
|
||||
onchange: v => {
|
||||
data.target.M = v;
|
||||
handleExceedingDay();
|
||||
}
|
||||
},
|
||||
'Year': {
|
||||
value: data.target.Y,
|
||||
min: 1900, max: 2100,
|
||||
onchange: v => {
|
||||
data.target.Y = v;
|
||||
handleExceedingDay();
|
||||
}
|
||||
},
|
||||
'Hours': {
|
||||
value: data.target.h,
|
||||
min: 0, max: 23, wrap: true,
|
||||
onchange: v => {
|
||||
data.target.h = v;
|
||||
},
|
||||
format: function (v) { return pad2(v); }
|
||||
},
|
||||
'Minutes': {
|
||||
value: data.target.m,
|
||||
min: 0, max: 59, wrap: true,
|
||||
onchange: v => {
|
||||
data.target.m = v;
|
||||
},
|
||||
format: function (v) { return pad2(v); }
|
||||
},
|
||||
'Seconds': {
|
||||
value: data.target.s,
|
||||
min: 0, max: 59, wrap: true,
|
||||
onchange: v => {
|
||||
data.target.s = v;
|
||||
},
|
||||
format: function (v) { return pad2(v); }
|
||||
},
|
||||
'Save': function () {
|
||||
E.showMenu();
|
||||
inMenu = false;
|
||||
Bangle.setUI("clock");
|
||||
setTarget(true);
|
||||
writeSettings();
|
||||
temp_displaySeconds = settings.displaySeconds;
|
||||
updateQueueMillis(settings.displaySeconds);
|
||||
draw();
|
||||
},
|
||||
'Reset': function () {
|
||||
E.showMenu();
|
||||
inMenu = false;
|
||||
Bangle.setUI("clock");
|
||||
setTarget(false);
|
||||
updateQueueMillis(settings.displaySeconds);
|
||||
draw();
|
||||
}
|
||||
};
|
||||
|
||||
function queueDraw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
var delay = queueMillis - (Date.now() % queueMillis);
|
||||
if (queueMillis == 60000 && signIsNegative()) {
|
||||
delay += 1000;
|
||||
}
|
||||
|
||||
drawTimeout = setTimeout(function () {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
function updateQueueMillis(displaySeconds) {
|
||||
if (displaySeconds) {
|
||||
queueMillis = 1000;
|
||||
} else {
|
||||
queueMillis = 60000;
|
||||
}
|
||||
}
|
||||
|
||||
Bangle.on('lock', function (on, reason) {
|
||||
if (on) { // screen is locked
|
||||
temp_displaySeconds = false;
|
||||
updateQueueMillis(false);
|
||||
draw();
|
||||
} else { // screen is unlocked
|
||||
temp_displaySeconds = settings.displaySeconds;
|
||||
updateQueueMillis(temp_displaySeconds);
|
||||
draw();
|
||||
}
|
||||
});
|
||||
|
||||
function signIsNegative() {
|
||||
var now = new Date();
|
||||
return (now < target);
|
||||
}
|
||||
|
||||
function diffToTarget() {
|
||||
var diff = {
|
||||
sign: "+",
|
||||
Y: "0",
|
||||
M: "0",
|
||||
D: "0",
|
||||
hh: "00",
|
||||
mm: "00",
|
||||
ss: "00"
|
||||
};
|
||||
|
||||
if (!data.target.isSet) {
|
||||
return (diff);
|
||||
}
|
||||
|
||||
var now = new Date();
|
||||
diff.sign = now < target ? '-' : '+';
|
||||
|
||||
if (settings.displayMonthsYears) {
|
||||
var start;
|
||||
var end;
|
||||
|
||||
if (now > target) {
|
||||
start = target;
|
||||
end = now;
|
||||
} else {
|
||||
start = now;
|
||||
end = target;
|
||||
}
|
||||
|
||||
diff.Y = end.getFullYear() - start.getFullYear();
|
||||
diff.M = end.getMonth() - start.getMonth();
|
||||
diff.D = end.getDate() - start.getDate();
|
||||
diff.hh = end.getHours() - start.getHours();
|
||||
diff.mm = end.getMinutes() - start.getMinutes();
|
||||
diff.ss = end.getSeconds() - start.getSeconds();
|
||||
|
||||
// Adjust negative differences
|
||||
if (diff.ss < 0) {
|
||||
diff.ss += 60;
|
||||
diff.mm--;
|
||||
}
|
||||
if (diff.mm < 0) {
|
||||
diff.mm += 60;
|
||||
diff.hh--;
|
||||
}
|
||||
if (diff.hh < 0) {
|
||||
diff.hh += 24;
|
||||
diff.D--;
|
||||
}
|
||||
if (diff.D < 0) {
|
||||
var lastMonthDays = new Date(end.getFullYear(), end.getMonth(), 0).getDate();
|
||||
diff.D += lastMonthDays;
|
||||
diff.M--;
|
||||
}
|
||||
if (diff.M < 0) {
|
||||
diff.M += 12;
|
||||
diff.Y--;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
var timeDifference = target - now;
|
||||
timeDifference = Math.abs(timeDifference);
|
||||
|
||||
// Calculate days, hours, minutes, and seconds
|
||||
diff.D = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
||||
diff.hh = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
diff.mm = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
|
||||
diff.ss = Math.floor((timeDifference % (1000 * 60)) / 1000);
|
||||
}
|
||||
|
||||
// add zero padding
|
||||
diff.hh = pad2(diff.hh);
|
||||
diff.mm = pad2(diff.mm);
|
||||
diff.ss = pad2(diff.ss);
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
function draw() {
|
||||
var nowFormatted = formatDateTime(new Date(), settings.dateFormat, settings.time24, temp_displaySeconds);
|
||||
var targetFormatted = formatDateTime(target, settings.dateFormat, settings.time24, true);
|
||||
var diff = diffToTarget();
|
||||
|
||||
var diffYMD;
|
||||
if (settings.displayMonthsYears)
|
||||
diffYMD = `${diff.sign}${diff.Y}Y ${diff.M}M ${diff.D}D`;
|
||||
else
|
||||
diffYMD = `${diff.sign}${diff.D}D`;
|
||||
|
||||
var diff_hhmm = `${diff.hh}:${diff.mm}`;
|
||||
|
||||
g.clearRect(0, 24, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
//console.log("drawing");
|
||||
|
||||
let y = 24; //Bangle.getAppRect().y;
|
||||
|
||||
// draw current date
|
||||
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_CYAN : COLOUR_BLUE);
|
||||
g.drawString(nowFormatted.date, 4, y);
|
||||
y += SMALL_FONT_SIZE;
|
||||
|
||||
// draw current time
|
||||
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_CYAN : COLOUR_BLUE);
|
||||
g.drawString(nowFormatted.time, 4, y);
|
||||
y += SMALL_FONT_SIZE;
|
||||
|
||||
// draw arrow
|
||||
g.setFontCustom(arrowFont, 62, 16, 13).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
|
||||
g.drawString(">", 4, y + 3);
|
||||
|
||||
if (data.target.isSet) {
|
||||
// draw target date
|
||||
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
|
||||
g.drawString(targetFormatted.date, 4 + 16 + 6, y);
|
||||
y += SMALL_FONT_SIZE;
|
||||
|
||||
// draw target time
|
||||
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
|
||||
g.drawString(targetFormatted.time, 4, y);
|
||||
y += SMALL_FONT_SIZE + 4;
|
||||
|
||||
} else {
|
||||
// draw NOT SET
|
||||
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
|
||||
g.drawString("NOT SET", 4 + 16 + 6, y);
|
||||
y += 2 * SMALL_FONT_SIZE + 4;
|
||||
}
|
||||
|
||||
// draw separator
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawLine(0, y - 4, SCREEN_WIDTH, y - 4);
|
||||
|
||||
// draw diffYMD
|
||||
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(0, -1).setColor(g.theme.fg);
|
||||
g.drawString(diffYMD, SCREEN_WIDTH / 2, y);
|
||||
y += SMALL_FONT_SIZE;
|
||||
|
||||
// draw diff_hhmm
|
||||
g.setFont("Vector", BIG_FONT_SIZE).setFontAlign(0, -1).setColor(g.theme.fg);
|
||||
g.drawString(diff_hhmm, SCREEN_WIDTH / 2, y);
|
||||
|
||||
// draw diff_ss
|
||||
if (temp_displaySeconds) {
|
||||
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_LIGHT_GREY : COLOUR_GREY);
|
||||
g.drawString(diff.ss, SCREEN_WIDTH / 2 + 52, y + 13);
|
||||
}
|
||||
|
||||
queueDraw();
|
||||
}
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
Bangle.setUI("clock");
|
||||
|
||||
draw();
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"id": "elapsed_t",
|
||||
"name": "Elapsed Time Clock",
|
||||
"shortName": "Elapsed Time",
|
||||
"type": "clock",
|
||||
"version":"0.01",
|
||||
"description": "A clock that calculates the time difference between now and any given target date.",
|
||||
"tags": "clock,tool",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"elapsed_t.app.js","url":"app.js"},
|
||||
{"name":"elapsed_t.settings.js","url":"settings.js"},
|
||||
{"name":"elapsed_t.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"elapsed_t.data.json"}],
|
||||
"icon": "app.png",
|
||||
"readme": "README.md",
|
||||
"screenshots": [{ "url": "screenshot1.png" }, { "url": "screenshot2.png" }, { "url": "screenshot3.png" }, { "url": "screenshot4.png" }],
|
||||
"allow_emulator":true
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -0,0 +1,55 @@
|
|||
(function(back) {
|
||||
var APP_NAME = "elapsed_t";
|
||||
var FILE = APP_NAME + ".settings.json";
|
||||
// Load settings
|
||||
var settings = Object.assign({
|
||||
// default values
|
||||
displaySeconds: true,
|
||||
displayMonthsYears: true,
|
||||
dateFormat: 0,
|
||||
time24: true
|
||||
}, require('Storage').readJSON(APP_NAME + ".settings.json", true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
|
||||
var dateFormats = ["DD/MM/YYYY", "MM/DD/YYYY", "YYYY-MM-DD"];
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"" : { "title" : "Elapsed Time" },
|
||||
"< Back" : () => back(),
|
||||
'Show\nseconds': {
|
||||
value: !!settings.displaySeconds,
|
||||
onchange: v => {
|
||||
settings.displaySeconds = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'Show months/\nyears': {
|
||||
value: !!settings.displayMonthsYears,
|
||||
onchange: v => {
|
||||
settings.displayMonthsYears = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
'Time format': {
|
||||
value: !!settings.time24,
|
||||
onchange: v => {
|
||||
settings.time24 = v;
|
||||
writeSettings();
|
||||
},
|
||||
format: function (v) {return v ? "24h" : "AM/PM";}
|
||||
},
|
||||
'Date format': {
|
||||
value: settings.dateFormat,
|
||||
min: 0, max: 2, wrap: true,
|
||||
onchange: v => {
|
||||
settings.dateFormat = v;
|
||||
writeSettings();
|
||||
},
|
||||
format: function (v) {return dateFormats[v];}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Vaporwave Sunset Clock
|
||||
This is a simple clock with a Vaporwave Sunset theme.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
# Settings
|
||||
|
||||
You can select the text color:
|
||||
- white
|
||||
- ref
|
||||
- purple
|
||||
|
||||
# Todo
|
||||
|
||||
- add support for AM/PM time
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwcAtu27YC/AX4C/AX4C/AVnXroRO3oDBtwRMv9p02atPTCJf7AwgRK74gBEYWmpoRJ7wGF5oRJ8wjFzoRJ+nTps0AQYRI24jGzc2CJAgEAQQREBQc1EAYCDugWDEYe/EZm+/fvAR33799ARwj/EfruIARAj/AQ88+fPARwjRA"))
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
const COLOUR_BLACK = 0x0;
|
||||
const COLOUR_WHITE = 0xffff;
|
||||
//const COLOUR_DARK_GREY = "#3F3F3F";
|
||||
//const COLOUR_GREY = "#7F7F7F";
|
||||
//const COLOUR_LIGHT_GREY = "#BFBFBF";
|
||||
const COLOUR_RED = "#FF0000";
|
||||
//const COLOUR_BLUE = "#0000FF";
|
||||
//const COLOUR_YELLOW = "#FFFF00";
|
||||
//const COLOUR_LIGHT_CYAN = "#7FFFFF";
|
||||
//const COLOUR_DARK_YELLOW = "#7F7F00";
|
||||
//const COLOUR_DARK_CYAN = "#007F7F";
|
||||
//const COLOUR_ORANGE = "#FF7F00";
|
||||
const COLOUR_VPW_GREEN = 0xf0f;
|
||||
//const COLOUR_MAGENTA = "#ff00ff";
|
||||
const COLOUR_PURPLE = "#8000FF";
|
||||
|
||||
var settings = Object.assign({
|
||||
// default values
|
||||
foregroundColor: 0
|
||||
}, require('Storage').readJSON("vpw_clock.settings.json", true) || {});
|
||||
|
||||
var foregroundColor = COLOUR_BLACK;
|
||||
|
||||
switch (settings.foregroundColor) {
|
||||
case 0:
|
||||
foregroundColor = COLOUR_RED;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
foregroundColor = COLOUR_PURPLE;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
foregroundColor = COLOUR_WHITE;
|
||||
break;
|
||||
|
||||
default:
|
||||
foregroundColor = COLOUR_BLACK; // to detect problems
|
||||
break;
|
||||
}
|
||||
|
||||
Graphics.prototype.setFontMadeSunflower = function () {
|
||||
// Actual height 46 (45 - 0)
|
||||
return this.setFontCustom(
|
||||
E.toString(require('heatshrink').decompress(atob('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'))),
|
||||
46,
|
||||
atob("DxMiFyAgIiAgICEgDw=="),
|
||||
60 | 65536
|
||||
);
|
||||
};
|
||||
|
||||
var sun_img = require("heatshrink").decompress(atob("2GwwZC/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4AUjdt23btuAH/MNHwQCD7CA8AQlsIGsGHwwCD2BAzgI+IAQfAIOVp22bARZAxjaAKAQdsIOGatOmARuAIF02QBgCEIFsBQBwCDQlsNQB4CC7BBsQCACDIFcDQCACDsBBqjSDUtBBq6dtmwCTIFMGQCQCD0BBognTps0AScwINEmQa2mIE8BmmTpICVwBBnQCoCCIM8NknSpoCV6BBmhKDYzRBmfyACJIMyAXQdECpMkyQCXoBBlQbVgIMkSQbVIIMkaQbVoQf6DmyVpkwCZIMqDapJB/IP5BnghB/IL0gIP5B/IP5B/IP5B/IP5B/IP5B/IP5B4gBB/ILxAjIP5B/IP4AGiRBapBB/IP5BogRBaoBB/IP4CCIEgABIP5B/AAcJILGQIM0BILGAIP5BogBBYIE8AghBWkBB/INUAIKxApgESIKlIINUCIKlAINUAIKhArgEJIKWQINkBIKWAINkAIKRAtAAJBQIF8AiRBOpBBwgBBOIGMAhJBMyBBygEEIJUgIGYABiRBIpBA1ZBLC0QxSA4AH4A/AH4A/AGA"));
|
||||
|
||||
function drawPolygonWithGrid(x1, y1, x2, y2, x3, y3, x4, y4, M, N) {
|
||||
// Draw the polygon
|
||||
g.drawLine(x1, y1, x2, y2);
|
||||
g.drawLine(x2, y2, x3, y3);
|
||||
g.drawLine(x3, y3, x4, y4);
|
||||
g.drawLine(x4, y4, x1, y1);
|
||||
|
||||
for (let i = 1; i < N; i++) {
|
||||
let xi1 = x1 + i * ((x2 - x1) / N);
|
||||
let yi1 = y1 + i * ((y2 - y1) / N);
|
||||
|
||||
let xi2 = x4 - i * ((x4 - x3) / N);
|
||||
let yi2 = y4 - i * ((y4 - y3) / N);
|
||||
|
||||
g.drawLine(xi1, yi1, xi2, yi2);
|
||||
}
|
||||
|
||||
for (let j = 1; j < M; j++) {
|
||||
let xi1 = x1 + j * ((x4 - x1) / M);
|
||||
let yi1 = y1 + j * ((y4 - y1) / M);
|
||||
|
||||
let xi2 = x2 - j * ((x2 - x3) / M);
|
||||
let yi2 = y2 - j * ((y2 - y3) / M);
|
||||
|
||||
g.drawLine(xi1, yi1, xi2, yi2);
|
||||
}
|
||||
}
|
||||
|
||||
var SCREEN_WIDTH = 176;
|
||||
var SCREEN_HEIGHT = 176;
|
||||
var GROUND_HEIGHT = 176 - 45;
|
||||
|
||||
var GRID_BASE_OFFSET = 100;
|
||||
|
||||
// timeout used to update every minute
|
||||
var drawTimeout;
|
||||
|
||||
// schedule a draw for the next minute
|
||||
function queueDraw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function () {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
}
|
||||
|
||||
function draw() {
|
||||
var x = g.getWidth() / 2;
|
||||
var y = 24 + 20;
|
||||
|
||||
g.reset().clearRect(0, 24, g.getWidth(), g.getHeight());
|
||||
|
||||
//sky
|
||||
g.setColor(COLOUR_VPW_GREEN);
|
||||
g.fillRect(0, 24, SCREEN_WIDTH, GROUND_HEIGHT - 1);
|
||||
|
||||
g.drawImage(sun_img, 0, 0);
|
||||
|
||||
//ground
|
||||
g.setColor("#8000FF");
|
||||
g.fillRect(0, GROUND_HEIGHT, 176, SCREEN_HEIGHT);
|
||||
|
||||
//lines
|
||||
g.setColor(COLOUR_WHITE);
|
||||
drawPolygonWithGrid(0, GROUND_HEIGHT,
|
||||
SCREEN_WIDTH, GROUND_HEIGHT,
|
||||
SCREEN_WIDTH + GRID_BASE_OFFSET, SCREEN_HEIGHT - 1,
|
||||
0 - GRID_BASE_OFFSET, SCREEN_HEIGHT - 1,
|
||||
7, //vertical
|
||||
15); //horizontal
|
||||
|
||||
// work out locale-friendly date/time
|
||||
var date = new Date();
|
||||
var timeStr = require("locale").time(date, 1);
|
||||
var dateStr = require("locale").date(date).toUpperCase();
|
||||
var dowStr = require("locale").dow(date).toUpperCase();
|
||||
// draw time
|
||||
g.setFontAlign(0, 0).setFontMadeSunflower().setColor(foregroundColor);
|
||||
g.drawString(timeStr, x, y + 20);
|
||||
// draw date
|
||||
y += 35;
|
||||
g.setFontAlign(0, 0, 1).setFont("6x8");
|
||||
g.drawString(dateStr, g.getWidth() - 8, g.getHeight() / 2);
|
||||
// draw the day of the week
|
||||
g.setFontAlign(0, 0, 3).setFont("6x8");
|
||||
g.drawString(dowStr, 8, g.getHeight() / 2);
|
||||
// queue draw in one minute
|
||||
queueDraw();
|
||||
}
|
||||
|
||||
// Clear the screen once, at startup
|
||||
g.setTheme({ bg: COLOUR_VPW_GREEN, fg: foregroundColor, dark: true }).clear();
|
||||
// draw immediately at first, queue update
|
||||
draw();
|
||||
// Stop updates when LCD is off, restart when on
|
||||
Bangle.on('lcdPower', on => {
|
||||
if (on) {
|
||||
draw(); // draw immediately, queue redraw
|
||||
} else { // stop draw timer
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
}
|
||||
});
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"id": "vpw_clock",
|
||||
"name": "Vaporwave Sunset Clock",
|
||||
"shortName": "Vaporwave Sunset",
|
||||
"type": "clock",
|
||||
"version":"0.01",
|
||||
"description": "A clock with a vaporwave sunset theme.",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"vpw_clock.app.js","url":"app.js"},
|
||||
{"name":"vpw_clock.settings.js","url":"settings.js"},
|
||||
{"name":"vpw_clock.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"vpw_clock.settings.json"}],
|
||||
"icon": "app.png",
|
||||
"readme": "README.md",
|
||||
"screenshots": [{ "url": "screenshot.png" }, { "url": "screenshot2.png" }, { "url": "screenshot3.png" }],
|
||||
"allow_emulator":true
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
|
@ -0,0 +1,28 @@
|
|||
(function(back) {
|
||||
var FILE = "vpw_clock.settings.json";
|
||||
// Load settings
|
||||
var settings = Object.assign({
|
||||
foregroundColor: 0,
|
||||
}, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
|
||||
var foregroundColors = ["Red", "Purple", "White"];
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"" : { "title" : "Vaporwave Sunset" },
|
||||
"< Back" : () => back(),
|
||||
'Foreground color': {
|
||||
value: 0|settings.foregroundColor, // 0| converts undefined to 0
|
||||
min: 0, max: 2,
|
||||
onchange: v => {
|
||||
settings.foregroundColor = v;
|
||||
writeSettings();
|
||||
},
|
||||
format: function (v) {return foregroundColors[v];}
|
||||
},
|
||||
});
|
||||
})
|
||||