diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog index 327b18e34..4d2e28096 100644 --- a/apps/agenda/ChangeLog +++ b/apps/agenda/ChangeLog @@ -18,3 +18,4 @@ 0.16: Correct date for all day events in negative timezones, improve locale display 0.17: Fixed "Today" and "Tomorrow" labels displaying in non-current weeks 0.18: Correct date in clockinfo for all-day events in negative timezones +0.19: Change clockinfo title truncation to preserve images diff --git a/apps/agenda/agenda.clkinfo.js b/apps/agenda/agenda.clkinfo.js index fe56257b0..07c48e751 100644 --- a/apps/agenda/agenda.clkinfo.js +++ b/apps/agenda/agenda.clkinfo.js @@ -64,7 +64,7 @@ agenda.forEach((entry, i) => { - var title = entry.title.slice(0,12); + var title = g.setFont("6x8").wrapString(entry.title,100)[0]; // All day events are always in UTC and always start at 00:00:00, so we // need to "undo" the timezone offsetting to make sure that the day is // correct. diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index b841ecaff..bfa529ea5 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "0.18", + "version": "0.19", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], diff --git a/apps/altimeter/ChangeLog b/apps/altimeter/ChangeLog index 905152382..77f64d029 100644 --- a/apps/altimeter/ChangeLog +++ b/apps/altimeter/ChangeLog @@ -2,3 +2,4 @@ 0.02: Actually upload correct code 0.03: Display sea-level pressure, too, and allow calibration 0.04: Switch to using system code for pressure calibration +0.05: Prompt before resetting calibration (stops long-press of button resetting calibration) \ No newline at end of file diff --git a/apps/altimeter/app.js b/apps/altimeter/app.js index 6e44161da..222ed2d21 100644 --- a/apps/altimeter/app.js +++ b/apps/altimeter/app.js @@ -7,6 +7,7 @@ var R = Bangle.appRect; var y = R.y + R.h/2; var MEDIANLENGTH = 20; var avr = []; +var updateDisplay = true; function fmt(t) { if ((t > -100) && (t < 1000)) @@ -19,48 +20,57 @@ function fmt(t) { Bangle.on('pressure', function(e) { while (avr.length>MEDIANLENGTH) avr.pop(); avr.unshift(e.altitude); - let median = avr.slice().sort(); + if (!updateDisplay) return; + let median = avr.slice().sort(), value; g.reset().clearRect(0,y-30,g.getWidth()-10,R.h); if (median.length>10) { var mid = median.length>>1; - var value = E.sum(median.slice(mid-4,mid+5)) / 9; + value = E.sum(median.slice(mid-4,mid+5)) / 9; } else { - var value = median[median.length>>1]; + value = median[median.length>>1]; } - t = fmt(value); + var t = fmt(value); g.setFont("Vector",50).setFontAlign(0,0).drawString(t, g.getWidth()/2, y); let o = Bangle.getOptions(); let sea = o.seaLevelPressure; t = sea.toFixed(1) + " " + e.temperature.toFixed(1); - if (0) { + /*if (0) { print("alt raw:", value.toFixed(1)); print("temperature:", e.temperature); print("pressure:", e.pressure); print("sea pressure:", sea); - } + }*/ g.setFont("Vector",25).setFontAlign(-1,0).drawString(t, 10, R.y+R.h - 35); }); function setPressure(m, a) { - o = Bangle.getOptions(); - print(o); + var o = Bangle.getOptions(); + //print(o); o.seaLevelPressure = o.seaLevelPressure * m + a; Bangle.setOptions(o); avr = []; } -print(g.getFonts()); -g.reset(); -g.setFont("Vector:15"); -g.setFontAlign(0,0); -g.drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40); -g.drawString(/*LANG*/"SEA L (hPa) TEMP (C)", g.getWidth()/2, y+62); -g.flip(); -g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"STD", g.getWidth()-5, g.getHeight()/2); -Bangle.setUI("updown", btn=> { - if (!btn) setPressure(0, 1013.25); - if (btn<0) setPressure(1, 1); - if (btn>0) setPressure(1, -1); -}); +function start() { + g.reset(); + g.setFont("Vector:15"); + g.setFontAlign(0,0); + g.drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40); + g.drawString(/*LANG*/"SEA L (hPa) TEMP (C)", g.getWidth()/2, y+62); + g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"STD", g.getWidth()-5, g.getHeight()/2); + updateDisplay = true; + Bangle.setUI("updown", btn => { + if (!btn) { + updateDisplay = false; + E.showPrompt(/*LANG*/"Set calibration to default?",{title:/*LANG*/"Altitude"}).then(function(reset) { + start(); + if (reset) setPressure(0, 1013.25); + }); + } + if (btn<0) setPressure(1, 1); + if (btn>0) setPressure(1, -1); + }); +} +start(); \ No newline at end of file diff --git a/apps/altimeter/metadata.json b/apps/altimeter/metadata.json index ff5eb9935..2c8bf06ec 100644 --- a/apps/altimeter/metadata.json +++ b/apps/altimeter/metadata.json @@ -1,6 +1,6 @@ { "id": "altimeter", "name": "Altimeter", - "version":"0.04", + "version":"0.05", "description": "Simple altimeter that can display height changed using Bangle.js 2's built in pressure sensor.", "icon": "app.png", "tags": "tool,outdoors", diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 5b0fcc583..fa1967d11 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -75,4 +75,5 @@ 0.64: Automatically create .widcache and .clkinfocache to speed up loads Bangle.loadWidgets overwritten with fast version on success Refuse to work on firmware <2v16 and remove old polyfills -0.65: Only display interpreter errors if log is nonzero \ No newline at end of file +0.65: Only display interpreter errors if log is nonzero +0.66: Ensure __FILE__ is set even after a fresh boot (fix #3857) \ No newline at end of file diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index 6e6466f48..8228ab482 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -23,7 +23,8 @@ if (!_clkApp) { require("Storage").writeJSON("setting.json", s); } } +if (s.clock) __FILE__=s.clock; delete s; if (!_clkApp) _clkApp=`E.showMessage("No Clock Found");setWatch(()=>{Bangle.showLauncher();}, global.BTN2||BTN, {repeat:false,edge:"falling"});`; eval(_clkApp); -delete _clkApp; +delete _clkApp; \ No newline at end of file diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index afe576e71..93d699c15 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -1,7 +1,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.65", + "version": "0.66", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", diff --git a/apps/chargeanim/ChangeLog b/apps/chargeanim/ChangeLog index a7262b0c9..42e2cc260 100644 --- a/apps/chargeanim/ChangeLog +++ b/apps/chargeanim/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Bangle.js 2 compatibility +0.03: Add settings menu for showing time and battery percent with animation. diff --git a/apps/chargeanim/Screenshot1.png b/apps/chargeanim/Screenshot1.png new file mode 100644 index 000000000..047ab2ca6 Binary files /dev/null and b/apps/chargeanim/Screenshot1.png differ diff --git a/apps/chargeanim/Screenshot2.png b/apps/chargeanim/Screenshot2.png new file mode 100644 index 000000000..ba6b543fe Binary files /dev/null and b/apps/chargeanim/Screenshot2.png differ diff --git a/apps/chargeanim/Screenshot3.png b/apps/chargeanim/Screenshot3.png new file mode 100644 index 000000000..d1c6bcb0b Binary files /dev/null and b/apps/chargeanim/Screenshot3.png differ diff --git a/apps/chargeanim/app.js b/apps/chargeanim/app.js index 68d0cdff5..8913bda4a 100644 --- a/apps/chargeanim/app.js +++ b/apps/chargeanim/app.js @@ -1,8 +1,19 @@ + +var settings = Object.assign({ + // default values + showBatPercent: true, + showTime: true, + + + }, require("Storage").readJSON("chargeAnimSettings.json", true) || {}); + + g.setBgColor(0, 0, 0); g.clear().flip(); var imgbat = require("heatshrink").decompress(atob("nFYhBC/AH4A/AGUeACA22HEo3/G8YrTAC422HBQ2tHBI3/G/43/G/43/G/43/G/43/G/43/G+fTG+vSN+w326Q31GwI3/G9g2WG742CG/43rGwY3yGwg33RKo3bNzQ3bGwo3/G9A2GG942dG/43QGw43uGxA34IKw3VGyY3iG0I3pb8pBRG+wYPG8wYQG/42uG8oZSG/43bDKY3iDKg3cNzI3iRKo3gGyo3/G7A2WG7g2aG/43WGzA3dGzI3/G6fTGzRvcG/43/G/43/G/43/G/43/G/43/G/437HFw2IHFo2KAH4A/AH4Aa")); var imgbubble = require("heatshrink").decompress(atob("i0UhAebgoAFCaYXNBocjAAIWNCYoVHCw4UFIZwqELJQWFKZQVOChYVzABwVaCx7wKCqIWNCg4WMChIXJCZgAnA==")); - +require("Font8x12").add(Graphics); +var batteryPercentStr=""; var W=g.getWidth(),H=g.getHeight(); var b2v = (W != 240)?-1:1; var b2rot = (W != 240)?Math.PI:0; @@ -12,11 +23,50 @@ for (var i=0;i<10;i++) { bubbles.push({y:Math.random()*H,ly:0,x:(0.5+(i<5?i:i+8))*W/18,v:0.6+Math.random(),s:0.5+Math.random()}); } +g.setFont("Vector",22); +g.setFontAlign(0,0); + +var clockStr=""; +var x=g.getWidth()/2; +var cy=g.getHeight()-(g.getHeight()/7) +var by=g.getHeight()-(g.getHeight()/3.500) + + +function calculateTime(){ + + var d=new Date(); + clockStr = require("locale").time(d, 1); // Hour and minute + var meridian=require("locale").meridian(d); + if(meridian!=""){ + //Meridian active + clockStr=clockStr+" "+meridian; + } + +} +function calculate(){ + if(settings.showTime==true){ + calculateTime(); + } + if(settings.showBatPercent==true){ + batteryPercentStr=E.getBattery()+"%"; + } + + +} + function anim() { /* we don't use any kind of buffering here. Just draw one image at a time (image contains a background) too, and there is minimal flicker. */ - var mx = W/2.0, my = H/2.0; + var mx = W/2.0; + var my; + if(settings.showBatPercent){ + var my = H/2.5; + }else{ + var my = H/2.0; + } + + bubbles.forEach(f=>{ f.y-=f.v * b2v; if (f.y<-24) @@ -26,10 +76,25 @@ function anim() { g.drawImage(imgbubble,f.y,f.x,{scale:f.s * b2scale, rotate:b2rot}); }); g.drawImage(imgbat, mx,my,{scale:b2scale, rotate:Math.sin(getTime()*2)*0.5-Math.PI/2 + b2rot}); + if(settings.showTime==true){ + g.drawString(clockStr,x,cy); + } + if(settings.showBatPercent==true){ + g.drawString(batteryPercentStr,x,by,true); + } g.flip(); + + +} + +if(settings.showBatPercent||settings.showTime){ + //Eliminate unnesccesary need for calculation + calculate(); + setInterval(calculate,20000); } -setInterval(anim,20); +setInterval(anim,22); + Bangle.on("charging", isCharging => { if (!isCharging) load(); diff --git a/apps/chargeanim/bangle-charge-animation-screenshot.png b/apps/chargeanim/bangle-charge-animation-screenshot.png deleted file mode 100644 index 83ef1dbda..000000000 Binary files a/apps/chargeanim/bangle-charge-animation-screenshot.png and /dev/null differ diff --git a/apps/chargeanim/bangle2-charge-animation-screenshot.png b/apps/chargeanim/bangle2-charge-animation-screenshot.png deleted file mode 100644 index c3fb7c8c8..000000000 Binary files a/apps/chargeanim/bangle2-charge-animation-screenshot.png and /dev/null differ diff --git a/apps/chargeanim/metadata.json b/apps/chargeanim/metadata.json index 05d894e00..d8c5fa18f 100644 --- a/apps/chargeanim/metadata.json +++ b/apps/chargeanim/metadata.json @@ -1,16 +1,21 @@ { "id": "chargeanim", "name": "Charge Animation", - "version": "0.02", - "description": "When charging, show a sideways charging animation and keep the screen on. When removed from the charger load the clock again.", + "version": "0.03", + "description": "When charging, show a sideways charging animation and optionally, show time, or show battery percentage. When removed from the charger, clock loads again.", "icon": "icon.png", "tags": "battery", "supports": ["BANGLEJS", "BANGLEJS2"], "allow_emulator": true, - "screenshots": [{"url":"bangle2-charge-animation-screenshot.png"},{"url":"bangle-charge-animation-screenshot.png"}], + "screenshots": [ + {"url":"Screenshot1.png"}, + {"url":"Screenshot2.png"}, + {"url":"Screenshot3.png"}], "storage": [ {"name":"chargeanim.app.js","url":"app.js"}, {"name":"chargeanim.boot.js","url":"boot.js"}, + {"name":"chargeanim.settings.js","url":"settings.js"}, {"name":"chargeanim.img","url":"app-icon.js","evaluate":true} - ] + ], + "data": [{"name":"chargeAnimSettings.json"}] } diff --git a/apps/chargeanim/settings.js b/apps/chargeanim/settings.js new file mode 100644 index 000000000..39fc2333b --- /dev/null +++ b/apps/chargeanim/settings.js @@ -0,0 +1,44 @@ +(function(back) { + var FILE = "chargeAnimSettings.json"; + // Load settings + + var settings = Object.assign({ + // default values + showBatPercent: true, + showTime: true, + + + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + // Show the menu + E.showMenu({ + "" : { "title" : "Charge Animation" }, + "< Back" : () => back(), + 'Show Percent Charged': { + value: !!settings.showBatPercent, // !! converts undefined to false + onchange: v => { + settings.showBatPercent = v; + writeSettings(); + } + // format: ... may be specified as a function which converts the value to a string + // if the value is a boolean, showMenu() will convert this automatically, which + // keeps settings menus consistent + }, + 'Show Time': { + value: !!settings.showTime, // !! converts undefined to false + onchange: v => { + settings.showTime = v; + writeSettings(); + } + // format: ... may be specified as a function which converts the value to a string + // if the value is a boolean, showMenu() will convert this automatically, which + // keeps settings menus consistent + } + + + }); +}) diff --git a/apps/clock_info/ChangeLog b/apps/clock_info/ChangeLog index 49227c76d..963c2bb35 100644 --- a/apps/clock_info/ChangeLog +++ b/apps/clock_info/ChangeLog @@ -15,3 +15,4 @@ 0.14: Check for .clkinfocache and use that if exists (from boot 0.64) 0.15: Fix error when displaying a category with only one clockinfo (fix #3728) 0.16: Add BLE clkinfo entry +0.17: Fix BLE icon alignment and border on some clocks diff --git a/apps/clock_info/lib.js b/apps/clock_info/lib.js index 9fdacab55..b58e73089 100644 --- a/apps/clock_info/lib.js +++ b/apps/clock_info/lib.js @@ -128,7 +128,7 @@ exports.load = function() { get: function() { return { text: this.isOn() ? "On" : "Off", - img: atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==") + img: atob("GBiBAAAAAAAAAAAYAAAcAAAWAAATAAARgAMRgAGTAADWAAB8AAA4AAA4AAB8AADWAAGTAAMRgAARgAATAAAWAAAcAAAYAAAAAAAAAA==") }; }, run: function() { diff --git a/apps/clock_info/metadata.json b/apps/clock_info/metadata.json index 3876258b8..4a14b5348 100644 --- a/apps/clock_info/metadata.json +++ b/apps/clock_info/metadata.json @@ -1,7 +1,7 @@ { "id": "clock_info", "name": "Clock Info Module", "shortName": "Clock Info", - "version":"0.16", + "version":"0.17", "description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)", "icon": "app.png", "type": "module", diff --git a/apps/crsclock/README.md b/apps/crsclock/README.md index 17302cce0..0f3039994 100644 --- a/apps/crsclock/README.md +++ b/apps/crsclock/README.md @@ -113,6 +113,8 @@ Unless otherwise stated, this project is released under the MIT license. Use of the patented method may be subject to licensing or permission. For inquiries, contact the author. +Note: The patented method does not require licensing for non-commercial, research, educational, or personal use within the open-source community. Commercial or broad distribution beyond these uses may require permission or licensing. For such use cases, please contact the author. + ### **Summary** The Circadian Rhythm Clock transforms the Bangle.js 2 into a **bio-aware, personalized circadian dashboard**, guiding users toward better alignment with their biological clock and modern life. diff --git a/apps/crsclock/crsclock.js b/apps/crsclock/crsclock.js index 5a7c1bf9d..87de4aac5 100644 --- a/apps/crsclock/crsclock.js +++ b/apps/crsclock/crsclock.js @@ -83,7 +83,7 @@ const STATS_FONT_SIZE = 16; function getSleepWindowStr() { let a = ("0"+S.sleepStart).substr(-2) + ":00"; let b = ("0"+S.sleepEnd).substr(-2) + ":00"; - return a + "–" + b; + return a + "-" + b; } function stability(arr, key, hours) { @@ -518,7 +518,7 @@ function confirmResetAllData() { }); } -// Menu logic: Sleep window, hydration, BT calibration, theme, notifications, bio ref, about — unchanged, use as before +// Menu logic: Sleep window, hydration, BT calibration, theme, notifications, bio ref, about - unchanged, use as before function setSleepWindow() { let menu = { "": { title: "Select Start Hour" } }; @@ -610,7 +610,7 @@ function calibrateBT() { Bangle.setUI(uiOpts); }); })(d); - m["−" + d + "h"] = (() => () => { + m["-" + d + "h"] = (() => () => { S.phaseOffset -= d; saveSettings(); E.showAlert("Offset now: " + (S.phaseOffset>=0? "+"+S.phaseOffset : S.phaseOffset) + "h").then(() => { @@ -711,7 +711,7 @@ function setBioTimeReference() { E.showMenu(m); function promptRefTime() { - E.showPrompt("Hour (0–23)?").then(h => { + E.showPrompt("Hour (0-23)?").then(h => { if (h===undefined || h<0 || h>23) { E.showAlert("Invalid hour").then(() => { drawClock(); @@ -720,7 +720,7 @@ function setBioTimeReference() { return; } S.bioTimeRefHour = h; - E.showPrompt("Minute (0–59)?").then(m => { + E.showPrompt("Minute (0-59)?").then(m => { if (m===undefined || m<0 || m>59) { E.showAlert("Invalid minute").then(() => { drawClock(); @@ -743,7 +743,7 @@ function showAbout() { E.showAlert( "Circadian Wellness Clock v" + VERSION + "\n" + "Displays your CRS and BioTime.\n" + - "© 2025" + "Copyright 2025" ).then(()=>{ drawClock(); Bangle.setUI(uiOpts); diff --git a/apps/ios/ChangeLog b/apps/ios/ChangeLog index 904ad1f7d..f16ff9af6 100644 --- a/apps/ios/ChangeLog +++ b/apps/ios/ChangeLog @@ -16,4 +16,5 @@ 0.15: Enable calendar and weather updates via custom notifications (via shortcuts app) 0.16: Always request Current Time service from iOS 0.17: Default to passing full UTF8 strings into messages app (which can now process them with an international font) -0.18: Fix UTF8 conversion (check for `font` library, not `fonts`) \ No newline at end of file +0.18: Fix UTF8 conversion (check for `font` library, not `fonts`) +0.19: Convert numeric weather values to int from BangleDumpWeather shortcut \ No newline at end of file diff --git a/apps/ios/boot.js b/apps/ios/boot.js index fe9cde77d..1054a735f 100644 --- a/apps/ios/boot.js +++ b/apps/ios/boot.js @@ -191,6 +191,11 @@ E.on('notify',msg=>{ wdir: d.wdir, loc: d.loc } + // Convert string fields to numbers for iOS weather shortcut + const numFields = ['code', 'wdir', 'temp', 'hi', 'lo', 'hum', 'wind', 'uv', 'rain']; + numFields.forEach(field => { + if (weatherEvent[field] != null) weatherEvent[field] = +weatherEvent[field]; + }); require("weather").update(weatherEvent); NRF.ancsAction(msg.uid, false); return; diff --git a/apps/ios/metadata.json b/apps/ios/metadata.json index 6efcac15e..03b116640 100644 --- a/apps/ios/metadata.json +++ b/apps/ios/metadata.json @@ -1,7 +1,7 @@ { "id": "ios", "name": "iOS Integration", - "version": "0.18", + "version": "0.19", "description": "Display notifications/music/etc from iOS devices", "icon": "app.png", "tags": "tool,system,ios,apple,messages,notifications", diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 6b64d6149..980164b09 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -925,12 +925,6 @@ module.exports = { "no-undef" ] }, - "apps/fileman/fileman.app.js": { - "hash": "f378179e7dd3655ba7e9ce03e1f7fd5a2d1768ad7d9083b22e7d740405be842a", - "rules": [ - "no-undef" - ] - }, "apps/flappy/app.js": { "hash": "e24b0c5e0469070e02dae00887bf50569c2c141a80c7c356b36987ddf68ce9cc", "rules": [ @@ -1051,12 +1045,6 @@ module.exports = { "no-undef" ] }, - "apps/altimeter/app.js": { - "hash": "054ac328db51034aa339f1d10b4d264badd49438b95f08bc6fbfb90bd88c6ae0", - "rules": [ - "no-undef" - ] - }, "apps/alpinenav/app.js": { "hash": "f8e59724d282f7c5c989adf64974a3728dc521aa8fbe047b7c37dae09213095a", "rules": [ diff --git a/apps/messageicons/ChangeLog b/apps/messageicons/ChangeLog index ede169914..7bb8d1f70 100644 --- a/apps/messageicons/ChangeLog +++ b/apps/messageicons/ChangeLog @@ -6,4 +6,5 @@ 0.05: Add message icon for 'jira' 0.06: Add message icon for 'molly' and 'threema libre' 0.07: Minor code improvements -0.08: Add more icons including GMail, Google Messages, Google Agenda \ No newline at end of file +0.08: Add more icons including GMail, Google Messages, Google Agenda +0.09: Add Bereal, Nextcloud, Thunderbird, Davx⁵, Kleinanzeigen, Element X diff --git a/apps/messageicons/icons.img b/apps/messageicons/icons.img index bb74d05d9..39bb2339d 100644 Binary files a/apps/messageicons/icons.img and b/apps/messageicons/icons.img differ diff --git a/apps/messageicons/icons/bereal.png b/apps/messageicons/icons/bereal.png new file mode 100644 index 000000000..172c8228d Binary files /dev/null and b/apps/messageicons/icons/bereal.png differ diff --git a/apps/messageicons/icons/generate.js b/apps/messageicons/icons/generate.js index a07b7af44..c69e6d007 100755 --- a/apps/messageicons/icons/generate.js +++ b/apps/messageicons/icons/generate.js @@ -102,6 +102,7 @@ exports.getColor = function(msg,options) { */""} "bibel": "#54342c", "bring": "#455a64", + "davx⁵": "#8bc34a", "discord": "#5865f2", // https://discord.com/branding "etar": "#36a18b", "facebook": "#1877f2", // https://www.facebook.com/brand/resources/facebookapp/logo @@ -111,7 +112,8 @@ exports.getColor = function(msg,options) { "google home": "#fbbc05", // "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background "instagram": "#ff0069", // https://about.instagram.com/brand/gradient - "jira": "#0052cc", //https://atlassian.design/resources/logo-library + "jira": "#0052cc", // https://atlassian.design/resources/logo-library + "kleinanzeigen": "#69bd2f", // https://themen.kleinanzeigen.de/medien/mediathek/kleinanzeigen-guideline-nutzung-logo/ "leboncoin": "#fa7321", "lieferando": "#ff8000", "linkedin": "#0a66c2", // https://brand.linkedin.com/ @@ -121,6 +123,7 @@ exports.getColor = function(msg,options) { "mattermost": "#00f", "n26": "#36a18b", "nextbike": "#00f", + "nextcloud": "#0082c9", // https://nextcloud.com/brand/ "newpipe": "#f00", "nina": "#e57004", "opentasks": "#409f8f", @@ -137,6 +140,7 @@ exports.getColor = function(msg,options) { "teams": "#6264a7", // https://developer.microsoft.com/en-us/fluentui#/styles/web/colors/products "telegram": "#0088cc", "telegram foss": "#0088cc", + "thunderbird": "#1582e4", "to do": "#3999e5", "twitch": "#9146ff", // https://brand.twitch.tv/ "twitter": "#1d9bf0", // https://about.twitter.com/en/who-we-are/brand-toolkit diff --git a/apps/messageicons/icons/icon_names.json b/apps/messageicons/icons/icon_names.json index 89f81be08..63866b355 100644 --- a/apps/messageicons/icons/icon_names.json +++ b/apps/messageicons/icons/icon_names.json @@ -3,38 +3,41 @@ { "app":"airbnb", "icon":"airbnb.png" }, { "app":"agenda", "icon":"agenda.png" }, { "app":"alarm", "icon":"alarm.png" }, - { "app":"alarmclockreceiver", "icon":"alarm.png" }, + { "app":"alarmclockreceiver", "icon":"alarm.png" }, { "app":"amazon shopping", "icon":"amazon.png" }, + { "app":"bereal.", "icon":"bereal.png" }, { "app":"bibel", "icon":"bibel.png" }, { "app":"bitwarden", "icon":"security.png" }, - { "app":"1password", "icon":"security.png" }, - { "app":"lastpass", "icon":"security.png" }, - { "app":"dashlane", "icon":"security.png" }, + { "app":"1password", "icon":"security.png" }, + { "app":"lastpass", "icon":"security.png" }, + { "app":"dashlane", "icon":"security.png" }, { "app":"bring", "icon":"bring.png" }, { "app":"calendar", "icon":"etar.png" }, - { "app":"etar", "icon":"etar.png" }, + { "app":"etar", "icon":"etar.png" }, { "app":"chat", "icon":"google chat.png" }, { "app":"chrome", "icon":"chrome.png" }, { "app":"clock", "icon":"alarm.png" }, { "app":"corona-warn", "icon":"coronavirus.png" }, { "app":"bmo", "icon":"bank.png" }, - { "app":"desjardins", "icon":"bank.png" }, - { "app":"rbc mobile", "icon":"bank.png" }, - { "app":"nbc", "icon":"bank.png" }, - { "app":"rabobank", "icon":"bank.png" }, - { "app":"scotiabank", "icon":"bank.png" }, - { "app":"td (canada)", "icon":"bank.png" }, + { "app":"desjardins", "icon":"bank.png" }, + { "app":"rbc mobile", "icon":"bank.png" }, + { "app":"nbc", "icon":"bank.png" }, + { "app":"rabobank", "icon":"bank.png" }, + { "app":"scotiabank", "icon":"bank.png" }, + { "app":"td (canada)", "icon":"bank.png" }, + { "app":"davx⁵", "icon":"sync.png" }, { "app":"discord", "icon":"discord.png" }, { "app":"drive", "icon":"google drive.png" }, { "app":"element", "icon":"matrix element.png" }, + { "app":"element x", "icon":"matrix element.png" }, { "app":"facebook", "icon":"facebook.png" }, { "app":"messenger", "icon":"facebook messenger.png" }, { "app":"firefox", "icon":"firefox.png" }, - { "app":"firefox beta", "icon":"firefox.png" }, - { "app":"firefox nightly", "icon":"firefox.png" }, + { "app":"firefox beta", "icon":"firefox.png" }, + { "app":"firefox nightly", "icon":"firefox.png" }, { "app":"f-droid", "icon":"security.png" }, - { "app":"neo store", "icon":"security.png" }, - { "app":"aurora droid", "icon":"security.png" }, + { "app":"neo store", "icon":"security.png" }, + { "app":"aurora droid", "icon":"security.png" }, { "app":"github", "icon":"github.png" }, { "app":"gitlab", "icon":"gitlab.png" }, { "app":"gmail", "icon":"gmail.png" }, @@ -47,28 +50,30 @@ { "app":"jira", "icon":"jira.png" }, { "app":"kalender", "icon":"kalender.png" }, { "app":"keep notes", "icon":"google keep.png" }, + { "app":"kleinanzeigen", "icon":"kleinanzeigen.png" }, { "app":"leboncoin", "icon":"leboncoin.png" }, { "app":"lieferando", "icon":"lieferando.png" }, { "app":"linkedin", "icon":"linkedin.png" }, { "app":"maps", "icon":"map.png" }, - { "app":"organic maps", "icon":"map.png" }, - { "app":"osmand", "icon":"map.png" }, + { "app":"organic maps", "icon":"map.png" }, + { "app":"osmand", "icon":"map.png" }, { "app":"mastodon", "icon":"mastodon.png" }, - { "app":"fedilab", "icon":"mastodon.png" }, - { "app":"tooot", "icon":"mastodon.png" }, - { "app":"tusky", "icon":"mastodon.png" }, + { "app":"fedilab", "icon":"mastodon.png" }, + { "app":"tooot", "icon":"mastodon.png" }, + { "app":"tusky", "icon":"mastodon.png" }, { "app":"mattermost", "icon":"mattermost.png" }, { "app":"messages", "icon":"messages.png" }, { "app":"n26", "icon":"n26.png" }, { "app":"netflix", "icon":"netflix.png" }, { "app":"news", "icon":"news.png" }, - { "app":"cbc news", "icon":"news.png" }, - { "app":"rc info", "icon":"news.png" }, - { "app":"reuters", "icon":"news.png" }, - { "app":"ap news", "icon":"news.png" }, - { "app":"la presse", "icon":"news.png" }, - { "app":"nbc news", "icon":"news.png" }, + { "app":"cbc news", "icon":"news.png" }, + { "app":"rc info", "icon":"news.png" }, + { "app":"reuters", "icon":"news.png" }, + { "app":"ap news", "icon":"news.png" }, + { "app":"la presse", "icon":"news.png" }, + { "app":"nbc news", "icon":"news.png" }, { "app":"nextbike", "icon":"nextbike.png" }, + { "app":"nextcloud", "icon":"nextcloud.png" }, { "app":"nina", "icon":"nina.png" }, { "app":"outlook mail", "icon":"outlook.png" }, { "app":"paypal", "icon":"paypal.png" }, @@ -78,11 +83,11 @@ { "app":"post & dhl", "icon":"delivery.png" }, { "app":"proton mail", "icon":"protonmail.png" }, { "app":"reddit", "icon":"reddit.png" }, - { "app":"sync pro", "icon":"reddit.png" }, - { "app":"sync dev", "icon":"reddit.png" }, - { "app":"boost", "icon":"reddit.png" }, - { "app":"infinity", "icon":"reddit.png" }, - { "app":"slide", "icon":"reddit.png" }, + { "app":"sync pro", "icon":"reddit.png" }, + { "app":"sync dev", "icon":"reddit.png" }, + { "app":"boost", "icon":"reddit.png" }, + { "app":"infinity", "icon":"reddit.png" }, + { "app":"slide", "icon":"reddit.png" }, { "app":"signal", "icon":"signal.png" }, { "app":"molly", "icon":"signal.png" }, { "app":"skype", "icon":"skype.png" }, @@ -92,27 +97,28 @@ { "app":"steam", "icon":"steam.png" }, { "app":"teams", "icon":"teams.png" }, { "app":"telegram", "icon":"telegram.png" }, - { "app":"telegram foss", "icon":"telegram.png" }, + { "app":"telegram foss", "icon":"telegram.png" }, { "app":"threema", "icon":"threema.png" }, { "app":"threema libre", "icon":"threema.png" }, + { "app":"thunderbird", "icon":"mail.png" }, { "app":"tiktok", "icon":"tiktok.png" }, { "app":"to do", "icon":"task.png" }, - { "app":"opentasks", "icon":"task.png" }, - { "app":"tasks", "icon":"task.png" }, + { "app":"opentasks", "icon":"task.png" }, + { "app":"tasks", "icon":"task.png" }, { "app":"transit", "icon":"transit.png" }, { "app":"twitch", "icon":"twitch.png" }, { "app":"twitter", "icon":"twitter.png" }, { "app":"uber", "icon":"taxi.png" }, - { "app":"lyft", "icon":"taxi.png" }, + { "app":"lyft", "icon":"taxi.png" }, { "app":"vlc", "icon":"vlc.png" }, { "app":"warnapp", "icon":"warnapp.png" }, { "app":"whatsapp", "icon":"whatsapp.png" }, { "app":"wordfeud", "icon":"wordfeud.png" }, { "app":"youtube", "icon":"youtube.png" }, - { "app":"newpipe", "icon":"youtube.png" }, + { "app":"newpipe", "icon":"youtube.png" }, { "app":"zoom", "icon":"videoconf.png" }, - { "app":"meet", "icon":"videoconf.png" }, + { "app":"meet", "icon":"videoconf.png" }, { "app":"music", "icon":"music.png" }, { "app":"sms message", "icon":"default.png" }, - { "app":"mail", "icon":"default.png" } + { "app":"mail", "icon":"default.png" } ] diff --git a/apps/messageicons/icons/kleinanzeigen.png b/apps/messageicons/icons/kleinanzeigen.png new file mode 100644 index 000000000..bffee2e3a Binary files /dev/null and b/apps/messageicons/icons/kleinanzeigen.png differ diff --git a/apps/messageicons/icons/nextcloud.png b/apps/messageicons/icons/nextcloud.png new file mode 100644 index 000000000..1b0d8a32d Binary files /dev/null and b/apps/messageicons/icons/nextcloud.png differ diff --git a/apps/messageicons/icons/sync.png b/apps/messageicons/icons/sync.png new file mode 100644 index 000000000..8193cffe2 Binary files /dev/null and b/apps/messageicons/icons/sync.png differ diff --git a/apps/messageicons/lib.js b/apps/messageicons/lib.js index 9c070a03e..7e0c94f2d 100644 --- a/apps/messageicons/lib.js +++ b/apps/messageicons/lib.js @@ -4,7 +4,7 @@ exports.getImage = function(msg) { if (msg.img) return atob(msg.img); let s = (("string"=== typeof msg) ? msg : (msg.src || "")).toLowerCase(); if (msg.id=="music") s="music"; - let match = ",default|0,airbnb|1,agenda|2,alarm|3,alarmclockreceiver|3,amazon shopping|4,bibel|5,bitwarden|6,1password|6,lastpass|6,dashlane|6,bring|7,calendar|8,etar|8,chat|9,chrome|10,clock|3,corona-warn|11,bmo|12,desjardins|12,rbc mobile|12,nbc|12,rabobank|12,scotiabank|12,td (canada)|12,discord|13,drive|14,element|15,facebook|16,messenger|17,firefox|18,firefox beta|18,firefox nightly|18,f-droid|6,neo store|6,aurora droid|6,github|19,gitlab|20,gmail|21,gmx|22,google|23,google home|24,google play store|25,home assistant|26,instagram|27,jira|28,kalender|29,keep notes|30,leboncoin|31,lieferando|32,linkedin|33,maps|34,organic maps|34,osmand|34,mastodon|35,fedilab|35,tooot|35,tusky|35,mattermost|36,messages|37,n26|38,netflix|39,news|40,cbc news|40,rc info|40,reuters|40,ap news|40,la presse|40,nbc news|40,nextbike|41,nina|42,outlook mail|43,paypal|44,phone|45,plex|46,pocket|47,post & dhl|48,proton mail|49,reddit|50,sync pro|50,sync dev|50,boost|50,infinity|50,slide|50,signal|51,molly|51,skype|52,slack|53,snapchat|54,starbucks|55,steam|56,teams|57,telegram|58,telegram foss|58,threema|59,threema libre|59,tiktok|60,to do|61,opentasks|61,tasks|61,transit|62,twitch|63,twitter|64,uber|65,lyft|65,vlc|66,warnapp|67,whatsapp|68,wordfeud|69,youtube|70,newpipe|70,zoom|71,meet|71,music|72,sms message|0,mail|0,".match(new RegExp(`,${s}\\|(\\d+)`)) + let match = ",default|0,airbnb|1,agenda|2,alarm|3,alarmclockreceiver|3,amazon shopping|4,bereal.|5,bibel|6,bitwarden|7,1password|7,lastpass|7,dashlane|7,bring|8,calendar|9,etar|9,chat|10,chrome|11,clock|3,corona-warn|12,bmo|13,desjardins|13,rbc mobile|13,nbc|13,rabobank|13,scotiabank|13,td (canada)|13,davx⁵|14,discord|15,drive|16,element|17,element x|17,facebook|18,messenger|19,firefox|20,firefox beta|20,firefox nightly|20,f-droid|7,neo store|7,aurora droid|7,github|21,gitlab|22,gmail|23,gmx|24,google|25,google home|26,google play store|27,home assistant|28,instagram|29,jira|30,kalender|31,keep notes|32,kleinanzeigen|33,leboncoin|34,lieferando|35,linkedin|36,maps|37,organic maps|37,osmand|37,mastodon|38,fedilab|38,tooot|38,tusky|38,mattermost|39,messages|40,n26|41,netflix|42,news|43,cbc news|43,rc info|43,reuters|43,ap news|43,la presse|43,nbc news|43,nextbike|44,nextcloud|45,nina|46,outlook mail|47,paypal|48,phone|49,plex|50,pocket|51,post & dhl|52,proton mail|53,reddit|54,sync pro|54,sync dev|54,boost|54,infinity|54,slide|54,signal|55,molly|55,skype|56,slack|57,snapchat|58,starbucks|59,steam|60,teams|61,telegram|62,telegram foss|62,threema|63,threema libre|63,thunderbird|64,tiktok|65,to do|66,opentasks|66,tasks|66,transit|67,twitch|68,twitter|69,uber|70,lyft|70,vlc|71,warnapp|72,whatsapp|73,wordfeud|74,youtube|75,newpipe|75,zoom|76,meet|76,music|77,sms message|0,mail|0,".match(new RegExp(`,${s}\\|(\\d+)`)) return require("Storage").read("messageicons.img", (match===null)?0:match[1]*76, 76); }; @@ -24,6 +24,7 @@ exports.getColor = function(msg,options) { "sms message": "#0ff", "bibel": "#54342c", "bring": "#455a64", + "davx⁵": "#8bc34a", "discord": "#5865f2", // https://discord.com/branding "etar": "#36a18b", "facebook": "#1877f2", // https://www.facebook.com/brand/resources/facebookapp/logo @@ -33,7 +34,8 @@ exports.getColor = function(msg,options) { "google home": "#fbbc05", // "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background "instagram": "#ff0069", // https://about.instagram.com/brand/gradient - "jira": "#0052cc", //https://atlassian.design/resources/logo-library + "jira": "#0052cc", // https://atlassian.design/resources/logo-library + "kleinanzeigen": "#69bd2f", // https://themen.kleinanzeigen.de/medien/mediathek/kleinanzeigen-guideline-nutzung-logo/ "leboncoin": "#fa7321", "lieferando": "#ff8000", "linkedin": "#0a66c2", // https://brand.linkedin.com/ @@ -43,6 +45,7 @@ exports.getColor = function(msg,options) { "mattermost": "#00f", "n26": "#36a18b", "nextbike": "#00f", + "nextcloud": "#0082c9", // https://nextcloud.com/brand/ "newpipe": "#f00", "nina": "#e57004", "opentasks": "#409f8f", @@ -59,6 +62,7 @@ exports.getColor = function(msg,options) { "teams": "#6264a7", // https://developer.microsoft.com/en-us/fluentui#/styles/web/colors/products "telegram": "#0088cc", "telegram foss": "#0088cc", + "thunderbird": "#1582e4", "to do": "#3999e5", "twitch": "#9146ff", // https://brand.twitch.tv/ "twitter": "#1d9bf0", // https://about.twitter.com/en/who-we-are/brand-toolkit diff --git a/apps/messageicons/metadata.json b/apps/messageicons/metadata.json index 356eeba79..afa511aad 100644 --- a/apps/messageicons/metadata.json +++ b/apps/messageicons/metadata.json @@ -1,7 +1,7 @@ { "id": "messageicons", "name": "Message Icons", - "version": "0.08", + "version": "0.09", "description": "Library containing a list of icons and colors for apps", "icon": "app.png", "type": "module", diff --git a/apps/msgtwscr/ChangeLog b/apps/msgtwscr/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/msgtwscr/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/msgtwscr/README.md b/apps/msgtwscr/README.md new file mode 100644 index 000000000..ea92ce76f --- /dev/null +++ b/apps/msgtwscr/README.md @@ -0,0 +1,15 @@ +# Message Twist to Scroll + +Temporarily activate scroll on twist function when a new message triggers the message app. This way it's possible to scroll through a message in the message scroller hands free. + +## Usage + +This is a bootloader app and only needs to be installed to add the functionality to the watch. + +## Requests + +Mention @thyttan in an issue on the espruino/BangleApps repository. + +## Creator + +thyttan diff --git a/apps/msgtwscr/app.png b/apps/msgtwscr/app.png new file mode 100644 index 000000000..83d7e9add Binary files /dev/null and b/apps/msgtwscr/app.png differ diff --git a/apps/msgtwscr/boot.js b/apps/msgtwscr/boot.js new file mode 100644 index 000000000..4b43102a9 --- /dev/null +++ b/apps/msgtwscr/boot.js @@ -0,0 +1,63 @@ +{ + // twistThreshold How much acceleration to register a twist of the watch strap? Can be negative for opposite direction. default = 800 + // twistMaxY Maximum acceleration in Y to trigger a twist (low Y means watch is facing the right way up). default = -800 + // twistTimeout How little time (in ms) must a twist take from low->high acceleration? default = 1000 + let onTwistEmitDrag = ()=>{ + Bangle.setOptions({twistThreshold:2500, twistMaxY:-800, twistTimeout:400}); + let isTwistDragging = false; + let twistHandler = ()=>{ + if (!isTwistDragging) { + isTwistDragging = true; + Bangle.setLocked(false); + Bangle.setLCDPower(true); + let i = 25; + const int = setInterval(() => { + Bangle.emit("drag", {dy:-3, b:i===0?0:1}) + i--; + if (i<0) { + clearInterval(int); + isTwistDragging = false; + } + }, 10); + } + } + Bangle.on("twist", twistHandler); + // Give messagegui some extra time to add its remove function to + // Bangle.uiRemove, then attach msgtwscr remove logic. + setTimeout( + ()=>{if (Bangle.uiRemove) { + let showMessageUIRemove = Bangle.uiRemove; + Bangle.uiRemove = function () { + Bangle.removeListener("twist", twistHandler) + showMessageUIRemove(); + // Reset twist drag logic if we go to next message. + attachAfterTimeout(); + } + }}, + 800) + } + + // If doing regular loads, not Bangle.load, this is used: + if (global.__FILE__=="messagegui.new.js") { + onTwistEmitDrag(); + } + + let attachAfterTimeout = ()=>{ + setTimeout(()=>{ + if (global.__FILE__=="messagegui.new.js") { + onTwistEmitDrag(); + } + },700) + // It feels like there's a more elegant solution than checking the filename + // after 700 milliseconds. But this at least seems to work w/o sometimes + // activating when it shouldn't. + // Maybe we could add events for when fast load and/or Bangle.uiRemove occurs? + // Then that could be used similarly to boot code and/or the `kill` event. + } + + // If Fastload Utils is installed this is used: + Bangle.on("message", (_, msg)=>{if (Bangle.CLOCK && msg.new) { + attachAfterTimeout(); + }}); + +} diff --git a/apps/msgtwscr/metadata.json b/apps/msgtwscr/metadata.json new file mode 100644 index 000000000..6f267ea01 --- /dev/null +++ b/apps/msgtwscr/metadata.json @@ -0,0 +1,13 @@ +{ "id": "msgtwscr", + "name": "Message Twist to Scroll", + "version":"0.01", + "description": "Temporarily activate scroll on twist function when a new message triggers the message app.", + "icon": "app.png", + "tags": "messages,tweak,scroll", + "type": "bootloader", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"msgtwscr.boot.js","url":"boot.js"} + ] +} diff --git a/apps/owmweather/ChangeLog b/apps/owmweather/ChangeLog index a2251f83b..6a5706af1 100644 --- a/apps/owmweather/ChangeLog +++ b/apps/owmweather/ChangeLog @@ -6,4 +6,5 @@ 0.06: Fix One Call API 3.0 not returning city names, which are required by the weather app 0.07: Update weather after reconnecting bluetooth if update is due, refactor code 0.08: Undo change to One Call API 3.0 -0.09: Fix infinite loop when settings.updated is not defined \ No newline at end of file +0.09: Fix infinite loop when settings.updated is not defined +0.10: Fix settings.updated being updated even when OWM call failed \ No newline at end of file diff --git a/apps/owmweather/boot.js b/apps/owmweather/boot.js index dc206be38..82e3a280a 100644 --- a/apps/owmweather/boot.js +++ b/apps/owmweather/boot.js @@ -18,6 +18,13 @@ timeoutRef = setTimeout(loadIfDueAndReschedule, refreshMillis()); }; + let onError = function(e) { + console.log("owmweather error:", e); + loading = false; + if (timeoutRef) clearTimeout(timeoutRef); + timeoutRef = setTimeout(loadIfDueAndReschedule, refreshMillis()); + }; + let loadIfDueAndReschedule = function () { // also check if the weather.json file has been updated (e.g. force refresh) let weather = require("Storage").readJSON('weather.json') || {}; @@ -30,7 +37,7 @@ if (!MillisUntilDue || MillisUntilDue <= 0) { if (!loading) { loading = true; - require("owmweather").pull(onCompleted); + require("owmweather").pull(onCompleted, onError); } } else { // called to early, reschedule diff --git a/apps/owmweather/lib.js b/apps/owmweather/lib.js index baa9555d0..2f6af5f7b 100644 --- a/apps/owmweather/lib.js +++ b/apps/owmweather/lib.js @@ -27,13 +27,12 @@ function parseWeather(response) { json.weather = weather; require("Storage").writeJSON('weather.json', json); if (require("Storage").read("weather")!==undefined) require("weather").emit("update", json.weather); - return undefined; } else { - return /*LANG*/"Not OWM data"; + throw /*LANG*/"Not OWM data"; } } -exports.pull = function(completionCallback) { +exports.pull = function(completionCallback, errorCallback) { let location = require("Storage").readJSON("mylocation.json", 1) || { "lat": 51.50, "lon": 0.12, @@ -43,12 +42,12 @@ exports.pull = function(completionCallback) { let uri = "https://api.openweathermap.org/data/2.5/weather?lat=" + location.lat.toFixed(2) + "&lon=" + location.lon.toFixed(2) + "&exclude=hourly,daily&appid=" + settings.apikey; if (Bangle.http){ Bangle.http(uri, {timeout:10000}).then(event => { - let result = parseWeather(event.resp); - if (completionCallback) completionCallback(result); + parseWeather(event.resp); + if (completionCallback) completionCallback(); }).catch((e)=>{ - if (completionCallback) completionCallback(e); + if (errorCallback) errorCallback(e); }); } else { - if (completionCallback) completionCallback(/*LANG*/"No http method found"); + if (errorCallback) errorCallback(/*LANG*/"No http method found"); } }; diff --git a/apps/owmweather/metadata.json b/apps/owmweather/metadata.json index 8dfa4fe9c..1e514e6bb 100644 --- a/apps/owmweather/metadata.json +++ b/apps/owmweather/metadata.json @@ -1,7 +1,7 @@ { "id": "owmweather", "name": "OpenWeatherMap weather provider", "shortName":"OWM Weather", - "version": "0.09", + "version": "0.10", "description": "Pulls weather from OpenWeatherMap (OWM) API", "icon": "app.png", "type": "bootloader", diff --git a/apps/pebblepp/ChangeLog b/apps/pebblepp/ChangeLog index b44914451..3042937f1 100644 --- a/apps/pebblepp/ChangeLog +++ b/apps/pebblepp/ChangeLog @@ -1,6 +1,6 @@ 0.01: First release 0.02: clock_info now uses app name to maintain settings specifically for this clock face - ensure clockinfo text is usppercase (font doesn't render lowercase) + ensure clockinfo text is uppercase (font doesn't render lowercase) 0.03: Use smaller font if clock_info test doesn't fit in area 0.04: Ensure we only scale down clockinfo text if it really won't fit 0.05: Minor code improvements @@ -10,4 +10,6 @@ 0.09: Add date on the bottom 0.10: Fix size of bottom bar after 0.09 Make date toggleable with settings - Optional border around clockinfos (available from settings) \ No newline at end of file + Optional border around clockinfos (available from settings) +0.11: Make the border on clockinfos the default + Fix clockinfos when too long (previously just output '...') \ No newline at end of file diff --git a/apps/pebblepp/app.js b/apps/pebblepp/app.js index 7c01fcade..f242cba33 100644 --- a/apps/pebblepp/app.js +++ b/apps/pebblepp/app.js @@ -20,7 +20,7 @@ Graphics.prototype.setFontLECO1976Regular14 = function() { { const SETTINGS_FILE = "pebblepp.json"; -let settings = Object.assign({'theme':'System', 'showdate':true, 'clkinfoborder': false}, require("Storage").readJSON(SETTINGS_FILE,1)||{}); +let settings = Object.assign({'theme':'System', 'showdate':true, 'clkinfoborder': true}, require("Storage").readJSON(SETTINGS_FILE,1)||{}); let background = require("clockbg"); let theme; let drawTimeout; @@ -102,7 +102,7 @@ let clockInfoDraw = (itm, info, options) => { g.setFontLECO1976Regular14(); if (g.stringWidth(txt) > options.w) {// if still too big, split to 2 lines var l = g.wrapString(txt, options.w); - txt = l.slice(0,2).join("\n") + (l.length>2)?"...":""; + txt = l.slice(0,2).join("\n") + ((l.length>2)?"...":""); } y = options.y+options.h-12; if (settings.clkinfoborder) { @@ -147,4 +147,4 @@ background.fillRect(Bangle.appRect); // start off with completely clear backgrou g.setColor(theme.fg).fillRect(0, h2 - 6, w, h3 + 6); draw(); -} \ No newline at end of file +} diff --git a/apps/pebblepp/metadata.json b/apps/pebblepp/metadata.json index c2187483c..e26500fc9 100644 --- a/apps/pebblepp/metadata.json +++ b/apps/pebblepp/metadata.json @@ -2,7 +2,7 @@ "id": "pebblepp", "name": "Pebble++ Clock", "shortName": "Pebble++", - "version": "0.10", + "version": "0.11", "description": "A Pebble style clock (based on the 'Pebble Clock' app) but with two configurable ClockInfo items at the top and custom backgrounds. Date/theme/borders be reconfigured using settings page.", "icon": "app.png", "screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"}], diff --git a/apps/pebblepp/settings.js b/apps/pebblepp/settings.js index f2384577e..1ae7ed4d4 100644 --- a/apps/pebblepp/settings.js +++ b/apps/pebblepp/settings.js @@ -2,7 +2,7 @@ const SETTINGS_FILE = "pebblepp.json"; // Initialize with default settings... - let settings = {'theme':'System', 'showdate':true, 'clkinfoborder':false} + let settings = {'theme':'System', 'showdate':true, 'clkinfoborder':true} // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings const storage = require('Storage'); diff --git a/apps/ptlaunch/ChangeLog b/apps/ptlaunch/ChangeLog index 5871b1fdc..3d8fb6361 100644 --- a/apps/ptlaunch/ChangeLog +++ b/apps/ptlaunch/ChangeLog @@ -7,3 +7,7 @@ 0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/ 0.14: Update setUI to work with new Bangle.js 2v13 menu style 0.15: Update to support clocks in custom setUI mode +0.16: Fix issue adding new patterns (fix #3858) + Display message if tapping manage when there are no patterns + Speed improvements + Add widgets to app (work around E.showMenu(back) bug with no widgets in Espruino 2v27) \ No newline at end of file diff --git a/apps/ptlaunch/app.js b/apps/ptlaunch/app.js index 5db3a335b..d9504e20b 100644 --- a/apps/ptlaunch/app.js +++ b/apps/ptlaunch/app.js @@ -9,10 +9,10 @@ var showMainMenu = () => { var mainmenu = { "": { title: "Pattern Launcher", - }, - "< Back": () => { - log("cancel"); - load(); + back: () => { + log("showMainMenu cancel"); + load(); + } }, "Add Pattern": () => { log("creating pattern"); @@ -83,11 +83,11 @@ var showMainMenu = () => { var settingsmenu = { "": { title: "Pattern Settings", - }, - "< Back": () => { - log("cancel"); - load(); - }, + back: () => { + log("settings cancel"); + showMainMenu(); + }, + } }; if (settings.lockDisabled) { @@ -116,12 +116,7 @@ var showMainMenu = () => { var recognizeAndDrawPattern = () => { return new Promise((resolve) => { - E.showMenu(); - g.clear(); - drawCirclesWithPattern([]); - var pattern = []; - var isFinished = false; var finishHandler = () => { if (pattern.length === 0 || isFinished) { @@ -129,15 +124,14 @@ var recognizeAndDrawPattern = () => { } log("Pattern is finished."); isFinished = true; - Bangle.removeListener("drag", dragHandler); - Bangle.removeListener("tap", finishHandler); + g.clear(); + require("widget_utils").show(); + Bangle.setUI(); resolve(pattern.join("")); }; - setWatch(() => finishHandler(), BTN); - // setTimeout(() => Bangle.on("tap", finishHandler), 250); var positions = []; - var getPattern = (positions) => { + var getPattern = (positions) => { "ram";/*faster*/ var circles = [ { x: 25, y: 25, i: 0 }, { x: 87, y: 25, i: 1 }, @@ -151,18 +145,8 @@ var recognizeAndDrawPattern = () => { ]; return positions.reduce((pattern, p, i, arr) => { var idx = circles.findIndex((c) => { - var dx = p.x > c.x ? p.x - c.x : c.x - p.x; - if (dx > CIRCLE_RADIUS) { - return false; - } - var dy = p.y > c.y ? p.y - c.y : c.y - p.y; - if (dy > CIRCLE_RADIUS) { - return false; - } - if (dx + dy <= CIRCLE_RADIUS) { - return true; - } - return dx * dx + dy * dy <= CIRCLE_RADIUS_2; + var dx = p.x - c.x, dy = p.y - c.y; + return dx*dx + dy*dy <= CIRCLE_RADIUS_2; }); if (idx >= 0) { pattern += circles[idx].i; @@ -183,7 +167,10 @@ var recognizeAndDrawPattern = () => { positions = []; } }; - Bangle.on("drag", dragHandler); + require("widget_utils").hide(); + g.clear(); + drawCirclesWithPattern([]); + Bangle.setUI({mode:"custom", drag:dragHandler, btn :finishHandler}); }); }; @@ -215,14 +202,14 @@ var getAppList = () => { }; var getSelectedApp = () => { - E.showMessage("Loading apps..."); + E.showMessage(/*LANG*/"Loading apps..."); return new Promise((resolve) => { var selectAppMenu = { "": { - title: "Select App", + title: /*LANG*/"Select App", }, "< Cancel": () => { - log("cancel"); + log("getSelectedApp cancel"); showMainMenu(); }, }; @@ -286,6 +273,8 @@ var drawAppWithPattern = (i, r, storedPatterns) => { var showScrollerContainingAppsWithPatterns = () => { var storedPatternsArray = getStoredPatternsArray(); + if (!storedPatternsArray.length) + return E.showAlert(/*LANG*/"No Patterns",{title:/*LANG*/"Patterns"}).then(() => ({ pattern: "back", appName:"" })); log("drawing scroller for stored patterns"); log(storedPatternsArray); log(storedPatternsArray.length); @@ -485,4 +474,6 @@ var log = (message) => { // run main function ////// -showMainMenu(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +showMainMenu(); \ No newline at end of file diff --git a/apps/ptlaunch/boot.js b/apps/ptlaunch/boot.js index 885962761..9014da9d2 100644 --- a/apps/ptlaunch/boot.js +++ b/apps/ptlaunch/boot.js @@ -24,18 +24,8 @@ ]; return positions.reduce((pattern, p, i, arr) => { var idx = circles.findIndex((c) => { - var dx = p.x > c.x ? p.x - c.x : c.x - p.x; - if (dx > CIRCLE_RADIUS) { - return false; - } - var dy = p.y > c.y ? p.y - c.y : c.y - p.y; - if (dy > CIRCLE_RADIUS) { - return false; - } - if (dx + dy <= CIRCLE_RADIUS) { - return true; - } - return dx * dx + dy * dy <= CIRCLE_RADIUS_2; + var dx = p.x - c.x, dy = p.y - c.y; + return dx*dx + dy*dy <= CIRCLE_RADIUS_2; }); if (idx >= 0) { pattern += circles[idx].i; diff --git a/apps/ptlaunch/metadata.json b/apps/ptlaunch/metadata.json index 6f8a9e16f..e3dbb5701 100644 --- a/apps/ptlaunch/metadata.json +++ b/apps/ptlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "ptlaunch", "name": "Pattern Launcher", "shortName": "Pattern Launcher", - "version": "0.15", + "version": "0.16", "description": "Directly launch apps from the clock screen with custom patterns.", "icon": "app.png", "screenshots": [{"url":"manage_patterns_light.png"}], diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 33986f219..f5c0803bb 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -55,4 +55,9 @@ 0.43: Fix interaction on clocks without widgets 0.44: List tracks in reverse chronological order. 0.45: Move recorder from widget into library - Improve recorder ClockInfo icons \ No newline at end of file + Improve recorder ClockInfo icons +0.46: Ensure altitude graph draws properly (or any graph using the last column of CSV data) + Lower accuracy of barometer data to ~1cm (saves about 15b/record) +0.47: Fix 'blip' on speed map on some recordings + Ensure Battery voltage is only stored to 0.01v + Add graphs for Steps+Battery \ No newline at end of file diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 6d672cd85..37fa5cb3b 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -197,6 +197,14 @@ function viewTrack(filename, info) { menu[/*LANG*/'Plot HRM'] = function() { plotGraph(info, "Heartrate"); }; + if (info.fields.includes("Steps")) + menu[/*LANG*/'Plot Steps'] = function() { + plotGraph(info, "Steps"); + }; + if (info.fields.includes("Battery Percentage")) + menu[/*LANG*/'Plot Battery'] = function() { + plotGraph(info, "Battery"); + }; // TODO: steps, heart rate? menu[/*LANG*/'Erase'] = function() { E.showPrompt(/*LANG*/"Delete Track?").then(function(v) { @@ -325,6 +333,7 @@ function plotGraph(info, style) { "ram" var lt = 0; // last time //var tn = 0; // count for each time period var strt, dur = info.duration; + if (dur<1) dur=1; var f = require("Storage").open(filename,"r"); if (f===undefined) return; var l = f.readLine(f); @@ -333,14 +342,14 @@ function plotGraph(info, style) { "ram" var factor = 1; // multiplier used for values when graphing var timeIdx = info.fields.indexOf("Time"); if (l!==undefined) { - c = l.split(","); + c = l.trim().split(","); strt = c[timeIdx]; } if (style=="Heartrate") { title = /*LANG*/"Heartrate (bpm)"; var hrmIdx = info.fields.indexOf("Heartrate"); while(l!==undefined) { - c=l.split(",");l = f.readLine(f); + c=l.trim().split(",");l = f.readLine(f); if (c[hrmIdx]=="") continue; i = Math.round(80*(c[timeIdx] - strt)/dur); infn[i]+=+c[hrmIdx]; @@ -351,45 +360,63 @@ function plotGraph(info, style) { "ram" var altIdx = info.fields.indexOf("Barometer Altitude"); if (altIdx<0) altIdx = info.fields.indexOf("Altitude"); while(l!==undefined) { - c=l.split(",");l = f.readLine(f); + c=l.trim().split(",");l = f.readLine(f); if (c[altIdx]=="") continue; i = Math.round(80*(c[timeIdx] - strt)/dur); infn[i]+=+c[altIdx]; infc[i]++; } + } else if (style=="Steps") { + title = /*LANG*/"Steps/min"; + var stpIdx = info.fields.indexOf("Steps"); + var t,lt = c[timeIdx]; + while(l!==undefined) { + c=l.trim().split(",");l = f.readLine(f); + if (c[stpIdx]=="") continue; + t = c[timeIdx]; + i = Math.round(80*(t - strt)/dur); + infn[i]+=60*c[stpIdx]; + infc[i]+=t-lt; + lt = t; + } + } else if (style=="Battery") { + title = /*LANG*/"Battery %"; + var batIdx = info.fields.indexOf("Battery Percentage"); + while(l!==undefined) { + c=l.trim().split(",");l = f.readLine(f); + if (c[batIdx]=="") continue; + i = Math.round(80*(c[timeIdx] - strt)/dur); + infn[i]+=+c[batIdx]; + infc[i]++; + } } else if (style=="Speed") { // use locate to work out units var localeStr = require("locale").speed(1,5); // get what 1kph equates to let units = localeStr.replace(/[0-9.]*/,""); factor = parseFloat(localeStr)*3.6; // m/sec to whatever out units are - // title title = /*LANG*/"Speed"+` (${units})`; var latIdx = info.fields.indexOf("Latitude"); var lonIdx = info.fields.indexOf("Longitude"); // skip until we find our first data while(l!==undefined && c[latIdx]=="") { - c = l.split(","); + c = l.trim().split(","); l = f.readLine(f); } // now iterate - var p,lp = Bangle.project({lat:c[1],lon:c[2]}); + var p,lp = Bangle.project({lat:c[latIdx],lon:c[lonIdx]}); var t,dx,dy,d,lt = c[timeIdx]; while(l!==undefined) { - c=l.split(","); + c=l.trim().split(","); l = f.readLine(f); - if (c[latIdx] == "") { - continue; - } + if (c[latIdx] == "") continue; t = c[timeIdx]; i = Math.round(80*(t - strt)/dur); p = Bangle.project({lat:c[latIdx],lon:c[lonIdx]}); dx = p.x-lp.x; dy = p.y-lp.y; d = Math.sqrt(dx*dx+dy*dy); - if (t!=lt) { - infn[i]+=d / (t-lt); // speed - infc[i]++; - } + infn[i]+=d; // speed + infc[i]+=t-lt; lp = p; lt = t; } @@ -405,6 +432,7 @@ function plotGraph(info, style) { "ram" if (n>max) max=n; if (n { - return [E.getBattery(), NRF.getBattery(), Bangle.isCharging()]; + return [E.getBattery(), NRF.getBattery().toFixed(2), Bangle.isCharging()]; }, start : () => { }, @@ -120,9 +120,9 @@ exports.getRecorders = function() { recorders['baro'] = function() { var temp="",press="",alt=""; function onPress(c) { - temp=c.temperature; - press=c.pressure; - alt=c.altitude; + temp=c.temperature.toFixed(1); + press=c.pressure.toFixed(2); + alt=c.altitude.toFixed(2); } return { name : "Baro", diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 5a7ded5d4..2d7e54bdd 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.45", + "version": "0.47", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget,clkinfo", diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 17098b069..03ee8db12 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -87,3 +87,4 @@ of 'Select Clock' 0.76: Add altitude calibration menu (and update README after menu changed) 0.77: Save altitude calibration when user exits via reset 0.78: Fix menu scroll restore on BangleJS1 +0.79: Ensure that tapping on pressure/altitude doesn't cause a menu to display temporarily diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index 4940b5f70..e255a0dcb 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -1,7 +1,7 @@ { "id": "setting", "name": "Settings", - "version": "0.78", + "version": "0.79", "description": "A menu for setting up Bangle.js", "icon": "settings.png", "tags": "tool,system", diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 3d7f35cd8..45b971e32 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -1033,8 +1033,8 @@ function showTouchscreenCalibration() { // Calibrate altitude - Bangle.js2 only function showAltitude() { function onPressure(pressure) { - menuPressure.value = Math.round(pressure.pressure); - menuAltitude.value = Math.round(pressure.altitude); + menuPressure.value = Math.round(pressure.pressure).toString(); // toString stops tapping on the item bringing up an adjustment menu + menuAltitude.value = Math.round(pressure.altitude).toString(); m.draw(); } function altitudeDone() { diff --git a/apps/sleeplog/metadata.json b/apps/sleeplog/metadata.json index ff3d5a18f..95d9846ed 100644 --- a/apps/sleeplog/metadata.json +++ b/apps/sleeplog/metadata.json @@ -3,10 +3,10 @@ "name":"Sleep Log", "shortName": "SleepLog", "version": "0.19", - "description": "Log and view your sleeping habits. This app is using the built in movement calculation.", + "description": "Log and view your sleeping habits. This app uses built in movement calculations. View data from Bangle, or from the web app.", "icon": "app.png", "type": "app", - "tags": "tool,boot", + "tags": "tool,boot,health", "supports": ["BANGLEJS2"], "readme": "README.md", "interface": "interface.html", diff --git a/core b/core index 7e7475ba3..091675693 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7e7475ba3ab253099481a81e487aaacb9384f974 +Subproject commit 0916756932699d626555171ce8e0a2989b151c89