diff --git a/apps.json b/apps.json index 3a9925650..53478f638 100644 --- a/apps.json +++ b/apps.json @@ -183,7 +183,8 @@ }, { "id": "welcome", - "name": "Welcome", + "name": "Welcome (Bangle.js 1)", + "shortName": "Welcome", "version": "0.12", "description": "Appears at first boot and explains how to use Bangle.js", "icon": "app.png", @@ -216,6 +217,24 @@ ], "data": [{"name":"mywelcome.json"}] }, + { + "id": "welcome2", + "name": "Welcome (Bangle.js 2)", + "shortName": "Welcome", + "version": "0.13", + "description": "Appears at first boot and explains how to use Bangle.js 2", + "icon": "app.png", + "tags": "start,welcome", + "supports": ["BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"welcome2.boot.js","url":"boot.js"}, + {"name":"welcome2.app.js","url":"app.js"}, + {"name":"welcome2.settings.js","url":"settings.js"}, + {"name":"welcome2.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"welcome2.json"}] + }, { "id": "gbridge", "name": "Gadgetbridge", diff --git a/apps/welcome2/ChangeLog b/apps/welcome2/ChangeLog new file mode 100644 index 000000000..f72f77a4b --- /dev/null +++ b/apps/welcome2/ChangeLog @@ -0,0 +1,17 @@ +0.01: New App! +0.02: Animate balloon intro +0.03: BTN3 now won't restart when at the end +0.04: Fix regression after tweaks to Storage.readJSON +0.05: Move configuration into App/widget settings +0.06: Move loader into welcome.boot.js +0.07: Run again when updated + Don't run again when settings app is updated (or absent) + Add "Run Now" option to settings +0.08: Don't overwrite existing settings on app update +0.09: Allow welcome to run after a fresh install + More useful app menu + BTN2 now goes to menu on release +0.10: Tweaks to reduce memory usage +0.11: Fix initial screen fill colour +0.12: Fix swipe direction (#800) +0.13: Mods for Bangle.js 2 diff --git a/apps/welcome2/app-icon.js b/apps/welcome2/app-icon.js new file mode 100644 index 000000000..5c1373e17 --- /dev/null +++ b/apps/welcome2/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AU5gAEFtoxnEwXN53WAAXO5oJB42Wy26AAIueFoPXFggAD4AwEGTQiB6otBFgwAD3QvFGC5dCFxiRGGClhrdbv67BXAIuLMBIwPsIABF4OpLwXOFxjBCF6gtBw2r1mHXoXWFxqQWFwOH62rL4IeB6xeOAAIvHGBYuC6+rR4QvCXpovXw3X1i/DR4QuPR5AvKFQOs6+GF4eod4IvPd5AvLwvWLwQvCv4fBR54vURwOHF4iQCX0yOCF4aQBX0QvHSAoAN3SOSd4WyF4yQPLyhgD1YvDMCJeIFxhgCF47BN4BeHFxpgDSAiRORpAuPMIYAFGBYuaF5aSHFwQvEFqQwOeggSBLa4xNF4X+4wAC/xeCFjIADrYwGBIIvlMQiPDBAOk0gDBz2XF8BlEF4eIxADFF8lcF9n+wIrFF05bHF9AsGF9wupGAYv/F8QupGAov/F/4wOF1gA/AH4Ap")) diff --git a/apps/welcome2/app.js b/apps/welcome2/app.js new file mode 100644 index 000000000..d9a967d8a --- /dev/null +++ b/apps/welcome2/app.js @@ -0,0 +1,256 @@ +// exec each function from seq one after the other +function animate(seq,period) { + var c = g.getColor(); + var i = setInterval(function() { + if (seq.length) { + var f = seq.shift(); + g.setColor(c); + if (f) f(); + } else clearInterval(i); + },period); +} + +// Fade in to FG color with angled lines +function fade(col, callback) { + var n = 0; + function f() {"ram" + g.setColor(col); + for (var i=n;i<240;i+=10) g.drawLine(i,0,0,i).drawLine(i,240,240,i); + g.flip(); + n++; + if (n<10) setTimeout(f,0); + else callback(); + } + f(); +} + + +var SCENE_COUNT=10; +function getScene(n) { + if (n==0) return function() { + g.reset().setBgColor(0).clearRect(0,0,176,176); + g.setFont("6x15"); + var n=0; + var l = Bangle.getLogo(); + var im = g.imageMetrics(l); + var i = setInterval(function() { + n+=0.1; + g.setColor(n,n,n); + g.drawImage(l,(176-im.width)/2,(176-im.height)/2); + if (n>=1) { + clearInterval(i); + setTimeout(()=>g.drawString("Open",44,104), 500); + setTimeout(()=>g.drawString("Hackable",44,116), 1000); + setTimeout(()=>g.drawString("Smart Watch",44,128), 1500); + } + },50); + }; + if (n==1) return function() { + var img = require("heatshrink").decompress(atob("ptR4n/j/4gH+8H5wl+jOukVVoHZ8dt/n//n37OtgH9sHhwHp4H5xmkGiH72MRje/LL/7iIAEE7sPEgoAC+AlagIlIiMQErPxDwUYxAABwIHCj8N7nOl3uEqa6BEggnFjfM5nCkUil3gEq5KDAAQmC6QmBE4JxSEhIABiQmB8QmSXoQlCYRMdEwIlCAAIlNhYlOiO85nNEyMPEoZwIAAcsYIYmPXoYlMiKaFExX/u9VEqLBBOYrCH+czmtVqJyDEpiaCOYsgSYszmc3qtTEqMR7hzG8AlGmd1OQglOOY6aEgYlCmmZoJMCTBrnD6SaIEoU/zOUuolSjbnBJgqaCEoU5zOXX4RyQYBBzCS4X5zNDqqZCJiERJg5zBEoVJEoM1JgYlQjhMHc4JLEmZMEEp6ZIJgPzS4WTmZMVTILmFYAK+BmglCmd1JgUYJiPNEorABEIOZygDBm5MCiJMQlhMH8ByBXwIlBJgUxJiMd5nOTIzlBTAK+BAANVq4jPAAS/HJgJyCTATAEACC/B4S/IJgIlCYAgAPiS/Kn5yEYANTEyPc5niOQxMB/LlCOapyJJgbpBYAZzROQK/Gl0ATIWfEoZzBc6IlB6SYGgBJBJgpzSlhyH8EAh5MBTIjnCuIlOjjlHTAJzC/LmDTSSYIEoTABOYIlETSKYHXwIABOYM0yYmETSCYHEobnDOYqaBExu8TAwlEc4U5EoiaCmK+NTAolFEwX0TQzBMXwXiEpTBCAAomNEoS+EEo4mIYIImKEoS+EEpDoBEyUbEo3gEo4mJdAImIJY4lJEycdEoPOOBYmPuIlE+HcJYhKKTZ1fhYkB2EAhnNcYMuEhomMr8A3YABEoJyB5gjOAAYmHm9VgELEoJMBEoXAEyXzE45YBJgXwEqx1I+ByDOYJyVJw5yCgEB3cQGgJMWJwQnCu6/CgFBigDB13S/glVAAf1qomCglEoADB1QDBADEPEoNVqEAolEgEKolKErJMDYAJMD0lE0AmaEoNaAgJMCFIYAahV/IgIiDOTgABNYJMEOToiCIoJMCOTzfCN4RMBOTxsDJIRyfIwZMBKQZzfJgRyfOYZMBOUBzCJgNKOT5zDJgLoCADxKBOAIABOT6aCAARyfOYRyjOYRyjOYlKEsBzEEsBzEOUJzDOUIABOUiaDOURzCOUZzCEscKCiY")); + var im = g.imageMetrics(img); + g.reset(); + g.setBgColor("#ff00ff"); + var y = 176, speed = 5; + function balloon(callback) { + y-=speed; + var x = (176-im.width)/2; + g.drawImage(img,x,y); + g.clearRect(x,y+81,x+77,y+81+speed); + if (y>30) setTimeout(balloon,0,callback); + else callback(); + } + fade("#ff00ff", function() { + balloon(function() { + g.setColor(-1).setFont("6x15:2").setFontAlign(0,0); + g.drawString("Welcome.",88,130); + }); + }); + setTimeout(function() { + var n=0; + var i = setInterval(function() { + n+=4; + g.scroll(0,-4); + if (n>150) + clearInterval(i); + },20); + },3500); + + }; + if (n==2) return function() { + g.reset(); + g.setBgColor("#ffff00").setColor(0).clear(); + g.setFont("12x20").setFontAlign(0,0); + var x = 70, y = 25, h=25; + animate([ + ()=>g.drawString("Your",x,y+=h), + ()=>g.drawString("Bangle.js",x,y+=h), + ()=>g.drawString("has one",x,y+=h), + ()=>g.drawString("button",x,y+=h), + ()=>{g.setFont("12x20:2").setFontAlign(0,0,1).drawString("HERE!",150,88);} + ],200); + }; + if (n==3) return function() { + g.reset(); + g.setBgColor("#00ffff").setColor(0).clear(); + g.setFontAlign(0,0).setFont("6x15:2"); + g.drawString("Press",88,40).setFontAlign(0,-1); + g.setFont("12x20"); + g.drawString("To wake the\nscreen up, or to\nselect", 88,60); + }; + if (n==4) return function() { + g.reset(); + g.setBgColor("#00ffff").setColor(0).clear(); + g.setFontAlign(0,0).setFont("6x15:2"); + g.drawString("Long Press",88,40).setFontAlign(0,-1); + g.setFont("12x20"); + g.drawString("To go back to\nthe clock", 88,60); + }; + if (n==5) return function() { + g.reset(); + g.setBgColor("#ff0000").setColor(0).clear(); + g.setFontAlign(0,0).setFont("12x20"); + g.drawString("If Bangle.js ever\nstops, hold the\nbutton for\nten seconds.\n\nBangle.js will\nthen reboot.", 88,78); + }; + if (n==6) return function() { + g.reset(); + g.setBgColor("#0000ff").setColor(-1).clear(); + g.setFont("12x20").setFontAlign(0,0); + var x = 88, y = -20, h=60; + animate([ + ()=>{g.drawString("Bangle.js has a\nfull touchscreen",x,y+=h);}, + 0,0, + ()=>{g.drawString("Drag up and down\nto scroll and\ntap to select",x,y+=h);}, + ],300); + }; + if (n==7) return function() { + g.reset(); + g.setBgColor("#00ff00").setColor(0).clear(); + g.setFont("12x20").setFontAlign(0,0); + var x = 88, y = -35, h=80; + animate([ + ()=>{g.drawString("Bangle.js comes\nwith a few\napps installed",x,y+=h);}, + 0,0, + ()=>{g.drawString("To add more, visit\nbanglejs.com/apps",x,y+=h);}, + ],400); + }; + if (n==8) return function() { + g.reset(); + g.setBgColor("#ff0000").setColor(0).clear(); + g.setFont("12x20").setFontAlign(0,0); + var x = 88; + g.drawString("You can also make\nyour own apps!",x,30); + g.drawString("Check out\nbanglejs.com",x,130); + + var rx = 0, ry = 0; + // draw a cube + function draw() { + // rotate + rx += 0.1; + ry += 0.11; + var rcx=Math.cos(rx), + rsx=Math.sin(rx), + rcy=Math.cos(ry), + rsy=Math.sin(ry); + // Project 3D coordinates into 2D + function p(x,y,z) { + var t; + t = x*rcy + z*rsy; + z = z*rcy - x*rsy; + x=t; + t = y*rcx + z*rsx; + z = z*rcx - y*rsx; + y=t; + z += 4; + return [88 + 60*x/z, 78+ 60*y/z]; + } + + var a; + // draw a series of lines to make up our cube + var s = 30; + g.clearRect(88-s,78-s,88+s,78+s); + a = p(-1,-1,-1); g.moveTo(a[0],a[1]); + a = p(1,-1,-1); g.lineTo(a[0],a[1]); + a = p(1,1,-1); g.lineTo(a[0],a[1]); + a = p(-1,1,-1); g.lineTo(a[0],a[1]); + a = p(-1,-1,-1); g.lineTo(a[0],a[1]); + a = p(-1,-1,1); g.moveTo(a[0],a[1]); + a = p(1,-1,1); g.lineTo(a[0],a[1]); + a = p(1,1,1); g.lineTo(a[0],a[1]); + a = p(-1,1,1); g.lineTo(a[0],a[1]); + a = p(-1,-1,1); g.lineTo(a[0],a[1]); + a = p(-1,-1,-1); g.moveTo(a[0],a[1]); + a = p(-1,-1,1); g.lineTo(a[0],a[1]); + a = p(1,-1,-1); g.moveTo(a[0],a[1]); + a = p(1,-1,1); g.lineTo(a[0],a[1]); + a = p(1,1,-1); g.moveTo(a[0],a[1]); + a = p(1,1,1); g.lineTo(a[0],a[1]); + a = p(-1,1,-1); g.moveTo(a[0],a[1]); + a = p(-1,1,1); g.lineTo(a[0],a[1]); + } + + setInterval(draw,50); + }; + if (n==9) return function() { + g.reset(); + g.setBgColor("#ffffff");g.clear(); + g.setFontAlign(0,0); + g.setFont("12x20"); + + var x = 88, y = 10, h=21; + animate([ + ()=>g.drawString("That's it!",x,y+=h), + ()=>{g.drawString("Press",x,y+=h*2); + g.drawString("the button",x,y+=h); + g.drawString("to start",x,y+=h); + g.drawString("Bangle.js",x,y+=h);} + ],400); + } +} + +var sceneNumber = 0; + +function move(dir) { + if (dir>0 && sceneNumber+1 == SCENE_COUNT) return; // at the end + sceneNumber = (sceneNumber+dir)%SCENE_COUNT; + if (sceneNumber<0) sceneNumber=0; + clearInterval(); + getScene(sceneNumber)(); + if (sceneNumber>1) { + var l = SCENE_COUNT; + for (var i=0;i move(dir)); +setWatch(()=>{ + if (sceneNumber == SCENE_COUNT-1) + load(); + else + move(1); +}, BTN1, {repeat:true}); + +(function migrateSettings(){ + let global_settings = require('Storage').readJSON('setting.json', 1) + if (global_settings) { + delete global_settings.welcomed + require('Storage').write('setting.json', global_settings) + } +})() + +Bangle.setLCDTimeout(0); +Bangle.setLCDPower(1); +move(0); diff --git a/apps/welcome2/app.png b/apps/welcome2/app.png new file mode 100644 index 000000000..ebbf254bd Binary files /dev/null and b/apps/welcome2/app.png differ diff --git a/apps/welcome2/boot.js b/apps/welcome2/boot.js new file mode 100644 index 000000000..07b7386f1 --- /dev/null +++ b/apps/welcome2/boot.js @@ -0,0 +1,9 @@ +(function() { + let s = require('Storage').readJSON('welcome2.json', 1) || {}; + if (!s.welcomed) { + setTimeout(() => { + require('Storage').write('welcome2.json', {welcomed: true}) + load('welcome2.app.js') + }) + } +})() diff --git a/apps/welcome2/settings.js b/apps/welcome2/settings.js new file mode 100644 index 000000000..d87cf4b55 --- /dev/null +++ b/apps/welcome2/settings.js @@ -0,0 +1,18 @@ +(function(back) { + let settings = require('Storage').readJSON('welcome2.json', 1) + || require('Storage').readJSON('setting.json', 1) || {} + E.showMenu({ + '': { 'title': 'Welcome App' }, + 'Run next boot': { + value: !settings.welcomed, + format: v => v ? 'Yes' : 'No', + onchange: v => require('Storage').write('welcome2.json', {welcomed: !v}), + }, + 'Run Now': () => load('welcome2.app.js'), + 'Turn off & run next': () => { + require('Storage').write('welcome2.json', {welcomed: false}); + Bangle.off(); + }, + '< Back': back, + }) +})