diff --git a/apps/chargent/ChangeLog b/apps/chargent/ChangeLog index 7f837e50e..ae4aa0e36 100644 --- a/apps/chargent/ChangeLog +++ b/apps/chargent/ChangeLog @@ -1 +1,2 @@ 0.01: First version +0.02: Support BangleJS2 diff --git a/apps/chargent/boot.js b/apps/chargent/boot.js index 802c3f55a..b02d00a8e 100644 --- a/apps/chargent/boot.js +++ b/apps/chargent/boot.js @@ -1,4 +1,6 @@ (() => { + const pin = process.env.HWVERSION === 2 ? D3 : D30; + var id; Bangle.on('charging', (charging) => { if (charging) { @@ -6,9 +8,9 @@ var max = 0; var count = 0; id = setInterval(() => { - var d30 = analogRead(D30); - if (max < d30) { - max = d30; + var battlvl = analogRead(pin); + if (max < battlvl) { + max = battlvl; count = 0; } else { count++; diff --git a/apps/chargent/boot.min.js b/apps/chargent/boot.min.js deleted file mode 100644 index 700198146..000000000 --- a/apps/chargent/boot.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){var a;Bangle.on("charging",function(e){if(e){if(!a){var c=0,b=0;a=setInterval(function(){var d=analogRead(D30);c 12 ? h-12 : h; + h += date.getMinutes()/60.0; + h = parseInt(h*360/12); + + // Draw minute and hour fg + g.setColor(g.theme.fg); + drawHour(h); + drawMinute(m); +} + + +let drawSmile = function(isLocked){ + var y = 120; + var o = parseInt(E.getBattery()*0.8); + + // Draw smile + drawCurve(30, y, W/2+12, y+o, W-40, y); + + // And the two "mouth lines" + var reachedSteps = Bangle.getHealthStatus("day").steps >= 10000; + for(var i=0; i < 6; i++){ + if(isLocked) g.drawLine(25, y+6+i, 35, y-5+i); + if(reachedSteps) g.drawLine(W-35, y+5+i, W-45, y-5+i); + } +} + +let drawEyeBrow = function(){ + var w = 6; + for(var i = 0; i < w; i++){ + g.drawLine(25, 25+i, 70, 15+i%3); + g.drawLine(W-25, 28+i%3, W-68, 19+i); + } +} + + + +let draw = function(){ + // Queue draw in one minute + queueDraw(); + + var isLocked = Bangle.isLocked(); + drawHelper(isLocked); +} + +let drawHelper = function(isLocked){ + g.setColor(g.theme.fg); + g.reset().clear(); + + drawEyes(); + drawEyeBrow(); + drawSmile(isLocked); +} + + +/* + * Listeners + */ +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + +Bangle.on('lock', function(isLocked) { + draw(isLocked); +}); + + +/* + * Some helpers + */ +let queueDraw = function() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + + +/* + * Lets start widgets, listen for btn etc. + */ +// Show launcher when middle button pressed +Bangle.setUI("clock"); +Bangle.loadWidgets(); +/* + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ +require('widget_utils').hide(); + +// Clear the screen once, at startup and draw clock +// g.setTheme({bg:"#fff",fg:"#000",dark:false}); +draw(); + +// After drawing the watch face, we can draw the widgets +// Bangle.drawWidgets(); diff --git a/apps/happyclk/happyclk.icon.js b/apps/happyclk/happyclk.icon.js new file mode 100644 index 000000000..d59fc0668 --- /dev/null +++ b/apps/happyclk/happyclk.icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgP/ADEP/AEC+E//kH//+gYIB8F//1/B4U/ERgdB/wdB//AFIJGCx/n+P8EIM/+fnE4IBB/PAv4aBv/84E/z/8//8wAFDwwFB74FBgQFD/wFGyF/AoUAz//z/+AoPfAoV/gPP/+/IIP585lCj/z8ZvCw+H/HwPQUf/iACACIrBAAaRCGAP+AoXzAonxAoJRB//lAQJLBC4X/44IE8KeCVoQCBj4CB/iYBEwX+h6sCAAOB8BCD4C+CDwTKCACI=")) \ No newline at end of file diff --git a/apps/happyclk/happyclk.png b/apps/happyclk/happyclk.png new file mode 100644 index 000000000..53fbe152e Binary files /dev/null and b/apps/happyclk/happyclk.png differ diff --git a/apps/happyclk/metadata.json b/apps/happyclk/metadata.json new file mode 100644 index 000000000..2388db667 --- /dev/null +++ b/apps/happyclk/metadata.json @@ -0,0 +1,21 @@ +{ + "id": "happyclk", + "name": "Happy Clock", + "shortName":"Happy Clock", + "icon": "happyclk.png", + "version":"0.01", + "readme": "README.md", + "supports": ["BANGLEJS2"], + "description": "A happy clock :)", + "type": "clock", + "tags": "clock", + "screenshots": [ + {"url":"screenshot_1.png"}, + {"url":"screenshot_2.png"}, + {"url":"screenshot_3.png"} + ], + "storage": [ + {"name":"happyclk.app.js","url":"happyclk.app.js"}, + {"name":"happyclk.img","url":"happyclk.icon.js","evaluate":true} + ] +} diff --git a/apps/happyclk/screenshot_1.png b/apps/happyclk/screenshot_1.png new file mode 100644 index 000000000..20bf2d294 Binary files /dev/null and b/apps/happyclk/screenshot_1.png differ diff --git a/apps/happyclk/screenshot_2.png b/apps/happyclk/screenshot_2.png new file mode 100644 index 000000000..5bb00bc38 Binary files /dev/null and b/apps/happyclk/screenshot_2.png differ diff --git a/apps/happyclk/screenshot_3.png b/apps/happyclk/screenshot_3.png new file mode 100644 index 000000000..404bd7918 Binary files /dev/null and b/apps/happyclk/screenshot_3.png differ diff --git a/apps/hwid_a_battery_widget/metadata.json b/apps/hwid_a_battery_widget/metadata.json index 29b0540c2..981b81079 100644 --- a/apps/hwid_a_battery_widget/metadata.json +++ b/apps/hwid_a_battery_widget/metadata.json @@ -9,6 +9,7 @@ "readme": "README.md", "description": "Simple and slim battery widget with charge status and percentage", "tags": "widget,battery", + "provides_widgets" : ["battery"], "storage": [ {"name":"hwid_a_battery_widget.wid.js","url":"widget.js"} ] diff --git a/apps/iconlaunch/README.md b/apps/iconlaunch/README.md index 0d36fdeb4..49d01d3fd 100644 --- a/apps/iconlaunch/README.md +++ b/apps/iconlaunch/README.md @@ -6,7 +6,3 @@ This launcher shows 9 apps per screen, making it much faster to navigate versus ![A screenshot](screenshot1.png) ![Another screenshot](screenshot2.png) - -## Technical note - -The app uses `E.showScroller`'s code in the app but not the function itself because `E.showScroller` doesn't report the position of a press to the select function. diff --git a/apps/iconlaunch/app.js b/apps/iconlaunch/app.js index acf695ddb..8d155c73e 100644 --- a/apps/iconlaunch/app.js +++ b/apps/iconlaunch/app.js @@ -32,13 +32,14 @@ }) }; s.writeJSON("iconlaunch.cache.json", launchCache); } - let scroll = 0; + let selectedItem = -1; const R = Bangle.appRect; const iconSize = 48; const appsN = Math.floor(R.w / iconSize); const whitespace = (R.w - appsN * iconSize) / (appsN + 1); const itemSize = iconSize + whitespace; + let drawItem = function(itemI, r) { g.clearRect(r.x, r.y, r.x + r.w - 1, r.y + r.h - 1); let x = 0; @@ -61,36 +62,26 @@ } x += iconSize; } - drawText(itemI); + drawText(itemI, r.y); }; - let drawItemAuto = function(i) { - let y = idxToY(i); - g.reset().setClipRect(R.x, y, R.x2, y + itemSize); - drawItem(i, { - x: R.x, - y: y, - w: R.w, - h: itemSize - }); - g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); - }; - let lastIsDown = false; - let drawText = function(i) { + + let drawText = function(i, appY) { const selectedApp = launchCache.apps[selectedItem]; const idy = (selectedItem - (selectedItem % 3)) / 3; if (!selectedApp || i != idy) return; - const appY = idxToY(idy) + iconSize / 2; + appY = appY + itemSize/2; g.setFontAlign(0, 0, 0); g.setFont("12x20"); const rect = g.stringMetrics(selectedApp.name); g.clearRect( - R.w / 2 - rect.width / 2, - appY - rect.height / 2, - R.w / 2 + rect.width / 2, - appY + rect.height / 2 + R.w / 2 - rect.width / 2 - 2, + appY - rect.height / 2 - 2, + R.w / 2 + rect.width / 2 + 1, + appY + rect.height / 2 + 1 ); g.drawString(selectedApp.name, R.w / 2, appY); }; + let selectItem = function(id, e) { const iconN = E.clip(Math.floor((e.x - R.x) / itemSize), 0, appsN - 1); const appId = id * appsN + iconN; @@ -108,96 +99,32 @@ } } selectedItem = appId; - drawItems(); + if (scroller) scroller.draw(); }; - let idxToY = function(i) { - return i * itemSize + R.y - (scroll & ~1); - }; - let YtoIdx = function(y) { - return Math.floor((y + (scroll & ~1) - R.y) / itemSize); - }; - let drawItems = function() { - g.reset().clearRect(R.x, R.y, R.x2, R.y2); - g.setClipRect(R.x, R.y, R.x2, R.y2); - let a = YtoIdx(R.y); - let b = Math.min(YtoIdx(R.y2), 99); - for (let i = a; i <= b; i++) - drawItem(i, { - x: R.x, - y: idxToY(i), - w: R.w, - h: itemSize, - }); - g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); - }; - drawItems(); - g.flip(); const itemsN = Math.ceil(launchCache.apps.length / appsN); - let onDrag = function(e) { - updateTimeout(); - g.setColor(g.theme.fg); - g.setBgColor(g.theme.bg); - let dy = e.dy; - if (scroll + R.h - dy > itemsN * itemSize) { - dy = scroll + R.h - itemsN * itemSize; - } - if (scroll - dy < 0) { - dy = scroll; - } - scroll -= dy; - scroll = E.clip(scroll, 0, itemSize * (itemsN - 1)); - g.setClipRect(R.x, R.y, R.x2, R.y2); - g.scroll(0, dy); - if (dy < 0) { - g.setClipRect(R.x, R.y2 - (1 - dy), R.x2, R.y2); - let i = YtoIdx(R.y2 - (1 - dy)); - let y = idxToY(i); - while (y < R.y2) { - drawItem(i, { - x: R.x, - y: y, - w: R.w, - h: itemSize, - }); - i++; - y += itemSize; - } - } else { - g.setClipRect(R.x, R.y, R.x2, R.y + dy); - let i = YtoIdx(R.y + dy); - let y = idxToY(i); - while (y > R.y - itemSize) { - drawItem(i, { - x: R.x, - y: y, - w: R.w, - h: itemSize, - }); - y -= itemSize; - i--; - } - } - g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); - }; - let mode = { - mode: "custom", - drag: onDrag, - touch: (_, e) => { - if (e.y < R.y - 4) return; - updateTimeout(); - let i = YtoIdx(e.y); - selectItem(i, e); - }, - swipe: (h,_) => { if(settings.swipeExit && h==1) { Bangle.showClock(); } }, - btn: _=> { if (settings.oneClickExit) Bangle.showClock(); }, + + let back = ()=>{}; + if (settings.oneClickExit) back = Bangle.showClock; + + let options = { + h: itemSize, + c: itemsN, + draw: drawItem, + select: selectItem, + back: back, remove: function() { if (timeout) clearTimeout(timeout); + Bangle.removeListener("drag", updateTimeout); + Bangle.removeListener("touch", updateTimeout); + Bangle.removeListener("swipe", swipeHandler); if (settings.fullscreen) { // for fast-load, if we hid widgets then we should show them again require("widget_utils").show(); } } }; + let scroller = E.showScroller(options); + let timeout; const updateTimeout = function(){ if (settings.timeOut!="Off"){ @@ -207,7 +134,11 @@ } }; - updateTimeout(); + let swipeHandler = (h,_) => { if(settings.swipeExit && h==1) { Bangle.showClock(); } }; + + Bangle.on("swipe", swipeHandler) + Bangle.on("drag", updateTimeout); + Bangle.on("touch", updateTimeout); - Bangle.setUI(mode); + updateTimeout(); } diff --git a/apps/lightswitch/README.md b/apps/lightswitch/README.md index 67d070f5c..c17a6a4ed 100644 --- a/apps/lightswitch/README.md +++ b/apps/lightswitch/README.md @@ -1,6 +1,6 @@ # Light Switch Widget -With this widget I wanted to create a solution to quickly en-/disable the LCD backlight and even change the brightness. +With this widget I wanted to create a solution to quickly en-/disable the LCD backlight and even change the brightness. In addition it shows the lock status with the option to personalize the lock icon with a tiny image. All touch and drag inputs related to this widget are cached/masked to prevent actions in the active app. @@ -9,32 +9,32 @@ All touch and drag inputs related to this widget are cached/masked to prevent ac --- ### Control --- -* __On / off__ +* __On / off__ Single touch the widget to en-/disable the backlight. -* __Change brightness__ _(can be disabled)_ +* __Change brightness__ _(can be disabled)_ First touch the widget, then quickly touch the screen again and drag up/down until you reach your wished brigthness. -* __Double tap to flash backlight__ _(can be disabled)_ - By defaut you can double tap on the right side of your bangle to flash the backlight for a short duration. +* __Double tap to flash backlight__ _(can be disabled)_ + By defaut you can double tap on the right side of your bangle to flash the backlight for a short duration. (While the backlight is active your bangle will be unlocked.) -* __Double tap to unlock__ _(disabled by default)_ +* __Double tap to unlock__ _(disabled by default)_ If a side is defined in the app settings, your bangle will be unlocked if you double tap on that side. --- ### Settings --- #### Widget - Change the apperance of the widget: -* __Bulb col__ - _red_ / _yellow_ / _green_ / __cyan__ / _blue_ / _magenta_ - Define the color used for the lightbulbs inner circle. +* __Bulb col__ + _red_ / _yellow_ / _green_ / __cyan__ / _blue_ / _magenta_ + Define the color used for the lightbulbs inner circle. The selected color will be dimmed depending on the actual brightness value. -* __Image__ - __default__ / _random_ / _..._ +* __Image__ + __default__ / _random_ / _..._ Set your favourite lock icon image. (If no image file is found _no image_ will be displayed.) * _random_ -> Select a random image on each time the widget is drawn. #### Control - Change when and how to use the widget: -* __Touch__ - _on def clk_ / _on all clk_ / _clk+setting_ / _clk+launch_ / _except apps_ / __always on__ +* __Touch__ + _on def clk_ / _on all clk_ / _clk+setting_ / _clk+launch_ / _except apps_ / __always on__ Select when touching the widget is active to en-/disable the backlight. * _on def clk_ -> only on your selected main clock face * _on all clk_ -> on all apps of the type _clock_ @@ -42,32 +42,34 @@ All touch and drag inputs related to this widget are cached/masked to prevent ac * _clk+launch_ -> on all apps of the types _clock_ and _launch_ * _except apps_ -> on all apps of the types _clock_ and _launch_ and in the settings * _always on_ -> always enabled when the widget is displayed -* __Oversize__ - _0px_ / _1px_ / _..._ / __20px__ / _..._ / _50px_ +* __Oversize__ + _0px_ / _1px_ / _..._ / __20px__ / _..._ / _50px_ To make it easier to hit the widget, this value extends the touch area of the widget in all directions. -* __Drag Delay__ - _off_ / _50ms_ / _100ms_ / _..._ / __500ms__ / _..._ / _1000ms_ +* __Drag Delay__ + _off_ / _50ms_ / _100ms_ / _..._ / __500ms__ / _..._ / _1000ms_ Change the maximum delay between first touch and re-touch/drag to change the brightness or disable changing the brightness completely. -* __Min Value__ - _1%_ / _2%_ / _..._ / __10%__ / _..._ / _100%_ - Set the minimal level of brightness you can change to. +* __Min Value__ + _1%_ / _2%_ / _..._ / __10%__ / _..._ / _100%_ + Set the minimal level of brightness you can change to. +* __Tap to lock__ + Tapping the widget locks the screen, rather than toggling brightness. #### Unlock - Set double tap side to unlock: -* __TapSide__ +* __TapSide__ __off__ / _left_ / _right_ / _top_ / _bottom_ / _front_ / _back_ #### Flash - Change if and how to flash the backlight: -* __TapSide__ - _off_ / _left_ / __right__ / _top_ / _bottom_ / _front_ / _back_ +* __TapSide__ + _off_ / _left_ / __right__ / _top_ / _bottom_ / _front_ / _back_ Set double tap side to flash the backlight or disable completely. -* __Tap__ - _on locked_ / _on unlocked_ / __always on__ +* __Tap__ + _on locked_ / _on unlocked_ / __always on__ Select when a double tap is recognised. -* __Timeout__ - _0.5s_ / _1s_ / _..._ / __2s__ / _..._ / _10s_ +* __Timeout__ + _0.5s_ / _1s_ / _..._ / __2s__ / _..._ / _10s_ Change how long the backlight will be activated on a flash. -* __Min Value__ - _1%_ / _2%_ / _..._ / __20%__ / _..._ / _100%_ +* __Min Value__ + _1%_ / _2%_ / _..._ / __20%__ / _..._ / _100%_ Set the minimal level of brightness for the backlight on a flash. --- @@ -81,7 +83,7 @@ All touch and drag inputs related to this widget are cached/masked to prevent ac Examples in default light and dark theme. -| Lock | Heart | Invader | JS | Smiley | Skull | Storm | +| Lock | Heart | Invader | JS | Smiley | Skull | Storm | |:----:|:-----:|:-------:|:--:|:------:|:-----:|:-----:| | ![](images/image_lock.png) | ![](images/image_heart.png) | ![](images/image_invader.png) | ![](images/image_js.png) | ![](images/image_smiley.png) | ![](images/image_skull.png) | ![](images/image_storm.png) | diff --git a/apps/lightswitch/settings.js b/apps/lightswitch/settings.js index 5ac70bc28..aff45a444 100644 --- a/apps/lightswitch/settings.js +++ b/apps/lightswitch/settings.js @@ -10,6 +10,7 @@ oversize: 20, dragDelay: 500, minValue: 0.1, + tapToLock: false, unlockSide: "", tapSide: "right", tapOn: "always", @@ -119,6 +120,11 @@ max: 100, step: 1 }, + tapToLock: { + title: ["on", "off"], + value: [true, false], + drawWidgets: false + }, unlockSide: { title: ["off", "left", "right", "top", "bottom", "front", "back"], value: ["", "left", "right", "top", "bottom", "front", "back"] @@ -154,6 +160,7 @@ "Oversize": getEntry("oversize"), "Drag Delay": getEntry("dragDelay"), "Min Value": getEntry("minValue"), + "Tap to lock": getEntry("tapToLock"), "-- Unlock": 0, "TapSide": getEntry("unlockSide"), "-- Flash": 0, diff --git a/apps/lightswitch/widget.js b/apps/lightswitch/widget.js index 9eb488aca..922875216 100644 --- a/apps/lightswitch/widget.js +++ b/apps/lightswitch/widget.js @@ -7,6 +7,7 @@ oversize: 20, dragDelay: 500, minValue: 0.1, + tapToLock: false, unlockSide: "", tapSide: "right", tapOn: "always", @@ -208,8 +209,12 @@ w.dragStatus = "off"; }, w.dragDelay, w); } - // switch backlight - w.changeValue(); + if (w.tapToLock) { + Bangle.setLocked(true); + } else { + // switch backlight + w.changeValue(); + } // masks this touch event by messing up the event handler // see https://github.com/espruino/Espruino/issues/2151 Bangle.removeListener("touch", w.touchListener); @@ -251,7 +256,7 @@ w = undefined; } }); - + Bangle.on("lock", locked => { var w = WIDGETS.lightswitch; // set lcd brightness on unlocking diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog index 795c62fa2..4815e5e75 100644 --- a/apps/sleepphasealarm/ChangeLog +++ b/apps/sleepphasealarm/ChangeLog @@ -13,3 +13,4 @@ 0.10: Fix: Do not wake when falling asleep 0.11: Minor tweaks 0.12: Support javascript command to execute as defined in scheduler 'js' configuration +0.13: Fix dated events alarm on wrong date diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index ba8bff9b2..0aef07760 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -10,7 +10,7 @@ const config = Object.assign({ disableAlarm: false, } }, require("Storage").readJSON(CONFIGFILE,1) || {}); -const active = alarms.filter(a=>a.on); +const active = alarms.filter(alarm => require("sched").getTimeToAlarm(alarm)); const schedSettings = require("sched").getSettings(); let buzzCount = schedSettings.buzzCount; let logs = []; diff --git a/apps/sleepphasealarm/metadata.json b/apps/sleepphasealarm/metadata.json index ced99062f..5382160c0 100644 --- a/apps/sleepphasealarm/metadata.json +++ b/apps/sleepphasealarm/metadata.json @@ -2,7 +2,7 @@ "id": "sleepphasealarm", "name": "SleepPhaseAlarm", "shortName": "SleepPhaseAlarm", - "version": "0.12", + "version": "0.13", "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", "icon": "app.png", "tags": "alarm", @@ -14,6 +14,6 @@ {"name":"sleepphasealarm.settings.js","url":"settings.js"}, {"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true} ], - "data": [{"name":"sleepphasealarm.json","storageFile":true}], + "data": [{"name":"sleepphasealarm.json"}], "interface": "interface.html" } diff --git a/apps/terminalclock/ChangeLog b/apps/terminalclock/ChangeLog index 268e0427c..2df526734 100644 --- a/apps/terminalclock/ChangeLog +++ b/apps/terminalclock/ChangeLog @@ -7,3 +7,4 @@ 0.07: Use ClockFace module and rework the settings to be able to personnalize the order of the lines 0.08: Hide widgets instead of not loading them at all Use Clockface_menu for widgets and power saving settings +0.09: Add default HRM value, default altitude value diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index 515ad8f66..04e4fb5c8 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -1,211 +1,239 @@ -const locale = require("locale"); -var heartRate = 0; -var altitude = -9001; +{ + const locale = require("locale"); + let heartRate = 0; + let altitude = -9001; -const fontColor = g.theme.dark ? "#0f0" : "#000"; -// handling the differents versions of the Banglejs smartwatch screen sizes -if (process.env.HWVERSION == 1){ - var paddingY = 3; - var font6x8At4Size = 48; - var font6x8At2Size = 27; - var font6x8FirstTextSize = 6; - var font6x8DefaultTextSize = 3; -} else{ - var paddingY = 2; - var font6x8At4Size = 32; - var font6x8At2Size = 18; - var font6x8FirstTextSize = 4; - var font6x8DefaultTextSize = 2; -} + const fontColor = g.theme.dark ? "#0f0" : "#000"; + // handling the differents versions of the Banglejs smartwatch screen sizes + // default BJS2 + let paddingY = 2; + let font6x8At4Size = 32; + let font6x8At2Size = 18; + let font6x8FirstTextSize = 4; + let font6x8DefaultTextSize = 2; + if (process.env.HWVERSION == 1){ + paddingY = 3; + font6x8At4Size = 48; + font6x8At2Size = 27; + font6x8FirstTextSize = 6; + font6x8DefaultTextSize = 3; + } + // initialising the clockface + const ClockFace = require("ClockFace"); + const clock = new ClockFace({ + precision: 60, + settingsFile: "terminalclock.json", -// initialising the clockface -const ClockFace = require("ClockFace"); -const clock = new ClockFace({ - precision: 60, - settingsFile: "terminalclock.json", + init: function () { + // check settings and set default if needed + this.showHRM = false; + this.showAltitude = false; + this.lock_precision = this.precision; + this.unlock_precision = 1; + if (this.HRMinConfidence === undefined) this.HRMinConfidence = 50; + if (this.PowerOnInterval === undefined) this.PowerOnInterval = 15; + if (this.powerSave===undefined) this.powerSave = this.powerSaving; // migrate old setting + if (this.powerSave===undefined) this.powerSave = true; - init: function () { - // check settings and set default if needed - this.showHRM = false; - this.showAltitude = false; - this.lock_precision = this.precision; - this.unlock_precision = 1; - if (this.HRMinConfidence === undefined) this.HRMinConfidence = 50; - if (this.PowerOnInterval === undefined) this.PowerOnInterval = 15; - if (this.powerSave===undefined) this.powerSave = this.powerSaving; // migrate old setting - if (this.powerSave===undefined) this.powerSave = true; - ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(k => { - if (this[k]===undefined){ - if(k == "L2") this[k] = "Date"; - else if(k == "L3") { - this[k] = "HR"; - this.showHRM = true; - }else if(k == "L4") this[k] = "Motion"; - else if(k == "L5") this[k] = "Steps"; - else if(k == "L6") this[k] = ">"; - else this[k] = "Empty"; - } - else if (this[k]==="HR") this.showHRM = true; - else if (this[k]==="Alt") this.showAltitude = true && process.env.HWVERSION == 2; - }); + ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(k => { + if (this[k]===undefined){ + if(k == "L2") this[k] = "Date"; + else if(k == "L3") { + this[k] = "HR"; + this.showHRM = true; + }else if(k == "L4") this[k] = "Motion"; + else if(k == "L5") this[k] = "Steps"; + else if(k == "L6") this[k] = ">"; + else this[k] = "Empty"; + } + else if (this[k]==="HR") this.showHRM = true; + else if (this[k]==="Alt") this.showAltitude = true && process.env.HWVERSION == 2; + }); - // set the lock and unlock actions - Bangle.on("lock", on => { - if (on) lock(); - else unlock(); - }); + // set the services (HRM, pressure sensor, etc....) + if(!this.powerSave){ + turnOnServices(); + } else{ + this.turnOnInterval = setInterval(turnOnServices, this.PowerOnInterval*60000); // every PowerOnInterval min + } + // start the clock unlocked + unlock(); + }, - // set the services (HRM, pressure sensor, etc....) - if(!this.powerSave){ - turnOnServices(); - } else{ - setInterval(turnOnServices, this.PowerOnInterval*60000); // every PowerOnInterval min - } - // start the clock unlocked - unlock(); - }, - - draw: function (date) { - var curPos = 1; - g.setFontAlign(-1, -1); - g.setColor(fontColor); - drawTime(date, curPos); - curPos++; - - ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(line => { - if (this[line]==='Date') drawDate(date, curPos); - else if (this[line]==='HR') drawHRM(curPos); - else if (this[line]==='Motion') drawMotion(curPos); - else if (this[line]==='Alt') drawAltitude(curPos); - else if (this[line]==='Steps') drawStepCount(curPos); - else if (this[line]==='>') drawInput(curPos); + draw: function (date) { + let curPos = 1; + g.setFontAlign(-1, -1); + g.setColor(fontColor); + drawTime(date, curPos); curPos++; - }); - }, -}); + ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(line => { + if (this[line]==='Date') drawDate(date, curPos); + else if (this[line]==='HR') drawHRM(curPos); + else if (this[line]==='Motion') drawMotion(curPos); + else if (this[line]==='Alt') drawAltitude(curPos); + else if (this[line]==='Steps') drawStepCount(curPos); + else if (this[line]==='>') drawInput(curPos); + curPos++; + }); + }, -/* ---------------------------- -Draw related of specific lines --------------------------------- */ - -function drawLine(line, pos){ - if(pos == 1) - g.setFont("6x8", font6x8FirstTextSize); - else - g.setFont("6x8", font6x8DefaultTextSize); - - var yPos = Bangle.appRect.y + - paddingY * (pos - 1) + - font6x8At4Size * Math.min(1, pos-1) + - font6x8At2Size * Math.max(0, pos-2); - g.drawString(line, 5, yPos, true); -} - -function drawTime(now, pos){ - var h = now.getHours(); - var m = now.getMinutes(); - var time = ">" + (""+h).substr(-2) + ":" + ("0"+m).substr(-2); - drawLine(time, pos); -} - -function drawDate(now, pos){ - var dow = locale.dow(now, 1); - var date = locale.date(now, 1).substr(0,6) + locale.date(now, 1).substr(-2); - var locale_date = ">" + dow + " " + date; - drawLine(locale_date, pos); -} - -function drawInput(pos){ - drawLine(">", pos); -} - -function drawStepCount(pos){ - var health = Bangle.getHealthStatus("day"); - var steps_formated = ">Steps: " + health.steps; - drawLine(steps_formated, pos); -} - -function drawHRM(pos){ - if(heartRate != 0) - drawLine(">HR: " + parseInt(heartRate), pos); - else - drawLine(">HR: unknown", pos); -} - -function drawAltitude(pos){ - if(altitude > 0) - drawLine(">Alt: " + altitude.toFixed(1) + "m", pos); - else - drawLine(">Alt: unknown", pos); -} - -function drawMotion(pos){ - var health = Bangle.getHealthStatus('last'); - var steps_formated = ">Motion: " + parseInt(health.movement); - drawLine(steps_formated, pos); -} - -/* ----------------------------------------------- -Services functions (HRM, pressure, etc...) --------------------------------------------------- */ - -function turnOnServices(){ - if(clock.showHRM){ - Bangle.setHRMPower(true, "terminalclock"); - } - if(clock.showAltitude){ - Bangle.setBarometerPower(true, "terminalclock"); - } - if(clock.powerSave){ - setTimeout(function () { + /* + // todo add fastloading when the memory leak is fixed + remove: function() { + if (this.turnOnInterval){ + clearInterval(this.turnOnInterval); + delete this.turnOnInterval; + } + if (this.turnOffServiceTimeout){ + clearTimeout(this.turnOffServiceTimeout) + } turnOffServices(); - }, 45000); - } -} + if (this.onLock) Bangle.removeListener('lock', this.onLock); + if (this.onHRM) Bangle.removeListener('HRM', this.onHRM); + if (this.onPressure) Bangle.removeListener('onPressure', this.onPressure); + } + */ -function turnOffServices(){ - if(clock.showHRM){ - Bangle.setHRMPower(false, "terminalclock"); - } - if(clock.showAltitude){ - Bangle.setBarometerPower(false, "terminalclock"); - } -} + }); -Bangle.on('HRM',function(hrmInfo) { - if(hrmInfo.confidence >= clock.HRMinConfidence) - heartRate = hrmInfo.bpm; -}); -const MEDIANLENGTH = 20; // technical -var avr = [], median; // technical -Bangle.on('pressure', function(e) { - while (avr.length>MEDIANLENGTH) avr.pop(); - avr.unshift(e.altitude); - median = avr.slice().sort(); - if (median.length>10) { - var mid = median.length>>1; - altitude = E.sum(median.slice(mid-4,mid+5)) / 9; - } -}); + /* ---------------------------- + Draw related of specific lines + -------------------------------- */ -/* ------------------------------------------------- -Clock related functions but not in the ClockFace module ----------------------------------------------------- */ + let drawLine = function(line, pos){ + if(pos == 1) + g.setFont("6x8", font6x8FirstTextSize); + else + g.setFont("6x8", font6x8DefaultTextSize); -function unlock(){ - if(clock.powerSave){ - turnOnServices(); - } - clock.precision = clock.unlock_precision; - clock.tick(); -} + let yPos = Bangle.appRect.y + + paddingY * (pos - 1) + + font6x8At4Size * Math.min(1, pos-1) + + font6x8At2Size * Math.max(0, pos-2); + g.drawString(line, 5, yPos, true); + }; -function lock(){ - clock.precision = clock.lock_precision; - clock.tick(); -} + let drawTime = function(now, pos){ + let h = now.getHours(); + let m = now.getMinutes(); + let time = ">" + (""+h).substr(-2) + ":" + ("0"+m).substr(-2); + drawLine(time, pos); + }; -// starting the clock -clock.start(); + let drawDate = function(now, pos){ + let dow = locale.dow(now, 1); + let date = locale.date(now, 1).substr(0,6) + locale.date(now, 1).substr(-2); + let locale_date = ">" + dow + " " + date; + drawLine(locale_date, pos); + }; + + let drawInput = function(pos){ + drawLine(">", pos); + }; + + let drawStepCount = function(pos){ + let health = Bangle.getHealthStatus("day"); + let steps_formated = ">Steps: " + health.steps; + drawLine(steps_formated, pos); + }; + + let drawHRM = function(pos){ + if(heartRate != 0) + drawLine(">HR: " + parseInt(heartRate), pos); + else + drawLine( + ">HR: " + parseInt(Math.round(Bangle.getHealthStatus().bpm||Bangle.getHealthStatus("last").bpm)), + pos); + }; + + let drawAltitude = function(pos){ + if(altitude > 0) + drawLine(">Alt: " + altitude.toFixed(1) + "m", pos); + else + drawLine(">Alt: unknown", pos); + }; + + let drawMotion = function(pos){ + let health = Bangle.getHealthStatus('last'); + let steps_formated = ">Motion: " + parseInt(health.movement); + drawLine(steps_formated, pos); + }; + + /* ----------------------------------------------- + Services functions (HRM, pressure, etc...) + -------------------------------------------------- */ + + let turnOnServices = function(){ + if(clock.showHRM){ + Bangle.setHRMPower(true, "terminalclock"); + } + if(clock.showAltitude){ + Bangle.setBarometerPower(true, "terminalclock"); + } + if(clock.powerSave){ + clock.turnOffServiceTimeout = setTimeout(function () { + turnOffServices(); + }, 45000); + } + }; + + let turnOffServices = function(){ + if(clock.showHRM){ + Bangle.setHRMPower(false, "terminalclock"); + } + if(clock.showAltitude){ + Bangle.setBarometerPower(false, "terminalclock"); + } + }; + + // set the lock and unlock actions + clock.onLock = lock_event => { + if (lock_event) lock(); + else unlock(); + }; + Bangle.on("lock", clock.onLock); + + clock.onHRM = hrmInfo => { + if(hrmInfo.confidence >= clock.HRMinConfidence) + heartRate = hrmInfo.bpm; + }; + Bangle.on('HRM', clock.onHRM); + + const MEDIANLENGTH = 20; // technical + let avr = [], median; // technical + clock.onPressure = pressureInfo => { + while (avr.length>MEDIANLENGTH) avr.pop(); + avr.unshift(pressureInfo.altitude); + median = avr.slice().sort(); + if (median.length>10) { + let mid = median.length>>1; + altitude = E.sum(median.slice(mid-4,mid+5)) / 9; + } + else + altitude = pressureInfo.altitude; + }; + Bangle.on('pressure', clock.onPressure); + + + /* ------------------------------------------------- + Clock related functions but not in the ClockFace module + ---------------------------------------------------- */ + + let unlock = function(){ + if(clock.powerSave){ + turnOnServices(); + } + clock.precision = clock.unlock_precision; + clock.tick(); + }; + + let lock = function(){ + clock.precision = clock.lock_precision; + clock.tick(); + }; + + // starting the clock + clock.start(); +} \ No newline at end of file diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json index 8403a3b4d..fcdafd017 100644 --- a/apps/terminalclock/metadata.json +++ b/apps/terminalclock/metadata.json @@ -3,12 +3,12 @@ "name": "Terminal Clock", "shortName":"Terminal Clock", "description": "A terminal cli like clock displaying multiple sensor data", - "version":"0.08", + "version":"0.09", "icon": "app.png", "type": "clock", "tags": "clock", "supports": ["BANGLEJS", "BANGLEJS2"], - "allow_emulator": true, + "allow_emulator": false, "readme": "README.md", "storage": [ {"name": "terminalclock.app.js","url": "app.js"}, diff --git a/apps/wid_a_battery_widget/metadata.json b/apps/wid_a_battery_widget/metadata.json index 6c507b7b3..017550b1e 100644 --- a/apps/wid_a_battery_widget/metadata.json +++ b/apps/wid_a_battery_widget/metadata.json @@ -9,6 +9,7 @@ "readme": "README.md", "description": "Simple and slim battery widget with charge status and percentage", "tags": "widget,battery", + "provides_widgets" : ["battery"], "storage": [ {"name":"wid_a_battery_widget.wid.js","url":"widget.js"} ] diff --git a/apps/widalarmeta/ChangeLog b/apps/widalarmeta/ChangeLog index 37b619f7f..19a19c006 100644 --- a/apps/widalarmeta/ChangeLog +++ b/apps/widalarmeta/ChangeLog @@ -2,3 +2,4 @@ 0.02: Change font to 5x9 7 segment-style Add settings page Add option to show seconds +0.03: Fix Bell not appearing on alarms > 24h and redrawing interval diff --git a/apps/widalarmeta/metadata.json b/apps/widalarmeta/metadata.json index 79387c1c5..89e35c090 100644 --- a/apps/widalarmeta/metadata.json +++ b/apps/widalarmeta/metadata.json @@ -2,7 +2,7 @@ "id": "widalarmeta", "name": "Alarm & Timer ETA", "shortName": "Alarm ETA", - "version": "0.02", + "version": "0.03", "description": "A widget that displays the time to the next Alarm or Timer in hours and minutes, maximum 24h (configurable).", "icon": "widget.png", "type": "widget", diff --git a/apps/widalarmeta/widget.js b/apps/widalarmeta/widget.js index 5d6a8bc9c..8615aa1d2 100644 --- a/apps/widalarmeta/widget.js +++ b/apps/widalarmeta/widget.js @@ -14,7 +14,7 @@ && require("sched").getTimeToAlarm(alarm) }) .filter(a => a !== undefined); - const next = Math.min.apply(null, times); + const next = times.length > 0 ? Math.min.apply(null, times) : 0; let calcWidth = 0; let drawSeconds = false; @@ -39,7 +39,7 @@ if (drawSeconds) { calcWidth += 3*5; } - } else if (times.length > 0 && config.drawBell) { + } else if (config.drawBell && alarms.some(alarm=>alarm.on&&(alarm.hidden!==true))) { // next alarm too far in future, draw only widalarm bell g.reset().drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y); calcWidth = 24; @@ -57,8 +57,13 @@ if (timeout === 0) { timeout += period; } - setTimeout(()=>{ - WIDGETS["widalarmeta"].draw(WIDGETS["widalarmeta"]); + + if (this.timeoutId !== undefined) { + clearTimeout(this.timeoutId); + } + this.timeoutId = setTimeout(()=>{ + this.timeoutId = undefined; + this.draw(); }, timeout); } /* draw */ diff --git a/apps/widbatpc/ChangeLog b/apps/widbatpc/ChangeLog index e70093659..97da2cba6 100644 --- a/apps/widbatpc/ChangeLog +++ b/apps/widbatpc/ChangeLog @@ -13,3 +13,5 @@ 0.14: Fix drawing the bar when charging 0.15: Added option to always display the icon when charging (useful if 'hide if charge greater than' is enabled) 0.16: Increase screen update rate when charging +0.17: Add option 'Remove Jitter'='Drop only' to prevent percentage from getting up again when not charging + Add option to disable vibration when charger connects diff --git a/apps/widbatpc/metadata.json b/apps/widbatpc/metadata.json index 953f8d345..cb47475cb 100644 --- a/apps/widbatpc/metadata.json +++ b/apps/widbatpc/metadata.json @@ -2,7 +2,7 @@ "id": "widbatpc", "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", - "version": "0.16", + "version": "0.17", "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", "icon": "widget.png", "type": "widget", diff --git a/apps/widbatpc/settings.js b/apps/widbatpc/settings.js index b45fc6749..c988d23bf 100644 --- a/apps/widbatpc/settings.js +++ b/apps/widbatpc/settings.js @@ -5,6 +5,7 @@ (function(back) { const SETTINGS_FILE = 'widbatpc.json' const COLORS = ['By Level', 'Green', 'Monochrome'] + const RM_JITTER_OPTIONS = [/*LANG*/'Off', /*LANG*/'Drop only']; // initialize with default settings... let s = { @@ -14,6 +15,8 @@ 'charger': true, 'hideifmorethan': 100, 'alwaysoncharge': false, + 'removejitter': 0, + 'buzzoncharge': true, } // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings @@ -28,7 +31,9 @@ return function (value) { s[key] = value; storage.write(SETTINGS_FILE, s); - WIDGETS["batpc"].reload(); + if ("WIDGETS" in global && WIDGETS["batpc"] !== undefined) { + WIDGETS["batpc"].reload(); + } } } @@ -36,17 +41,17 @@ const menu = { '': { 'title': 'Battery Widget' }, '< Back': back, - 'Percentage': { + /*LANG*/'Percentage': { value: s.percentage, format: onOffFormat, onchange: save('percentage'), }, - 'Charging Icon': { + /*LANG*/'Charging Icon': { value: s.charger, format: onOffFormat, onchange: save('charger'), }, - 'Color': { + /*LANG*/'Color': { format: () => s.color, onchange: function () { // cycles through options @@ -56,12 +61,12 @@ save('color')(s.color) } }, - 'Fill Bar': { + /*LANG*/'Fill Bar': { value: s.fillbar, format: onOffFormat, onchange: save('fillbar'), }, - 'Hide if >': { + /*LANG*/'Hide if >': { value: s.hideifmorethan||100, min: 10, max : 100, @@ -69,11 +74,22 @@ format: x => x+"%", onchange: save('hideifmorethan'), }, - 'Show on charge': { // Not sure if this is readable enough in the 'big' menu + /*LANG*/'Show on charge': { // Not sure if this is readable enough in the 'big' menu value: s.alwaysoncharge, format: onOffFormat, onchange: save('alwaysoncharge'), }, + /*LANG*/'Buzz on charge': { + value: s.buzzoncharge, + format: onOffFormat, + onchange: save('buzzoncharge'), + }, + /*LANG*/'Remove Jitter': { + value: s.removejitter, + min: 0, max: 1, + format: v => RM_JITTER_OPTIONS[v], + onchange: save('removejitter'), + }, } E.showMenu(menu) }) diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widget.js index 529923386..7f483c960 100644 --- a/apps/widbatpc/widget.js +++ b/apps/widbatpc/widget.js @@ -2,6 +2,8 @@ const intervalLow = 60000; // update time when not charging const intervalHigh = 2000; // update time when charging + let prevMin = 100; + let COLORS = {}; if (process.env.HWVERSION == 1) { @@ -33,6 +35,8 @@ 'charger': true, 'hideifmorethan': 100, 'alwaysoncharge': false, + 'removejitter': 0, // 0 == off, 1 == downwards only + 'buzzoncharge': true, }; Object.keys(DEFAULTS).forEach(k=>{ if (settings[k]===undefined) settings[k]=DEFAULTS[k]; @@ -88,8 +92,18 @@ // else... var s = 39; var x = this.x, y = this.y; - const l = E.getBattery(), - c = levelColor(l); + let l = E.getBattery(); + if (setting('removejitter') === 1) { + // if we have seen a battery percentage that was lower than current, use lower + if (Bangle.isCharging()) { + prevMin = l; // charging is the only way to increase percentage + } else if (prevMin >= l) { + prevMin = l; + } else { + l = prevMin; + } + } + const c = levelColor(l); if (Bangle.isCharging() && setting('charger')) { g.setColor(chargerColor()).drawImage(atob( @@ -148,7 +162,9 @@ } Bangle.on('charging',function(charging) { - if(charging) Bangle.buzz(); + if (setting('buzzoncharge')) { + if(charging) Bangle.buzz(); + } update(); g.flip(); });