Merge pull request #3291 from paul-arg/master

Two new apps: Elapsed Time Clock and Vaporwave Sunset Clock
master
thyttan 2024-03-25 16:07:56 +01:00 committed by GitHub
commit ecbac6e017
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 765 additions and 0 deletions

1
apps/elapsed_t/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App!

23
apps/elapsed_t/README.md Normal file
View File

@ -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.
![Screenshot 1](screenshot1.png)
![Screenshot 2](screenshot2.png)
![Screenshot 3](screenshot3.png)
![Screenshot 4](screenshot4.png)
# 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)

View File

@ -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=="))

437
apps/elapsed_t/app.js Normal file
View File

@ -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();

BIN
apps/elapsed_t/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -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];}
}
});
})

1
apps/vpw_clock/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App!

17
apps/vpw_clock/README.md Normal file
View File

@ -0,0 +1,17 @@
# Vaporwave Sunset Clock
This is a simple clock with a Vaporwave Sunset theme.
![Screenshot](screenshot.png)
![Screenshot 2](screenshot2.png)
![Screenshot 3](screenshot3.png)
# Settings
You can select the text color:
- white
- ref
- purple
# Todo
- add support for AM/PM time

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwcAtu27YC/AX4C/AX4C/AVnXroRO3oDBtwRMv9p02atPTCJf7AwgRK74gBEYWmpoRJ7wGF5oRJ8wjFzoRJ+nTps0AQYRI24jGzc2CJAgEAQQREBQc1EAYCDugWDEYe/EZm+/fvAR33799ARwj/EfruIARAj/AQ88+fPARwjRA"))

161
apps/vpw_clock/app.js Normal file
View File

@ -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('AAmAAwt/AwsP/AHF/4WFj/8AwkB//AB1I7Hg/wBws+O6s4AwsfFgp3Gg//AwkDIQpYH//gUQpQFn4qFNo0P/w4aj44FgKJGjiCOEwIuFAwI9En4GBKYZKBAAI3CDgQeECoQWDCoYWDv4GCOQUPBwZWBEgglCj/+D4SXBgKaCF4IOBeQc/GgMDLod/RQLqDgIOGg4OFgE8BwKjDgIEBn6aFgZ7DBwbeDDoROCFgcfNoUHLIRoHAwYZCBwiVQGgIACKwQlDIwYWCCoQWENgYtCWQIACDwIcDgFAAYUIAQMOO4aaCIwUAjACBjwOFgIpDVIUfCwUfBwJZEboiGEO4gOCO4YOCh6VLBxCzOYR4ADg53CAAZoCAAaGDAAaGCBxYAGBwcfZoQ7Ch/8JwSkCfYV/SohzCSofwCIKGECIN/NAfwg/nO4kA/gOFj+HBwMD8F/bYIOCngIBn0HBwWAAoIRBBwM4BAP8BwgnB4AODMwQOFK4IsDCoJLBHYZmBOAIOBN4J4BBwYGB/wOG4EPNAiWBcAuABwSGC+AODGQIzBj4OCv4zBGAKkDEgSzEwACCEoQVCBwTVCn5MBABZxBAwgzDHYPAAQI2BCQIDBHwLyBNAIOCKgIhDLgIDBBwJrDO4QKBDoKGCIwV/g4OCFALZBXAIODnkBGAIOBhgFBjgOCBYQOEnwXBBwYjBBwomCBwY1CBwfjKYQ7DvpPBg4OC9+f8EBPYJoB+JnBPYUfEoIGBd4fABwRoC/DiCBwaFCSofgQoKVDF4KjBKgUfwDBBGYUBCII0Bc4UeVYbYEZIYADh7nFgF8AwsPFYL2EdwQADfIQADj/cCov5Bwv/VQIVE4IOEg/4BwraDCobmCCofwBwMYCobXBgKkBgE/wAOECoIOBgYOBZofAvAVCWQTCCYATCFBwreCB3AACgPBdAQACNAYODQwgOCQwYOKgAOGdAsfTALhEIQr3Bf4cD/kH//gLIfAv//EIX//inBEoIODO4ngngdBO4X+gYdBg4ODvEHCIIOCBYM8KYQOCAoJiBBwZiDBwN8OIYOCBYIOMLwQODv4OBHYhPBEAQOC8EBP4IOCaIQOEcAgOENAc/AwKGBgZ3BBwQ2Bn/gS4KkCg/+S4X+BwIKBUYIzCh4KBGgIzBgACBEoIVCAAQWBdAovBAwg6DcwbTBfghCDfgZgDDgYWECoQWDCoZDDQoR3CJAQlFAwZhCEgYOCEgWAn40Cn/5GIM/NIMH/jOBgAOCv+DBYSOC8AOCCIcDfwkPwE+fwcA+EDJ4IOCjwxDBwMB8BEBwAgCBILgCfwXARwoOEfwWAcAS0CjBxDQwQQBSoqPDbIjvEVojZEEoLoFv4VEAAsfdgg5CGAgOJDoxVDBxQ/FgJkEBws/AYIODR4IOEPAKVCBwJwCJwIOCWYgOBToQODg4OGWYQODCoQODCoTRCBwIGCHYYVCJwUf8YbCNAaqFj/vSwiGBPAojBWZqkGXQoOBJoIOEVYoALFAkfgBxBEIUPQ4QwCIYPwJoLGD/+BPAIGBDQP8BIIlCBYPnSobOB/9/SoYGB+6kETYUPGgLdCBgMfPYIpBHIV8BwPwSwUDBwM8C4IOBjgJBwA1BGIIOBnEAXYQODCwOABwk/HIIODJgPgBwU8LYQODGIJfBHYU/wBMB+JZFAAIOBNAQABBwJ3CNQYOC/oGBJgKVCz6VF/AGBUgSaBT4QGBOwQJBYQUPJALRDKoQvBcAQACv4VCBgKcBAAbZBIAQACLwYACNwIWEOARICJQYyCd4glBjB3E4EBd4hQBXAIOEXAIzBwYOEVwQOBg4OBBIQOBFwIYCh/Ah5CBBwMAvkBJgIOCEAM/BYLgBAQMHP4LgCgfBNQQRDRwUDBQMH36kCn/+KgRHBcAiXCd4icER4iGCTwiVCVoakCXgizBEgiOEaIi7FCwL1DFoToFgECAQL+DgIVBv4eE8EPHgZ5CcQQlC+EfFwY8BIwJEDB0g7Hj72BOIhPBnxqFAAQ'))),
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();

BIN
apps/vpw_clock/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -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];}
},
});
})