diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index b1b5637ad..9e36f67ba 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -33,3 +33,4 @@ 0.17: Load circles from clkinfo 0.18: Improved clkinfo handling and using it for the weather circle 0.19: Remove old code and fixing clkinfo handling (fix HRM and other items that change) + Remove settings for what is displayed and instead allow circles to be changed by swiping diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 8c8fbe4ae..7f6a2585c 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -5,6 +5,7 @@ A clock with three or four circles for different data at the bottom in a probabl By default the time, date and day of week is shown. It can show the following information (this can be configured): + * Steps * Steps distance * Heart rate (automatically updates when screen is on and unlocked) @@ -14,15 +15,24 @@ It can show the following information (this can be configured): * Temperature inside circle * Condition as icon below circle * Big weather icon next to clock - * Time and progress until next sunrise or sunset (requires [my location app](https://banglejs.com/apps/#mylocation)) - * Temperature, air pressure or altitude from internal pressure sensor + * Altitude from internal pressure sensor + * Active alarms (if `Alarm` app installed) + * Sunrise or sunset (if `Sunrise Clockinfo` app installed) +To change what is shown: -The color of each circle can be configured. The following colors are available: +* Unlock the watch +* Tap on the circle to change (a border is drawn around it) +* Swipe up/down to change the guage within the given group +* Swipe left/right to change the group (eg. between standard Bangle.js and Alarms/etc) + +Data is provided by ['Clock Info'](http://www.espruino.com/Bangle.js+Clock+Info) +so any apps that implement this feature can add extra information to be displayed. + +The color of each circle can be configured from `Settings -> Apps -> Circles Clock`. The following colors are available: * Basic colors (red, green, blue, yellow, magenta, cyan, black, white) * Color depending on value (green -> red, red -> green) - ## Screenshots ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) @@ -38,5 +48,5 @@ The color of each circle can be configured. The following colors are available: Marco ([myxor](https://github.com/myxor)) ## Icons -Most of the icons are taken from [materialdesignicons](https://materialdesignicons.com) under Apache License 2.0 except the big weather icons which are from +Most of the icons are taken from [materialdesignicons](https://materialdesignicons.com) under Apache License 2.0 except the big weather icons which are from [icons8](https://icons8.com/icon/set/weather/small--static--black) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 11036dcfc..efd0b0aa6 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -41,11 +41,6 @@ let now = Math.round(new Date().getTime() / 1000); // layout values: let colorFg = g.theme.dark ? '#fff' : '#000'; let colorBg = g.theme.dark ? '#000' : '#fff'; -let colorGrey = '#808080'; -let colorRed = '#ff0000'; -let colorGreen = '#008000'; -let colorBlue = '#0000ff'; -let colorYellow = '#ffff00'; let widgetOffset = showWidgets ? 24 : 0; let dowOffset = circleCount == 3 ? 20 : 22; // dow offset relative to date let h = g.getHeight() - widgetOffset; @@ -53,7 +48,7 @@ let w = g.getWidth(); let hOffset = (circleCount == 3 ? 34 : 30) - widgetOffset; let h1 = Math.round(1 * h / 5 - hOffset); let h2 = Math.round(3 * h / 5 - hOffset); -let h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position +let h3 = Math.round(8 * h / 8 - hOffset - 3); // circle middle y position /* * circle x positions @@ -76,28 +71,17 @@ let circlePosX = [ ]; let radiusOuter = circleCount == 3 ? 25 : 20; +let radiusBorder = radiusOuter+3; // absolute border of circles let radiusInner = circleCount == 3 ? 20 : 15; let circleFontSmall = circleCount == 3 ? "Vector:14" : "Vector:10"; let circleFont = circleCount == 3 ? "Vector:15" : "Vector:11"; let circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:12"; let iconOffset = circleCount == 3 ? 6 : 8; -let defaultCircleTypes = ["Bangle/Steps", "Bangle/HRM", "Bangle/Battery", "weather"]; -let circleInfoNum = [ - 0, // circle1 - 0, // circle2 - 0, // circle3 - 0, // circle4 -]; -let circleItemNum = [ - 0, // circle1 - 1, // circle2 - 2, // circle3 - 3, // circle4 -]; function draw() { - g.reset().clearRect(Bangle.appRect); + let R = Bangle.appRect; + g.reset().clearRect(R.x,R.y, R.x2, h3-(radiusBorder+1)); g.setColor(colorBg); g.fillRect(0, widgetOffset, w, h2 + 22); @@ -139,16 +123,13 @@ function draw() { if (icon) g.drawImage(icon, w - 48, h1, {scale:0.75}); } - // FIXME do we really need to redraw circles every time? - for (var i=1;i<=circleCount;i++) - drawCircle(i); - queueDraw(); } function getCircleColor(index) { let color = settings["circle" + index + "color"]; if (color && color != "") return color; + return g.theme.fg; } function getGradientColor(color, percent) { @@ -176,7 +157,7 @@ function getCircleIconColor(index, color, percent) { if (colorizeIcon) { return getGradientColor(color, percent); } else { - return ""; + return g.theme.fg; } } @@ -189,23 +170,15 @@ function drawEmpty(img, w, color) { .drawImage(img, w - iconOffset, h3 + radiusOuter - iconOffset, {scale: 16/24}); } -function drawCircle(index) { - var info = menu[circleInfoNum[index-1]]; - var type = settings['circle'+index]; +function drawCircle(index, item, data) { var w = circlePosX[index-1]; drawCircleBackground(w); const color = getCircleColor(index); - var item = info && info.items[circleItemNum[index-1]]; - if(!info || !item) { - drawEmpty(info? info.img : null, w, color); - return; - } - var data=item.get(); + //drawEmpty(info? info.img : null, w, color); var img = data.img; var percent = 1; //fill up if no range var txt = ""+data.text; if (txt.endsWith(" bpm")) txt=txt.slice(0,-4); // hack for heart rate - remove the 'bpm' text - if(!img) img = info.img; if(item.hasRange) percent = (data.v-data.min) / (data.max-data.min); if(data.short) txt = data.short; drawGauge(w, h3, percent, color); @@ -293,12 +266,11 @@ function formatSeconds(s) { * Draws the background and the grey circle */ function drawCircleBackground(w) { - g.clearRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); // Draw rectangle background: g.setColor(colorBg); - g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.fillRect(w - radiusBorder, h3 - radiusBorder, w + radiusBorder, g.getHeight()-1); // Draw grey background circle: - g.setColor(colorGrey); + g.setColor('#808080'); // grey g.fillCircle(w, h3, radiusOuter); } @@ -310,10 +282,6 @@ function drawInnerCircleAndTriangle(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); } -function radians(a) { - return a * Math.PI / 180; -} - /* * This draws the actual gauge consisting out of lots of little filled circles */ @@ -332,10 +300,12 @@ function drawGauge(cx, cy, percent, color) { color = getGradientColor(color, percent); g.setColor(color); + // FIXME: this one loop takes 0.25 sec EACH TIME the function is called for (let i = startRotation; i > endRotation - size; i -= size) { - x = cx + radius * Math.sin(radians(i)); - y = cy + radius * Math.cos(radians(i)); - g.fillCircle(x, y, size); + let r = i * Math.PI / 180; // radians + g.fillCircle( + cx + radius * Math.sin(r), + cy + radius * Math.cos(r), size); } } @@ -354,35 +324,7 @@ function getWeather() { return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined; } - -var menu = clock_info.load(); -for(var i=1; i<5; i++) { - var circleType = settings['circle'+i]; - if(circleType.includes("/")) { - let parts = circleType.split("/"); - let infoName = parts[0], itemName = parts[1]; - let infoNum = menu.findIndex(e=>e.name==infoName); - if (infoNum<0) infoNum=0; // not found! - let itemNum = 0; //get first if dynamic - if(!menu[infoNum].dynamic) - itemNum = menu[infoNum].items.findIndex(it=>it.name==itemName); - if (itemNum<0) itemNum=0; - circleInfoNum[i-1] = infoNum; - circleItemNum[i-1] = itemNum; - let menuItem = menu[infoNum].items[itemNum]; - if (menuItem) { - (function(i){ - menuItem.on('redraw', function() { - drawCircle(i); - }); - })(i); - menuItem.show(); - } - } else { // empty? - circleInfoNum[i-1] = -1; - circleItemNum[i-1] = -1; - } -} +g.clear(1); // clear the whole screen Bangle.setUI({ mode : "clock", @@ -393,12 +335,29 @@ Bangle.setUI({ // Called to unload all of the clock app if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - // must call clkinfo.hide here for any showing clkinfo + for(var i=1;i<=circleCount; i++) + clockInfoMenu[i].remove(); delete Graphics.prototype.setFontRobotoRegular50NumericOnly; delete Graphics.prototype.setFontRobotoRegular21; }*/ }); +let clockInfoDraw = (itm, info, options) => { + //print("Draw",itm.name,options); + drawCircle(options.circlePosition, itm, info); + if (options.focus) g.reset().drawRect(options.x, options.y, options.x+options.w-2, options.y+options.h-1) +}; +let clockInfoItems = require("clock_info").load(); +let clockInfoMenu = []; +for(var i=0;i{ - if(e.dynamic) { - valuesCircleTypes = valuesCircleTypes.concat([e.name+"/"]); - namesCircleTypes = namesCircleTypes.concat([e.name]); - } else { - let values = e.items.map(i=>e.name+"/"+i.name); - let names = e.name=="Bangle" ? e.items.map(i=>i.name) : values; - valuesCircleTypes = valuesCircleTypes.concat(values); - namesCircleTypes = namesCircleTypes.concat(names); - } - }) - - const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000", "green-red", "red-green", "fg"]; const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", @@ -103,12 +88,6 @@ const menu = { '': { 'title': /*LANG*/'Circle ' + circleId }, /*LANG*/'< Back': ()=>showMainMenu(), - /*LANG*/'data': { - value: valuesCircleTypes.indexOf(settings[circleName]), - min: 0, max: valuesCircleTypes.length - 1, - format: v => namesCircleTypes[v], - onchange: x => save(circleName, valuesCircleTypes[x]), - }, /*LANG*/'color': { value: valuesColors.indexOf(settings[colorKey]) || 0, min: 0, max: valuesColors.length - 1,