diff --git a/apps.json b/apps.json index 329945adf..6fe2c14a8 100644 --- a/apps.json +++ b/apps.json @@ -2639,14 +2639,16 @@ { "id": "magnav", "name": "Navigation Compass", - "version": "0.04", + "version": "0.05", "description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.", + "screenshots": [{"url":"screenshot-b2.png"},{"url":"screenshot-light-b2.png"}], "icon": "magnav.png", "tags": "tool,outdoors", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ - {"name":"magnav.app.js","url":"magnav.min.js"}, + {"name":"magnav.app.js","url":"magnav_b1.js","supports":["BANGLEJS"]}, + {"name":"magnav.app.js","url":"magnav_b2.js","supports":["BANGLEJS2"]}, {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} ], "data": [{"name":"magnav.json"}] @@ -2730,8 +2732,9 @@ { "id": "multiclock", "name": "Multi Clock", - "version": "0.08", - "description": "Clock with multiple faces. Switch between faces with BTN1 & BTN3 or swipe left-right. For best display set theme Background 2 to cyan or some other bright colour in settings.", + "version": "0.09", + "description": "Clock with multiple faces. Switch between faces with BTN1 & BTN3 (Bangle 2 touch top-right, bottom right). For best display set theme Background 2 to cyan or some other bright colour in settings.", + "screenshots": [{"url":"screen-ana.png"},{"url":"screen-big.png"},{"url":"screen-td.png"},{"url":"screen-nifty.png"},{"url":"screen-word.png"},{"url":"screen-sec.png"}], "icon": "multiclock.png", "type": "clock", "tags": "clock", @@ -3127,15 +3130,17 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.04", - "description": "Desktop style App Launcher with six apps per page - fast access if you have lots of apps installed.", + "version": "0.05", + "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", + "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "icon": "icon.png", "type": "launch", "tags": "tool,system,launcher", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ - {"name":"dtlaunch.app.js","url":"app.js"}, + {"name":"dtlaunch.app.js","url":"app-b1.js", "supports": ["BANGLEJS"]}, + {"name":"dtlaunch.app.js","url":"app-b2.js", "supports": ["BANGLEJS2"]}, {"name":"dtlaunch.img","url":"app-icon.js","evaluate":true} ] }, diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index 985321e91..c3102b4b9 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -2,3 +2,4 @@ 0.02: Multiple pages 0.03: cycle thru pages 0.04: reset to clock after 2 mins of inactivity +0.05: add Bangle 2 version diff --git a/apps/dtlaunch/README.md b/apps/dtlaunch/README.md index 70f7ff931..ba2301d91 100644 --- a/apps/dtlaunch/README.md +++ b/apps/dtlaunch/README.md @@ -3,7 +3,7 @@ ![](screenshot.jpg) In the picture above, the Settings app is selected. -## Controls +## Controls- Bangle **BTN1** - move backward through app icons on a page @@ -13,4 +13,12 @@ In the picture above, the Settings app is selected. **Swipe Left** - move to next page of app icons +**Swipe Right** - move to previous page of app icons + +## Controls- Bangle 2 + +**Touch** - icon to select, scond touch launches app + +**Swipe Left** - move to next page of app icons + **Swipe Right** - move to previous page of app icons \ No newline at end of file diff --git a/apps/dtlaunch/app.js b/apps/dtlaunch/app-b1.js similarity index 100% rename from apps/dtlaunch/app.js rename to apps/dtlaunch/app-b1.js diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js new file mode 100644 index 000000000..674fe3677 --- /dev/null +++ b/apps/dtlaunch/app-b2.js @@ -0,0 +1,105 @@ +/* Desktop launcher +* +*/ + +var s = require("Storage"); +var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || 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; +}); +apps.forEach(app=>{ + if (app.icon) + app.icon = s.read(app.icon); // should just be a link to a memory area + }); + +var Napps = apps.length; +var Npages = Math.ceil(Napps/4); +var maxPage = Npages-1; +var selected = -1; +var oldselected = -1; +var page = 0; +const XOFF = 24; +const YOFF = 30; + +function draw_icon(p,n,selected) { + var x = (n%2)*72+XOFF; + var y = n>1?72+YOFF:YOFF; + (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+10,y+2,x+60,y+52); + g.clearRect(x+12,y+4,x+59,y+51); + g.setColor(g.theme.fg); + try{g.drawImage(apps[p*4+n].icon,x+12,y+4);} catch(e){} + g.setFontAlign(0,-1,0).setFont("6x8",1); + var txt = apps[p*4+n].name.split(" "); + for (var i = 0; i < txt.length; i++) { + txt[i] = txt[i].trim(); + g.drawString(txt[i],x+36,y+54+i*8); + } +} + +function drawPage(p){ + g.reset(); + g.clearRect(0,24,175,175); + var O = 88+YOFF/2-12*(Npages/2); + for (var j=0;j{ + selected = 0; + oldselected=-1; + if (dir<0){ + ++page; if (page>maxPage) page=0; + drawPage(page); + } else { + --page; if (page<0) page=maxPage; + drawPage(page); + } +}); + +function isTouched(p,n){ + if (n<0 || n>3) return false; + var x1 = (n%2)*72+XOFF; var y1 = n>1?72+YOFF:YOFF; + var x2 = x1+71; var y2 = y1+81; + return (p.x>x1 && p.y>y1 && p.x{ + var i; + for (i=0;i<4;i++){ + if((page*4+i)=0) { + if (selected!=i){ + draw_icon(page,selected,false); + } else { + load(apps[page*4+i].src); + } + } + selected=i; + break; + } + } + } + if ((i==4 || (page*4+i)>Napps) && selected>=0) { + draw_icon(page,selected,false); + selected=-1; + } +}); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); +drawPage(0); diff --git a/apps/dtlaunch/shot1.png b/apps/dtlaunch/shot1.png new file mode 100644 index 000000000..e6a9bcd3a Binary files /dev/null and b/apps/dtlaunch/shot1.png differ diff --git a/apps/dtlaunch/shot2.png b/apps/dtlaunch/shot2.png new file mode 100644 index 000000000..4c0c33c91 Binary files /dev/null and b/apps/dtlaunch/shot2.png differ diff --git a/apps/dtlaunch/shot3.png b/apps/dtlaunch/shot3.png new file mode 100644 index 000000000..1ffdf8090 Binary files /dev/null and b/apps/dtlaunch/shot3.png differ diff --git a/apps/magnav/ChangeLog b/apps/magnav/ChangeLog index 35e8798c6..2b2782c7b 100644 --- a/apps/magnav/ChangeLog +++ b/apps/magnav/ChangeLog @@ -2,5 +2,6 @@ 0.02: Course marker 0.03: Tilt compensation and calibration 0.04: Fix Font size +0.05: Inital portable version diff --git a/apps/magnav/README.md b/apps/magnav/README.md index a036644fb..7ef506b2e 100644 --- a/apps/magnav/README.md +++ b/apps/magnav/README.md @@ -6,19 +6,20 @@ This is a tilt and roll compensated compass with a linear display. The compass w ## Calibration -Correct operation of this app depends critically on calibration. When first run on a Bangle, the app will request calibration. This lasts for 30 seconds during which you should move the watch slowly through figures of 8. It is important that during calibration the watch is fully rotated around each of it axes. If the app does give the correct direction heading or is not stable with respect to tilt and roll - redo the calibration by pressing *BTN3*. Calibration data is recorded in a storage file named `magnav.json`. +Correct operation of this app depends critically on calibration. When first run on a Bangle, the app will request calibration. This lasts for 20 seconds during which you should move the watch slowly through figures of 8. It is important that during calibration the watch is fully rotated around each of it axes. If the app does give the correct direction heading or is not stable with respect to tilt and roll - redo the calibration by pressing *BTN2*. Calibration data is recorded in a storage file named `magnav.json`. + +Note: Charging your Bangle due to the magnetic connector clamp seems to require recalibration afterwards for accurate readings. ## Controls -*BTN1* - switches to your selected clock app. +*BTN1* - marks the current heading with a blue circle - see screen shot. This can be used to take a bearing and then follow it.. +(Swipe UP on Bangle 2) -*BTN2* - switches to the app launcher. +*BTN2* - invokes calibration ( can be cancelled if pressed accidentally). +(*BTN1* on Bangle 2) -*BTN3* - invokes calibration ( can be cancelled if pressed accidentally) - -*Touch Left* - marks the current heading with a blue circle - see screen shot. This can be used to take a bearing and then follow it. - -*Touch Right* - cancels the marker (blue circle not displayed). +*BTN3* - cancels the marker (blue circle not displayed) +(swipe DOWN on Bangle 2) ## Support diff --git a/apps/magnav/magnav.min.js b/apps/magnav/magnav.min.js deleted file mode 100644 index 1d5439164..000000000 --- a/apps/magnav/magnav.min.js +++ /dev/null @@ -1,10 +0,0 @@ -var Yoff=80,pal2color=new Uint16Array([0,65535,2047,50712],0,2),buf=Graphics.createArrayBuffer(240,60,2,{msb:!0});Bangle.setLCDTimeout(30);function flip(b,c){g.drawImage({width:240,height:60,bpp:2,buffer:b.buffer,palette:pal2color},0,c);b.clear()}var labels="N NE E SE S SW W NW".split(" "),brg=null; -function drawCompass(b){buf.setColor(1);buf.setFont("Vector",24);var c=b-90;0>c&&(c+=360);buf.fillRect(28,45,212,49);var a=30,d=15-c%15;15>d?a+=d:d=0;for(var e=d;e<=180-d;e+=15){var f=c+e;0==f%90?(buf.drawString(labels[Math.floor(f/45)%8],a-8,0),buf.fillRect(a-2,25,a+2,45)):0==f%45?(buf.drawString(labels[Math.floor(f/45)%8],a-12,0),buf.fillRect(a-2,30,a+2,45)):0==f%15&&buf.fillRect(a,35,a+1,45);a+=15}brg&&(b=brg-b,180b&&(b+=360),b+=120,30>b&&(b=14),210c?1:-1;180<=a&&(a=360-a,d=-d);if(2>a)return c;a=c+d*(1+Math.round(a/5));0>a&&(a+=360);360a&&(a+=360);return a} -function reading(){var b=tiltfixread(CALIBDATA.offset,CALIBDATA.scale);heading=newHeading(b,heading);drawCompass(heading);buf.setColor(1);buf.setFont("6x8",2);buf.setFontAlign(-1,-1);buf.drawString("o",170,0);buf.setFont("Vector",54);b=Math.round(heading);var c=b.toString();buf.drawString(10>b?"00"+c:100>b?"0"+c:c,70,10);flip(buf,Yoff+80)} -function calibrate(){var b=-32E3,c=-32E3,a=-32E3,d=32E3,e=32E3,f=32E3,k=setInterval(function(){var h=Bangle.getCompass();b=h.x>b?h.x:b;c=h.y>c?h.y:c;a=h.z>a?h.z:a;d=h.x{ + CALIBDATA=r; require("Storage").write("magnav.json",r); - CALIBDATA = r; - startdraw(); - setButtons(); + restart() }); } else { - startdraw(); - setTimeout(setButtons,1000); - } + restart() + } } if (first===undefined) first=false; stopdraw(); - clearWatch(); if (first) E.showAlert(msg,title).then(action.bind(null,true)); else E.showPrompt(msg,{title:title,buttons:{"Start":true,"Cancel":false}}).then(action); } -Bangle.on('touch', function(b) { - if(!candraw) return; - if(b==1) brg=heading; - if(b==2) brg=null; - }); - var intervalRef; function startdraw(){ @@ -176,29 +174,17 @@ function stopdraw() { } function setButtons(){ - setWatch(()=>{load();}, BTN1, {repeat:false,edge:"falling"}); - setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); - setWatch(docalibrate, BTN3, {repeat:false,edge:"falling"}); + function actions(v){ + if (!v) docalibrate(false); + else if (v==1) brg=null; + else brg=heading; + } + Bangle.setUI("updown",actions); } -var SCREENACCESS = { - withApp:true, - request:function(){ - this.withApp=false; - stopdraw(); - clearWatch(); - }, - release:function(){ - this.withApp=true; - startdraw(); - setButtons(); - } -}; - Bangle.on('lcdPower',function(on) { - if (!SCREENACCESS.withApp) return; if (on) { - startdraw(); + if (!calibrating) startdraw(); } else { stopdraw(); } @@ -209,7 +195,7 @@ Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); Bangle.loadWidgets(); Bangle.setCompassPower(1); if (!CALIBDATA) - docalibrate({},true); + docalibrate(true); else { startdraw(); setButtons(); @@ -217,4 +203,3 @@ else { - diff --git a/apps/magnav/magnav_b2.js b/apps/magnav/magnav_b2.js new file mode 100644 index 000000000..e54280796 --- /dev/null +++ b/apps/magnav/magnav_b2.js @@ -0,0 +1,192 @@ + +const Ypos = 40; + +const labels = ["N","NE","E","SE","S","SW","W","NW"]; +var brg=null; + +function drawCompass(course) { + "ram" + g.setColor(g.theme.fg); + g.setFont("Vector",18); + var start = course-90; + if (start<0) start+=360; + g.fillRect(16,Ypos+45,160,Ypos+49); + var xpos = 16; + var frag = 15 - start%15; + if (frag<15) xpos+=Math.floor((frag*4)/5); else frag = 0; + for (var i=frag;i<=180-frag;i+=15){ + var res = start + i; + if (res%90==0) { + g.drawString(labels[Math.floor(res/45)%8],xpos-6,Ypos+6); + g.fillRect(xpos-2,Ypos+25,xpos+2,Ypos+45); + } else if (res%45==0) { + g.drawString(labels[Math.floor(res/45)%8],xpos-9,Ypos+6); + g.fillRect(xpos-2,Ypos+30,xpos+2,Ypos+45); + } else if (res%15==0) { + g.fillRect(xpos,Ypos+35,xpos+1,Ypos+45); + } + xpos+=12; + } + if (brg) { + var bpos = brg - course; + if (bpos>180) bpos -=360; + if (bpos<-180) bpos +=360; + bpos= Math.floor((bpos*4)/5)+88; + if (bpos<16) bpos = 8; + if (bpos>160) bpos = 170; + g.setColor(g.theme.fg2); + g.fillCircle(bpos,Ypos+45,6); + } +} + +var heading = 0; +function newHeading(m,h){ + var s = Math.abs(m - h); + var delta = (m>h)?1:-1; + if (s>=180){s=360-s; delta = -delta;} + if (s<2) return h; + var hd = h + delta*(1 + Math.round(s/5)); + if (hd<0) hd+=360; + if (hd>360)hd-= 360; + return hd; +} + +var candraw = false; +var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; + +function tiltfixread(O,S){ + "ram" + var m = Bangle.getCompass(); + 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; + if (d<0) d+=360; + var phi = Math.atan(-g.x/-g.z); + var cosphi = Math.cos(phi), sinphi = Math.sin(phi); + var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi)); + var costheta = Math.cos(theta), sintheta = Math.sin(theta); + var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta; + var yh = m.dz*sinphi - m.dx*cosphi; + var psi = Math.atan2(yh,xh)*180/Math.PI; + if (psi<0) psi+=360; + return psi; +} + +// Note actual mag is 360-m, error in firmware +function reading() { + "ram" + g.clearRect(0,24,175,175); + var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); + heading = newHeading(d,heading); + drawCompass(heading); + g.setColor(g.theme.fg); + g.setFont("6x8",2); + g.setFontAlign(-1,-1); + g.drawString("o",120,Ypos+80); + g.setFont("Vector",40); + var course = Math.round(heading); + var cs = course.toString(); + cs = course<10?"00"+cs : course<100 ?"0"+cs : cs; + g.drawString(cs,50,Ypos+90); + g.setColor(g.theme.fg2); + g.fillPoly([88,Ypos+60,78,Ypos+80,98,Ypos+80]); + g.setColor(g.theme.fg); + g.flip(); +} + +function calibrate(){ + var max={x:-32000, y:-32000, z:-32000}, + min={x:32000, y:32000, z:32000}; + var ref = setInterval(()=>{ + var m = Bangle.getCompass(); + max.x = m.x>max.x?m.x:max.x; + max.y = m.y>max.y?m.y:max.y; + max.z = m.z>max.z?m.z:max.z; + min.x = m.x { + setTimeout(()=>{ + if(ref) clearInterval(ref); + var offset = {x:(max.x+min.x)/2,y:(max.y+min.y)/2,z:(max.z+min.z)/2}; + var delta = {x:(max.x-min.x)/2,y:(max.y-min.y)/2,z:(max.z-min.z)/2}; + var avg = (delta.x+delta.y+delta.z)/3; + var scale = {x:avg/delta.x, y:avg/delta.y, z:avg/delta.z}; + resolve({offset:offset,scale:scale}); + },20000); + }); +} + +var calibrating=false; +function docalibrate(first){ + calibrating=true; + const title = "Calibrate"; + const msg = "takes 20 seconds"; + function restart() { + calibrating=false; + setButtons(); + startdraw(); + } + function action(b){ + if (b) { + g.clearRect(0,24,175,175); + g.setColor(g.theme.fg); + g.setFont("Vector",18); + g.setFontAlign(0,-1); + g.drawString("Fig 8s to",88,Ypos); + g.drawString("Calibrate",88,Ypos+18); + g.flip(); + calibrate().then((r)=>{ + CALIBDATA=r; + require("Storage").write("magnav.json",r); + restart(); + }); + } else { + restart(); + } + } + if (first===undefined) first=false; + stopdraw(); + if (first) + E.showAlert(msg,title).then(action.bind(null,true)); + else + E.showPrompt(msg,{title:title,buttons:{"Start":true,"Cancel":false}}).then(action); +} + +var intervalRef; + +function startdraw(){ + g.clear(1); + Bangle.drawWidgets(); + candraw = true; + intervalRef = setInterval(reading,200); +} + +function stopdraw() { + candraw=false; + if(intervalRef) {clearInterval(intervalRef);} +} + +function setButtons(){ + function actions(v){ + if (!v) docalibrate(false); + else if (v==1) brg=null; + else brg=heading; + } + Bangle.setUI("updown",actions); +} + +Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); + +Bangle.loadWidgets(); +Bangle.setCompassPower(1); +if (!CALIBDATA) + docalibrate(true); +else { + startdraw(); + setButtons(); +} + + + diff --git a/apps/magnav/screenshot-b2.png b/apps/magnav/screenshot-b2.png new file mode 100644 index 000000000..63f830bfc Binary files /dev/null and b/apps/magnav/screenshot-b2.png differ diff --git a/apps/magnav/screenshot-light-b2.png b/apps/magnav/screenshot-light-b2.png new file mode 100644 index 000000000..943dc392c Binary files /dev/null and b/apps/magnav/screenshot-light-b2.png differ diff --git a/apps/multiclock/ChangeLog b/apps/multiclock/ChangeLog index 9d02ae85e..442a5277a 100644 --- a/apps/multiclock/ChangeLog +++ b/apps/multiclock/ChangeLog @@ -6,6 +6,7 @@ 0.06: add minute tick for efficiency and nifty A clock 0.07: compatible with Bang;e.js 2 0.08: fix minute tick bug +0.09: use setUI clockupdown for controls + fix small display bug in nifty face diff --git a/apps/multiclock/README.md b/apps/multiclock/README.md index e8b8335ea..25c997329 100644 --- a/apps/multiclock/README.md +++ b/apps/multiclock/README.md @@ -5,7 +5,9 @@ This is a clock app that supports multiple clock faces. The user can switch betw ## Controls -Swipe left and right on both the Bangle and Bangle 2 switch between faces. BTN1 & BTH3 also switch faces on the Bangle. +Uses `setUI("clockupdown")` +BTN1 & BTH3 switch faces on the Bangle. +Touch upper right and lower right quadrant switch faces on the Bangle 2. ## Adding a new face Clock faces are described in javascript storage files named `name.face.js`. For example, the Analog Clock Face is described in `ana.face.js`. These files have the following structure: diff --git a/apps/multiclock/multiclock.app.js b/apps/multiclock/multiclock.app.js index c24e5c94b..0565a7040 100644 --- a/apps/multiclock/multiclock.app.js +++ b/apps/multiclock/multiclock.app.js @@ -67,7 +67,7 @@ function setButtons(){ startdraw(); } } - Bangle.setUI("leftright", newFace); + Bangle.setUI("clockupdown", newFace); } E.on('kill',()=>{ diff --git a/apps/multiclock/nifty.face.js b/apps/multiclock/nifty.face.js index 2c2af6063..54962da34 100644 --- a/apps/multiclock/nifty.face.js +++ b/apps/multiclock/nifty.face.js @@ -28,7 +28,7 @@ var now = new Date(); const hour = d02(now.getHours() - (is12Hour && now.getHours() > 12 ? 12 : 0)); const minutes = d02(now.getMinutes()); - const day = d02(now.getDay()); + const day = d02(now.getDate()); const month = d02(now.getMonth() + 1); const year = now.getFullYear(); const month2 = locale.month(now, 3); diff --git a/apps/multiclock/screen-ana.png b/apps/multiclock/screen-ana.png new file mode 100644 index 000000000..67d794aa3 Binary files /dev/null and b/apps/multiclock/screen-ana.png differ diff --git a/apps/multiclock/screen-big.png b/apps/multiclock/screen-big.png new file mode 100644 index 000000000..80544d552 Binary files /dev/null and b/apps/multiclock/screen-big.png differ diff --git a/apps/multiclock/screen-date.png b/apps/multiclock/screen-date.png new file mode 100644 index 000000000..21093f458 Binary files /dev/null and b/apps/multiclock/screen-date.png differ diff --git a/apps/multiclock/screen-nifty.png b/apps/multiclock/screen-nifty.png new file mode 100644 index 000000000..884456125 Binary files /dev/null and b/apps/multiclock/screen-nifty.png differ diff --git a/apps/multiclock/screen-sec.png b/apps/multiclock/screen-sec.png new file mode 100644 index 000000000..cc1149254 Binary files /dev/null and b/apps/multiclock/screen-sec.png differ diff --git a/apps/multiclock/screen-td.png b/apps/multiclock/screen-td.png new file mode 100644 index 000000000..edea06a2e Binary files /dev/null and b/apps/multiclock/screen-td.png differ diff --git a/apps/multiclock/screen-word.png b/apps/multiclock/screen-word.png new file mode 100644 index 000000000..ad029a60f Binary files /dev/null and b/apps/multiclock/screen-word.png differ