diff --git a/apps/jsonclock/ChangeLog b/apps/jsonclock/ChangeLog index 9db0e26c52..f8cb62040b 100644 --- a/apps/jsonclock/ChangeLog +++ b/apps/jsonclock/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: memory leak fix; color changes to better align with VSCode color scheme; logo is transparent diff --git a/apps/jsonclock/README.md b/apps/jsonclock/README.md index 740024e686..e37bfc5377 100644 --- a/apps/jsonclock/README.md +++ b/apps/jsonclock/README.md @@ -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. ## Screenshots -![](dark.png) -![](white.png) -![](no_steps.png) -![](no_location.png) -![](dark-emulator.png) \ No newline at end of file +![dark](dark.png) +![dark-no location](dark-noloc.png) +![dark-no step](dark-nostep.png) +![dark-no location and step](dark-nolocnostep.png) +![light](light.png) +![light-no location](light-noloc.png) +![light-no step](light-nostep.png) +![light-no location and step](light-nolocnostep.png) \ No newline at end of file diff --git a/apps/jsonclock/app-icon.js b/apps/jsonclock/app-icon.js index dcac31aa38..745ebdc170 100644 --- a/apps/jsonclock/app-icon.js +++ b/apps/jsonclock/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwcCBhEcuPHAQsDwE48AQDnEDx048YCEDQ/AEZAxEnADCEZAKBg5HQCIxiJuARPAEZHBgEBwQGBwE04VNmBHHXYXDhlAg0YsIbBEY8AZQmDhBHcFwcg4AOE4YpCI4swI4NgAQUAAQRHDg0IkAdDkGSAoRBNiBZWjgDCI4UBLAqPHKQMgCJQWFQIIROI6BzD4DXBw0YI5EAhEhwwIBoEwdQwAEWYIDBEYJIYa4REBSQKBBI5kJkmCgECpkwQIprEgcMmOAEZCPVJQYANhwRQaiIjRABqPCgLPEkilBNYxoCmHDa4L+BDAqzFgUIkGCjEgHhwxGAA4uEGYxHImPAahBHDgxEByEAAIIAqI4T+DABXgEaICEADoA=")) +require("heatshrink").decompress(atob("mEwwcDtu27YCOvv2/d933fBAP7DSICIsOG4dh2HYBAPDEbVsmwdPCKICmso7C23jxvHjlx48bI4gUBy1JkoaC5Mkt1GLIopGyJWrGoeSrYICxu47lt28jC42SAoXcyO3jgUBI9eW7ILD03TLJwRIC4zpituyGoRZLrLpCtJHNlpZDdN225IXPy1LINICNrdyo3bx028YOH5cly3bt028lum8jIljpCxoIC4xHDUInblgOC3McuPIWZACE28cEwYCmwz7UAWEMgxHShoRNgJHiA==")) diff --git a/apps/jsonclock/app.js b/apps/jsonclock/app.js index f42a9313e1..759b51793d 100644 --- a/apps/jsonclock/app.js +++ b/apps/jsonclock/app.js @@ -4,14 +4,23 @@ const storage = require('Storage'); const widget_utils = require('widget_utils'); const global_settings = storage.readJSON("setting.json", true) || {}; const LOCATION_FILE = "mylocation.json"; -const h = g.getHeight(); -const w = g.getWidth(); let location; let cachedSunTimes = null; let lastSunCalcDate = null; -var prevVals = {}; +var valsArrs = {}; 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 = { hr_12: global_settings["12hour"] !== undefined ? global_settings["12hour"] : false, dark_mode: g.theme.dark @@ -26,22 +35,6 @@ let clrs = { 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 let loadLocation = function() { location = require("Storage").readJSON(LOCATION_FILE, 1) || {}; @@ -110,45 +103,49 @@ let getVal = function(now, loc) { 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 vals = getVal(now, location); //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 - let raw; - - if (location.location !== null) { - raw = { - 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], - min: now.getMinutes(), + const hasLoc = location.location !== null; + let raw = { + time: hasLoc + ? vals.time + : { + hr: getHr(now.getHours())[0], + min: now.getMinutes(), }, - dt: vals.date, - "batt_%": vals.batt_pct, + dt: vals.date, + "batt_%": vals.batt_pct, + }; + if (vals.steps != null) { + raw.steps = vals.steps; + } + if (hasLoc) { + raw.sun = { + rise: vals.rise, + set: vals.set, }; } - - if (vals.steps != null) raw.steps = vals.steps; - - jsonText = JSON.stringify(raw, null, 2); - lines = jsonText.split("\n"); + let jsonText = JSON.stringify(raw, null, 2); + return jsonText.split("\n"); }; let draw = function() { g.clear(); g.setFontAlign(-1, -1); g.setFont("Vector", 10); - valuePositions = []; g.setColor(clrs.tab); @@ -159,77 +156,95 @@ let draw = function() { g.setFont("Vector", buttonHeight); g.drawString("X", buttonX, buttonY); 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++) { const y = headerHeight + i * lineHeight; const lineNumberStr = (i + 1).toString().padStart(2, " ") + " "; g.drawString(lineNumberStr, 0, y); numWidth = Math.max(numWidth, g.stringWidth(lineNumberStr)); } - - redrawValues(); -}; - -let redraw = function() { for (let i = 0; i < maxLines; i++) { - const lineIndex = i; - const line = lines[lineIndex]; - if (!line) continue; const y = headerHeight + i * lineHeight; + const line = lines[i]; + if (!line) continue; - const indentMatch = line.match(/^(\s*)/); - const indent = indentMatch ? indentMatch[1] : ""; - - const kvMatch = line.trim().match(/^"([^"]+)":\s*(.+)$/); + let kvMatch = getKeyValRegex(line); if (kvMatch) { const key = kvMatch[1]; let value = kvMatch[2]; - if (prevVals.key == value) continue; - prevVals.key = value; - // Key g.setColor(clrs.keys); - g.drawString(indent + `"${key}"`, numWidth, y); - const keyWidth = g.stringWidth(indent + `"${key}"`); - const valueX = numWidth + keyWidth; - const valueText = ": " + value; + const indent = getIndentRegex(line); + const keyText = indent + `"${key}"`; + g.drawString(keyText, numWidth, y); + 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 + const endComma = value.endsWith(','); + valsArrs[key] = {text:value, x:x, y:y, endComma:endComma}; + if (endComma) value = value.slice(0, -1); if (value.startsWith('"')) { - g.setColor(clrs.strings); + valsArrs[key].color = clrs.strings; } else if (value.startsWith('{') || value.startsWith('}')) { - g.setColor(clrs.brackets); + valsArrs[key].color = clrs.brackets; } else { - g.setColor(clrs.ints); + valsArrs[key].color = clrs.ints; } - g.drawString(valueText, valueX, y); - - valuePositions.push({ - key, - x: valueX, - y, - text: value - }); - } else { + g.setColor(valsArrs[key].color); + g.drawString(value, x, y); + if (endComma){ + g.setColor(clrs.brackets); + g.drawString(',', x + g.stringWidth(value), y); + } + } + else { g.setColor(clrs.brackets); g.drawString(line, numWidth, y); } } }; -let clearVals = function() { - g.setFont("Vector", fontSize); +// Redraws only values that changed +let redraw = function() { 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.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() { - loadJson(); - clearVals(); redraw(); if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = setTimeout(function() { @@ -256,4 +271,5 @@ loadLocation(); Bangle.loadWidgets(); widget_utils.hide(); draw(); +redrawValues(); // To set the timeout } \ No newline at end of file diff --git a/apps/jsonclock/app.png b/apps/jsonclock/app.png index ab6c821f4c..753fab3549 100644 Binary files a/apps/jsonclock/app.png and b/apps/jsonclock/app.png differ diff --git a/apps/jsonclock/dark-emulator.png b/apps/jsonclock/dark-emulator.png deleted file mode 100644 index 88e06c4ef2..0000000000 Binary files a/apps/jsonclock/dark-emulator.png and /dev/null differ diff --git a/apps/jsonclock/dark-noloc.png b/apps/jsonclock/dark-noloc.png new file mode 100644 index 0000000000..f0470de64a Binary files /dev/null and b/apps/jsonclock/dark-noloc.png differ diff --git a/apps/jsonclock/dark-nolocnostep.png b/apps/jsonclock/dark-nolocnostep.png new file mode 100644 index 0000000000..40474ed469 Binary files /dev/null and b/apps/jsonclock/dark-nolocnostep.png differ diff --git a/apps/jsonclock/dark-nostep.png b/apps/jsonclock/dark-nostep.png new file mode 100644 index 0000000000..3e16f6dc0d Binary files /dev/null and b/apps/jsonclock/dark-nostep.png differ diff --git a/apps/jsonclock/dark.png b/apps/jsonclock/dark.png index fcbc3e6fff..ad28f69888 100644 Binary files a/apps/jsonclock/dark.png and b/apps/jsonclock/dark.png differ diff --git a/apps/jsonclock/light-noloc.png b/apps/jsonclock/light-noloc.png new file mode 100644 index 0000000000..2db238a69e Binary files /dev/null and b/apps/jsonclock/light-noloc.png differ diff --git a/apps/jsonclock/light-nolocnostep.png b/apps/jsonclock/light-nolocnostep.png new file mode 100644 index 0000000000..c9763abad6 Binary files /dev/null and b/apps/jsonclock/light-nolocnostep.png differ diff --git a/apps/jsonclock/light-nostep.png b/apps/jsonclock/light-nostep.png new file mode 100644 index 0000000000..2fd0a8431f Binary files /dev/null and b/apps/jsonclock/light-nostep.png differ diff --git a/apps/jsonclock/light.png b/apps/jsonclock/light.png index b5ecef0d60..c0a90fdd51 100644 Binary files a/apps/jsonclock/light.png and b/apps/jsonclock/light.png differ diff --git a/apps/jsonclock/metadata.json b/apps/jsonclock/metadata.json index 215da7e580..d097d5b084 100644 --- a/apps/jsonclock/metadata.json +++ b/apps/jsonclock/metadata.json @@ -1,9 +1,9 @@ { "id": "jsonclock", "name": "JsonClock", - "version": "0.01", + "version": "0.02", "description": "JSON view of the time, date, steps, battery, and sunrise and sunset times", "icon": "app.png", - "screenshots": [{"url":"dark-emulator.png"}], + "screenshots": [{"url":"dark.png"}], "readme": "README.md", "type": "clock", "tags": "clock", diff --git a/apps/jsonclock/no_location.png b/apps/jsonclock/no_location.png deleted file mode 100644 index 5699ba7e36..0000000000 Binary files a/apps/jsonclock/no_location.png and /dev/null differ diff --git a/apps/jsonclock/no_steps.png b/apps/jsonclock/no_steps.png deleted file mode 100644 index 5919aa0f2e..0000000000 Binary files a/apps/jsonclock/no_steps.png and /dev/null differ diff --git a/apps/jsonclock/tran.png b/apps/jsonclock/tran.png new file mode 100644 index 0000000000..463180e9f8 Binary files /dev/null and b/apps/jsonclock/tran.png differ