From bcc30cadae9fea049ab5fb715d08576b353921d7 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Wed, 27 Apr 2022 20:28:42 +0100 Subject: [PATCH 01/82] First commit for this app --- apps/timersimple/ChangeLog | 1 + apps/timersimple/Readme.md | 10 ++ apps/timersimple/icons8-time-span-48.png | Bin 0 -> 1933 bytes apps/timersimple/metadata.json | 18 +++ apps/timersimple/timersimple.app.js | 191 +++++++++++++++++++++++ apps/timersimple/timersimple.icon.js | 1 + 6 files changed, 221 insertions(+) create mode 100644 apps/timersimple/ChangeLog create mode 100644 apps/timersimple/Readme.md create mode 100644 apps/timersimple/icons8-time-span-48.png create mode 100644 apps/timersimple/metadata.json create mode 100644 apps/timersimple/timersimple.app.js create mode 100644 apps/timersimple/timersimple.icon.js diff --git a/apps/timersimple/ChangeLog b/apps/timersimple/ChangeLog new file mode 100644 index 000000000..7b83706bf --- /dev/null +++ b/apps/timersimple/ChangeLog @@ -0,0 +1 @@ +0.01: First release diff --git a/apps/timersimple/Readme.md b/apps/timersimple/Readme.md new file mode 100644 index 000000000..e940ba0ab --- /dev/null +++ b/apps/timersimple/Readme.md @@ -0,0 +1,10 @@ +# Simple Timer + +Does one thing well. Set a time in hours, minutes and seconds, and alerts you when time is up. Opening the app while the timer is running (or just leaving the app open) shows how much time is left on the timer. This is the part I felt was missing from the Alarms and Timer app. + +Drag or tap on the up and down buttons over the hour, minute or second to set the time. + +![](timersimple-scr1.png) +![](timersimple-scr2.png) + +Written by: [Sir Indy](https://github.com/sir-indy) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) \ No newline at end of file diff --git a/apps/timersimple/icons8-time-span-48.png b/apps/timersimple/icons8-time-span-48.png new file mode 100644 index 0000000000000000000000000000000000000000..9a9dfb6abd1801997481d40bd41e475afe845f1a GIT binary patch literal 1933 zcmV;82Xgp{P)}f;`d3 z{4|bF%roc{(>PYg>)2T4uNQwW0+8Ygn zw6{|X*_#deBv!4>$$!2UDtwRtR+g1(ggqUDi`B3w1D||bZ8oxLjVqIK^H_${Y^z~l z4qgh>@{lV8OUG!WT9`-!KJBimUYE47XSH$tg5tx3jsS-xFyB^uwzDMC;IL=l!y5-< z9+954uQIM*AISi#lMCP$CvkuJ4u)O*aEx9--^e9+r0Ecf=!uc#t|RYnvWwyLAC`go z?%yS^GUR=enP|!kU-~Re#w|gd=<}d^s2vxspT^kKkXqR19O8=wOG^ls-(f)m?_4{g zFW`RgpNxbx8DS|_K+V7$d{n|$jx%WMJqbznDr)IjZYFiFu&+^B5r751fyc1Hwpj5C zfh8P%XxfioJo9HP)2AqE$&bX?v9}lML({h39gzCC-!JN^E^y&m@Z=oN4bkCgbVMQwY= z*zAbfFN;ZmOl8~{`+A-uz>|e9nCd!CJ0_IvRcAnwn3n+P0ASKRj=tMAtW3&7f<7H2 zI>#qXY|Z(Z@>SCLAit>AHpqY=2n+~H{kd(AmO#hGAuWClRwX@&1bsTFOrxvX4>~Ru zJ95hcI0}>%e^MOu#snGg6E*WLM0JofT47ge>o>5KdAF#$Bv=7xfvTbZp6TV6R*5nj$K=3XG9ERMqDlz z>g(%q>((vJb~&kmV-sNE8K6L}e|dR=DX3#Y2rL#0Y&IL3o12lJpO1k7CtiQ`D4u(! z6ixMQkfp%o_x}C+sH>~PzJ2?UnVE?L2M(a2p+VC?#n0qV=B z!M~vA;xz{W0ES^;u~^XA*$J!F3bWaakvk(Ot9l%zZ?1#gZigs}U>F8lw{AsMRTZvX zyM_}dPH6V4=Yz&xrX-?rBbfukFeoi8MM+5s($muc3Q(Csuh*lxx*EmB#aOW-=&3FV zY6d0&%kx24*)GTc-?{xVK<8gx zuQY?JL+Ac4BDK&x)CR9K<4+B+o!jinc50_lnSj*$a~H0khL1+~tfK{=Ea80rX$4E_ z)l!kF_W_obYXHn=1IDI?@Rj3CbX98LOGhKdrvnxo4+X7JYpZHN*wZmcfm(mAt@k9H z<2}(+83NAn9-Qkt6~Iy8gGx)gY62^OsT7&SwJ%$GR z8<6CH6YUreIpm!qk|9-Y~btXXO?+BBgadZuyMRxK!B*jK2-{l-V))ssgCmz0~7A7~9{puZA!bcD6>M4aR)Z`rw@fW8YLWV&yWxJwCsS^1Op#z=x9{zFq~ zY5UkGlC_kO_W*bzjaPw(0`GD>zcy0wz!HD*mA4dTF~Ca{v=ksKBa5a^fU#20noyfm zIEc<~RzYCIg7cdI6#g&uVFr+e@9x)=00sf{fxt#&($02nvq$4M>q9)m_Z|NQLRok` Trm{7g00000NkvXXu0mjfz&ofF literal 0 HcmV?d00001 diff --git a/apps/timersimple/metadata.json b/apps/timersimple/metadata.json new file mode 100644 index 000000000..5d0e5d5e4 --- /dev/null +++ b/apps/timersimple/metadata.json @@ -0,0 +1,18 @@ +{ + "id":"timersimple", + "name":"Timer Simple", + "shortName": "Timer Simple", + "version": "0.01", + "description": "Sets a single timer, and tells you how long left.", + "readme": "README.md", + "icon":"icons8-time-span-48.png", + "screenshots": [{"url":"timersimple-scr1.png"},{"url":"timersimple-scr2.png"}], + "tags": "tool,alarm,timer", + "supports": ["BANGLEJS2"], + "dependencies": {"scheduler":"type"}, + "allow_emulator": true, + "storage": [ + {"name":"timersimple.app.js","url":"timersimple.app.js"}, + {"name":"timersimple.img","url":"timersimple.icon.js","evaluate":true} + ] + } \ No newline at end of file diff --git a/apps/timersimple/timersimple.app.js b/apps/timersimple/timersimple.app.js new file mode 100644 index 000000000..ddc6bb4c1 --- /dev/null +++ b/apps/timersimple/timersimple.app.js @@ -0,0 +1,191 @@ +Modules.addCached("Layout",function(){function Layout(d,b){function e(a){a.id&&(h[a.id]=a),a.type||(a.type=''),a.c&&a.c.forEach(e)}this._l=this.l=d,this.physBtns=process.env.HWVERSION==2?1:3,b=b||{},this.lazy=b.lazy||!1;var c,f;if(Bangle.setUI(),process.env.HWVERSION!=2){c=[];function a(b){b.type=='btn'&&c.push(b),b.c&&b.c.forEach(a)}a(d),c.length&&(this.physBtns=0,this.buttons=c,this.selectedButton=-1,Bangle.setUI({mode:'updown',back:b.back},c=>{var a=this.selectedButton,b=this.buttons.length;if(c===undefined&&this.buttons[a])return this.buttons[a].cb();this.buttons[a]&&(delete this.buttons[a].selected,this.render(this.buttons[a])),a=(a+b+c)%b,this.buttons[a]&&(this.buttons[a].selected=1,this.render(this.buttons[a])),this.selectedButton=a}),f=!0)}if(b.back&&!f&&Bangle.setUI({mode:'custom',back:b.back}),b.btns){var a=b.btns;if(this.b=a,this.physBtns>=a.length){function b(a,b){b.time-b.lastTime>.75&&this.b[a].cbl?this.b[a].cbl(b):this.b[a].cb&&this.b[a].cb(b)}let c=Math.floor(Bangle.appRect.h/this.physBtns);Bangle.btnWatches&&Bangle.btnWatches.forEach(clearWatch),Bangle.btnWatches=[],this.physBtns>2&&a.length==1&&a.unshift({label:''});while(this.physBtns>a.length)a.push({label:''});a[0]&&Bangle.btnWatches.push(setWatch(b.bind(this,0),BTN1,{repeat:!0,edge:-1})),a[1]&&Bangle.btnWatches.push(setWatch(b.bind(this,1),BTN2,{repeat:!0,edge:-1})),a[2]&&Bangle.btnWatches.push(setWatch(b.bind(this,2),BTN3,{repeat:!0,edge:-1})),this._l.width=g.getWidth()-8,this._l={type:'h',filly:1,c:[this._l,{type:'v',pad:1,filly:1,c:a.map(a=>(a.type='txt',a.font='6x8',a.height=c,a.r=1,a))}]}}else this._l.width=g.getWidth()-32,this._l={type:'h',c:[this._l,{type:'v',c:a.map(a=>(a.type='btn',a.filly=1,a.width=32,a.r=1,a))}]},c&&c.push.apply(c,this._l.c[1].c)}if(process.env.HWVERSION==2){function a(b,c){b.cb&&c.x>=b.x&&c.y>=b.y&&c.x<=b.x+b.w&&c.y<=b.y+b.h&&(c.type==2&&b.cbl?b.cbl(c):b.cb&&b.cb(c)),b.c&&b.c.forEach(b=>a(b,c))}Bangle.touchHandler=(c,b)=>a(this._l,b),Bangle.on('touch',Bangle.touchHandler)}var h=this;e(this._l),this.updateNeeded=!0}function prepareLazyRender(a,h,b,i,c){var d=a.bgCol==null?c:g.toColor(a.bgCol);if(d!=c||a.type=='txt'||a.type=='btn'||a.type=='img'||a.type=='custom'){var e=a.c;delete a.c;var f='H'+E.CRC32(E.toJS(a));if(e&&(a.c=e),!delete h[f]){var j=i[f]=[a.x,a.y,a.x+a.w-1,a.y+a.h-1];j.bg=c==null?g.theme.bg:c,b&&(b.push(a),b=null)}}if(a.c)for(var k of a.c)prepareLazyRender(k,h,b,i,d)}Layout.prototype.remove=function(a){Bangle.btnWatches&&(Bangle.btnWatches.forEach(clearWatch),delete Bangle.btnWatches),Bangle.touchHandler&&(Bangle.removeListener('touch',Bangle.touchHandler),delete Bangle.touchHandler)},Layout.prototype.render=function(b){function c(a){"ram";g.reset(),a.col!==undefined&&g.setColor(a.col),a.bgCol!==undefined&&g.setBgColor(a.bgCol).clearRect(a.x,a.y,a.x+a.w-1,a.y+a.h-1),f[a.type](a)}b||(b=this._l),this.updateNeeded&&this.update();var f={'':function(){},txt:function(a){if(a.wrap){g.setFont(a.font).setFontAlign(0,-1);var b=g.wrapString(a.label,a.w),c=a.y+(a.h-g.getFontHeight()*b.length>>1);b.forEach((b,d)=>g.drawString(b,a.x+(a.w>>1),c+g.getFontHeight()*d))}else g.setFont(a.font).setFontAlign(0,0,a.r).drawString(a.label,a.x+(a.w>>1),a.y+(a.h>>1))},btn:function(a){var b=a.x+(0|a.pad),c=a.y+(0|a.pad),d=a.w-(a.pad<<1),e=a.h-(a.pad<<1),f=[b,c+4,b+4,c,b+d-5,c,b+d-1,c+4,b+d-1,c+e-5,b+d-5,c+e-1,b+4,c+e-1,b,c+e-5,b,c+4],h=a.selected?g.theme.bgH:g.theme.bg2;g.setColor(h).fillPoly(f).setColor(a.selected?g.theme.fgH:g.theme.fg2).drawPoly(f),a.col!==undefined&&g.setColor(a.col),a.src?g.setBgColor(h).drawImage('f'==(typeof a.src)[0]?a.src():a.src,a.x+10+(0|a.pad),a.y+8+(0|a.pad)):g.setFont('6x8',2).setFontAlign(0,0,a.r).drawString(a.label,a.x+a.w/2,a.y+a.h/2)},img:function(a){g.drawImage('f'==(typeof a.src)[0]?a.src():a.src,a.x+(0|a.pad),a.y+(0|a.pad),a.scale?{scale:a.scale}:undefined)},custom:function(a){a.render(a)},h:function(a){a.c.forEach(c)},v:function(a){a.c.forEach(c)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),d=[];prepareLazyRender(b,a,d,this.rects,null);for(var h in a)delete this.rects[h];var i=Object.keys(a).map(b=>a[b]).reverse();for(var e of i)g.setBgColor(e.bg).clearRect.apply(g,e);d.forEach(c)}else c(b)},Layout.prototype.forgetLazyState=function(){this.rects={}},Layout.prototype.layout=function(a){switch(a.type){case'h':{var b=a.x+(0|a.pad),h=0,d=a.c&&a.c.reduce((a,b)=>a+(0|b.fillx),0);d||(b+=a.w-a._w>>1,d=1);var e=b;a.c.forEach(c=>{c.x=0|e,b+=c._w,h+=0|c.fillx,e=b+Math.floor(h*(a.w-a._w)/d),c.w=0|e-c.x,c.h=0|(c.filly?a.h-(a.pad<<1):c._h),c.y=0|a.y+(0|a.pad)+((1+(0|c.valign))*(a.h-(a.pad<<1)-c.h)>>1),c.c&&this.layout(c)});break}case'v':{var c=a.y+(0|a.pad),i=0,f=a.c&&a.c.reduce((a,b)=>a+(0|b.filly),0);f||(c+=a.h-a._h>>1,f=1);var g=c;a.c.forEach(b=>{b.y=0|g,c+=b._h,i+=0|b.filly,g=c+Math.floor(i*(a.h-a._h)/f),b.h=0|g-b.y,b.w=0|(b.fillx?a.w-(a.pad<<1):b._w),b.x=0|a.x+(0|a.pad)+((1+(0|b.halign))*(a.w-(a.pad<<1)-b.w)>>1),b.c&&this.layout(b)});break}}},Layout.prototype.debug=function(a,b){a||(a=this._l),b=b||1,g.setColor(b&1,b&2,b&4).drawRect(a.x+b-1,a.y+b-1,a.x+a.w-b,a.y+a.h-b),a.pad&&g.drawRect(a.x+a.pad-1,a.y+a.pad-1,a.x+a.w-a.pad,a.y+a.h-a.pad),b++,a.c&&a.c.forEach(a=>this.debug(a,b))},Layout.prototype.update=function(){function b(a){"ram";if(c[a.type](a),a.r&1){var b=a._w;a._w=a._h,a._h=b}a._w=0|Math.max(a._w+(a.pad<<1),0|a.width),a._h=0|Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var c={txt:function(a){if(a.font.endsWith('%')&&(a.font='Vector'+Math.round(g.getHeight()*a.font.slice(0,-1)/100)),a.wrap)a._h=a._w=0;else{var b=g.setFont(a.font).stringMetrics(a.label);a._w=b.width,a._h=b.height}},btn:function(a){var b=a.src?g.imageMetrics('f'==(typeof a.src)[0]?a.src():a.src):g.setFont('6x8',2).stringMetrics(a.label);a._h=16+b.height,a._w=20+b.width},img:function(a){var b=g.imageMetrics('f'==(typeof a.src)[0]?a.src():a.src),c=a.scale||1;a._w=b.width*c,a._h=b.height*c},'':function(a){a._w=0,a._h=0},custom:function(a){a._w=0,a._h=0},h:function(a){a.c.forEach(b),a._h=a.c.reduce((a,b)=>Math.max(a,b._h),0),a._w=a.c.reduce((a,b)=>a+b._w,0),a.fillx==null&&a.c.some(a=>a.fillx)&&(a.fillx=1),a.filly==null&&a.c.some(a=>a.filly)&&(a.filly=1)},v:function(a){a.c.forEach(b),a._h=a.c.reduce((a,b)=>a+b._h,0),a._w=a.c.reduce((a,b)=>Math.max(a,b._w),0),a.fillx==null&&a.c.some(a=>a.fillx)&&(a.fillx=1),a.filly==null&&a.c.some(a=>a.filly)&&(a.filly=1)}},a=this._l;b(a),a.fillx||a.filly?(a.w=Bangle.appRect.w,a.h=Bangle.appRect.h,a.x=Bangle.appRect.x,a.y=Bangle.appRect.y):(a.w=a._w,a.h=a._h,a.x=Bangle.appRect.w-a.w>>1,a.y=Bangle.appRect.y+(Bangle.appRect.h-a.h>>1)),this.layout(a)},Layout.prototype.clear=function(a){a||(a=this._l),g.reset(),a.bgCol!==undefined&&g.setBgColor(a.bgCol),g.clearRect(a.x,a.y,a.x+a.w-1,a.y+a.h-1)},exports=Layout}); + +const secondsToTime = (s) => new Object({h:Math.floor((s/3600) % 24), m:Math.floor((s/60) % 60), s:Math.floor(s % 60)}); +const clamp = (num, min, max) => Math.min(Math.max(num, min), max); +function formatTime(s) { + var t = secondsToTime(s); + if (t.h) { + return t.h + ':' + ("0" + t.m).substr(-2) + ':' + ("0" + t.s).substr(-2); + } else { + return t.m + ':' + ("0" + t.s).substr(-2); + } +} + +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +var Layout = require("Layout"); +var seconds = 5 * 60; +var drawTimeout; +var timerLayout; +var timePickerLayout; +var imgArrowDown = Graphics.createImage(` +xxx xxx +xxx xxx + xxx xxx + xxx xxx + xxxxx + xxxxx + xxx + xxx + x +`); +var imgArrowUp = Graphics.createImage(` + x + xxx + xxx + xxxxx + xxxxx + xxx xxx + xxx xxx +xxx xxx +xxx xxx +`); + +function onDrag(event) { + var scale = 1; + if (event.x < timePickerLayout.hours.w) { + scale = 3600; + } else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) { + scale = 60; + } + seconds -= Math.round(event.dy/5) * scale; + updateTimePicker(); +} + +function onTouch(button, xy) { + var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; + var diff = 0; + if (xy.y > 24 && xy.y < touchMidpoint - 10) { + diff = 1; + } else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { + diff = -1; + } else if (xy.y > timePickerLayout.btnStart.y) { + runTimer(); + return; + } + if (xy.x < timePickerLayout.hours.w) { + diff *= 3600; + } else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) { + diff *= 60; + } + seconds += diff; + updateTimePicker(); +} + +function updateTimePicker() { + seconds = clamp(seconds, 0, 24 * 3600 - 1); + var set_time = secondsToTime(seconds); + updateLayoutField(timePickerLayout, 'hours', set_time.h); + updateLayoutField(timePickerLayout, 'mins', set_time.m); + updateLayoutField(timePickerLayout, 'secs', set_time.s); +} + +function updateLayoutField(layout, field, value) { + layout.clear(layout[field]); + layout[field].label = value; + layout.render(layout[field]); +} + +function updateTimer() { + var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm("simpletimer")); + var d = new Date(); + updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000)); + updateLayoutField(timerLayout, 'time', require("locale").time(d,1)); + queueDraw(1000); +} + +function queueDraw(millisecs) { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + updateTimer(); + }, millisecs - (Date.now() % millisecs)); +} + +function timerStop() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + seconds = require("sched").getTimeToAlarm(require("sched").getAlarm("simpletimer")) / 1000; + require("sched").setAlarm("simpletimer", undefined); + require("sched").reload(); + runTimePicker(); +} + +var timePickerLayoutCode = { + type:"v", c: [ + {type:undefined, height:2}, + //{type:"txt", font:"15%", label:"TIMER", id:"title"}, + {type:"h", c: [ + {type:"v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Hours", col:g.theme.fg2}, + {type:"img", pad:8, src:imgArrowUp, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"0", id:"hours", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrowDown, col:g.theme.fg2} + ]}, + {type:"v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Minutes", col:g.theme.fg2}, + {type:"img", pad:8, src:imgArrowUp, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"0", id:"mins", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrowDown, col:g.theme.fg2} + ]}, + {type:"v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Seconds", col:g.theme.fg2}, + {type:"img", pad:8, src:imgArrowUp, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"0", id:"secs", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrowDown, col:g.theme.fg2} + ]}, + ]}, + {type:"btn", font:"12x20", label:"Start", id:"btnStart", fillx:1 } + ], filly:1 +}; + +var timerLayoutCode = { + type:"v", c: [ + {type:undefined, height:8}, + {type:"txt", font:"6x8", label:/*LANG*/"Timer", id:"title", col:g.theme.fg2}, + {type:"txt", font:"22%", label:"0:00", id:"timer", fillx:1, filly:1 }, + {type:"h", c: [ + {type:"txt", font:"6x8", pad:8, label:/*LANG*/"Time Now:", halign:-1, col:g.theme.fg2}, + {type:"txt", font:"6x8", label:"00:00", id:"time", halign:1, col:g.theme.fg2}, + ]}, + {type:"btn", font:"12x20", label:"Stop", cb: l=>timerStop(), fillx:1 } + ], filly:1 +}; + +function runTimePicker() { + g.clearRect(Bangle.appRect); + timePickerLayout = new Layout(timePickerLayoutCode); + Bangle.setUI({ + mode : "custom", + touch : function(n,e) {onTouch(n,e);}, + drag : function(e) {onDrag(e);}, + btn : function(n) {runTimer();}, + }); + timePickerLayout.render(); + updateTimePicker(); +} + +function runTimer() { + require("sched").setAlarm("simpletimer", { + //msg : "Mr Flibble is very angry!", + vibrate : ".-.-", + hidden: true, + timer : seconds * 1000 + }); + require("sched").reload(); + g.clearRect(Bangle.appRect); + timerLayout = new Layout(timerLayoutCode); + timerLayout.render(); + updateTimer(); +} + +var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm("simpletimer")); +if (timeToNext != undefined) { + g.clearRect(Bangle.appRect); + timerLayout = new Layout(timerLayoutCode); + timerLayout.render(); + updateTimer(); +} else { + runTimePicker(); +} diff --git a/apps/timersimple/timersimple.icon.js b/apps/timersimple/timersimple.icon.js new file mode 100644 index 000000000..cd40303a0 --- /dev/null +++ b/apps/timersimple/timersimple.icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcBkmSpIC/ARf//9JkQRMCAIRBAwIRKv4RFpARIz4QCCIdJiREJAAgJCCI0nCI3+BgOJCIs/CI3/9MkyJoIAAxuGp4RJ8gRQ/mSogRDu4RJNwKSEqXfCJPSCImSrYRJ+SkEyVfCJP6CIo1B4wRHUgIREA4MAj4SHCIeUCIP//EAt4RHkQRF//ggIDB+EHCJf/wEAAAQRM/0CoAmCCJf/4VDI5pcCNwoRKNZ4RMUIQRLYowAIYozpRrYRJ+QREqVLCJPSpGSCIdJv5GIyQREpVJfA///mSogRDpNJloRH8mSBwQRDku/CIwMBCIspkmXCAvpkmRCIslAYKkETwMkxIRFkmkyVLNwYJCBwgCDAwyeEAQqSBAwiMEAQwGFBxACDygDBkQOKAX4CD")) \ No newline at end of file From ed71d95f651dc86450875b5120f3ae0941d3cce1 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Wed, 27 Apr 2022 20:44:06 +0100 Subject: [PATCH 02/82] Added screenshots --- apps/timersimple/timersimple-scr1.png | Bin 0 -> 3232 bytes apps/timersimple/timersimple-scr2.png | Bin 0 -> 3017 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/timersimple/timersimple-scr1.png create mode 100644 apps/timersimple/timersimple-scr2.png diff --git a/apps/timersimple/timersimple-scr1.png b/apps/timersimple/timersimple-scr1.png new file mode 100644 index 0000000000000000000000000000000000000000..5556f8ecc0f2b0c0e343e144f53b2a90741e55c3 GIT binary patch literal 3232 zcmd5<`8(7L7oQD-8eJL0SXwNlAzSvP?5_~YHnymQWKUyEW=fJ>w(KF2vSchX4D(Il zR`zT~W9(eUV6tU<-TVFp?{D{qb3V`coO3?UdCv2kAI`I@mL^AeM0h|T&`~o}Lz_da z{@dW3hrX&|+Vv2?!8RtBL6zO81rX?nlbPYAYY$wRd5amNl1HLaHzVhnfj0NKFJ0h= ze7*hq^=nc2{&~;%_awZocv3;fCp{8pq-A`TL6yB^U{S?l-$Ox91?24``@6!|bJl)O z8s@Fe%{6KE%!%k&%ZK-sfh@Uwp9?^BJ}JjOfkb?I`%LxRo&3PTm+9>+pG-kQQKBsQ z))oFg-9U5P8Qi8IwViBv4ZHcJ7^e9l_h7HmfK^lnAz_0h;{?3fbcuah zEW}cqrwX>p1)%LO%PSA=^8=A`6Sgs^n>YH01dBqxqZp`eeum26&jvAgu4xV*;dtkx z==bW*#uh%Sq?jQ^%ue*JqSoWbwGkglx5 zml0!u9i>h;<>UFPFL%a&Ts$RIfil50TFdG4y5Cg5eOpY3X`%}bB50*dVY+^X8L&SGP zL%iOuVo@9Kf4Lo$X~<5N_Xj!&FsM_Kz@ws=rlH0mKzC%j&#Gi_9|B13>pUU@TEm~ZHfgk=J}L*bKZz|W_#A; zv&DnG!SX^ywPj9$_azE94B@-m$uH7*yVtgzjuU|=lCmKmt8`#KE|9s<* zx%&A(Dtc51qW-VY93z;O2&?i?>_XIK93p-x4ukXXx9CRs^8nVaukUhWG^N9{D!|S; zuj}mh^LIvxU)!uly(IKfXHNo=+2wTOohCU}tP(N#mGq*fPNRd1v`Nvgz^%Ud?|G<#C>g%_8v~Wst z$;v{EEjy&9-r;MYO8l!9Z|6AT69{=WZD`VTuNx+OwzqSSv~fnK#&(NkzhS?p5xq_a&%~!V?bmIoU{Y+7UZsab5{K4Q zyQ79xRoNsoQrLz7;``ju?IovA=&1zFN&MfjyC$G4k$||hJc50SlA?5XKw_*_wnhrraYoE45S0z>XvC*WIU^$8!-9uXY`Bmu#}5t)BSI*i~;Q&@uE zU9Upb#H4Jdto6p@p5%HB`VNsx_V0m;IcS%y`BHi#ob*k)kzH0fAKwK^ZhJkUb$K+;RP~pb7h&+FAh~^Vk@+ zP(l4(kTjj)A&O26OFXSn7nG$c|NI~s>ih5msT9q>wRG_owa>kFy6VlPsCv`H+XPka zQvFI;Te^o4kIvgeeWRdom(LX#xH%Dx?=_^3x}3FRjj2X^_I>W}*b`{wk1FYTH~Fi* z+2&od^Sgr6B9eYzw$XTabxo{l3Pw#XY~(aXp9I`lFd%S&jhn_fZie{#68rj}f{J1L z{$aCy$w~tgv!<2(t+oFYrQb4+{UNgUAItdZ{}AL@LWc4+*9M$A=V$CF(HW{N@H=b_ zaUcyreOc=yTgMc71+wacZiUj%QHO8*t%`w@b2p;%pS(9wq}!5&(HfZF#~7=P_f1yL zUkR)EeDrF}|ESL#deNKbJ0Ar!*-CC7j{NLA9v;x(Jatr?S6RGk3vQ}wDhkndjgva< z5KB38Vd~5wkz)=TYqYI!am6tcvYSE;HVNLB{csKXABeT9h0MPDq!1-qLMhQExRhte z(@eQm-Tt$`o$lcVW0w#Yl)OVW{U~keY=drGTTV&)=FaVexH~$q>gm?rPhi@LL)@qn zYWkT#QEFI@<94S=L*~H+Krp6Q(4OBMlRLlN^~Gz5jE->u87olwct2V8Hj*=-21h0r1ajHRv~hVnOywJvv!QTnz(hxNadCL zGCw*jjKFv6%Nf>m%bPW=>6pfqtaT~CSm6}lKauD+$pp!}s4E85jTel1itf=)hEF-K zvSle&f$oq9qcfq3=dAytzu^Wx7ts z(6dij6su6iwm5L&zC8iNvIN@LGJuc*V|n5@<0m)y!9Hwjl4DFK0z%aS3-uI$+^B@6 zr&fe88OG#xBzSBmDO(|5;UkRfw7ogCYM=vIy{fyu%kf~Yqfkh# zgxT8ThzDPpn@OMbvCoFBvR`g?W-8W`_@tLg0p3YH0%drLe&A$ZR8U}os2*))=wEYx z1_@#4hYj10J~ocYL>$>N)D%hzDmaD~*KhTG}OiH zDWf>A>}Ckme*sVeLZ2qgKIoe)ghJ)Iik}Tp!dX$jP)+fayKe2a-7JTK|g%>#)7HVTtkWDz6wm2ioIpB5d91BtIkbUZvC!v z%QgbKa|m@9bS3Aq^BXseerBmy_*DM6U!`1^|7*@2kf1)<3o8l>O&Y> zntgwSjh$B?KD;mQNJ>S+boNq1_zyJKvuo+$-yj5NK zgq2b?kKY*wMuXMfUoIUkfG#&no7{YNQe8bTYiCI(A50RnL0P$-uF-y?&2TiJd8*UM zGEMr)c>t@6F6oS+><#0&h!lc`3!MJX+9P)|j(4Mi{#XghH~p2x=L*zwn-#K_jwDKR zp+xH1;D;35!~6a1IX%`vpIsaZX6yQgnGkxL7I<(29jGFhjFYf6OiyfW3ZI5Lop@h4 zCQQk4Q2x}U$aBd}gFOx9j&5O-T??`f_YrO^`pkKPLMk`&Jo_r@uVTn(#Y^CW!b!bjmMxN~ds}UK{8ghtW>aG;SF*kAL_0 z5L>+Q4)KQ`D7_|1FsmmRh&sYY;HvjD= zyem_o;H{U6>(&bOVSJs3deDoS<8N4YTq=!Yuvg zQ=wjes_lSZ3C10WccGNfZL&~hukr-z-;5FLbBcR8uLrKJHblC@h_TW`(AsrdyeW4) z?fK+kLt@1F7oU!}2)>vdAXMFb(&o&usPCvAVuy;TLTWGQ7EHIOBRCr;lYU*fo!}f| z+hI7TpCii)-iObt*sZZ9oF(lw(S26JjgFn)KilXpB)C7+)itCQ#m~CYD>kRwzkw!Y zw%gE{R@AXoTUf)w>ES9smBmzB*B?5UkMrw}R|_Lmsw-E$|FBRBnmPrU2feUwGu^KQ zfFZvBzz1$foDs3nkPx=`JFXuCmaEFY2i7fJG-T>l+37?UUWC@laHx4gd`l7`p+CL| za^-?J#|;0nIrkDrZzF^(2Vo7Eh)}p}kW=%iZkgn_-ScW#enw&1ZA za4fd|adchZjbOErU;5Fs8x66Miok;!H|-x~OSn0yA#kV+JEz$mwmaqBL#XG?Yeh;8 zq2897eyiIjNE_!jz^a#e6v{jA{>9-{{BDsa$Kb5v8$D6AP(UU@4>zBMfUBP*o8`0t zMNR{J8j%72zcCS6!_QeH9qn4}wc8i_tmIZ$@G5&11zIzekTp9_OwrP7iz#O&GgBEa zm4LE1QSvJ4ys;17lN3@Vgf}t;%EC49I$5V|5_S)$3BO}|wbj+TY5_-de%s{$C>qdm zrO4OF^l-ZhW4JR?{_IFVOa7ptO||_5>QD2h!SV+$DJ0kXP;a!i8vwFdb|fTYG2?|| zjm-5^fcHjAdpt86RY^Z~=j-Z2WuVIz1~1fjP85CpQhvwP;-A*o1V`pBL7i&dizO1k ze$Aw4!fj9Za_nG#eU(4^jQ!X0^(kptUM84&vq8>v?NZcC1un3>VI>3b`j4k=B2P)EI0O?rwZ=|MRD`9@}WZ;AW2|Hbn? zdHUA`20Ah7F>&PA>SIXG=LX6{6e?KIJ6BLy_ z0~-rTO@CPgOx$OC9lT%sb98K0m{P7_zqeHOK^EwCDYGcMID&!^rJN!Sa}3gd9dbWW zwgYPIrjS-LVeLIq+eHE)djh0h>aq3>HST-R_aGJSbN~#mI0CT7_E`P~A(D4Qivdc^ zq;B*tV1R+PzyYh}r<_S7Kq*7GP~gd35mPY+5>!eM1k}u}-=r#oTUIOv0DoWKd}Sp` zY2U|l1z_4JZoCM=8s9a45P-$}*7;r-Z(ev=_J6U4sKXkXWAv<>h;#k#DmJ@PN?IwG zLkXStYQ2lT1azades9r)>h+&G$;tW7gfKwa8{B7)f}!-N4G-k2W6G1mBI*5yR4Rpb zBAR4n2u&`iudA-D6RCX_hzg@Ml*qi=o}6#L3=vMbcb}=CCD1Lho&lJMEtl#3$k{}^ zo*dX*+NgZo$mQfRgMwE%$RcaU*a59-`TmZ_9lAUWKOn1}}7-ftnPP_RsMOL7wd61j^ZvPeqz`^)dL058qo)VKFPMB9DnTnO7)-7)w! z^s7UkBqdHIz#V&b>t1VIEIlXYQTw42nN-de7&OT+y=>*9v?=q>IR+{|d9!`?b4{Ot z)NAS;_gPor%|*?ZG21|uu|(r3OW3Q3Im=fRk5@p_0-2;E2rMUI&fN5pP` zOpV8_-97)9jxzVsd~&4wW0g;73;WZi%_aN*VsmBVh(jyrBseScUiiep*8gd_9^G9g z(yV_BwVb5zpfW4KG_5$ylGkCxa(aWMz_>VAh=fNhJy4}LBEzRW9v+n+j4786p5d`> z?B98I8$&!l>@qB~WxuOWfGrhVVa3DCc2=Su{7|ErH)X}c#OzcZ4G$x0rt9{b2Z|$( z)69$MeH!H9aH31g@g$g{o$3b##!@r`6UQg;h1my;<&t1O^VSz-N6X*LKmswUC?}#Q zi80X@|Fukt$h$WNFI*61#iK)cOeOBmXrgCqM$wy&ZD*Xd*($xX*{1$%$qUU%6F!&* zJ+~Bt+0@Zo>&pJYG@FW08eUnA5MxdXoYz`fD7cmJSmI~1)BJ1Y?;{*|%L^5=czGk< ck6mkVJ{)FXgo2O#b~gvsmUb3&bI%+90%6jGHUIzs literal 0 HcmV?d00001 From 8cef58b110b8132b606265f109b2017698521ce6 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Wed, 27 Apr 2022 20:45:30 +0100 Subject: [PATCH 03/82] Rename Readme to README --- apps/timersimple/{Readme.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/timersimple/{Readme.md => README.md} (100%) diff --git a/apps/timersimple/Readme.md b/apps/timersimple/README.md similarity index 100% rename from apps/timersimple/Readme.md rename to apps/timersimple/README.md From d320b91a301f617399eb9f45f9ddda90be08ef53 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Thu, 28 Apr 2022 00:09:48 -0700 Subject: [PATCH 04/82] Delete app-icon.js --- apps/quicklaunch/app-icon.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 apps/quicklaunch/app-icon.js diff --git a/apps/quicklaunch/app-icon.js b/apps/quicklaunch/app-icon.js deleted file mode 100644 index 14ae94823..000000000 --- a/apps/quicklaunch/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("kMigILIgPAAYMD/ADBwcGhkAwM5wcA/+2//Av/Rn/giFoyFggkUrFggEKlAkCiApCx+AAYNGoADBkU4AYMQj4DBvEICANkAoIPBgE2B4MAiMAH4MAwECAYNALYUgBIISCHYMYAoQWBAIMEgAYBAIMBwEDDQNgDwUf/4eBg4DCAA4")) From 9bf2ea6b39d684c487f9269131dd363985dc6ad8 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Thu, 28 Apr 2022 00:09:54 -0700 Subject: [PATCH 05/82] Delete app.js --- apps/quicklaunch/app.js | 120 ---------------------------------------- 1 file changed, 120 deletions(-) delete mode 100644 apps/quicklaunch/app.js diff --git a/apps/quicklaunch/app.js b/apps/quicklaunch/app.js deleted file mode 100644 index f2b749e3e..000000000 --- a/apps/quicklaunch/app.js +++ /dev/null @@ -1,120 +0,0 @@ -var settings = Object.assign(require("Storage").readJSON("quicklaunch.json", true) || {}); - -var apps = require("Storage").list(/\.info$/).map(app=>{var a=require("Storage").readJSON(app,1);return a&&{name:a.name,type:a.type,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="launch" || app.type=="clock" || !app.type)); - -apps.sort((a,b)=>{ - var n=(0|a.sortorder)-(0|b.sortorder); - if (n) return n; // do sortorder first - if (a.nameb.name) return 1; - return 0; -}); - -function save(key, value) { - settings[key] = value; - require("Storage").write("quicklaunch.json",settings); -} - -// Quick Launch menu -function showMainMenu() { - var mainmenu = { - "" : { "title" : "Quick Launch" }, - "< Back" : ()=>{load();} - }; - - //List all selected apps - mainmenu["Left: "+settings.leftapp.name] = function() { E.showMenu(leftmenu); }; - mainmenu["Right: "+settings.rightapp.name] = function() { E.showMenu(rightmenu); }; - mainmenu["Up: "+settings.upapp.name] = function() { E.showMenu(upmenu); }; - mainmenu["Down: "+settings.downapp.name] = function() { E.showMenu(downmenu); }; - mainmenu["Tap: "+settings.tapapp.name] = function() { E.showMenu(tapmenu); }; - - return E.showMenu(mainmenu); -} - -//Left swipe menu -var leftmenu = { - "" : { "title" : "Left Swipe" }, - "< Back" : showMainMenu -}; - -leftmenu["(none)"] = function() { - save("leftapp", {"name":"(none)"}); - showMainMenu(); -}; -apps.forEach((a)=>{ - leftmenu[a.name] = function() { - save("leftapp", a); - showMainMenu(); - }; -}); - -//Right swipe menu -var rightmenu = { - "" : { "title" : "Right Swipe" }, - "< Back" : showMainMenu -}; - -rightmenu["(none)"] = function() { - save("rightapp", {"name":"(none)"}); - showMainMenu(); -}; -apps.forEach((a)=>{ - rightmenu[a.name] = function() { - save("rightapp", a); - showMainMenu(); - }; -}); - -//Up swipe menu -var upmenu = { - "" : { "title" : "Up Swipe" }, - "< Back" : showMainMenu -}; - -upmenu["(none)"] = function() { - save("upapp", {"name":"(none)"}); - showMainMenu(); -}; -apps.forEach((a)=>{ - upmenu[a.name] = function() { - save("upapp", a); - showMainMenu(); - }; -}); - -//Down swipe menu -var downmenu = { - "" : { "title" : "Down Swipe" }, - "< Back" : showMainMenu -}; - -downmenu["(none)"] = function() { - save("downapp", {"name":"(none)"}); - showMainMenu(); -}; -apps.forEach((a)=>{ - downmenu[a.name] = function() { - save("downapp", a); - showMainMenu(); - }; -}); - -//Tap menu -var tapmenu = { - "" : { "title" : "Tap" }, - "< Back" : showMainMenu -}; - -tapmenu["(none)"] = function() { - save("tapapp", {"name":"(none)"}); - showMainMenu(); -}; -apps.forEach((a)=>{ - tapmenu[a.name] = function() { - save("tapapp", a); - showMainMenu(); - }; -}); - -showMainMenu(); From 4c100e77e48bb72af037527e59691e3c106f06ba Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Thu, 28 Apr 2022 00:10:50 -0700 Subject: [PATCH 06/82] Add files via upload --- apps/quicklaunch/settings.js | 122 +++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 apps/quicklaunch/settings.js diff --git a/apps/quicklaunch/settings.js b/apps/quicklaunch/settings.js new file mode 100644 index 000000000..ac4cc5805 --- /dev/null +++ b/apps/quicklaunch/settings.js @@ -0,0 +1,122 @@ +(function(back) { +var settings = Object.assign(require("Storage").readJSON("quicklaunch.json", true) || {}); + +var apps = require("Storage").list(/\.info$/).map(app=>{var a=require("Storage").readJSON(app,1);return a&&{name:a.name,type:a.type,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="launch" || app.type=="clock" || !app.type)); + +apps.sort((a,b)=>{ + var n=(0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.nameb.name) return 1; + return 0; +}); + +function save(key, value) { + settings[key] = value; + require("Storage").write("quicklaunch.json",settings); +} + +// Quick Launch menu +function showMainMenu() { + var mainmenu = { + "" : { "title" : "Quick Launch" }, + "< Back" : ()=>{load();} + }; + + //List all selected apps + mainmenu["Left: "+settings.leftapp.name] = function() { E.showMenu(leftmenu); }; + mainmenu["Right: "+settings.rightapp.name] = function() { E.showMenu(rightmenu); }; + mainmenu["Up: "+settings.upapp.name] = function() { E.showMenu(upmenu); }; + mainmenu["Down: "+settings.downapp.name] = function() { E.showMenu(downmenu); }; + mainmenu["Tap: "+settings.tapapp.name] = function() { E.showMenu(tapmenu); }; + + return E.showMenu(mainmenu); +} + +//Left swipe menu +var leftmenu = { + "" : { "title" : "Left Swipe" }, + "< Back" : showMainMenu +}; + +leftmenu["(none)"] = function() { + save("leftapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + leftmenu[a.name] = function() { + save("leftapp", a); + showMainMenu(); + }; +}); + +//Right swipe menu +var rightmenu = { + "" : { "title" : "Right Swipe" }, + "< Back" : showMainMenu +}; + +rightmenu["(none)"] = function() { + save("rightapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + rightmenu[a.name] = function() { + save("rightapp", a); + showMainMenu(); + }; +}); + +//Up swipe menu +var upmenu = { + "" : { "title" : "Up Swipe" }, + "< Back" : showMainMenu +}; + +upmenu["(none)"] = function() { + save("upapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + upmenu[a.name] = function() { + save("upapp", a); + showMainMenu(); + }; +}); + +//Down swipe menu +var downmenu = { + "" : { "title" : "Down Swipe" }, + "< Back" : showMainMenu +}; + +downmenu["(none)"] = function() { + save("downapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + downmenu[a.name] = function() { + save("downapp", a); + showMainMenu(); + }; +}); + +//Tap menu +var tapmenu = { + "" : { "title" : "Tap" }, + "< Back" : showMainMenu +}; + +tapmenu["(none)"] = function() { + save("tapapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + tapmenu[a.name] = function() { + save("tapapp", a); + showMainMenu(); + }; +}); + +showMainMenu(); +}); \ No newline at end of file From 5b5ded5c56fca6ab5095cd9737ee802e483c90b5 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Thu, 28 Apr 2022 00:11:39 -0700 Subject: [PATCH 07/82] Update ChangeLog --- apps/quicklaunch/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/quicklaunch/ChangeLog b/apps/quicklaunch/ChangeLog index ec66c5568..ae1d4a848 100644 --- a/apps/quicklaunch/ChangeLog +++ b/apps/quicklaunch/ChangeLog @@ -1 +1,2 @@ 0.01: Initial version +0.02: Moved settings from launcher to settings->apps menu From 80f32ea7f38a8b8afc432e94af631e0ac6f5b045 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Thu, 28 Apr 2022 00:12:29 -0700 Subject: [PATCH 09/82] Update metadata.json --- apps/quicklaunch/metadata.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/quicklaunch/metadata.json b/apps/quicklaunch/metadata.json index 6411d1a5f..b14a950c6 100644 --- a/apps/quicklaunch/metadata.json +++ b/apps/quicklaunch/metadata.json @@ -1,14 +1,15 @@ -{ "id": "quicklaunch", +{ + "id": "quicklaunch", "name": "Quick Launch", "icon": "app.png", - "version":"0.01", - "description": "Tap or swipe left/right/up/down on your clock face to launch up to five apps of your choice.", + "version":"0.02", + "description": "Tap or swipe left/right/up/down on your clock face to launch up to five apps of your choice. Configurations can be accessed through Settings->Apps.", + "type": "launch", "tags": "tools, system", "supports": ["BANGLEJS2"], "storage": [ - {"name":"quicklaunch.app.js","url":"app.js"}, - {"name":"quicklaunch.boot.js","url":"boot.js"}, - {"name":"quicklaunch.img","url":"app-icon.js","evaluate":true} + {"name":"quicklaunch.settings.js","url":"settings.js"}, + {"name":"quicklaunch.boot.js","url":"boot.js"} ], "data": [{"name":"quicklaunch.json"}] } From 966acedd0cc3ab14ba51085e5d08317c52890b0b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 28 Apr 2022 10:14:10 +0100 Subject: [PATCH 10/82] URL matching when hyphens in github username --- loader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader.js b/loader.js index ee7b584a2..42db3f430 100644 --- a/loader.js +++ b/loader.js @@ -25,7 +25,7 @@ DEVICEINFO = DEVICEINFO.filter(x=>x.id.startsWith("BANGLEJS")); // Set up source code URL (function() { let username = "espruino"; - let githubMatch = window.location.href.match(/\/(\w+)\.github\.io/); + let githubMatch = window.location.href.match(/\/([\w-]+)\.github\.io/); if (githubMatch) username = githubMatch[1]; Const.APP_SOURCECODE_URL = `https://github.com/${username}/BangleApps/tree/master/apps`; })(); From bb0aa17d4a11a09dff40c090de9d263741942596 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Thu, 28 Apr 2022 12:08:06 +0100 Subject: [PATCH 11/82] Changes after feedback Feedback in forum here: http://forum.espruino.com/conversations/375342 --- apps/timersimple/timersimple.app.js | 53 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/apps/timersimple/timersimple.app.js b/apps/timersimple/timersimple.app.js index ddc6bb4c1..8bbe66e83 100644 --- a/apps/timersimple/timersimple.app.js +++ b/apps/timersimple/timersimple.app.js @@ -1,5 +1,3 @@ -Modules.addCached("Layout",function(){function Layout(d,b){function e(a){a.id&&(h[a.id]=a),a.type||(a.type=''),a.c&&a.c.forEach(e)}this._l=this.l=d,this.physBtns=process.env.HWVERSION==2?1:3,b=b||{},this.lazy=b.lazy||!1;var c,f;if(Bangle.setUI(),process.env.HWVERSION!=2){c=[];function a(b){b.type=='btn'&&c.push(b),b.c&&b.c.forEach(a)}a(d),c.length&&(this.physBtns=0,this.buttons=c,this.selectedButton=-1,Bangle.setUI({mode:'updown',back:b.back},c=>{var a=this.selectedButton,b=this.buttons.length;if(c===undefined&&this.buttons[a])return this.buttons[a].cb();this.buttons[a]&&(delete this.buttons[a].selected,this.render(this.buttons[a])),a=(a+b+c)%b,this.buttons[a]&&(this.buttons[a].selected=1,this.render(this.buttons[a])),this.selectedButton=a}),f=!0)}if(b.back&&!f&&Bangle.setUI({mode:'custom',back:b.back}),b.btns){var a=b.btns;if(this.b=a,this.physBtns>=a.length){function b(a,b){b.time-b.lastTime>.75&&this.b[a].cbl?this.b[a].cbl(b):this.b[a].cb&&this.b[a].cb(b)}let c=Math.floor(Bangle.appRect.h/this.physBtns);Bangle.btnWatches&&Bangle.btnWatches.forEach(clearWatch),Bangle.btnWatches=[],this.physBtns>2&&a.length==1&&a.unshift({label:''});while(this.physBtns>a.length)a.push({label:''});a[0]&&Bangle.btnWatches.push(setWatch(b.bind(this,0),BTN1,{repeat:!0,edge:-1})),a[1]&&Bangle.btnWatches.push(setWatch(b.bind(this,1),BTN2,{repeat:!0,edge:-1})),a[2]&&Bangle.btnWatches.push(setWatch(b.bind(this,2),BTN3,{repeat:!0,edge:-1})),this._l.width=g.getWidth()-8,this._l={type:'h',filly:1,c:[this._l,{type:'v',pad:1,filly:1,c:a.map(a=>(a.type='txt',a.font='6x8',a.height=c,a.r=1,a))}]}}else this._l.width=g.getWidth()-32,this._l={type:'h',c:[this._l,{type:'v',c:a.map(a=>(a.type='btn',a.filly=1,a.width=32,a.r=1,a))}]},c&&c.push.apply(c,this._l.c[1].c)}if(process.env.HWVERSION==2){function a(b,c){b.cb&&c.x>=b.x&&c.y>=b.y&&c.x<=b.x+b.w&&c.y<=b.y+b.h&&(c.type==2&&b.cbl?b.cbl(c):b.cb&&b.cb(c)),b.c&&b.c.forEach(b=>a(b,c))}Bangle.touchHandler=(c,b)=>a(this._l,b),Bangle.on('touch',Bangle.touchHandler)}var h=this;e(this._l),this.updateNeeded=!0}function prepareLazyRender(a,h,b,i,c){var d=a.bgCol==null?c:g.toColor(a.bgCol);if(d!=c||a.type=='txt'||a.type=='btn'||a.type=='img'||a.type=='custom'){var e=a.c;delete a.c;var f='H'+E.CRC32(E.toJS(a));if(e&&(a.c=e),!delete h[f]){var j=i[f]=[a.x,a.y,a.x+a.w-1,a.y+a.h-1];j.bg=c==null?g.theme.bg:c,b&&(b.push(a),b=null)}}if(a.c)for(var k of a.c)prepareLazyRender(k,h,b,i,d)}Layout.prototype.remove=function(a){Bangle.btnWatches&&(Bangle.btnWatches.forEach(clearWatch),delete Bangle.btnWatches),Bangle.touchHandler&&(Bangle.removeListener('touch',Bangle.touchHandler),delete Bangle.touchHandler)},Layout.prototype.render=function(b){function c(a){"ram";g.reset(),a.col!==undefined&&g.setColor(a.col),a.bgCol!==undefined&&g.setBgColor(a.bgCol).clearRect(a.x,a.y,a.x+a.w-1,a.y+a.h-1),f[a.type](a)}b||(b=this._l),this.updateNeeded&&this.update();var f={'':function(){},txt:function(a){if(a.wrap){g.setFont(a.font).setFontAlign(0,-1);var b=g.wrapString(a.label,a.w),c=a.y+(a.h-g.getFontHeight()*b.length>>1);b.forEach((b,d)=>g.drawString(b,a.x+(a.w>>1),c+g.getFontHeight()*d))}else g.setFont(a.font).setFontAlign(0,0,a.r).drawString(a.label,a.x+(a.w>>1),a.y+(a.h>>1))},btn:function(a){var b=a.x+(0|a.pad),c=a.y+(0|a.pad),d=a.w-(a.pad<<1),e=a.h-(a.pad<<1),f=[b,c+4,b+4,c,b+d-5,c,b+d-1,c+4,b+d-1,c+e-5,b+d-5,c+e-1,b+4,c+e-1,b,c+e-5,b,c+4],h=a.selected?g.theme.bgH:g.theme.bg2;g.setColor(h).fillPoly(f).setColor(a.selected?g.theme.fgH:g.theme.fg2).drawPoly(f),a.col!==undefined&&g.setColor(a.col),a.src?g.setBgColor(h).drawImage('f'==(typeof a.src)[0]?a.src():a.src,a.x+10+(0|a.pad),a.y+8+(0|a.pad)):g.setFont('6x8',2).setFontAlign(0,0,a.r).drawString(a.label,a.x+a.w/2,a.y+a.h/2)},img:function(a){g.drawImage('f'==(typeof a.src)[0]?a.src():a.src,a.x+(0|a.pad),a.y+(0|a.pad),a.scale?{scale:a.scale}:undefined)},custom:function(a){a.render(a)},h:function(a){a.c.forEach(c)},v:function(a){a.c.forEach(c)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),d=[];prepareLazyRender(b,a,d,this.rects,null);for(var h in a)delete this.rects[h];var i=Object.keys(a).map(b=>a[b]).reverse();for(var e of i)g.setBgColor(e.bg).clearRect.apply(g,e);d.forEach(c)}else c(b)},Layout.prototype.forgetLazyState=function(){this.rects={}},Layout.prototype.layout=function(a){switch(a.type){case'h':{var b=a.x+(0|a.pad),h=0,d=a.c&&a.c.reduce((a,b)=>a+(0|b.fillx),0);d||(b+=a.w-a._w>>1,d=1);var e=b;a.c.forEach(c=>{c.x=0|e,b+=c._w,h+=0|c.fillx,e=b+Math.floor(h*(a.w-a._w)/d),c.w=0|e-c.x,c.h=0|(c.filly?a.h-(a.pad<<1):c._h),c.y=0|a.y+(0|a.pad)+((1+(0|c.valign))*(a.h-(a.pad<<1)-c.h)>>1),c.c&&this.layout(c)});break}case'v':{var c=a.y+(0|a.pad),i=0,f=a.c&&a.c.reduce((a,b)=>a+(0|b.filly),0);f||(c+=a.h-a._h>>1,f=1);var g=c;a.c.forEach(b=>{b.y=0|g,c+=b._h,i+=0|b.filly,g=c+Math.floor(i*(a.h-a._h)/f),b.h=0|g-b.y,b.w=0|(b.fillx?a.w-(a.pad<<1):b._w),b.x=0|a.x+(0|a.pad)+((1+(0|b.halign))*(a.w-(a.pad<<1)-b.w)>>1),b.c&&this.layout(b)});break}}},Layout.prototype.debug=function(a,b){a||(a=this._l),b=b||1,g.setColor(b&1,b&2,b&4).drawRect(a.x+b-1,a.y+b-1,a.x+a.w-b,a.y+a.h-b),a.pad&&g.drawRect(a.x+a.pad-1,a.y+a.pad-1,a.x+a.w-a.pad,a.y+a.h-a.pad),b++,a.c&&a.c.forEach(a=>this.debug(a,b))},Layout.prototype.update=function(){function b(a){"ram";if(c[a.type](a),a.r&1){var b=a._w;a._w=a._h,a._h=b}a._w=0|Math.max(a._w+(a.pad<<1),0|a.width),a._h=0|Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var c={txt:function(a){if(a.font.endsWith('%')&&(a.font='Vector'+Math.round(g.getHeight()*a.font.slice(0,-1)/100)),a.wrap)a._h=a._w=0;else{var b=g.setFont(a.font).stringMetrics(a.label);a._w=b.width,a._h=b.height}},btn:function(a){var b=a.src?g.imageMetrics('f'==(typeof a.src)[0]?a.src():a.src):g.setFont('6x8',2).stringMetrics(a.label);a._h=16+b.height,a._w=20+b.width},img:function(a){var b=g.imageMetrics('f'==(typeof a.src)[0]?a.src():a.src),c=a.scale||1;a._w=b.width*c,a._h=b.height*c},'':function(a){a._w=0,a._h=0},custom:function(a){a._w=0,a._h=0},h:function(a){a.c.forEach(b),a._h=a.c.reduce((a,b)=>Math.max(a,b._h),0),a._w=a.c.reduce((a,b)=>a+b._w,0),a.fillx==null&&a.c.some(a=>a.fillx)&&(a.fillx=1),a.filly==null&&a.c.some(a=>a.filly)&&(a.filly=1)},v:function(a){a.c.forEach(b),a._h=a.c.reduce((a,b)=>a+b._h,0),a._w=a.c.reduce((a,b)=>Math.max(a,b._w),0),a.fillx==null&&a.c.some(a=>a.fillx)&&(a.fillx=1),a.filly==null&&a.c.some(a=>a.filly)&&(a.filly=1)}},a=this._l;b(a),a.fillx||a.filly?(a.w=Bangle.appRect.w,a.h=Bangle.appRect.h,a.x=Bangle.appRect.x,a.y=Bangle.appRect.y):(a.w=a._w,a.h=a._h,a.x=Bangle.appRect.w-a.w>>1,a.y=Bangle.appRect.y+(Bangle.appRect.h-a.h>>1)),this.layout(a)},Layout.prototype.clear=function(a){a||(a=this._l),g.reset(),a.bgCol!==undefined&&g.setBgColor(a.bgCol),g.clearRect(a.x,a.y,a.x+a.w-1,a.y+a.h-1)},exports=Layout}); - const secondsToTime = (s) => new Object({h:Math.floor((s/3600) % 24), m:Math.floor((s/60) % 60), s:Math.floor(s % 60)}); const clamp = (num, min, max) => Math.min(Math.max(num, min), max); function formatTime(s) { @@ -10,12 +8,13 @@ function formatTime(s) { return t.m + ':' + ("0" + t.s).substr(-2); } } +const timerID = "simpletimer"; Bangle.loadWidgets(); Bangle.drawWidgets(); var Layout = require("Layout"); -var seconds = 5 * 60; +var seconds = 5 * 60; // Default to 5 minutes var drawTimeout; var timerLayout; var timePickerLayout; @@ -42,15 +41,17 @@ xxx xxx xxx xxx `); +const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/w=="); +const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); + function onDrag(event) { - var scale = 1; + var diff = -Math.round(event.dy/5); if (event.x < timePickerLayout.hours.w) { - scale = 3600; + diff *= 3600; } else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) { - scale = 60; + diff *= 60; } - seconds -= Math.round(event.dy/5) * scale; - updateTimePicker(); + updateTimePicker(diff); } function onTouch(button, xy) { @@ -69,12 +70,11 @@ function onTouch(button, xy) { } else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) { diff *= 60; } - seconds += diff; - updateTimePicker(); + updateTimePicker(diff); } -function updateTimePicker() { - seconds = clamp(seconds, 0, 24 * 3600 - 1); +function updateTimePicker(diff) { + seconds = clamp(seconds + (diff || 0), 0, 24 * 3600 - 1); var set_time = secondsToTime(seconds); updateLayoutField(timePickerLayout, 'hours', set_time.h); updateLayoutField(timePickerLayout, 'mins', set_time.m); @@ -88,10 +88,10 @@ function updateLayoutField(layout, field, value) { } function updateTimer() { - var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm("simpletimer")); - var d = new Date(); + var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000)); - updateLayoutField(timerLayout, 'time', require("locale").time(d,1)); + //var d = new Date(); + //updateLayoutField(timerLayout, 'time', require("locale").time(d,1)); queueDraw(1000); } @@ -106,8 +106,8 @@ function queueDraw(millisecs) { function timerStop() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - seconds = require("sched").getTimeToAlarm(require("sched").getAlarm("simpletimer")) / 1000; - require("sched").setAlarm("simpletimer", undefined); + seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000; + require("sched").setAlarm(timerID, undefined); require("sched").reload(); runTimePicker(); } @@ -136,20 +136,20 @@ var timePickerLayoutCode = { {type:"img", pad:8, src:imgArrowDown, col:g.theme.fg2} ]}, ]}, - {type:"btn", font:"12x20", label:"Start", id:"btnStart", fillx:1 } + {type:"btn", src:imgPlay, id:"btnStart", fillx:1 } ], filly:1 }; var timerLayoutCode = { type:"v", c: [ {type:undefined, height:8}, - {type:"txt", font:"6x8", label:/*LANG*/"Timer", id:"title", col:g.theme.fg2}, + //{type:"txt", font:"6x8", label:/*LANG*/"Timer", id:"title", col:g.theme.fg2}, {type:"txt", font:"22%", label:"0:00", id:"timer", fillx:1, filly:1 }, - {type:"h", c: [ - {type:"txt", font:"6x8", pad:8, label:/*LANG*/"Time Now:", halign:-1, col:g.theme.fg2}, - {type:"txt", font:"6x8", label:"00:00", id:"time", halign:1, col:g.theme.fg2}, - ]}, - {type:"btn", font:"12x20", label:"Stop", cb: l=>timerStop(), fillx:1 } + //{type:"h", c: [ + // {type:"txt", font:"6x8", pad:8, label:/*LANG*/"Time Now:", halign:-1, col:g.theme.fg2}, + // {type:"txt", font:"6x8", label:"00:00", id:"time", halign:1, col:g.theme.fg2}, + //]}, + {type:"btn", src:imgPause, cb: l=>timerStop(), fillx:1 } ], filly:1 }; @@ -167,8 +167,7 @@ function runTimePicker() { } function runTimer() { - require("sched").setAlarm("simpletimer", { - //msg : "Mr Flibble is very angry!", + require("sched").setAlarm(timerID, { vibrate : ".-.-", hidden: true, timer : seconds * 1000 @@ -180,7 +179,7 @@ function runTimer() { updateTimer(); } -var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm("simpletimer")); +var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); if (timeToNext != undefined) { g.clearRect(Bangle.appRect); timerLayout = new Layout(timerLayoutCode); From 1dbcbd47f82652348f7df3cbd94cf86a7b72676d Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 17:57:39 -0400 Subject: [PATCH 12/82] Fix true wind computation bug, add swipe gesture to pause GPS --- apps/openwind/ChangeLog | 1 + apps/openwind/README.md | 4 ++- apps/openwind/app.js | 72 ++++++++++++++++++++++++------------- apps/openwind/metadata.json | 2 +- 4 files changed, 53 insertions(+), 26 deletions(-) diff --git a/apps/openwind/ChangeLog b/apps/openwind/ChangeLog index 5560f00bc..1e5f791b2 100644 --- a/apps/openwind/ChangeLog +++ b/apps/openwind/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Fix true wind computation, add swipe gesture to pause GPS diff --git a/apps/openwind/README.md b/apps/openwind/README.md index 1df7ea158..c03ec1401 100644 --- a/apps/openwind/README.md +++ b/apps/openwind/README.md @@ -14,7 +14,9 @@ additionally displayed in red. In this mode, the speed over ground in knots is ## Controls -There are no controls in the main app, but there are two settings in the settings app that can be changed: +In the main app, when true wind mode is enabled (see below), swiping left on the screen will temporarily disable GPS (to preserve battery); a small +red satellite symbol will appear on the bottom right. Swiping right will turn GPS back on. +The settings app provides the following two settings: * True wind: enables or disables true wind calculations; enabling this will turn on GPS inside the app * Mounting angle: mounting relative to the boat of the wind instrument (in degrees) diff --git a/apps/openwind/app.js b/apps/openwind/app.js index b1c8fea4b..ca837defa 100644 --- a/apps/openwind/app.js +++ b/apps/openwind/app.js @@ -1,16 +1,20 @@ OW_CHAR_UUID = '0000cc91-0000-1000-8000-00805f9b34fb'; require("Font7x11Numeric7Seg").add(Graphics); -gatt = {}; -cx = g.getWidth()/2; -cy = 24+(g.getHeight()-24)/2; -w = (g.getWidth()-24)/2; - -gps_course = { spd: 0 }; +var gatt = {}; +var cx = g.getWidth()/2; +var cy = 24+(g.getHeight()-24)/2; +var w = (g.getWidth()-24)/2; +var y1 = 24; +var y2 = g.getHeight()-1; +var gps_course = { spd: 0 }; +var course_marker_len = g.getWidth()/4; var settings = require("Storage").readJSON('openwindsettings.json', 1) || {}; -i = 0; -hullpoly = []; +var pause_gps = false; + +var i = 0; +var hullpoly = []; for (y=-1; y<=1; y+=0.1) { hullpoly[i++] = cx - (y<0 ? 1+y*0.15 : (Math.sqrt(1-0.7*y*y)-Math.sqrt(0.3))/(1-Math.sqrt(0.3)))*w*0.3; hullpoly[i++] = cy - y*w*0.7; @@ -22,21 +26,22 @@ for (y=1; y>=-1; y-=0.1) { function wind_updated(ev) { if (ev.target.uuid == "0xcc91") { - awa = settings.mount_angle-ev.target.value.getInt16(1, true)*0.1; + awa = settings.mount_angle+ev.target.value.getInt16(1, true)*0.1; + if (awa<0) awa += 360; aws = ev.target.value.getInt16(3, true)*0.01; -// console.log(awa, aws); + //console.log(awa, aws); if (gps_course.spd > 0) { - wv = { // wind vector (in fixed reference frame) - lon: Math.sin(Math.PI*(gps_course.course+awa)/180)*aws, - lat: Math.cos(Math.PI*(gps_course.course+awa)/180)*aws + wv = { // wind vector (in "earth" reference frame) + vlon: Math.sin(Math.PI*(gps_course.course+(awa+180))/180)*aws, + vlat: Math.cos(Math.PI*(gps_course.course+(awa+180))/180)*aws }; - twv = { lon: wv.lon+gps_course.lon, lat: wv.lat+gps_course.lat }; - tws = Math.sqrt(Math.pow(twv.lon,2)+Math.pow(twv.lat, 2)); - twa = Math.atan2(twv.lat, twv.lon)*180/Math.PI-gps_course.course; + twv = { vlon: wv.vlon+gps_course.vlon, vlat: wv.vlat+gps_course.vlat }; + tws = Math.sqrt(Math.pow(twv.vlon,2)+Math.pow(twv.vlat, 2)); + twa = 180+Math.atan2(twv.vlon, twv.vlat)*180/Math.PI-gps_course.course; if (twa<0) twa += 360; if (twa>360) twa -=360; } - else { + else { tws = -1; twa = 0; } @@ -57,15 +62,18 @@ function draw_compass(awa, aws, twa, tws) { a = i*Math.PI/2+Math.PI/4; g.drawLineAA(cx+Math.cos(a)*w*0.85, cy+Math.sin(a)*w*0.85, cx+Math.cos(a)*w*0.99, cy+Math.sin(a)*w*0.99); } - g.setColor(0, 1, 0).fillCircle(cx+Math.sin(Math.PI*awa/180)*w*0.9, cy+Math.cos(Math.PI*awa/180)*w*0.9, w*0.1); + g.setColor(0, 1, 0).fillCircle(cx+Math.sin(Math.PI*awa/180)*w*0.9, cy-Math.cos(Math.PI*awa/180)*w*0.9, w*0.1); if (tws>0) g.setColor(1, 0, 0).fillCircle(cx+Math.sin(Math.PI*twa/180)*w*0.9, cy+Math.cos(Math.PI*twa/180)*w*0.9, w*0.1); g.setColor(0, 1, 0).setFont("7x11Numeric7Seg",w*0.06); g.setFontAlign(0, 0, 0).drawString(aws.toFixed(1), cx, cy-0.32*w); - if (tws>0) g.setColor(1, 0, 0).drawString(tws.toFixed(1), cx, cy+0.32*w); - if (settings.truewind && typeof gps_course.spd!=='undefined') { - spd = gps_course.spd/1.852; - g.setColor(g.theme.fg).setFont("7x11Numeric7Seg", w*0.03).setFontAlign(-1, 1, 0).drawString(spd.toFixed(1), 1, g.getHeight()-1); + if (!pause_gps) { + if (tws>0) g.setColor(1, 0, 0).drawString(tws.toFixed(1), cx, cy+0.32*w); + if (settings.truewind && gps_course.spd!=-1) { + spd = gps_course.spd/1.852; + g.setColor(g.theme.fg).setFont("7x11Numeric7Seg", w*0.03).setFontAlign(-1, 1, 0).drawString(spd.toFixed(1), 1, g.getHeight()-1); + } } + if (pause_gps) g.setColor("#f00").drawImage(atob("DAwBEAKARAKQE4DwHkPqPRGKAEAA"),g.getWidth()-15, g.getHeight()-15); } function parseDevice(d) { @@ -96,8 +104,10 @@ if (settings.truewind) { Bangle.on('GPS',function(fix) { if (fix.fix && fix.satellites>3 && fix.speed>2) { // only uses fixes w/ more than 3 sats and speed > 2kph gps_course = - { lon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, - lat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, + { vlon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, + vlat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, + lat: fix.lat, + lon: fix.lon, spd: fix.speed, course: fix.course }; @@ -107,6 +117,20 @@ if (settings.truewind) { Bangle.setGPSPower(1, "app"); } +if (settings.truewind) { + Bangle.on("swipe", (d)=>{ + if (d==-1 && !pause_gps) { + pause_gps = true; + Bangle.setGPSPower(0); + draw_compass(0, 0, 0, 0); + } + else if (d==1 && pause_gps) { + pause_gps = false; + Bangle.setGPSPower(1, "app"); + draw_compass(0, 0, 0, 0); + } + }); +} Bangle.loadWidgets(); Bangle.drawWidgets(); draw_compass(0, 0, 0, 0); diff --git a/apps/openwind/metadata.json b/apps/openwind/metadata.json index 9229f7f25..43961cc44 100644 --- a/apps/openwind/metadata.json +++ b/apps/openwind/metadata.json @@ -1,7 +1,7 @@ { "id": "openwind", "name": "OpenWind", "shortName":"OpenWind", - "version":"0.01", + "version":"0.02", "description": "OpenWind", "icon": "openwind.png", "readme": "README.md", From 4d6c037f2e331056a051646412499489fb0bb8b8 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Thu, 28 Apr 2022 16:09:23 -0700 Subject: [PATCH 13/82] Update metadata.json --- apps/quicklaunch/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/quicklaunch/metadata.json b/apps/quicklaunch/metadata.json index b14a950c6..49eafdd35 100644 --- a/apps/quicklaunch/metadata.json +++ b/apps/quicklaunch/metadata.json @@ -4,7 +4,7 @@ "icon": "app.png", "version":"0.02", "description": "Tap or swipe left/right/up/down on your clock face to launch up to five apps of your choice. Configurations can be accessed through Settings->Apps.", - "type": "launch", + "type": "bootloader", "tags": "tools, system", "supports": ["BANGLEJS2"], "storage": [ From 3032376af713854801a621c4bb333a685f1ae014 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:38:34 -0400 Subject: [PATCH 14/82] Fix spaces/tabs issue --- apps/scicalc/app.js | 113 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 apps/scicalc/app.js diff --git a/apps/scicalc/app.js b/apps/scicalc/app.js new file mode 100644 index 000000000..5d914d0c5 --- /dev/null +++ b/apps/scicalc/app.js @@ -0,0 +1,113 @@ +const W = g.getWidth(); +const H = g.getHeight(); + +const dispH = H/5; +const butH = H-dispH; + +const buttons = [[['7', '8', '9'], + ['4', '5', '6'], + ['1', '2', '3'], + ['E', '0', '.']], + [['<', 'M', 'C'], + ['+', '-', '*'], + ['/', '(', ')'], + ['^', ',', '=']], + [['Sin', 'Cos', 'Tan'], + ['Asi', 'Aco', 'Ata'], + ['Pi', '1/x', '+/-'], + ['Log', 'Exp', 'Pow'] + ]]; + +var curPage = 0; +var inputStr = ''; +var memory = ''; +var qResult = false; + +function drawPage (p) { + g.clearRect(0, dispH, W-1, H-1); + g.setFont('Vector', butH/5).setFontAlign(0, 0, 0).setColor(g.theme.fg); + for (x=0; x<3; ++x) + for (y=0; y<4; ++y) + g.drawString(buttons[p][y][x], (x+0.5)*W/3, dispH+(y+0.7)*butH/4); + g.setColor(0.5, 0.5, 0.5); + for (x=1; x<3; ++x) g.drawLine(x*W/3, dispH+0.2*butH/4-2, x*W/3, H-1); + for (y=1; y<4; ++y) g.drawLine(0, dispH+(y+0.2)*butH/4, W-1, dispH+(y+0.2)*butH/4); + g.setColor(g.theme.fg).drawLine(0, dispH+0.2*butH/4-2, W-1, dispH+0.2*butH/4-2); +} + +function updateDisp(s, len) { + var fh = butH/5; + if (s.toString().length>len) s = s.toString().substr(0,len); + g.setFont("Vector", butH/5).setColor(g.theme.fg).setFontAlign(1, 0, 0); + while (g.stringWidth(s) > W-1) { + fh /= 1.05; + g.setFont("Vector", fh); + } + g.clearRect(0, 0, W-1, dispH-1).drawString(s, W-2, dispH/2); + g.setColor(g.theme.fg).drawLine(0, dispH+0.2*butH/4-2, W-1, dispH+0.2*butH/4-2); +} + +function processInp (s) { + var idx = s.indexOf("^"); + if (idx > 0) s = "Math.pow(" + s.slice(0,idx) + "," + s.slice(idx+1, s.length) + ")"; + ['Sin', 'Cos', 'Tan', 'Asin', 'Acos', 'Atan', 'Log', 'Exp', 'Pow'].forEach((x) => { + var i = s.indexOf(x); + while (i>-1) { + s = s.slice(0,i)+"Math."+s.slice(i,i+1).toLowerCase()+s.slice(i+1, s.length); + i = s.indexOf(x, i+6); + } + }); + idx = s.indexOf('Pi'); + if (idx>-1) s = s.slice(0,idx) + "Math.PI" + s.slice(idx+2, s.length); + idx = 0; + s.split('').forEach((x)=>{ if (x=='(') idx++; if (x==')') idx-- }); + s += ')'.repeat(idx); + return s; +} + +function compute() { + var res; + console.log(processInp(inputStr)); + try { res = eval(processInp(inputStr)); } + catch(e) { res = "error"; } + inputStr = res; + qResult = true; + updateDisp(inputStr, 19); +} + +function touchHandler(e, d) { + var x = Math.floor(d.x/(W/3)); + var y = Math.floor((d.y-dispH-0.2*butH/4)/(butH/4)); + var c = buttons[curPage][y][x]; + if (c=="=") { // do the computation + compute(); + return; + } + else if (c=="<" && inputStr.length>0) inputStr = inputStr.slice(0, -1); // delete last character + else if (c=='M' && qResult) memory = inputStr; + else if (c=='M') inputStr += memory; + else if (c=="C") inputStr = ''; // clear + else { + if ("Sin Cos Tan Log Exp Pow".indexOf(c)>-1 && c!='E') c += "("; + if ("Asi Aco Ata".indexOf(c)>-1) c += "n("; + if (c=='1/x') { inputStr = "1/("+inputStr+")"; compute(); return; } + if (c=='+/-') { inputStr = "-("+inputStr+")"; compute(); return; } + if (qResult && "+-*/^".indexOf(c)==-1) inputStr = c + inputStr + ")"; + else inputStr += c; + } + qResult = false; + updateDisp(inputStr, 32); +} + +function swipeHandler(e,d) { + curPage -= e; + if (curPage>buttons.length-1) curPage = 0; + if (curPage<0) curPage = buttons.length-1; + drawPage(curPage); + if (d==1) compute(); +} + +Bangle.on("touch", touchHandler); +Bangle.on("swipe", swipeHandler); +g.clear(); +drawPage(curPage); From 2675dd6c2dd777a1d8bdc416a35a5051579be29e Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:40:33 -0400 Subject: [PATCH 15/82] New app scicalc --- apps/scicalc/ChangeLog | 1 + apps/scicalc/README.md | 18 ++++++++++++++++++ apps/scicalc/app-icon.js | 1 + apps/scicalc/metadata.json | 14 ++++++++++++++ apps/scicalc/scicalc.png | Bin 0 -> 562 bytes 5 files changed, 34 insertions(+) create mode 100644 apps/scicalc/ChangeLog create mode 100644 apps/scicalc/README.md create mode 100644 apps/scicalc/app-icon.js create mode 100644 apps/scicalc/metadata.json create mode 100644 apps/scicalc/scicalc.png diff --git a/apps/scicalc/ChangeLog b/apps/scicalc/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/scicalc/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/scicalc/README.md b/apps/scicalc/README.md new file mode 100644 index 000000000..bbe4b93c4 --- /dev/null +++ b/apps/scicalc/README.md @@ -0,0 +1,18 @@ +# SciCalc + +Simple scientific calculator. I needed one, so I wrote a basic one, no design frills. Input expressions are slightly post processed and then evaluated +by the JS interpreter. + +## Usage + +Buttons are arranged on 3 separate screens, swiping left or right switches between them. Swiping down has the same effect as hitting the "=" button. + +## Features + +The calculator supports the following operations: + + * basic arithmetic: +, -, *, /, ^ (raise to a power), +/- (invert sign), 1/x (inverse), use of parentheses + * trigonometric fucntions: sin, cos, tan, asin, acos, atan + * exponential exp, natural logarithm log, pow function (this one takes 2 comma separated arguments) + * Pi is provided as a constant + * a memory button "M" stores or recalls the last result (after hitting the "=" button or swiping down) diff --git a/apps/scicalc/app-icon.js b/apps/scicalc/app-icon.js new file mode 100644 index 000000000..b8363e6ee --- /dev/null +++ b/apps/scicalc/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AJioAaF1wwSFzowRCQUZo4AWjIvVFy4ABF/4vXyGQAYov/R+sZFy8ZF6oAcF/4vvi4AeF/4SCjseAAMdAx8MAAYvVEAQABAx4v/R/TvvF96PUg8cAAMHd9QuCAAIv/R+rvvF96Pvd94vvR97vvF96Pvd94vvR97vsGDwuQGDouSAH4A/AGwA==")) diff --git a/apps/scicalc/metadata.json b/apps/scicalc/metadata.json new file mode 100644 index 000000000..54fdc5a26 --- /dev/null +++ b/apps/scicalc/metadata.json @@ -0,0 +1,14 @@ +{ "id": "scicalc", + "name": "Scientific Calculator", + "shortName":"SciCalc", + "version":"0.01", + "description": "Scientific calculator", + "icon": "scicalc.png", + "readme": "README.md", + "tags": "app,tool", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"scicalc.app.js","url":"app.js"}, + {"name":"scicalc.img","url":"app-icon.js","evaluate":true}, + ] +} diff --git a/apps/scicalc/scicalc.png b/apps/scicalc/scicalc.png new file mode 100644 index 0000000000000000000000000000000000000000..b5aa6ff7e90ddf52c08c77ea9f943ff62c19574c GIT binary patch literal 562 zcmV-20?qx2P)f z2@6dVMx#5}gm-ZDZ`78BmPBO0q0t4JLbUhZmbO;!Z|ceUa_@I~PES%mAo$-bu!xGq zVxACk3ZMjFIb2J42cSukbf{_C9ZgIvU~K*dKxQ89IOqe|=yW=Umx$0#8Nd0c&0~D$ z2~Ct@IH)vv*gnW3lV1#Cii-I%!u7fH(o0@ifT06$&3xGA0YF||a)&E4Jxc+`25#lPK+wD%px~>P#J*B3n_(76*EYbhSDwWD7*NJmRRaH-qi65cZw@|rUMmC#u za;9mb)oL+&ihT>Y%>#fe%RH8nKSHr@AIkXnmLv&bOm6CrVEKnRaJMr1k?`Lwp{~Y(R3luCxp~!B5DE6 zX7kpz?M(m|aE()l3;Lhx AZ2$lO literal 0 HcmV?d00001 From 06581584a63d241f6f69007f9aaa7323ecdc2ffe Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:42:43 -0400 Subject: [PATCH 16/82] Typo in metadata.json --- apps/scicalc/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/scicalc/metadata.json b/apps/scicalc/metadata.json index 54fdc5a26..6732e097d 100644 --- a/apps/scicalc/metadata.json +++ b/apps/scicalc/metadata.json @@ -9,6 +9,6 @@ "supports" : ["BANGLEJS2"], "storage": [ {"name":"scicalc.app.js","url":"app.js"}, - {"name":"scicalc.img","url":"app-icon.js","evaluate":true}, + {"name":"scicalc.img","url":"app-icon.js","evaluate":true} ] } From 7ec3b149b18ea4806bb1502938e59639bc6e3491 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:45:37 -0400 Subject: [PATCH 17/82] Fix more spaces/tabs --- apps/openwind/app.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openwind/app.js b/apps/openwind/app.js index ca837defa..4abe84fca 100644 --- a/apps/openwind/app.js +++ b/apps/openwind/app.js @@ -79,20 +79,20 @@ function draw_compass(awa, aws, twa, tws) { function parseDevice(d) { device = d; console.log("Found device"); - device.gatt.connect().then(function(ga) { - console.log("Connected"); - gatt = ga; - return ga.getPrimaryService("cc90"); -}).then(function(s) { - return s.getCharacteristic("cc91"); -}).then(function(c) { - c.on('characteristicvaluechanged', (event)=>wind_updated(event)); - return c.startNotifications(); -}).then(function() { - console.log("Done!"); -}).catch(function(e) { - console.log("ERROR"+e); -});} + device.gatt.connect().then(function(ga) { + console.log("Connected"); + gatt = ga; + return ga.getPrimaryService("cc90"); + }).then(function(s) { + return s.getCharacteristic("cc91"); + }).then(function(c) { + c.on('characteristicvaluechanged', (event)=>wind_updated(event)); + return c.startNotifications(); + }).then(function() { + console.log("Done!"); + }).catch(function(e) { + console.log("ERROR"+e); + });} function connection_setup() { NRF.setScan(); @@ -106,8 +106,8 @@ if (settings.truewind) { gps_course = { vlon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, vlat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, - lat: fix.lat, - lon: fix.lon, + lat: fix.lat, + lon: fix.lon, spd: fix.speed, course: fix.course }; From 31ef7c3d97367abf71dcf81a3604b457bffb1616 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:48:24 -0400 Subject: [PATCH 18/82] Fix tabs, again, sigh... --- apps/openwind/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openwind/app.js b/apps/openwind/app.js index 4abe84fca..db67804f3 100644 --- a/apps/openwind/app.js +++ b/apps/openwind/app.js @@ -106,8 +106,8 @@ if (settings.truewind) { gps_course = { vlon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, vlat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, - lat: fix.lat, - lon: fix.lon, + lat: fix.lat, + lon: fix.lon, spd: fix.speed, course: fix.course }; From 51aa4ac12ab2eb74829b85e331870932a165fccc Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:56:09 -0400 Subject: [PATCH 19/82] Enable emulator --- apps/scicalc/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/scicalc/metadata.json b/apps/scicalc/metadata.json index 6732e097d..d2d855dc2 100644 --- a/apps/scicalc/metadata.json +++ b/apps/scicalc/metadata.json @@ -6,6 +6,7 @@ "icon": "scicalc.png", "readme": "README.md", "tags": "app,tool", + "allow_emulator": true, "supports" : ["BANGLEJS2"], "storage": [ {"name":"scicalc.app.js","url":"app.js"}, From 9d758075da2de655050b0681af03cdf59eb6175c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 29 Apr 2022 09:29:02 +0100 Subject: [PATCH 20/82] Add extra checks for app type and dependencies, document available types, and fix invalid app types --- README.md | 12 +++++++++--- apps/hrmaccevents/metadata.json | 2 +- apps/menusmall/metadata.json | 2 +- apps/menuwheel/metadata.json | 2 +- apps/mmind/mmind.info | 2 +- apps/mysticdock/metadata.json | 2 +- apps/promenu/metadata.json | 2 +- apps/swp2clk/metadata.json | 2 +- bin/sanitycheck.js | 6 ++++++ 9 files changed, 22 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 78dd1b492..e5d8333aa 100644 --- a/README.md +++ b/README.md @@ -257,12 +257,18 @@ and which gives information about the app for the Launcher. // 'app' - an application // 'clock' - a clock - required for clocks to automatically start // 'widget' - a widget - // 'launch' - replacement launcher app - // 'bootloader' - code that runs at startup only + // 'bootloader' - an app that at startup (app.boot.js) but doesn't have a launcher entry for 'app.js' // 'RAM' - code that runs and doesn't upload anything to storage + // 'launch' - replacement 'Launcher' + // 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle + // 'scheduler' - provides 'sched' library and boot code for scheduling alarms/timers + // (currently only 'sched' app) + // 'notify' - provides 'notify' library for showing notifications + // 'locale' - provides 'locale' library for language-specific date/distance/etc + // (a version of 'locale' is included in the firmware) "tags": "", // comma separated tag list for searching "supports": ["BANGLEJS2"], // List of device IDs supported, either BANGLEJS or BANGLEJS2 - "dependencies" : { "notify":"type" } // optional, app 'types' we depend on + "dependencies" : { "notify":"type" } // optional, app 'types' we depend on (see "type" above) "dependencies" : { "messages":"app" } // optional, depend on a specific app ID // for instance this will use notify/notifyfs is they exist, or will pull in 'notify' "readme": "README.md", // if supplied, a link to a markdown-style text file diff --git a/apps/hrmaccevents/metadata.json b/apps/hrmaccevents/metadata.json index de59dceac..7207f685a 100644 --- a/apps/hrmaccevents/metadata.json +++ b/apps/hrmaccevents/metadata.json @@ -3,7 +3,7 @@ "name": "HRM Accelerometer event recorder", "shortName": "HRM ACC recorder", "version": "0.01", - "type": "ram", + "type": "RAM", "description": "Record HRM and accelerometer events in high resolution to CSV files in your browser", "icon": "app.png", "tags": "debug", diff --git a/apps/menusmall/metadata.json b/apps/menusmall/metadata.json index aafb7da28..51ab825bd 100644 --- a/apps/menusmall/metadata.json +++ b/apps/menusmall/metadata.json @@ -4,7 +4,7 @@ "version": "0.02", "description": "Replace Bangle.js 2's menus with a version that contains smaller text", "icon": "app.png", - "type": "boot", + "type": "bootloader", "tags": "system", "supports": ["BANGLEJS2"], "storage": [ diff --git a/apps/menuwheel/metadata.json b/apps/menuwheel/metadata.json index 1ad042344..5f49b640c 100644 --- a/apps/menuwheel/metadata.json +++ b/apps/menuwheel/metadata.json @@ -9,7 +9,7 @@ {"url":"screenshot_b1_dark.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_light.png"}, {"url":"screenshot_b2_dark.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_light.png"} ], - "type": "boot", + "type": "bootloader", "tags": "system", "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ diff --git a/apps/mmind/mmind.info b/apps/mmind/mmind.info index 2e79822b1..b4b822508 100644 --- a/apps/mmind/mmind.info +++ b/apps/mmind/mmind.info @@ -5,7 +5,7 @@ "icon": "mmind.png", "version":"0.01", "description": "This is the classic game for masterminds", - "type": "game", + "type": "app", "tags": "mastermind, game, classic", "readme":"README.md", "supports": ["BANGLEJS2"], diff --git a/apps/mysticdock/metadata.json b/apps/mysticdock/metadata.json index 54ebedd93..2775b0b72 100644 --- a/apps/mysticdock/metadata.json +++ b/apps/mysticdock/metadata.json @@ -4,7 +4,7 @@ "version": "0.01", "description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.", "icon": "mystic-dock.png", - "type": "dock", + "type": "app", "tags": "dock", "supports": ["BANGLEJS"], "readme": "README.md", diff --git a/apps/promenu/metadata.json b/apps/promenu/metadata.json index 443809004..e0124467a 100644 --- a/apps/promenu/metadata.json +++ b/apps/promenu/metadata.json @@ -4,7 +4,7 @@ "version": "0.02", "description": "Replace the built in menu function. Supports Bangle.js 1 and Bangle.js 2.", "icon": "icon.png", - "type": "boot", + "type": "bootloader", "tags": "system", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", diff --git a/apps/swp2clk/metadata.json b/apps/swp2clk/metadata.json index aa95a6473..8b0cce2d8 100644 --- a/apps/swp2clk/metadata.json +++ b/apps/swp2clk/metadata.json @@ -5,7 +5,7 @@ "version": "0.01", "description": "Let's you swipe from left to right on any app to return back to the clock face. Please configure in the settings app after installing to activate, since its disabled by default.", "icon": "app.png", - "type": "boot", + "type": "bootloader", "tags": "tools", "supports": ["BANGLEJS2"], "readme": "README.md", diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 8fdb5a4d2..850b793f4 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -65,6 +65,7 @@ const APP_KEYS = [ const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports']; const DATA_KEYS = ['name', 'wildcard', 'storageFile', 'url', 'content', 'evaluate']; const SUPPORTS_DEVICES = ["BANGLEJS","BANGLEJS2"]; // device IDs allowed for 'supports' +const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","textinput","scheduler","notify","locale"]; // values allowed for "type" field const FORBIDDEN_FILE_NAME_CHARS = /[,;]/; // used as separators in appid.info const VALID_DUPLICATES = [ '.tfmodel', '.tfnames' ]; const GRANDFATHERED_ICONS = ["s7clk", "snek", "astral", "alpinenav", "slomoclock", "arrow", "pebble", "rebble"]; @@ -94,6 +95,8 @@ apps.forEach((app,appIdx) => { if (!app.name) ERROR(`App ${app.id} has no name`); var isApp = !app.type || app.type=="app"; if (app.name.length>20 && !app.shortName && isApp) ERROR(`App ${app.id} has a long name, but no shortName`); + if (app.type && !METADATA_TYPES.includes(app.type)) + ERROR(`App ${app.id} 'type' is one one of `+METADATA_TYPES); if (!Array.isArray(app.supports)) ERROR(`App ${app.id} has no 'supports' field or it's not an array`); else { app.supports.forEach(dev => { @@ -135,6 +138,9 @@ apps.forEach((app,appIdx) => { Object.keys(app.dependencies).forEach(dependency => { if (!["type","app"].includes(app.dependencies[dependency])) ERROR(`App ${app.id} 'dependencies' must all be tagged 'type' or 'app' right now`); + if (app.dependencies[dependency]=="type" && !METADATA_TYPES.includes(dependency)) + ERROR(`App ${app.id} 'type' dependency must be one of `+METADATA_TYPES); + }); } else ERROR(`App ${app.id} 'dependencies' must be an object`); From 67fc91fb62b0165caf24741b76bcd4c6c98d77d5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 29 Apr 2022 09:31:06 +0100 Subject: [PATCH 21/82] remove duplication --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e5d8333aa..93507de75 100644 --- a/README.md +++ b/README.md @@ -226,10 +226,8 @@ and which gives information about the app for the Launcher. "name":"Short Name", // for Bangle.js menu "icon":"*myappid", // for Bangle.js menu "src":"-myappid", // source file - "type":"widget/clock/app/bootloader", // optional, default "app" - // if this is 'widget' then it's not displayed in the menu - // if it's 'clock' then it'll be loaded by default at boot time - // if this is 'bootloader' then it's code that is run at boot time, but is not in a menu + "type":"widget/clock/app/bootloader/...", // optional, default "app" + // see 'type' in 'metadata.json format' below for more options/info "version":"1.23", // added by BangleApps loader on upload based on metadata.json "files:"file1,file2,file3", From 7f2af3c892862f79d47c54384d94d41491de285c Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 09:55:31 +0100 Subject: [PATCH 22/82] Update Layout.js --- modules/Layout.js | 71 ++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 0bfbc28ad..8784e1a8d 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -1,18 +1,13 @@ /* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */ /* - Take a look at README.md for hints on developing with this library. - Usage: - ``` var Layout = require("Layout"); var layout = new Layout( layoutObject, options ) layout.render(optionalObject); ``` - For example: - ``` var Layout = require("Layout"); var layout = new Layout( { @@ -24,10 +19,7 @@ var layout = new Layout( { g.clear(); layout.render(); ``` - - layoutObject has: - * A `type` field of: * `undefined` - blank, can be used for padding * `"txt"` - a text label, with value `label` and `r` for text rotation. 'font' is required @@ -51,34 +43,25 @@ layoutObject has: * A `fillx` int to choose if the object should fill available space in x. 0=no, 1=yes, 2=2x more space * A `filly` int to choose if the object should fill available space in y. 0=no, 1=yes, 2=2x more space * `width` and `height` fields to optionally specify minimum size - options is an object containing: - * `lazy` - a boolean specifying whether to enable automatic lazy rendering * `btns` - array of objects containing: * `label` - the text on the button * `cb` - a callback function * `cbl` - a callback function for long presses * `back` - a callback function, passed as `back` into Bangle.setUI - If automatic lazy rendering is enabled, calls to `layout.render()` will attempt to automatically determine what objects have changed or moved, clear their previous locations, and re-render just those objects. - Once `layout.update()` is called, the following fields are added to each object: - * `x` and `y` for the top left position * `w` and `h` for the width and height * `_w` and `_h` for the **minimum** width and height - - Other functions: - * `layout.update()` - update positions of everything if contents have changed * `layout.debug(obj)` - draw outlines for objects on screen * `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render) * `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render - */ @@ -138,15 +121,15 @@ function Layout(layout, options) { } // enough physical buttons let btnHeight = Math.floor(Bangle.appRect.h / this.physBtns); - if (Bangle.btnWatch) Bangle.btnWatch.forEach(clearWatch); - Bangle.btnWatch = []; + if (Bangle.btnWatches) Bangle.btnWatches.forEach(clearWatch); + Bangle.btnWatches = []; if (this.physBtns > 2 && buttons.length==1) buttons.unshift({label:""}); // pad so if we have a button in the middle while (this.physBtns > buttons.length) buttons.push({label:""}); - if (buttons[0]) Bangle.btnWatch.push(setWatch(pressHandler.bind(this,0), BTN1, {repeat:true,edge:-1})); - if (buttons[1]) Bangle.btnWatch.push(setWatch(pressHandler.bind(this,1), BTN2, {repeat:true,edge:-1})); - if (buttons[2]) Bangle.btnWatch.push(setWatch(pressHandler.bind(this,2), BTN3, {repeat:true,edge:-1})); + if (buttons[0]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,0), BTN1, {repeat:true,edge:-1})); + if (buttons[1]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,1), BTN2, {repeat:true,edge:-1})); + if (buttons[2]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,2), BTN3, {repeat:true,edge:-1})); this._l.width = g.getWidth()-8; // text width this._l = {type:"h", filly:1, c: [ this._l, @@ -190,9 +173,9 @@ function Layout(layout, options) { } Layout.prototype.remove = function (l) { - if (Bangle.btnWatch) { - Bangle.btnWatch.forEach(clearWatch); - delete Bangle.btnWatch; + if (Bangle.btnWatches) { + Bangle.btnWatches.forEach(clearWatch); + delete Bangle.btnWatches; } if (Bangle.touchHandler) { Bangle.removeListener("touch",Bangle.touchHandler); @@ -237,34 +220,34 @@ Layout.prototype.render = function (l) { "":function(){}, "txt":function(l){ if (l.wrap) { - g.setFont(l.font).setFontAlign(0,-1); + g.setFont(l.font, l.scale||1).setFontAlign(0,-1); var lines = g.wrapString(l.label, l.w); var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1); // TODO: on 2v11 we can just render in a single drawString call lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i)); } else { - g.setFont(l.font).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); + g.setFont(l.font, l.scale||1).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); } }, "btn":function(l){ var x = l.x+(0|l.pad), y = l.y+(0|l.pad), w = l.w-(l.pad<<1), h = l.h-(l.pad<<1); - var poly = [ - x,y+4, - x+4,y, - x+w-5,y, - x+w-1,y+4, - x+w-1,y+h-5, - x+w-5,y+h-1, - x+4,y+h-1, - x,y+h-5, - x,y+4 - ], bg = l.selected?g.theme.bgH:g.theme.bg2; - g.setColor(bg).fillPoly(poly).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawPoly(poly); + var bg = l.selected?g.theme.bgH:g.theme.bg2; + g.setColor(bg).fillRect(x, y, x+w, y+h, 4).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawRect(x, y, x+w, y+h, 4); if (l.col!==undefined) g.setColor(l.col); - if (l.src) g.setBgColor(bg).drawImage("function"==typeof l.src?l.src():l.src, l.x + 10 + (0|l.pad), l.y + 8 + (0|l.pad)); - else g.setFont("6x8",2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); + if (l.src) g.setBgColor(bg).drawImage( + "function"==typeof l.src?l.src():l.src, + l.x + l.w/2 + (0|l.pad), + l.y + l.h/2 + (0|l.pad), + {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} + ); + else g.setFont(l.font||"6x8", l.scale||2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); }, "img":function(l){ - g.drawImage("function"==typeof l.src?l.src():l.src, l.x + (0|l.pad), l.y + (0|l.pad), l.scale?{scale:l.scale}:undefined); + g.drawImage( + "function"==typeof l.src?l.src():l.src, + l.x + l.w/2 + (0|l.pad), + l.y + l.h/2 + (0|l.pad), + {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} + ); }, "custom":function(l){ l.render(l); },"h":function(l) { l.c.forEach(render); }, @@ -361,11 +344,11 @@ Layout.prototype.update = function() { if (l.wrap) { l._h = l._w = 0; } else { - var m = g.setFont(l.font).stringMetrics(l.label); + var m = g.setFont(l.font, l.scale||1).stringMetrics(l.label); l._w = m.width; l._h = m.height; } }, "btn": function(l) { - var m = l.src?g.imageMetrics("function"==typeof l.src?l.src():l.src):g.setFont("6x8",2).stringMetrics(l.label); + var m = l.src?g.imageMetrics("function"==typeof l.src?l.src():l.src):g.setFont(l.font||"6x8", l.scale||2).stringMetrics(l.label); l._h = 16 + m.height; l._w = 20 + m.width; }, "img": function(l) { From 826bc2973857a01e9f0288d4359768dfad2691dc Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 10:16:42 +0100 Subject: [PATCH 23/82] Update Layout.js --- modules/Layout.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 8784e1a8d..39aab9dc8 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -22,17 +22,19 @@ layout.render(); layoutObject has: * A `type` field of: * `undefined` - blank, can be used for padding - * `"txt"` - a text label, with value `label` and `r` for text rotation. 'font' is required + * `"txt"` - a text label, with value `label`. 'font' is required * `"btn"` - a button, with value `label` and callback `cb` optional `src` specifies an image (like img) in which case label is ignored + Default font is `6x8`, scale 2. This can be overridden with the `font` or `scale` fields. * `"img"` - an image where `src` is an image, or a function which is called to return an image to draw. - optional `scale` specifies if image should be scaled up or not * `"custom"` - a custom block where `render(layoutObj)` is called to render * `"h"` - Horizontal layout, `c` is an array of more `layoutObject` * `"v"` - Vertical layout, `c` is an array of more `layoutObject` * A `id` field. If specified the object is added with this name to the returned `layout` object, so can be referenced as `layout.foo` * A `font` field, eg `6x8` or `30%` to use a percentage of screen height +* A `scale` field, eg `2` to set scale of an image or text +* A `r` field to set rotation of text or images. * A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` and `fillx`/`filly` to be set. Not compatible with text rotation. * A `col` field, eg `#f00` for red @@ -232,20 +234,20 @@ Layout.prototype.render = function (l) { var x = l.x+(0|l.pad), y = l.y+(0|l.pad), w = l.w-(l.pad<<1), h = l.h-(l.pad<<1); var bg = l.selected?g.theme.bgH:g.theme.bg2; - g.setColor(bg).fillRect(x, y, x+w, y+h, 4).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawRect(x, y, x+w, y+h, 4); + g.setColor(bg).fillRect({x:x,y:y,x2:x+w,y2:y+h,r:4}).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawRect({x:x,y:y,x2:x+w,y2:y+h,r:4}); if (l.col!==undefined) g.setColor(l.col); if (l.src) g.setBgColor(bg).drawImage( "function"==typeof l.src?l.src():l.src, - l.x + l.w/2 + (0|l.pad), - l.y + l.h/2 + (0|l.pad), + l.x + (l.w + (0|l.pad))/2, + l.y + (l.h + (0|l.pad))/2, {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} ); else g.setFont(l.font||"6x8", l.scale||2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); }, "img":function(l){ g.drawImage( "function"==typeof l.src?l.src():l.src, - l.x + l.w/2 + (0|l.pad), - l.y + l.h/2 + (0|l.pad), + l.x + (l.w + (0|l.pad))/2, + l.y + (l.h + (0|l.pad))/2, {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} ); }, "custom":function(l){ From 1e4486861a672f13f5accf405862f6df0654502d Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 10:26:44 +0100 Subject: [PATCH 24/82] Update Layout.js --- modules/Layout.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 39aab9dc8..230d488be 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -233,8 +233,18 @@ Layout.prototype.render = function (l) { }, "btn":function(l){ var x = l.x+(0|l.pad), y = l.y+(0|l.pad), w = l.w-(l.pad<<1), h = l.h-(l.pad<<1); - var bg = l.selected?g.theme.bgH:g.theme.bg2; - g.setColor(bg).fillRect({x:x,y:y,x2:x+w,y2:y+h,r:4}).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawRect({x:x,y:y,x2:x+w,y2:y+h,r:4}); + var poly = [ + x,y+4, + x+4,y, + x+w-5,y, + x+w-1,y+4, + x+w-1,y+h-5, + x+w-5,y+h-1, + x+4,y+h-1, + x,y+h-5, + x,y+4 + ], bg = l.selected?g.theme.bgH:g.theme.bg2; + g.setColor(bg).fillPoly(poly).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawPoly(poly); if (l.col!==undefined) g.setColor(l.col); if (l.src) g.setBgColor(bg).drawImage( "function"==typeof l.src?l.src():l.src, From 673bb38cd1f59ec4c7d888a91d55b0e592c856fe Mon Sep 17 00:00:00 2001 From: Marco H Date: Fri, 29 Apr 2022 11:40:50 +0200 Subject: [PATCH 25/82] Update boot.js Do not alarm while charging --- apps/activityreminder/boot.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/activityreminder/boot.js b/apps/activityreminder/boot.js index 0f89bf543..09aa9d757 100644 --- a/apps/activityreminder/boot.js +++ b/apps/activityreminder/boot.js @@ -1,4 +1,5 @@ function run(){ + if (Bangle.isCharging()) return; var now = new Date(); var h = now.getHours(); if(h >= activityreminder.startHour && h < activityreminder.endHour){ From 321617ad7b8a76d295f5088b170321661ed068b8 Mon Sep 17 00:00:00 2001 From: Marco H Date: Fri, 29 Apr 2022 11:41:14 +0200 Subject: [PATCH 26/82] Update metadata.json --- apps/activityreminder/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/activityreminder/metadata.json b/apps/activityreminder/metadata.json index eba5de105..7fd425ceb 100644 --- a/apps/activityreminder/metadata.json +++ b/apps/activityreminder/metadata.json @@ -3,7 +3,7 @@ "name": "Activity Reminder", "shortName":"Activity Reminder", "description": "A reminder to take short walks for the ones with a sedentary lifestyle", - "version":"0.02", + "version":"0.03", "icon": "app.png", "type": "app", "tags": "tool,activity", From dd3f7e47fe9d302d9b2eed64538b594a717bcc5a Mon Sep 17 00:00:00 2001 From: Marco H Date: Fri, 29 Apr 2022 11:41:33 +0200 Subject: [PATCH 27/82] Update ChangeLog --- apps/activityreminder/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/activityreminder/ChangeLog b/apps/activityreminder/ChangeLog index 53e29a66d..6681ac41d 100644 --- a/apps/activityreminder/ChangeLog +++ b/apps/activityreminder/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Fix the settings bug and some tweaking +0.03: Do not alarm while charging From fc1bd36ec217c2857abff529da886c1c474f47d0 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:16:48 +0100 Subject: [PATCH 28/82] Update Layout.js --- modules/Layout.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 230d488be..7e5dd4b62 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -231,6 +231,8 @@ Layout.prototype.render = function (l) { g.setFont(l.font, l.scale||1).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); } }, "btn":function(l){ + if (l.font && l.font.endsWith("%")) + l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100); var x = l.x+(0|l.pad), y = l.y+(0|l.pad), w = l.w-(l.pad<<1), h = l.h-(l.pad<<1); var poly = [ @@ -248,16 +250,16 @@ Layout.prototype.render = function (l) { if (l.col!==undefined) g.setColor(l.col); if (l.src) g.setBgColor(bg).drawImage( "function"==typeof l.src?l.src():l.src, - l.x + (l.w + (0|l.pad))/2, - l.y + (l.h + (0|l.pad))/2, + l.x + l.w/2, + l.y + l.h/2, {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} ); else g.setFont(l.font||"6x8", l.scale||2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); }, "img":function(l){ g.drawImage( "function"==typeof l.src?l.src():l.src, - l.x + (l.w + (0|l.pad))/2, - l.y + (l.h + (0|l.pad))/2, + l.x + l.w/2, + l.y + l.h/2, {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} ); }, "custom":function(l){ @@ -360,6 +362,8 @@ Layout.prototype.update = function() { l._w = m.width; l._h = m.height; } }, "btn": function(l) { + if (l.font && l.font.endsWith("%")) + l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100); var m = l.src?g.imageMetrics("function"==typeof l.src?l.src():l.src):g.setFont(l.font||"6x8", l.scale||2).stringMetrics(l.label); l._h = 16 + m.height; l._w = 20 + m.width; @@ -413,5 +417,3 @@ Layout.prototype.clear = function(l) { if (l.bgCol!==undefined) g.setBgColor(l.bgCol); g.clearRect(l.x,l.y,l.x+l.w-1,l.y+l.h-1); }; - -exports = Layout; From c69fe8e2c4191cdffcca236a45fed3590dced07b Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:17:27 +0100 Subject: [PATCH 29/82] Update timersimple.app.js --- apps/timersimple/timersimple.app.js | 41 +++++++++++------------------ 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/apps/timersimple/timersimple.app.js b/apps/timersimple/timersimple.app.js index 8bbe66e83..ef53c1e72 100644 --- a/apps/timersimple/timersimple.app.js +++ b/apps/timersimple/timersimple.app.js @@ -13,23 +13,12 @@ const timerID = "simpletimer"; Bangle.loadWidgets(); Bangle.drawWidgets(); -var Layout = require("Layout"); +//var Layout = require("Layout"); var seconds = 5 * 60; // Default to 5 minutes var drawTimeout; var timerLayout; var timePickerLayout; -var imgArrowDown = Graphics.createImage(` -xxx xxx -xxx xxx - xxx xxx - xxx xxx - xxxxx - xxxxx - xxx - xxx - x -`); -var imgArrowUp = Graphics.createImage(` +var imgArrow = Graphics.createImage(` x xxx xxx @@ -117,26 +106,27 @@ var timePickerLayoutCode = { {type:undefined, height:2}, //{type:"txt", font:"15%", label:"TIMER", id:"title"}, {type:"h", c: [ - {type:"v", c: [ + {type:"v", width:g.getWidth()/3, c: [ {type:"txt", font:"6x8", label:/*LANG*/"Hours", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrowUp, col:g.theme.fg2}, - {type:"txt", font:"20%", label:"0", id:"hours", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrowDown, col:g.theme.fg2} + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"00", id:"hours", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} ]}, - {type:"v", c: [ + {type:"v", width:g.getWidth()/3, c: [ {type:"txt", font:"6x8", label:/*LANG*/"Minutes", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrowUp, col:g.theme.fg2}, - {type:"txt", font:"20%", label:"0", id:"mins", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrowDown, col:g.theme.fg2} + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"00", id:"mins", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} ]}, - {type:"v", c: [ + {type:"v", width:g.getWidth()/3, c: [ {type:"txt", font:"6x8", label:/*LANG*/"Seconds", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrowUp, col:g.theme.fg2}, - {type:"txt", font:"20%", label:"0", id:"secs", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrowDown, col:g.theme.fg2} + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"00", id:"secs", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} ]}, ]}, {type:"btn", src:imgPlay, id:"btnStart", fillx:1 } + //{type:"btn", label:'Start', font:"20%", id:"btnStart", fillx:0 } ], filly:1 }; @@ -164,6 +154,7 @@ function runTimePicker() { }); timePickerLayout.render(); updateTimePicker(); + //timePickerLayout.debug(); } function runTimer() { From b840a92f5ae7e75704813b6ab03ebf23236849cd Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:20:26 +0100 Subject: [PATCH 30/82] Update timersimple.app.js --- apps/timersimple/timersimple.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/timersimple/timersimple.app.js b/apps/timersimple/timersimple.app.js index ef53c1e72..cece0dd6b 100644 --- a/apps/timersimple/timersimple.app.js +++ b/apps/timersimple/timersimple.app.js @@ -13,7 +13,7 @@ const timerID = "simpletimer"; Bangle.loadWidgets(); Bangle.drawWidgets(); -//var Layout = require("Layout"); +var Layout = require("Layout"); var seconds = 5 * 60; // Default to 5 minutes var drawTimeout; var timerLayout; From f1149233050055e0a6e8376227ff4cb53659512b Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:27:43 +0100 Subject: [PATCH 31/82] Update README.md --- apps/timersimple/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/timersimple/README.md b/apps/timersimple/README.md index e940ba0ab..894a46e7a 100644 --- a/apps/timersimple/README.md +++ b/apps/timersimple/README.md @@ -1,5 +1,7 @@ # Simple Timer +TESTING - DO NOT INSTALL, MAY BE BROKEN + Does one thing well. Set a time in hours, minutes and seconds, and alerts you when time is up. Opening the app while the timer is running (or just leaving the app open) shows how much time is left on the timer. This is the part I felt was missing from the Alarms and Timer app. Drag or tap on the up and down buttons over the hour, minute or second to set the time. @@ -7,4 +9,4 @@ Drag or tap on the up and down buttons over the hour, minute or second to set th ![](timersimple-scr1.png) ![](timersimple-scr2.png) -Written by: [Sir Indy](https://github.com/sir-indy) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) \ No newline at end of file +Written by: [Sir Indy](https://github.com/sir-indy) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) From baa242e92bd245b703a9ddf9c2881fbeb15f1847 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:28:58 +0100 Subject: [PATCH 32/82] Update Layout.js --- modules/Layout.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/Layout.js b/modules/Layout.js index 7e5dd4b62..19553c0a5 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -417,3 +417,5 @@ Layout.prototype.clear = function(l) { if (l.bgCol!==undefined) g.setBgColor(l.bgCol); g.clearRect(l.x,l.y,l.x+l.w-1,l.y+l.h-1); }; + +exports = Layout; From f60d0f22a23bcb7a8ef37765ff46e16629aace97 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Fri, 29 Apr 2022 12:33:42 +0100 Subject: [PATCH 33/82] Update timersimple.app.js --- apps/timersimple/timersimple.app.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/timersimple/timersimple.app.js b/apps/timersimple/timersimple.app.js index cece0dd6b..1c775b908 100644 --- a/apps/timersimple/timersimple.app.js +++ b/apps/timersimple/timersimple.app.js @@ -34,6 +34,7 @@ const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/ const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); function onDrag(event) { + Bangle.buzz(20, 0.3); var diff = -Math.round(event.dy/5); if (event.x < timePickerLayout.hours.w) { diff *= 3600; @@ -47,10 +48,13 @@ function onTouch(button, xy) { var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; var diff = 0; if (xy.y > 24 && xy.y < touchMidpoint - 10) { + Bangle.buzz(40, 0.3); diff = 1; } else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { + Bangle.buzz(40, 0.3); diff = -1; } else if (xy.y > timePickerLayout.btnStart.y) { + Bangle.buzz(40, 0.6); runTimer(); return; } From 4b8912ad49acd90209e03f3b984a5a195a52fee0 Mon Sep 17 00:00:00 2001 From: marko Date: Fri, 29 Apr 2022 08:55:02 -0400 Subject: [PATCH 34/82] Add screenshots --- apps/scicalc/README.md | 4 ++++ apps/scicalc/scicalc_screenshot1.png | Bin 0 -> 4040 bytes apps/scicalc/scicalc_screenshot2.png | Bin 0 -> 3171 bytes apps/scicalc/scicalc_screenshot3.png | Bin 0 -> 2922 bytes 4 files changed, 4 insertions(+) create mode 100644 apps/scicalc/scicalc_screenshot1.png create mode 100644 apps/scicalc/scicalc_screenshot2.png create mode 100644 apps/scicalc/scicalc_screenshot3.png diff --git a/apps/scicalc/README.md b/apps/scicalc/README.md index bbe4b93c4..89a78bf77 100644 --- a/apps/scicalc/README.md +++ b/apps/scicalc/README.md @@ -16,3 +16,7 @@ The calculator supports the following operations: * exponential exp, natural logarithm log, pow function (this one takes 2 comma separated arguments) * Pi is provided as a constant * a memory button "M" stores or recalls the last result (after hitting the "=" button or swiping down) + +![](scicalc_screenshot1.png) +![](scicalc_screenshot2.png) +![](scicalc_screenshot3.png) diff --git a/apps/scicalc/scicalc_screenshot1.png b/apps/scicalc/scicalc_screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..7f9d468604d4ca56f8c84e0da50e39977a41e54b GIT binary patch literal 4040 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 IH^xW)AFc<{9 literal 0 HcmV?d00001 diff --git a/apps/scicalc/scicalc_screenshot2.png b/apps/scicalc/scicalc_screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..795d922e8f0ba39f2baeed45e711df5e3bc0d610 GIT binary patch literal 3171 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 Cm+n{q literal 0 HcmV?d00001 diff --git a/apps/scicalc/scicalc_screenshot3.png b/apps/scicalc/scicalc_screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..9319157ba7ca6654d9b407eedb3421cafc79b876 GIT binary patch literal 2922 zcmaJ@c{tSD8~+Ytm_gZwxKy@eO&Cdch%DK|7}=+;^^SfdvWJVZ?+O_)wuu@0GG!ZG zC3|RQEMZDTmWDER^_%zRG9lZZuQ}!4o|`b=Fc}>3ezF4NZH`$ z*G`KaRF7q-LJ7wcr24~;4%sdDrx*BGIz<_zhkB-UARGtQG0@TFfNqR`tK5VJY6J#@ zg&5_ZEEa_so{VLlL#~Zg*1oRRod@fB?kSc5Kb$TFxguAV$?r(Zq^`jsF~+=+?CE-m zt!IcJ3;fPcEbU3_DP%@(k7y@C)iHbzAQl>N+FBL6!_}7jr=>|qY)sy5o6Y*FR#cjn zgzIg5|85LM2!4(0?&eB>}* zx?SQb-2+=-nc&F&XYBYztw4+3n3@3_k|FFbnOx8g2Hc-PQ0*6{j234T2Y63zU zVK|cUTWhpW(|qkdL5jXtG&MXb1;M12F2pz8`Qaqs(?62ZamTfGf7^Y-3bgV1VDc`k zN#l{paL|v!^Uc~{Eotri<;kJA0H^StOY!vDN|SgE<*Jv7BYbI^f1so15qd!j#{#4y z#5j`D=A>5$$IF-MXUNSQruTQ6FO@2(JNM0qb}JhUwweAJZ!+e=6}A)>5!=-}r|7+& za)=W_W@G#17>>8vYA78rN=;0U+9*jWP%DsRe9OS;AQT(h&e62jKOZ{dO*1r#4~=}I zgg4LMzV)|5FA>ycO`F?vEgWm%&H!r|qHfh=`8Qw!U9&ML)xLVYPw2)$z?d%u99!kK zyywT?;LtQ5DyV2eSgeARAC35Ck&LK^VV2C|WvFG082({0i6-;BfYc!{@t=6el#qfOuRfYM`4jbFX#PsP07_@CZI4gdtro`Ys1JW@7!9am|`e`t3Cm zbalILG7+BzfO=S!c#k~_dTpSDx;b$u+8-I3SHV)@73QbdWtnEwbC7l2n?ih=%#XS} zQ{_9K%=ND1>I|IU+GHn^y>?Qn!zqdMzLF!Xdbt*;%XkzuT}ULg;-jwS!>{9|GaqCC z{FE|>DSt^kM}T&Cgswzvp%Jd?Jta;HI7Jv~8L%8M=Ty%nOnyA2lLcXLwiap^DmwWA z-a;Wohn(CKKvb#rZNDQ${sC90SXq#GFG`flkOPx!~U& zS;ZE1<92rN+wQ8xG%f$Fhym+pwqG{N*i;*P){)V5z;Bn;2P3P9O{l*#lRY919m9S z&tD0x;(PQbHv|^Y@A^hnn@BJ~Hl-ru$ zaB14fjMjkza6w|$0Tl8%r4h6-}1QjBl4Gm|w?PNb3Xo;SRCrcg8o$qPN|RW$oXYl1zZ%c%qx#~&U@Yt0-gABdga9#A&Ono zy53i(;?ry|vI~*Wo;z3~;w1MwE0HsePsQ#nkrIPXe>)|K8Cx@QSm1ebRXR7nhC9Qq zka*4?zng41bHI8TJ=c%IJY0DU-#waRaJLC$*9bLnln2O%qvrZ!vU*X`SQo{h-$<;A z*DNG&{bY#cbomYd01F zZ&J75e-!6#T^2bO5T?(?xu;V}r`>ZfNg${==$Mz`K__s(mr$YOYT^4kwF_e~|M$BxmAe`A`ToEGiQxsA(#$}6N{zps9mTz&!O2OvV4YX7u)ta-E5e#)IF)qASxy;A z@j8Q-ZWBPrbfUG#K`L`0Ss5#%++xqO_VB(u_=9nodo!fudR*+R6FV0?b6%K zw^)j78p5w1sPO1MEg_%er(E6aoaOdxl38?iS@i&6?7K=j6IIxsXTZ$Z+NjPD^Vfd? D_85W5 literal 0 HcmV?d00001 From 31a1312c7df3765eda39cb8f64fac82b6f5c546b Mon Sep 17 00:00:00 2001 From: marko Date: Fri, 29 Apr 2022 08:59:55 -0400 Subject: [PATCH 35/82] Formatting --- apps/scicalc/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/scicalc/README.md b/apps/scicalc/README.md index 89a78bf77..740b4216b 100644 --- a/apps/scicalc/README.md +++ b/apps/scicalc/README.md @@ -18,5 +18,7 @@ The calculator supports the following operations: * a memory button "M" stores or recalls the last result (after hitting the "=" button or swiping down) ![](scicalc_screenshot1.png) + ![](scicalc_screenshot2.png) + ![](scicalc_screenshot3.png) From 0dae17cf70db3c24825f0939d86f64c16aeff81d Mon Sep 17 00:00:00 2001 From: Marco H Date: Fri, 29 Apr 2022 15:45:16 +0200 Subject: [PATCH 36/82] Fix potential crash --- apps/widbaroalarm/ChangeLog | 1 + apps/widbaroalarm/metadata.json | 2 +- apps/widbaroalarm/widget.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/widbaroalarm/ChangeLog b/apps/widbaroalarm/ChangeLog index c12cc0d65..5786741c7 100644 --- a/apps/widbaroalarm/ChangeLog +++ b/apps/widbaroalarm/ChangeLog @@ -1,2 +1,3 @@ 0.01: Initial version 0.02: Do not warn multiple times for the same exceedance +0.03: Fix crash diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json index 9c58a41ab..134f03623 100644 --- a/apps/widbaroalarm/metadata.json +++ b/apps/widbaroalarm/metadata.json @@ -2,7 +2,7 @@ "id": "widbaroalarm", "name": "Barometer Alarm Widget", "shortName": "Barometer Alarm", - "version": "0.02", + "version": "0.03", "description": "A widget that can alarm on when the pressure reaches defined thresholds.", "icon": "widget.png", "type": "widget", diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 5d62156eb..2745db8ad 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -104,7 +104,7 @@ saveSetting("lastHighWarningTs", 0); } - if (!alreadyWarned) { + if (history3.length > 0 && !alreadyWarned) { // 3h change detection const drop3halarm = setting("drop3halarm"); const raise3halarm = setting("raise3halarm"); From a558d3398504149b6ba04f5aa89c393a50818794 Mon Sep 17 00:00:00 2001 From: boski1987 <35831740+boski1987@users.noreply.github.com> Date: Fri, 29 Apr 2022 19:02:01 +0200 Subject: [PATCH 37/82] Update boot.js edit uncodeRemap to map polish characters to characters supported by Bangle. --- apps/ios/boot.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/ios/boot.js b/apps/ios/boot.js index a3b23a79d..5ea7550eb 100644 --- a/apps/ios/boot.js +++ b/apps/ios/boot.js @@ -115,7 +115,23 @@ E.on('notify',msg=>{ // could also use NRF.ancsGetAppInfo(msg.appId) here }; var unicodeRemap = { - '2019':"'" + '2019':"'", + '260':"A", + '261':"a", + '262':"C", + '263':"c", + '280':"E", + '281':"e", + '321':"L", + '322':"l", + '323':"N", + '324':"n", + '346':"S", + '347':"s", + '377':"Z", + '378':"z", + '379':"Z", + '380':"z", }; var replacer = ""; //(n)=>print('Unknown unicode '+n.toString(16)); //if (appNames[msg.appId]) msg.a From 124ab84e4c2419d2c6fadc809e0066e6363ba475 Mon Sep 17 00:00:00 2001 From: Marco H Date: Fri, 29 Apr 2022 20:40:22 +0200 Subject: [PATCH 38/82] Obey system quiet mode & extend allowed dismiss delay --- apps/activityreminder/ChangeLog | 1 + apps/activityreminder/README.md | 4 ++-- apps/activityreminder/app.js | 7 +++++-- apps/activityreminder/metadata.json | 2 +- apps/activityreminder/settings.js | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/activityreminder/ChangeLog b/apps/activityreminder/ChangeLog index 6681ac41d..ef387d098 100644 --- a/apps/activityreminder/ChangeLog +++ b/apps/activityreminder/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Fix the settings bug and some tweaking 0.03: Do not alarm while charging +0.04: Obey system quiet mode diff --git a/apps/activityreminder/README.md b/apps/activityreminder/README.md index 1e643fb54..c2bc18da8 100644 --- a/apps/activityreminder/README.md +++ b/apps/activityreminder/README.md @@ -1,13 +1,13 @@ # Activity reminder A reminder to take short walks for the ones with a sedentary lifestyle. -The alert will popup only if you didn't take your short walk yet +The alert will popup only if you didn't take your short walk yet. Different settings can be personalized: - Enable : Enable/Disable the app - Start hour: Hour to start the reminder - End hour: Hour to end the reminder - Max inactivity: Maximum inactivity time to allow before the alert. From 15 to 60 min -- Dismiss delay: Delay added before the next alert if the alert is dismissed. From 5 to 15 min +- Dismiss delay: Delay added before the next alert if the alert is dismissed. From 5 to 60 min - Min steps: Minimal amount of steps to count as an activity diff --git a/apps/activityreminder/app.js b/apps/activityreminder/app.js index 310dc10b0..811399ca6 100644 --- a/apps/activityreminder/app.js +++ b/apps/activityreminder/app.js @@ -13,8 +13,11 @@ function drawAlert(){ } load(); }); - - Bangle.buzz(400); + + // Obey system quiet mode: + if (!(require('Storage').readJSON('setting.json',1)||{}).quiet) { + Bangle.buzz(400); + } setTimeout(load, 20000); } diff --git a/apps/activityreminder/metadata.json b/apps/activityreminder/metadata.json index 7fd425ceb..89b0fbc0b 100644 --- a/apps/activityreminder/metadata.json +++ b/apps/activityreminder/metadata.json @@ -3,7 +3,7 @@ "name": "Activity Reminder", "shortName":"Activity Reminder", "description": "A reminder to take short walks for the ones with a sedentary lifestyle", - "version":"0.03", + "version":"0.04", "icon": "app.png", "type": "app", "tags": "tool,activity", diff --git a/apps/activityreminder/settings.js b/apps/activityreminder/settings.js index 9b9a0ecd8..e4f44efc6 100644 --- a/apps/activityreminder/settings.js +++ b/apps/activityreminder/settings.js @@ -43,7 +43,7 @@ }, 'Dismiss delay': { value: settings.dismissDelayMin, - min: 5, max: 15, + min: 5, max: 60, onchange: v => { settings.dismissDelayMin = v; require("activityreminder").writeSettings(settings); From f3fb1465147335acf62d30098ad8c199f3e6a7e2 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Fri, 29 Apr 2022 22:52:21 +0200 Subject: [PATCH 39/82] Add .jekyll-cache to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fce2efb1a..231851dd6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ tests/Layout/bin/tmp.* tests/Layout/testresult.bmp apps.local.json _site +.jekyll-cache From c4ec72004e6fb73eb109d96d7f85f65857a71efc Mon Sep 17 00:00:00 2001 From: Marco H Date: Sat, 30 Apr 2022 11:19:01 +0200 Subject: [PATCH 40/82] Add notice --- apps/activityreminder/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/activityreminder/README.md b/apps/activityreminder/README.md index c2bc18da8..e8be66f3c 100644 --- a/apps/activityreminder/README.md +++ b/apps/activityreminder/README.md @@ -9,5 +9,6 @@ Different settings can be personalized: - End hour: Hour to end the reminder - Max inactivity: Maximum inactivity time to allow before the alert. From 15 to 60 min - Dismiss delay: Delay added before the next alert if the alert is dismissed. From 5 to 60 min + Notice: If Dissmiss delay > Max inactivity then it will be equal Max inactivity - Min steps: Minimal amount of steps to count as an activity From 2e8744ca22f42d699792a786e58eb3ed532caa94 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Sun, 1 May 2022 18:02:15 +0100 Subject: [PATCH 41/82] Move changes to smpltmr --- apps/smpltmr/ChangeLog | 3 +- apps/smpltmr/README.md | 15 +- apps/smpltmr/app.js | 255 ++++++++++++++--------- apps/smpltmr/description.png | Bin 7771 -> 0 bytes apps/smpltmr/metadata.json | 4 +- apps/timersimple/ChangeLog | 1 - apps/timersimple/README.md | 12 -- apps/timersimple/icons8-time-span-48.png | Bin 1933 -> 0 bytes apps/timersimple/metadata.json | 18 -- apps/timersimple/timersimple-scr1.png | Bin 3232 -> 0 bytes apps/timersimple/timersimple-scr2.png | Bin 3017 -> 0 bytes apps/timersimple/timersimple.app.js | 185 ---------------- apps/timersimple/timersimple.icon.js | 1 - 13 files changed, 159 insertions(+), 335 deletions(-) delete mode 100644 apps/smpltmr/description.png delete mode 100644 apps/timersimple/ChangeLog delete mode 100644 apps/timersimple/README.md delete mode 100644 apps/timersimple/icons8-time-span-48.png delete mode 100644 apps/timersimple/metadata.json delete mode 100644 apps/timersimple/timersimple-scr1.png delete mode 100644 apps/timersimple/timersimple-scr2.png delete mode 100644 apps/timersimple/timersimple.app.js delete mode 100644 apps/timersimple/timersimple.icon.js diff --git a/apps/smpltmr/ChangeLog b/apps/smpltmr/ChangeLog index 07afedd21..bf128e2fb 100644 --- a/apps/smpltmr/ChangeLog +++ b/apps/smpltmr/ChangeLog @@ -1 +1,2 @@ -0.01: Release \ No newline at end of file +0.01: Release +0.02: Rewrite with new interface \ No newline at end of file diff --git a/apps/smpltmr/README.md b/apps/smpltmr/README.md index 1296166e2..2c6e6f9ab 100644 --- a/apps/smpltmr/README.md +++ b/apps/smpltmr/README.md @@ -1,21 +1,12 @@ # Simple Timer -A simple app to set a timer quickly. Simply tab on top/bottom/left/right -to select the minutes and tab in the middle of the screen to start/stop -the timer. Note that this timer depends on qalarm. - -# Overview -If you open the app, you can simply control the timer -by clicking on top, bottom, left or right of the screen. -If you tab at the middle of the screen, the timer is -started / stopped. - -![](description.png) +A simple app to set a timer quickly. Drag or tap on the up and down buttons over the hour, minute or second to set the time. +This app uses the `sched` library, which allows the timer to continue to run in the background when this app is closed. # Creator [David Peer](https://github.com/peerdavid) - +[Sir Indy](https://github.com/sir-indy) # Thanks to... Time icon created by CreativeCons - Flaticon \ No newline at end of file diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index eb01e27d0..5f893b054 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -1,124 +1,173 @@ -/* - * SIMPLE TIMER - * - * Creator: David Peer - * Date: 02/2022 - */ +const secondsToTime = (s) => new Object({h:Math.floor((s/3600) % 24), m:Math.floor((s/60) % 60), s:Math.floor(s % 60)}); +const clamp = (num, min, max) => Math.min(Math.max(num, min), max); +function formatTime(s) { + var t = secondsToTime(s); + if (t.h) { + return t.h + ':' + ("0" + t.m).substr(-2) + ':' + ("0" + t.s).substr(-2); + } else { + return t.m + ':' + ("0" + t.s).substr(-2); + } +} +const timerID = "simpletimer"; Bangle.loadWidgets(); +Bangle.drawWidgets(); +var Layout = require("Layout"); +var seconds = 5 * 60; // Default to 5 minutes +var drawTimeout; +var imgArrow = Graphics.createImage(` + x + xxx + xxx + xxxxx + xxxxx + xxx xxx + xxx xxx +xxx xxx +xxx xxx +`); -const alarm = require("sched"); +const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/w=="); +const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); -const TIMER_IDX = "smpltmr"; -const screenWidth = g.getWidth(); -const screenHeight = g.getHeight(); -const cx = parseInt(screenWidth/2); -const cy = parseInt(screenHeight/2)-12; -var minutes = 5; -var interval; //used for the 1 second interval timer - - -function isTimerEnabled(){ - var alarmObj = alarm.getAlarm(TIMER_IDX); - if(alarmObj===undefined || !alarmObj.on){ - return false; +function onDrag(event) { + Bangle.buzz(20, 0.3); + var diff = -Math.round(event.dy/5); + if (event.x < timePickerLayout.hours.w) { + diff *= 3600; + } else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) { + diff *= 60; } - - return true; + updateTimePicker(diff); } -function getTimerMin(){ - var alarmObj = alarm.getAlarm(TIMER_IDX); - return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000)); -} - -function setTimer(minutes){ - alarm.setAlarm(TIMER_IDX, { - // msg : "Simple Timer", - timer : minutes*60*1000, - }); - alarm.reload(); -} - -function deleteTimer(){ - alarm.setAlarm(TIMER_IDX, undefined); - alarm.reload(); -} - -setWatch(_=>load(), BTN1); -function draw(){ - g.clear(1); - Bangle.drawWidgets(); - - if (interval) { - clearInterval(interval); +function onTouch(button, xy) { + var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; + var diff = 0; + if (xy.y > 24 && xy.y < touchMidpoint - 10) { + Bangle.buzz(40, 0.3); + diff = 1; + } else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { + Bangle.buzz(40, 0.3); + diff = -1; + } else if (xy.y > timePickerLayout.btnStart.y) { + Bangle.buzz(40, 0.6); + runTimer(); + return; } - interval = undefined; - - // Write time - g.setFontAlign(0, 0, 0); - g.setFont("Vector", 32).setFontAlign(0,-1); - - var started = isTimerEnabled(); - var text = minutes + " min."; - if(started){ - var min = getTimerMin(); - text = min + " min."; + if (xy.x < timePickerLayout.hours.w) { + diff *= 3600; + } else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) { + diff *= 60; } + updateTimePicker(diff); +} - var rectWidth = parseInt(g.stringWidth(text) / 2); - - if(started){ - interval = setInterval(draw, 1000); - g.setColor("#ff0000"); +function onButton() { + var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); + g.clearRect(Bangle.appRect); + if (timeToNext != undefined) { + runTimer(); } else { - g.setColor(g.theme.fg); + runTimePicker(); } - g.fillRect(cx-rectWidth-5, cy-5, cx+rectWidth, cy+30); - - g.setColor(g.theme.bg); - g.drawString(text, cx, cy); } +function updateTimePicker(diff) { + seconds = clamp(seconds + (diff || 0), 0, 24 * 3600 - 1); + var set_time = secondsToTime(seconds); + updateLayoutField(timePickerLayout, 'hours', set_time.h); + updateLayoutField(timePickerLayout, 'mins', set_time.m); + updateLayoutField(timePickerLayout, 'secs', set_time.s); +} -Bangle.on('touch', function(btn, e){ - var left = parseInt(g.getWidth() * 0.25); - var right = g.getWidth() - left; - var upper = parseInt(g.getHeight() * 0.25); - var lower = g.getHeight() - upper; +function updateLayoutField(layout, field, value) { + layout.clear(layout[field]); + layout[field].label = value; + layout.render(layout[field]); +} - var isLeft = e.x < left; - var isRight = e.x > right; - var isUpper = e.y < upper; - var isLower = e.y > lower; - var isMiddle = !isLeft && !isRight && !isUpper && !isLower; - var started = isTimerEnabled(); +function updateTimer() { + var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); + updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000)); + queueDraw(1000); +} - if(isRight && !started){ - minutes += 1; - Bangle.buzz(40, 0.3); - } else if(isLeft && !started){ - minutes -= 1; - Bangle.buzz(40, 0.3); - } else if(isUpper && !started){ - minutes += 5; - Bangle.buzz(40, 0.3); - } else if(isLower && !started){ - minutes -= 5; - Bangle.buzz(40, 0.3); - } else if(isMiddle) { - if(!started){ - setTimer(minutes); - } else { - deleteTimer(); - } - Bangle.buzz(80, 0.6); - } - minutes = Math.max(0, minutes); +function queueDraw(millisecs) { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + updateTimer(); + }, millisecs - (Date.now() % millisecs)); +} - draw(); +function timerStop() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000; + require("sched").setAlarm(timerID, undefined); + require("sched").reload(); + runTimePicker(); +} + +function runTimePicker() { + g.clearRect(Bangle.appRect); + Bangle.setUI({ + mode : "custom", + touch : function(n,e) {onTouch(n,e);}, + drag : function(e) {onDrag(e);}, + btn : function(n) {onButton();}, + }); + timePickerLayout.render(); + updateTimePicker(); + //timePickerLayout.debug(); +} + +function runTimer() { + require("sched").setAlarm(timerID, { + vibrate : ".-.-", + hidden: true, + timer : seconds * 1000 + }); + require("sched").reload(); + g.clearRect(Bangle.appRect); + timerLayout.render(); + updateTimer(); +} + +var timePickerLayout = new Layout({ + type:"v", c: [ + {type:undefined, height:2}, + {type:"h", c: [ + {type:"v", width:g.getWidth()/3, c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Hours", col:g.theme.fg2}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"00", id:"hours", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} + ]}, + {type:"v", width:g.getWidth()/3, c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Minutes", col:g.theme.fg2}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"00", id:"mins", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} + ]}, + {type:"v", width:g.getWidth()/3, c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Seconds", col:g.theme.fg2}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"20%", label:"00", id:"secs", filly:1, fillx:1}, + {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} + ]}, + ]}, + {type:"btn", src:imgPlay, id:"btnStart", fillx:1 } + ], filly:1 }); -g.reset(); -draw(); \ No newline at end of file +var timerLayout = new Layout({ + type:"v", c: [ + {type:"txt", font:"22%", label:"0:00", id:"timer", fillx:1, filly:1 }, + {type:"btn", src:imgPause, cb: l=>timerStop(), fillx:1 } + ], filly:1 +}); + +onButton(); \ No newline at end of file diff --git a/apps/smpltmr/description.png b/apps/smpltmr/description.png deleted file mode 100644 index 1286d1ab94e56658995ba8dabe08bfc7dea51bc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7771 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 SWZ<+Iq^bmYRH|V9`ab}V`IlM% diff --git a/apps/smpltmr/metadata.json b/apps/smpltmr/metadata.json index 06bad962d..ee5c7ce9b 100644 --- a/apps/smpltmr/metadata.json +++ b/apps/smpltmr/metadata.json @@ -2,10 +2,10 @@ "id": "smpltmr", "name": "Simple Timer", "shortName": "Simple Timer", - "version": "0.01", + "version": "0.02", "description": "A very simple app to start a timer.", "icon": "app.png", - "tags": "tool", + "tags": "tool,alarm,timer", "dependencies": {"scheduler":"type"}, "supports": ["BANGLEJS2"], "screenshots": [{"url":"screenshot.png"}, {"url": "screenshot_2.png"}], diff --git a/apps/timersimple/ChangeLog b/apps/timersimple/ChangeLog deleted file mode 100644 index 7b83706bf..000000000 --- a/apps/timersimple/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -0.01: First release diff --git a/apps/timersimple/README.md b/apps/timersimple/README.md deleted file mode 100644 index 894a46e7a..000000000 --- a/apps/timersimple/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Simple Timer - -TESTING - DO NOT INSTALL, MAY BE BROKEN - -Does one thing well. Set a time in hours, minutes and seconds, and alerts you when time is up. Opening the app while the timer is running (or just leaving the app open) shows how much time is left on the timer. This is the part I felt was missing from the Alarms and Timer app. - -Drag or tap on the up and down buttons over the hour, minute or second to set the time. - -![](timersimple-scr1.png) -![](timersimple-scr2.png) - -Written by: [Sir Indy](https://github.com/sir-indy) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/timersimple/icons8-time-span-48.png b/apps/timersimple/icons8-time-span-48.png deleted file mode 100644 index 9a9dfb6abd1801997481d40bd41e475afe845f1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1933 zcmV;82Xgp{P)}f;`d3 z{4|bF%roc{(>PYg>)2T4uNQwW0+8Ygn zw6{|X*_#deBv!4>$$!2UDtwRtR+g1(ggqUDi`B3w1D||bZ8oxLjVqIK^H_${Y^z~l z4qgh>@{lV8OUG!WT9`-!KJBimUYE47XSH$tg5tx3jsS-xFyB^uwzDMC;IL=l!y5-< z9+954uQIM*AISi#lMCP$CvkuJ4u)O*aEx9--^e9+r0Ecf=!uc#t|RYnvWwyLAC`go z?%yS^GUR=enP|!kU-~Re#w|gd=<}d^s2vxspT^kKkXqR19O8=wOG^ls-(f)m?_4{g zFW`RgpNxbx8DS|_K+V7$d{n|$jx%WMJqbznDr)IjZYFiFu&+^B5r751fyc1Hwpj5C zfh8P%XxfioJo9HP)2AqE$&bX?v9}lML({h39gzCC-!JN^E^y&m@Z=oN4bkCgbVMQwY= z*zAbfFN;ZmOl8~{`+A-uz>|e9nCd!CJ0_IvRcAnwn3n+P0ASKRj=tMAtW3&7f<7H2 zI>#qXY|Z(Z@>SCLAit>AHpqY=2n+~H{kd(AmO#hGAuWClRwX@&1bsTFOrxvX4>~Ru zJ95hcI0}>%e^MOu#snGg6E*WLM0JofT47ge>o>5KdAF#$Bv=7xfvTbZp6TV6R*5nj$K=3XG9ERMqDlz z>g(%q>((vJb~&kmV-sNE8K6L}e|dR=DX3#Y2rL#0Y&IL3o12lJpO1k7CtiQ`D4u(! z6ixMQkfp%o_x}C+sH>~PzJ2?UnVE?L2M(a2p+VC?#n0qV=B z!M~vA;xz{W0ES^;u~^XA*$J!F3bWaakvk(Ot9l%zZ?1#gZigs}U>F8lw{AsMRTZvX zyM_}dPH6V4=Yz&xrX-?rBbfukFeoi8MM+5s($muc3Q(Csuh*lxx*EmB#aOW-=&3FV zY6d0&%kx24*)GTc-?{xVK<8gx zuQY?JL+Ac4BDK&x)CR9K<4+B+o!jinc50_lnSj*$a~H0khL1+~tfK{=Ea80rX$4E_ z)l!kF_W_obYXHn=1IDI?@Rj3CbX98LOGhKdrvnxo4+X7JYpZHN*wZmcfm(mAt@k9H z<2}(+83NAn9-Qkt6~Iy8gGx)gY62^OsT7&SwJ%$GR z8<6CH6YUreIpm!qk|9-Y~btXXO?+BBgadZuyMRxK!B*jK2-{l-V))ssgCmz0~7A7~9{puZA!bcD6>M4aR)Z`rw@fW8YLWV&yWxJwCsS^1Op#z=x9{zFq~ zY5UkGlC_kO_W*bzjaPw(0`GD>zcy0wz!HD*mA4dTF~Ca{v=ksKBa5a^fU#20noyfm zIEc<~RzYCIg7cdI6#g&uVFr+e@9x)=00sf{fxt#&($02nvq$4M>q9)m_Z|NQLRok` Trm{7g00000NkvXXu0mjfz&ofF diff --git a/apps/timersimple/metadata.json b/apps/timersimple/metadata.json deleted file mode 100644 index 5d0e5d5e4..000000000 --- a/apps/timersimple/metadata.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id":"timersimple", - "name":"Timer Simple", - "shortName": "Timer Simple", - "version": "0.01", - "description": "Sets a single timer, and tells you how long left.", - "readme": "README.md", - "icon":"icons8-time-span-48.png", - "screenshots": [{"url":"timersimple-scr1.png"},{"url":"timersimple-scr2.png"}], - "tags": "tool,alarm,timer", - "supports": ["BANGLEJS2"], - "dependencies": {"scheduler":"type"}, - "allow_emulator": true, - "storage": [ - {"name":"timersimple.app.js","url":"timersimple.app.js"}, - {"name":"timersimple.img","url":"timersimple.icon.js","evaluate":true} - ] - } \ No newline at end of file diff --git a/apps/timersimple/timersimple-scr1.png b/apps/timersimple/timersimple-scr1.png deleted file mode 100644 index 5556f8ecc0f2b0c0e343e144f53b2a90741e55c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3232 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 diff --git a/apps/timersimple/timersimple.app.js b/apps/timersimple/timersimple.app.js deleted file mode 100644 index 1c775b908..000000000 --- a/apps/timersimple/timersimple.app.js +++ /dev/null @@ -1,185 +0,0 @@ -const secondsToTime = (s) => new Object({h:Math.floor((s/3600) % 24), m:Math.floor((s/60) % 60), s:Math.floor(s % 60)}); -const clamp = (num, min, max) => Math.min(Math.max(num, min), max); -function formatTime(s) { - var t = secondsToTime(s); - if (t.h) { - return t.h + ':' + ("0" + t.m).substr(-2) + ':' + ("0" + t.s).substr(-2); - } else { - return t.m + ':' + ("0" + t.s).substr(-2); - } -} -const timerID = "simpletimer"; - -Bangle.loadWidgets(); -Bangle.drawWidgets(); - -var Layout = require("Layout"); -var seconds = 5 * 60; // Default to 5 minutes -var drawTimeout; -var timerLayout; -var timePickerLayout; -var imgArrow = Graphics.createImage(` - x - xxx - xxx - xxxxx - xxxxx - xxx xxx - xxx xxx -xxx xxx -xxx xxx -`); - -const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/w=="); -const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); - -function onDrag(event) { - Bangle.buzz(20, 0.3); - var diff = -Math.round(event.dy/5); - if (event.x < timePickerLayout.hours.w) { - diff *= 3600; - } else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) { - diff *= 60; - } - updateTimePicker(diff); -} - -function onTouch(button, xy) { - var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; - var diff = 0; - if (xy.y > 24 && xy.y < touchMidpoint - 10) { - Bangle.buzz(40, 0.3); - diff = 1; - } else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { - Bangle.buzz(40, 0.3); - diff = -1; - } else if (xy.y > timePickerLayout.btnStart.y) { - Bangle.buzz(40, 0.6); - runTimer(); - return; - } - if (xy.x < timePickerLayout.hours.w) { - diff *= 3600; - } else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) { - diff *= 60; - } - updateTimePicker(diff); -} - -function updateTimePicker(diff) { - seconds = clamp(seconds + (diff || 0), 0, 24 * 3600 - 1); - var set_time = secondsToTime(seconds); - updateLayoutField(timePickerLayout, 'hours', set_time.h); - updateLayoutField(timePickerLayout, 'mins', set_time.m); - updateLayoutField(timePickerLayout, 'secs', set_time.s); -} - -function updateLayoutField(layout, field, value) { - layout.clear(layout[field]); - layout[field].label = value; - layout.render(layout[field]); -} - -function updateTimer() { - var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); - updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000)); - //var d = new Date(); - //updateLayoutField(timerLayout, 'time', require("locale").time(d,1)); - queueDraw(1000); -} - -function queueDraw(millisecs) { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - updateTimer(); - }, millisecs - (Date.now() % millisecs)); -} - -function timerStop() { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; - seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000; - require("sched").setAlarm(timerID, undefined); - require("sched").reload(); - runTimePicker(); -} - -var timePickerLayoutCode = { - type:"v", c: [ - {type:undefined, height:2}, - //{type:"txt", font:"15%", label:"TIMER", id:"title"}, - {type:"h", c: [ - {type:"v", width:g.getWidth()/3, c: [ - {type:"txt", font:"6x8", label:/*LANG*/"Hours", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, - {type:"txt", font:"20%", label:"00", id:"hours", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} - ]}, - {type:"v", width:g.getWidth()/3, c: [ - {type:"txt", font:"6x8", label:/*LANG*/"Minutes", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, - {type:"txt", font:"20%", label:"00", id:"mins", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} - ]}, - {type:"v", width:g.getWidth()/3, c: [ - {type:"txt", font:"6x8", label:/*LANG*/"Seconds", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, - {type:"txt", font:"20%", label:"00", id:"secs", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} - ]}, - ]}, - {type:"btn", src:imgPlay, id:"btnStart", fillx:1 } - //{type:"btn", label:'Start', font:"20%", id:"btnStart", fillx:0 } - ], filly:1 -}; - -var timerLayoutCode = { - type:"v", c: [ - {type:undefined, height:8}, - //{type:"txt", font:"6x8", label:/*LANG*/"Timer", id:"title", col:g.theme.fg2}, - {type:"txt", font:"22%", label:"0:00", id:"timer", fillx:1, filly:1 }, - //{type:"h", c: [ - // {type:"txt", font:"6x8", pad:8, label:/*LANG*/"Time Now:", halign:-1, col:g.theme.fg2}, - // {type:"txt", font:"6x8", label:"00:00", id:"time", halign:1, col:g.theme.fg2}, - //]}, - {type:"btn", src:imgPause, cb: l=>timerStop(), fillx:1 } - ], filly:1 -}; - -function runTimePicker() { - g.clearRect(Bangle.appRect); - timePickerLayout = new Layout(timePickerLayoutCode); - Bangle.setUI({ - mode : "custom", - touch : function(n,e) {onTouch(n,e);}, - drag : function(e) {onDrag(e);}, - btn : function(n) {runTimer();}, - }); - timePickerLayout.render(); - updateTimePicker(); - //timePickerLayout.debug(); -} - -function runTimer() { - require("sched").setAlarm(timerID, { - vibrate : ".-.-", - hidden: true, - timer : seconds * 1000 - }); - require("sched").reload(); - g.clearRect(Bangle.appRect); - timerLayout = new Layout(timerLayoutCode); - timerLayout.render(); - updateTimer(); -} - -var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); -if (timeToNext != undefined) { - g.clearRect(Bangle.appRect); - timerLayout = new Layout(timerLayoutCode); - timerLayout.render(); - updateTimer(); -} else { - runTimePicker(); -} diff --git a/apps/timersimple/timersimple.icon.js b/apps/timersimple/timersimple.icon.js deleted file mode 100644 index cd40303a0..000000000 --- a/apps/timersimple/timersimple.icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("mEwwcBkmSpIC/ARf//9JkQRMCAIRBAwIRKv4RFpARIz4QCCIdJiREJAAgJCCI0nCI3+BgOJCIs/CI3/9MkyJoIAAxuGp4RJ8gRQ/mSogRDu4RJNwKSEqXfCJPSCImSrYRJ+SkEyVfCJP6CIo1B4wRHUgIREA4MAj4SHCIeUCIP//EAt4RHkQRF//ggIDB+EHCJf/wEAAAQRM/0CoAmCCJf/4VDI5pcCNwoRKNZ4RMUIQRLYowAIYozpRrYRJ+QREqVLCJPSpGSCIdJv5GIyQREpVJfA///mSogRDpNJloRH8mSBwQRDku/CIwMBCIspkmXCAvpkmRCIslAYKkETwMkxIRFkmkyVLNwYJCBwgCDAwyeEAQqSBAwiMEAQwGFBxACDygDBkQOKAX4CD")) \ No newline at end of file From eca76d78ba51126342855cda72a486b68f05814d Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Sun, 1 May 2022 18:11:00 +0100 Subject: [PATCH 42/82] Update to button press --- apps/smpltmr/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 5f893b054..25a11361b 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -53,7 +53,7 @@ function onTouch(button, xy) { diff = -1; } else if (xy.y > timePickerLayout.btnStart.y) { Bangle.buzz(40, 0.6); - runTimer(); + onButton(); return; } if (xy.x < timePickerLayout.hours.w) { From d42afd7f9e00efb9cad0de517075e918c099d1a0 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Sun, 1 May 2022 18:20:59 +0100 Subject: [PATCH 43/82] Tweak to button --- apps/smpltmr/app.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 25a11361b..72cb3b387 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -68,9 +68,9 @@ function onButton() { var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); g.clearRect(Bangle.appRect); if (timeToNext != undefined) { - runTimer(); + timerRun(); } else { - runTimePicker(); + timerStop(); } } @@ -102,15 +102,6 @@ function queueDraw(millisecs) { }, millisecs - (Date.now() % millisecs)); } -function timerStop() { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; - seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000; - require("sched").setAlarm(timerID, undefined); - require("sched").reload(); - runTimePicker(); -} - function runTimePicker() { g.clearRect(Bangle.appRect); Bangle.setUI({ @@ -124,7 +115,7 @@ function runTimePicker() { //timePickerLayout.debug(); } -function runTimer() { +function timerRun() { require("sched").setAlarm(timerID, { vibrate : ".-.-", hidden: true, @@ -136,6 +127,15 @@ function runTimer() { updateTimer(); } +function timerStop() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000; + require("sched").setAlarm(timerID, undefined); + require("sched").reload(); + runTimePicker(); +} + var timePickerLayout = new Layout({ type:"v", c: [ {type:undefined, height:2}, From ea0d17afebceefdc5fb8402cc6935522f6e3e5d6 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Sun, 1 May 2022 18:25:55 +0100 Subject: [PATCH 44/82] Fix start time --- apps/smpltmr/app.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 72cb3b387..27cbe52c4 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -130,7 +130,10 @@ function timerRun() { function timerStop() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000; + var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); + if (timeToNext != undefined) { + seconds = timeToNext / 1000; + } require("sched").setAlarm(timerID, undefined); require("sched").reload(); runTimePicker(); From 4ee8b843bee607fa255b53b3c1f1d071d0ab00c6 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Sun, 1 May 2022 18:38:49 +0100 Subject: [PATCH 45/82] Update to select running mode --- apps/smpltmr/app.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 27cbe52c4..7bee1ad20 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -16,6 +16,7 @@ Bangle.drawWidgets(); var Layout = require("Layout"); var seconds = 5 * 60; // Default to 5 minutes var drawTimeout; +var timerRunning = False; var imgArrow = Graphics.createImage(` x xxx @@ -32,7 +33,7 @@ const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/ const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); function onDrag(event) { - Bangle.buzz(20, 0.3); + Bangle.buzz(40, 0.3); var diff = -Math.round(event.dy/5); if (event.x < timePickerLayout.hours.w) { diff *= 3600; @@ -65,12 +66,11 @@ function onTouch(button, xy) { } function onButton() { - var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); g.clearRect(Bangle.appRect); - if (timeToNext != undefined) { - timerRun(); - } else { + if (timerRunning) { timerStop(); + } else { + timerRun(); } } @@ -82,12 +82,6 @@ function updateTimePicker(diff) { updateLayoutField(timePickerLayout, 'secs', set_time.s); } -function updateLayoutField(layout, field, value) { - layout.clear(layout[field]); - layout[field].label = value; - layout.render(layout[field]); -} - function updateTimer() { var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000)); @@ -173,4 +167,13 @@ var timerLayout = new Layout({ ], filly:1 }); +function updateLayoutField(layout, field, value) { + layout.clear(layout[field]); + layout[field].label = value; + layout.render(layout[field]); +} + +if (require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) != undefined) { + timerRunning = True; +} onButton(); \ No newline at end of file From cebdf1453c7975e1ba1d124e0777a33f9492a878 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Sun, 1 May 2022 18:45:52 +0100 Subject: [PATCH 46/82] True False to true false --- apps/smpltmr/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 7bee1ad20..350c2f5d8 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -16,7 +16,7 @@ Bangle.drawWidgets(); var Layout = require("Layout"); var seconds = 5 * 60; // Default to 5 minutes var drawTimeout; -var timerRunning = False; +var timerRunning = false; var imgArrow = Graphics.createImage(` x xxx @@ -174,6 +174,6 @@ function updateLayoutField(layout, field, value) { } if (require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) != undefined) { - timerRunning = True; + timerRunning = true; } onButton(); \ No newline at end of file From bbb4a92383b65cecc75d7a6b6fd50e113431f2f8 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Sun, 1 May 2022 20:58:10 +0100 Subject: [PATCH 47/82] Set timer running properly --- apps/smpltmr/app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 350c2f5d8..502891c6a 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -68,8 +68,10 @@ function onTouch(button, xy) { function onButton() { g.clearRect(Bangle.appRect); if (timerRunning) { + timerRunning = false; timerStop(); } else { + timerRunning = true; timerRun(); } } From cfb737e1c0c49ee7929d259a8a555698d8a3a254 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 2 May 2022 01:36:24 +0200 Subject: [PATCH 48/82] kbtouch v0.02 - introduce settings for layout... ...and functionality. --- apps/kbtouch/ChangeLog | 1 + apps/kbtouch/README.md | 11 ++++++ apps/kbtouch/lib.js | 81 ++++++++++++++++++++++++++++---------- apps/kbtouch/metadata.json | 5 ++- apps/kbtouch/settings.js | 59 +++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 22 deletions(-) create mode 100644 apps/kbtouch/settings.js diff --git a/apps/kbtouch/ChangeLog b/apps/kbtouch/ChangeLog index 5560f00bc..17e824c00 100644 --- a/apps/kbtouch/ChangeLog +++ b/apps/kbtouch/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Introduced settings to customize the layout and functionality of the keyboard. diff --git a/apps/kbtouch/README.md b/apps/kbtouch/README.md index 513ba9239..07188ff0c 100644 --- a/apps/kbtouch/README.md +++ b/apps/kbtouch/README.md @@ -2,6 +2,17 @@ A library that provides an on-screen keyboard for text input. +## Settings ( -> Apps -> kbtouch ) +Text size - small or big text font. Default=Big. Suggested=Small. + +Offset keyboard - display the keyboard on top, making it faster to see what character you have selected. Default=No. Suggested=Yes. + +Loop around - should the keyboard highlight loop around when going past the edges? Default=Yes. Suggested=No. + +One-to-one input and release to select - should the input correspond directly to discrete areas on the screen, instead of being handled by scaled relative changes in position on swipes? Default=No. Suggested=Yes. + +Speed scaling - how much should a swipe move the highligt on the keyboard? Higher number corresponds to slower movement. Not applicable if using one-to-one input. Default=24. Suggested=15. + ## Usage In your app's metadata, add: diff --git a/apps/kbtouch/lib.js b/apps/kbtouch/lib.js index 3dfdce00c..a1c90795a 100644 --- a/apps/kbtouch/lib.js +++ b/apps/kbtouch/lib.js @@ -69,13 +69,29 @@ var KEYEXTRA = [ String.fromCharCode(27,91,53,126), // 0x84 page up String.fromCharCode(27,91,54,126), // 0x85 page down ]; + +var settings = Object.assign({ + // default values + textSize: 1, + offsetKeyboard: 0, + loopAround: 1, + oneToOne: 0, + speedScaling: 24 +}, require('Storage').readJSON("kbtouch.settings.json", true) || {}); +print(settings); + +//settings = { "textSize": 1, "offsetKeyboard": 0, "oneToOne": 1, +// "speedScaling": 15, "loopAround": 0 /*, "releaseToSelect": 0*/}; + +print(settings); // state const R = Bangle.appRect; var kbx = 0, kby = 0, kbdx = 0, kbdy = 0, kbShift = false, flashToggle = false; -const PX=12, PY=16, DRAGSCALE=24; -var xoff = 3, yoff = g.getHeight()-PY*4; +const PX=12, PY=16, DRAGSCALE=settings.speedScaling; +var xoff = 3, yoff = g.getHeight()-PY*(4+5*settings.offsetKeyboard); function draw() { + "ram"; var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER; //g.drawImage(KEYIMG,0,yoff); g.reset().setFont("6x8:2"); @@ -88,9 +104,9 @@ function draw() { g.drawString(map[1],xoff,yoff+PY); g.drawString(map[2],xoff,yoff+PY*2); g.drawString(map[3],xoff,yoff+PY*3); - var l = g.setFont("6x8:4").wrapString(text+(flashToggle?"_":" "), R.w-8); - if (l.length>2) l=l.slice(-2); - g.drawString(l.join("\n"),R.x+4,R.y+4); + var l = g.setFont(settings.textSize ? "6x8:4":"6x8:2").wrapString(text+(flashToggle?"_":" "), R.w-8); + if (l.length>2+2*settings.textSize) l=l.slice(-(2+2*settings.textSize)); + g.drawString(l.join("\n"),R.x+4,R.y+4 +82*settings.offsetKeyboard); g.flip(); } @@ -104,24 +120,49 @@ function draw() { return new Promise((resolve,reject) => { Bangle.setUI({mode:"custom", drag:e=>{ - kbdx += e.dx; - kbdy += e.dy; - var dx = Math.round(kbdx/DRAGSCALE), dy = Math.round(kbdy/DRAGSCALE); - kbdx -= dx*DRAGSCALE; - kbdy -= dy*DRAGSCALE; - if (dx || dy) { - kbx = (kbx+dx+15)%15; - kby = (kby+dy+4)%4; + if (settings.oneToOne) { + kbx = Math.max(Math.min(Math.floor((e.x-16) / (6*2)) , 13) , 0); + kby = Math.max(Math.min(Math.floor((e.y-120) / (8*2)) , 4) , 0); + //print(e.y, kby, e.x, kbx); + } + + if (!settings.oneToOne) { + kbdx += e.dx; + kbdy += e.dy; + var dx = Math.round(kbdx/DRAGSCALE), dy = Math.round(kbdy/DRAGSCALE); + kbdx -= dx*DRAGSCALE; + kbdy -= dy*DRAGSCALE; + if (dx || dy) { + if (settings.loopAround) { + kbx = (kbx+dx+15)%15; + kby = (kby+dy+4)%4; + } else { + kbx = Math.max(Math.min((kbx+dx),13),0); + kby = Math.max(Math.min((kby+dy),3),0); + } + } + } + draw(); + + if (!e.b && e.y>Bangle.appRect.y && settings.oneToOne /*&& settings.releaseToSelect*/) { + var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER; + var ch = map[kby][kbx]; + if (ch=="\2") kbShift=!kbShift; + else if (ch=="\b") text = text.slice(0,-1); + else text += ch; + Bangle.buzz(20); draw(); } },touch:()=>{ - var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER; - var ch = map[kby][kbx]; - if (ch=="\2") kbShift=!kbShift; - else if (ch=="\b") text = text.slice(0,-1); - else text += ch; - Bangle.buzz(20); - draw(); + if ( !settings.oneToOne /*|| !settings.releaseToSelect*/) { + var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER; + var ch = map[kby][kbx]; + if (ch=="\2") kbShift=!kbShift; + else if (ch=="\b") text = text.slice(0,-1); + else text += ch; + Bangle.buzz(20); + draw(); + } },back:()=>{ clearInterval(flashInterval); Bangle.setUI(); diff --git a/apps/kbtouch/metadata.json b/apps/kbtouch/metadata.json index da8b6c3c6..f6d6d5228 100644 --- a/apps/kbtouch/metadata.json +++ b/apps/kbtouch/metadata.json @@ -1,6 +1,6 @@ { "id": "kbtouch", "name": "Touch keyboard", - "version":"0.01", + "version":"0.02", "description": "A library for text input via onscreen keyboard", "icon": "app.png", "type":"textinput", @@ -9,6 +9,7 @@ "screenshots": [{"url":"screenshot.png"}], "readme": "README.md", "storage": [ - {"name":"textinput","url":"lib.js"} + {"name":"textinput","url":"lib.js"}, + {"name":"kbtouch.settings.js","url":"settings.js"} ] } diff --git a/apps/kbtouch/settings.js b/apps/kbtouch/settings.js new file mode 100644 index 000000000..871cc5d32 --- /dev/null +++ b/apps/kbtouch/settings.js @@ -0,0 +1,59 @@ +(function(back) { + function settings() { + let settings = require('Storage').readJSON("kbtouch.settings.json", true) || {}; + if (settings.textSize===undefined) settings.textSize=1; + if (settings.offsetKeyboard===undefined) settings.offsetKeyboard=0; + if (settings.loopAround===undefined) settings.loopAround=1; + if (settings.oneToOne===undefined) settings.oneToOne=0; + if (settings.speedScaling===undefined) settings.speedScaling=24; + return settings; + } + + function updateSetting(setting, value) { + let settings = require('Storage').readJSON("kbtouch.settings.json", true) || {}; + settings[setting] = value; + require('Storage').writeJSON("kbtouch.settings.json", settings); + } + + var mainmenu = { + "" : { "title" : /*LANG*/"Touch Keyboard" }, + "< Back" : back, + /*LANG*/'Text size': { + value: settings().textSize, + min: 0, max: 1, + format: v => [/*LANG*/"Small",/*LANG*/"Big"][v], + onchange: v => updateSetting("textSize", v) + }, + /*LANG*/'Offset keyboard': { + value: settings().offsetKeyboard, + min: 0, max: 1, + format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], + onchange: v => updateSetting("offsetKeyboard", v) + }, + /*LANG*/'Loop around': { + value: settings().loopAround, + min: 0, max: 1, + format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], + onchange: v => updateSetting("loopAround", v) + }, + /*LANG*/'One-to-one input and release to select': { + value: settings().oneToOne, + min: 0, max: 1, + format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], + onchange: v => updateSetting("oneToOne", v) + }, + /*LANG*/'Speed scaling': { + value: settings().speedScaling, + min: 1, max: 24, step : 1, + format: v => v, + onchange: v => updateSetting("speedScaling", v) + } + ///*LANG*/'Release to select': { + // value: 1|settings().fontSize, + // min: 0, max: 1, + // format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], + // onchange: v => updateSetting("releaseToSelect", v) + //} + }; + E.showMenu(mainmenu); +}) From d0f57e9b2fe5cb930098ac4ac9efd6ecea336132 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 2 May 2022 01:43:51 +0200 Subject: [PATCH 49/82] Update README.md --- apps/kbtouch/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbtouch/README.md b/apps/kbtouch/README.md index 07188ff0c..6bd0337a8 100644 --- a/apps/kbtouch/README.md +++ b/apps/kbtouch/README.md @@ -2,7 +2,7 @@ A library that provides an on-screen keyboard for text input. -## Settings ( -> Apps -> kbtouch ) +## Settings Text size - small or big text font. Default=Big. Suggested=Small. Offset keyboard - display the keyboard on top, making it faster to see what character you have selected. Default=No. Suggested=Yes. From d32735c6864a01570706954faca20538a1daf247 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 2 May 2022 02:11:27 +0200 Subject: [PATCH 50/82] Update lib.js --- apps/kbtouch/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbtouch/lib.js b/apps/kbtouch/lib.js index a1c90795a..614fb8e96 100644 --- a/apps/kbtouch/lib.js +++ b/apps/kbtouch/lib.js @@ -122,7 +122,7 @@ function draw() { Bangle.setUI({mode:"custom", drag:e=>{ if (settings.oneToOne) { kbx = Math.max(Math.min(Math.floor((e.x-16) / (6*2)) , 13) , 0); - kby = Math.max(Math.min(Math.floor((e.y-120) / (8*2)) , 4) , 0); + kby = Math.max(Math.min(Math.floor((e.y-120) / (8*2)) , 3) , 0); //print(e.y, kby, e.x, kbx); } From 0f47f917467dc989d1d4047c745f56fe06039d49 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 2 May 2022 02:13:38 +0200 Subject: [PATCH 51/82] Update lib.js --- apps/kbtouch/lib.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/kbtouch/lib.js b/apps/kbtouch/lib.js index 614fb8e96..db90440b9 100644 --- a/apps/kbtouch/lib.js +++ b/apps/kbtouch/lib.js @@ -78,12 +78,7 @@ var settings = Object.assign({ oneToOne: 0, speedScaling: 24 }, require('Storage').readJSON("kbtouch.settings.json", true) || {}); -print(settings); -//settings = { "textSize": 1, "offsetKeyboard": 0, "oneToOne": 1, -// "speedScaling": 15, "loopAround": 0 /*, "releaseToSelect": 0*/}; - -print(settings); // state const R = Bangle.appRect; var kbx = 0, kby = 0, kbdx = 0, kbdy = 0, kbShift = false, flashToggle = false; From 072ce2444db6e615bcd270da27ecc47e95c9095f Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Mon, 2 May 2022 10:59:07 +0100 Subject: [PATCH 52/82] Change timerRunning to a function, and other bits --- apps/smpltmr/app.js | 101 +++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 502891c6a..de02319fd 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -1,3 +1,17 @@ +/* + * SIMPLE TIMER + * + * Creator: David Peer + * Date: 02/2022 + * + * Modified: Sir Indy + * Date: 05/2022 + */ + +const Layout = require("Layout"); +const alarm = require("sched") +const TIMER_IDX = "smpltmr"; + const secondsToTime = (s) => new Object({h:Math.floor((s/3600) % 24), m:Math.floor((s/60) % 60), s:Math.floor(s % 60)}); const clamp = (num, min, max) => Math.min(Math.max(num, min), max); function formatTime(s) { @@ -8,16 +22,14 @@ function formatTime(s) { return t.m + ':' + ("0" + t.s).substr(-2); } } -const timerID = "simpletimer"; -Bangle.loadWidgets(); -Bangle.drawWidgets(); - -var Layout = require("Layout"); var seconds = 5 * 60; // Default to 5 minutes var drawTimeout; -var timerRunning = false; -var imgArrow = Graphics.createImage(` +//var timerRunning = false; +function timerRunning() { + return (alarm.getTimeToAlarm(alarm.getAlarm(TIMER_IDX)) != undefined) +} +const imgArrow = Graphics.createImage(` x xxx xxx @@ -33,23 +45,25 @@ const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/ const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); function onDrag(event) { - Bangle.buzz(40, 0.3); - var diff = -Math.round(event.dy/5); - if (event.x < timePickerLayout.hours.w) { - diff *= 3600; - } else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) { - diff *= 60; + if (timerRunning()) { + Bangle.buzz(40, 0.3); + var diff = -Math.round(event.dy/5); + if (event.x < timePickerLayout.hours.w) { + diff *= 3600; + } else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) { + diff *= 60; + } + updateTimePicker(diff); } - updateTimePicker(diff); } function onTouch(button, xy) { var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; var diff = 0; - if (xy.y > 24 && xy.y < touchMidpoint - 10) { + if (timerRunning() && xy.y > 24 && xy.y < touchMidpoint - 10) { Bangle.buzz(40, 0.3); diff = 1; - } else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { + } else if (timerRunning() && xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { Bangle.buzz(40, 0.3); diff = -1; } else if (xy.y > timePickerLayout.btnStart.y) { @@ -67,11 +81,9 @@ function onTouch(button, xy) { function onButton() { g.clearRect(Bangle.appRect); - if (timerRunning) { - timerRunning = false; + if (timerRunning()) { timerStop(); } else { - timerRunning = true; timerRun(); } } @@ -85,7 +97,7 @@ function updateTimePicker(diff) { } function updateTimer() { - var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); + var timeToNext = alarm.getTimeToAlarm(alarm.getAlarm(TIMER_IDX)); updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000)); queueDraw(1000); } @@ -98,26 +110,13 @@ function queueDraw(millisecs) { }, millisecs - (Date.now() % millisecs)); } -function runTimePicker() { - g.clearRect(Bangle.appRect); - Bangle.setUI({ - mode : "custom", - touch : function(n,e) {onTouch(n,e);}, - drag : function(e) {onDrag(e);}, - btn : function(n) {onButton();}, - }); - timePickerLayout.render(); - updateTimePicker(); - //timePickerLayout.debug(); -} - function timerRun() { - require("sched").setAlarm(timerID, { + alarm.setAlarm(TIMER_IDX, { vibrate : ".-.-", hidden: true, timer : seconds * 1000 }); - require("sched").reload(); + alarm.reload(); g.clearRect(Bangle.appRect); timerLayout.render(); updateTimer(); @@ -126,13 +125,15 @@ function timerRun() { function timerStop() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)); + var timeToNext = alarm.getTimeToAlarm(alarm.getAlarm(TIMER_IDX)); if (timeToNext != undefined) { seconds = timeToNext / 1000; } - require("sched").setAlarm(timerID, undefined); - require("sched").reload(); - runTimePicker(); + alarm.setAlarm(TIMER_IDX, undefined); + alarm.reload(); + g.clearRect(Bangle.appRect); + timePickerLayout.render(); + updateTimePicker(); } var timePickerLayout = new Layout({ @@ -175,7 +176,21 @@ function updateLayoutField(layout, field, value) { layout.render(layout[field]); } -if (require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) != undefined) { - timerRunning = true; -} -onButton(); \ No newline at end of file +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +Bangle.setUI({ + mode : "custom", + touch : function(n,e) {onTouch(n,e);}, + drag : function(e) {onDrag(e);}, + btn : function(n) {onButton();}, +}); + +g.clearRect(Bangle.appRect); +if (timerRunning()) { + timerLayout.render(); + updateTimer(); +} else { + timePickerLayout.render(); + updateTimePicker(); +} \ No newline at end of file From d49980291c646f707b3acfd46b49efdd1ae886c8 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Mon, 2 May 2022 11:14:35 +0100 Subject: [PATCH 53/82] correct onTouch if timerRunning --- apps/smpltmr/app.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index de02319fd..2904fd6a1 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -45,7 +45,7 @@ const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/ const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); function onDrag(event) { - if (timerRunning()) { + if (!timerRunning()) { Bangle.buzz(40, 0.3); var diff = -Math.round(event.dy/5); if (event.x < timePickerLayout.hours.w) { @@ -84,7 +84,9 @@ function onButton() { if (timerRunning()) { timerStop(); } else { - timerRun(); + if (seconds > 0) { + timerRun(); + } } } From ba0a1be37395f396c3ba44599ea6fe60fdf37a8d Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Mon, 2 May 2022 11:32:57 +0100 Subject: [PATCH 54/82] Tweak Readme.md --- apps/smpltmr/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/smpltmr/README.md b/apps/smpltmr/README.md index 2c6e6f9ab..310332955 100644 --- a/apps/smpltmr/README.md +++ b/apps/smpltmr/README.md @@ -4,8 +4,9 @@ A simple app to set a timer quickly. Drag or tap on the up and down buttons over This app uses the `sched` library, which allows the timer to continue to run in the background when this app is closed. -# Creator +# Creators [David Peer](https://github.com/peerdavid) + [Sir Indy](https://github.com/sir-indy) # Thanks to... From a95af8225b1ef4aedb93a6ea033f7b93c8a3fdd1 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Mon, 2 May 2022 12:30:07 +0100 Subject: [PATCH 55/82] Added screenshots --- apps/smpltmr/screenshot.png | Bin 1845 -> 0 bytes apps/smpltmr/screenshot_1.png | Bin 0 -> 2940 bytes apps/smpltmr/screenshot_2.png | Bin 1950 -> 2496 bytes apps/smpltmr/screenshot_3.png | Bin 0 -> 2715 bytes apps/smpltmr/screenshot_4.png | Bin 0 -> 2994 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/smpltmr/screenshot.png create mode 100644 apps/smpltmr/screenshot_1.png create mode 100644 apps/smpltmr/screenshot_3.png create mode 100644 apps/smpltmr/screenshot_4.png diff --git a/apps/smpltmr/screenshot.png b/apps/smpltmr/screenshot.png deleted file mode 100644 index eff94475c73638521c0dc59ff9ec55182f609d2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1845 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(Y4M?uv{v-}aF%}28J29*~C-ahlf$hDgi(^Pd z+}qiKlNKBBu%7(OKUcTRJd~$-VopVqxYhh-<&$gsl6{_;`d+Sn#L5`Vq|ajZRwnho zYQq6@@rQr+T^E1y+EhFE%da!F>gr75Uz1FDnf|L^pCHlbepajMzWakqQ}dJare85! ze_-M`+oX?^!(1r(YN05 zUn=@~hHH1)E|DFI5N*eT9;}`EnR$Wg=WATu2NvJD^Srij~2yWZt$P7^8?HeYqN_FlPpKOR{N6b&?wG5b55k+pJnUz*s*Q@nrPzGufLnPvczZb-@UaeX8zmyVgX^ zjHnJi^Gq=+jUiFD%<2|!47mqF}Pn!OwF`6l~BXr{8?VR^b z{sl6v4}Z?JQ>&ey8>sxPq%K=@Ltesar+JC-vYVz5+vfEQ6 z_CEKpt^MUE%%tBjcQ2EB@4MWvZ_P6-89Sx!7t2WIo;CW~v#H~mq15)1RkPGy>YuAt z3E^7Sv$t(^R?;_*PaOw7$5d5?nU=G}{at=wqMGaK4zCB(VlK89FPRr;r@T{XUiEc- zOSjW?U;CWybjh3k!t9)ndMy9JV|j*so4D52)BKVf{Ug)kq^JaK@_}qI}O^xkl|6WrVIOj!G8SA+tmbY&6+9R2WXAV;h3!S&t^6R=4dmryFVm)WJMm(&n#_WIO<3$!1OT!+V6SdH0di;k& z=5N{CxgS-v3-TxSd{=BZV7GVCC0-_u9iv(YW#6nR?9uY z+&)RB(uB;ivAH#?hHkE3_1*dT`wx77c-@|_*XxJZ>+ycRAFu4d0B<#AJ!JrZny-&% zkj&QnD~ju6y1H>HLS|qILEi45ii4H_pt94~b8j#yLVBB@JZYrr#sBqdhEr#^Ig_&C zO4Ezf2xoub=Y1GbsJCEw;pc|3&3wAr+1{*QzAgyL2U2JsTlo`v zp_BEfKGP?Br?}nQ#~i9vf!89Vte}Yb4@Mlhu&|E*{B33*7LDmr_v)QAv4l*t(tZro62uk zo;jw#GnT*TqcsDYmwbL17nNQOBOowO3}+554Gd!t~u~5vjpQY#n2SwXB9y z%526Atnq?w2|hJMe*o6fJzbNGyYyt!&(p0!MOP4T8`D^})jVy_IcFmBw`@FDR?>fw zQe_kX<2XJ1-tdRk>`2i`ffQJCihm_?m|R&yY(&VUobGw?92$AI9sUCynkN6 z+{|sM@2{X@leNp7yOC*1#4~$dYTO?pM;1)$WAc3`Axq=fLslIfmXH;vkj49v#lu&< zTS(hI{CW;BMCGZS&m`rmkfqtkUas6{NvEVLYmK^)lT$l#{rqd|E_Rk@z3Qdyp9fxs zqzdZVau=n?U_AJQfX+__LYck-odPU}Fa?On&~R0G4hs$j3do9bDYrM>#^Pe zDqrJTU3)F>WMW9mAWJqy77RUgY0EFlpSdgzCxGYk^=(&&~*m)0H6gH zMJN6NC@sFPAyZk|28)DTf-)dF#^{nVQdX;E8=^7`x3XbxO7)u8C%P7e@J;`(OIEk!!jD|Hfte+@G~0+KiDQVgR$xNVYb{l*U*g%Q%e zb{x6i#%}Yw;W;0S@AY!oV2oocwyorlvs- zv?eVp8c>em@Up2teciANJcqc-V4gc|N&*+DmD)g5`PzFPsKT+^0EE3k6TwjHo*o92 zMr*@oa2wUrl>qz|?v{bTp?IOxS&+_W_xdf@2iB}^sX4-oaio-Ija3#7v{q5Zti%O5 z_KW{4H^VLccUaH&WMYeV3?IH4>C6dOHmJqN8(g2%0EQ-c`%x6W_FJ%v`Jf8mHTAEb zPL;T&hQzCuN_QM>n049FHw*lJ7A*E;R;u?ceMRDX=|7v5T7vvX0l~LE@nFpbyHO>P ze(Z?sU&?jqtcmUoMR2E>lG41nuoMHGB09{H;OzYVC^-dvwi|VG<J1|h3C#d5E z!Gnxic}$I04IOdRo*zi(wXVkE-hHp_%7Z&Hhn4@tuXYnzJBOi%l4xH!iq%J@)qHEF zO+~Dozu>0Z&>m|&P~+u#OxW+Geeuwl2ie#`hMpq8ZmwI@4-Zc5qHVB`!>@!)yrBM1 zClQz9xzJvk6H7xO+_almtM#9T$aq1ev`zF4#c){QE*RLdtc>IF4>Y>0QXd)krqGP7 z-p!I{0|#X*9Dgr4N_7zi(78{N*AaBZ%*t(0x$ZWl=4$&vIt^K{Zg z__wg;2jPIektELOK6zcQM|g!HKh@uytPoO{cvnq1L<`_@Qoi4=0^q=Q80`NwM9Iw$ zHQHTV+?QTL@v09JwoH+yI`&tA&pux*ypn!@gn4JtjD#-{c^HXc&NOq5oNLB?DKd)Av?ZHj}o=J%qb!Fx$n{wF>-qeZ+d@5-xTkB4k{j?%c{fjief zX;JV|^KQyMGM+vPs>cSwKt!FTyxAc@Dc|2u@Rd>YWu5x9U>KlVc(s_xxM}vl?oi2K<;h9jR69}(X>fzk%p1$g-@g5Apz=lC;HaA2f)a71`^*FT zYyx9X??)vY&g-HRjduQ&rNz68d_(4YPLyIu8Km?@1;Q1w;EmH$OW7mY*UE|t_cfo*;c+_85y zXs~a6lC$b7bqfU|t{gtulz`Sj9DbAFT*(BoX>o2zpIaVB_g{61dmO3~m#qa+<3yDm z?1@CtuufP>I+l{YwI)lhZ+p|v-3ond`DRwcUq+!hf literal 0 HcmV?d00001 diff --git a/apps/smpltmr/screenshot_2.png b/apps/smpltmr/screenshot_2.png index 7b5dc9a3df7dc091d1dfe6d8dd3aa29c51351127..fb0145f17dde8dd27f1f443d7b4ac722657c6a88 100644 GIT binary patch literal 2496 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 literal 0 HcmV?d00001 diff --git a/apps/smpltmr/screenshot_4.png b/apps/smpltmr/screenshot_4.png new file mode 100644 index 0000000000000000000000000000000000000000..c0f984378e178638882b93c8c3d2b8a1f70aa475 GIT binary patch literal 2994 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 Date: Mon, 2 May 2022 12:30:18 +0100 Subject: [PATCH 56/82] updated readme --- apps/smpltmr/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/smpltmr/README.md b/apps/smpltmr/README.md index 310332955..eeb48d338 100644 --- a/apps/smpltmr/README.md +++ b/apps/smpltmr/README.md @@ -4,6 +4,11 @@ A simple app to set a timer quickly. Drag or tap on the up and down buttons over This app uses the `sched` library, which allows the timer to continue to run in the background when this app is closed. +![](screenshot_1.png) +![](screenshot_2.png) +![](screenshot_3.png) +![](screenshot_4.png) + # Creators [David Peer](https://github.com/peerdavid) From 51807e2b9ae988b7130f79ff5dc08150c4b09a6e Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Mon, 2 May 2022 12:31:57 +0100 Subject: [PATCH 57/82] Update onTouch to work properly --- apps/smpltmr/app.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 2904fd6a1..63aeafa91 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -60,14 +60,12 @@ function onDrag(event) { function onTouch(button, xy) { var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; var diff = 0; - if (timerRunning() && xy.y > 24 && xy.y < touchMidpoint - 10) { - Bangle.buzz(40, 0.3); + Bangle.buzz(40, 0.3); + if (!timerRunning() && xy.y > 24 && xy.y < touchMidpoint - 10) { diff = 1; - } else if (timerRunning() && xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { - Bangle.buzz(40, 0.3); + } else if (!timerRunning() && xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { diff = -1; } else if (xy.y > timePickerLayout.btnStart.y) { - Bangle.buzz(40, 0.6); onButton(); return; } From c5e1adc7a2384c9839a98007885a23a80989b284 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Mon, 2 May 2022 12:33:22 +0100 Subject: [PATCH 58/82] Add screenshots to metadata.json --- apps/smpltmr/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smpltmr/metadata.json b/apps/smpltmr/metadata.json index ee5c7ce9b..cb1ef6eab 100644 --- a/apps/smpltmr/metadata.json +++ b/apps/smpltmr/metadata.json @@ -8,7 +8,7 @@ "tags": "tool,alarm,timer", "dependencies": {"scheduler":"type"}, "supports": ["BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}, {"url": "screenshot_2.png"}], + "screenshots": [{"url":"screenshot_1.png"}, {"url": "screenshot_2.png"}, {"url": "screenshot_3.png"}, {"url": "screenshot_4.png"}], "readme": "README.md", "storage": [ {"name":"smpltmr.app.js","url":"app.js"}, From cc8a606fd5903471a4cdec06dfe2cd150ecccb54 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Mon, 2 May 2022 18:56:36 +0200 Subject: [PATCH 59/82] waypointe fallback to built in compass heading --- apps/waypointer/ChangeLog | 1 + apps/waypointer/app.js | 8 ++++++-- apps/waypointer/metadata.json | 2 +- apps/waypointer/waypoints.html | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/waypointer/ChangeLog b/apps/waypointer/ChangeLog index 1b584f7dd..7ccad08ea 100644 --- a/apps/waypointer/ChangeLog +++ b/apps/waypointer/ChangeLog @@ -1,2 +1,3 @@ 0.01: New app! 0.02: Make Bangle.js 2 compatible +0.03: Silently use built in heading when no magnav calibration file is present diff --git a/apps/waypointer/app.js b/apps/waypointer/app.js index 615fbbc36..bdb6f6857 100644 --- a/apps/waypointer/app.js +++ b/apps/waypointer/app.js @@ -74,11 +74,14 @@ function newHeading(m,h){ return hd; } -var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; +var CALIBDATA = require("Storage").readJSON("magnav.json",1) || {}; function tiltfixread(O,S){ - var start = Date.now(); var m = Bangle.getCompass(); + if (O === undefined || S === undefined) { + // no valid calibration from magnav, use built in + return 360-m.heading; + } var g = Bangle.getAccel(); m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z; var d = Math.atan2(-m.dx,m.dy)*180/Math.PI; @@ -97,6 +100,7 @@ function tiltfixread(O,S){ // Note actual mag is 360-m, error in firmware function read_compass() { var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); + if (isNaN(d)) return; // built in compass heading can return NaN when uncalibrated heading = newHeading(d,heading); direction = wp_bearing - heading; if (direction < 0) direction += 360; diff --git a/apps/waypointer/metadata.json b/apps/waypointer/metadata.json index 111259bbc..707da94cf 100644 --- a/apps/waypointer/metadata.json +++ b/apps/waypointer/metadata.json @@ -1,7 +1,7 @@ { "id": "waypointer", "name": "Way Pointer", - "version": "0.02", + "version": "0.03", "description": "Navigate to a waypoint using the GPS for bearing and compass to point way, uses the same waypoint interface as GPS Navigation", "icon": "waypointer.png", "tags": "tool,outdoors,gps", diff --git a/apps/waypointer/waypoints.html b/apps/waypointer/waypoints.html index d02260732..7a65821a2 100644 --- a/apps/waypointer/waypoints.html +++ b/apps/waypointer/waypoints.html @@ -73,8 +73,8 @@ event.preventDefault() var name = $name.value.trim() if(!name) return; - var lat = parseFloat($latitude.value).toPrecision(5); - var lon = parseFloat($longtitude.value).toPrecision(5); + var lat = parseFloat($latitude.value); + var lon = parseFloat($longtitude.value); waypoints.push({ name, lat,lon, From 4105f2a65dd4d9823e6b4a073ac010df3f513961 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Mon, 2 May 2022 21:37:31 +0200 Subject: [PATCH 60/82] Add new widget alarmeta This widget displays the time to the next Alarm or Timer in hours and minutes. --- apps/alarmeta/metadata.json | 15 ++++++++++++++ apps/alarmeta/screenshot.png | Bin 0 -> 3491 bytes apps/alarmeta/widget.js | 37 +++++++++++++++++++++++++++++++++++ apps/alarmeta/widget.png | Bin 0 -> 1011 bytes 4 files changed, 52 insertions(+) create mode 100644 apps/alarmeta/metadata.json create mode 100644 apps/alarmeta/screenshot.png create mode 100644 apps/alarmeta/widget.js create mode 100644 apps/alarmeta/widget.png diff --git a/apps/alarmeta/metadata.json b/apps/alarmeta/metadata.json new file mode 100644 index 000000000..0130a63ef --- /dev/null +++ b/apps/alarmeta/metadata.json @@ -0,0 +1,15 @@ +{ + "id": "alarmeta", + "name": "Alarm & Timer ETA", + "shortName": "Alarm ETA", + "version": "0.01", + "description": "A widget that displays the time to the next Alarm or Timer in hours and minutes, maximum 24h", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots" : [ { "url":"screenshot.png" } ], + "storage": [ + {"name":"alarmeta.wid.js","url":"widget.js"} + ] +} diff --git a/apps/alarmeta/screenshot.png b/apps/alarmeta/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..41a1095570813bd8d950a8a7d4da4d3eb7102fe9 GIT binary patch literal 3491 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 O09Qv(hqrd<)c*sBA&|ZR literal 0 HcmV?d00001 diff --git a/apps/alarmeta/widget.js b/apps/alarmeta/widget.js new file mode 100644 index 000000000..ff08dd6ef --- /dev/null +++ b/apps/alarmeta/widget.js @@ -0,0 +1,37 @@ +(() => { + const alarms = require("Storage").readJSON("sched.json",1) || []; + + function draw() { + const times = alarms.map(alarm => require("sched").getTimeToAlarm(alarm)).filter(a => a !== undefined); + const next = Math.min.apply(null, times); + if (next > 0 && next < 86400000) { + const hours = Math.floor((next % 86400000) / 3600000).toString(); + const minutes = Math.floor(((next % 86400000) % 3600000) / 60000).toString(); + + g.reset(); // reset the graphics context to defaults (color/font/etc) + g.setFontAlign(0,0); // center fonts + g.clearRect(this.x, this.y, this.x+this.width-1, this.y+23); + + // Use 'locale' module to get a shortened month name + // in the correct language + var text = hours.padStart(2, '0') + ":" + minutes.padStart(2, '0'); + g.setFont("6x8:1x2"); + g.drawString(text, this.x+this.width/2, this.y+12); + if (this.width === 0) { + this.width = 6*5+2; + Bangle.drawWidgets(); // width changed, re-layout + } + } + } + + setInterval(function() { + WIDGETS["alarmeta"].draw(WIDGETS["alarmeta"]); + }, 30000); // update every half minute + + // add your widget + WIDGETS["alarmeta"]={ + area:"tl", + width: 0, // hide by default = assume no timer + draw:draw + }; +})(); diff --git a/apps/alarmeta/widget.png b/apps/alarmeta/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..cfd942ea013fdda73add2a8f06f63628f6f4d8eb GIT binary patch literal 1011 zcmV0rD z1-1BOqO}O(lTg8jLJ)2HRIT^}1<@B3tE;kzRZPKx4Rq6xZQYf&R3tTNv)N5%=J>F? z>1LBQGkb19$$nqv-aGf)@Au3-_s*R;&_omK8z!v5=nK!D1oOZx5;L~{?ROsxV-snB z=9Y*D5Euw+(|`kzr0`q47-!tV&62XK{W%u_)k^Kcf`xjV!?yV-@(KK zh{zs|23-hAWNFWi$I93ItdHx5lJJm5f^rSW-Akp)espC%?8YP=8U@-#JX0+c7R%R? z7kX#Cq7k5SK;T5RJX0zQ54$TE_*tVt_zRpmJca$2m^T z6P%p(xocC1A%%1@5&KS~LH{O>_|E}Ffa!T*wiI|4ipKGW)%4l{hI(2v7OOo=Ve>G)@A@8 zeO5NRj{75qdv4HWEWY3jJ=|}u+Tyh806;1)oyPTk0!h@}I_<@rosV~!X`6i3zXwVV z|A1Ur<(BXISor{|g;fWB`BUO;MfVHfkyUQr-|D%?PfSR=O-^eLd@2&1bKTE?!JBj& zD73hrr_xT!*UBPJonLs`h?#4j?n{f(7I zB728=TaK-~5e{kxzRwjC;zfT4HeGKO`X=_%l|KwXzI%kpzR`NRf)Q^=vbSwg!>7d}`nAR6rabR+0O$TyExi|toW z)1Mhx)1*K1Jh#oBTB?g&AEOcI95CDoV8r9T@jXPm`LzlCBKM9zgAuPX1e-Myw0|Wo z19V*ckd4N0pknq*0)p0rMNchQd^6(|93UDaomuc3cD6HSjS&u4f;m z*3Q6YrM4~Px4u}ei1|b#LHT?AF?F^^3}c7COoz(K)Izxi^w}CC;j=Qe_}}LTnn^yJ hSeHq@CYo69_!rhyA?h4K76AYN002ovPDHLkV1g(R?#}=K literal 0 HcmV?d00001 From f52ad2e834a381465edd74002af29f82b3c06c55 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 3 May 2022 07:25:20 +0200 Subject: [PATCH 61/82] alarmeta widget renamed to widalarmeta --- apps/{alarmeta => widalarmeta}/metadata.json | 4 ++-- apps/{alarmeta => widalarmeta}/screenshot.png | Bin apps/{alarmeta => widalarmeta}/widget.js | 6 ++---- apps/{alarmeta => widalarmeta}/widget.png | Bin 4 files changed, 4 insertions(+), 6 deletions(-) rename apps/{alarmeta => widalarmeta}/metadata.json (83%) rename apps/{alarmeta => widalarmeta}/screenshot.png (100%) rename apps/{alarmeta => widalarmeta}/widget.js (86%) rename apps/{alarmeta => widalarmeta}/widget.png (100%) diff --git a/apps/alarmeta/metadata.json b/apps/widalarmeta/metadata.json similarity index 83% rename from apps/alarmeta/metadata.json rename to apps/widalarmeta/metadata.json index 0130a63ef..b6d8bd62b 100644 --- a/apps/alarmeta/metadata.json +++ b/apps/widalarmeta/metadata.json @@ -1,5 +1,5 @@ { - "id": "alarmeta", + "id": "widalarmeta", "name": "Alarm & Timer ETA", "shortName": "Alarm ETA", "version": "0.01", @@ -10,6 +10,6 @@ "supports": ["BANGLEJS","BANGLEJS2"], "screenshots" : [ { "url":"screenshot.png" } ], "storage": [ - {"name":"alarmeta.wid.js","url":"widget.js"} + {"name":"widalarmeta.wid.js","url":"widget.js"} ] } diff --git a/apps/alarmeta/screenshot.png b/apps/widalarmeta/screenshot.png similarity index 100% rename from apps/alarmeta/screenshot.png rename to apps/widalarmeta/screenshot.png diff --git a/apps/alarmeta/widget.js b/apps/widalarmeta/widget.js similarity index 86% rename from apps/alarmeta/widget.js rename to apps/widalarmeta/widget.js index ff08dd6ef..0cddf953a 100644 --- a/apps/alarmeta/widget.js +++ b/apps/widalarmeta/widget.js @@ -12,8 +12,6 @@ g.setFontAlign(0,0); // center fonts g.clearRect(this.x, this.y, this.x+this.width-1, this.y+23); - // Use 'locale' module to get a shortened month name - // in the correct language var text = hours.padStart(2, '0') + ":" + minutes.padStart(2, '0'); g.setFont("6x8:1x2"); g.drawString(text, this.x+this.width/2, this.y+12); @@ -25,11 +23,11 @@ } setInterval(function() { - WIDGETS["alarmeta"].draw(WIDGETS["alarmeta"]); + WIDGETS["widalarmeta"].draw(WIDGETS["widalarmeta"]); }, 30000); // update every half minute // add your widget - WIDGETS["alarmeta"]={ + WIDGETS["widalarmeta"]={ area:"tl", width: 0, // hide by default = assume no timer draw:draw diff --git a/apps/alarmeta/widget.png b/apps/widalarmeta/widget.png similarity index 100% rename from apps/alarmeta/widget.png rename to apps/widalarmeta/widget.png From cf060cfe3e655b49f4f9fd6406d80ffe62d99a1a Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Tue, 3 May 2022 09:12:28 +0100 Subject: [PATCH 62/82] Update app.js --- apps/smpltmr/app.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 63aeafa91..b474b8454 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -29,18 +29,7 @@ var drawTimeout; function timerRunning() { return (alarm.getTimeToAlarm(alarm.getAlarm(TIMER_IDX)) != undefined) } -const imgArrow = Graphics.createImage(` - x - xxx - xxx - xxxxx - xxxxx - xxx xxx - xxx xxx -xxx xxx -xxx xxx -`); - +const imgArrow = atob("CQmBAAgOBwfD47ndx+OA"); const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/w=="); const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA=="); @@ -193,4 +182,4 @@ if (timerRunning()) { } else { timePickerLayout.render(); updateTimePicker(); -} \ No newline at end of file +} From e9bf77578019802e98aebe6812c5ebc37d98037e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 3 May 2022 09:21:13 +0100 Subject: [PATCH 63/82] link in screenshots --- README.md | 10 +++++----- apps/scicalc/metadata.json | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 93507de75..ee555cad2 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ The widget example is available in [`apps/_example_widget`](apps/_example_widget Widgets are just small bits of code that run whenever an app that supports them calls `Bangle.loadWidgets()`. If they want to display something in the 24px high -widget bar at the top of the screen they can add themselves to the global +widget bar at the top of the screen they can add themselves to the global `WIDGETS` array with: ``` @@ -250,7 +250,7 @@ and which gives information about the app for the Launcher. "version": "0v01", // the version of this app "description": "...", // long description (can contain markdown) "icon": "icon.png", // icon in apps/ - "screenshots" : [ { url:"screenshot.png" } ], // optional screenshot for app + "screenshots" : [ { "url":"screenshot.png" } ], // optional screenshot for app "type":"...", // optional(if app) - // 'app' - an application // 'clock' - a clock - required for clocks to automatically start @@ -259,10 +259,10 @@ and which gives information about the app for the Launcher. // 'RAM' - code that runs and doesn't upload anything to storage // 'launch' - replacement 'Launcher' // 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle - // 'scheduler' - provides 'sched' library and boot code for scheduling alarms/timers + // 'scheduler' - provides 'sched' library and boot code for scheduling alarms/timers // (currently only 'sched' app) // 'notify' - provides 'notify' library for showing notifications - // 'locale' - provides 'locale' library for language-specific date/distance/etc + // 'locale' - provides 'locale' library for language-specific date/distance/etc // (a version of 'locale' is included in the firmware) "tags": "", // comma separated tag list for searching "supports": ["BANGLEJS2"], // List of device IDs supported, either BANGLEJS or BANGLEJS2 @@ -419,7 +419,7 @@ Example `settings.js` // make sure to enclose the function in parentheses (function(back) { let settings = require('Storage').readJSON('myappid.json',1)||{}; - if (typeof settings.monkeys !== "number") settings.monkeys = 12; // default value + if (typeof settings.monkeys !== "number") settings.monkeys = 12; // default value function save(key, value) { settings[key] = value; require('Storage').write('myappid.json', settings); diff --git a/apps/scicalc/metadata.json b/apps/scicalc/metadata.json index d2d855dc2..beda619e2 100644 --- a/apps/scicalc/metadata.json +++ b/apps/scicalc/metadata.json @@ -4,10 +4,11 @@ "version":"0.01", "description": "Scientific calculator", "icon": "scicalc.png", + "screenshots" : [ { "url":"scicalc_screenshot1.png" }, { "url":"scicalc_screenshot2.png" }, { "url":"scicalc_screenshot3.png" } ], "readme": "README.md", "tags": "app,tool", "allow_emulator": true, - "supports" : ["BANGLEJS2"], + "supports" : ["BANGLEJS2"], "storage": [ {"name":"scicalc.app.js","url":"app.js"}, {"name":"scicalc.img","url":"app-icon.js","evaluate":true} From 0a93ea7c00af5c65892bc129d4d5807caab80526 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Tue, 3 May 2022 10:06:10 +0100 Subject: [PATCH 64/82] Update Layout.js Remove text scale option, as scale can be set in font, as per #1699 --- modules/Layout.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 19553c0a5..f2ebc418a 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -32,9 +32,9 @@ layoutObject has: * `"v"` - Vertical layout, `c` is an array of more `layoutObject` * A `id` field. If specified the object is added with this name to the returned `layout` object, so can be referenced as `layout.foo` -* A `font` field, eg `6x8` or `30%` to use a percentage of screen height -* A `scale` field, eg `2` to set scale of an image or text -* A `r` field to set rotation of text or images. +* A `font` field, eg `6x8` or `30%` to use a percentage of screen height. Set scale with :, e.g. `6x8:2`. +* A `scale` field, eg `2` to set scale of an image +* A `r` field to set rotation of text or images (0: 0°, 1: 90°, 2: 180°, 3: 270°). * A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` and `fillx`/`filly` to be set. Not compatible with text rotation. * A `col` field, eg `#f00` for red @@ -222,13 +222,13 @@ Layout.prototype.render = function (l) { "":function(){}, "txt":function(l){ if (l.wrap) { - g.setFont(l.font, l.scale||1).setFontAlign(0,-1); + g.setFont(l.font).setFontAlign(0,-1); var lines = g.wrapString(l.label, l.w); var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1); // TODO: on 2v11 we can just render in a single drawString call lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i)); } else { - g.setFont(l.font, l.scale||1).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); + g.setFont(l.font).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); } }, "btn":function(l){ if (l.font && l.font.endsWith("%")) @@ -252,15 +252,15 @@ Layout.prototype.render = function (l) { "function"==typeof l.src?l.src():l.src, l.x + l.w/2, l.y + l.h/2, - {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} + {scale: l.scale||undefined, rotate: Math.PI*0.5*(l.r||0)} ); - else g.setFont(l.font||"6x8", l.scale||2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); + else g.setFont(l.font||"6x8:2").setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); }, "img":function(l){ g.drawImage( "function"==typeof l.src?l.src():l.src, l.x + l.w/2, l.y + l.h/2, - {scale: l.scale ? l.scale : undefined, rotate: Math.PI*0.5*(l.r ? l.r : 0)} + {scale: l.scale||undefined, rotate: Math.PI*0.5*(l.r||0)} ); }, "custom":function(l){ l.render(l); @@ -358,13 +358,13 @@ Layout.prototype.update = function() { if (l.wrap) { l._h = l._w = 0; } else { - var m = g.setFont(l.font, l.scale||1).stringMetrics(l.label); + var m = g.setFont(l.font).stringMetrics(l.label); l._w = m.width; l._h = m.height; } }, "btn": function(l) { if (l.font && l.font.endsWith("%")) l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100); - var m = l.src?g.imageMetrics("function"==typeof l.src?l.src():l.src):g.setFont(l.font||"6x8", l.scale||2).stringMetrics(l.label); + var m = l.src?g.imageMetrics("function"==typeof l.src?l.src():l.src):g.setFont(l.font||"6x8:2").stringMetrics(l.label); l._h = 16 + m.height; l._w = 20 + m.width; }, "img": function(l) { From 4cac27927b2d22eaf19131dccefcbc93771aa69c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 3 May 2022 12:05:09 +0100 Subject: [PATCH 65/82] > Merge branch 'master' of github.com:espruino/EspruinoAppLoaderCore > fix 'not correctly encoded' errors for backups --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 6fc78fc39..32d01b5b3 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 6fc78fc39531a43148ae8d515efaeff9404d1daf +Subproject commit 32d01b5b3d8e013ca0364671e2352b7b0dd48bb4 From fd5e0bf45c925c54576e601705e245d88afeffe1 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Tue, 3 May 2022 12:30:50 +0100 Subject: [PATCH 66/82] Update app.js Fix onTouch while timerRunning. Previously briefly showed timer picker numbers. --- apps/smpltmr/app.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index b474b8454..37d508359 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -50,20 +50,24 @@ function onTouch(button, xy) { var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; var diff = 0; Bangle.buzz(40, 0.3); - if (!timerRunning() && xy.y > 24 && xy.y < touchMidpoint - 10) { - diff = 1; - } else if (!timerRunning() && xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { - diff = -1; - } else if (xy.y > timePickerLayout.btnStart.y) { + if (xy.y > timePickerLayout.btnStart.y) { onButton(); return; } - if (xy.x < timePickerLayout.hours.w) { - diff *= 3600; - } else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) { - diff *= 60; + if (!timerRunning()) { + if (&& xy.y > 24 && xy.y < touchMidpoint - 10) { + diff = 1; + } else if (&& xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { + diff = -1; + } + if (xy.x < timePickerLayout.hours.w) { + diff *= 3600; + } else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) { + diff *= 60; + } + updateTimePicker(diff); } - updateTimePicker(diff); + } function onButton() { From aad0a48a88d9456249b9b109a0ee4230b02675df Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Tue, 3 May 2022 12:33:12 +0100 Subject: [PATCH 67/82] Update app.js Whoops --- apps/smpltmr/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 37d508359..1583663ba 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -55,9 +55,9 @@ function onTouch(button, xy) { return; } if (!timerRunning()) { - if (&& xy.y > 24 && xy.y < touchMidpoint - 10) { + if (xy.y > 24 && xy.y < touchMidpoint - 10) { diff = 1; - } else if (&& xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { + } else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { diff = -1; } if (xy.x < timePickerLayout.hours.w) { From 7d5aa89c2194a03e78b7144e2f9047393e73e25f Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Tue, 3 May 2022 12:54:34 +0100 Subject: [PATCH 68/82] Update app.js Fix layout button uninitialised if timer already running. --- apps/smpltmr/app.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index 1583663ba..b7511724a 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -47,14 +47,15 @@ function onDrag(event) { } function onTouch(button, xy) { - var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; - var diff = 0; - Bangle.buzz(40, 0.3); - if (xy.y > timePickerLayout.btnStart.y) { + if (xy.y > (timePickerLayout.btnStart.y||timerLayout.btnStart.y)) { + Bangle.buzz(40, 0.3); onButton(); return; } if (!timerRunning()) { + var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2; + var diff = 0; + Bangle.buzz(40, 0.3); if (xy.y > 24 && xy.y < touchMidpoint - 10) { diff = 1; } else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) { @@ -159,7 +160,7 @@ var timePickerLayout = new Layout({ var timerLayout = new Layout({ type:"v", c: [ {type:"txt", font:"22%", label:"0:00", id:"timer", fillx:1, filly:1 }, - {type:"btn", src:imgPause, cb: l=>timerStop(), fillx:1 } + {type:"btn", src:imgPause, id:"btnStart", cb: l=>timerStop(), fillx:1 } ], filly:1 }); From ce06879fe46844476d4b7cce1c3926fa931fed15 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 3 May 2022 21:15:40 +0200 Subject: [PATCH 69/82] [date_utils] Refactor functions, documentation - Use the same names used in locale module (so dow instead of getDOW, month instead of getMonth, etc.) - Add documentation --- modules/date_utils.js | 94 +++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/modules/date_utils.js b/modules/date_utils.js index da0ed24d9..7239d4f1f 100644 --- a/modules/date_utils.js +++ b/modules/date_utils.js @@ -1,39 +1,65 @@ -/* Utility functions that use the 'locale' module so can produce text -in the currently selected language. */ +// module "date_utils" +// +// Utility functions that use the "locale" module so can produce +// date-related text in the currently selected language. +// +// Some functions have a "firstDayOfWeek" parameter. +// Most used values are: +// - 0/undefined --> Sunday +// - 1 --> Monday +// but you can start the week from any day if you need it. +// +// Some functions have an "abbreviated" parameter. +// It supports the following 3 values: +// - 0/undefined --> get the full value, without abbreviation (eg.: "Monday", "January", etc.) +// - 1 --> get the short value (eg.: "Mon", "Jan", etc.) +// - 2 --> get only the first char (eg.: "M", "J", etc.) +// -/** Return the day of the week (0=Sunday) - short==0/undefined -> "Sunday" - short==1 -> "Sun" -*/ -exports.getDOW = (dow, short) => require("locale").dow({getDay:()=>dow},short); - -/** Return the month (1=January) - short==0/undefined -> "January" - short==1 -> "Jan" -*/ -exports.getMonth = (month, short) => require("locale").month({getMonth:()=>month-1},short); - -/** Return all 7 days of the week as an array ["Sunday","Monday",...]. - short==0/undefined -> ["Sunday",... - short==1 -> ["Sun",... - short==2 -> ["S",... -*/ -exports.getDOWs = (short) => { - var locale = require("locale"); - var days = []; - for (var i=0;i<7;i++) - days.push(locale.dow({getDay:()=>i},short).slice(0,(short==2)?1:100)); - return days; +/** + * @param {int} i The index of the day of the week (0 = Sunday) + * @param {int} abbreviated + * @returns The localized name of the i-th day of the week + */ +exports.dow = (i, abbreviated) => { + var dow = require("locale").dow(new Date(((i || 0) + 3.5) * 86400000), abbreviated).slice(0, (abbreviated == 2) ? 1 : 100); + return abbreviated == 2 ? dow.toUpperCase() : dow; } -/** Return all 12 months as an array ["January","February",...] - short==0/undefined -> ["January",... - short==1 -> ["Jan",... -*/ -exports.getMonths = (short) => { +/** + * @param {int} firstDayOfWeek 0/undefined -> Sunday, + * 1 -> Monday + * @param {int} abbreviated + * @returns All 7 days of the week (localized) as an array + */ +exports.dows = (firstDayOfWeek, abbreviated) => { + var dows = []; var locale = require("locale"); + for (var i = 0; i < 7; i++) { + dows.push(exports.dow(i + (firstDayOfWeek || 0), abbreviated)) + } + return abbreviated == 2 ? dows.map(dow => dow.toUpperCase()) : dows; +}; + +/** + * @param {int} i The index of the month (1 = January) + * @param {int} abbreviated + * @returns The localized name of the i-th month + */ +exports.month = (i, abbreviated) => { + var month = require("locale").month(new Date((i - 0.5) * 2628000000), abbreviated).slice(0, (abbreviated == 2) ? 1 : 100); + return abbreviated == 2 ? month.toUpperCase() : month; +} + +/** + * @param {int} abbreviated + * @returns All 12 months (localized) as an array + */ +exports.months = (abbreviated) => { var months = []; - for (var i=0;i<12;i++) - months.push(locale.month({getMonth:()=>i},short)); - return months; -} + var locale = require("locale"); + for (var i = 1; i <= 12; i++) { + months.push(locale.month(new Date((i - 0.5) * 2628000000), abbreviated).slice(0, (abbreviated == 2) ? 1 : 100)); + } + return abbreviated == 2 ? months.map(month => month.toUpperCase()) : months; +}; From 74db2585d714f9328aa9e4b3f20a996a9bdc82eb Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Sun, 1 May 2022 22:42:28 +0200 Subject: [PATCH 70/82] [Settings] Add new option for selecting the first day of the week --- apps/setting/README.md | 2 +- apps/setting/settings.js | 35 +++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/apps/setting/README.md b/apps/setting/README.md index 42e3939fb..77bf70845 100644 --- a/apps/setting/README.md +++ b/apps/setting/README.md @@ -7,7 +7,7 @@ This is Bangle.js's settings menu * **Beep** most Bangle.js do not have a speaker inside, but they can use the vibration motor to beep in different pitches. You can change the behaviour here to use a Piezo speaker if one is connected * **Vibration** enable/disable the vibration motor * **Quiet Mode** prevent notifications/alarms from vibrating/beeping/turning the screen on - see below -* **Locale** set time zone/whether the clock is 12/24 hour (for supported clocks) +* **Locale** set time zone, the time format (12/24h, for supported clocks) and the first day of the week * **Select Clock** if you have more than one clock face, select the default one * **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader * **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below. diff --git a/apps/setting/settings.js b/apps/setting/settings.js index afc7e23c8..a2a3dfbf0 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -37,18 +37,19 @@ function internalToG(u) { function resetSettings() { settings = { - ble: true, // Bluetooth enabled by default - blerepl: true, // Is REPL on Bluetooth - can Espruino IDE be used? - log: false, // Do log messages appear on screen? - quiet: 0, // quiet mode: 0: off, 1: priority only, 2: total silence - timeout: 10, // Default LCD timeout in seconds - vibrate: true, // Vibration enabled by default. App must support - beep: BANGLEJS2?true:"vib", // Beep enabled by default. App must support - timezone: 0, // Set the timezone for the device - HID: false, // BLE HID mode, off by default - clock: null, // a string for the default clock's name - "12hour" : false, // 12 or 24 hour clock? - brightness: 1, // LCD brightness from 0 to 1 + ble: true, // Bluetooth enabled by default + blerepl: true, // Is REPL on Bluetooth - can Espruino IDE be used? + log: false, // Do log messages appear on screen? + quiet: 0, // quiet mode: 0: off, 1: priority only, 2: total silence + timeout: 10, // Default LCD timeout in seconds + vibrate: true, // Vibration enabled by default. App must support + beep: BANGLEJS2 ? true : "vib", // Beep enabled by default. App must support + timezone: 0, // Set the timezone for the device + HID: false, // BLE HID mode, off by default + clock: null, // a string for the default clock's name + "12hour" : false, // 12 or 24 hour clock? + firstDayOfWeek: 0, // 0 -> Sunday (default), 1 -> Monday + brightness: 1, // LCD brightness from 0 to 1 // welcomed : undefined/true (whether welcome app should show) options: { wakeOnBTN1: true, @@ -493,6 +494,16 @@ function showLocaleMenu() { settings["12hour"] = v; updateSettings(); } + }, + /*LANG*/'Start Week On': { + value: settings["firstDayOfWeek"] || 0, + min: 0, // Sunday + max: 1, // Monday + format: v => require("date_utils").dow(v, 1), + onchange: v => { + settings["firstDayOfWeek"] = v; + updateSettings(); + }, } }; return E.showMenu(localemenu); From ec4ba0d0a71dd0b1469ec127047dcce7e35617c3 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Mon, 2 May 2022 11:55:05 +0200 Subject: [PATCH 71/82] [Settings] Fix the time zone format A positive value is shown as '+X' instead of 'X' --- apps/setting/settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index a2a3dfbf0..981a7b864 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -479,6 +479,7 @@ function showLocaleMenu() { '< Back': ()=>showSystemMenu(), /*LANG*/'Time Zone': { value: settings.timezone, + format: v => (v > 0 ? "+" : "") + v, min: -11, max: 13, step: 0.5, From fdcb965b5e93eb9d3cc3db31fb39e9be0dd05fba Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Mon, 2 May 2022 12:09:06 +0200 Subject: [PATCH 72/82] [Settings] Improve the "Date & Time" menu - Use month name instead of month number - Move the "time" options after the "date" options --- apps/setting/settings.js | 53 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 981a7b864..9b5bdae68 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -95,7 +95,7 @@ function showSystemMenu() { /*LANG*/'LCD': ()=>showLCDMenu(), /*LANG*/'Locale': ()=>showLocaleMenu(), /*LANG*/'Select Clock': ()=>showClockMenu(), - /*LANG*/'Set Time': ()=>showSetTimeMenu() + /*LANG*/'Date & Time': ()=>showSetTimeMenu() }; return E.showMenu(mainmenu); @@ -488,9 +488,9 @@ function showLocaleMenu() { updateSettings(); } }, - /*LANG*/'Clock Style': { + /*LANG*/'Time Format': { value: !!settings["12hour"], - format: v => v ? "12hr" : "24hr", + format: v => v ? "12h" : "24h", onchange: v => { settings["12hour"] = v; updateSettings(); @@ -618,11 +618,34 @@ function showClockMenu() { function showSetTimeMenu() { d = new Date(); const timemenu = { - '': { 'title': /*LANG*/'Set Time' }, + '': { 'title': /*LANG*/'Date & Time' }, '< Back': function () { setTime(d.getTime() / 1000); showSystemMenu(); }, + /*LANG*/'Day': { + value: d.getDate(), + onchange: function (v) { + this.value = ((v+30)%31)+1; + d.setDate(this.value); + } + }, + /*LANG*/'Month': { + value: d.getMonth() + 1, + format: v => require("date_utils").month(v), + onchange: function (v) { + this.value = ((v+11)%12)+1; + d.setMonth(this.value - 1); + } + }, + /*LANG*/'Year': { + value: d.getFullYear(), + min: 2019, + max: 2100, + onchange: function (v) { + d.setFullYear(v); + } + }, /*LANG*/'Hour': { value: d.getHours(), onchange: function (v) { @@ -643,28 +666,6 @@ function showSetTimeMenu() { this.value = (v+60)%60; d.setSeconds(this.value); } - }, - /*LANG*/'Date': { - value: d.getDate(), - onchange: function (v) { - this.value = ((v+30)%31)+1; - d.setDate(this.value); - } - }, - /*LANG*/'Month': { - value: d.getMonth() + 1, - onchange: function (v) { - this.value = ((v+11)%12)+1; - d.setMonth(this.value - 1); - } - }, - /*LANG*/'Year': { - value: d.getFullYear(), - min: 2019, - max: 2100, - onchange: function (v) { - d.setFullYear(v); - } } }; return E.showMenu(timemenu); From 7abb4c780c28f5b05db4ea78c85d706414fda702 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Mon, 2 May 2022 12:12:19 +0200 Subject: [PATCH 73/82] [Settings] Update metadata and changelog --- apps/setting/ChangeLog | 2 ++ apps/setting/metadata.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index fe259827c..bfd32a130 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -46,3 +46,5 @@ 0.41: Stop users disabling all wake-up methods and locking themselves out (fix #1272) 0.42: Fix theme customizer on new Bangle 2 firmware 0.43: Add some Bangle 1 colours to theme customizer +0.44: Add "Start Week On X" option (#1780) + UI improvements to Locale and Date & Time menu diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index 750752bd7..85dddf9db 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -1,7 +1,7 @@ { "id": "setting", "name": "Settings", - "version": "0.43", + "version": "0.44", "description": "A menu for setting up Bangle.js", "icon": "settings.png", "tags": "tool,system", From ea70f011857389c683e0005ec6fac88574fdff4e Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 3 May 2022 21:34:03 +0200 Subject: [PATCH 74/82] [Alarms & Timers] Add support for Monday as first day of the week --- apps/alarm/app.js | 119 +++++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 44 deletions(-) diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 90a62afc5..25c03c3c5 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -2,10 +2,14 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); // An array of alarm objects (see sched/README.md) -let alarms = require("sched").getAlarms(); +var alarms = require("sched").getAlarms(); + +// 0 = Sunday +// 1 = Monday +var firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0; function getCurrentTime() { - let time = new Date(); + var time = new Date(); return ( time.getHours() * 3600000 + time.getMinutes() * 60000 + @@ -14,6 +18,9 @@ function getCurrentTime() { } function saveAndReload() { + // Before saving revert the dow to the standard format + alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek)); + require("sched").setAlarms(alarms); require("sched").reload(); } @@ -23,30 +30,32 @@ function showMainMenu() { // Alarm img "\0"+atob("FBSBAABgA4YcMPDGP8Zn/mx/48//PP/zD/8A//AP/wD/8A//AP/wH/+D//w//8AAAADwAAYA") const menu = { '': { 'title': /*LANG*/'Alarms&Timers' }, - /*LANG*/'< Back' : ()=>{load();}, - /*LANG*/'New Alarm': ()=>editAlarm(-1), - /*LANG*/'New Timer': ()=>editTimer(-1) + /*LANG*/'< Back': () => { load(); }, + /*LANG*/'New Alarm': () => editAlarm(-1), + /*LANG*/'New Timer': () => editTimer(-1) }; - alarms.forEach((alarm,idx)=>{ - var type,txt; // a leading space is currently required (JS error in Espruino 2v12) + alarms.forEach((alarm, idx) => { + alarm.dow = handleFirstDayOfWeek(alarm.dow, firstDayOfWeek); + + var type, txt; // a leading space is currently required (JS error in Espruino 2v12) if (alarm.timer) { type = /*LANG*/"Timer"; - txt = " "+require("sched").formatTime(alarm.timer); + txt = " " + require("sched").formatTime(alarm.timer); } else { type = /*LANG*/"Alarm"; - txt = " "+require("sched").formatTime(alarm.t); + txt = " " + require("sched").formatTime(alarm.t); } - if (alarm.rp) txt += "\0"+atob("FBaBAAABgAAcAAHn//////wAHsABzAAYwAAMAADAAAAAAwAAMAADGAAzgAN4AD//////54AAOAABgAA="); + if (alarm.rp) txt += "\0" + atob("FBaBAAABgAAcAAHn//////wAHsABzAAYwAAMAADAAAAAAwAAMAADGAAzgAN4AD//////54AAOAABgAA="); // rename duplicate alarms - if (menu[type+txt]) { + if (menu[type + txt]) { var n = 2; - while (menu[type+" "+n+txt]) n++; - txt = type+" "+n+txt; - } else txt = type+txt; + while (menu[type + " " + n + txt]) n++; + txt = type + " " + n + txt; + } else txt = type + txt; // add to menu menu[txt] = { - value : "\0"+atob(alarm.on?"EhKBAH//v/////////////5//x//j//H+eP+Mf/A//h//z//////////3//g":"EhKBAH//v//8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA///3//g"), - onchange : function() { + value: "\0" + atob(alarm.on ? "EhKBAH//v/////////////5//x//j//H+eP+Mf/A//h//z//////////3//g" : "EhKBAH//v//8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA///3//g"), + onchange: function () { setTimeout(alarm.timer ? editTimer : editAlarm, 10, idx, alarm); } }; @@ -69,25 +78,27 @@ function showMainMenu() { function editDOW(dow, onchange) { const menu = { '': { 'title': /*LANG*/'Days of Week' }, - /*LANG*/'< Back' : () => onchange(dow) + /*LANG*/'< Back': () => onchange(dow) }; - for (let i = 0; i < 7; i++) (i => { - let dayOfWeek = require("locale").dow({ getDay: () => i }); - menu[dayOfWeek] = { - value: !!(dow&(1< { + menu[dows[i]] = { + value: !!(dow & (1 << (i + firstDayOfWeek))), format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", - onchange: v => v ? dow |= 1< v ? (dow |= 1 << (i + firstDayOfWeek)) : (dow &= ~(1 << (i + firstDayOfWeek))) }; })(i); E.showMenu(menu); } function editAlarm(alarmIndex, alarm) { - let newAlarm = alarmIndex < 0; - let a = require("sched").newDefaultAlarm(); + var newAlarm = alarmIndex < 0; + var a = require("sched").newDefaultAlarm(); + a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek); + if (!newAlarm) Object.assign(a, alarms[alarmIndex]); - if (alarm) Object.assign(a,alarm); - let t = require("sched").decodeTime(a.t); + if (alarm) Object.assign(a, alarm); + var t = require("sched").decodeTime(a.t); const menu = { '': { 'title': /*LANG*/'Alarm' }, @@ -96,17 +107,17 @@ function editAlarm(alarmIndex, alarm) { showMainMenu(); }, /*LANG*/'Hours': { - value: t.hrs, min : 0, max : 23, wrap : true, - onchange: v => t.hrs=v + value: t.hrs, min: 0, max: 23, wrap: true, + onchange: v => t.hrs = v }, /*LANG*/'Minutes': { - value: t.mins, min : 0, max : 59, wrap : true, - onchange: v => t.mins=v + value: t.mins, min: 0, max: 59, wrap: true, + onchange: v => t.mins = v }, /*LANG*/'Enabled': { value: a.on, format: v => v ? /*LANG*/"On" : /*LANG*/"Off", - onchange: v=>a.on=v + onchange: v => a.on = v }, /*LANG*/'Repeat': { value: a.rp, @@ -114,14 +125,14 @@ function editAlarm(alarmIndex, alarm) { onchange: v => a.rp = v }, /*LANG*/'Days': { - value: "SMTWTFS".split("").map((d,n)=>a.dow&(1< setTimeout(editDOW, 100, a.dow, d => { a.dow = d; a.t = require("sched").encodeTime(t); editAlarm(alarmIndex, a); }) }, - /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate=v ), + /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), /*LANG*/'Auto Snooze': { value: a.as, format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", @@ -156,11 +167,11 @@ function saveAlarm(newAlarm, alarmIndex, a, t) { } function editTimer(alarmIndex, alarm) { - let newAlarm = alarmIndex < 0; - let a = require("sched").newDefaultTimer(); + var newAlarm = alarmIndex < 0; + var a = require("sched").newDefaultTimer(); if (!newAlarm) Object.assign(a, alarms[alarmIndex]); - if (alarm) Object.assign(a,alarm); - let t = require("sched").decodeTime(a.timer); + if (alarm) Object.assign(a, alarm); + var t = require("sched").decodeTime(a.timer); const menu = { '': { 'title': /*LANG*/'Timer' }, @@ -169,26 +180,26 @@ function editTimer(alarmIndex, alarm) { showMainMenu(); }, /*LANG*/'Hours': { - value: t.hrs, min : 0, max : 23, wrap : true, - onchange: v => t.hrs=v + value: t.hrs, min: 0, max: 23, wrap: true, + onchange: v => t.hrs = v }, /*LANG*/'Minutes': { - value: t.mins, min : 0, max : 59, wrap : true, - onchange: v => t.mins=v + value: t.mins, min: 0, max: 59, wrap: true, + onchange: v => t.mins = v }, /*LANG*/'Enabled': { value: a.on, format: v => v ? /*LANG*/"On" : /*LANG*/"Off", onchange: v => a.on = v }, - /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate=v ), + /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), }; menu[/*LANG*/"Cancel"] = () => showMainMenu(); if (!newAlarm) { - menu[/*LANG*/"Delete"] = function() { - alarms.splice(alarmIndex,1); + menu[/*LANG*/"Delete"] = function () { + alarms.splice(alarmIndex, 1); saveAndReload(); showMainMenu(); }; @@ -210,6 +221,26 @@ function saveTimer(newAlarm, alarmIndex, a, t) { saveAndReload(); } +function handleFirstDayOfWeek(dow, firstDayOfWeek) { + if (firstDayOfWeek == 1) { + if ((dow & 1) == 1) { + // By default 1 = Sunday. + // Here the week starts on Monday and Sunday is ON so move Sunday to 128. + dow += 127; + } else if ((dow & 128) == 128) { + dow -= 127; + } + } + return dow; +} + +function decodeDOW(dow) { + return require("date_utils") + .dows(firstDayOfWeek, 2) + .map((day, index) => dow & (1 << (index + firstDayOfWeek)) ? day : "_") + .join(""); +} + function enableAll(on) { E.showPrompt(/*LANG*/"Are you sure?", { title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" From 4d4eccb821c4daf5e2e363fdb585f2c36f2c8752 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 3 May 2022 22:01:04 +0200 Subject: [PATCH 75/82] [Alarms & Timers] Update metadata and changelog --- apps/alarm/ChangeLog | 1 + apps/alarm/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 9daf7bcbf..ca1417b5b 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -25,3 +25,4 @@ 0.24: Automatically save the alarm/timer when the user returns to the main menu using the back arrow Add "Enable All", "Disable All" and "Remove All" actions 0.25: Fix redrawing selected Alarm/Timer entry inside edit submenu +0.26: Add support for Monday as first day of the week (#1780) diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index 33312beb6..c062b030d 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,7 +2,7 @@ "id": "alarm", "name": "Alarms & Timers", "shortName": "Alarms", - "version": "0.25", + "version": "0.26", "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm,widget", From 0ac5822d7a683fce97b59e152580cf5df89db75f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 May 2022 08:33:40 +0100 Subject: [PATCH 76/82] update readme for https://github.com/espruino/BangleApps/pull/1773 --- apps/setting/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/setting/README.md b/apps/setting/README.md index 77bf70845..451b48c06 100644 --- a/apps/setting/README.md +++ b/apps/setting/README.md @@ -9,7 +9,7 @@ This is Bangle.js's settings menu * **Quiet Mode** prevent notifications/alarms from vibrating/beeping/turning the screen on - see below * **Locale** set time zone, the time format (12/24h, for supported clocks) and the first day of the week * **Select Clock** if you have more than one clock face, select the default one -* **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader +* **Date & Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader * **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below. * **Theme** Adjust the colour scheme * **Utils** Utilities - including resetting settings (see below) @@ -35,11 +35,15 @@ This is Bangle.js's settings menu `Wake on Touch` actually uses the accelerometer, and you need to actually tap the display to wake Bangle.js. * **Twist X** these options adjust the sensitivity of `Wake on Twist` to ensure Bangle.js wakes up with just the right amount of wrist movement. +## Locale +* **Time Zone** your current Time zone. This is usually set automatically by the App Loader +* **Time Format** whether you want a 24 or 12 hour clock. However not all clocks will honour this. +* **Start Week On** start the displayed week on Sunday, or Monday. This currently only applies to the Alarm app. ## Quiet Mode -Quiet Mode is a hint to apps and widgets that you do not want to be disturbed. +Quiet Mode is a hint to apps and widgets that you do not want to be disturbed. The exact effects depend on the app. In general the watch will not wake up by itself, but will still respond to button presses. * **Quiet Mode** From 00ccc21fe74f55b89946cce4ec77f02e538dc44f Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 4 May 2022 10:34:34 +0200 Subject: [PATCH 77/82] [Alarms & Timers] Code quality fix https://github.com/espruino/BangleApps/pull/1773#pullrequestreview-961431288 --- apps/alarm/app.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 25c03c3c5..0d4c7c7ee 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -80,14 +80,15 @@ function editDOW(dow, onchange) { '': { 'title': /*LANG*/'Days of Week' }, /*LANG*/'< Back': () => onchange(dow) }; - var dows = require("date_utils").dows(firstDayOfWeek); - for (var i = 0; i < 7; i++) (i => { - menu[dows[i]] = { + + require("date_utils").dows(firstDayOfWeek).forEach((day, i) => (i => { + menu[day] = { value: !!(dow & (1 << (i + firstDayOfWeek))), format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: v => v ? (dow |= 1 << (i + firstDayOfWeek)) : (dow &= ~(1 << (i + firstDayOfWeek))) }; - })(i); + })(i)); + E.showMenu(menu); } From 8d499a10b4b58ca875694602776c618f16d7fcf3 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 May 2022 09:42:27 +0100 Subject: [PATCH 78/82] minor tweak --- apps/alarm/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 0d4c7c7ee..cf46823d6 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -81,13 +81,13 @@ function editDOW(dow, onchange) { /*LANG*/'< Back': () => onchange(dow) }; - require("date_utils").dows(firstDayOfWeek).forEach((day, i) => (i => { + require("date_utils").dows(firstDayOfWeek).forEach((day, i) => { menu[day] = { value: !!(dow & (1 << (i + firstDayOfWeek))), format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: v => v ? (dow |= 1 << (i + firstDayOfWeek)) : (dow &= ~(1 << (i + firstDayOfWeek))) }; - })(i)); + }); E.showMenu(menu); } From c94b8be6292b55d1ec5351fbfa42b391658de2f6 Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Wed, 4 May 2022 10:18:48 +0100 Subject: [PATCH 79/82] Update Layout.js Removed as per https://github.com/espruino/BangleApps/pull/1788#discussion_r863924717 --- modules/Layout.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index f2ebc418a..c978c611b 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -231,8 +231,6 @@ Layout.prototype.render = function (l) { g.setFont(l.font).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); } }, "btn":function(l){ - if (l.font && l.font.endsWith("%")) - l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100); var x = l.x+(0|l.pad), y = l.y+(0|l.pad), w = l.w-(l.pad<<1), h = l.h-(l.pad<<1); var poly = [ From ffcba2a8fe0a9a4cdd2d5870fb81ae8fc0329b1f Mon Sep 17 00:00:00 2001 From: sir-indy <53864146+sir-indy@users.noreply.github.com> Date: Wed, 4 May 2022 10:19:59 +0100 Subject: [PATCH 80/82] Update app.js Tweak colours --- apps/smpltmr/app.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js index b7511724a..4e95d3a30 100644 --- a/apps/smpltmr/app.js +++ b/apps/smpltmr/app.js @@ -135,22 +135,22 @@ var timePickerLayout = new Layout({ {type:undefined, height:2}, {type:"h", c: [ {type:"v", width:g.getWidth()/3, c: [ - {type:"txt", font:"6x8", label:/*LANG*/"Hours", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"6x8", label:/*LANG*/"Hours"}, + {type:"img", pad:8, src:imgArrow}, {type:"txt", font:"20%", label:"00", id:"hours", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} + {type:"img", pad:8, src:imgArrow, r:2} ]}, {type:"v", width:g.getWidth()/3, c: [ - {type:"txt", font:"6x8", label:/*LANG*/"Minutes", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"6x8", label:/*LANG*/"Minutes"}, + {type:"img", pad:8, src:imgArrow}, {type:"txt", font:"20%", label:"00", id:"mins", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} + {type:"img", pad:8, src:imgArrow, r:2} ]}, {type:"v", width:g.getWidth()/3, c: [ - {type:"txt", font:"6x8", label:/*LANG*/"Seconds", col:g.theme.fg2}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2}, + {type:"txt", font:"6x8", label:/*LANG*/"Seconds"}, + {type:"img", pad:8, src:imgArrow}, {type:"txt", font:"20%", label:"00", id:"secs", filly:1, fillx:1}, - {type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2} + {type:"img", pad:8, src:imgArrow, r:2} ]}, ]}, {type:"btn", src:imgPlay, id:"btnStart", fillx:1 } From 90e3915e24a3d471d6f98827d630ed17a138a74e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 May 2022 11:08:36 +0100 Subject: [PATCH 81/82] fix test regression --- tests/Layout/bin/runtest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Layout/bin/runtest.sh b/tests/Layout/bin/runtest.sh index c85b3fe6c..e06dec86b 100755 --- a/tests/Layout/bin/runtest.sh +++ b/tests/Layout/bin/runtest.sh @@ -19,7 +19,7 @@ SRCBMP=$SRCDIR/`basename $SRCJS .js`.bmp echo "TEST $SRCJS ($SRCBMP)" cat ../../modules/Layout.js > $TESTJS -echo 'Bangle = { setUI : function(){} };BTN1=0;process.env = process.env;process.env.HWVERSION=2;' >> $TESTJS +echo 'Bangle = { setUI : function(){}, appRect:{x:0,y:0,w:176,h:176,x2:175,y2:175} };BTN1=0;process.env = process.env;process.env.HWVERSION=2;' >> $TESTJS echo 'g = Graphics.createArrayBuffer(176,176,4);' >> $TESTJS cat $SRCJS >> $TESTJS || exit 1 echo 'layout.render()' >> $TESTJS From ad038d4c344dd26165f5e97fba2695245d8d2973 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 4 May 2022 11:22:23 +0100 Subject: [PATCH 82/82] updated layout tests --- tests/Layout/tests/buttons_1_bangle1.js | 1 + tests/Layout/tests/buttons_3_bangle1.js | 1 + tests/Layout/tests/buttons_osd_bangle1.js | 1 + tests/Layout/tests/padding.bmp | Bin 15562 -> 15562 bytes tests/Layout/tests/padding_with_fill.bmp | Bin 15562 -> 15562 bytes 5 files changed, 3 insertions(+) diff --git a/tests/Layout/tests/buttons_1_bangle1.js b/tests/Layout/tests/buttons_1_bangle1.js index fb6fb29fa..481f09df3 100644 --- a/tests/Layout/tests/buttons_1_bangle1.js +++ b/tests/Layout/tests/buttons_1_bangle1.js @@ -1,6 +1,7 @@ var BTN2 = 1, BTN3=2; process.env = process.env;process.env.HWVERSION=1; g = Graphics.createArrayBuffer(240,240,4); +Bangle.appRect = {x:0,y:0,w:240,h:240,x2:239,y2:239}; var layout = new Layout({ type: "v", c: [ {type:"txt", font:"6x8", label:"A test"}, diff --git a/tests/Layout/tests/buttons_3_bangle1.js b/tests/Layout/tests/buttons_3_bangle1.js index c8346f449..2d5fbea9d 100644 --- a/tests/Layout/tests/buttons_3_bangle1.js +++ b/tests/Layout/tests/buttons_3_bangle1.js @@ -1,6 +1,7 @@ var BTN2 = 1, BTN3=2; process.env = process.env;process.env.HWVERSION=1; g = Graphics.createArrayBuffer(240,240,4); +Bangle.appRect = {x:0,y:0,w:240,h:240,x2:239,y2:239}; var layout = new Layout({ type: "v", c: [ {type:"txt", font:"6x8", label:"A test"}, diff --git a/tests/Layout/tests/buttons_osd_bangle1.js b/tests/Layout/tests/buttons_osd_bangle1.js index 108cb62b0..55656ef33 100644 --- a/tests/Layout/tests/buttons_osd_bangle1.js +++ b/tests/Layout/tests/buttons_osd_bangle1.js @@ -1,6 +1,7 @@ var BTN2 = 1, BTN3=2; process.env = process.env;process.env.HWVERSION=1; g = Graphics.createArrayBuffer(240,240,4); +Bangle.appRect = {x:0,y:0,w:240,h:240,x2:239,y2:239}; /* When displaying OSD buttons on Bangle.js 1 we should turn the side buttons into 'soft' buttons and then use the physical diff --git a/tests/Layout/tests/padding.bmp b/tests/Layout/tests/padding.bmp index 84ae4dc1bcdebea1b531156b07448700812f843a..506bb014e9377b9f38cff65596c80e7d98ccf5f1 100644 GIT binary patch delta 687 zcmX?Ad8%^5B-Y6fv@Nk>1vak9uUI2Dzh-3;pRB;fI{BlF#N> z5(8-lOMYNL0sP34^HHRL9FSI+PBe`S3?QvwH~p6rWd^DwhYfTR*i!!g9~k(-5aa}? zVQ@*P6hGK`I3)jLm4q0}k5A_Z?2`XK@c;i0auNuT>AT5DAp;70oIwbZ#2fhNT2Z16 ZXM___fbD18FcA^>BjE6vwYnXi7u+Rq_Ekgwm+gtw3wX zY~4gR+aS39-#b~BW1Vg3J%yOuvn`zt>*v4!_xw&i`{kQoFAT?PYil(ib`?jFwNX5d2pY!`jwxbm`*JO2^6Y9nCKhP?0yP(hQZDNyE^dwsu>vk%+2jB) zk~a+>`s=N^aF$FUqvLw$Y;PZ!Tjc||w?e45;zH~ay63q0vU7d^>ik`QzV8_;xrXD} zS*JL0XRY7fE%#@$fVuL>J>P_SFR1d`<(W-^%TokbNK|xJDAPoN+d8vpaG??9oMk(` znAyZ!j8)srCg!?)Se$;KU5UFivvuJ9XqK_MNOI?g<&Wa#`Fnvn=9%B5T$+1OBymSw zryWNeNx8oHP0XF?h1gmzS~4!i$}_*oxHC5^TkD-vuLIeZ`Awwvy#B(vLF4!4`FrkG z1h9mGi>ln_v{FKACDfoE^rKz%bm8)XPM$Lm9OeQSTr4KD_zKyLA$yy>&3Xc2Z9u7SD&zk1ai5F0Ub!r| zzYkuy#z1i3Vl*F~5A=DXG^Wk$q2a?|+=fn7y?4WPW-H{`?7dfeJ?=t2Sk4Lkd{E>z z#|>tXA1Zo>;2MyX=^cp6b}nrmUY%UBfIA+P4{5sx)QbzL{?`wQ_re7BO1NIZ zkSpP0<*+?~6>;f&UkLp5A-O+rojpB$XnrQ1%$B6yHGAdlz;zxD=|fRq@bt&+$e6!F zaBqrYZwM~^A!Mt#dpCpVJt~Sp#w{8s&s^ov&)>jB=^3K#>{hG4_3lzWPY@w+osZk- z1O0Nt|4gO-b6mRjA>EP>^e0;048g^(D}>k8i{G)FW@Rq0`g$>FZrtc!PMSWz)p;o9 b!yJlM;5s|*xewAh5Y7({1P6ixTkXJq)aC)t diff --git a/tests/Layout/tests/padding_with_fill.bmp b/tests/Layout/tests/padding_with_fill.bmp index 9f82ed09f1dae4357bbd77875d3cc8af90b91f33..92eccace27083c9808fd5491bf1a4be83c9ef298 100644 GIT binary patch delta 256 zcmX?Ad8%@QDa&L9CgaTlEHx~XW0)c~_i*U4OqOR7-F%K`4b$W--iXOn{5g~Bc-<%K z3J6X17h>J~hToMDtinz373bs&k`bE?q&G8f?w0$<%E|x#0|P$@PTr`fI{Ckn7AKg8 zRpdWH4MZ0|hOQ4tBL6?||Njp)d9%J|9>?TB#&DK828QR81@%H$9=v@Aw|P154Judk0b#3KWgltf2RnY4a>I12zCtC{_3X delta 449 zcmX?Ad8%@QDa+O?*P+bXR0Zs`t7yZZKA|!ESoBt#E0GBw}#~^?INA&@w_~v?zy^ND{R3kRqXl-Ph zT%g;*T=(wz