diff --git a/apps/tapelauncher/ChangeLog b/apps/tapelauncher/ChangeLog new file mode 100644 index 000000000..918e4a9ac --- /dev/null +++ b/apps/tapelauncher/ChangeLog @@ -0,0 +1,2 @@ +0.01: Initial version + diff --git a/apps/tapelauncher/README.md b/apps/tapelauncher/README.md new file mode 100644 index 000000000..2296dc357 --- /dev/null +++ b/apps/tapelauncher/README.md @@ -0,0 +1,17 @@ +# The Tape App Launcher + +Reminiscent of a Telegram or Turing machine tape. + +![](screenshot.jpg) + +## Controls + +**BTN1** - move backward to the previous app icon + +**BTN2** - run the selected app + +**BTN3** - move forward to the next app icon + +**Swipe Left** - move forward to the next app icon + +**Swipe Right** - move backwards (to the left) to the previous app diff --git a/apps/tapelauncher/app.js b/apps/tapelauncher/app.js new file mode 100644 index 000000000..c1211c032 --- /dev/null +++ b/apps/tapelauncher/app.js @@ -0,0 +1,87 @@ +/* + * Tape 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; +}); + +var Napps = apps.length; +var selected = 1; // assumes we have at least 2 apps + +function draw_icon(pos, id, select) { + var x = ((pos % 3)*80) + 2; + var y = 80; + + if (select) { + //g.setColor(0.3,0.3,0.3).fillRect(x,y,x+79,y+99); // bigger than icon + } else { + // some icons will vanish on a black background, so draw a box smaller than the icon to sit on + //g.setColor(0.3,0.3,0.3).fillRect(x+5,y+11,x+73,y+73); + } + + g.setColor(-1); + g.drawImage(s.read(apps[id].icon),x+2,y+11,{scale:1.625}); + + if (select) { + // white bounding box + g.setColor(1,1,1).drawRect(x,y,x+79,y+99); + } +} + +function draw() { + g.setColor(0,0,0).fillRect(0,0,239,239); + + if (selected -1 > -1) + draw_icon(0, selected -1, false); + + draw_icon(1, selected, true); + + if (selected + 1 < Napps) + draw_icon(2, selected + 1, false); + + g.setColor(-1).setFontAlign(0,-1,0).setFont("6x8",3); + + if (apps[selected].name.length <= 12) { + g.drawString(apps[selected].name, 120, 40, true); + } else { + // some app names are too long for one line + var name = apps[selected].name; + var first = name.substring(0, name.lastIndexOf(" ")); + var last = name.substring(name.lastIndexOf(" ") + 1, name.length); + g.drawString(first, 120, 40, true); + g.drawString(last, 120, 200, true); + } +} + +Bangle.on("swipe",(dir)=>{ + (dir<0) ? nextapp(1) : nextapp(-1); +}); + +function nextapp(dir){ + selected += dir; + + if (selected > Napps - 1) { + selected = Napps - 1; + } else if (selected < 0) { + selected = 0; + } + draw(); +} + +function doselect(){ + load(apps[selected].src); +} + +setWatch(nextapp.bind(null,-1), BTN1, {repeat:true,edge:"falling"}); +setWatch(doselect, BTN2, {repeat:true,edge:"falling"}); +setWatch(nextapp.bind(null,1), BTN3, {repeat:true,edge:"falling"}); + +draw(); diff --git a/apps/tapelauncher/icon.js b/apps/tapelauncher/icon.js new file mode 100644 index 000000000..b5c7afd6c --- /dev/null +++ b/apps/tapelauncher/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("AH4A/ACXd7vQC6vUpoBBDaQXEDaQXIDZwXMAIQZHC4R6BAAIZJDAwXIDY4XHAAodJ7oXMDpQXSAAiRHhoWN7zFLDY/e9ve9zeMhvQCIIBFC5ARIC5oVNC5EOCpwABC4vuCZYXPCIwXOCJAAFC5gAJ8AXFCpwuHgDjCFqQXC6lN6gbFf5gXEAInd6AXVDYndhoXKBoIbMC5QZLC44AFDpIXNDpQXdhoYMAAbwIC6oZQbxhOKC5gbKC6BUGC6oA/AHgA=="); diff --git a/apps/tapelauncher/icon.png b/apps/tapelauncher/icon.png new file mode 100644 index 000000000..db4e42fab Binary files /dev/null and b/apps/tapelauncher/icon.png differ diff --git a/apps/tapelauncher/screenshot.jpg b/apps/tapelauncher/screenshot.jpg new file mode 100644 index 000000000..664f711f1 Binary files /dev/null and b/apps/tapelauncher/screenshot.jpg differ