|
|
@ -1 +1,2 @@
|
||||||
0.01: first release
|
0.01: first release
|
||||||
|
0.02: memory leak fix; color changes to better align with VSCode color scheme; logo is transparent
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ inspired by [This FitBit face](https://github.com/Sharkgrammer/clockface.json)
|
||||||
* If the location isn't set, then the JSON array will ignore the sun info and instead display the time as a struct.
|
* If the location isn't set, then the JSON array will ignore the sun info and instead display the time as a struct.
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
@ -1 +1 @@
|
||||||
require("heatshrink").decompress(atob("mEwwcCBhEcuPHAQsDwE48AQDnEDx048YCEDQ/AEZAxEnADCEZAKBg5HQCIxiJuARPAEZHBgEBwQGBwE04VNmBHHXYXDhlAg0YsIbBEY8AZQmDhBHcFwcg4AOE4YpCI4swI4NgAQUAAQRHDg0IkAdDkGSAoRBNiBZWjgDCI4UBLAqPHKQMgCJQWFQIIROI6BzD4DXBw0YI5EAhEhwwIBoEwdQwAEWYIDBEYJIYa4REBSQKBBI5kJkmCgECpkwQIprEgcMmOAEZCPVJQYANhwRQaiIjRABqPCgLPEkilBNYxoCmHDa4L+BDAqzFgUIkGCjEgHhwxGAA4uEGYxHImPAahBHDgxEByEAAIIAqI4T+DABXgEaICEADoA="))
|
require("heatshrink").decompress(atob("mEwwcDtu27YCOvv2/d933fBAP7DSICIsOG4dh2HYBAPDEbVsmwdPCKICmso7C23jxvHjlx48bI4gUBy1JkoaC5Mkt1GLIopGyJWrGoeSrYICxu47lt28jC42SAoXcyO3jgUBI9eW7ILD03TLJwRIC4zpituyGoRZLrLpCtJHNlpZDdN225IXPy1LINICNrdyo3bx028YOH5cly3bt028lum8jIljpCxoIC4xHDUInblgOC3McuPIWZACE28cEwYCmwz7UAWEMgxHShoRNgJHiA=="))
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,23 @@ const storage = require('Storage');
|
||||||
const widget_utils = require('widget_utils');
|
const widget_utils = require('widget_utils');
|
||||||
const global_settings = storage.readJSON("setting.json", true) || {};
|
const global_settings = storage.readJSON("setting.json", true) || {};
|
||||||
const LOCATION_FILE = "mylocation.json";
|
const LOCATION_FILE = "mylocation.json";
|
||||||
const h = g.getHeight();
|
|
||||||
const w = g.getWidth();
|
|
||||||
let location;
|
let location;
|
||||||
let cachedSunTimes = null;
|
let cachedSunTimes = null;
|
||||||
let lastSunCalcDate = null;
|
let lastSunCalcDate = null;
|
||||||
var prevVals = {};
|
var valsArrs = {};
|
||||||
let drawTimeout;
|
let drawTimeout;
|
||||||
|
|
||||||
|
const h = g.getHeight();
|
||||||
|
const w = g.getWidth();
|
||||||
|
const fontSize = 13;
|
||||||
|
const lineHeight = 16;
|
||||||
|
const buttonHeight = 12;
|
||||||
|
const buttonX = 78;
|
||||||
|
const buttonY = 3;
|
||||||
|
const headerHeight = 16;
|
||||||
|
const usableHeight = h - headerHeight;
|
||||||
|
const maxLines = Math.floor(usableHeight / lineHeight);
|
||||||
|
|
||||||
var settings = {
|
var settings = {
|
||||||
hr_12: global_settings["12hour"] !== undefined ? global_settings["12hour"] : false,
|
hr_12: global_settings["12hour"] !== undefined ? global_settings["12hour"] : false,
|
||||||
dark_mode: g.theme.dark
|
dark_mode: g.theme.dark
|
||||||
|
|
@ -26,22 +35,6 @@ let clrs = {
|
||||||
brackets: g.theme.fg,
|
brackets: g.theme.fg,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let jsonText;
|
|
||||||
let lines = [];
|
|
||||||
let fontSize = 13;
|
|
||||||
const lineHeight = 16;
|
|
||||||
|
|
||||||
const buttonHeight = 12;
|
|
||||||
const buttonX = 78;
|
|
||||||
const buttonY = 3;
|
|
||||||
|
|
||||||
let valuePositions = [];
|
|
||||||
const headerHeight = 16;
|
|
||||||
const usableHeight = h - headerHeight;
|
|
||||||
const maxLines = Math.floor(usableHeight / lineHeight);
|
|
||||||
var numWidth = 0;
|
|
||||||
|
|
||||||
// requires the myLocation app
|
// requires the myLocation app
|
||||||
let loadLocation = function() {
|
let loadLocation = function() {
|
||||||
location = require("Storage").readJSON(LOCATION_FILE, 1) || {};
|
location = require("Storage").readJSON(LOCATION_FILE, 1) || {};
|
||||||
|
|
@ -110,45 +103,49 @@ let getVal = function(now, loc) {
|
||||||
return vals;
|
return vals;
|
||||||
};
|
};
|
||||||
|
|
||||||
let loadJson = function() {
|
|
||||||
|
let getKeyValRegex = function(line) {
|
||||||
|
return line.trim().match(/^"([^"]+)":\s*(.+)$/);
|
||||||
|
};
|
||||||
|
|
||||||
|
let getIndentRegex = function(line) {
|
||||||
|
const indentMatch = line.match(/^(\s*)/);
|
||||||
|
return indentMatch ? indentMatch[1] : "";
|
||||||
|
};
|
||||||
|
|
||||||
|
let getJsonLine = function() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const vals = getVal(now, location);
|
const vals = getVal(now, location);
|
||||||
//vals.steps = null; // For testing; uncomment to see the steps not appear
|
//vals.steps = null; // For testing; uncomment to see the steps not appear
|
||||||
//location.location = null; // For testing, if null, the time becomes an struct to take up sun's struct
|
//location.location = null; // For testing, if null, the time becomes an struct to take up sun's struct
|
||||||
let raw;
|
const hasLoc = location.location !== null;
|
||||||
|
let raw = {
|
||||||
if (location.location !== null) {
|
time: hasLoc
|
||||||
raw = {
|
? vals.time
|
||||||
time: vals.time,
|
: {
|
||||||
dt: vals.date,
|
|
||||||
sun: {
|
|
||||||
rise: vals.rise,
|
|
||||||
set: vals.set,
|
|
||||||
},
|
|
||||||
"batt_%": vals.batt_pct,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
raw = {
|
|
||||||
time: {
|
|
||||||
hr: getHr(now.getHours())[0],
|
hr: getHr(now.getHours())[0],
|
||||||
min: now.getMinutes(),
|
min: now.getMinutes(),
|
||||||
},
|
},
|
||||||
dt: vals.date,
|
dt: vals.date,
|
||||||
"batt_%": vals.batt_pct,
|
"batt_%": vals.batt_pct,
|
||||||
};
|
};
|
||||||
|
if (vals.steps != null) {
|
||||||
|
raw.steps = vals.steps;
|
||||||
}
|
}
|
||||||
|
if (hasLoc) {
|
||||||
if (vals.steps != null) raw.steps = vals.steps;
|
raw.sun = {
|
||||||
|
rise: vals.rise,
|
||||||
jsonText = JSON.stringify(raw, null, 2);
|
set: vals.set,
|
||||||
lines = jsonText.split("\n");
|
};
|
||||||
|
}
|
||||||
|
let jsonText = JSON.stringify(raw, null, 2);
|
||||||
|
return jsonText.split("\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw = function() {
|
let draw = function() {
|
||||||
g.clear();
|
g.clear();
|
||||||
g.setFontAlign(-1, -1);
|
g.setFontAlign(-1, -1);
|
||||||
g.setFont("Vector", 10);
|
g.setFont("Vector", 10);
|
||||||
valuePositions = [];
|
|
||||||
|
|
||||||
g.setColor(clrs.tab);
|
g.setColor(clrs.tab);
|
||||||
|
|
||||||
|
|
@ -160,76 +157,94 @@ let draw = function() {
|
||||||
g.drawString("X", buttonX, buttonY);
|
g.drawString("X", buttonX, buttonY);
|
||||||
g.setFont("Vector", fontSize);
|
g.setFont("Vector", fontSize);
|
||||||
|
|
||||||
|
var lines = getJsonLine();
|
||||||
|
var numWidth = 0;
|
||||||
|
|
||||||
|
// Draw numbers first to find out their max width
|
||||||
for (let i = 0; i < maxLines; i++) {
|
for (let i = 0; i < maxLines; i++) {
|
||||||
const y = headerHeight + i * lineHeight;
|
const y = headerHeight + i * lineHeight;
|
||||||
const lineNumberStr = (i + 1).toString().padStart(2, " ") + " ";
|
const lineNumberStr = (i + 1).toString().padStart(2, " ") + " ";
|
||||||
g.drawString(lineNumberStr, 0, y);
|
g.drawString(lineNumberStr, 0, y);
|
||||||
numWidth = Math.max(numWidth, g.stringWidth(lineNumberStr));
|
numWidth = Math.max(numWidth, g.stringWidth(lineNumberStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
redrawValues();
|
|
||||||
};
|
|
||||||
|
|
||||||
let redraw = function() {
|
|
||||||
for (let i = 0; i < maxLines; i++) {
|
for (let i = 0; i < maxLines; i++) {
|
||||||
const lineIndex = i;
|
|
||||||
const line = lines[lineIndex];
|
|
||||||
if (!line) continue;
|
|
||||||
const y = headerHeight + i * lineHeight;
|
const y = headerHeight + i * lineHeight;
|
||||||
|
const line = lines[i];
|
||||||
|
if (!line) continue;
|
||||||
|
|
||||||
const indentMatch = line.match(/^(\s*)/);
|
let kvMatch = getKeyValRegex(line);
|
||||||
const indent = indentMatch ? indentMatch[1] : "";
|
|
||||||
|
|
||||||
const kvMatch = line.trim().match(/^"([^"]+)":\s*(.+)$/);
|
|
||||||
if (kvMatch) {
|
if (kvMatch) {
|
||||||
const key = kvMatch[1];
|
const key = kvMatch[1];
|
||||||
let value = kvMatch[2];
|
let value = kvMatch[2];
|
||||||
|
|
||||||
if (prevVals.key == value) continue;
|
|
||||||
prevVals.key = value;
|
|
||||||
|
|
||||||
// Key
|
// Key
|
||||||
g.setColor(clrs.keys);
|
g.setColor(clrs.keys);
|
||||||
g.drawString(indent + `"${key}"`, numWidth, y);
|
const indent = getIndentRegex(line);
|
||||||
const keyWidth = g.stringWidth(indent + `"${key}"`);
|
const keyText = indent + `"${key}"`;
|
||||||
const valueX = numWidth + keyWidth;
|
g.drawString(keyText, numWidth, y);
|
||||||
const valueText = ": " + value;
|
const keyWidth = g.stringWidth(keyText);
|
||||||
|
let x = numWidth + keyWidth;
|
||||||
|
|
||||||
|
g.setColor(clrs.brackets);
|
||||||
|
const colonText = ": ";
|
||||||
|
g.drawString(colonText, x, y);
|
||||||
|
x += g.stringWidth(colonText);
|
||||||
|
|
||||||
// Value color
|
// Value color
|
||||||
|
const endComma = value.endsWith(',');
|
||||||
|
valsArrs[key] = {text:value, x:x, y:y, endComma:endComma};
|
||||||
|
if (endComma) value = value.slice(0, -1);
|
||||||
if (value.startsWith('"')) {
|
if (value.startsWith('"')) {
|
||||||
g.setColor(clrs.strings);
|
valsArrs[key].color = clrs.strings;
|
||||||
} else if (value.startsWith('{') || value.startsWith('}')) {
|
} else if (value.startsWith('{') || value.startsWith('}')) {
|
||||||
g.setColor(clrs.brackets);
|
valsArrs[key].color = clrs.brackets;
|
||||||
} else {
|
} else {
|
||||||
g.setColor(clrs.ints);
|
valsArrs[key].color = clrs.ints;
|
||||||
}
|
}
|
||||||
g.drawString(valueText, valueX, y);
|
g.setColor(valsArrs[key].color);
|
||||||
|
g.drawString(value, x, y);
|
||||||
valuePositions.push({
|
if (endComma){
|
||||||
key,
|
g.setColor(clrs.brackets);
|
||||||
x: valueX,
|
g.drawString(',', x + g.stringWidth(value), y);
|
||||||
y,
|
}
|
||||||
text: value
|
}
|
||||||
});
|
else {
|
||||||
} else {
|
|
||||||
g.setColor(clrs.brackets);
|
g.setColor(clrs.brackets);
|
||||||
g.drawString(line, numWidth, y);
|
g.drawString(line, numWidth, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let clearVals = function() {
|
// Redraws only values that changed
|
||||||
g.setFont("Vector", fontSize);
|
let redraw = function() {
|
||||||
g.setFontAlign(-1, -1);
|
g.setFontAlign(-1, -1);
|
||||||
valuePositions.forEach(pos => {
|
g.setFont("Vector", fontSize);
|
||||||
|
var lines = getJsonLine();
|
||||||
|
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
let kvMatch = getKeyValRegex(lines[i]);
|
||||||
|
if (!kvMatch) continue;
|
||||||
|
const key = kvMatch[1];
|
||||||
|
let value = kvMatch[2];
|
||||||
|
if (!(key in valsArrs)) continue;
|
||||||
|
let valsArr = valsArrs[key];
|
||||||
|
if (value === valsArr.text) continue; // No need to update
|
||||||
|
valsArrs[key].text = value;
|
||||||
|
|
||||||
|
// Clear prev values
|
||||||
g.setColor(clrs.bg);
|
g.setColor(clrs.bg);
|
||||||
g.fillRect(pos.x, pos.y, w, pos.y + lineHeight);
|
g.fillRect(valsArr.x, valsArr.y, w, valsArr.y + lineHeight);
|
||||||
});
|
|
||||||
|
g.setColor(valsArr.color);
|
||||||
|
g.drawString(value, valsArr.x, valsArr.y);
|
||||||
|
if (valsArr.endComma){
|
||||||
|
g.setColor(clrs.brackets);
|
||||||
|
g.drawString(',', valsArr.Banglex + g.stringWidth(value), valsArr.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let redrawValues = function() {
|
let redrawValues = function() {
|
||||||
loadJson();
|
|
||||||
clearVals();
|
|
||||||
redraw();
|
redraw();
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
drawTimeout = setTimeout(function() {
|
drawTimeout = setTimeout(function() {
|
||||||
|
|
@ -256,4 +271,5 @@ loadLocation();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
widget_utils.hide();
|
widget_utils.hide();
|
||||||
draw();
|
draw();
|
||||||
|
redrawValues(); // To set the timeout
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 2.7 KiB |
|
|
@ -1,9 +1,9 @@
|
||||||
{ "id": "jsonclock",
|
{ "id": "jsonclock",
|
||||||
"name": "JsonClock",
|
"name": "JsonClock",
|
||||||
"version": "0.01",
|
"version": "0.02",
|
||||||
"description": "JSON view of the time, date, steps, battery, and sunrise and sunset times",
|
"description": "JSON view of the time, date, steps, battery, and sunrise and sunset times",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [{"url":"dark-emulator.png"}],
|
"screenshots": [{"url":"dark.png"}],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.6 KiB |