Skip to content

Commit 1e5ce20

Browse files
authored
Merge pull request #3821 from voloved/jsonclock
Jsonclock v2
2 parents a243ac6 + ba6d265 commit 1e5ce20

18 files changed

+112
-92
lines changed

apps/jsonclock/ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
0.01: first release
2+
0.02: memory leak fix; color changes to better align with VSCode color scheme; logo is transparent

apps/jsonclock/README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ inspired by [This FitBit face](https://github.com/Sharkgrammer/clockface.json)
1313
* If the location isn't set, then the JSON array will ignore the sun info and instead display the time as a struct.
1414

1515
## Screenshots
16-
![](dark.png)
17-
![](white.png)
18-
![](no_steps.png)
19-
![](no_location.png)
20-
![](dark-emulator.png)
16+
![dark](dark.png)
17+
![dark-no location](dark-noloc.png)
18+
![dark-no step](dark-nostep.png)
19+
![dark-no location and step](dark-nolocnostep.png)
20+
![light](light.png)
21+
![light-no location](light-noloc.png)
22+
![light-no step](light-nostep.png)
23+
![light-no location and step](light-nolocnostep.png)

apps/jsonclock/app-icon.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/jsonclock/app.js

Lines changed: 100 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,23 @@ const storage = require('Storage');
44
const widget_utils = require('widget_utils');
55
const global_settings = storage.readJSON("setting.json", true) || {};
66
const LOCATION_FILE = "mylocation.json";
7-
const h = g.getHeight();
8-
const w = g.getWidth();
97
let location;
108
let cachedSunTimes = null;
119
let lastSunCalcDate = null;
12-
var prevVals = {};
10+
var valsArrs = {};
1311
let drawTimeout;
1412

13+
const h = g.getHeight();
14+
const w = g.getWidth();
15+
const fontSize = 13;
16+
const lineHeight = 16;
17+
const buttonHeight = 12;
18+
const buttonX = 78;
19+
const buttonY = 3;
20+
const headerHeight = 16;
21+
const usableHeight = h - headerHeight;
22+
const maxLines = Math.floor(usableHeight / lineHeight);
23+
1524
var settings = {
1625
hr_12: global_settings["12hour"] !== undefined ? global_settings["12hour"] : false,
1726
dark_mode: g.theme.dark
@@ -26,22 +35,6 @@ let clrs = {
2635
brackets: g.theme.fg,
2736
};
2837

29-
30-
let jsonText;
31-
let lines = [];
32-
let fontSize = 13;
33-
const lineHeight = 16;
34-
35-
const buttonHeight = 12;
36-
const buttonX = 78;
37-
const buttonY = 3;
38-
39-
let valuePositions = [];
40-
const headerHeight = 16;
41-
const usableHeight = h - headerHeight;
42-
const maxLines = Math.floor(usableHeight / lineHeight);
43-
var numWidth = 0;
44-
4538
// requires the myLocation app
4639
let loadLocation = function() {
4740
location = require("Storage").readJSON(LOCATION_FILE, 1) || {};
@@ -110,45 +103,49 @@ let getVal = function(now, loc) {
110103
return vals;
111104
};
112105

113-
let loadJson = function() {
106+
107+
let getKeyValRegex = function(line) {
108+
return line.trim().match(/^"([^"]+)":\s*(.+)$/);
109+
};
110+
111+
let getIndentRegex = function(line) {
112+
const indentMatch = line.match(/^(\s*)/);
113+
return indentMatch ? indentMatch[1] : "";
114+
};
115+
116+
let getJsonLine = function() {
114117
const now = new Date();
115118
const vals = getVal(now, location);
116119
//vals.steps = null; // For testing; uncomment to see the steps not appear
117120
//location.location = null; // For testing, if null, the time becomes an struct to take up sun's struct
118-
let raw;
119-
120-
if (location.location !== null) {
121-
raw = {
122-
time: vals.time,
123-
dt: vals.date,
124-
sun: {
125-
rise: vals.rise,
126-
set: vals.set,
127-
},
128-
"batt_%": vals.batt_pct,
129-
};
130-
} else {
131-
raw = {
132-
time: {
133-
hr: getHr(now.getHours())[0],
134-
min: now.getMinutes(),
121+
const hasLoc = location.location !== null;
122+
let raw = {
123+
time: hasLoc
124+
? vals.time
125+
: {
126+
hr: getHr(now.getHours())[0],
127+
min: now.getMinutes(),
135128
},
136-
dt: vals.date,
137-
"batt_%": vals.batt_pct,
129+
dt: vals.date,
130+
"batt_%": vals.batt_pct,
131+
};
132+
if (vals.steps != null) {
133+
raw.steps = vals.steps;
134+
}
135+
if (hasLoc) {
136+
raw.sun = {
137+
rise: vals.rise,
138+
set: vals.set,
138139
};
139140
}
140-
141-
if (vals.steps != null) raw.steps = vals.steps;
142-
143-
jsonText = JSON.stringify(raw, null, 2);
144-
lines = jsonText.split("\n");
141+
let jsonText = JSON.stringify(raw, null, 2);
142+
return jsonText.split("\n");
145143
};
146144

147145
let draw = function() {
148146
g.clear();
149147
g.setFontAlign(-1, -1);
150148
g.setFont("Vector", 10);
151-
valuePositions = [];
152149

153150
g.setColor(clrs.tab);
154151

@@ -159,77 +156,95 @@ let draw = function() {
159156
g.setFont("Vector", buttonHeight);
160157
g.drawString("X", buttonX, buttonY);
161158
g.setFont("Vector", fontSize);
162-
159+
160+
var lines = getJsonLine();
161+
var numWidth = 0;
162+
163+
// Draw numbers first to find out their max width
163164
for (let i = 0; i < maxLines; i++) {
164165
const y = headerHeight + i * lineHeight;
165166
const lineNumberStr = (i + 1).toString().padStart(2, " ") + " ";
166167
g.drawString(lineNumberStr, 0, y);
167168
numWidth = Math.max(numWidth, g.stringWidth(lineNumberStr));
168169
}
169-
170-
redrawValues();
171-
};
172-
173-
let redraw = function() {
174170
for (let i = 0; i < maxLines; i++) {
175-
const lineIndex = i;
176-
const line = lines[lineIndex];
177-
if (!line) continue;
178171
const y = headerHeight + i * lineHeight;
172+
const line = lines[i];
173+
if (!line) continue;
179174

180-
const indentMatch = line.match(/^(\s*)/);
181-
const indent = indentMatch ? indentMatch[1] : "";
182-
183-
const kvMatch = line.trim().match(/^"([^"]+)":\s*(.+)$/);
175+
let kvMatch = getKeyValRegex(line);
184176
if (kvMatch) {
185177
const key = kvMatch[1];
186178
let value = kvMatch[2];
187179

188-
if (prevVals.key == value) continue;
189-
prevVals.key = value;
190-
191180
// Key
192181
g.setColor(clrs.keys);
193-
g.drawString(indent + `"${key}"`, numWidth, y);
194-
const keyWidth = g.stringWidth(indent + `"${key}"`);
195-
const valueX = numWidth + keyWidth;
196-
const valueText = ": " + value;
182+
const indent = getIndentRegex(line);
183+
const keyText = indent + `"${key}"`;
184+
g.drawString(keyText, numWidth, y);
185+
const keyWidth = g.stringWidth(keyText);
186+
let x = numWidth + keyWidth;
197187

188+
g.setColor(clrs.brackets);
189+
const colonText = ": ";
190+
g.drawString(colonText, x, y);
191+
x += g.stringWidth(colonText);
192+
198193
// Value color
194+
const endComma = value.endsWith(',');
195+
valsArrs[key] = {text:value, x:x, y:y, endComma:endComma};
196+
if (endComma) value = value.slice(0, -1);
199197
if (value.startsWith('"')) {
200-
g.setColor(clrs.strings);
198+
valsArrs[key].color = clrs.strings;
201199
} else if (value.startsWith('{') || value.startsWith('}')) {
202-
g.setColor(clrs.brackets);
200+
valsArrs[key].color = clrs.brackets;
203201
} else {
204-
g.setColor(clrs.ints);
202+
valsArrs[key].color = clrs.ints;
205203
}
206-
g.drawString(valueText, valueX, y);
207-
208-
valuePositions.push({
209-
key,
210-
x: valueX,
211-
y,
212-
text: value
213-
});
214-
} else {
204+
g.setColor(valsArrs[key].color);
205+
g.drawString(value, x, y);
206+
if (endComma){
207+
g.setColor(clrs.brackets);
208+
g.drawString(',', x + g.stringWidth(value), y);
209+
}
210+
}
211+
else {
215212
g.setColor(clrs.brackets);
216213
g.drawString(line, numWidth, y);
217214
}
218215
}
219216
};
220217

221-
let clearVals = function() {
222-
g.setFont("Vector", fontSize);
218+
// Redraws only values that changed
219+
let redraw = function() {
223220
g.setFontAlign(-1, -1);
224-
valuePositions.forEach(pos => {
221+
g.setFont("Vector", fontSize);
222+
var lines = getJsonLine();
223+
224+
for (let i = 0; i < lines.length; i++) {
225+
let kvMatch = getKeyValRegex(lines[i]);
226+
if (!kvMatch) continue;
227+
const key = kvMatch[1];
228+
let value = kvMatch[2];
229+
if (!(key in valsArrs)) continue;
230+
let valsArr = valsArrs[key];
231+
if (value === valsArr.text) continue; // No need to update
232+
valsArrs[key].text = value;
233+
234+
// Clear prev values
225235
g.setColor(clrs.bg);
226-
g.fillRect(pos.x, pos.y, w, pos.y + lineHeight);
227-
});
236+
g.fillRect(valsArr.x, valsArr.y, w, valsArr.y + lineHeight);
237+
238+
g.setColor(valsArr.color);
239+
g.drawString(value, valsArr.x, valsArr.y);
240+
if (valsArr.endComma){
241+
g.setColor(clrs.brackets);
242+
g.drawString(',', valsArr.Banglex + g.stringWidth(value), valsArr.y);
243+
}
244+
}
228245
};
229246

230247
let redrawValues = function() {
231-
loadJson();
232-
clearVals();
233248
redraw();
234249
if (drawTimeout) clearTimeout(drawTimeout);
235250
drawTimeout = setTimeout(function() {
@@ -256,4 +271,5 @@ loadLocation();
256271
Bangle.loadWidgets();
257272
widget_utils.hide();
258273
draw();
274+
redrawValues(); // To set the timeout
259275
}

apps/jsonclock/app.png

-174 Bytes
Loading

apps/jsonclock/dark-emulator.png

-3.68 KB
Binary file not shown.

apps/jsonclock/dark-noloc.png

2.54 KB
Loading
2.52 KB
Loading

apps/jsonclock/dark-nostep.png

3.18 KB
Loading

apps/jsonclock/dark.png

-122 Bytes
Loading

0 commit comments

Comments
 (0)