diff --git a/apps.json b/apps.json index 59b3892a5..df49a3442 100644 --- a/apps.json +++ b/apps.json @@ -104,7 +104,7 @@ "id": "launch", "name": "Launcher", "shortName": "Launcher", - "version": "0.09", + "version": "0.10", "description": "This is needed to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "icon": "app.png", "type": "launch", @@ -112,8 +112,10 @@ "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"launch.app.js","url":"app-bangle1.js","supports":["BANGLEJS"]}, - {"name":"launch.app.js","url":"app-bangle2.js","supports":["BANGLEJS2"]} + {"name":"launch.app.js","url":"app-bangle2.js","supports":["BANGLEJS2"]}, + {"name":"launch.settings.js","url":"settings.js","supports":["BANGLEJS2"]} ], + "data": [{"name":"launch.json"}], "sortorder": -10 }, { @@ -4449,7 +4451,7 @@ "shortName": "AuthWatch", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], - "version": "0.03", + "version": "0.04", "description": "Google Authenticator compatible tool.", "tags": "tool", "interface": "interface.html", @@ -4687,6 +4689,21 @@ "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"widChargingStatus.wid.js","url":"widget.js"} + ] + }, + { + "id": "flow", + "name": "FLOW", + "shortName": "FLOW", + "version": "0.01", + "description": "A game where you have to help a flow avoid white obstacles thing by tapping! This is a demake of an app which I forgot the name of. Press BTN(1) to restart. See if you can get to 2500 score!", + "icon": "app.png", + "tags": "game", + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name": "flow.app.js", "url": "app.js" }, + {"name": "flow.img", "url": "app-icon.js","evaluate": true } ] } ] diff --git a/apps/authentiwatch/ChangeLog b/apps/authentiwatch/ChangeLog index 50cf3fcea..e1b8ed5bc 100644 --- a/apps/authentiwatch/ChangeLog +++ b/apps/authentiwatch/ChangeLog @@ -1,3 +1,4 @@ +0.04: Fix tapping at very bottom of list, exit on inactivity 0.03: Add "Calculating" placeholder, update JSON save format 0.02: Fix JSON save format 0.01: First release diff --git a/apps/authentiwatch/app.js b/apps/authentiwatch/app.js index 85c76b5d1..c0cb608c0 100644 --- a/apps/authentiwatch/app.js +++ b/apps/authentiwatch/app.js @@ -10,6 +10,8 @@ const calculating = "Calculating"; const notokens = "No tokens"; const notsupported = "Not supported"; +// sample settings: +// {tokens:[{"algorithm":"SHA1","digits":6,"period":30,"issuer":"","account":"","secret":"Bbb","label":"Aaa"}],misc:{}} var settings = require("Storage").readJSON("authentiwatch.json", true) || {tokens:[],misc:{}}; if (settings.data ) tokens = settings.data ; /* v0.02 settings */ if (settings.tokens) tokens = settings.tokens; /* v0.03+ settings */ @@ -146,14 +148,14 @@ function drawToken(id, r) { // counter - draw triangle as swipe hint let yc = (y1 + y2) / 2; g.fillPoly([0, yc, 10, yc - 10, 10, yc + 10, 0, yc]); - adj = 5; + adj = 10; } // digits just below label sz = 30; do { g.setFont("Vector", sz--); } while (g.stringWidth(state.otp) > (r.w - adj)); - g.drawString(state.otp, (x1 + x2) / 2 + adj, y1 + 16, false); + g.drawString(state.otp, (x1 + adj + x2) / 2, y1 + 16, false); } // shaded lines top and bottom g.setColor(0.5, 0.5, 0.5); @@ -163,6 +165,8 @@ function drawToken(id, r) { } function draw() { + var timerfn = exitApp; + var timerdly = 10000; var d = new Date(); if (state.curtoken != -1) { var t = tokens[state.curtoken]; @@ -203,17 +207,13 @@ function draw() { y += tokenentryheight; } if (drewcur) { - // the current token has been drawn - draw it again in 1sec - if (state.drawtimer) { - clearTimeout(state.drawtimer); - } - var dly; + // the current token has been drawn - schedule a redraw if (tokens[state.curtoken].period > 0) { - dly = (state.otp == calculating) ? 1 : 1000; + timerdly = (state.otp == calculating) ? 1 : 1000; // timed } else { - dly = state.nexttime - d.getTime(); + timerdly = state.nexttime - d.getTime(); // counter } - state.drawtimer = setTimeout(draw, dly); + timerfn = draw; if (tokens[state.curtoken].period <= 0) { state.hide = 0; } @@ -230,12 +230,16 @@ function draw() { g.setFontAlign(0, 0, 0); g.drawString(notokens, Bangle.appRect.x + Bangle.appRect.w / 2, Bangle.appRect.y + Bangle.appRect.h / 2, false); } + if (state.drawtimer) { + clearTimeout(state.drawtimer); + } + state.drawtimer = setTimeout(timerfn, timerdly); } function onTouch(zone, e) { if (e) { var id = Math.floor((state.listy + (e.y - Bangle.appRect.y)) / tokenentryheight); - if (id == state.curtoken || tokens.length == 0) { + if (id == state.curtoken || tokens.length == 0 || id >= tokens.length) { id = -1; } if (state.curtoken != id) { @@ -254,26 +258,20 @@ function onTouch(zone, e) { state.nextTime = 0; state.curtoken = id; state.hide = 2; - draw(); } } + draw(); } function onDrag(e) { if (e.x > g.getWidth() || e.y > g.getHeight()) return; if (e.dx == 0 && e.dy == 0) return; var newy = Math.min(state.listy - e.dy, tokens.length * tokenentryheight - Bangle.appRect.h); - newy = Math.max(0, newy); - if (newy != state.listy) { - state.listy = newy; - draw(); - } + state.listy = Math.max(0, newy); + draw(); } function onSwipe(e) { - if (e == 1) { - Bangle.showLauncher(); - } if (e == -1 && state.curtoken != -1 && tokens[state.curtoken].period <= 0) { tokens[state.curtoken].period--; let newsettings={tokens:tokens,misc:settings.misc}; @@ -281,8 +279,8 @@ function onSwipe(e) { state.nextTime = 0; state.otp = ""; state.hide = 2; - draw(); } + draw(); } function bangle1Btn(e) { @@ -302,16 +300,22 @@ function bangle1Btn(e) { state.curtoken = -1; state.nextTime = 0; onTouch(0, fakee); + } else { + draw(); // resets idle timer } } +function exitApp() { + Bangle.showLauncher(); +} + Bangle.on('touch', onTouch); Bangle.on('drag' , onDrag ); Bangle.on('swipe', onSwipe); if (typeof BTN2 == 'number') { - setWatch(function(){bangle1Btn(-1); }, BTN1, {edge:"rising", debounce:50, repeat:true}); - setWatch(function(){Bangle.showLauncher();}, BTN2, {edge:"rising", debounce:50, repeat:true}); - setWatch(function(){bangle1Btn( 1); }, BTN3, {edge:"rising", debounce:50, repeat:true}); + setWatch(function(){bangle1Btn(-1);}, BTN1, {edge:"rising", debounce:50, repeat:true}); + setWatch(function(){exitApp(); }, BTN2, {edge:"rising", debounce:50, repeat:true}); + setWatch(function(){bangle1Btn( 1);}, BTN3, {edge:"rising", debounce:50, repeat:true}); } Bangle.loadWidgets(); diff --git a/apps/flow/README.md b/apps/flow/README.md new file mode 100644 index 000000000..caeaf92d9 --- /dev/null +++ b/apps/flow/README.md @@ -0,0 +1,12 @@ +# FLOW + +This is a game where you have to help a flow avoid white obstacles thing by tapping! +This is a demake of an app which I forgot the name of. +Press BTN(1) to restart. +See if you can get to 2500 score! + +## Screenshots + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) diff --git a/apps/flow/app-icon.js b/apps/flow/app-icon.js new file mode 100644 index 000000000..969a608f4 --- /dev/null +++ b/apps/flow/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X/AwX48EHgEC1WgCQkVqoDBBfuqBQcBqoLagEqGAguBqALaGAOoAoQuEBbEAKgIMBBQNUBbgMCyoKHBbBVBBYIKGBbEBtNVrQLfOgNaT4gLagp0CPQOABbcBFwNAgEKBgILbitVqAFClWq0ALZFwTDFGAQLZFwYwDBfg")) diff --git a/apps/flow/app.js b/apps/flow/app.js new file mode 100644 index 000000000..5f4da8f35 --- /dev/null +++ b/apps/flow/app.js @@ -0,0 +1,220 @@ +const isB2 = process.env.HWVERSION === 2; + +// Bangle.js 1 runs just too fast in direct mode??? (also no getPixel) +if (!isB2) Bangle.setLCDMode("120x120"); + +const options = Bangle.getOptions(); + +options.lockTimeout = 0; +options.lcdPowerTimeout = 0; + +Bangle.setOptions(options); + +g.reset(); +g.setBgColor(0, 0, 0); +g.setColor(255, 255, 255); +g.clear(); +const h = g.getHeight(); + +function trigToCoord(ret) { + return ((ret + 1) * h) / 2; +} + +function trigToLen(ret) { + return (ret * h) / 2; +} + +let i = 0.2; +let speedCoef = 0.014; + +let flowFile = require("Storage").readJSON("flow.json"); + +let highestI = (flowFile && flowFile.hiscore) || 0.1; + +let colorA = [255, 255, 0]; +let colorB = [0, 255, 255]; + +let x = 0; +let xt = 0; +let safeMode = false; +let lost = false; + +function offsetRect(g, x, y, w) { + g.fillRect(x, y, x + w, y + w); +} + +function getColor(num) { + return [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [1, 1, 0], + [0, 1, 1], + [1, 0, 1], + [0.5, 0.5, 1], + [1, 0.5, 0], + [0, 1, 0.5], + [0.5, 0.5, 0.5], + ][num]; +} + +function calculateColor(num) { + colorA = getColor(Math.floor((num % 1) * 10)); + colorB = getColor(Math.floor((num % 10) - (num % 1))); +} + +calculateColor(highestI); + +Bangle.on("touch", () => (safeMode = !safeMode)); + +function resetGame() { + x = xt = 0; + safeMode = lost = false; + i = 0.2; + speedCoef = 0.014; + obstaclePeriod = 150; + obstacleMode = 1; + g.clear(); + shownScore = false; + intervalId = setInterval(draw); +} + +function checkCollision() { + lost = g.getPixel(trigToCoord(+x), (h * 2) / 3 - 4) !== 0; + if (lost) { + scoringI = i; + speedCoef = Math.min(speedCoef, 0.02); + g.setFont(isB2 ? "6x15" : "4x6", 3); + g.setColor(colorA[0], colorA[1], colorA[2]) + .drawString( + "Game over", + trigToCoord(0) - g.stringWidth("Game over") / 2, + trigToCoord(0) + ) + .setColor(1, 1, 1); + } +} + +function drawPlayer() { + if (!safeMode) xt = Math.cos(i * Math.PI * 4) / 7.5; + else xt = -Math.cos(i * Math.PI * 2) / 20 + 0.35; + x = x * 0.8 + xt * 0.2; + if (highestI > 250) calculateColor(i); + g.setColor(colorA[0], colorA[1], colorA[2]); + offsetRect(g, trigToCoord(+x), (h * 2) / 3, 3); + g.setColor(colorB[0], colorB[1], colorB[2]); + offsetRect(g, trigToCoord(-x), (h * 2) / 3, 3); +} + +let obstaclePeriod = 150; +let obstacleMode = 1; + +function drawObstracle() { + g.setColor(1, 1, 1); + switch (obstacleMode) { + case 0: + offsetRect(g, trigToCoord(-0.15), 0, trigToLen(0.3)); + break; + case 1: + offsetRect(g, trigToCoord(0.2), 0, trigToLen(0.2)); + offsetRect(g, trigToCoord(-0.4), 0, trigToLen(0.2)); + break; + case 2: + break; + } + obstaclePeriod--; + if (obstaclePeriod <= 0) { + // If we are off cooldown mode, pick a random actual mode + if (obstacleMode === 2) { + obstaclePeriod = Math.random() * 50 + 50; + obstacleMode = Math.round(Math.random()); + } else if (Math.random() > 0.5) { + // Give it a chance to repeat with no cooldown + obstaclePeriod = 25 + 2.5 * speedCoef; + obstacleMode = 2; + } + } +} + +let shownScore = false; +let scoringI = 0; + +function draw() { + if (!lost) { + drawPlayer(); + checkCollision(); + speedCoef *= 1.0005; + drawObstracle(); + } else { + speedCoef /= 1.05; + if (speedCoef <= 0.005) { + clearInterval(intervalId); + i -= speedCoef; + g.setFont(isB2 ? "6x15" : "4x6", 1); + const str = "Hiscore: " + Math.round(highestI * 10); + g.setColor( + scoringI > highestI ? 0 : 255, + 0, + scoringI > highestI ? 255 : 0 + ) + .drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) + ) + .setColor(255, 255, 255); + if (scoringI > highestI) { + highestI = scoringI; + require("Storage").writeJSON("flow.json", { + hiscore: highestI, + }); + calculateColor(highestI); + } + setTimeout(resetGame, 3000); + } else if (speedCoef <= 0.01 && !shownScore) { + shownScore = true; + g.setFont(isB2 ? "6x15" : "4x6", 2); + const str = "Score: " + Math.round(scoringI * 10); + g.setColor(colorB[0], colorB[1], colorB[2]) + .drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) + ) + .setColor(1, 1, 1); + } + } + i += speedCoef; + g.scroll(0, speedCoef * h); + g.flip(); +} + +let intervalId; + +if (BTN.read()) { + for (let i = 0; i < 10; i++) { + color = getColor(i); + g.setColor(color[0], color[1], color[2]); + g.fillRect((i / 10) * h, 0, ((i + 1) / 10) * h, h); + } + g.setColor(0); + g.setFont("Vector", 9); + let str = "Welcome to the debug screen!"; + g.drawString( + str, + trigToCoord(0) - g.stringWidth(str) / 2, + trigToCoord(0) - 9 + ); + str = "Don't hold BTN while opening to play!"; + g.drawString(str, trigToCoord(0) - g.stringWidth(str) / 2, trigToCoord(0)); + g.flip(); + setInterval(() => { + g.scroll(0, 0.014 * h); + i += 0.014; + calculateColor(i); + g.setColor(colorA[0], colorA[1], colorA[2]); + g.fillRect(0, 0, trigToCoord(0), 0.014 * h); + g.setColor(colorB[0], colorB[1], colorB[2]); + g.fillRect(trigToCoord(0), 0, trigToCoord(1), 0.014 * h); + }, 1000 / 30); +} else intervalId = setInterval(draw, 1000 / 30); diff --git a/apps/flow/app.png b/apps/flow/app.png new file mode 100644 index 000000000..b35c3ca77 Binary files /dev/null and b/apps/flow/app.png differ diff --git a/apps/flow/screenshot1.png b/apps/flow/screenshot1.png new file mode 100644 index 000000000..fd5dee427 Binary files /dev/null and b/apps/flow/screenshot1.png differ diff --git a/apps/flow/screenshot2.png b/apps/flow/screenshot2.png new file mode 100644 index 000000000..e29691b69 Binary files /dev/null and b/apps/flow/screenshot2.png differ diff --git a/apps/flow/screenshot3.png b/apps/flow/screenshot3.png new file mode 100644 index 000000000..3e1c80ba7 Binary files /dev/null and b/apps/flow/screenshot3.png differ diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 3b9dbc30c..0b2f134ad 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -8,3 +8,4 @@ 0.08: Merge Bangle.js 1 and 2 launchers 0.09: Bangle.js 2 - pressing the button goes back to clock (fix #971) After 10s of being locked, the launcher goes back to the clock screen +0.10: added in selectable font in settings including scalable vector font diff --git a/apps/launch/app-bangle2.js b/apps/launch/app-bangle2.js index 9a7aa81ed..156eecdf4 100644 --- a/apps/launch/app-bangle2.js +++ b/apps/launch/app-bangle2.js @@ -1,4 +1,22 @@ var s = require("Storage"); +let fonts = g.getFonts(); +var scaleval = 1; +var vectorval = 20; +var font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2"; +let settings = require('Storage').readJSON("launch.json", true) || {}; +if ("vectorsize" in settings) { + vectorval = parseInt(settings.vectorsize); +} +if ("font" in settings){ + if(settings.font == "Vector"){ + scaleval = vectorval/20; + font = "Vector"+(vectorval).toString(); + } + else{ + font = settings.font; + scaleval = (font.split('x')[1])/20; + } +} 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); @@ -11,8 +29,6 @@ apps.forEach(app=>{ if (app.icon) app.icon = s.read(app.icon); // should just be a link to a memory area }); -// FIXME: not needed after 2v11 -var font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2"; // FIXME: check not needed after 2v11 if (g.wrapString) { g.setFont(font); @@ -22,9 +38,9 @@ if (g.wrapString) { function drawApp(i, r) { var app = apps[i]; if (!app) return; - g.clearRect(r.x,r.y,r.x+r.w-1, r.y+r.h-1); - g.setFont(font).setFontAlign(-1,0).drawString(app.name,64,r.y+32); - if (app.icon) try {g.drawImage(app.icon,8,r.y+8);} catch(e){} + g.clearRect((r.x),(r.y),(r.x+r.w-1), (r.y+r.h-1)); + g.setFont(font).setFontAlign(-1,0).drawString(app.name,64*scaleval,r.y+(32*scaleval)); + if (app.icon) try {g.drawImage(app.icon,8*scaleval, r.y+(8*scaleval), {scale: scaleval});} catch(e){} } g.clear(); @@ -32,7 +48,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); E.showScroller({ - h : 64, c : apps.length, + h : 64*scaleval, c : apps.length, draw : drawApp, select : i => { var app = apps[i]; diff --git a/apps/launch/settings.js b/apps/launch/settings.js new file mode 100644 index 000000000..8be1adb36 --- /dev/null +++ b/apps/launch/settings.js @@ -0,0 +1,25 @@ +// make sure to enclose the function in parentheses +(function(back) { + let settings = require('Storage').readJSON('launch.json',1)||{}; + let fonts = g.getFonts(); + function save(key, value) { + settings[key] = value; + require('Storage').write('launch.json',settings); + } + const appMenu = { + '': {'title': 'Launcher Settings'}, + '< Back': back, + 'Font': { + value: fonts.includes(settings.font)? fonts.indexOf(settings.font) : fonts.indexOf("12x20"), + min:0, max:fonts.length-1, step:1,wrap:true, + onchange: (m) => {save('font', fonts[m])}, + format: v => fonts[v] + }, + 'Vector font size': { + value: settings.vectorsize || 10, + min:10, max: 20,step:1,wrap:true, + onchange: (m) => {save('vectorsize', m)} + } + }; + E.showMenu(appMenu); +}); diff --git a/core b/core index 23854083e..59f80bb52 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 23854083e0c3f83c649073a2d85e8079efc471d3 +Subproject commit 59f80bb52a38da12cb272f9106cb3951b49dab2e