From 66b0edf6c2d52d06356632e386ba3eff377133f4 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 24 Oct 2024 12:39:02 +0100 Subject: [PATCH 01/63] clock_info 0.13: Cache loaded ClockInfos so if we have clockInfoWidget and a clock, we don't load them twice (saves ~300ms) --- apps/clock_info/ChangeLog | 3 ++- apps/clock_info/lib.js | 8 ++++++++ apps/clock_info/metadata.json | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/clock_info/ChangeLog b/apps/clock_info/ChangeLog index 8276321ace2..4fb43809781 100644 --- a/apps/clock_info/ChangeLog +++ b/apps/clock_info/ChangeLog @@ -10,4 +10,5 @@ 0.09: Save clkinfo settings on kill and remove 0.10: Fix focus bug when changing focus between two clock infos 0.11: Prepend swipe listener if possible -0.12: Add drawFilledImage to allow drawing icons with a separately coloured middle \ No newline at end of file +0.12: Add drawFilledImage to allow drawing icons with a separately coloured middle +0.13: Cache loaded ClockInfos so if we have clockInfoWidget and a clock, we don't load them twice (saves ~300ms) \ No newline at end of file diff --git a/apps/clock_info/lib.js b/apps/clock_info/lib.js index a9ca7de3185..7e0653c220f 100644 --- a/apps/clock_info/lib.js +++ b/apps/clock_info/lib.js @@ -14,6 +14,8 @@ if (stepGoal == undefined) { exports.loadCount = 0; /// A list of all the instances returned by addInteractive exports.clockInfos = []; +/// A list of loaded clockInfos +exports.clockInfoMenus = undefined; /// Load the settings, with defaults exports.loadSettings = function() { @@ -29,6 +31,8 @@ exports.loadSettings = function() { /// Load a list of ClockInfos - this does not cache and reloads each time exports.load = function() { + if (exports.clockInfoMenus) + return exports.clockInfoMenus; var settings = exports.loadSettings(); delete settings.apps; // keep just the basic settings in memory // info used for drawing... @@ -146,6 +150,7 @@ exports.load = function() { }); // return it all! + exports.clockInfoMenus = menu; return menu; }; @@ -345,6 +350,9 @@ exports.addInteractive = function(menu, options) { menuHideItem(menu[options.menuA].items[options.menuB]); exports.loadCount--; delete exports.clockInfos[options.index]; + // If nothing loaded now, clear our list of loaded menus + if (exports.loadCount==0) + exports.clockInfoMenus = undefined; }; options.redraw = function() { drawItem(menu[options.menuA].items[options.menuB]); diff --git a/apps/clock_info/metadata.json b/apps/clock_info/metadata.json index 3d47c506264..46e230a60ea 100644 --- a/apps/clock_info/metadata.json +++ b/apps/clock_info/metadata.json @@ -1,7 +1,7 @@ { "id": "clock_info", "name": "Clock Info Module", "shortName": "Clock Info", - "version":"0.12", + "version":"0.13", "description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)", "icon": "app.png", "type": "module", From 8a4ebbca7c96e2c5d196f139f811b9e1bc5b1b5d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 24 Oct 2024 12:41:58 +0100 Subject: [PATCH 02/63] At connect get list of pre-installed modules and use that to figure out if we need to drag in other things --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 7e5ac0271f7..97ba43366ea 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7e5ac0271f794bcacda3a5a692cfa479457eb4dd +Subproject commit 97ba43366eaded3dc6db00229825063f8c95382a From 1ec8fba5ba26f2a6facc3289d40e90f029304fa5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 24 Oct 2024 19:56:17 +0100 Subject: [PATCH 03/63] bootloader and clock_info update - checking hash of all js vs just boot.js is the same cost, so we make caches of widgets and clockinfos in bootupdate - this drastically improves boot time --- apps/boot/ChangeLog | 3 + apps/boot/bootupdate.js | 156 +++++++++++++++++++++------------- apps/boot/metadata.json | 5 +- apps/clock_info/ChangeLog | 3 +- apps/clock_info/lib.js | 8 +- apps/clock_info/metadata.json | 2 +- 6 files changed, 115 insertions(+), 62 deletions(-) diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 1d8e44b72f1..dd47229f7a5 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -72,3 +72,6 @@ 0.61: Instead of breaking execution with an Exception when updating boot, just use if..else (fix 'Uncaught undefined') 0.62: Handle setting for configuring BLE privacy 0.63: Only set BLE `display:1` if we have a passkey +0.64: Automatically create .widcache and .clkinfocache to speed up loads + Bangle.loadWidgets overwritten with fast version on success + Refuse to work on firmware <2v16 and remove old polyfills \ No newline at end of file diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index aa4a7e7b585..416d5939c85 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -12,14 +12,13 @@ if (DEBUG) { boot += "var _tm=Date.now()\n"; bootPost += "delete _tm;"; } -if (require('Storage').hash) { // new in 2v11 - helps ensure files haven't changed - let CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.boot\.js/)+E.CRC32(process.env.GIT_COMMIT); - boot += `if(E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\\.boot\\.js/)+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; -} else { - let CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))+E.CRC32(process.env.GIT_COMMIT); - boot += `if(E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\\.boot\\.js/))+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; +if (FWVERSION < 216) { + E.showMessage(/*LANG*/"Please update Bangle.js firmware\n\nCurrent = "+process.env.VERSION,{title:"ERROR"}); + throw new Error("Old firmware"); } -boot += `{eval(require('Storage').read('bootupdate.js'));print("Storage Updated!")}else{\n`; +let CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.js$/)+E.CRC32(process.env.GIT_COMMIT); +boot += `if(E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\\.js$/)+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; +boot += `{eval(require('Storage').read('bootupdate.js'));}else{\n`; boot += `E.setFlags({pretokenise:1});\n`; boot += `var bleServices = {}, bleServiceOptions = { uart : true};\n`; bootPost += `NRF.setServices(bleServices,bleServiceOptions);delete bleServices,bleServiceOptions;\n`; // executed after other boot code @@ -44,7 +43,7 @@ LoopbackA.setConsole(true);\n`; boot += ` Bluetooth.line=""; Bluetooth.on('data',function(d) { - var l = (Bluetooth.line + d).split(/[\\n\\r]/); + let l = (Bluetooth.line + d).split(/[\\n\\r]/); Bluetooth.line = l.pop(); l.forEach(n=>Bluetooth.emit("line",n)); }); @@ -86,11 +85,8 @@ if (s.bleprivacy || (s.passkey!==undefined && s.passkey.length==6)) { if (s.blename === false) boot+=`NRF.setAdvertising({},{showName:false});\n`; if (s.whitelist && !s.whitelist_disabled) boot+=`NRF.on('connect', function(addr) { if (!NRF.ignoreWhitelist) { let whitelist = (require('Storage').readJSON('setting.json',1)||{}).whitelist; if (NRF.resolveAddress !== undefined) { let resolvedAddr = NRF.resolveAddress(addr); if (resolvedAddr !== undefined) addr = resolvedAddr + " (resolved)"; } if (!whitelist.includes(addr)) NRF.disconnect(); }});\n`; if (s.rotate) boot+=`g.setRotation(${s.rotate&3},${s.rotate>>2});\n` // screen rotation +boot+=`Bangle.loadWidgets=function(){if(!global.WIDGETS)eval(require("Storage").read(".widcache"))};\n`; // ================================================== FIXING OLDER FIRMWARES -if (FWVERSION<215.068) // 2v15.68 and before had compass heading inverted. - boot += `Bangle.on('mag',e=>{if(!isNaN(e.heading))e.heading=360-e.heading;}); -Bangle.getCompass=(c=>(()=>{e=c();if(!isNaN(e.heading))e.heading=360-e.heading;return e;}))(Bangle.getCompass);`; - // deleting stops us getting confused by our own decl. builtins can't be deleted // this is a polyfill without fastloading capability delete Bangle.showClock; @@ -98,18 +94,10 @@ if (!Bangle.showClock) boot += `Bangle.showClock = ()=>{load(".bootcde")};\n`; delete Bangle.load; if (!Bangle.load) boot += `Bangle.load = load;\n`; let date = new Date(); -delete date.toLocalISOString; // toLocalISOString was only introduced in 2v15 -if (!date.toLocalISOString) boot += `Date.prototype.toLocalISOString = function() { - var o = this.getTimezoneOffset(); - var d = new Date(this.getTime() - o*60000); - var sign = o>0?"-":"+"; - o = Math.abs(o); - return d.toISOString().slice(0,-1)+sign+Math.floor(o/60).toString().padStart(2,0)+(o%60).toString().padStart(2,0); -};\n`; // show timings if (DEBUG) boot += `print(".boot0",0|(Date.now()-_tm),"ms");_tm=Date.now();\n` -// ================================================== BOOT.JS +// ================================================== .BOOT0 // Append *.boot.js files. // Name files with a number - eg 'foo.5.boot.js' to enforce order (lowest first). Numbered files get placed before non-numbered // These could change bleServices/bleServiceOptions if needed @@ -128,51 +116,105 @@ let bootFiles = require('Storage').list(/\.boot\.js$/).sort((a,b)=>{ }); // precalculate file size bootPost += "}"; -let fileSize = boot.length + bootPost.length; -bootFiles.forEach(bootFile=>{ - // match the size of data we're adding below in bootFiles.forEach - if (DEBUG) fileSize += 2+bootFile.length+1; // `//${bootFile}\n` comment - fileSize += require('Storage').read(bootFile).length+2; // boot code plus ";\n" - if (DEBUG) fileSize += 48+E.toJS(bootFile).length; // `print(${E.toJS(bootFile)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n` -}); -// write file in chunks (so as not to use up all RAM) -require('Storage').write('.boot0',boot,0,fileSize); -let fileOffset = boot.length; -bootFiles.forEach(bootFile=>{ +let fileOffset,fileSize; +/* code to output a file, plus preable and postable +when called with dst==undefined it just increments +fileOffset so we can see ho wbig the file has to be */ +let outputFile = (dst,src,pre,post) => {"ram"; + if (DEBUG) { + if (dst) require('Storage').write(dst,`//${src}\n`,fileOffset); + fileOffset+=2+src.length+1; + } + if (pre) { + if (dst) require('Storage').write(dst,pre,fileOffset); + fileOffset+=pre.length; + } + let f = require('Storage').read(src); + if (src.endsWith("clkinfo.js") && f[0]!="(") { + /* we shouldn't have to do this but it seems sometimes (sched 0.28) folks have + used libraries which get added into the clockinfo, and we can't use them directly + to we have to rever back to eval. */ + f = `eval(require('Storage').read(${E.toJS(src)}))`; + } + if (dst) { + // we can't just write 'f' in one go because it can be too big + let len = f.length; + let offset = 0; + while (len) { + let chunk = Math.min(len, 2048); + require('Storage').write(dst,f.substr(offset, chunk),fileOffset); + fileOffset+=chunk; + offset+=chunk; + len-=chunk; + } + } else + fileOffset+=f.length; + if (dst) require('Storage').write(dst,post,fileOffset); + fileOffset+=post.length; + if (DEBUG) { + if (dst) require('Storage').write(dst,`print(${E.toJS(src)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n`,fileOffset); + fileOffset += 48+E.toJS(src).length; + } +}; +let outputFileComplete = (dst,fn) => { // we add a semicolon so if the file is wrapped in (function(){ ... }() // with no semicolon we don't end up with (function(){ ... }()(function(){ ... }() // which would cause an error! // we write: // "//"+bootFile+"\n"+require('Storage').read(bootFile)+";\n"; // but we need to do this without ever loading everything into RAM as some - // boot files seem to be getting pretty big now. - if (DEBUG) { - require('Storage').write('.boot0',`//${bootFile}\n`,fileOffset); - fileOffset+=2+bootFile.length+1; - } - let bf = require('Storage').read(bootFile); - // we can't just write 'bf' in one go because at least in 2v13 and earlier - // Espruino wants to read the whole file into RAM first, and on Bangle.js 1 - // it can be too big (especially BTHRM). - let bflen = bf.length; - let bfoffset = 0; - while (bflen) { - let bfchunk = Math.min(bflen, 2048); - require('Storage').write('.boot0',bf.substr(bfoffset, bfchunk),fileOffset); - fileOffset+=bfchunk; - bfoffset+=bfchunk; - bflen-=bfchunk; - } - require('Storage').write('.boot0',";\n",fileOffset); - fileOffset+=2; - if (DEBUG) { - require('Storage').write('.boot0',`print(${E.toJS(bootFile)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n`,fileOffset); - fileOffset += 48+E.toJS(bootFile).length - } -}); + // boot files seem to be getting pretty big now. + outputFile(dst,fn,"",";\n"); +}; +fileOffset = boot.length + bootPost.length; +bootFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes +fileSize = fileOffset; +require('Storage').write('.boot0',boot,0,fileSize); +fileOffset = boot.length; +bootFiles.forEach(fn=>outputFileComplete('.boot0',fn)); require('Storage').write('.boot0',bootPost,fileOffset); +delete boot,bootPost,bootFiles; +// ================================================== .WIDCACHE for widgets +let widgetFiles = require("Storage").list(/\.wid\.js$/); +let widget = `// Made by bootupdate.js\nglobal.WIDGETS={};`, widgetPost = `var W=WIDGETS;WIDGETS={}; +Object.keys(W).sort((a,b)=>(0|W[b].sortorder)-(0|W[a].sortorder)).forEach(k=>WIDGETS[k]=W[k]);`; // sort +if (DEBUG) widget+="var _tm=Date.now();"; +outputFileComplete = (dst,fn) => { + outputFile(dst,fn,"try{",`}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`); +}; +fileOffset = widget.length + widgetPost.length; +widgetFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes +fileSize = fileOffset; +require('Storage').write('.widcache',widget,0,fileSize); +fileOffset = widget.length; +widgetFiles.forEach(fn=>outputFileComplete('.widcache',fn)); +require('Storage').write('.widcache',widgetPost,fileOffset); +delete widget,widgetPost,widgetFiles; +// ================================================== .clkinfocache for clockinfos +let ciFiles = require("Storage").list(/\.clkinfo\.js$/); +let ci = `// Made by bootupdate.js\n`; +if (DEBUG) ci+="var _tm=Date.now();"; +outputFileComplete = (dst,fn) => { + outputFile(dst,fn,"try{let a=",`(),b=menu.find(x=>x.name===a.name);if(b)b.items=b.items.concat(a.items)else menu=menu.concat(a);}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`); +}; +fileOffset = ci.length; +ciFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes +fileSize = fileOffset; +require('Storage').write('.clkinfocache',ci,0,fileSize); +fileOffset = ci.length; +ciFiles.forEach(fn=>outputFileComplete('.clkinfocache',fn)); +delete ci,ciFiles; +// test with require("clock_info").load() +// ================================================== END E.showMessage(/*LANG*/"Reloading..."); } // .bootcde should be run automatically after if required, since // we normally get called automatically from '.boot0' eval(require('Storage').read('.boot0')); +/* +f = require("Storage").read("sched.clkinfo.js") +if (f.startsWith("Modules.addCached")) { + +} + +*/ \ No newline at end of file diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index dcc55da58ec..c71de37c78e 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -1,7 +1,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.63", + "version": "0.64", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", @@ -11,6 +11,9 @@ {"name":".boot0","url":"boot0.js"}, {"name":".bootcde","url":"bootloader.js"}, {"name":"bootupdate.js","url":"bootupdate.js"} + ],"data": [ + {"name":".widcache"}, + {"name":".clkinfocache"} ], "sortorder": -10 } diff --git a/apps/clock_info/ChangeLog b/apps/clock_info/ChangeLog index 4fb43809781..7d204389968 100644 --- a/apps/clock_info/ChangeLog +++ b/apps/clock_info/ChangeLog @@ -11,4 +11,5 @@ 0.10: Fix focus bug when changing focus between two clock infos 0.11: Prepend swipe listener if possible 0.12: Add drawFilledImage to allow drawing icons with a separately coloured middle -0.13: Cache loaded ClockInfos so if we have clockInfoWidget and a clock, we don't load them twice (saves ~300ms) \ No newline at end of file +0.13: Cache loaded ClockInfos so if we have clockInfoWidget and a clock, we don't load them twice (saves ~300ms) +0.14: Check for .clkinfocache and use that if exists (from boot 0.64) \ No newline at end of file diff --git a/apps/clock_info/lib.js b/apps/clock_info/lib.js index 7e0653c220f..1134749c278 100644 --- a/apps/clock_info/lib.js +++ b/apps/clock_info/lib.js @@ -135,10 +135,14 @@ exports.load = function() { hide : function() { clearInterval(this.interval); delete this.interval; }, }); } - + var clkInfoCache = require('Storage').read('.clkinfocache'); + if (clkInfoCache!==undefined) { + // note: code below is included in clkinfocache by bootupdate.js + // we use clkinfocache if it exists as it's faster + eval(clkInfoCache); + } else require("Storage").list(/clkinfo.js$/).forEach(fn => { // In case there exists already a menu object b with the same name as the next // object a, we append the items. Otherwise we add the new object a to the list. - require("Storage").list(/clkinfo.js$/).forEach(fn => { try{ var a = eval(require("Storage").read(fn))(); var b = menu.find(x => x.name === a.name); diff --git a/apps/clock_info/metadata.json b/apps/clock_info/metadata.json index 46e230a60ea..1d9a73ce3a5 100644 --- a/apps/clock_info/metadata.json +++ b/apps/clock_info/metadata.json @@ -1,7 +1,7 @@ { "id": "clock_info", "name": "Clock Info Module", "shortName": "Clock Info", - "version":"0.13", + "version":"0.14", "description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)", "icon": "app.png", "type": "module", From 9185793042c7bfddba13333d33f678c2ca246e5d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 24 Oct 2024 20:09:19 +0100 Subject: [PATCH 04/63] use slightly slower code to deal with the fact that many apps put semi-colons on clockinfo/settings that are supposed to be evaluated --- apps/boot/bootupdate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 416d5939c85..a10a0cb150d 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -133,7 +133,7 @@ let outputFile = (dst,src,pre,post) => {"ram"; if (src.endsWith("clkinfo.js") && f[0]!="(") { /* we shouldn't have to do this but it seems sometimes (sched 0.28) folks have used libraries which get added into the clockinfo, and we can't use them directly - to we have to rever back to eval. */ + to we have to revert back to eval */ f = `eval(require('Storage').read(${E.toJS(src)}))`; } if (dst) { @@ -195,7 +195,7 @@ let ciFiles = require("Storage").list(/\.clkinfo\.js$/); let ci = `// Made by bootupdate.js\n`; if (DEBUG) ci+="var _tm=Date.now();"; outputFileComplete = (dst,fn) => { - outputFile(dst,fn,"try{let a=",`(),b=menu.find(x=>x.name===a.name);if(b)b.items=b.items.concat(a.items)else menu=menu.concat(a);}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`); + outputFile(dst,fn,"try{let fn=",`;let a=fn(),b=menu.find(x=>x.name===a.name);if(b)b.items=b.items.concat(a.items)else menu=menu.concat(a);}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`); }; fileOffset = ci.length; ciFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes From 385d2799d534d693a49c164fd23bcf7b79e26ade Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 25 Oct 2024 09:35:55 +0100 Subject: [PATCH 05/63] android 0.39: Move GB message handling into a library to reduce boot time from 40ms->13ms --- apps/android/ChangeLog | 3 +- apps/android/boot.js | 410 ++----------------------------------- apps/android/lib.js | 388 +++++++++++++++++++++++++++++++++++ apps/android/metadata.json | 5 +- 4 files changed, 407 insertions(+), 399 deletions(-) create mode 100644 apps/android/lib.js diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index 1e62173dcfa..f1107fc8422 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -38,4 +38,5 @@ 0.36: Move from wrapper function to {} and let - faster execution at boot Allow `calendar-` to take an array of items to remove 0.37: Support Gadgetbridge canned responses -0.38: Don't rewrite settings file on every boot! \ No newline at end of file +0.38: Don't rewrite settings file on every boot! +0.39: Move GB message handling into a library to reduce boot time from 40ms->13ms \ No newline at end of file diff --git a/apps/android/boot.js b/apps/android/boot.js index 53cf51ff2b3..18297d84f9f 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -1,349 +1,24 @@ /* global GB */ { - let gbSend = function(message) { - Bluetooth.println(""); - Bluetooth.println(JSON.stringify(message)); - } - let lastMsg; // for music messages - may not be needed now... - let actInterval; // Realtime activity reporting interval when `act` is true - let actHRMHandler; // For Realtime activity reporting - let gpsState = {}; // keep information on GPS via Gadgetbridge - - // this settings var is deleted after this executes to save memory + // settings var is deleted after this executes to save memory let settings = Object.assign({rp:true,as:true,vibrate:".."}, require("Storage").readJSON("android.settings.json",1)||{} ); let _GB = global.GB; - let fetchRecInterval; - global.GB = (event) => { + global.GB = e => { // feed a copy to other handlers if there were any - if (_GB) setTimeout(_GB,0,Object.assign({},event)); - - /* TODO: Call handling, fitness */ - var HANDLERS = { - // {t:"notify",id:int, src,title,subject,body,sender,tel:string} add - "notify" : function() { - Object.assign(event,{t:"add",positive:true, negative:true}); - // Detect a weird GadgetBridge bug and fix it - // For some reason SMS messages send two GB notifications, with different sets of info - if (lastMsg && event.body == lastMsg.body && lastMsg.src == undefined && event.src == "Messages") { - // Mutate the other message - event.id = lastMsg.id; - } - lastMsg = event; - require("messages").pushMessage(event); - }, - // {t:"notify~",id:int, title:string} // modified - "notify~" : function() { event.t="modify";require("messages").pushMessage(event); }, - // {t:"notify-",id:int} // remove - "notify-" : function() { event.t="remove";require("messages").pushMessage(event); }, - // {t:"find", n:bool} // find my phone - "find" : function() { - if (Bangle.findDeviceInterval) { - clearInterval(Bangle.findDeviceInterval); - delete Bangle.findDeviceInterval; - } - if (event.n) // Ignore quiet mode: we always want to find our watch - Bangle.findDeviceInterval = setInterval(_=>Bangle.buzz(),1000); - }, - // {t:"musicstate", state:"play/pause",position,shuffle,repeat} - "musicstate" : function() { - require("messages").pushMessage({t:"modify",id:"music",title:"Music",state:event.state}); - }, - // {t:"musicinfo", artist,album,track,dur,c(track count),n(track num} - "musicinfo" : function() { - require("messages").pushMessage(Object.assign(event, {t:"modify",id:"music",title:"Music"})); - }, - // {"t":"call","cmd":"incoming/end","name":"Bob","number":"12421312"}) - "call" : function() { - Object.assign(event, { - t:event.cmd=="incoming"?"add":"remove", - id:"call", src:"Phone", - positive:true, negative:true, - title:event.name||/*LANG*/"Call", body:/*LANG*/"Incoming call\n"+event.number}); - require("messages").pushMessage(event); - }, - "canned_responses_sync" : function() { - require("Storage").writeJSON("replies.json", event.d); - }, - // {"t":"alarm", "d":[{h:int,m:int,rep:int},... } - "alarm" : function() { - //wipe existing GB alarms - var sched; - try { sched = require("sched"); } catch (e) {} - if (!sched) return; // alarms may not be installed - var gbalarms = sched.getAlarms().filter(a=>a.appid=="gbalarms"); - for (var i = 0; i < gbalarms.length; i++) - sched.setAlarm(gbalarms[i].id, undefined); - var alarms = sched.getAlarms(); - var time = new Date(); - var currentTime = time.getHours() * 3600000 + - time.getMinutes() * 60000 + - time.getSeconds() * 1000; - for (var j = 0; j < event.d.length; j++) { - // prevents all alarms from going off at once?? - var dow = event.d[j].rep; - var rp = false; - if (!dow) { - dow = 127; //if no DOW selected, set alarm to all DOW - } else { - rp = true; - } - var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0; - var a = require("sched").newDefaultAlarm(); - a.id = "gb"+j; - a.appid = "gbalarms"; - a.on = event.d[j].on !== undefined ? event.d[j].on : true; - a.t = event.d[j].h * 3600000 + event.d[j].m * 60000; - a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format - a.rp = rp; - a.last = last; - alarms.push(a); - } - sched.setAlarms(alarms); - sched.reload(); - }, - //TODO perhaps move those in a library (like messages), used also for viewing events? - //add and remove events based on activity on phone (pebble-like) - // {t:"calendar", id:int, type:int, timestamp:seconds, durationInSeconds, title:string, description:string,location:string,calName:string.color:int,allDay:bool - "calendar" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true); - if (!cal || !Array.isArray(cal)) cal = []; - var i = cal.findIndex(e=>e.id==event.id); - if(i<0) - cal.push(event); - else - cal[i] = event; - require("Storage").writeJSON("android.calendar.json", cal); - }, - // {t:"calendar-", id:int} - "calendar-" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true); - //if any of those happen we are out of sync! - if (!cal || !Array.isArray(cal)) cal = []; - if (Array.isArray(event.id)) - cal = cal.filter(e=>!event.id.includes(e.id)); - else - cal = cal.filter(e=>e.id!=event.id); - require("Storage").writeJSON("android.calendar.json", cal); - }, - //triggered by GB, send all ids - // { t:"force_calendar_sync_start" } - "force_calendar_sync_start" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true); - if (!cal || !Array.isArray(cal)) cal = []; - gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)}); - }, - // {t:"http",resp:"......",[id:"..."]} - "http":function() { - //get the promise and call the promise resolve - if (Bangle.httpRequest === undefined) return; - var request=Bangle.httpRequest[event.id]; - if (request === undefined) return; //already timedout or wrong id - delete Bangle.httpRequest[event.id]; - clearTimeout(request.t); //t = timeout variable - if(event.err!==undefined) //if is error - request.j(event.err); //r = reJect function - else - request.r(event); //r = resolve function - }, - // {t:"gps", lat, lon, alt, speed, course, time, satellites, hdop, externalSource:true } - "gps": function() { - if (!settings.overwriteGps) return; - // modify event for using it as Bangle GPS event - delete event.t; - if (!isFinite(event.satellites)) event.satellites = NaN; - if (!isFinite(event.course)) event.course = NaN; - event.fix = 1; - if (event.long!==undefined) { // for earlier Gadgetbridge implementations - event.lon = event.long; - delete event.long; - } - if (event.time){ - event.time = new Date(event.time); - } - - if (!gpsState.lastGPSEvent) { - // this is the first event, save time of arrival and deactivate internal GPS - Bangle.moveGPSPower(0); - } else { - // this is the second event, store the intervall for expecting the next GPS event - gpsState.interval = Date.now() - gpsState.lastGPSEvent; - } - gpsState.lastGPSEvent = Date.now(); - // in any case, cleanup the GPS state in case no new events arrive - if (gpsState.timeoutGPS) clearTimeout(gpsState.timeoutGPS); - gpsState.timeoutGPS = setTimeout(()=>{ - // reset state - gpsState.lastGPSEvent = undefined; - gpsState.timeoutGPS = undefined; - gpsState.interval = undefined; - // did not get an expected GPS event but have GPS clients, switch back to internal GPS - if (Bangle.isGPSOn()) Bangle.moveGPSPower(1); - }, (gpsState.interval || 10000) + 1000); - Bangle.emit('GPS', event); - }, - // {t:"is_gps_active"} - "is_gps_active": function() { - gbSend({ t: "gps_power", status: Bangle.isGPSOn() }); - }, - // {t:"act", hrm:bool, stp:bool, int:int} - "act": function() { - if (actInterval) clearInterval(actInterval); - actInterval = undefined; - if (actHRMHandler) - actHRMHandler = undefined; - Bangle.setHRMPower(event.hrm,"androidact"); - if (!(event.hrm || event.stp)) return; - if (!isFinite(event.int)) event.int=1; - var lastSteps = Bangle.getStepCount(); - var lastBPM = 0; - actHRMHandler = function(e) { - lastBPM = e.bpm; - }; - Bangle.on('HRM',actHRMHandler); - actInterval = setInterval(function() { - var steps = Bangle.getStepCount(); - gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM, rt:1 }); - lastSteps = steps; - }, event.int*1000); - }, - // {t:"actfetch", ts:long} - "actfetch": function() { - gbSend({t: "actfetch", state: "start"}); - var actCount = 0; - var actCb = function(r) { - // The health lib saves the samples at the start of the 10-minute block - // However, GB expects them at the end of the block, so let's offset them - // here to keep a consistent API in the health lib - var sampleTs = r.date.getTime() + 600000; - if (sampleTs >= event.ts) { - gbSend({ - t: "act", - ts: sampleTs, - stp: r.steps, - hrm: r.bpm, - mov: r.movement - }); - actCount++; - } - } - if (event.ts != 0) { - require("health").readAllRecordsSince(new Date(event.ts - 600000), actCb); - } else { - require("health").readFullDatabase(actCb); - } - gbSend({t: "actfetch", state: "end", count: actCount}); - }, - //{t:"listRecs", id:"20230616a"} - "listRecs": function() { - let recs = require("Storage").list(/^recorder\.log.*\.csv$/,{sf:true}).map(s => s.slice(12, 21)); - if (event.id.length > 2) { // Handle if there was no id supplied. Then we send a list all available recorder logs back. - let firstNonsyncedIdx = recs.findIndex((logId) => logId > event.id); - if (-1 == firstNonsyncedIdx) { - recs = [] - } else { - recs = recs.slice(firstNonsyncedIdx); - } - } - gbSend({t:"actTrksList", list: recs}); // TODO: split up in multiple transmissions? - }, - //{t:"fetchRec", id:"20230616a"} - "fetchRec": function() { - // TODO: Decide on what names keys should have. - if (fetchRecInterval) { - clearInterval(fetchRecInterval); - fetchRecInterval = undefined; - } - if (event.id=="stop") { - return - } else { - let log = require("Storage").open("recorder.log"+event.id+".csv","r"); - let lines = "init";// = log.readLine(); - let pkgcnt = 0; - gbSend({t:"actTrk", log:event.id, lines:"erase", cnt:pkgcnt}); // "erase" will prompt Gadgetbridge to erase the contents of a already fetched log so we can rewrite it without keeping lines from the previous (probably failed) fetch. - let sendlines = ()=>{ - lines = log.readLine(); - for (var i = 0; i < 3; i++) { - let line = log.readLine(); - if (line) lines += line; - } - pkgcnt++; - gbSend({t:"actTrk", log:event.id, lines:lines, cnt:pkgcnt}); - if (!lines && fetchRecInterval) { - clearInterval(fetchRecInterval); - fetchRecInterval = undefined; - } - } - fetchRecInterval = setInterval(sendlines, 50) - } - }, - "nav": function() { - event.id="nav"; - if (event.instr) { - event.t="add"; - event.src="maps"; // for the icon - event.title="Navigation"; - if (require("messages").getMessages().find(m=>m.id=="nav")) - event.t = "modify"; - } else { - event.t="remove"; - } - require("messages").pushMessage(event); - }, - "cards" : function() { - // we receive all, just override what we have - if (Array.isArray(event.d)) - require("Storage").writeJSON("android.cards.json", event.d); - }, - "accelsender": function () { - require("Storage").writeJSON("accelsender.json", {enabled: event.enable, interval: event.interval}); - load(); - } - }; - var h = HANDLERS[event.t]; - if (h) h(); else console.log("GB Unknown",event); + if (_GB) setTimeout(_GB,0,Object.assign({},e)); + Bangle.emit("GB",e); + require("android").gbHandler(e); }; // HTTP request handling - see the readme - // options = {id,timeout,xpath} - Bangle.http = (url,options)=>{ - options = options||{}; - if (!NRF.getSecurityStatus().connected) - return Promise.reject(/*LANG*/"Not connected to Bluetooth"); - if (Bangle.httpRequest === undefined) - Bangle.httpRequest={}; - if (options.id === undefined) { - // try and create a unique ID - do { - options.id = Math.random().toString().substr(2); - } while( Bangle.httpRequest[options.id]!==undefined); - } - //send the request - var req = {t: "http", url:url, id:options.id}; - if (options.xpath) req.xpath = options.xpath; - if (options.return) req.return = options.return; // for xpath - if (options.method) req.method = options.method; - if (options.body) req.body = options.body; - if (options.headers) req.headers = options.headers; - gbSend(req); - //create the promise - var promise = new Promise(function(resolve,reject) { - //save the resolve function in the dictionary and create a timeout (30 seconds default) - Bangle.httpRequest[options.id]={r:resolve,j:reject,t:setTimeout(()=>{ - //if after "timeoutMillisec" it still hasn't answered -> reject - delete Bangle.httpRequest[options.id]; - reject("Timeout"); - },options.timeout||30000)}; - }); - return promise; - }; - + Bangle.http = (url,options)=>require("android").httpHandler(url,options); // Battery monitor - let sendBattery = function() { gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); } + let sendBattery = function() { require("android").gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); } Bangle.on("charging", sendBattery); NRF.on("connect", () => setTimeout(function() { sendBattery(); - gbSend({t: "ver", fw: process.env.VERSION, hw: process.env.HWVERSION}); + require("android").gbSend({t: "ver", fw: process.env.VERSION, hw: process.env.HWVERSION}); GB({t:"force_calendar_sync_start"}); // send a list of our calendar entries to start off the sync process }, 2000)); NRF.on("disconnect", () => { @@ -357,81 +32,24 @@ setInterval(sendBattery, 10*60*1000); // Health tracking - if 'realtime' data is sent with 'rt:1', but let's still send our activity log every 10 mins Bangle.on('health', h=>{ - gbSend({ t: "act", stp: h.steps, hrm: h.bpm, mov: h.movement }); + require("android").gbSend({ t: "act", stp: h.steps, hrm: h.bpm, mov: h.movement }); }); // Music control Bangle.musicControl = cmd => { // play/pause/next/previous/volumeup/volumedown - gbSend({ t: "music", n:cmd }); + require("android").gbSend({ t: "music", n:cmd }); }; // Message response Bangle.messageResponse = (msg,response) => { - if (msg.id=="call") return gbSend({ t: "call", n:response?"ACCEPT":"REJECT" }); - if (isFinite(msg.id)) return gbSend({ t: "notify", n:response?"OPEN":"DISMISS", id: msg.id }); + if (msg.id=="call") return require("android").gbSend({ t: "call", n:response?"ACCEPT":"REJECT" }); + if (isFinite(msg.id)) return require("android").gbSend({ t: "notify", n:response?"OPEN":"DISMISS", id: msg.id }); // error/warn here? }; Bangle.messageIgnore = msg => { - if (isFinite(msg.id)) return gbSend({ t: "notify", n:"MUTE", id: msg.id }); + if (isFinite(msg.id)) return require("android").gbSend({ t: "notify", n:"MUTE", id: msg.id }); }; // GPS overwrite logic - if (settings.overwriteGps) { // if the overwrite option is set.. - const origSetGPSPower = Bangle.setGPSPower; - Bangle.moveGPSPower = (state) => { - if (Bangle.isGPSOn()){ - let orig = Bangle._PWR.GPS; - delete Bangle._PWR.GPS; - origSetGPSPower(state); - Bangle._PWR.GPS = orig; - } - }; - - // work around Serial1 for GPS not working when connected to something - let serialTimeout; - let wrap = function(f){ - return (s)=>{ - if (serialTimeout) clearTimeout(serialTimeout); - origSetGPSPower(1, "androidgpsserial"); - f(s); - serialTimeout = setTimeout(()=>{ - serialTimeout = undefined; - origSetGPSPower(0, "androidgpsserial"); - }, 10000); - }; - }; - Serial1.println = wrap(Serial1.println); - Serial1.write = wrap(Serial1.write); - - // replace set GPS power logic to suppress activation of gps (and instead request it from the phone) - Bangle.setGPSPower = ((isOn, appID) => { - let pwr; - if (!this.lastGPSEvent){ - // use internal GPS power function if no gps event has arrived from GadgetBridge - pwr = origSetGPSPower(isOn, appID); - } else { - // we are currently expecting the next GPS event from GadgetBridge, keep track of GPS state per app - if (!Bangle._PWR) Bangle._PWR={}; - if (!Bangle._PWR.GPS) Bangle._PWR.GPS=[]; - if (!appID) appID="?"; - if (isOn && !Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.push(appID); - if (!isOn && Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.splice(Bangle._PWR.GPS.indexOf(appID),1); - pwr = Bangle._PWR.GPS.length>0; - // stop internal GPS, no clients left - if (!pwr) origSetGPSPower(0); - } - // always update Gadgetbridge on current power state - gbSend({ t: "gps_power", status: pwr }); - return pwr; - }).bind(gpsState); - // allow checking for GPS via GadgetBridge - Bangle.isGPSOn = () => { - return !!(Bangle._PWR && Bangle._PWR.GPS && Bangle._PWR.GPS.length>0); - }; - // stop GPS on boot if not activated - setTimeout(()=>{ - if (!Bangle.isGPSOn()) gbSend({ t: "gps_power", status: false }); - },3000); - } - + if (settings.overwriteGps) require("android").overwriteGPS(); // remove settings object so it's not taking up RAM delete settings; } diff --git a/apps/android/lib.js b/apps/android/lib.js new file mode 100644 index 00000000000..71d7f60437b --- /dev/null +++ b/apps/android/lib.js @@ -0,0 +1,388 @@ +exports.gbSend = function(message) { + Bluetooth.println(""); + Bluetooth.println(JSON.stringify(message)); +} +let lastMsg, // for music messages - may not be needed now... + gpsState = {}, // keep information on GPS via Gadgetbridge + settings = Object.assign({rp:true,as:true,vibrate:".."}, + require("Storage").readJSON("android.settings.json",1)||{} + ); + +exports.gbHandler = (event) => { + var HANDLERS = { + // {t:"notify",id:int, src,title,subject,body,sender,tel:string} add + "notify" : function() { + print("notify",event); + Object.assign(event,{t:"add",positive:true, negative:true}); + // Detect a weird GadgetBridge bug and fix it + // For some reason SMS messages send two GB notifications, with different sets of info + if (lastMsg && event.body == lastMsg.body && lastMsg.src == undefined && event.src == "Messages") { + // Mutate the other message + event.id = lastMsg.id; + } + lastMsg = event; + require("messages").pushMessage(event); + }, + // {t:"notify~",id:int, title:string} // modified + "notify~" : function() { event.t="modify";require("messages").pushMessage(event); }, + // {t:"notify-",id:int} // remove + "notify-" : function() { event.t="remove";require("messages").pushMessage(event); }, + // {t:"find", n:bool} // find my phone + "find" : function() { + if (Bangle.findDeviceInterval) { + clearInterval(Bangle.findDeviceInterval); + delete Bangle.findDeviceInterval; + } + if (event.n) // Ignore quiet mode: we always want to find our watch + Bangle.findDeviceInterval = setInterval(_=>Bangle.buzz(),1000); + }, + // {t:"musicstate", state:"play/pause",position,shuffle,repeat} + "musicstate" : function() { + require("messages").pushMessage({t:"modify",id:"music",title:"Music",state:event.state}); + }, + // {t:"musicinfo", artist,album,track,dur,c(track count),n(track num} + "musicinfo" : function() { + require("messages").pushMessage(Object.assign(event, {t:"modify",id:"music",title:"Music"})); + }, + // {"t":"call","cmd":"incoming/end","name":"Bob","number":"12421312"}) + "call" : function() { + Object.assign(event, { + t:event.cmd=="incoming"?"add":"remove", + id:"call", src:"Phone", + positive:true, negative:true, + title:event.name||/*LANG*/"Call", body:/*LANG*/"Incoming call\n"+event.number}); + require("messages").pushMessage(event); + }, + "canned_responses_sync" : function() { + require("Storage").writeJSON("replies.json", event.d); + }, + // {"t":"alarm", "d":[{h:int,m:int,rep:int},... } + "alarm" : function() { + //wipe existing GB alarms + var sched; + try { sched = require("sched"); } catch (e) {} + if (!sched) return; // alarms may not be installed + var gbalarms = sched.getAlarms().filter(a=>a.appid=="gbalarms"); + for (var i = 0; i < gbalarms.length; i++) + sched.setAlarm(gbalarms[i].id, undefined); + var alarms = sched.getAlarms(); + var time = new Date(); + var currentTime = time.getHours() * 3600000 + + time.getMinutes() * 60000 + + time.getSeconds() * 1000; + for (var j = 0; j < event.d.length; j++) { + // prevents all alarms from going off at once?? + var dow = event.d[j].rep; + var rp = false; + if (!dow) { + dow = 127; //if no DOW selected, set alarm to all DOW + } else { + rp = true; + } + var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0; + var a = require("sched").newDefaultAlarm(); + a.id = "gb"+j; + a.appid = "gbalarms"; + a.on = event.d[j].on !== undefined ? event.d[j].on : true; + a.t = event.d[j].h * 3600000 + event.d[j].m * 60000; + a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format + a.rp = rp; + a.last = last; + alarms.push(a); + } + sched.setAlarms(alarms); + sched.reload(); + }, + //TODO perhaps move those in a library (like messages), used also for viewing events? + //add and remove events based on activity on phone (pebble-like) + // {t:"calendar", id:int, type:int, timestamp:seconds, durationInSeconds, title:string, description:string,location:string,calName:string.color:int,allDay:bool + "calendar" : function() { + var cal = require("Storage").readJSON("android.calendar.json",true); + if (!cal || !Array.isArray(cal)) cal = []; + var i = cal.findIndex(e=>e.id==event.id); + if(i<0) + cal.push(event); + else + cal[i] = event; + require("Storage").writeJSON("android.calendar.json", cal); + }, + // {t:"calendar-", id:int} + "calendar-" : function() { + var cal = require("Storage").readJSON("android.calendar.json",true); + //if any of those happen we are out of sync! + if (!cal || !Array.isArray(cal)) cal = []; + if (Array.isArray(event.id)) + cal = cal.filter(e=>!event.id.includes(e.id)); + else + cal = cal.filter(e=>e.id!=event.id); + require("Storage").writeJSON("android.calendar.json", cal); + }, + //triggered by GB, send all ids + // { t:"force_calendar_sync_start" } + "force_calendar_sync_start" : function() { + var cal = require("Storage").readJSON("android.calendar.json",true); + if (!cal || !Array.isArray(cal)) cal = []; + exports.gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)}); + }, + // {t:"http",resp:"......",[id:"..."]} + "http":function() { + //get the promise and call the promise resolve + if (Bangle.httpRequest === undefined) return; + var request=Bangle.httpRequest[event.id]; + if (request === undefined) return; //already timedout or wrong id + delete Bangle.httpRequest[event.id]; + clearTimeout(request.t); //t = timeout variable + if(event.err!==undefined) //if is error + request.j(event.err); //r = reJect function + else + request.r(event); //r = resolve function + }, + // {t:"gps", lat, lon, alt, speed, course, time, satellites, hdop, externalSource:true } + "gps": function() { + if (!settings.overwriteGps) return; + // modify event for using it as Bangle GPS event + delete event.t; + if (!isFinite(event.satellites)) event.satellites = NaN; + if (!isFinite(event.course)) event.course = NaN; + event.fix = 1; + if (event.long!==undefined) { // for earlier Gadgetbridge implementations + event.lon = event.long; + delete event.long; + } + if (event.time){ + event.time = new Date(event.time); + } + + if (!gpsState.lastGPSEvent) { + // this is the first event, save time of arrival and deactivate internal GPS + Bangle.moveGPSPower(0); + } else { + // this is the second event, store the intervall for expecting the next GPS event + gpsState.interval = Date.now() - gpsState.lastGPSEvent; + } + gpsState.lastGPSEvent = Date.now(); + // in any case, cleanup the GPS state in case no new events arrive + if (gpsState.timeoutGPS) clearTimeout(gpsState.timeoutGPS); + gpsState.timeoutGPS = setTimeout(()=>{ + // reset state + gpsState.lastGPSEvent = undefined; + gpsState.timeoutGPS = undefined; + gpsState.interval = undefined; + // did not get an expected GPS event but have GPS clients, switch back to internal GPS + if (Bangle.isGPSOn()) Bangle.moveGPSPower(1); + }, (gpsState.interval || 10000) + 1000); + Bangle.emit('GPS', event); + }, + // {t:"is_gps_active"} + "is_gps_active": function() { + exports.gbSend({ t: "gps_power", status: Bangle.isGPSOn() }); + }, + // {t:"act", hrm:bool, stp:bool, int:int} + "act": function() { + if (exports.actInterval) clearInterval(exports.actInterval); + exports.actInterval = undefined; + if (exports.actHRMHandler) + exports.actHRMHandler = undefined; + Bangle.setHRMPower(event.hrm,"androidact"); + if (!(event.hrm || event.stp)) return; + if (!isFinite(event.int)) event.int=1; + var lastSteps = Bangle.getStepCount(); + var lastBPM = 0; + exports.actHRMHandler = function(e) { + lastBPM = e.bpm; + }; + Bangle.on('HRM',exports.actHRMHandler); + exports.actInterval = setInterval(function() { + var steps = Bangle.getStepCount(); + exports.gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM, rt:1 }); + lastSteps = steps; + }, event.int*1000); + }, + // {t:"actfetch", ts:long} + "actfetch": function() { + exports.gbSend({t: "actfetch", state: "start"}); + var actCount = 0; + var actCb = function(r) { + // The health lib saves the samples at the start of the 10-minute block + // However, GB expects them at the end of the block, so let's offset them + // here to keep a consistent API in the health lib + var sampleTs = r.date.getTime() + 600000; + if (sampleTs >= event.ts) { + exports.gbSend({ + t: "act", + ts: sampleTs, + stp: r.steps, + hrm: r.bpm, + mov: r.movement + }); + actCount++; + } + } + if (event.ts != 0) { + require("health").readAllRecordsSince(new Date(event.ts - 600000), actCb); + } else { + require("health").readFullDatabase(actCb); + } + exports.gbSend({t: "actfetch", state: "end", count: actCount}); + }, + //{t:"listRecs", id:"20230616a"} + "listRecs": function() { + let recs = require("Storage").list(/^recorder\.log.*\.csv$/,{sf:true}).map(s => s.slice(12, 21)); + if (event.id.length > 2) { // Handle if there was no id supplied. Then we send a list all available recorder logs back. + let firstNonsyncedIdx = recs.findIndex((logId) => logId > event.id); + if (-1 == firstNonsyncedIdx) { + recs = [] + } else { + recs = recs.slice(firstNonsyncedIdx); + } + } + exports.gbSend({t:"actTrksList", list: recs}); // TODO: split up in multiple transmissions? + }, + //{t:"fetchRec", id:"20230616a"} + "fetchRec": function() { + // TODO: Decide on what names keys should have. + if (exports.fetchRecInterval) { + clearInterval(exports.fetchRecInterval); + exports.fetchRecInterval = undefined; + } + if (event.id=="stop") { + return; + } else { + let log = require("Storage").open("recorder.log"+event.id+".csv","r"); + let lines = "init";// = log.readLine(); + let pkgcnt = 0; + exports.gbSend({t:"actTrk", log:event.id, lines:"erase", cnt:pkgcnt}); // "erase" will prompt Gadgetbridge to erase the contents of a already fetched log so we can rewrite it without keeping lines from the previous (probably failed) fetch. + let sendlines = ()=>{ + lines = log.readLine(); + for (var i = 0; i < 3; i++) { + let line = log.readLine(); + if (line) lines += line; + } + pkgcnt++; + exports.gbSend({t:"actTrk", log:event.id, lines:lines, cnt:pkgcnt}); + if (!lines && exports.fetchRecInterval) { + clearInterval(exports.fetchRecInterval); + exports.fetchRecInterval = undefined; + } + }; + exports.fetchRecInterval = setInterval(sendlines, 50); + } + }, + "nav": function() { + event.id="nav"; + if (event.instr) { + event.t="add"; + event.src="maps"; // for the icon + event.title="Navigation"; + if (require("messages").getMessages().find(m=>m.id=="nav")) + event.t = "modify"; + } else { + event.t="remove"; + } + require("messages").pushMessage(event); + }, + "cards" : function() { + // we receive all, just override what we have + if (Array.isArray(event.d)) + require("Storage").writeJSON("android.cards.json", event.d); + }, + "accelsender": function () { + require("Storage").writeJSON("accelsender.json", {enabled: event.enable, interval: event.interval}); + load(); + } + }; + var h = HANDLERS[event.t]; + if (h) h(); else console.log("GB Unknown",event); +}; + +// HTTP request handling - see the readme +// options = {id,timeout,xpath} +exports.httpHandler = (url,options) => { + options = options||{}; + if (!NRF.getSecurityStatus().connected) + return Promise.reject(/*LANG*/"Not connected to Bluetooth"); + if (Bangle.httpRequest === undefined) + Bangle.httpRequest={}; + if (options.id === undefined) { + // try and create a unique ID + do { + options.id = Math.random().toString().substr(2); + } while( Bangle.httpRequest[options.id]!==undefined); + } + //send the request + var req = {t: "http", url:url, id:options.id}; + if (options.xpath) req.xpath = options.xpath; + if (options.return) req.return = options.return; // for xpath + if (options.method) req.method = options.method; + if (options.body) req.body = options.body; + if (options.headers) req.headers = options.headers; + exports.gbSend(req); + //create the promise + var promise = new Promise(function(resolve,reject) { + //save the resolve function in the dictionary and create a timeout (30 seconds default) + Bangle.httpRequest[options.id]={r:resolve,j:reject,t:setTimeout(()=>{ + //if after "timeoutMillisec" it still hasn't answered -> reject + delete Bangle.httpRequest[options.id]; + reject("Timeout"); + },options.timeout||30000)}; + }); + return promise; +}; + +exports.overwriteGPS = () => { // if the overwrite option is set, call this on init.. + const origSetGPSPower = Bangle.setGPSPower; + Bangle.moveGPSPower = (state) => { + if (Bangle.isGPSOn()){ + let orig = Bangle._PWR.GPS; + delete Bangle._PWR.GPS; + origSetGPSPower(state); + Bangle._PWR.GPS = orig; + } + }; + + // work around Serial1 for GPS not working when connected to something + let serialTimeout; + let wrap = function(f){ + return (s)=>{ + if (serialTimeout) clearTimeout(serialTimeout); + origSetGPSPower(1, "androidgpsserial"); + f(s); + serialTimeout = setTimeout(()=>{ + serialTimeout = undefined; + origSetGPSPower(0, "androidgpsserial"); + }, 10000); + }; + }; + Serial1.println = wrap(Serial1.println); + Serial1.write = wrap(Serial1.write); + + // replace set GPS power logic to suppress activation of gps (and instead request it from the phone) + Bangle.setGPSPower = ((isOn, appID) => { + let pwr; + if (!this.lastGPSEvent){ + // use internal GPS power function if no gps event has arrived from GadgetBridge + pwr = origSetGPSPower(isOn, appID); + } else { + // we are currently expecting the next GPS event from GadgetBridge, keep track of GPS state per app + if (!Bangle._PWR) Bangle._PWR={}; + if (!Bangle._PWR.GPS) Bangle._PWR.GPS=[]; + if (!appID) appID="?"; + if (isOn && !Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.push(appID); + if (!isOn && Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.splice(Bangle._PWR.GPS.indexOf(appID),1); + pwr = Bangle._PWR.GPS.length>0; + // stop internal GPS, no clients left + if (!pwr) origSetGPSPower(0); + } + // always update Gadgetbridge on current power state + require("android").gbSend({ t: "gps_power", status: pwr }); + return pwr; + }).bind(gpsState); + // allow checking for GPS via GadgetBridge + Bangle.isGPSOn = () => { + return !!(Bangle._PWR && Bangle._PWR.GPS && Bangle._PWR.GPS.length>0); + }; + // stop GPS on boot if not activated + setTimeout(()=>{ + if (!Bangle.isGPSOn()) require("android").gbSend({ t: "gps_power", status: false }); + },3000); +}; \ No newline at end of file diff --git a/apps/android/metadata.json b/apps/android/metadata.json index b1c3ecfaa06..584c071cf3c 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.38", + "version": "0.39", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", @@ -13,7 +13,8 @@ {"name":"android.app.js","url":"app.js"}, {"name":"android.settings.js","url":"settings.js"}, {"name":"android.img","url":"app-icon.js","evaluate":true}, - {"name":"android.boot.js","url":"boot.js"} + {"name":"android.boot.js","url":"boot.js"}, + {"name":"android","url":"lib.js"} ], "data": [{"name":"android.settings.json"}, {"name":"android.calendar.json"}, {"name":"android.cards.json"}], "sortorder": -8 From 527a3c10b8048af4b674b1778edde35cc9cb5d25 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 25 Oct 2024 09:36:23 +0100 Subject: [PATCH 06/63] tidying up time_utils to make it faster and pretokenise better --- modules/time_utils.js | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/modules/time_utils.js b/modules/time_utils.js index 6a3ed6faff0..0f503ad3758 100644 --- a/modules/time_utils.js +++ b/modules/time_utils.js @@ -13,18 +13,13 @@ // Note that if a field is undefined then its value is zero. // -const ONE_SECOND = 1000; -const ONE_MINUTE = 60 * ONE_SECOND; -const ONE_HOUR = 60 * ONE_MINUTE; -const ONE_DAY = 24 * ONE_HOUR; - /** * @param {object} time {d, h, m, s} * @returns the milliseconds contained in the passed time object */ exports.encodeTime = (time) => { time = safeTime(time); - return time.d * ONE_DAY + time.h * ONE_HOUR + time.m * ONE_MINUTE + time.s * ONE_SECOND; + return time.d * 86400000 + time.h * 3600000 + time.m * 60000 + time.s * 1000; } // internal use, set to zero all the undefined fields @@ -38,26 +33,26 @@ function safeTime(time) { */ exports.decodeTime = (millis) => { if (typeof millis !== "number") throw "Only a number can be decoded"; - var d = Math.floor(millis / ONE_DAY); - millis -= d * ONE_DAY; - var h = Math.floor(millis / ONE_HOUR); - millis -= h * ONE_HOUR; - var m = Math.floor(millis / ONE_MINUTE); - millis -= m * ONE_MINUTE; - var s = Math.floor(millis / ONE_SECOND); + var d = Math.floor(millis / 86400000); + millis -= d * 86400000; + var h = Math.floor(millis / 3600000); + millis -= h * 3600000; + var m = Math.floor(millis / 60000); + millis -= m * 60000; + var s = Math.floor(millis / 1000); return { d: d, h: h, m: m, s: s }; } -/** +/** * @param {object|int} value {h, m} object or milliseconds * @returns an human-readable time string like "10:25" * @throws an exception if d != 0 or h > 23 or m > 59 */ exports.formatTime = (value) => { var time = safeTime(typeof value === "object" ? value : exports.decodeTime(value)); - if (time.d != 0) throw "days not supported here"; - if (time.h < 0 || time.h > 23) throw "Invalid value: must be 0 <= h <= 23"; - if (time.m < 0 || time.m > 59) throw "Invalid value: must be 0 <= m <= 59"; + time.h += time.d*24; + /*if (time.h < 0 || time.h > 23) throw "Invalid value: must be 0 <= h <= 23"; + if (time.m < 0 || time.m > 59) throw "Invalid value: must be 0 <= m <= 59";*/ return time.h + ":" + ("0" + time.m).substr(-2); } From e00cba4094d71ea564630cd270ba6eb083a0a935 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 25 Oct 2024 09:36:51 +0100 Subject: [PATCH 07/63] sched 0.29: Improve clkinfo startup time by 10ms --- apps/sched/ChangeLog | 1 + apps/sched/clkinfo.js | 45 ++++++++++++++++------------------------ apps/sched/lib.js | 1 + apps/sched/metadata.json | 2 +- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog index 2ecbb9a943b..83eb2ca20c8 100644 --- a/apps/sched/ChangeLog +++ b/apps/sched/ChangeLog @@ -29,3 +29,4 @@ 0.26: Fix hitting snooze on an alarm after when the snooze would've fired 0.27: Tapping clkinfo enables/disables the selected alarm 0.28: Added an icon for disabled events +0.29: Improve clkinfo startup time by 10ms \ No newline at end of file diff --git a/apps/sched/clkinfo.js b/apps/sched/clkinfo.js index 73ba4a259dc..8d4d747c0ce 100644 --- a/apps/sched/clkinfo.js +++ b/apps/sched/clkinfo.js @@ -1,15 +1,7 @@ (function() { - const alarm = require('sched'); - const iconAlarmOn = atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/n+B/n+B/h+B/4+A/+8A//8Af/4AP/wAH/gAB+AAAAAAAAAA=="); - const iconAlarmOff = atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/nAB/mAB/geB/5/g/5tg/zAwfzhwPzhwHzAwB5tgAB/gAAeA=="); - const iconTimerOn = atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADnAADDAAGBgAGBgAGBgAf/4Af/4AAAAAAAAAAAAA=="); - const iconTimerOff = atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADkeADB/gGBtgGDAwGDhwfzhwfzAwABtgAB/gAAeA=="); - const iconEventOn = atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B/++B/8+B/5+B8z+B+H+B/P+B//+B//+B//+A//8AAAAAAAAAAAAA=="); - const iconEventOff = atob("GBgBAAAAAAAAAAAAD//wH//4GAAYGAAYGAAYH//4H//4H//4H/74H/wAH/gAHzB4H4H+H8m2H/MDH/OHH/OHD/MDAAG2AAH+AAB4"); - //from 0 to max, the higher the closer to fire (as in a progress bar) - function getAlarmValue(a){ - let min = Math.round(alarm.getTimeToAlarm(a)/(60*1000)); + function getAlarmValue(a) { + let min = Math.round(require('sched').getTimeToAlarm(a)/(60*1000)); if(!min) return 0; //not active or more than a day return getAlarmMax(a)-min; } @@ -23,20 +15,20 @@ function getAlarmIcon(a) { if(a.on) { - if(a.timer) return iconTimerOn; - if(a.date) return iconEventOn; - return iconAlarmOn; + if(a.timer) return atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADnAADDAAGBgAGBgAGBgAf/4Af/4AAAAAAAAAAAAA=="); + if(a.date) return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B/++B/8+B/5+B8z+B+H+B/P+B//+B//+B//+A//8AAAAAAAAAAAAA=="); + return atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/n+B/n+B/h+B/4+A/+8A//8Af/4AP/wAH/gAB+AAAAAAAAAA=="); } else { - if(a.timer) return iconTimerOff; - if(a.date) return iconEventOff; - return iconAlarmOff; + if(a.timer) return atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADkeADB/gGBtgGDAwGDhwfzhwfzAwABtgAB/gAAeA=="); + if(a.date) return atob("GBgBAAAAAAAAAAAAD//wH//4GAAYGAAYGAAYH//4H//4H//4H/74H/wAH/gAHzB4H4H+H8m2H/MDH/OHH/OHD/MDAAG2AAH+AAB4"); + return atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/nAB/mAB/geB/5/g/5tg/zAwfzhwPzhwHzAwB5tgAB/gAAeA=="); } } function getAlarmText(a){ if(a.timer) { if(!a.on) return /*LANG*/"off"; - let time = Math.round(alarm.getTimeToAlarm(a)/(60*1000)); + let time = Math.round(require('sched').getTimeToAlarm(a)/(60*1000)); if(time > 60) time = Math.round(time / 60) + "h"; else @@ -52,7 +44,7 @@ //workaround for sorting undefined values function getAlarmOrder(a) { - let val = alarm.getTimeToAlarm(a); + let val = require('sched').getTimeToAlarm(a); if(typeof val == "undefined") return 86400*1000; return val; } @@ -66,7 +58,7 @@ const minute = 60 * 1000; const halfhour = 30 * minute; const hour = 2 * halfhour; - let msecs = alarm.getTimeToAlarm(a); + let msecs = require('sched').getTimeToAlarm(a); if(typeof msecs == "undefined" || msecs == 0) return []; if(msecs > hour) { //refresh every half an hour @@ -103,15 +95,15 @@ }, switchTimeout); } - var img = iconAlarmOn; - var all = alarm.getAlarms(); + // read the file direct here to avoid loading sched library (saves 10ms!) + var all = /*require('sched').getAlarms()*/require("Storage").readJSON("sched.json",1)||[]; //get only alarms not created by other apps var alarmItems = { name: /*LANG*/"Alarms", - img: img, + img: getAlarmIcon({on:1}), dynamic: true, items: all.filter(a=>!a.appid) - //.sort((a,b)=>alarm.getTimeToAlarm(a)-alarm.getTimeToAlarm(b)) + //.sort((a,b)=>require('sched').getTimeToAlarm(a)-require('sched').getTimeToAlarm(b)) .sort((a,b)=>getAlarmOrder(a)-getAlarmOrder(b)) .map(a => ({ name: null, @@ -135,13 +127,12 @@ run: function() { if (a.date) return; // ignore events a.on = !a.on; - if(a.on && a.timer) alarm.resetTimer(a); + if(a.on && a.timer) require('sched').resetTimer(a); this.emit("redraw"); - alarm.setAlarms(all); - alarm.reload(); // schedule/unschedule the alarm + require('sched').setAlarms(all); + require('sched').reload(); // schedule/unschedule the alarm } })), }; - return alarmItems; }) diff --git a/apps/sched/lib.js b/apps/sched/lib.js index fcd971fc43f..e11448a1845 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -1,5 +1,6 @@ // Return an array of all alarms exports.getAlarms = function() { + // we do this direct in clkinfo.js to avoid loading the library return require("Storage").readJSON("sched.json",1)||[]; }; // Write a list of alarms back to storage diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index 4141c779767..274b83d146c 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -1,7 +1,7 @@ { "id": "sched", "name": "Scheduler", - "version": "0.28", + "version": "0.29", "description": "Scheduling library for alarms and timers", "icon": "app.png", "type": "scheduler", From 4ff01d1db0cd7d21ca631393e16273ac2ab13fb7 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 25 Oct 2024 09:37:43 +0100 Subject: [PATCH 08/63] widmessages 0.07: Only load messages module if we have messages (30ms speed improvement) --- apps/widmessages/ChangeLog | 3 ++- apps/widmessages/metadata.json | 2 +- apps/widmessages/widget.js | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/widmessages/ChangeLog b/apps/widmessages/ChangeLog index 314b1490c62..35bde7bbd46 100644 --- a/apps/widmessages/ChangeLog +++ b/apps/widmessages/ChangeLog @@ -4,4 +4,5 @@ 0.03: Fix messages not showing if UI auto-open is disabled 0.04: Now shows message icons again (#2416) 0.05: Match draw() API e.g. to allow wid_edit to alter this widget -0.06: Fix bug that meant that only one widget was shown (now 3 unless changed in Settings->Apps->Messages->Widget messages) \ No newline at end of file +0.06: Fix bug that meant that only one widget was shown (now 3 unless changed in Settings->Apps->Messages->Widget messages) +0.07: Only load messages module if we have messages (30ms speed improvement) \ No newline at end of file diff --git a/apps/widmessages/metadata.json b/apps/widmessages/metadata.json index 436b77d3e3a..95a34e8928f 100644 --- a/apps/widmessages/metadata.json +++ b/apps/widmessages/metadata.json @@ -1,7 +1,7 @@ { "id": "widmessages", "name": "Message Widget", - "version": "0.06", + "version": "0.07", "description": "Widget showing new messages", "icon": "app.png", "type": "widget", diff --git a/apps/widmessages/widget.js b/apps/widmessages/widget.js index 0351fbead71..3212ee64948 100644 --- a/apps/widmessages/widget.js +++ b/apps/widmessages/widget.js @@ -65,7 +65,7 @@ if ((require("Storage").readJSON("messages.settings.json", true) || {}).maxMessa this.onMsg("show", {}); // reload messages+redraw } }; - Bangle.on("message", WIDGETS["messages"].onMsg.bind(WIDGETS["messages"])); - WIDGETS["messages"].onMsg("init", {}); // abuse type="init" to prevent Bangle.drawWidgets(); + if (require("Storage").read("messages.json")!==undefined) // only call init if we've got messages - otherwise we can avoid loading messages lib (saves 30ms) + WIDGETS["messages"].onMsg("init", {}); // abuse type="init" to prevent Bangle.drawWidgets(); } \ No newline at end of file From 242eda245b4a3de72ef18482a5256a41bd95debf Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 25 Oct 2024 09:38:00 +0100 Subject: [PATCH 09/63] clockbg 0.06: 25% speed improvement if Math.randInt exists (2v25 fw) --- apps/clockbg/ChangeLog | 3 ++- apps/clockbg/lib.js | 8 ++++++-- apps/clockbg/metadata.json | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/clockbg/ChangeLog b/apps/clockbg/ChangeLog index 3c681a6388f..a370befc096 100644 --- a/apps/clockbg/ChangeLog +++ b/apps/clockbg/ChangeLog @@ -4,4 +4,5 @@ 0.04: More options for different background colors 'Plasma' generative background Add a 'view' option in settings menu to view the current background -0.05: Random square+plasma speed improvements (~2x faster) \ No newline at end of file +0.05: Random square+plasma speed improvements (~2x faster) +0.06: 25% speed improvement if Math.randInt exists (2v25 fw) \ No newline at end of file diff --git a/apps/clockbg/lib.js b/apps/clockbg/lib.js index 59345340fd7..256f2f37243 100644 --- a/apps/clockbg/lib.js +++ b/apps/clockbg/lib.js @@ -1,6 +1,7 @@ let settings; exports.reload = function() { + //let t = Date.now(); settings = Object.assign({ style : "randomcolor", colors : ["#F00","#0F0","#00F"] @@ -17,7 +18,8 @@ exports.reload = function() { let bpp = (settings.colors.length>4)?4:2; let bg = Graphics.createArrayBuffer(11,11,bpp,{msb:true}); let u32 = new Uint32Array(bg.buffer); // faster to do 1/4 of the ops of E.mapInPlace(bg.buffer, bg.buffer, ()=>Math.random()*256); - E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels + if (Math.randInt) E.mapInPlace(u32, u32, Math.randInt); // random pixels + else E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels bg.buffer[bg.buffer.length-1]=Math.random()*256; // 11x11 isn't a multiple of 4 bytes - we need to set the last one! bg.palette = new Uint16Array(1<g.toColor(c))); @@ -28,7 +30,8 @@ exports.reload = function() { settings.style = "image"; let bg = Graphics.createArrayBuffer(16,16,4,{msb:true}); let u32 = new Uint32Array(bg.buffer); // faster to do 1/4 of the ops of E.mapInPlace(bg.buffer, bg.buffer, ()=>Math.random()*256); - E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels + if (Math.randInt) E.mapInPlace(u32, u32, Math.randInt); // random pixels + else E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels bg.filter([ // a gaussian filter to smooth out 1, 4, 7, 4, 1, 4,16,26,16, 4, @@ -42,6 +45,7 @@ exports.reload = function() { settings.imgOpt = {scale:11}; delete settings.colors; } + //console.log("bg",Date.now()-t); }; exports.reload(); diff --git a/apps/clockbg/metadata.json b/apps/clockbg/metadata.json index 85b1f8a5a1d..ba6fb6712f5 100644 --- a/apps/clockbg/metadata.json +++ b/apps/clockbg/metadata.json @@ -1,7 +1,7 @@ { "id": "clockbg", "name": "Clock Backgrounds", "shortName":"Backgrounds", - "version": "0.05", + "version": "0.06", "description": "Library that allows clocks to include a custom background (generated on demand or uploaded).", "icon": "app.png", "screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"}], From f7381a7d31457d3d75a837711a693a4e1f00ab52 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 25 Oct 2024 09:39:45 +0100 Subject: [PATCH 10/63] boot 0.65: Only display interpreter errors if log is nonzero --- apps/boot/ChangeLog | 3 ++- apps/boot/bootupdate.js | 28 ++++++++++------------------ apps/boot/metadata.json | 2 +- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index dd47229f7a5..5b0fcc58307 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -74,4 +74,5 @@ 0.63: Only set BLE `display:1` if we have a passkey 0.64: Automatically create .widcache and .clkinfocache to speed up loads Bangle.loadWidgets overwritten with fast version on success - Refuse to work on firmware <2v16 and remove old polyfills \ No newline at end of file + Refuse to work on firmware <2v16 and remove old polyfills +0.65: Only display interpreter errors if log is nonzero \ No newline at end of file diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index a10a0cb150d..07d8d2031e7 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -66,12 +66,12 @@ if (s.ble===false) boot += `if (!NRF.getSecurityStatus().connected) NRF.sleep(); if (s.timeout!==undefined) boot += `Bangle.setLCDTimeout(${s.timeout});\n`; if (!s.timeout) boot += `Bangle.setLCDPower(1);\n`; boot += `E.setTimeZone(${s.timezone});`; -// Draw out of memory errors onto the screen -boot += `E.on('errorFlag', function(errorFlags) { +// Draw out of memory errors onto the screen if logging enabled +if (s.log) boot += `E.on('errorFlag', function(errorFlags) { g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); print("Interpreter error:", errorFlags); - E.getErrorFlags(); // clear flags so we get called next time -});\n`; + E.getErrorFlags(); +});\n`;// E.getErrorFlags() -> clear flags so we get called next time // stop users doing bad things! if (global.save) boot += `global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); }\n`; // Apply any settings-specific stuff @@ -93,7 +93,6 @@ delete Bangle.showClock; if (!Bangle.showClock) boot += `Bangle.showClock = ()=>{load(".bootcde")};\n`; delete Bangle.load; if (!Bangle.load) boot += `Bangle.load = load;\n`; -let date = new Date(); // show timings if (DEBUG) boot += `print(".boot0",0|(Date.now()-_tm),"ms");_tm=Date.now();\n` @@ -118,7 +117,7 @@ let bootFiles = require('Storage').list(/\.boot\.js$/).sort((a,b)=>{ bootPost += "}"; let fileOffset,fileSize; /* code to output a file, plus preable and postable -when called with dst==undefined it just increments +when called with dst==undefined it just increments fileOffset so we can see ho wbig the file has to be */ let outputFile = (dst,src,pre,post) => {"ram"; if (DEBUG) { @@ -163,14 +162,14 @@ let outputFileComplete = (dst,fn) => { // we write: // "//"+bootFile+"\n"+require('Storage').read(bootFile)+";\n"; // but we need to do this without ever loading everything into RAM as some - // boot files seem to be getting pretty big now. + // boot files seem to be getting pretty big now. outputFile(dst,fn,"",";\n"); }; fileOffset = boot.length + bootPost.length; bootFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes fileSize = fileOffset; require('Storage').write('.boot0',boot,0,fileSize); -fileOffset = boot.length; +fileOffset = boot.length; bootFiles.forEach(fn=>outputFileComplete('.boot0',fn)); require('Storage').write('.boot0',bootPost,fileOffset); delete boot,bootPost,bootFiles; @@ -186,7 +185,7 @@ fileOffset = widget.length + widgetPost.length; widgetFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes fileSize = fileOffset; require('Storage').write('.widcache',widget,0,fileSize); -fileOffset = widget.length; +fileOffset = widget.length; widgetFiles.forEach(fn=>outputFileComplete('.widcache',fn)); require('Storage').write('.widcache',widgetPost,fileOffset); delete widget,widgetPost,widgetFiles; @@ -196,12 +195,12 @@ let ci = `// Made by bootupdate.js\n`; if (DEBUG) ci+="var _tm=Date.now();"; outputFileComplete = (dst,fn) => { outputFile(dst,fn,"try{let fn=",`;let a=fn(),b=menu.find(x=>x.name===a.name);if(b)b.items=b.items.concat(a.items)else menu=menu.concat(a);}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`); -}; +}; fileOffset = ci.length; ciFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes fileSize = fileOffset; require('Storage').write('.clkinfocache',ci,0,fileSize); -fileOffset = ci.length; +fileOffset = ci.length; ciFiles.forEach(fn=>outputFileComplete('.clkinfocache',fn)); delete ci,ciFiles; // test with require("clock_info").load() @@ -211,10 +210,3 @@ E.showMessage(/*LANG*/"Reloading..."); // .bootcde should be run automatically after if required, since // we normally get called automatically from '.boot0' eval(require('Storage').read('.boot0')); -/* -f = require("Storage").read("sched.clkinfo.js") -if (f.startsWith("Modules.addCached")) { - -} - -*/ \ No newline at end of file diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index c71de37c78e..afe576e71cc 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -1,7 +1,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.64", + "version": "0.65", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", From feb5f6213befe330294b1ff763e0b5fc510e800f Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 25 Oct 2024 19:28:16 +0200 Subject: [PATCH 11/63] trail: Disable demo/debugging hacks. --- apps/trail/trail.app.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/trail/trail.app.js b/apps/trail/trail.app.js index aa06d9e1d50..601a9f08910 100644 --- a/apps/trail/trail.app.js +++ b/apps/trail/trail.app.js @@ -134,7 +134,6 @@ let gps = { init: function(x) { this.emulator = (process.env.BOARD=="EMSCRIPTEN" || process.env.BOARD=="EMSCRIPTEN2")?1:0; - this.emulator = 1; // FIXME }, state: {}, on_gps: function(f) { @@ -602,7 +601,7 @@ function step_to(pp, pass_all) { return quiet; } -var demo_mode = 0; //fixme +var demo_mode = 0; function step() { const fast = 0; @@ -666,7 +665,7 @@ function step() { drop_last(); let v2 = getTime(); print("Step took", (v2-v1), "seconds"); - setTimeout(step, 10); /* FIXME! */ + setTimeout(step, 1000); } function recover() { From e7392aca3d4370ef980dd0ceb1315ed02426e412 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 25 Oct 2024 20:15:55 +0200 Subject: [PATCH 12/63] trail: mark this as 0.11 --- apps/trail/ChangeLog | 1 + apps/trail/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/trail/ChangeLog b/apps/trail/ChangeLog index 097869de39f..ae1c44012c1 100644 --- a/apps/trail/ChangeLog +++ b/apps/trail/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.10: Redesign to make screen updates fast +0.11: bugfix (demo mode was enabled by default) diff --git a/apps/trail/metadata.json b/apps/trail/metadata.json index 3cb9672c7fe..0981d6dbe26 100644 --- a/apps/trail/metadata.json +++ b/apps/trail/metadata.json @@ -1,6 +1,6 @@ { "id": "trail", "name": "Trail Rail", - "version":"0.10", + "version":"0.11", "description": "Follow a GPX track in car or on bike", "icon": "app.png", "readme": "README.md", From 6c050b5107c4987df9aa61e961cf92fe78ea5bf6 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 11:47:52 +0000 Subject: [PATCH 13/63] hworldclock 0.37: Fix settings (show default as '90' not 'off') --- apps/hworldclock/ChangeLog | 1 + apps/hworldclock/metadata.json | 2 +- apps/hworldclock/settings.js | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/hworldclock/ChangeLog b/apps/hworldclock/ChangeLog index 42e785b0abe..ad327831a60 100644 --- a/apps/hworldclock/ChangeLog +++ b/apps/hworldclock/ChangeLog @@ -21,3 +21,4 @@ 0.34: Fix 'fast load' so clock doesn't always redraw when screen unlocked/locked 0.35: Minor code improvements 0.36: Minor code improvements +0.37: Fix settings (show default as '90' not 'off') \ No newline at end of file diff --git a/apps/hworldclock/metadata.json b/apps/hworldclock/metadata.json index 422ef6b89c1..aeae2d254b7 100644 --- a/apps/hworldclock/metadata.json +++ b/apps/hworldclock/metadata.json @@ -2,7 +2,7 @@ "id": "hworldclock", "name": "Hanks World Clock", "shortName": "Hanks World Clock", - "version": "0.36", + "version": "0.37", "description": "Current time zone plus up to three others", "allow_emulator":true, "icon": "app.png", diff --git a/apps/hworldclock/settings.js b/apps/hworldclock/settings.js index 98b91dc7bb9..457bc47b3ad 100644 --- a/apps/hworldclock/settings.js +++ b/apps/hworldclock/settings.js @@ -2,6 +2,7 @@ var FILE = "hworldclock.json"; var settings = Object.assign({ secondsOnUnlock: false, + rotationTarget: "90", }, require('Storage').readJSON(FILE, true) || {}); function writeSettings() { @@ -55,4 +56,4 @@ E.showMenu(mainmenu); -}); +}) \ No newline at end of file From f73b02deaf371704f83b6a730e447000abd865fa Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 12:21:08 +0000 Subject: [PATCH 14/63] assistengps 0.07: Bangle.js 2 now gets estimated time + lat/lon from the browser (~3x faster fix) --- apps/assistedgps/ChangeLog | 3 +- apps/assistedgps/custom.html | 78 +++++++++++++++++++++++++++++++--- apps/assistedgps/metadata.json | 2 +- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/apps/assistedgps/ChangeLog b/apps/assistedgps/ChangeLog index 13f928f1894..89b1c80f855 100644 --- a/apps/assistedgps/ChangeLog +++ b/apps/assistedgps/ChangeLog @@ -3,4 +3,5 @@ 0.03: Select GNSS systems to use for Bangle.js 2 0.04: Now turns GPS off after upload 0.05: Fix regression in 0.04 that caused AGPS data not to get loaded -0.06: Auto-set GPS output sentences - newer Bangle.js 2 don't include RMC (GPS direction + time) by default \ No newline at end of file +0.06: Auto-set GPS output sentences - newer Bangle.js 2 don't include RMC (GPS direction + time) by default +0.07: Bangle.js 2 now gets estimated time + lat/lon from the browser (~3x faster fix) \ No newline at end of file diff --git a/apps/assistedgps/custom.html b/apps/assistedgps/custom.html index 994f6d053c1..a5121934618 100644 --- a/apps/assistedgps/custom.html +++ b/apps/assistedgps/custom.html @@ -60,6 +60,7 @@

Assisted GPS

diff --git a/apps/assistedgps/metadata.json b/apps/assistedgps/metadata.json index 8d4e07fa3a6..73f775a7246 100644 --- a/apps/assistedgps/metadata.json +++ b/apps/assistedgps/metadata.json @@ -2,7 +2,7 @@ "id": "assistedgps", "name": "Assisted GPS Updater (AGPS)", "shortName": "AGPS", - "version": "0.06", + "version": "0.07", "description": "Downloads assisted GPS (AGPS) data to Bangle.js for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", "sortorder": -1, "icon": "app.png", From a22640632ecd88a958eed393b00df49637bcddec Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 12:22:00 +0000 Subject: [PATCH 15/63] minor core tweaks --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 97ba43366ea..cbf53ec34fe 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 97ba43366eaded3dc6db00229825063f8c95382a +Subproject commit cbf53ec34fee9b7d9234a7bbfc276592d9e076a5 From e7bfc18e70262ab7aab8beedbd6de4a097ab2230 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 16:02:40 +0000 Subject: [PATCH 16/63] add sanity check for setting/clockinfo that end in a semicolon --- bin/sanitycheck.js | 48 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 82856b639d2..0df4625f523 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -5,6 +5,12 @@ var fs = require("fs"); var vm = require("vm"); var heatshrink = require("../webtools/heatshrink"); +/*var apploader = require("../core/lib/apploader.js"); +apploader.init({ + DEVICEID : "BANGLEJS2" +});*/ + + var acorn; try { acorn = require("acorn"); @@ -181,6 +187,7 @@ const isGlob = f => /[?*]/.test(f) // All storage+data files in all apps: {app:,[file: | data:]} let allFiles = []; let existingApps = []; +let promise = Promise.resolve(); apps.forEach((app,appIdx) => { if (!app.id) ERROR(`App ${appIdx} has no id`); var appDirRelative = APPSDIR_RELATIVE+app.id+"/"; @@ -306,8 +313,9 @@ apps.forEach((app,appIdx) => { } if (file.name.endsWith(".js")) { // TODO: actual lint? + var ast; try { - acorn.parse(fileContents); + ast = acorn.parse(fileContents); } catch(e) { console.log("====================================================="); console.log(" PARSE OF "+appDir+file.url+" failed."); @@ -337,6 +345,12 @@ apps.forEach((app,appIdx) => { WARN(`Settings for ${app.id} has a boolean formatter - this is handled automatically, the line can be removed`, {file:appDirRelative+file.url, line: fileContents.substr(0, m.index).split("\n").length}); } } + // something that needs to be evaluated with 'eval(require("Storage").read(fn))' + if (/\.clkinfo?\.js$/.test(file.name) || + /\.settings?\.js$/.test(file.name)) { + if (!fileContents.trim().endsWith(")")) + WARN(`App ${app.id} file ${file.name} should be evaluated as a function but doesn't end in ')'`, {file:appDirRelative+file.url}); + } } for (const key in file) { if (!STORAGE_KEYS.includes(key)) ERROR(`App ${app.id} file ${file.name} has unknown key ${key}`, {file:appDirRelative+file.url}); @@ -436,6 +450,18 @@ apps.forEach((app,appIdx) => { ERROR(`App ${app.id} has provides_modules ${modulename} but it doesn't provide that filename`, {file:metadataFile}); }); } + /* + // We could try to create the files we need to upload for this app to check it all works ok... + promise = promise.then(() => apploader.getAppFiles(app).then(files => { + files.forEach(file => { + if (/\.clkinfo?\.js$/.test(file.name) || + /\.settings?\.js$/.test(file.name)) { + if (!file.content.startsWith("(")) { + ERROR(`App ${app.id} file ${file.name} should evaluate to a simple fn and doesn't (starts: ${JSON.stringify(file.content.substr(0,30))})`, {file:appDirRelative+file.url}); + } + } + }); + }));*/ }); @@ -481,12 +507,14 @@ function sanityCheckLocales(){ } } -console.log("=================================="); -console.log(`${errorCount} errors, ${warningCount} warnings (and ${knownErrorCount} known errors, ${knownWarningCount} known warnings)`); -console.log("=================================="); -if (errorCount) { - process.exit(1); -} else if ("CI" in process.env && warningCount) { - console.log("Running in CI, raising an error from warnings"); - process.exit(1); -} +promise.then(function() { + console.log("=================================="); + console.log(`${errorCount} errors, ${warningCount} warnings (and ${knownErrorCount} known errors, ${knownWarningCount} known warnings)`); + console.log("=================================="); + if (errorCount) { + process.exit(1); + } else if ("CI" in process.env && warningCount) { + console.log("Running in CI, raising an error from warnings"); + process.exit(1); + } +}); From cd340ed83ff0fd956c76675c751567f756c6cfdb Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 16:34:26 +0000 Subject: [PATCH 17/63] Add meridians to try and get rid of some errors, and some context for some locale errors. --- apps/locale/locales.js | 38 ++++++++--------- apps/locale/sanitycheck.js | 39 ++++++++++------- bin/sanitycheck.js | 86 +++++++++++++++++++------------------- 3 files changed, 86 insertions(+), 77 deletions(-) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 7e4105f3d1c..c704e0f9043 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -177,7 +177,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mär 2020 // 01.03.20 abmonth: "Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", @@ -194,7 +194,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%Y/%m/%d", 1: "%y/%m/%d" }, abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", @@ -210,7 +210,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d %b %Y", 1: "%d-%m-%Y" }, // 28 feb 2020 // 28-02-2020 abday: "zo,ma,di,wo,do,vr,za", @@ -258,7 +258,7 @@ var locales = { speed: "km/h", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d %B %Y", "1": "%d/%m/%Y" }, // 1 mars 2020 // 01/03/2020 abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc", @@ -290,7 +290,7 @@ var locales = { speed: 'km/h', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%B %d %Y", "1": "%Y-%m-%d" }, // March 1 2020 // 2020-03-01 abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", @@ -306,7 +306,7 @@ var locales = { speed: "km/t", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b. %Y", 1: "%d/%m %Y" }, // 1. feb. 2020 // 01/02 2020 // a better short ver. is 1/2 2020 but its not supported abmonth: "jan,feb,mar,apr,maj,jun,jul,aug,sep,okt,nov,dec", @@ -322,7 +322,7 @@ var locales = { speed: "km/h", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b. %Y", 1: "%d/%m %Y" }, // 1. feb. 2020 // 01/02 2020 // a better short ver. is 1/2 2020 but its not supported abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", @@ -370,7 +370,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%y" }, // Sonntag, 1. März 2020 // 01.03.20 abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", @@ -403,7 +403,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A, %d de %B de %Y", "1": "%d/%m/%y" }, // domingo, 1 de marzo de 2020 // 01/03/20 abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic", @@ -420,7 +420,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 abmonth: "janv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", @@ -484,7 +484,7 @@ var locales = { speed: 'kmh', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM.%SS", 1: "%HH:%MM" }, // 17:00.00 // 17:00 datePattern: { 0: "%d %b %Y", "1": "%d/%m/%Y" }, // 1 marzo 2020 // 01/03/2020 abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", @@ -500,7 +500,7 @@ var locales = { speed: 'kmh', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM.%SS", 1: "%HH:%MM" }, // 17:00.00 // 17:00 datePattern: { 0: "%d %b %Y", "1": "%d/%m/%Y" }, // 1 marzo 2020 // 01/03/2020 abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", @@ -516,7 +516,7 @@ var locales = { speed: 'kmh', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH.%MM.%SS", 1: "%HH.%MM" }, // 17.00.00 // 17.00 datePattern: { 0: "%A, %d. %B %Y", "1": "%Y-%m-%d" }, // Sunntag, 1. Märze 2020 // 2020-03-01 abmonth: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr", @@ -564,7 +564,7 @@ var locales = { speed: "km/h", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A %d %B de %Y", "1": "%d/%m/%Y" }, // dimenge 1 de març de 2020 // 01/03/2020 abmonth: "gen.,febr.,març,abril,mai,junh,julh,ago.,set.,oct.,nov.,dec.", @@ -660,7 +660,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2021 // 01.03.2021 abmonth: "Sty,Lut,Mar,Kwi,Maj,Cze,Lip,Sie,Wrz,Paź,Lis,Gru", @@ -676,7 +676,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20 abmonth: "Jan,Feb,Mar,Apr,Mai,Jūn,Jūl,Aug,Sep,Okt,Nov,Dec", @@ -692,7 +692,7 @@ var locales = { speed: "kmt", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20 abmonth: "Jan,Feb,Mar,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Des", @@ -708,7 +708,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20 abmonth: "Jan,Feb,Mar,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Des", @@ -725,7 +725,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d %B %Y", "1": "%d/%m/%y" }, abmonth: "gen.,febr.,març,abr.,maig,juny,jul.,ag.,set.,oct.,nov.,des.", diff --git a/apps/locale/sanitycheck.js b/apps/locale/sanitycheck.js index 06c7ad3d684..ceca89b8d9d 100644 --- a/apps/locale/sanitycheck.js +++ b/apps/locale/sanitycheck.js @@ -4,15 +4,15 @@ */ const datetime_length_map = { // %A, %a, %B, %b vary depending on the locale, so they are calculated later - "%Y": [4, 4], - "%y": [2, 2], - "%m": [2, 2], - "%-m": [1, 2], - "%d": [2, 2], - "%-d": [1, 2], - "%HH": [2, 2], - "%MM": [2, 2], - "%SS": [2, 2], + "%Y": [4, 4, "2024", "2024"], + "%y": [2, 2, "24", "24"], + "%m": [2, 2, "10", "10"], + "%-m": [1, 2, "1", "10"], + "%d": [2, 2, "10", "10"], + "%-d": [1, 2, "1", "10"], + "%HH": [2, 2, "10", "10"], + "%MM": [2, 2, "10", "10"], + "%SS": [2, 2, "10", "10"], }; /** @@ -30,20 +30,21 @@ function getLengthOfDatetimeFormat(name, datetimeEspruino, locale, errors) { ["%a", locale.abday], ["%B", locale.month], ["%b", locale.abmonth], - ]){ + ]) { const length = [Infinity, 0]; for(const value of values.split(",")){ - if(length[0] > value.length) length[0] = value.length; - if(length[1] < value.length) length[1] = value.length; + if(length[0] > value.length) { length[0] = value.length; length[2] = value; } + if(length[1] < value.length) { length[1] = value.length; length[3] = value; } } length_map[symbol] = length; } // Find the length of the output - let formatLength = [0, 0]; + let formatLength = [0, 0, "", ""]; let i = 0; while (i < datetimeEspruino.length) { - if (datetimeEspruino[i] === "%") { + let ch = datetimeEspruino[i]; + if (ch === "%") { let match; for(const symbolLength of [2, 3]){ const length = length_map[datetimeEspruino.substring(i, i+symbolLength)]; @@ -57,16 +58,22 @@ function getLengthOfDatetimeFormat(name, datetimeEspruino, locale, errors) { if(match){ formatLength[0] += match.length[0]; formatLength[1] += match.length[1]; + formatLength[2] += match.length[2]; + formatLength[3] += match.length[3]; i += match.symbolLength; }else{ errors.push({name, value: datetimeEspruino, lang: locale.lang, error: `uses an unsupported format symbol: ${datetimeEspruino.substring(i, i+3)}`}); formatLength[0]++; formatLength[1]++; + formatLength[2]+=" "; + formatLength[3]+=" "; i++; } } else { formatLength[0]++; formatLength[1]++; + formatLength[2]+=ch; + formatLength[3]+=ch; i++; } } @@ -154,10 +161,10 @@ function checkLocale(locale, {speedUnits, distanceUnits, codePages, CODEPAGE_CON function checkFormatLength(name, value, min, max) { const length = getLengthOfDatetimeFormat(name, value, locale, errors); if (min && length[0] < min) { - errors.push({name, value, lang: locale.lang, error: `output must be longer than ${min-1} characters`}); + errors.push({name, value, lang: locale.lang, error: `output must be longer than ${min-1} characters (${length[2]} -> ${length[0]})`}); } if (max && length[1] > max) { - errors.push({name, value, lang: locale.lang, error: `output must be shorter than ${max+1} characters`}); + errors.push({name, value, lang: locale.lang, error: `output must be shorter than ${max+1} characters (${length[3]} -> ${length[1]})`}); } } function checkIsIn(name, value, listName, list) { diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 0df4625f523..ec2644f6b78 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -54,54 +54,56 @@ function WARN(msg, opt) { } /* These are errors that we temporarily allow */ var KNOWN_ERRORS = [ - "In locale en_CA, long date output must be shorter than 15 characters", - "In locale fr_FR, long date output must be shorter than 15 characters", - "In locale en_SE, long date output must be shorter than 15 characters", - "In locale en_NZ, long date output must be shorter than 15 characters", - "In locale en_AU, long date output must be shorter than 15 characters", - "In locale de_AT, long date output must be shorter than 15 characters", - "In locale en_IL, long date output must be shorter than 15 characters", - "In locale es_ES, long date output must be shorter than 15 characters", - "In locale fr_BE, long date output must be shorter than 15 characters", - "In locale fi_FI, long date output must be shorter than 15 characters", - "In locale de_CH, long date output must be shorter than 15 characters", - "In locale fr_CH, long date output must be shorter than 15 characters", - "In locale wae_CH, long date output must be shorter than 15 characters", - "In locale tr_TR, long date output must be shorter than 15 characters", - "In locale hu_HU, long date output must be shorter than 15 characters", - "In locale oc_FR, long date output must be shorter than 15 characters", - "In locale ca_ES, long date output must be shorter than 15 characters", + "In locale en_CA, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale fr_FR, long date output must be shorter than 15 characters (10 septembre 2024 -> 17)", + "In locale fr_FR, short month must be shorter than 5 characters", + "In locale sv_SE, speed must be shorter than 5 characters", + "In locale en_SE, long date output must be shorter than 15 characters (September 10 2024 -> 17)", + "In locale en_NZ, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale en_AU, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale de_AT, long date output must be shorter than 15 characters (Donnerstag, 10. September 2024 -> 30)", + "In locale en_IL, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale es_ES, long date output must be shorter than 15 characters (miércoles, 10 de septiembre de 2024 -> 35)", + "In locale fr_BE, long date output must be shorter than 15 characters (dimanche septembre 10 2024 -> 26)", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fr_BE, short month must be shorter than 5 characters", "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fi_FI, long date output must be shorter than 15 characters (keskiviikkona 10. maaliskuuta 2024 -> 34)", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", "In locale fi_FI, short month must be shorter than 5 characters", + "In locale de_CH, meridian must be shorter than 4 characters", + "In locale de_CH, meridian must be shorter than 4 characters", + "In locale de_CH, long date output must be shorter than 15 characters (Donnerstag, 10. September 2024 -> 30)", + "In locale fr_CH, long date output must be shorter than 15 characters (dimanche 10 septembre 2024 -> 26)", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale fr_CH, short month must be shorter than 5 characters", "In locale fr_CH, short month must be shorter than 5 characters", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale wae_CH, long date output must be shorter than 15 characters (Sunntag, 10. Herbštmánet 2024 -> 29)", + "In locale tr_TR, long date output must be shorter than 15 characters (10 Haziran 2024 Pazartesi -> 25)", + "In locale hu_HU, long date output must be shorter than 15 characters (2024 Szep 10, Csütörtök -> 23)", + "In locale oc_FR, long date output must be shorter than 15 characters (divendres 10 setembre de 2024 -> 29)", + "In locale oc_FR, short month must be shorter than 5 characters", "In locale oc_FR, short month must be shorter than 5 characters", - "In locale hr_HR, short month must be shorter than 5 characters", - "In locale ca_ES, short month must be shorter than 5 characters", - "In locale de_DE, meridian must be longer than 0 characters", - "In locale en_JP, meridian must be longer than 0 characters", - "In locale nl_NL, meridian must be longer than 0 characters", - "In locale fr_FR, meridian must be longer than 0 characters", - "In locale se_SE, meridian must be longer than 0 characters", - "In locale en_SE, meridian must be longer than 0 characters", - "In locale da_DK, meridian must be longer than 0 characters", - "In locale en_DK, meridian must be longer than 0 characters", - "In locale de_AT, meridian must be longer than 0 characters", - "In locale es_ES, meridian must be longer than 0 characters", - "In locale fr_BE, meridian must be longer than 0 characters", - "In locale it_CH, meridian must be longer than 0 characters", - "In locale it_IT, meridian must be longer than 0 characters", - "In locale wae_CH, meridian must be longer than 0 characters", - "In locale oc_FR, meridian must be longer than 0 characters", - "In locale pl_PL, meridian must be longer than 0 characters", - "In locale lv_LV, meridian must be longer than 0 characters", - "In locale nn_NO, meridian must be longer than 0 characters", - "In locale nb_NO, meridian must be longer than 0 characters", - "In locale ca_ES, meridian must be longer than 0 characters", - "In locale de_CH, meridian must be shorter than 4 characters", "In locale hr_HR, meridian must be shorter than 4 characters", + "In locale hr_HR, meridian must be shorter than 4 characters", + "In locale hr_HR, short month must be shorter than 5 characters", "In locale sl_SI, meridian must be shorter than 4 characters", - "In locale fr_FR, short month must be shorter than 5 characters", - "In locale sv_SE, speed must be shorter than 5 characters", + "In locale sl_SI, meridian must be shorter than 4 characters", + "In locale ca_ES, long date output must be shorter than 15 characters (10 setembre 2024 -> 16)", + "In locale ca_ES, short month must be shorter than 5 characters", ]; /* These are warnings we know about but don't want in our output */ var KNOWN_WARNINGS = [ From 595e4a71ea73f475b5e07dc70c808a3de8bf1eaf Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 16:50:44 +0000 Subject: [PATCH 18/63] Fix Layout regression after https://github.com/espruino/BangleApps/commit/9c4cc9d58573e6e0fc2dbef3db507eb995bf76db fixes https://github.com/espruino/BangleApps/issues/3623 --- modules/Layout.js | 8 ++++---- modules/Layout.min.js | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 639173f4df2..5c66fc31308 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -235,7 +235,7 @@ Layout.prototype.forgetLazyState = function () { Layout.prototype.layout = function (l) { // l = current layout element - var cb = { + var floor = Math.floor, cb = { "h" : function(l) {"ram"; var acc_w = l.x + (0|l.pad), accfillx = 0, @@ -246,7 +246,7 @@ Layout.prototype.layout = function (l) { c.x = 0|x; acc_w += c._w; accfillx += 0|c.fillx; - x = acc_w + 0|(accfillx*(l.w-l._w)/fillx); + x = acc_w + floor(accfillx*(l.w-l._w)/fillx); c.w = 0|(x - c.x); c.h = 0|(c.filly ? l.h - (l.pad<<1) : c._h); c.y = 0|(l.y + (0|l.pad) + ((1+(0|c.valign))*(l.h-(l.pad<<1)-c.h)>>1)); @@ -263,7 +263,7 @@ Layout.prototype.layout = function (l) { c.y = 0|y; acc_h += c._h; accfilly += 0|c.filly; - y = acc_h + 0|(accfilly*(l.h-l._h)/filly); + y = acc_h + floor(accfilly*(l.h-l._h)/filly); c.h = 0|(y - c.y); c.w = 0|(c.fillx ? l.w - (l.pad<<1) : c._w); c.x = 0|(l.x + (0|l.pad) + ((1+(0|c.halign))*(l.w-(l.pad<<1)-c.w)>>1)); @@ -363,4 +363,4 @@ Layout.prototype.clear = function(l) { g.clearRect(l.x,l.y,l.x+l.w-1,l.y+l.h-1); }; -exports = Layout; \ No newline at end of file +exports = Layout; diff --git a/modules/Layout.min.js b/modules/Layout.min.js index 8dd7f8c87c4..4c64d078a7a 100644 --- a/modules/Layout.min.js +++ b/modules/Layout.min.js @@ -1,14 +1,14 @@ -function p(d,k){function c(f){"ram";f.id&&(l[f.id]=f);f.type||(f.type="");f.c&&f.c.forEach(c)}this._l=this.l=d;this.options=k||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let h;if(2!=process.env.HWVERSION){this.physBtns=3;h=[];function f(a){"ram";"btn"==a.type&&h.push(a);a.c&&a.c.forEach(f)}f(d);h.length&&(this.physBtns=0,this.buttons=h,this.selectedButton=-1)}if(this.options.btns)if(d=this.options.btns,this.physBtns>=d.length){this.b=d;let f=Math.floor(Bangle.appRect.h/ -this.physBtns);for(2d.length;)d.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:d.map(a=>(a.type="txt",a.font="6x8",a.height=f,a.r=1,a))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:d.map(f=>(f.type="btn",f.filly=1,f.width=32,f.r=1,f))}]},h&&h.push.apply(h,this._l.c[1].c);this.setUI();var l=this;c(this._l);this.updateNeeded=!0}function t(d, -k,c,h,l){var f=null==d.bgCol?l:g.toColor(d.bgCol);if(f!=l||"txt"==d.type||"btn"==d.type||"img"==d.type||"custom"==d.type){var a=d.c;delete d.c;var e="H"+E.CRC32(E.toJS(d));a&&(d.c=a);delete k[e]||((h[e]=[d.x,d.y,d.x+d.w-1,d.y+d.h-1]).bg=null==l?g.theme.bg:l,c&&(c.push(d),c=null))}if(d.c)for(var b of d.c)t(b,k,c,h,f)}p.prototype.setUI=function(){Bangle.setUI();let d;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},k=>{var c=this.selectedButton,h=this.buttons.length; -if(void 0===k&&this.buttons[c])return this.buttons[c].cb();this.buttons[c]&&(delete this.buttons[c].selected,this.render(this.buttons[c]));c=(c+h+k)%h;this.buttons[c]&&(this.buttons[c].selected=1,this.render(this.buttons[c]));this.selectedButton=c}),d=!0);!this.options.back&&!this.options.remove||d||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function k(c,h){.75=c.x&&h.y>=c.y&&h.x<=c.x+c.w&&h.y<=c.y+c.h&&(2==h.type&&c.cbl?c.cbl(h):c.cb&&c.cb(h));c.c&&c.c.forEach(l=>k(l,h))}Bangle.touchHandler= -(c,h)=>k(this._l,h);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(d){function k(b){"ram";c.reset();void 0!==b.col&&c.setColor(b.col);void 0!==b.bgCol&&c.setBgColor(b.bgCol).clearRect(b.x,b.y,b.x+b.w-1,b.y+b.h-1);h[b.type](b)}d||(d=this._l);this.updateNeeded&&this.update();var c=g,h={"":function(){},txt:function(b){"ram";if(b.wrap){var m=c.setFont(b.font).setFontAlign(0,-1).wrapString(b.label,b.w),n=b.y+(b.h-c.getFontHeight()*m.length>>1);c.drawString(m.join("\n"),b.x+(b.w>> -1),n)}else c.setFont(b.font).setFontAlign(0,0,b.r).drawString(b.label,b.x+(b.w>>1),b.y+(b.h>>1))},btn:function(b){"ram";var m=b.x+(0|b.pad),n=b.y+(0|b.pad),q=b.w-(b.pad<<1),r=b.h-(b.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=void 0!==b.btnBorderCol?b.btnBorderCol:c.theme.fg2;q=void 0!==b.btnFaceCol?b.btnFaceCol:c.theme.bg2;b.selected&&(q=c.theme.bgH,n=c.theme.fgH);c.setColor(q).fillPoly(m).setColor(n).drawPoly(m);void 0!==b.col&&c.setColor(b.col);b.src? -c.setBgColor(q).drawImage("function"==typeof b.src?b.src():b.src,b.x+b.w/2,b.y+b.h/2,{scale:b.scale||void 0,rotate:.5*Math.PI*(b.r||0)}):c.setFont(b.font||"6x8:2").setFontAlign(0,0,b.r).drawString(b.label,b.x+b.w/2,b.y+b.h/2)},img:function(b){"ram";c.drawImage("function"==typeof b.src?b.src():b.src,b.x+b.w/2,b.y+b.h/2,{scale:b.scale||void 0,rotate:.5*Math.PI*(b.r||0)})},custom:function(b){"ram";b.render(b)},h:function(b){"ram";b.c.forEach(k)},v:function(b){"ram";b.c.forEach(k)}};if(this.lazy){this.rects|| -(this.rects={});var l=this.rects.clone(),f=[];t(d,l,f,this.rects,null);for(var a in l)delete this.rects[a];d=Object.keys(l).map(b=>l[b]).reverse();for(var e of d)c.setBgColor(e.bg).clearRect.apply(g,e);f.forEach(k)}else k(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var k={h:function(c){"ram";var h=c.x+(0|c.pad),l=0,f=c.c&&c.c.reduce((e,b)=>e+(0|b.fillx),0);f||(h+=c.w-c._w>>1,f=1);var a=h;c.c.forEach(e=>{e.x=0|a;h+=e._w;l+=0|e.fillx;a=h+0|l*(c.w-c._w)/f; -e.w=0|a-e.x;e.h=0|(e.filly?c.h-(c.pad<<1):e._h);e.y=0|c.y+(0|c.pad)+((1+(0|e.valign))*(c.h-(c.pad<<1)-e.h)>>1);if(e.c)k[e.type](e)})},v:function(c){"ram";var h=c.y+(0|c.pad),l=0,f=c.c&&c.c.reduce((e,b)=>e+(0|b.filly),0);f||(h+=c.h-c._h>>1,f=1);var a=h;c.c.forEach(e=>{e.y=0|a;h+=e._h;l+=0|e.filly;a=h+0|l*(c.h-c._h)/f;e.h=0|a-e.y;e.w=0|(e.fillx?c.w-(c.pad<<1):e._w);e.x=0|c.x+(0|c.pad)+((1+(0|e.halign))*(c.w-(c.pad<<1)-e.w)>>1);if(e.c)k[e.type](e)})}};if(k[d.type])k[d.type](d)};p.prototype.debug=function(d, -k){d||(d=this._l);k=k||1;g.setColor(k&1,k&2,k&4).drawRect(d.x+k-1,d.y+k-1,d.x+d.w-k,d.y+d.h-k);d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);k++;d.c&&d.c.forEach(c=>this.debug(c,k))};p.prototype.update=function(){function d(a){"ram";l[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=c(a._w+(a.pad<<1),0|a.width);a._h=c(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var k=g,c=Math.max,h=Math.round,l={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+h(k.getHeight()* -a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var e=k.setFont(a.font).stringMetrics(a.label);a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+h(k.getHeight()*a.font.slice(0,-1)/100));var e=a.src?k.imageMetrics("function"==typeof a.src?a.src():a.src):k.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=k.imageMetrics("function"==typeof a.src?a.src():a.src),b=a.scale||1;a._w=e.width*b;a._h= -e.height*b},"":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0},h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,b)=>c(e,b._h),0);a._w=a.c.reduce((e,b)=>e+b._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,b)=>e+b._h,0);a._w=a.c.reduce((e,b)=>c(e,b._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)}},f=this._l; -d(f);delete l;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p \ No newline at end of file +function p(c,h){function d(f){"ram";f.id&&(l[f.id]=f);f.type||(f.type="");f.c&&f.c.forEach(d)}this._l=this.l=c;this.options=h||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let e;if(2!=process.env.HWVERSION){this.physBtns=3;e=[];function f(b){"ram";"btn"==b.type&&e.push(b);b.c&&b.c.forEach(f)}f(c);e.length&&(this.physBtns=0,this.buttons=e,this.selectedButton=-1)}if(this.options.btns)if(c=this.options.btns,this.physBtns>=c.length){this.b=c;let f=Math.floor(Bangle.appRect.h/ +this.physBtns);for(2c.length;)c.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:c.map(b=>(b.type="txt",b.font="6x8",b.height=f,b.r=1,b))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:c.map(f=>(f.type="btn",f.filly=1,f.width=32,f.r=1,f))}]},e&&e.push.apply(e,this._l.c[1].c);this.setUI();var l=this;d(this._l);this.updateNeeded=!0}function t(c, +h,d,e,l){var f=null==c.bgCol?l:g.toColor(c.bgCol);if(f!=l||"txt"==c.type||"btn"==c.type||"img"==c.type||"custom"==c.type){var b=c.c;delete c.c;var k="H"+E.CRC32(E.toJS(c));b&&(c.c=b);delete h[k]||((e[k]=[c.x,c.y,c.x+c.w-1,c.y+c.h-1]).bg=null==l?g.theme.bg:l,d&&(d.push(c),d=null))}if(c.c)for(var a of c.c)t(a,h,d,e,f)}p.prototype.setUI=function(){Bangle.setUI();let c;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},h=>{var d=this.selectedButton,e=this.buttons.length; +if(void 0===h&&this.buttons[d])return this.buttons[d].cb();this.buttons[d]&&(delete this.buttons[d].selected,this.render(this.buttons[d]));d=(d+e+h)%e;this.buttons[d]&&(this.buttons[d].selected=1,this.render(this.buttons[d]));this.selectedButton=d}),c=!0);!this.options.back&&!this.options.remove||c||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function h(d,e){.75=d.x&&e.y>=d.y&&e.x<=d.x+d.w&&e.y<=d.y+d.h&&(2==e.type&&d.cbl?d.cbl(e):d.cb&&d.cb(e));d.c&&d.c.forEach(l=>h(l,e))}Bangle.touchHandler= +(d,e)=>h(this._l,e);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(c){function h(a){"ram";d.reset();void 0!==a.col&&d.setColor(a.col);void 0!==a.bgCol&&d.setBgColor(a.bgCol).clearRect(a.x,a.y,a.x+a.w-1,a.y+a.h-1);e[a.type](a)}c||(c=this._l);this.updateNeeded&&this.update();var d=g,e={"":function(){},txt:function(a){"ram";if(a.wrap){var m=d.setFont(a.font).setFontAlign(0,-1).wrapString(a.label,a.w),n=a.y+(a.h-d.getFontHeight()*m.length>>1);d.drawString(m.join("\n"),a.x+(a.w>> +1),n)}else d.setFont(a.font).setFontAlign(0,0,a.r).drawString(a.label,a.x+(a.w>>1),a.y+(a.h>>1))},btn:function(a){"ram";var m=a.x+(0|a.pad),n=a.y+(0|a.pad),q=a.w-(a.pad<<1),r=a.h-(a.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=void 0!==a.btnBorderCol?a.btnBorderCol:d.theme.fg2;q=void 0!==a.btnFaceCol?a.btnFaceCol:d.theme.bg2;a.selected&&(q=d.theme.bgH,n=d.theme.fgH);d.setColor(q).fillPoly(m).setColor(n).drawPoly(m);void 0!==a.col&&d.setColor(a.col);a.src? +d.setBgColor(q).drawImage("function"==typeof a.src?a.src():a.src,a.x+a.w/2,a.y+a.h/2,{scale:a.scale||void 0,rotate:.5*Math.PI*(a.r||0)}):d.setFont(a.font||"6x8:2").setFontAlign(0,0,a.r).drawString(a.label,a.x+a.w/2,a.y+a.h/2)},img:function(a){"ram";d.drawImage("function"==typeof a.src?a.src():a.src,a.x+a.w/2,a.y+a.h/2,{scale:a.scale||void 0,rotate:.5*Math.PI*(a.r||0)})},custom:function(a){"ram";a.render(a)},h:function(a){"ram";a.c.forEach(h)},v:function(a){"ram";a.c.forEach(h)}};if(this.lazy){this.rects|| +(this.rects={});var l=this.rects.clone(),f=[];t(c,l,f,this.rects,null);for(var b in l)delete this.rects[b];c=Object.keys(l).map(a=>l[a]).reverse();for(var k of c)d.setBgColor(k.bg).clearRect.apply(g,k);f.forEach(h)}else h(c)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(c){var h=Math.floor,d={h:function(e){"ram";var l=e.x+(0|e.pad),f=0,b=e.c&&e.c.reduce((a,m)=>a+(0|m.fillx),0);b||(l+=e.w-e._w>>1,b=1);var k=l;e.c.forEach(a=>{a.x=0|k;l+=a._w;f+=0|a.fillx;k=l+h(f* +(e.w-e._w)/b);a.w=0|k-a.x;a.h=0|(a.filly?e.h-(e.pad<<1):a._h);a.y=0|e.y+(0|e.pad)+((1+(0|a.valign))*(e.h-(e.pad<<1)-a.h)>>1);if(a.c)d[a.type](a)})},v:function(e){"ram";var l=e.y+(0|e.pad),f=0,b=e.c&&e.c.reduce((a,m)=>a+(0|m.filly),0);b||(l+=e.h-e._h>>1,b=1);var k=l;e.c.forEach(a=>{a.y=0|k;l+=a._h;f+=0|a.filly;k=l+h(f*(e.h-e._h)/b);a.h=0|k-a.y;a.w=0|(a.fillx?e.w-(e.pad<<1):a._w);a.x=0|e.x+(0|e.pad)+((1+(0|a.halign))*(e.w-(e.pad<<1)-a.w)>>1);if(a.c)d[a.type](a)})}};if(d[c.type])d[c.type](c)};p.prototype.debug= +function(c,h){c||(c=this._l);h=h||1;g.setColor(h&1,h&2,h&4).drawRect(c.x+h-1,c.y+h-1,c.x+c.w-h,c.y+c.h-h);c.pad&&g.drawRect(c.x+c.pad-1,c.y+c.pad-1,c.x+c.w-c.pad,c.y+c.h-c.pad);h++;c.c&&c.c.forEach(d=>this.debug(d,h))};p.prototype.update=function(){function c(b){"ram";l[b.type](b);if(b.r&1){var k=b._w;b._w=b._h;b._h=k}b._w=d(b._w+(b.pad<<1),0|b.width);b._h=d(b._h+(b.pad<<1),0|b.height)}delete this.updateNeeded;var h=g,d=Math.max,e=Math.round,l={txt:function(b){"ram";b.font.endsWith("%")&&(b.font= +"Vector"+e(h.getHeight()*b.font.slice(0,-1)/100));if(b.wrap)b._h=b._w=0;else{var k=h.setFont(b.font).stringMetrics(b.label);b._w=k.width;b._h=k.height}},btn:function(b){"ram";b.font&&b.font.endsWith("%")&&(b.font="Vector"+e(h.getHeight()*b.font.slice(0,-1)/100));var k=b.src?h.imageMetrics("function"==typeof b.src?b.src():b.src):h.setFont(b.font||"6x8:2").stringMetrics(b.label);b._h=16+k.height;b._w=20+k.width},img:function(b){"ram";var k=h.imageMetrics("function"==typeof b.src?b.src():b.src),a=b.scale|| +1;b._w=k.width*a;b._h=k.height*a},"":function(b){"ram";b._w=0;b._h=0},custom:function(b){"ram";b._w=0;b._h=0},h:function(b){"ram";b.c.forEach(c);b._h=b.c.reduce((k,a)=>d(k,a._h),0);b._w=b.c.reduce((k,a)=>k+a._w,0);null==b.fillx&&b.c.some(k=>k.fillx)&&(b.fillx=1);null==b.filly&&b.c.some(k=>k.filly)&&(b.filly=1)},v:function(b){"ram";b.c.forEach(c);b._h=b.c.reduce((k,a)=>k+a._h,0);b._w=b.c.reduce((k,a)=>d(k,a._w),0);null==b.fillx&&b.c.some(k=>k.fillx)&&(b.fillx=1);null==b.filly&&b.c.some(k=>k.filly)&& +(b.filly=1)}},f=this._l;c(f);delete l;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(c){c||(c=this._l);g.reset();void 0!==c.bgCol&&g.setBgColor(c.bgCol);g.clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1)};exports=p \ No newline at end of file From a4f5978fb699ecb3bb10acead419e1f4fd2084d5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 17:21:31 +0000 Subject: [PATCH 19/63] widbt_notify 0.18: Use notify lib to stop this widget clearing the screen of the running clock/app --- apps/widbt_notify/ChangeLog | 3 ++- apps/widbt_notify/metadata.json | 3 ++- apps/widbt_notify/widget.js | 27 ++++++++------------------- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/apps/widbt_notify/ChangeLog b/apps/widbt_notify/ChangeLog index d48cdca6393..74f8515db41 100644 --- a/apps/widbt_notify/ChangeLog +++ b/apps/widbt_notify/ChangeLog @@ -13,4 +13,5 @@ 0.14: Added configuration option 0.15: Added option to hide widget when connected 0.16: Simplify code, add option to disable displaying a message -0.17: Minor display fix \ No newline at end of file +0.17: Minor display fix +0.18: Use notify lib to stop this widget clearing the screen of the running clock/app \ No newline at end of file diff --git a/apps/widbt_notify/metadata.json b/apps/widbt_notify/metadata.json index 5e3f15af211..4eda8694101 100644 --- a/apps/widbt_notify/metadata.json +++ b/apps/widbt_notify/metadata.json @@ -1,13 +1,14 @@ { "id": "widbt_notify", "name": "Bluetooth Widget with Notification", - "version": "0.17", + "version": "0.18", "description": "Show the current Bluetooth connection status with some optional features: show message, buzz on connect/loss, hide always/if connected.", "icon": "widget.png", "type": "widget", "tags": "widget,bluetooth", "provides_widgets" : ["bluetooth"], "supports": ["BANGLEJS","BANGLEJS2"], + "dependencies" : { "notify":"module" }, "storage": [ {"name":"widbt_notify.wid.js","url":"widget.js"}, {"name":"widbt_notify.settings.js","url":"settings.js"} diff --git a/apps/widbt_notify/widget.js b/apps/widbt_notify/widget.js index 4730db5b56b..bde218236d3 100644 --- a/apps/widbt_notify/widget.js +++ b/apps/widbt_notify/widget.js @@ -1,6 +1,6 @@ -(function() { +{ // load settings - var settings = Object.assign({ + let settings = Object.assign({ showWidget: true, buzzOnConnect: true, buzzOnLoss: true, @@ -10,7 +10,7 @@ }, require("Storage").readJSON("widbt_notify.json", true) || {}); // setup widget with to hide if connected and option set - var widWidth = settings.hideConnected && NRF.getSecurityStatus().connected ? 0 : 15; + let widWidth = settings.hideConnected && NRF.getSecurityStatus().connected ? 0 : 15; // write widget with loaded settings WIDGETS.bluetooth_notify = Object.assign(settings, { @@ -31,24 +31,13 @@ g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); } } else { - // g.setColor(g.theme.dark ? "#666" : "#999"); + // g.setColor(g.theme.dark ? "#666" : "#999"); g.setColor("#f00"); // red is easier to distinguish from blue g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); } } }, - redrawCurrentApp: function() { - if (typeof(draw) == 'function') { - g.reset().clear(); - draw(); - Bangle.loadWidgets(); - Bangle.drawWidgets(); - } else { - load(); // fallback. This might reset some variables - } - }, - onNRF: function(connect) { // setup widget with and reload widgets to show/hide if hideConnected is enabled if (this.hideConnected) { @@ -61,10 +50,10 @@ if (this.warningEnabled) { if (this.showMessage) { - E.showMessage( /*LANG*/ 'Connection\n' + (connect ? /*LANG*/ 'restored.' : /*LANG*/ 'lost.'), 'Bluetooth'); + require("notify").show({id:"widbtnotify", title:"Bluetooth", body:/*LANG*/ 'Connection\n' + (connect ? /*LANG*/ 'restored.' : /*LANG*/ 'lost.')}); setTimeout(() => { - WIDGETS.bluetooth_notify.redrawCurrentApp(); - }, 3000); // clear message - this will reload the widget, resetting 'warningEnabled'. + require("notify").hide({id:"widbtnotify"}); + }, 3000); } this.warningEnabled = 0; @@ -87,4 +76,4 @@ NRF.on('connect', (addr) => WIDGETS.bluetooth_notify.onNRF(addr)); NRF.on('disconnect', () => WIDGETS.bluetooth_notify.onNRF()); -})() \ No newline at end of file +} \ No newline at end of file From f0c9ae183c8f65ab62934af71f897a3017414636 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 28 Oct 2024 17:27:31 +0000 Subject: [PATCH 20/63] Add check for widgets that clear the screen! Remove clear of the screen on reload (will break currently running app) --- apps/banglebridge/ChangeLog | 1 + apps/banglebridge/metadata.json | 4 ++-- apps/banglebridge/widget.js | 35 +++++++++++++++------------------ apps/lint_exemptions.js | 12 ----------- apps/widbatpc/ChangeLog | 1 + apps/widbatpc/metadata.json | 2 +- apps/widbatpc/widget.js | 1 - bin/sanitycheck.js | 10 ++++++++-- 8 files changed, 29 insertions(+), 37 deletions(-) diff --git a/apps/banglebridge/ChangeLog b/apps/banglebridge/ChangeLog index 62542be6085..a4b22db228c 100644 --- a/apps/banglebridge/ChangeLog +++ b/apps/banglebridge/ChangeLog @@ -1,2 +1,3 @@ 0.01: New app! 0.02: Minor code improvements +0.03: Remove clearing of the screen (will break running apps) and fix lint errors \ No newline at end of file diff --git a/apps/banglebridge/metadata.json b/apps/banglebridge/metadata.json index 86e1face03e..1dbb2e1de6f 100644 --- a/apps/banglebridge/metadata.json +++ b/apps/banglebridge/metadata.json @@ -2,8 +2,8 @@ "id": "banglebridge", "name": "BangleBridge", "shortName": "BangleBridge", - "version": "0.02", - "description": "Widget that allows Bangle Js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App", + "version": "0.03", + "description": "Widget that allows Bangle.js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App (**Note:** this has nothing to do with Gadgetbridge)", "icon": "widget.png", "type": "widget", "tags": "widget", diff --git a/apps/banglebridge/widget.js b/apps/banglebridge/widget.js index 692822b3912..c805b0f3994 100644 --- a/apps/banglebridge/widget.js +++ b/apps/banglebridge/widget.js @@ -1,10 +1,10 @@ (() => { /** * Widget measurements - * Description: + * Description: * name: connection.wid.js *icon: conectionIcon.icon - * + * */ //Font @@ -24,7 +24,7 @@ //Sensors code /** - * + * * @author Jorge */ function accel() { @@ -35,8 +35,7 @@ }); setInterval(function () { - - acclS = accelN.x + "##" + accelN.y + "##" + accelN.z + "\n" + accelN.diff + "##" + accelN.mag; + //acclS = accelN.x + "##" + accelN.y + "##" + accelN.z + "\n" + accelN.diff + "##" + accelN.mag; data[3] = accelN; }, 2 * 1000); @@ -45,8 +44,7 @@ function btt() { setInterval(function () { - - bttS = E.getBattery(); //return String + //bttS = E.getBattery(); //return String data[2] = E.getBattery(); }, 15 * 1000); @@ -65,9 +63,9 @@ setInterval(function () { - compssS = "A: " + compssN.x + " ## " + compssN.y + " ## " + compssN.z + "\n" + + /*compssS = "A: " + compssN.x + " ## " + compssN.y + " ## " + compssN.z + "\n" + "B: " + compssN.dx + " ## " + compssN.dy + " ## " + compssN.dz + " ## " + "\n" + - "C: " + compssN.heading; //return String + "C: " + compssN.heading; *///return String data[4] = compssN; }, 2 * 1000); @@ -86,8 +84,8 @@ setInterval(function () { - gpsS = "A: " + gpsN.lat + " ## " + gpsN.lon + " ## " + gpsN.alt + "\n" + "B: " + gpsN.speed + " ## " + gpsN.course + " ## " + gpsN.time + "\n" + - "C: " + gpsN.satellites + " ## " + gpsN.fix; //return String + /*gpsS = "A: " + gpsN.lat + " ## " + gpsN.lon + " ## " + gpsN.alt + "\n" + "B: " + gpsN.speed + " ## " + gpsN.course + " ## " + gpsN.time + "\n" + + "C: " + gpsN.satellites + " ## " + gpsN.fix; *///return String // work out how to display the current time var d = new Date(); var year = d.getFullYear(); @@ -150,7 +148,7 @@ //console.log("Index ==> "+ index); msr[indexFinal] = nueva; - item = nueva; + //item = nueva; lastInsert = indexFinal; } @@ -180,7 +178,7 @@ hrmN = normalize(hrmN); var roundedRate = parseFloat(hrmN).toFixed(2); - hrmS = String.valueOf(roundedRate); //return String + //hrmS = String.valueOf(roundedRate); //return String //console.log("array----->" + msr); data[0] = roundedRate; @@ -205,7 +203,7 @@ setInterval(function () { - stepS = String.valueOf(stepN); //return String + //stepS = String.valueOf(stepN); //return String data[1] = stepN; }, 2 * 1000); @@ -240,12 +238,11 @@ g.setFont("Vector", 45); g.drawString(prueba,100,200);*/ if (flip == 1) { //when off - + flip = 0; //Bangle.buzz(1000); - g.clear(); } else { //when on - + flip = 1; g.setFont("Vector", 30); g.drawString(data[0], 65, 180); @@ -283,7 +280,7 @@ com: data[4], gps: data[5] }; - /* g.clear(); + /* g.drawString(compssS,100,200); */ @@ -293,7 +290,7 @@ //draw(); }, 5 * 1000); - + WIDGETS["banglebridge"]={ area: "tl", width: 10, diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index b5c6bc640c0..3bcbf6fd3dd 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -515,12 +515,6 @@ module.exports = { "no-undef" ] }, - "apps/widbt_notify/widget.js": { - "hash": "16372ffcbc6bd1419ca326c7da40c2195f82a4bfceb6f123c15872624c4f0adf", - "rules": [ - "no-undef" - ] - }, "apps/widbgjs/widget.js": { "hash": "9852ce9aafb0a1ca3029d497282c8cdf07438ea36a3323313bad5b7569b1081b", "rules": [ @@ -1157,12 +1151,6 @@ module.exports = { "no-undef" ] }, - "apps/banglebridge/widget.js": { - "hash": "4ee8d6749e1d0e28c58ad871fd9f6ccbca2d716bb4fbd3511ba4c34a6a5897e1", - "rules": [ - "no-undef" - ] - }, "apps/bad/bad.app.js": { "hash": "d1354613102818190dd4e6e28fd715db7dc4d51b8e618cae61a3135529cc97eb", "rules": [ diff --git a/apps/widbatpc/ChangeLog b/apps/widbatpc/ChangeLog index e9326fd2c6c..34873124ccd 100644 --- a/apps/widbatpc/ChangeLog +++ b/apps/widbatpc/ChangeLog @@ -17,3 +17,4 @@ Add option to disable vibration when charger connects 0.18: Only redraw when values change 0.19: Match draw() API e.g. to allow wid_edit to alter this widget +0.20: Remove clear of the screen on reload (will break currently running app) \ No newline at end of file diff --git a/apps/widbatpc/metadata.json b/apps/widbatpc/metadata.json index 4c364a86485..5e160b5d44a 100644 --- a/apps/widbatpc/metadata.json +++ b/apps/widbatpc/metadata.json @@ -2,7 +2,7 @@ "id": "widbatpc", "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", - "version": "0.19", + "version": "0.20", "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", "icon": "widget.png", "type": "widget", diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widget.js index 7ba060d6dc5..163c0f54123 100644 --- a/apps/widbatpc/widget.js +++ b/apps/widbatpc/widget.js @@ -156,7 +156,6 @@ // need to redraw all widgets, because changing the "charger" setting // can affect the width and mess with the whole widget layout setWidth(); - g.clear(); Bangle.drawWidgets(); } diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index ec2644f6b78..b2332b16f4e 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -348,11 +348,17 @@ apps.forEach((app,appIdx) => { } } // something that needs to be evaluated with 'eval(require("Storage").read(fn))' - if (/\.clkinfo?\.js$/.test(file.name) || - /\.settings?\.js$/.test(file.name)) { + if (/\.clkinfo\.js$/.test(file.name) || + /\.settings\.js$/.test(file.name)) { if (!fileContents.trim().endsWith(")")) WARN(`App ${app.id} file ${file.name} should be evaluated as a function but doesn't end in ')'`, {file:appDirRelative+file.url}); } + if (/\.clkinfo\.js$/.test(file.name) || + /\.wid\.js$/.test(file.name)) { + if (fileContents.indexOf("g.clear(")>=0 || + fileContents.indexOf("g.reset().clear()")>=0) + ERROR(`App ${app.id} widget/clkinfo ${file.name} should never totally clear the screen`, {file:appDirRelative+file.url}); + } } for (const key in file) { if (!STORAGE_KEYS.includes(key)) ERROR(`App ${app.id} file ${file.name} has unknown key ${key}`, {file:appDirRelative+file.url}); From 8acffd521d1b74e6f72f64f0489c1a913a992edb Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 28 Oct 2024 18:12:57 +0000 Subject: [PATCH 21/63] Fix build failure from e7bfc18e7 (sanitycheck warnings) --- bin/sanitycheck.js | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index b2332b16f4e..61a251bb5e2 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -120,6 +120,104 @@ var KNOWN_WARNINGS = [ `In locale test, long time format might not work in some apps if it is not "%HH:%MM:%SS"`, `In locale wae_CH, short time format might not work in some apps if it is not "%HH:%MM"`, `In locale test, short time format might not work in some apps if it is not "%HH:%MM"`, + "App a_dndtoggle file a_dndtoggle.settings.js should be evaluated as a function but doesn't end in ')'", + "App activepedom file activepedom.settings.js should be evaluated as a function but doesn't end in ')'", + "App agpsdata file agpsdata.settings.js should be evaluated as a function but doesn't end in ')'", + "App alarm file alarm.settings.js should be evaluated as a function but doesn't end in ')'", + "App andark file andark.settings.js should be evaluated as a function but doesn't end in ')'", + "App antonclkplus file antonclkplus.settings.js should be evaluated as a function but doesn't end in ')'", + "App banglexercise file banglexercise.settings.js should be evaluated as a function but doesn't end in ')'", + "App barclock file barclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App berlinc file berlinc.settings.js should be evaluated as a function but doesn't end in ')'", + "App bikespeedo file bikespeedo.settings.js should be evaluated as a function but doesn't end in ')'", + "App blc file blc.settings.js should be evaluated as a function but doesn't end in ')'", + "App boxclk file boxclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App bthome file bthome.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App bthrm file bthrm.settings.js should be evaluated as a function but doesn't end in ')'", + "App carcrazy file carcrazy.settings.js should be evaluated as a function but doesn't end in ')'", + "App chimer file chimer.settings.js should be evaluated as a function but doesn't end in ')'", + "App circlesclock file circlesclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App clicompleteclk file clicompleteclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App clkinfocal file clkinfocal.settings.js should be evaluated as a function but doesn't end in ')'", + "App clkinfogps file gps.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfogpsspeed file clkinfogpsspeed.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfom file ram.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfomag file clkinfomag.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfostopw file stopw.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clockcal file clockcal.settings.js should be evaluated as a function but doesn't end in ')'", + "App cogclock file cogclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App counter2 file counter2.settings.js should be evaluated as a function but doesn't end in ')'", + "App cprassist file cprassist.settings.js should be evaluated as a function but doesn't end in ')'", + "App dane_tcr file dane_tcr.settings.js should be evaluated as a function but doesn't end in ')'", + "App dragboard file dragboard.settings.js should be evaluated as a function but doesn't end in ')'", + "App draguboard file draguboard.settings.js should be evaluated as a function but doesn't end in ')'", + "App drained file drained.settings.js should be evaluated as a function but doesn't end in ')'", + "App drinkcounter file drinkcounter.settings.js should be evaluated as a function but doesn't end in ')'", + "App dtlaunch file dtlaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App ffcniftyb file ffcniftyb.settings.js should be evaluated as a function but doesn't end in ')'", + "App folderlaunch file folderlaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App gassist file gassist.settings.js should be evaluated as a function but doesn't end in ')'", + "App gbmusic file gbmusic.settings.js should be evaluated as a function but doesn't end in ')'", + "App getup file getup.settings.js should be evaluated as a function but doesn't end in ')'", + "App gipy file gipy.settings.js should be evaluated as a function but doesn't end in ')'", + "App gpsrec file gpsrec.settings.js should be evaluated as a function but doesn't end in ')'", + "App gpssetup file gpssetup.settings.js should be evaluated as a function but doesn't end in ')'", + "App iconlaunch file iconlaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App infoclk file infoclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App largeclock file largeclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App launch file launch.settings.js should be evaluated as a function but doesn't end in ')'", + "App messagelist file messagelist.settings.js should be evaluated as a function but doesn't end in ')'", + "App messages file messages.settings.js should be evaluated as a function but doesn't end in ')'", + "App messages_light file messages_light.settings.js should be evaluated as a function but doesn't end in ')'", + "App messagesoverlay file messagesoverlay.settings.js should be evaluated as a function but doesn't end in ')'", + "App metronome file metronome.settings.js should be evaluated as a function but doesn't end in ')'", + "App multitimer file multitimer.settings.js should be evaluated as a function but doesn't end in ')'", + "App nesclock file nesclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App nightwatch file nightwatch.settings.js should be evaluated as a function but doesn't end in ')'", + "App owmweather file owmweather.settings.js should be evaluated as a function but doesn't end in ')'", + "App pebble file pebble.settings.js should be evaluated as a function but doesn't end in ')'", + "App pebbled file pebbled.settings.js should be evaluated as a function but doesn't end in ')'", + "App pongclock file pongclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App popconlaunch file popcon.settings.js should be evaluated as a function but doesn't end in ')'", + "App poweroff file poweroff.settings.js should be evaluated as a function but doesn't end in ')'", + "App puzzle15 file puzzle15.settings.js should be evaluated as a function but doesn't end in ')'", + "App qcenter file qcenter.settings.js should be evaluated as a function but doesn't end in ')'", + "App rebbleagenda file rebbleagenda.settings.js should be evaluated as a function but doesn't end in ')'", + "App recorder file recorder.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App rep file rep.settings.js should be evaluated as a function but doesn't end in ')'", + "App saclock file saclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App sched file sched.settings.js should be evaluated as a function but doesn't end in ')'", + "App score file score.settings.js should be evaluated as a function but doesn't end in ')'", + "App sensortools file sensortools.settings.js should be evaluated as a function but doesn't end in ')'", + "App shadowclk file shadowclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App shortcuts file shortcuts.settings.js should be evaluated as a function but doesn't end in ')'", + "App simplebgclock file simplebgclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App slomoclock file slomoclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App slopeclockpp file slopeclockpp.settings.js should be evaluated as a function but doesn't end in ')'", + "App smclock file smclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App speedalt file speedalt.settings.js should be evaluated as a function but doesn't end in ')'", + "App speedalt2 file speedalt2.settings.js should be evaluated as a function but doesn't end in ')'", + "App swp2clk file swp2clk.settings.js should be evaluated as a function but doesn't end in ')'", + "App taglaunch file taglaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App thunder file thunder.settings.js should be evaluated as a function but doesn't end in ')'", + "App timecal file timecal.settings.js should be evaluated as a function but doesn't end in ')'", + "App timerclk file timerclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App timestamplog file timestamplog.settings.js should be evaluated as a function but doesn't end in ')'", + "App toucher file toucher.settings.js should be evaluated as a function but doesn't end in ')'", + "App touchtimer file touchtimer.settings.js should be evaluated as a function but doesn't end in ')'", + "App trex file trex.settings.js should be evaluated as a function but doesn't end in ')'", + "App usgs file usgs.settings.js should be evaluated as a function but doesn't end in ')'", + "App weatherClock file weatherClock.settings.js should be evaluated as a function but doesn't end in ')'", + "App wid_edit file wid_edit.settings.js should be evaluated as a function but doesn't end in ')'", + "App widalarmeta file widalarmeta.settings.js should be evaluated as a function but doesn't end in ')'", + "App widbaroalarm file widbaroalarm.settings.js should be evaluated as a function but doesn't end in ')'", + "App widbatwarn file widbatwarn.settings.js should be evaluated as a function but doesn't end in ')'", + "App widbgjs file widbgjs.settings.js should be evaluated as a function but doesn't end in ')'", + "App widdst file widdst.settings.js should be evaluated as a function but doesn't end in ')'", + "App widgps file widgps.settings.js should be evaluated as a function but doesn't end in ')'", + "App widhrm file widhrm.settings.js should be evaluated as a function but doesn't end in ')'", + "App widmp file widmp.settings.js should be evaluated as a function but doesn't end in ')'", + "App widsleepstatus file widsleepstatus.settings.js should be evaluated as a function but doesn't end in ')'", ]; var apps = []; From 8742e11581e77ffcce15842921a5a3c7297e9406 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 28 Oct 2024 18:03:45 +0000 Subject: [PATCH 22/63] drained: fix not restoring when charge threshold met previously the assumption was that the `"changing"` event would be fired periodically when charging. fixes #3625 --- apps/drained/ChangeLog | 1 + apps/drained/app.js | 12 ++++-------- apps/drained/app.ts | 12 ++++-------- apps/drained/metadata.json | 2 +- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/apps/drained/ChangeLog b/apps/drained/ChangeLog index 3767ad71ef4..0667d8ff612 100644 --- a/apps/drained/ChangeLog +++ b/apps/drained/ChangeLog @@ -5,3 +5,4 @@ 0.04: Enhance menu: enable bluetooth, visit settings & visit recovery 0.05: Enhance menu: permit toggling bluetooth 0.06: Display clock in green when charging, with "charging" text +0.07: Correctly restore full power when the charged threshold is reached diff --git a/apps/drained/app.js b/apps/drained/app.js index deafe7d6814..57acadf25d2 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -88,7 +88,7 @@ var reload = function () { }; reload(); Bangle.emit("drained", E.getBattery()); -var _a = require("Storage").readJSON("".concat(app, ".setting.json"), true) || {}, _b = _a.keepStartup, keepStartup = _b === void 0 ? true : _b, _c = _a.restore, restore = _c === void 0 ? 20 : _c, _d = _a.exceptions, exceptions = _d === void 0 ? ["widdst.0"] : _d; +var _a = require("Storage").readJSON("".concat(app, ".setting.json"), true) || {}, _b = _a.keepStartup, keepStartup = _b === void 0 ? true : _b, _c = _a.restore, restore = _c === void 0 ? 20 : _c, _d = _a.exceptions, exceptions = _d === void 0 ? ["widdst.0"] : _d, _e = _a.interval, interval = _e === void 0 ? 10 : _e; function drainedRestore() { if (!keepStartup) { try { @@ -101,18 +101,14 @@ function drainedRestore() { load(); } var checkCharge = function () { - if (E.getBattery() < restore) { + if (!Bangle.isCharging() || E.getBattery() < restore) { draw(); return; } drainedRestore(); }; -if (Bangle.isCharging()) - checkCharge(); -Bangle.on("charging", function (charging) { - if (charging) - checkCharge(); -}); +checkCharge(); +drainedInterval = setInterval(checkCharge, interval * 60 * 1000); if (!keepStartup) { var storage = require("Storage"); for (var _i = 0, exceptions_1 = exceptions; _i < exceptions_1.length; _i++) { diff --git a/apps/drained/app.ts b/apps/drained/app.ts index a779a8660ca..343fa10692f 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -115,7 +115,7 @@ reload(); Bangle.emit("drained", E.getBattery()); // restore normal boot on charge -const { keepStartup = true, restore = 20, exceptions = ["widdst.0"] }: DrainedSettings +const { keepStartup = true, restore = 20, exceptions = ["widdst.0"], interval = 10 }: DrainedSettings = require("Storage").readJSON(`${app}.setting.json`, true) || {}; // re-enable normal boot code when we're above a threshold: @@ -131,19 +131,15 @@ function drainedRestore() { // "public", to allow users to call } const checkCharge = () => { - if(E.getBattery() < restore) { + if(!Bangle.isCharging() || E.getBattery() < restore) { draw(); return; } drainedRestore(); }; -if (Bangle.isCharging()) - checkCharge(); - -Bangle.on("charging", charging => { - if(charging) checkCharge(); -}); +checkCharge(); +drainedInterval = setInterval(checkCharge, interval * 60 * 1000); if(!keepStartup){ const storage = require("Storage"); diff --git a/apps/drained/metadata.json b/apps/drained/metadata.json index a5389a91b96..eff9a331b1d 100644 --- a/apps/drained/metadata.json +++ b/apps/drained/metadata.json @@ -1,7 +1,7 @@ { "id": "drained", "name": "Drained", - "version": "0.06", + "version": "0.07", "description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals", "readme": "README.md", "icon": "icon.png", From f8a0c73356f509b5c24ed144a6987bed84e10fdd Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 28 Oct 2024 20:43:12 +0000 Subject: [PATCH 23/63] messagegui: stop buzzing for a message when it's removed e.g. a call is answered --- apps/android/lib.js | 2 +- apps/messagegui/ChangeLog | 3 ++- apps/messagegui/lib.js | 2 ++ apps/messagegui/metadata.json | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/android/lib.js b/apps/android/lib.js index 71d7f60437b..038d154b3f5 100644 --- a/apps/android/lib.js +++ b/apps/android/lib.js @@ -44,7 +44,7 @@ exports.gbHandler = (event) => { "musicinfo" : function() { require("messages").pushMessage(Object.assign(event, {t:"modify",id:"music",title:"Music"})); }, - // {"t":"call","cmd":"incoming/end","name":"Bob","number":"12421312"}) + // {"t":"call","cmd":"incoming/end/start/outgoing","name":"Bob","number":"12421312"}) "call" : function() { Object.assign(event, { t:event.cmd=="incoming"?"add":"remove", diff --git a/apps/messagegui/ChangeLog b/apps/messagegui/ChangeLog index f97d7b85fef..d0676ec9b93 100644 --- a/apps/messagegui/ChangeLog +++ b/apps/messagegui/ChangeLog @@ -109,4 +109,5 @@ 0.80: Add ability to reply to messages if a reply library is installed and the message can be replied to 0.81: Fix issue stopping Music message for being marked as read Make sure play button image is transparent - Add top-right menu to music playback to allow message to be deleted \ No newline at end of file + Add top-right menu to music playback to allow message to be deleted +0.82: Stop buzzing when a message is removed (e.g. call answered) diff --git a/apps/messagegui/lib.js b/apps/messagegui/lib.js index 54d79866abb..1dcb30ed815 100644 --- a/apps/messagegui/lib.js +++ b/apps/messagegui/lib.js @@ -25,6 +25,8 @@ exports.listener = function(type, msg) { require("messages").apply(msg, Bangle.MESSAGES); if (!Bangle.MESSAGES.length) delete Bangle.MESSAGES; } + if(type!=="music") + require("messages").stopBuzz(); return require("messages").save(msg); // always write removal to flash } diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json index ff8376bae91..4e3ca6057d9 100644 --- a/apps/messagegui/metadata.json +++ b/apps/messagegui/metadata.json @@ -2,7 +2,7 @@ "id": "messagegui", "name": "Message UI", "shortName": "Messages", - "version": "0.81", + "version": "0.82", "description": "Default app to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", From bfeffa4a871662639881a338dcce373042e756f2 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 28 Oct 2024 21:02:36 +0000 Subject: [PATCH 24/63] messagegui: stop buzzing on disconnect too --- apps/messagegui/lib.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/messagegui/lib.js b/apps/messagegui/lib.js index 1dcb30ed815..43141531f37 100644 --- a/apps/messagegui/lib.js +++ b/apps/messagegui/lib.js @@ -18,6 +18,10 @@ exports.listener = function(type, msg) { clearTimeout(exports.messageTimeout); delete exports.messageTimeout; } + if (type==="clearAll") { + require("messages").stopBuzz(); + return; + } if (msg.t==="remove") { // we won't open the UI for removed messages, so make sure to delete it from flash if (Bangle.MESSAGES) { From 69e344fbc557a9291b51ec9bef7d5934b6b1ea64 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 29 Oct 2024 10:00:48 +0000 Subject: [PATCH 25/63] minor regex tweaks --- apps/clock_info/lib.js | 2 +- apps/powermanager/interface.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/clock_info/lib.js b/apps/clock_info/lib.js index 1134749c278..0e20ab85559 100644 --- a/apps/clock_info/lib.js +++ b/apps/clock_info/lib.js @@ -140,7 +140,7 @@ exports.load = function() { // note: code below is included in clkinfocache by bootupdate.js // we use clkinfocache if it exists as it's faster eval(clkInfoCache); - } else require("Storage").list(/clkinfo.js$/).forEach(fn => { + } else require("Storage").list(/clkinfo\.js$/).forEach(fn => { // In case there exists already a menu object b with the same name as the next // object a, we append the items. Otherwise we add the new object a to the list. try{ diff --git a/apps/powermanager/interface.html b/apps/powermanager/interface.html index 51c31cc815e..450ad4f260e 100644 --- a/apps/powermanager/interface.html +++ b/apps/powermanager/interface.html @@ -148,7 +148,7 @@ //try finding possible sources for the given function, currently does not work because function.toString() not being identical to code in the *.js files. - /*Puck.eval(`require("Storage").list(/.*.js$/)`, (f)=>{ + /*Puck.eval(`require("Storage").list(/.*\.js$/)`, (f)=>{ console.log("Found files:", f, rows[1].func); for (let file of f){ let query = `require("Storage").read('${file}').includes('${rows[1].func}')`; From 9805bb16444199acdd51722957f3f61f936ef1f0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 29 Oct 2024 14:50:06 +0000 Subject: [PATCH 26/63] Add sudoku game --- apps/sudoku/ChangeLog | 1 + apps/sudoku/app-icon.js | 1 + apps/sudoku/app.js | 163 +++++++++++++++++++++++++++ apps/sudoku/app.png | Bin 0 -> 6481 bytes apps/sudoku/gen_sudoku.js | 24 ++++ apps/sudoku/metadata.json | 17 +++ apps/sudoku/screenshot.png | Bin 0 -> 3905 bytes apps/sudoku/sudoku.easy.txt | 200 ++++++++++++++++++++++++++++++++++ apps/sudoku/sudoku.hard.txt | 200 ++++++++++++++++++++++++++++++++++ apps/sudoku/sudoku.medium.txt | 200 ++++++++++++++++++++++++++++++++++ 10 files changed, 806 insertions(+) create mode 100644 apps/sudoku/ChangeLog create mode 100644 apps/sudoku/app-icon.js create mode 100644 apps/sudoku/app.js create mode 100644 apps/sudoku/app.png create mode 100644 apps/sudoku/gen_sudoku.js create mode 100644 apps/sudoku/metadata.json create mode 100644 apps/sudoku/screenshot.png create mode 100644 apps/sudoku/sudoku.easy.txt create mode 100644 apps/sudoku/sudoku.hard.txt create mode 100644 apps/sudoku/sudoku.medium.txt diff --git a/apps/sudoku/ChangeLog b/apps/sudoku/ChangeLog new file mode 100644 index 00000000000..5560f00bce7 --- /dev/null +++ b/apps/sudoku/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/sudoku/app-icon.js b/apps/sudoku/app-icon.js new file mode 100644 index 00000000000..6762e0c1a16 --- /dev/null +++ b/apps/sudoku/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("l0vwQPM/4AI+E4ChEDwYgJhkwgGAgYHChED3cACwM8gHwBYXwn/wCwMLwELBQULgeACxXACwIPBCwotKAIIWIAAIWCn5EJgewFou4CwQpDAYhyCCQJWBgE7BwWDh6gICwgtDCwYtOF4QWIgf8CxMwL4gtFh7OGCwS0CCxABB4AWHnBbJIhc7LZI2DCw4AFwcDTIPw/6lD/gWB3YABhewAgW72CgQW6wWphELhYCBgYEBgYWC+AAHCwIQBAAwtEHgTOHAA+DB4QAGnk7TYYAFwCxCAAzVGAAo")) diff --git a/apps/sudoku/app.js b/apps/sudoku/app.js new file mode 100644 index 00000000000..5a7f9cd1fd7 --- /dev/null +++ b/apps/sudoku/app.js @@ -0,0 +1,163 @@ +var settings = require("Storage").readJSON("sudoku.json",1)||{}; + +const Layout = require("Layout"); +var puzzle = ""; // start puzzle space for blanks, 81 char str +var solution = ""; // the solution for the puzzle 81 char str +var current = ""; // current puzzle state, 81 char str +var sx=4, sy=4; // selected item +var dx=0, dy=0, dmoved=false; // current drag amount +const DRAG = 20; +const CHOOSERFONT = "12x20:2"; +const COL_GOOD = "#00F"; +const COL_BAD = "#F00"; + +function saveSettings() { + settings.puzzle = puzzle; + settings.solution = solution; + settings.current = current; + require("Storage").writeJSON("sudoku.json",settings); +} + +function startGame(difficulty) { + let file = require("Storage").read("sudoku.easy.txt"); + let games = 0|(file.length/163); + let game = Math.floor(Math.random()*games); + let line = file.substr(game*163, 162); + puzzle = line.substr(0,81).replaceAll("-"," "); + current = ""+puzzle; // new string + solution = line.substr(81,81); + showGrid(); +} + +function draw() { + g.clear(1); + for (var i=0;i<10;i++) { + g.setColor((i%3)?"#888":g.theme.fg); + g.fillRect(7+18*i, 7, 7+18*i, 169); + g.fillRect(7, 7+18*i, 169, 7+18*i); + } + i = 0; + g.setFont("6x8:2").setFontAlign(0,0); + for (var y=0;y<9;y++) + for (var x=0;x<9;x++) + g.setColor(puzzle[i]==" "?((solution[i]==current[i])?COL_GOOD:COL_BAD):g.theme.fg).drawString(current[i++], 16 + 18*x, 16 + 18*y); +} +function drawSq(x,y,sel) { + g.setColor(sel ? g.theme.bgH : g.theme.bg).fillRect(8+x*18,8+y*18,24+x*18,24+y*18); + g.setFont("6x8:2").setFontAlign(0,0).setColor(sel ? g.theme.fgH : g.theme.fg); + var i = x+y*9; + g.setColor(puzzle[i]==" "?((solution[i]==current[i])?COL_GOOD:COL_BAD):g.theme.fg).drawString(current[i++], 16 + 18*x, 16 + 18*y); +} + +// precalculate our layout +var choose = function(num) { + if (num!==undefined) { + Bangle.buzz(100); + var i = sx+sy*9; + current = current.substr(0,i)+num+current.substr(i+1); + } + showGrid(); + if (current == solution) { + saveSettings(); + E.showMessage(/*LANG*/"Well done,\nyou finished!", { + title:"Sudoku", + buttons : {"Ok":true}, + img : require("heatshrink").decompress(atob("k8pwcBkmSpICCnVp0IIFAQl27dt2wOJ9On7/582YtOJBws7tv/DoQKCBwubvvmzVp0wCCHAvf9u2DpE8uOn7waEjQdDq1Itv+DQQCB0gZBkMkyPHj1tHAuGAQOJktt/Ubvo4DAQI3ChMcuPHzd5HAeasICBtFOr/kw3fDQe27RhCofH/lx4xxFSQIFBiu/rNhHAp0DyHx447BHAh0Ekt/61YlodFOgaPBDoJWFAQeJrf1yySBDohWCoVJOgUcKw+YyVOrtly0LKw4eBp4dCjytHBwNOrNlyUbDoVpHAYDBo4dH02EFoTpBDoQ7B2MyZALMCHYsGtOOjALDAQQ7CyM6tFkFIgCDDoPBnkT4wLFAQegxP8z/JBxNwp8E+ALHAQMl+V/n4aIAQI4B4McBxU/z/P8gOKjnx4JHJAQP//5WKSoVwDRICBv//FJTRDBxeT/5WLkmR45WLkitLARNIA")) + }).then(showMenu); + } +}; +var numberChooser = new Layout( { + type:"v", c: [ + {type:"h", c: [ + {type:"btn", font:CHOOSERFONT, label:"1", fillx:1, cb:()=>choose(1) }, + {type:"btn", font:CHOOSERFONT, label:"2", fillx:1, cb:()=>choose(2) }, + {type:"btn", font:CHOOSERFONT, label:"3", fillx:1, cb:()=>choose(3) } + ]}, + {type:"h", c: [ + {type:"btn", font:CHOOSERFONT, label:"4", fillx:1, cb:()=>choose(4) }, + {type:"btn", font:CHOOSERFONT, label:"5", fillx:1, cb:()=>choose(5) }, + {type:"btn", font:CHOOSERFONT, label:"6", fillx:1, cb:()=>choose(6) } + ]}, + {type:"h", c: [ + {type:"btn", font:CHOOSERFONT, label:"7", fillx:1, cb:()=>choose(7) }, + {type:"btn", font:CHOOSERFONT, label:"8", fillx:1, cb:()=>choose(8) }, + {type:"btn", font:CHOOSERFONT, label:"9", fillx:1, cb:()=>choose(9) } + ]} + ], fillx:1 +}, {btns:[ {label:/*LANG*/"Back", cb: l=>choose()} ]}); + +function showGrid() { + Bangle.setUI({mode:"custom", drag:e=>{ + if (e.b) { + dx += e.dx; + dy += e.dy; + while (Math.abs(dx) >= DRAG) { + Bangle.buzz(40); + let old = sx; + sx = (sx+9+Math.sign(dx))%9; + dx -= Math.sign(dx)*DRAG; + drawSq(old,sy,0); + drawSq(sx,sy,1); + dmoved = true; + } + while (Math.abs(dy) >= DRAG) { + Bangle.buzz(40); + let old = sy; + sy = (sy+9+Math.sign(dy))%9; + dy -= Math.sign(dy)*DRAG; + drawSq(sx,old,0); + drawSq(sx,sy,1); + dmoved = true; + } + } else { + if (!dmoved && puzzle[sx+sy*9]==" ") { + Bangle.buzz(100); + setTimeout(showSelectNumber, 10); + } + dx = dy = 0; + dmoved = false; + } + }, btn:() => { + saveSettings(); + showMenu(); + }}); + draw(); + drawSq(sx,sy,1); +} + +function showSelectNumber() { + g.clear(); + numberChooser.setUI(); + numberChooser.render(); +} + +function showMenu() { + var menu = { "" : { title: "Sudoku" } }; + if (settings.puzzle) + menu["Resume Game"] = () => { + puzzle = settings.puzzle; + solution = settings.solution; + current = settings.current; + showGrid(); + }; + menu["New Game"] = () => { + E.showMenu({ "" : { title: /*LANG*/"Difficulty", back : showMenu }, + "Easy" : () => startGame("easy"), + "Medium" : () => startGame("medium"), + "Hard" : () => startGame("hard") + }); + }; + menu["Exit"] = () => load(); + E.showMenu(menu); +} + +if (settings.puzzle) { + puzzle = settings.puzzle; + solution = settings.solution; + current = settings.current; + showGrid(); +} else { + showMenu(); +} + +E.on("kill", saveSettings); // ensure we save the game diff --git a/apps/sudoku/app.png b/apps/sudoku/app.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5f449e8f845620b5436608fa2dd1a9dbae5408 GIT binary patch literal 6481 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 literal 0 HcmV?d00001 diff --git a/apps/sudoku/sudoku.easy.txt b/apps/sudoku/sudoku.easy.txt new file mode 100644 index 00000000000..5937edea3fe --- /dev/null +++ b/apps/sudoku/sudoku.easy.txt @@ -0,0 +1,200 @@ +8----47---47----639-5--381-7--46-13219---5---4----2597--13-724--2--46--83-4-----1813694725247581963965273814758469132192735486436812597681357249529146378374928651 +6------1-----954-3--94-1----76-3-----18562-94-927-4638--4-5----9--2--1-62-3----47645378219821695473739421865476839521318562794592714638164957382987243156253186947 +9-6-----3-186239-----945---3-521--8-4--3---1---189---46--57-1---7--38-9----16-47-946781523518623947237945861365214789489357216721896354694572138172438695853169472 +---4-71---895-27637128-3-495-7-8--3--94-31--------96---5--7---------8-959-1---8-6635497128489512763712863549567284931894631257123759684358976412276148395941325876 +4-5----97-92-4-------6--2--7---68----89-14763651-324-9---17-9-8-1-4---265---9----465321897192847635873659214734968152289514763651732489326175948917483526548296371 +1---23986------154--819-----3-4--8---2-85-6-3--4-3-2-147----3-93--9--5-7-1---7-28147523986293678154568194732639412875721859643854736291476285319382941567915367428 +--6-25837-2--891-6-3-74-5-947-21---5---97--8------4---59-8-23-----4--9-2---5974-8946125837725389146138746529473218695651973284289654713594862371867431952312597468 +--5---61-4---1-------6-9-25-5349786--84-----9-17-562345--1-43----6-----23-9-68---895742613462315978731689425253497861684231759917856234578124396146973582329568147 +3--16-9--------32794-7-5---6-9-2---18-1---459--489-6-27-628319--------68---6-92-3387162945165948327942735816639524781821376459574891632756283194293417568418659273 +------1---2---3----8---6-4564--3-28-2938-4--68--6-7493---9--5--358---9729-4--2618436785129529143867781296345647539281293814756815627493162978534358461972974352618 +-96--1-521354-6-9---------6974182-632--597--1---6--7--5192---7-3--7-----6-7--4-35496871352135426897728359146974182563263597481851643729519238674342765918687914235 +-9127----------562-5-4-89--43----1791--3-98-698---6--4---89-6-582-65349--------83691275348748931562253468917436582179172349856985716234314897625827653491569124783 +58----24-----1--8-3-72--9--6435-8-2989-132-67----4--35-7----3-----8-7-9-4-8-91---589763241264915783317284956643578129895132467721649835972456318136827594458391672 +2--4-3-756--5----1----6129-3--74----8--6--143-961--82796--8-5-----2-67--1-2--7-68218493675649572381753861294321748956875629143496135827967384512584216739132957468 +---5--3-86---34-5235--27--6-49----3--6-31--4----47-28-8-67-391413----7--9----286-492561378687934152351827496749285631268319547513476289826753914134698725975142863 +76---9--5142--83--98--31-7--29-7-5-157---2-6-8-1---7--4--187--3----461-92-8-----7763429815142758396985631472629874531574312968831965724496187253357246189218593647 +--476-53-9-6-3-4-1-----9------18------295-7-359-473--21-9-2-3-47---9-1-646351---7284761539976835421315249678637182945842956713591473862159627384728394156463518297 +-3--9-----29-46--81-82-75-6--4---3---15--2---9---5-461-9--75684--1--49-7-57--921-536891742729546138148237596674918325315462879982753461293175684861324957457689213 +-863--2-9--17--6--34-----718-----3-76--47--5--751-3--81295--7-----9--82-538-471--786315249951724683342869571894652317613478952275193468129586734467931825538247196 +--13-98--7---21--4----471-692--543---4--38-6-6---9-4-----286---87-----9--34975--8451369827768521934392847156927654381145738269683192475519286743876413592234975618 +1--93-46-3-4--1----9---7-83--61493-8-21----5---3526-9-63--84-----76---3-5-271--4-178932465364851279295467183756149328921378654843526791639284517417695832582713946 +-1-7-8--5--4-65-2--59-42---9---714---7--3468--4--8--9----619---8-----21---18237-4612798345784365921359142876968271453175934682243586197427619538836457219591823764 +9132-5--4874----------439---21-98-5--45--27----9-7--2--68-3---259-6---4--32----67913285674874916235256743918721398456345162789689574321168437592597621843432859167 +-8---63--3---42--8-2--816-7--8-975---4-26--9--93-58------734-----4615-826-----4-5581976324376542918429381657268197543745263891193458276852734169934615782617829435 +81-64-379----89------7-348-69-524---48---6--75--8-7-94-45---21----371----3-4---68812645379374289156956713482697524831483196527521837694745968213268371945139452768 +9--8--4-5----641-94-6-95---713-42----4--8-25-2------3-1-2--85473974----65--726---921873465835264179476195382713542698649387251258619734162938547397451826584726913 +2-4--5---75-48---99--73--54-273-8----8-6-4-9--4----18--92-7---1--3----46861-439-2234965718756481329918732654127398465385614297649257183492876531573129846861543972 +2---------95-86--3--87-32-5-268-9--1-74------8391--62--679--358--25-79----13-87-2213495876795286143648713295526879431174632589839154627467921358382567914951348762 +--6-----2-2-6-791-57--286-4-9-7563-8--78--56---------9--34-2---1-5369--7--258-4-3316945872824637915579128634491756328237894561658213749983472156145369287762581493 +-3--27--52----6---496----233-1----788--73-5-----89--316841--3--9-2473-5-7-----412138927645275346189496518723341265978829731564567894231684152397912473856753689412 +-617--52-5-74--6--48325--7---9---4-----1--26-634-2---7----7--9-8--34-71-3-25-18-6961783524527419638483256971219867453758134269634925187145678392896342715372591846 +98-----71-1---3---5---9-42--27--8----64932-15-9517-2682-------4-5-41-------3-518-983246571412753896576891423127568349864932715395174268231687954758419632649325187 +-39-2--16-8--19---164-83---41-3-----79---6-48--8------3-1-75-9-9-62345--84--61-2-539427816287619453164583972412398765793156248658742139321875694976234581845961327 +1-8--6---526-73--4-93--18-62345--6-9--9--432---------591-43-2-84-21--57------2--1148956732526873194793241856234587619859614327671329485917435268462198573385762941 +----96--8923------6854-79--7-9--4--38---3--4-5-4-82-7-4-6---31-2-1-6-4---781---9-147396258923851764685427931769514823812739546534682179496278315251963487378145692 +---264-----1---52-2--5713-8-2--13--969-85----8--49--5---632-8---3-78-41--8-1---6-358264971471938526269571348524613789697852134813497652146325897932786415785149263 +------437--524----4--1-9258-9--7-5---1-35-8-9--79--1-476----9-29---2-3-6-4---6-15129685437385247691476139258892471563614352879537968124768513942951724386243896715 +-3-8--47-91537------7---9----6--8-34---23--162-364----569--3--27-1-8-345--4725---632859471915374628847162953176598234498237516253641897569413782721986345384725169 +-24--13-5--7--84--16-----87-891-7--24---86-9-2-----1-891286-7-------523-735--98--824971365597638421163542987389157642471286593256394178912863754648715239735429816 +248-1--65--152---9-9548---3-------579-6-3-481-3-14--96-8-6-4-12------9---2985---4248319765371526849695487123412968357956732481837145296783694512564271938129853674 +57-6321----3--5-8-4-6---3-2---3----1---9---3-13--84-9676-24---8--186-27-2-915---3578632149923415687416798352894376521657921834132584796765243918341869275289157463 +4-258-7----3---------2635----9---4-26-7--81-55--1-28---7-621-84-1--9-25-24--356-1462589713853417926791263548189356472627948135534172869975621384316894257248735691 +679-8-3-5-14-----92-549---1----7------25-6--856892--7-12-64-58--867-3-1-----1---6679182345814365729235497861391874652742536198568921473123649587986753214457218936 +-2--6-------9-34-5--4----96--9---5---4-6-2-1--13-97---4-1238-797-2---3--6-8-49251925164738186973425374825196269381547847652913513497862451238679792516384638749251 +4-5----6-2-1-397488-94265-33------7--9-14-8--68--53----4---1---9-----3-1---36--97435718269261539748879426513314682975592147836687953124743891652956274381128365497 +7-4---85-----6874---8-45--1--32------4-53-1--269---43-982--7--43-6459-1---5---379794123856521968743638745921153294687847536192269871435982317564376459218415682379 +--8---9729-6428-5-231-7---47-4---38-----3674---3-84--5162---49--4-8-95----91-----458613972976428153231975864724591386815236749693784215162357498347869521589142637 +--46-19-5-5-------2-9-481--5-84-23--6-7------1423---58--31-45-6--59-6--28-62--491784631925351729864269548173598462317637815249142397658923174586415986732876253491 +82-43---9-4--6----7-39-1-58---2---6-3--51-----5---482157--4-9824--75-13-2--1---47825437619149865273763921458914278365382516794657394821571643982498752136236189547 +------75937-2-----8-4--7321-9--4-2--52--8-1-44--9--8-7--6-7--82-3---45-6----694-3612438759379215648854697321798341265523786194461952837146573982937824516285169473 +3--25---7------6137-4-19---27-6---5-85----974-4-78--62----27-36------28-12-8637-5318256497592478613764319528273694851856132974941785362485927136637541289129863745 +6---8-3-519----2--3-529-64197--28-5-5---49-87---7--93----4-28-3-5-9-1--4-46-----9627184395194536278385297641971328456532649187468715932719452863853961724246873519 +5-------8-1-49--3-23--65----9---4------52-8-11-----45-3-197256-9-6-----27-4-51389549237618617498235238165947895314726473526891162789453381972564956843172724651389 +--9--2-84-6-5------72---6-192--6174383-4259-614-7-------4---8---9--86------95--67319672584468519372572348691925861743837425916146793258654137829791286435283954167 +-1------279---8-----69--74186-1-45--2--6------57-834-993---6-78-7---13-66--3-9154314765982792418635586932741863194527249657813157283469931546278475821396628379154 +9--8317------946-82-3---1--51---2-4--26-1-8-53-8-----114---65--892--3--763--78-1-964831752751294638283567194519782346426319875378645921147926583892153467635478219 +--8----7----3-------6-15-4-4-186-7--879--4-166--197-2491-436-8-765928------5----9598642173147389652236715948421863795879254316653197824912436587765928431384571269 +674----92-9-3-2-1---26-------8-391------87-595-9----83486-5-9--2-7943--1--3---425674815392895372614132694578728539146361487259549126783486251937257943861913768425 +---8-37--687--41---45---2-6---6-8--7--3-79-5--7-23-6-9-16-82-7---8346--1--2-579--921863745687524193345791286259618437163479852874235619516982374798346521432157968 +--4-9-57---1458-62-5273-8-418-6--4-7-7-5-46--9-----2-53--------52--671-----3857--834296571791458362652731894185629437273514689946873215367142958528967143419385726 +6-8---93--------469436-57-8---7-418248-1--69--9-8-6-7-76---38--5-2-18---------359628471935175389246943625718356794182487152693291836574769543821532918467814267359 +-6--7-5-89----523-51----7-66---1---23--82-6-4--16--9-3-9-3-6427--279----------189263179548978465231514238796647913852359827614821654973195386427482791365736542189 +4-158-9-------6----294--5-6-3-894-61---72-----4816-3---943--6-2-526----8-8-21-459461582973875936124329471586537894261916723845248165397794358612152649738683217459 +61-5-9------6--2---83--7-9-76-43-829---81-5--54897--163----8------7---63-56---7-2617529438495683271283147695761435829932816547548972316379268154824751963156394782 +2--3-4-15-1--8-32----2--6-478-4-5---624--97-------21-6-6-9--47194--2-56--5---328-276394815419586327835217694781465932624139758593872146362958471948721563157643289 +-68--9153--5-------438---2-3--15---9---9-86349-4-37815-5-78---2-----6-8-8125--7--268479153795312468143865927386154279571928634924637815659781342437296581812543796 +39-----57-26--741---4--39---1--7983-8--3-5--4-37-----1--953-1786-1--2-----3--8269398421657526987413174653982415279836862315794937864521249536178681792345753148269 +--28-3145-517--8-9-849--2----725139----6-8----253-9--7-185--9-4----9----53-4-2--1972863145651724839384915276467251398193678452825349617718536924246197583539482761 +2-3--1----89-2-613------4723---8-5-7-5-2--19----54-3-8--8--42-91-79--8-64--8----1243671985789425613615398472324189567856237194971546328568714239137952846492863751 +-4---1-2-31--28-9-2---694---7--53--2--591--6-----72-54---346---9-2187--676----1--649531728317428695258769431476853912825914367193672854581346279932187546764295183 +-7-4-9------37-9-61------4--15-6-----24813-79-879-5162-9--3----7----84-186-----95576489213248371956139256847915762384624813579387945162491537628752698431863124795 +39742-5-81-----6-3-648132-7-7-3-5-2----64--719-------4-45-----22-91-4-------5--3-397426518182579643564813297471395826853642971926781354745938162239164785618257439 +-3-689-2---54-2-631--5-7-4--5-26------71-5-8-61--48--546-----795--82----3--9--652734689521895412763126537948958263417247195386613748295462351879579826134381974652 +4-2-583-656--2--97---6--2--658-7-4-1-4-5---68------7--7168-95--23-1------842--1-3492758316561324897873691254658973421347512968129486735716839542235147689984265173 +2--68-5--17-23--8--5--7--2---97-8-6--4-91---2---42--958-2347--6---561---46----7--293684517174235689658179423329758164546913872781426395812347956937561248465892731 +9-68--4-5-----6---4--93-28-6-57--8-4--36--5-989452---3---15-----62348--77--26-3-8936812475258476931417935286625793814173684529894521763389157642562348197741269358 +-8----9-5456-237-13-95812-462-3-8-------7--5-7-3-----2--47-5-2--6------3----39-48281647935456923781379581264625398417198472356743156892834765129962814573517239648 +8-67-194337----1--9--2--8-6----142-8-6--37--4-49-----775-12--6-6--47--25-----578-826751943374896152915243876537614298268937514149582637753128469681479325492365781 +4-27-869--39-41-8--1--5---------35----4-76----6-1--379--3--712--26-1-938--1-624-7452738691639241785817659243178923564394576812265184379543897126726415938981362457 +-----95-29-2--5-368---461793-91--768-76--8--31---------415--8-75----7---2-786-35-764319582912785436835246179359124768476958213128673945641532897583497621297861354 +-2--79-5-7--1-------9--5762-4--563--3817-4---65793-4-8--------55364---172----7-83823679154765142839419385762942856371381724596657931428178263945536498217294517683 +2---75-968--9-4-13--16-8274---5-----75--83-6-----974------5--8996-84---2---769-45234175896876924513591638274489516327752483961613297458147352689965841732328769145 +6-75-8---8---9--4--34--2658---2--8------8-1---8261--791-58--2-42---359-6-639--5-7627548391851396742934172658719254863346789125582613479195867234278435916463921587 +--3--85-18-1--49-2259-613---862934--4---862-3----17------8-----9---35-265-8--21-9743928561861354972259761384186293457497586213325417698612849735974135826538672149 +---256----6-78491-7-----4-6--1--7--55---691----9-182-7--697--3--1--32--4-53-41---194256378365784912728193456481327695572469183639518247246975831917832564853641729 +31----97--7--8----4--3--6-5-4-7-5-------481-76------5--349-7216-2586374--69-1----318526974576489321492371685941735862253648197687192453834957216125863749769214538 +-4----372-1-9-346------2----547-1--6-6-4--5-3-93--8---6-9-1-73543--5--8--7539--24946185372512973468387642951254731896768429513193568247629814735431257689875396124 +6--18973-9-8---5-1-4--7---9-9-2------21-5469---69-----83-4-1--6--96-78-2--48-531-652189734978342561143576289495268173321754698786913425837421956519637842264895317 +---2-76-8------37-1-7638-257-2-8-5--3-5---249--9-238-76---75--229-4-1---------186953247618826159374147638925762984531385716249419523867631875492298461753574392186 +---6-814-1---53-296---9---8----162--46-7--9--8-1--2-67-46-8-7123--52----7---6-853293678145187453629654291378975816234462735981831942567546389712318527496729164853 +-534-8-7--94-26-1-1829-73--8---42-----9-75-26---6------1-78--49-68294----47-6----653418972794326815182957364876142593439875126521639487215783649368294751947561238 +15---84---3-4---8-89-3-6-5-78-----2426-7----83-5-2--1-416---------1-73--973-85--1157298463632451789894376152781563924269714538345829617416932875528147396973685241 +-916-25--3--49--1-5-----9-224----69---69----3-532--7-86871----9125-49--6---7---85891672534362495817574318962248537691716984253953261748687153429125849376439726185 +2-759-----3------4---3-7-9-4-3--6--917-----26----5--7-8247-196-----2-14-79-64538-217594638936812754548367291453276819179483526682159473824731965365928147791645382 +691-8-4----7-----1---2---6815983--4-3-41----6-624---835--91--24----4--7-9-83-26-5691783452827564931435291768159836247384127596762459183576918324213645879948372615 +35---29--62--7-154-1---------51-4-7-----27536-3758-412----6-2--492--1--81--2-8-9-354612987629873154718495623265134879841927536937586412583769241492351768176248395 +---8-6-4--8----3--1-654----96----21-----5--6-3-8--24--7136-9-2464-235-78----1--39537826941482791356196543782964378215271954863358162497713689524649235178825417639 +437---56859--8-123---5--7--3--16-95484539---11-9--483-------2----3-1--97--8-4----437921568596487123281536749372168954845392671169754832914673285623815497758249316 +--4267-5--7--5-24-2-------96523-18-4819----32-3-8--56-7---18-2-586-92--3-----5---394267158178953246265184379652371894819546732437829561743618925586792413921435687 +7418-356-----4-78--6397512--2------73-4-69------3-26------9-3--2-75----6-38---4-5741823569952146783863975124526481937384769251179352648415698372297534816638217495 +--26-13-884-5-91----97-8-54-2---3-----1--2----3597--212-8---5-7-9--6-2--1--285-46752641398846539172319728654927813465681452739435976821268394517594167283173285946 +8-23---19--1--7-637--1----8-5-6--38----57--414---1--52------276-13-6-8946-4--8---842356719591287463736194528159642387328579641467813952985431276213765894674928135 +------91687--21---9--5-38--4-3---782--78-456-5-86---3--------45----8569-1-54963-8352748916876921453941563827463159782217834569598672134689317245734285691125496378 +--9-18-5----3----8587-9-1---2--79-4----84-36264-1-28978-34--7292-6-8---59--------439718256162354978587296134328679541791845362645132897853461729276983415914527683 +--9-----4---465219-2--39678-18--6593-369528--5--3-8-62-5-2-------------7-8-6--43-169827354873465219425139678218746593736952841594318762357294186641583927982671435 +8-6---5-9-94------25--196489-8--3-54375-42-----2-95-8-5---6--92---35-7-1681------816234579794586123253719648968173254375842916142695387537461892429358761681927435 +---1-459---927--8-3-----4---74---8--83-54---------7-2-2934-86-75-----2-1-416259-8627184593459273186318956472974362815832541769165897324293418657586739241741625938 +-7-1-42--5--98--1-13-2-7-----9---5-2-5-692-78---345-----35-8--77----93--8--7-69-4978164253524983716136257849649871532351692478287345691493528167762419385815736924 +---375---81-649-5-9-5-----63-6-148----7--61--1---58--7--9-23-1-----9127--2-86-5--264375981813649752975182436396714825587236149142958367759423618638591274421867593 +94---16-33-1--6---625-897--4----7-29------5--7925--4-6-----21---1479-3-22-71---85948271653371456298625389741453617829186924537792538416539862174814795362267143985 +--6-957-1--2-8134--5-2746-8--------33-4--896----7--41-----37184----16-3-8-1-2--76486395721972681345153274698617942853324158967598763412269537184745816239831429576 +6-3---4--2--7-3--97-9--21-51--92-3-6------8--9--358---5-7-89-63-26537-1-39--4--7-613895427254713689789462135178924356435671892962358741547189263826537914391246578 +----78-598--961-4-2-1----6-51--946--67--5--3-982-1---4-25--6-9336--2-7--1-9-----6436278159857961342291345867513794628674852931982613574725186493368429715149537286 +3952----88-7--15-4--48-------25389-----7---8-1839624-773---92-5------7--5491-7--3395246178867391524214875639472538916956714382183962457731689245628453791549127863 +--915-8726-2--3-----1--896319----75---4--1--9-36--7-24-17---2--8---154---2-7-9-18349156872682973541751428963198342756274561389536897124917684235863215497425739618 +869-3175--45-792182---48------9-254--9-7---836----5----53--7---7-6----25---8--3--869231754345679218217548936138962547592714683674385192953427861786193425421856379 +---3-85--49----72-352--41--5--78-26--8--56--9---2-3-5--7--956---3-842-1-12--37--5716328594498561723352974186543789261281456379967213458874195632635842917129637845 +2-9---5-715--9---------3-1-42318--9556-94-378--763------2-5--------74-56-4---91-3239418567154796832876523419423187695561942378987635241692351784318274956745869123 +395---4-1-4----5-881-95-2---53----1--8743---94---------34-2-9-59-8--61235-1-8-7-6395278461742163598816954237253697814187432659469815372634721985978546123521389746 +631----5--4-57162---7--319837-2-8-----47-5-8-85----37-----9--6-4--65---776----912631829754948571623527463198376218549194735286852946371283197465419652837765384912 +---9-1-------68-945-942-1689-4--26--1-2734-----3-9641----685---43-----578---4-92-648971235321568794579423168984152673162734589753896412297685341436219857815347926 +37--98--5---1-----5-2--71-8--9-325872-8--19--7-5--42-1--475931-----26---9-7-13--4371298465896145723542367198419632587238571946765984231684759312153426879927813654 +-6-7-----8-1-6-7-972--93-6545--8-9373-79--5---8----------4--2-624-6--35--9-3-1478569714823831265749724893165456182937317946582982537614173458296248679351695321478 +--98-15--7-----6-82-45--1-98-6-592--3-----------3489---2-184-56-1--7-89--6893-4-1639821547751493628284567139846759213395216784172348965927184356413675892568932471 +6-3-98-7-7-1-6---2954-3-8--4--973--8----149-653------7-65--72-92-7-5--1-39----7--623198475781465392954732861416973528872514936539286147165347289247859613398621754 +-9146--7-7-6----4-3542---18---3-------9-15-2-51294-3--97-65-2-12-5-387-----7---5-891463572726581943354279618487326195639815427512947386978654231245138769163792854 +5----6---743-9--26619---538----8-9---25-7-3--4----------7-23689268-17--393-8--2-7582136794743598126619742538371284965825679341496351872157423689268917453934865217 +26-4-1-59-5--371-6--15------7-9-8621---7-------6-129----58-429---8---4-53-26--817267481359954237186831569742473958621129746538586312974615874293798123465342695817 +75829-1-4-6----5-39-36157-2--7-54-2--8----9-----93-67----4---5-82--69---4-9---2--758293164261748593943615782697854321382176945514932678136427859825369417479581236 +625-1-39-381---4577--3-----93468-5----659-14315---46-9-97-6---5----4---12--------625417398381926457749358216934681572876592143152734689497163825568249731213875964 +47-2-89---92-6--7-8-39-------1--5398---8-416-3-7--9----69--2-4-7185---3--34-9-58-476258913192463875853971624641725398925834167387619452569382741718546239234197586 +6-7-4-8---5-------18-5--467-2--7----5-92--7-473-4-6-28-4--69175----1-3-231--2-68-697142853453687291182593467824971536569238714731456928248369175976815342315724689 +-49--2-5--6-----138516-394---3---5-8--831---9-2486----2-7-38-9-43-7-----9---26-37349182756762954813851673942193247568678315429524869371217538694436791285985426137 +---7--9288--3596--9761-2--4---6-8-5751-----8676-5--4----32------27-6--4----913-62351746928842359671976182534234698157519437286768521493693274815127865349485913762 +-17432-8----856---8-4-----25--2--1----178---52-631-7-----14-95--9--278--4--69--1-617432589329856471854971362578269134931784625246315798762148953193527846485693217 +-9------38--5431--1-38---4-5-8--2-6--12-7638563----972-6-93-528----8----3--72---4496217853827543196153869247578392461912476385634158972761934528245681739389725614 +-9-523-611---4-------719438--839-6-236---218927-168--3----5-----8----9---2-6-43--894523761137846295652719438418395672365472189279168543743951826586237914921684357 +4---5----6-9---34---79--2-897-3-416223--6----18-52947---2----8-----756-47--4-8---428753916659812347317946258975384162234167895186529473542631789891275634763498521 +---8--3---6-23--7-37----49825----7-171--95-----6-725--134---2--6--7249-3--7--1854591847326468239175372516498259683741713495682846172539134958267685724913927361854 +17-269-38------6-1---1-892-81--2-3--36----8545--68-21--9-31--8-------792-857-4---174269538928537641653148927819425376362971854547683219796312485431856792285794163 +53--467-----1-----7-8-3-4-1--6-853478-4-1---63-7-2-1-8--2367-15----98---6-3-512--531846792469172583728539461216985347854713926397624158942367815175298634683451279 +--274-6-----29--343-4----27--7---8131-9874--68253--4--598----41-4--17-6---1--5---912743685756298134384156927467529813139874256825361479598632741243917568671485392 +---7-39-29376---45-5--8-7--7----6---1---7-----28-19-763-2--8-946-5--71-38-934-6--481753962937621845256984731794536218163872459528419376372168594645297183819345627 +7648--53--5--9---4---4-61-74----8---2---4-----19-2784-9-763---88-5--46-26-1--937-764812539158793264392456187473568921286941753519327846927635418835174692641289375 +---3----6746---21339--2-4588-9--7-4227349-8--4--81-739--4-8-69---2-7------------5528341976746958213391726458819637542273495861465812739154283697632579184987164325 +--5---9-18--7-9--36-4--38-71-983---4--2---------962--8-7--5--8991--287-6-4-69713-735286941821749563694513827169835274382174695457962318276351489913428756548697132 +8--5-6-27-7-8-14594--39--16---96-5-------3---9-328---16-1-58-4-----3--68---619-35819546327376821459452397816127964583568173294943285671631758942795432168284619735 +18----62-3-56---49--98----14--1-6-878-6---4---7-28-9---543-------1-28764--87--153187493625325617849649852371492136587816975432573284916754361298931528764268749153 +---736----7-82154---1---8-7--357-4--4--1----35--24-6-1-4-69---87---15-9-93-48----854736912379821546261954837613578429428169753597243681145692378786315294932487165 +6---384-2----2-7--8-54-1-96983-5--2------49-5--7-----3368-152--1-2--3--9-94--25-1679538412431629758825471396983157624216384975547296183368915247152743869794862531 +-35-842-----2--8-38-96---4----39-58---8--5--6--3-261-7--4571--8--1----7298-432--5135784269476219853829653741612397584798145326543826197264571938351968472987432615 +---3-----2-4--75-3-71-854--9--748-31----26---7-8-319--4-7--93-28---127545-2--3--8685394127294167583371285469956748231143926875728531946467859312839612754512473698 +783-16-2---4593--7----8-643-15---47-----7458--78-5---29---6----86-7--2-----13976-783416925624593817159287643315928476296374581478651392937862154861745239542139768 +27---1---46-83259-35-79-142--2---6------85-195--96----1-3---97---53---269----8---279451368461832597358796142892147653634285719517963284183624975745319826926578431 +-4-8-5--16------2-----29-74564-1283--9257314-7-----95-----8---51-62-7----28----1-247865391619734528385129674564912837892573146731648952973481265156297483428356719 +8-6--4--21-3--94-8--2-78163--9132-472-1-479------85---71--263-----4-----3-8--16-4876314592153269478942578163569132847281647935437985216714826359625493781398751624 +---524----5-36197-1-----3-5-2873------5-19-8--7-48---32--95-7----967-4-1--71----2793524816852361974146897325628735149435219687971486253214953768589672431367148592 +-2968--5--4-2---8---857-4---1-93---83---25-7----81--34-71---2-----749---8-5162--7129684753547293186638571492714936528386425971952817634471358269263749815895162347 +34--789-17-1-4--62---1--4--187-2-3-5--37---18------2---384--5-94-95-----2158-67--346278951751943862892165473187629345923754618564381297638417529479532186215896734 +-4------9--765--8--18-34---35------178-52143-62--47895--5--6------41-9-7-7----64-546182379237659184918734562354968721789521436621347895495876213862413957173295648 +9---8-237-5-4291-6281-----4--51-4-9--19---762-----7--15--94---3-9863-----43---8-9964581237357429186281376954725164398419853762836297541572948613198632475643715829 +95---386-6-3--8---8741-92--297-4-58-------4--5----2-97-3592-67-7-2-3--41-----73--951273864623458719874169235297641583318795426546382197135924678782536941469817352 +71-4-5-------72-4---2---8--831-67-94-74859-32---1---86-67---91-28--9-4-----5---7-716485329358972641942613857831267594674859132529134786467328915285791463193546278 +--------21--4--87-478-2--615-36-----6827-9--471-3---568-4-3-92----8----3-31-47-85396178542125463879478925361543612798682759134719384256864531927257896413931247685 +8937514-67--982--1-----4-9--841--2-7--------41624-38--6----9---218--79--4-93--6-2893751426746982531521634798384195267975826314162473859637249185218567943459318672 +5341-9--2-684-----7-16--8-4--------3--72--15-152-3-4-767--215-8-25-6-39----5----6534189672268473915791652834946715283387246159152938467679321548425867391813594726 +---5-3-12398--------2-64--89-6-271--251---4-74---9-2-6-248796-376-------8-92-6---647583912398712564512964378986427135251638497473195286124879653765341829839256741 +1-8-34---------71269--2---3-7-39--6-53-4---79---65-834------95-9-3----2775291-3-6128734695345869712697125483874392561536481279219657834461273958983546127752918346 +-3-68-1-7--72196--5--43-8--7---2-3168-1---4-23---96-----3-61----4-35-9--1-59-8--3932685147487219635516437829759824316861573492324196758293761584648352971175948263 +---4-2-36491--------658---1-659718-478-------1-98-6---5---9-6-8623---5-79-876-3--857412936491637285236589471365971824782354169149826753574293618623148597918765342 +-236------5------98---2-315-3-5--7-8-728---36--827-541-8615-4----9-8----34-7-61-2923615874157438269864927315431569728572841936698273541786152493219384657345796182 +---1238-7-27-493---4--8-2-9---465---1-6----32-98--2--5---97----5742-89-62-9-54---965123847827549361341786259732465198156897432498312675683971524574238916219654783 +291-6-53-346---1877----3-----2-51863538-42-1-61-8---25-57-2---1----8---69--------291768534346295187785413692472951863538642719619837425857326941124589376963174258 +--4---5811-3745-6-529--87---7-41---6--19-----935----178-7----42----32-78--2-746--764329581183745269529168734278413956641957823935286417857691342496532178312874695 +---8---5-4--915--21562348-7-18--29-4--------82796-81--9214--5--8-5--67-97--5-----392867451487915362156234897618352974543791628279648135921473586835126749764589213 +97-5-36148342-157---69-4-------4-2---85----6772---5-----8--7-------3679-3---5--42972583614834261579156974328619748253485312967723695481598427136241836795367159842 +--96-7---4-1---53---2--56949--4-6----3--98-7-8-417-9---9--6124-2--754-6---8-39-1-359647128461982537782315694975426381136598472824173956597861243213754869648239715 +4----69-5-92--3----3-49--2898--52-----68----9-1763---27-3-----1--832459---9178--4471286935892513476635497128984752613326841759517639842743965281168324597259178364 +----3-8---9--68-4-84----71365----4-242-5-1-----96-45----42--357287---6--9--7461-8512437869793168245846952713651893472428571936379624581164289357287315694935746128 +17----8---98-51------7---6-4---67-8----12-54---9---1--94681-3-7--5---6-221-5364-8174693825698251734532784961451967283763128549829345176946812357385479612217536498 +75-34----------9239--1-87----56-78-28-7--2--16-1---547---87-2-9-------863-829617-752349618184765923963128754435617892897452361621983547516874239279531486348296175 +-94-28--5--2-6---9-15--96------172--2479-5-1-861-------79----63-38-7--9-52-3----1694728135382561749715439628953617284247985316861243957179852463438176592526394871 +2-4--1-383----------85-3146--92--481---9--6--4-6--539--9-3-----6-31728591--4892--264791538315648972978523146539267481781934625426815397892356714643172859157489263 +4----97---18----9476---85-329-8-4--6--7-91-2---6---8-9354--29-------365-68291-4--423159768518376294769248513295834176847691325136527849354762981971483652682915437 +-----6-7---1732--85731486-9382--17----9--7---7-65--9-2--------663-8--2-12986-53--824956173961732458573148629382491765159267834746583912417329586635874291298615347 +-7-5---46-9-2-----------3--71---569856-892-7---96-72-5-2--687538-----4-----459821278531946396284517145976382712345698563892174489617235924168753851723469637459821 +--2--413--54---8-9-9--8-4-75--9--2-3--371-9-6--9-5---1------5721--82-----2-3-9618782694135654137829391582467517946283243718956869253741938461572176825394425379618 +2-65984-19-7-3----5-14-7293-1---596-35----7-44---8----1--6-4------81-34--9------6236598471947132685581467293712345968358926714469781532173654829625819347894273156 +25-3--6-78--4----2-93---84-14-8-35----294--1---5---4-3---6---756781----4531-94--8254381697816479352793526841147863529382945716965217483429638175678152934531794268 +-274359-----198---9-3-----53--68-2-----32-16--6-5-7-9---297---15-824--7-1---5--2-827435916456198732913762845391684257785329164264517398642973581538241679179856423 +-76-8934194----8561-3--69--4--86---2----3-----9-54-6137-43--2---5------43--124-7-576289341942713856183456927435861792621937485897542613714395268259678134368124579 +1792-85-----95---7435------5-28----48-137--2---7-4--8-9-8---46-6-3-9-8--72---6-5-179238546286954317435617298592861734841379625367542189958723461613495872724186953 +76-2-35---2-196--7-3-8-5-4-----62--5-9-5-48--5--93--64256--1-7-18-----36----29-5-768243591425196387931875642843762915697514823512938764256381479189457236374629158 +31927-5---58--32-92--59-83169--2---5----3---8--4------871---356542-8-19---61-----319278564458613279267594831693821745725439618184765923871942356542386197936157482 +136---------6-82--298-57-6---23----5-592-1--7-67--53---418---5-72--4---6-85----34136924578574638219298157463412376895359281647867495321941863752723549186685712934 +---975--19-812---35----------14-9--23-7--21-46-----9-8-89-514-7-4--6--19-3-79482-463975281978126543512843796851439672397682154624517938289351467745268319136794825 +43-65-182-1-7--34--86---5------2573---4-68-2-1-2----6-----9-6-3-4-2-6-97-695-7--4437659182915782346286341579698425731374168925152973468721894653543216897869537214 +74516-3-2--6----14-329----5-29-76----7--14-3--1----57-2-1-8----98-7-1--33--6-9-81745168392896235714132947865529376148678514239413892576261483957984751623357629481 +--56-3-42--72----1----7159----5-74---79-8-2--5-1--4-78--87--163--346----79-1--854815693742967245381324871596682517439479386215531924678248759163153468927796132854 +4632--1-----3--94-529-716---9----5-1-8-71--2-1-26-5--975-----16--61--8--9-85--4-3463298157871356942529471638397824561685719324142635789754983216236147895918562473 diff --git a/apps/sudoku/sudoku.hard.txt b/apps/sudoku/sudoku.hard.txt new file mode 100644 index 00000000000..2a70aad7559 --- /dev/null +++ b/apps/sudoku/sudoku.hard.txt @@ -0,0 +1,200 @@ +---15962-----2-89-95-86--7-8--9-634---35-81677---1295-12--845------91--6---2-----478159623361427895952863471815976342293548167746312958127684539534791286689235714 +29---3---------9456-89--213-2-8--57---7-9--36---47-82-53--6-18-8----469--4--8-3--294513768713628945658947213429836571187295436365471829532769184871354692946182357 +-9431827--------98---79-1-3-79--1--2-28---567-5--879-15-764------3-297--------314694318275731452698285796143379561482128934567456287931517643829843129756962875314 +4-7--1-322----------3-92157-8--2----1--3784--5-2614389--8-4-713----8-5--7-5--92-8457861932219753846863492157384925671196378425572614389928546713631287594745139268 +--58--937-769-------3-156845-4----6-6--3-48-5-8-15--2-9-74--2-6--25--3--35-----41145862937876943512293715684534287169621394875789156423917438256462571398358629741 +-65--84-77-8--1--61937-48-------56-46314---8---2-----13-4-57-69---8--2--9--1-35-8265938417748521396193764852879315624631472985452689731384257169517896243926143578 +-6-9-372---86-43---3-2---8-3--7-5-1-85-3-1----4--62--54--1296-3---478-----2---14-564983721278614359931257486326795814859341267147862935485129673613478592792536148 +---1-72-4-61432-79------31---837-4-1-39---758-17-4-9--------642-2-91---787-6-5---983157264561432879742896315658379421439261758217548936195783642326914587874625193 +8--3259-4--5----82---781---76-29-----8-5-46--9--61--2--9--5--7---784---9-4-93--51876325914135469782429781536763298145281574693954613827392156478517842369648937251 +--3-----7-9-16--8-----57-94936-781-2--4---5-675-6248-917------83-874---------1-6-583492617497163285612857394936578142824319576751624839179236458368745921245981763 +--789--1-5--243-6--9-61--45-8-97--3-7-43-1--99---64-----9-36---4-1----82--5-2-496647895213518243967293617845186972534754381629932564178829436751461759382375128496 +--9-568376-8--2-9-7-3--1-629-7-25--1----64-----173925-57--98--3---2-----3-6--7-28129456837658372194743981562967825341235164789481739256572698413894213675316547928 +-38-972----2-8493-9-63------9-----75-7-91--2-86-74----62---85--4-----19-5174-96-2138597264752684931946321758291863475374915826865742319629178543483256197517439682 +-7--4--36698--1-24--------97--45--9--4---2-----5-9-487362-14---9846-51-31--98-6--571249836698531724423867519736458291849172365215396487362714958984625173157983642 +-----4-----678--419--15-----2--98-65-58-4-----49561---2918-63---739-5--8-6541---2712634589536789241984152736127398465658247193349561827291876354473925618865413972 +85169-----9--73--16372-1-592---3-746--68------4--263---------3-7139--86---4-6-51-851694273492573681637281459289135746376849125145726398568417932713952864924368517 +281---------48-7--7435-6--8-7--1--6--586--1---3627--5--64----91-29-4---65-7--9-8-281937645695481732743526918972815463458693127136274859864752391329148576517369284 +8-791-4--5--8--1----146---53--72--1--2--846-----13-25----657---6-3-----8-14398-6-837915426546872193291463785365729814129584637478136259982657341653241978714398562 +9-3257-41--8-14-7------935-29--48-------3-2-735--2-1---3286--1-6--4-3----891--63-963257841528314976174689352291748563846531297357926184732865419615493728489172635 +3-6-9---75-98--162--2-------6--12-8----98-536-834-6921197-2-4-----5----92---49-7-316295847579834162842761395965312784421987536783456921197623458634578219258149673 +-8--14392192-584--3-49--8-1-61-8---4----9---37--------235---946847-3-21-6----2---586714392192358467374926851961283574458197623723465189235871946847639215619542738 +-1837---6-9--8----2-65-1-43--7----9--241-----8---4-372--27---85-8-45-637-458--21-518374926493286751276591843357628194924137568861945372632719485189452637745863219 +48--75--1--9------7--6-1-9426-------59-7-8--38173--95-3--1-7-699--4-6-8-65-8--417486975231139284675725631894263519748594768123817342956348127569971456382652893417 +--634----5--97-3-2-----2---45-23-1--89-6-47--3617-5-8--1--674-574--2----62-453---276341598584976312139582647457238169892614753361795284913867425745129836628453971 +--1-6495-5-6-931---925-----7834-92-1-4----79-12---68--26-34----3--97--1-9------38831264957576893124492517386783459261645182793129736845268341579354978612917625438 +-2-56--4----7-8-239-------8-86-----44-938---------6-5-3-----7-5-781534-25928-46-1823569147165748923947231568286915374459387216731426859314692785678153492592874631 +3--65--7----73-58--5--412----712---88--4--7--4-697-1--2-3-----4-71394-2----286---328659471164732589759841236597123648812465793436978152283517964671394825945286317 +8---2-6-1-5-9---4227-----59--7--5-686--1-4-355--7---1---18-9---------487-8--56193894523671156987342273641859417235968628194735539768214341879526965312487782456193 +4-2-----5--84-79--9-78--6-328-746-3--94-5--7-7-691-42---9164-----------1--3-892-4432691785568437912917825643281746539394258176756913428829164357645372891173589264 +42-16--75-8-5-4-6-651-79-3--943--5-7------2--2154-----9--64-3-15-69----4---75-8--423168975789534162651279438894326517367815249215497683978642351536981724142753896 +6-8--259------68-21--7-56344---------35--19--9-6-4-1538-351--292----3----74-2-3-1648132597357496812192785634481359276735261948926847153863514729219673485574928361 +-2-6-359-5--489-6---71-2-3-2---96----1-2-7-8-7-983-2----2-68---9-3---41---5--4629428673591531489762697152834284596173316247985759831246142968357963725418875314629 +-2-6-4--35--39--7-13-75------124-5---4-58-96--5--6--1----129-----6---72-2--8764-5729614853564398172138752649691247538342581967857963214475129386986435721213876495 +-5-8---973781--46--294-78-38-7--9--6--6-139-8----5-7-496--74--1----2----732-----9654832197378195462129467853817249536546713928293658714965374281481926375732581649 +-31--246--4---------67-41928--4------2-168--3-94253786---8----9-19--78-4--83--621931582467247916538586734192863479215725168943194253786652841379319627854478395621 +--7--3-29-48-----62-9-6458775-----4--2-84--5----65--93----1-9-4--24-531--143-62--167583429548729136239164587756931842923847651481652793375218964692475318814396275 +-47---3---91843-76-856-14294----5----1-----65---36-1-21--45--9--6----2--93-7-6---647529381291843576385671429426195738713284965859367142178452693564938217932716854 +--1-35-7-364-729------4----9--3---64523---79-47695-8-31----4-87--7---2---8-716-4-891635472364172958752849136918327564523468791476951823135294687647583219289716345 +-9--16--3--542--1--81-39---8---549----9--2--8--4-976-2---685----5-27349-2-----3-5492716853635428719781539264826354971379162548514897632943685127158273496267941385 +-9-2-------19------24-57-9168-7-41----91-32-6--76-5-481--469-83-7--3-9--9-6---4-5795216834361948527824357691683724159549183276217695348152469783478531962936872415 +-84---2--2-9-78------4---1----86-73--3--14-2-9-----8---687513-27-----1-619328-5-4384195267219678453675423918541862739837914625926537841468751392752349186193286574 +1893-4---6-71--49---39-6-7--64------7-5---6-939-6-2745----192-8572------9----536-189374526657128493243956871864597132725431689391682745436719258572863914918245367 +89--3--21-4-81----72194----4---------17--9----852---471-965---8-7412---32-87936--896537421543812796721946835462375189317489562985261347139654278674128953258793614 +8--3912-------68--6-1-85--4-8----5----3--21985-68493721-295---3--5------9--6134-5854391267397426851621785934289137546743562198516849372162954783435278619978613425 +416-29--3---7---547536----9--4---9-169-3-14----829--6-84-1--7-5-21---39-3--9----8416529873982713654753648219274865931695371482138294567849136725521487396367952148 +--58--743--793----86-4--9522-4--95-8-86-5--1----2-8-9---23-71-9--81--4------84-26195826743427935861863471952274619538986753214351248697542367189638192475719584326 +-691--28--17--5-9--2-9--5---9435----1-27----3-83-9-4--246-7--19875-----------274-569137284417825396328964571794356128152748963683291457246573819875419632931682745 +-16--78----3---25-4283-56-1-6743-----4-52--1--5-----481---7359-6-59-----79--541--516247839973186254428395671867431925349528716251769348184673592635912487792854163 +6-21--4-33-79---589-5-836--531--6-82-2--9-1-----3-15-71--6-----4---1-----7954--16682157493317964258945283671531476982726895134894321567158632749463719825279548316 +7--8-6----6157---3-593---76----6-41-62--1--3-19--85---9-61243-8-----9-62--5-38--4732896541461572983859341276587263419624917835193485627976124358348759162215638794 +--7-63-5-------4728-59-2----56-4---3-31---985-8--51-64---5-6-47------6-1-6271453-127463859693185472845972316756849123431627985289351764318596247574238691962714538 +32-1-----7-42--1-31967-85--567-9-4-14--5---67------9--65--2--89---6--2---42-573-6325149678784265193196738542567893421439512867218476935651324789973681254842957316 +8569-2-74------89--79---5-67-83--6-9---4-87136--7-94--9-4--5--7------265-12-37---856912374423576891179843526748321659295468713631759482964285137387194265512637948 +8----------73-89416-1--9-784-89567239--1726---2-8-------26--197---2--4--1-4--38-2893417265257368941641529378418956723935172684726834519382645197579281436164793852 +---2-4-31764------3---95-7-9-6-381--123---58---5-6-39-6-73-9----98------53-78694-859274631764813259312695478976538124123947586485162397647329815298451763531786942 +96-175---13--9----2---6317---651-----7-83-59------9---6523-7--484-6-13--71-95-2--964175823137298465285463179396512748471836592528749631652387914849621357713954286 +--8-72-59-9-615-7-3---48-2--8-5-7-----4-83-6-53-26---89----158725-----418--7-6---618372459492615873375948126186597234724183965539264718963421587257839641841756392 +4---175---7825--1--1-8-6-----7-412---3-5986--1---6283---16-5----82---49---3--9168426917583378254916519836742867341259234598671195762834941685327682173495753429168 +4-5-386--3--174--58---96-2---681--421---629-----4-3--6---3-1-6-9-7----84643--7-5-495238617362174895871596423736819542154762938289453176528341769917625384643987251 +-6-93-8----4-27-3--5368----5--74---6--62--5----716-2-92-----4-8-4-812-67---459---762931845984527631153684792529748316816293574437165289291376458345812967678459123 +1-27598--5-82--379-7--382-53--82495----391786--9-6--------4----7-------32--6-5--8132759864548216379976438215367824951425391786819567432681943527754182693293675148 +-965-8----8-----7---124---652-----9-43-8-162716-3298-5--2--4----1----4-8---98-71-796518234284693571351247986528476193439851627167329845872164359915732468643985712 +-7--85-2---69-45---35-72------863----6-4217-94------62--9-17-48--7-4--3-3---96--7974185623826934571135672894792863415563421789481759362659317248217548936348296157 +-15-37-8---3-486---6---1-3--9--25--32--81--4-----93-26-49---1-----564---3-8179--4915637482723948651864251937496725813237816549581493726649382175172564398358179264 +-4192--6-532-4---9-76-1-8--15-6--2-8-68-5--7-2-4-----6---37-1-24-5---6----34629--841927563532846719976513824157634298368259471294781356689375142425198637713462985 +6--8-2-5-----3---29256--8---14-87269---12-347-7-9-6-1---6------3-2-1-9764-72----5631892754748531692925674831514387269869125347273946518186759423352418976497263185 +-9-5-----7---8--34---67-52-9371-485--6-3-2---2-57-86135-48------89----65----3-4--892543176756281934413679528937164852168352749245798613574826391389417265621935487 +-1--89542--6--21-8-98--136--69--3-----2---7--1---9-2566-43-89-5-7--1-----31-25--4317689542456732198298541367769253481582164739143897256624378915975416823831925674 +-671-943513----9---4-8--67-----9586-7---31-5-5-4----1-21-98---7-7-51--28-----21-6867129435135647982942853671321795864786431259594268713213986547679514328458372196 +8--------5-463-9-----7583--9-7--62-3--3-256--1-----4-5-458-37-2-2-1--53--9-572-64836249157574631928219758346957416283483925671162387495645893712728164539391572864 +5--329-47----81---3-9-475--8-2--36-4---4------37-962--9---783622-3--54-86-8--4--9561329847724581936389647521852713694196452783437896215945178362213965478678234159 +--9-5241----7------72--4-9371-495--6----38-----6-71-54294-13--5-37--6-49-5---7-32869352417341769528572184693713495286425638971986271354294813765137526849658947132 +----3859-827-------9-1-6-2-27--91---4-1-------69427-8171-9-4--5953----466--7---19146238597827549163395176428278391654431685972569427381712964835953812746684753219 +29876---34-5-8-----16-4-5-8963--28-1--1-3-69---------214-6-39-53-9--427-----9---4298765413435281769716349528963572841521438697874916352147623985389154276652897134 +81-56-2--4-539-7--7-6142--3--8------97-6--18-15---4---56148-----8-75-----47-2-56-813567294425398716796142853638219475974635182152874639561483927289756341347921568 +-7-1-8924--85-276---4-9351----3-----3-9-861------59--21-582--4-----3-85----91523-573168924918542763624793518852371496349286175761459382135827649297634851486915237 +8--9--216--6-3-----2-8-6-9-691-875-435746-----4-1-9--7------9----26--75-179-4-63-834975216916234875725816493691387524357462189248159367563721948482693751179548632 +83412-5-7156-47----7-3-8--19----415-318-7-46-------3---9-4-2-3-4---6------2--3984834126597156947823279358641927634158318275469645891372591482736483769215762513984 +--8-76--44----2-8-2-5-81-6-----9843--3-62--7-9---358---862197-----547---7-9-----2318976254467352189295481367652798431831624975974135826586219743123547698749863512 +21-7---8--75-9-6---96---47---1-4--6--63-15-2--82--6--4548----------89--11396-28--214763985375894612896521473751248369463915728982376154548137296627489531139652847 +--4-53-29---1-----1-3--26-4--7-192-5----68---91-2457--5----13-6432-965--6-1--74-2784653129269174853153982674847319265325768941916245738578421396432896517691537482 +2-7--51-4-54--1---9613-78---89-5--36-----95--52-78-4-9--2--8-97------6--798-6-2-1237895164854621973961347825189254736476139582523786419642518397315972648798463251 +5--39--2--3---1-----9-2-543------2--624--731--5--3-68-7--24---6861-73---2436-98-7586394721432751968179826543318465279624987315957132684795248136861573492243619857 +96---52-----7---1--81---53-----91-2-13-27------9---6---12657-49643-18-52---3---68967135284354782916281469537476591823138276495529843671812657349643918752795324168 +4-31-297617--------69---1-4--4--631-926----------542-8-3-4-1-9--915--74-8453-7---453182976178649532269735184584276319926813457317954268732461895691528743845397621 +134-8--26698---5475----6-----1-2467884-7--2-1267-91--4-25-1-4------7-8--3--------134587926698132547572946183951324678843765291267891354725618439419273865386459712 +6--9-3-85-3--567-----84---6-9--67-5--4-381--228--946--17-----98---43--6-468-1--2-614973285832156749759842316391267854546381972287594631173625498925438167468719523 +8-574-621-125---7-67----945-2-6318---86--2-3-9-------67---69152-6--54--3----2----895743621412596378673218945524631897186972534937485216748369152269154783351827469 +---3--4-656-2---7-8-4-67--36----82--4---321-9---45--689-----31-7--8196---567438--271395486563284971894167523615978234487632159329451768948526317732819645156743892 +4-----8--5----4296--1-287-47--4-----264-9-5--935-876411-7--6982----7------9-52-67472639815583714296691528734718465329264193578935287641157346982826971453349852167 +-817--4-97-49-----5691-2--3613-5-9-8--83--16---------53-6-7-52-87--316-4---6----7281763459734985216569142783613254978458397162927816345396478521872531694145629837 +165---3----4-6-295-8-3547-193----4-664-79------843-9--8--1-3-4------21--41----572165927384374861295289354761937218456641795823528436917852173649796542138413689572 +---865---49-213-5-3-5---2--9---546----6--2--98-2-91--4----39-67-7-42---5--3-78-9-721865943498213756365947281917354628546782319832691574284539167179426835653178492 +--267-13---41--5------54-82--94--765--73-6---48-5--3292-5-3-94--48--9--1---24---3952678134864123597713954682139482765527396418486517329275831946348769251691245873 +--8136-455-38----96-15-9--7--749-618-------528-6--7-941-59-3--6------9--46---1-83798136245543872169621549837237495618914368752856217394175983426382654971469721583 +328----49-4-----36-9623--7-83----9--56-48---2--4------48--7--239-3-6--516-2--1798328756149745918236196234875837125964569487312214693587481579623973862451652341798 +5-67-2493-29-----7--3--1-5634-----2----47--61-5-29--4----8--6-2--5-2418--82-175--516782493429536817873941256347168925298475361651293748134859672765324189982617534 +-9---3-4--6--9253-4---869----9-75-1--8-63---7-74-19-----83216-9---548---3-----18-192753846867492531453186972639275418581634297274819365748321659916548723325967184 +---2-54--457-86--2923-------4-3---8--62--83---784-9-6--915----86-4-1--2--85----13816235479457986132923741856149362587562178394378459261791523648634817925285694713 +8--3-5796-----62-46-4--2-157---------95--8--11-6-7-9582----9---4-958-12--37-2-8-9812345796953716284674892315748951632395268471126473958281639547469587123537124869 +-2---1635--7245-98851----4--7--24-6-1-2-96---6-4----21---3---8-7--48-2--2-8---953429871635367245198851963742573124869182596374694738521916352487735489216248617953 +937------6--9--45----61-3-81682-4---57---126--4-5-6-7--25------79----5-64-63-5729937458612681923457254617398168274935579831264342596871825769143793142586416385729 +8634-5-915-9261-78----3--4635--92-----7---6-----5-7--94-5---1-3----2---567-1--9--863475291549261378721839546354692817917348652286517439495786123138924765672153984 +--5912-7-6-3857294-2--6--------2--3-2---7-5193-1--4-629---46351--6------1-7--59-6845912673613857294729463185598621437264378519371594862982746351456139728137285946 +-65--97-3-27--814--4871---5--3-9----28--3459---9--5---7945--61-6---8---9---9-72-4165249783927358146348716925573892461286134597419675832794523618652481379831967254 +-1---2---925---6317435--28---48-35622869-43--35--6-4-88-14----3---6----5-7-------618392754925748631743516289194873562286954317357261498861425973439687125572139846 +--6452--7-75-86-1---8-193--561-2-7---29---8-5---64-1-----56---1--4-31-9--1-8-45-3136452987975386412248719356561928734429173865387645129893567241754231698612894573 +9--2--567-4-5891-3521-----8-86---2-94--89---6-9263---------7--1--4-18-9--19---735938241567647589123521763948386174259475892316192635874263957481754318692819426735 +264-398--8-3--4-1-51---893-7------4-421-9---8-----519---6-4258-----8-7--9-25-3-61264139875893754216517268934759816342421397658638425197176942583345681729982573461 +--135-8-2--58--6--6--19---58-----9-4-9-438-51---962----6754------9-81-7--5-27-4--971356842435827619682194735823715964796438251514962387367549128249681573158273496 +-----35-662-1--8-7-------2---4639-188--47--539--51-6-2---32-165---85-2--51--9-38-147283596629145837385967421254639718861472953973518642798324165436851279512796384 +3512-4--6-89--5---74---98-5--------1-7---643-463-1-5-79-746-3-8-36-9-12------3--9351284976689175243742639815295347681178956432463812597927461358536798124814523769 +--------5-3-451----8-6-39-132--6-4-819------7-6--123--9-6124-8-24-53-19--137---2-471289635639451872582673941325967418198345267764812359956124783247538196813796524 +--1-43----78--9-5-6397-814--4-96-----85---6-1-6--7-4-38-4---2--52---7-647---24-15251643789478219356639758142347961528985432671162875493814596237523187964796324815 +----83-----6-91-2591-245-6--89--6-42-5---9-78742-18-5---4-572-1---9------97--2-84275683419436791825918245763189576342653429178742318956364857291821964537597132684 +-97---21-1-5-9---------3--5----286-18----935--7--1-----2-63----73854-1-96-198-432397854216185296743264173985543728691812469357976315824429631578738542169651987432 +-17-2-4------5-6--3--------758-92--4-2--748566-45--7-2243-6--781----8---869---145517826439492753681386419527758692314921374856634581792243165978175948263869237145 +-2------59-7-86------9-28---93---7-42-54----8----6-9------7-53--8965412-5713-948-428731695937586241156942873893215764265497318714863952642178539389654127571329486 +7-94----243-682----129376-49---1-573-8---3---1-35---9-3----526-------9---4-27938-769451832435682719812937654926814573584793126173526498398145267257368941641279385 +-41-26---------792--785-1--8-239751--------83----819-74--13-8-95-3---4611-89----5941726358685413792237859146862397514719542683354681927426135879593278461178964235 +8-695----1---32-8---9---7---18643-59-53---6---2419-378--1----92----691-73--2-----876951423145732986239486715718643259953827641624195378561374892482569137397218564 +7---3-1596-9--27-8----7---6--8------9-3--581-1---28965-7--8------5197--38-6453271782634159639512748514879326258961437963745812147328965371286594425197683896453271 +78-542-63---1---95135-98-72-56-2-7-----4----889----2-16-----5---187-4-------86--7789542163264137895135698472456821739321479658897365241672913584918754326543286917 +7462138-5932--6--78------2-6--7392--2----5-----1-285-9--738-9-6--------81-85973--746213895932856417815974623654739281289165734371428569427381956593642178168597342 +1-----57--548-71--3--25---4---6---19471-25-8-8964---5-72----8-5--85---3--137--69-162349578954867123387251964235678419471925386896413257729136845648592731513784692 +--9--48676-3---1-4--87-5-----2-183--9--5467---8--736-9-1--825--2-635---88--6-7---529134867673829154148765923762918345931546782485273619317482596296351478854697231 +-2--319---8-576--4-64-82-1--37---2-6---8-51--618--74----125-6-9-5--19-3----6-8--1725431968189576324364982517537194286942865173618327495871253649456719832293648751 +9---36-2--6572---3-3-5-4---3---47-58-8-215-4---6-93-7---8--1534-57----91--34-2---974136825865729413231584769312647958789215346546893172628971534457368291193452687 +-1--46237-36--8--1-72--58-6-21-845------69----5-271-84-67--23-8---8-----2-4-137--815946237436728951972135846621384579748569123359271684567492318193857462284613795 +--4-5---2-5---4-73--3-28-415-6----94--76--32-4---9--687--4-3219------857-2--79---194357682258164973673928541516832794987641325432795168765483219349216857821579436 +----123-73--46-5---1--38--2--2-54-7--7---62---68-294---51----6-2-4691--5---875---846512397329467581517938642932154876475386219168729453751243968284691735693875124 +-----1---5--9-76-86-----7139-7--4---8--6--27-2-63-5-8-76--2---43-279--61-89-5-327473861952521937648698542713957284136834619275216375489765123894342798561189456327 +1--697-25-6----1-7---431----3--15--2--2--63----5-296-43-8-72-----156--8-2---847--183697425469258137527431968634715892972846351815329674398172546741563289256984713 +6-597124-9-83-----1-2-84369-2--1--954--7-----31----48--9----5-----2-7-342---45---635971248948362157172584369826413795459728613317659482794836521561297834283145976 +3-51--249-12--9---------167--3--651--97-5-43--6--3-9-----68-32--2-3--78-8---1--95375168249612749853948523167483976512297851436561432978759684321126395784834217695 +6-8-12--5--15489-22--------4-21795365--6--817-7----2--8-42-7--9---4--7----78516--648912375731548962259763481482179536593624817176385294864237159315496728927851643 +1------98---479-----92185-3-648-5----9-13-6----56-7-8--5---1-4-4--9-3--5-3-5-2-17127356498583479126649218573264895731798134652315627984852761349471983265936542817 +-2-3-6-4----5-----3514-89--9---3--15638---49-51469-7-3-4----8----7241-5-2----5-74729316548486579231351428967972834615638157492514692783145763829897241356263985174 +--91687---15---6----8457-2989-2-4-----3-8-9--6-153-4--5--97-8-4-7---329-9-4--5---249168753715392648368457129897214536453786912621539487532971864176843295984625371 +25-8---9----4---3---7-------845-93--9--134-58315--8-69879-51-4-461283-----2-----1253876194698412537147395826784569312926134758315728469879651243461283975532947681 +67-3----81------458524-17-6-4----82--2--54-7-36--12-----713--94-9324---74-6--9---674325918139687245852491736745963821921854673368712459287136594593248167416579382 +9-351---27-----------947--5--56-9--12-4--1-568------93-2-49613--39-75-64-6--8-5-9943518672751362948682947315375629481294831756816754293528496137139275864467183529 +---4------1------2-8--65--7--127-8-683-6917--76---8219-2-84796-9--5--------932175357429681416783592289165347591274836832691754764358219125847963973516428648932175 +6-7-14-5-2----6-1---1-35--28---971------8129--9-56--3-3-8-----6-156483-----723---687214953253976418941835672832497165576381294194562837328159746715648329469723581 +-269-85-----7--2-8---6217-93---86951-8--924-3-5-17-6-2-----7----1784---6---21--9-726938514139754268845621739372486951681592473954173682298367145517849326463215897 +-52974--6-71-86-5-43--21-9-58---234---3------14-7-----214-37---3---15---7-5-9-21-852974136971386452436521897587162349623849571149753628214637985398215764765498213 +----8----815-936--2---14--9--7925--89-----3---2---8-9758964-71--6-1---85143---9-6394786251815293674276514839637925148958471362421368597589642713762139485143857926 +-4329--17-7--8-23--6-7315-48------436-15---72--23-7-5----913-2-9--------3-4-52-6-543296817179485236268731594857129643631548972492367158786913425925674381314852769 +------4891-3--827678-6-----3--4--81--4--3--6-96--1-32--7---359---5-8-6-1----5473-526371489193548276784629153352496817841732965967815324478163592235987641619254738 +---6----4----1---616-48-37-59---1268--67--5--3-8-26-----19-2-8798--7--322-4-6--51859637124743215896162489375597341268426798513318526749631952487985174632274863951 +82-6-4--39415-38--65--97--1---7-----5---32-79--4-69---47-956----1-34--5636--7----827614593941523867653897421192785634586432179734169285478956312219348756365271948 +-6---5---7--6-91-5-4-321--64287635-9613--42---9-----6-------9--2--93-4-197-152--3169475832732689145845321796428763519613594278597218364351846927286937451974152683 +2-7-64-3-1-68-9-5-458-13--7----9-----4-6-8-----13-298-9-4186---6-39-----5--43-16-297564831136879254458213697825791346349658712761342985974186523613925478582437169 +73--2--9-2-51----81-8----26---9-17--471-83--9659--------76---8-8-47-5-3-9-3--86--736824591245196378198357426382961745471583269659472813527639184864715932913248657 +-9-2134-7---968---3------92--714--386--79---4--43---6--6542------9-375---4-85--2-596213487472968315381574692957146238638792154214385769165429873829637541743851926 +----8--1---6-4283-9-23-76-51-----4-------395-425-9---88-7--45--35---879-264-79-8-743685219516942837982317645139856472678423951425791368897134526351268794264579183 +8--3---5-7-4-5-3--1-586--7-6-92----55-2----93-78--9-4-281-75--4463---------42-8--896347251724951368135862479619234785542786193378519642281675934463198527957423816 +--2-96--1------3824-17-3----4--158-9-19-8-6---65---174-93258-16------59----1-92-8532896741976541382481723965347615829219487653865932174793258416128364597654179238 +-23--4--7--9-7--4--75-3--969512--7-3642-----------9-21-867---1-39--2-8---1748----123964587869571342475832196951248763642317958738659421586793214394126875217485639 +23---6-8-6-9-5-7--5-7---16-8-37----17-492--3---2-1--7-4253-78-----58---2198------231476589649158723587239164853764291714925638962813475425397816376581942198642357 +5--3-4--7---78-5627-2-15384-4-1-8--9----6-8--8394---1---4-------68-7-435-258--9--586324197413789562792615384647138259251967843839452716174593628968271435325846971 +1-826-5379-3----4-2-54836-9--6----7--2--31--5-5469------2---1-6----4672--3-1-----148269537963517248275483619316854972829731465754692381492378156581946723637125894 +---539-----9--71-4-67----25---9-3-71---81----1-5-748936--3-17-84-8726---7-14--3--214539687589267134367148925846953271973812456125674893652391748438726519791485362 +--6-824-9--96-4---7-2359--1--------3--1--825--3-5219-821-86-5-4-6-1-537---5-----6156782439389614725742359681528976143691438257437521968213867594864195372975243816 +429586------9----557-132-6-2--754-811-762-4--645--1-72--6----4---2-79-1----3-----429586137361947825578132964293754681187623459645891372956218743832479516714365298 +-8--65---627-81----15-3--6245---2-78--8------76-1-----87--26-3-1-6-49-5-5-23179--384265791627981543915734862451692378298473615763158429879526134136849257542317986 +7--69-8---5-----1-83-4-5----64----3--295-7168-872634-5-7----5-96----9------35--71742691853956832714831475926564918237329547168187263495473126589615789342298354671 +6---9517213-8-----5--7--8632-5----1--7-95--4---16-27-53-82--4-14--5--6---56----29684395172137826594529714863265473918873951246941682735398267451412539687756148329 +81----9---4-95-1-----16-2-7--8--74-2-95-----64-26-9518---3---29-39-76-4---4-9137-816723954247958163953164287368517492195482736472639518781345629539276841624891375 +17243---5------3---53-1-6-25941687-36--2951-----3---9-7--9-----3-9-4-2-72156----9172436985968752314453819672594168723637295148821374596746923851389541267215687439 +-36-582-77-5-3--14---7--3--587-4-6-96--5---78------4--86-3--9-22-39-----9748-15--136458297795236814428719356587142639642593178319687425861375942253964781974821563 +------6913-251------9-47-2--27--6--4-48---532-3--82-76---27--69-7196824-------7-8754823691362519487819647325927356814648791532135482976483275169571968243296134758 +389-145----4-8569356-9--4-8-7-----------9---68-2-4---5745-6-38-136---952-2---3---389614527214785693567932418673521849451897236892346175745269381136478952928153764 +----3--2-8-47-5---35------4--8-----5-9-2-3-4----15--9798254-3-6--7---1-251-6724-9671439528824715963359826714148967235795283641236154897982541376467398152513672489 +76-53---8-----6------79-2-----987-62----6--9398--23-1---43-81273--2-9-541--67--89761532948239846571845791236513987462427165893986423715694358127378219654152674389 +--7----86--9817--334-296--12-13-96---34-5--9-----6-3-2--26-57-8--3--1--5---42-13-127543986569817423348296571271389654634152897895764312912635748483971265756428139 +-96-43-----1---83---3-21-7--679----8-4-----123821-47-67--49--519-531---761---5---896743125271569834453821679167932548549687312382154796738496251925318467614275983 +8-6-14--3-178-------3-65-8176-45----4--19--3-1-----24-9245-13-7-5-----1937---6--2896214573517839624243765981762453198485192736139678245924581367658327419371946852 +2-194---8-7--82-4-8--1-3---1-9----76--5--6183--83-4---5--461-3---2-78-9--8--39-15251947368973682541846153927139825476425796183768314259597461832312578694684239715 +-----37-6--12-4398-73--645--35-8-14994---15----8--------6--9---28--6-9-1-9741--65429853716561274398873196452635782149942631587718945623156329874284567931397418265 +2-17-------3-89-72-78-25--3-2----65--5-24--3-81-59----6459-23-19------2413---8--6291734865563189472478625913324817659759246138816593247645972381987361524132458796 +--3---21---7-25--929-1-83--5-1---8-2-8---2-7-37---146-648--9-2------4-3613925--8-453697218817325649296148357561473892984562173372981465648739521725814936139256784 +1-8--5-4372----59---3--2--72-5---4---6--293--4--5-7-26--729-654-84--1-----2--6781198675243726134598543982167275863419861429375439517826317298654684751932952346781 +15-----872-97--64---65--1--5-7-----44--1-735--3-85---6--53--291--1-85473-942-----153462987289713645746598132517639824468127359932854716875346291621985473394271568 +712-96-844--2-7--683641------51--86-627-4-31--------7-5--9-17----1-3-----9-7--251712396584459287136836415927945173862627849315183652479568921743271534698394768251 +-54--38277---9--4-8-12-7---6-27--3-43---529-8-859--2-1---3--7------7-6---7386--19954613827726598143831247596692781354317452968485936271169324785548179632273865419 +-1-6-9--8------571-8453----4--2-87-962----83489---76-----98-1-795-712-86------29-512679348369824571784531962435268719627195834891347625246983157953712486178456293 +2--4--95---1--64-84-7---6-1-7--1-2-55---891-31----7--9--215-396-9--62---------782286431957951276438437895621879314265524689173163527849742158396398762514615943782 +639---7-4-4----2-927-93---54---------2864-3---96----7-3-2--16579-72--1-8-645--9-3639852714845176239271934865413729586728645391596318472382491657957263148164587923 +------1486-1--7---29--1-675---38-9-6--6-9-4-3-3-1---279----82-1--89--7--4-72--5-9375629148681547392294813675742385916816792453539164827953478261128956734467231589 +92-64--37--8--5---5-43-1-9--5---73217-24-----1-------8--57-69132--1---656-75--2-4921648537378295146564371892459867321782413659136952478845726913293184765617539284 +--91-43--3-17-56--745--912-6--9-723-------81--32--69574-35-17----------35--27-49-869124375321785649745639128658917234974352816132846957493561782217498563586273491 +3-65--82-9--6--37-27831--9---516-98----43----16-928-5------6---6-78--23---279-1-8316579824954682371278314596425167983789435612163928457831256749697841235542793168 +4--821--7---5---1-2197645-3--------57389-52---25--78-45-1--93-88724--1--3--1-----453821697687593412219764583146382975738945261925617834561279348872436159394158726 +53----6-7---416---4--5--82-2-5--8-1-9-8375-----32-195-----29------1-42-56-285-194531982647827416539496537821245698713918375462763241958154729386389164275672853194 +-135-4--74-8-1------76-3-14-4----95-38--56----5--42-7-92546-7-86------4287-3----9213594687468217395597683214742138956389756421156942873925461738631879542874325169 +6--432-5---198--7--8-57-63---8-25---3-7---49---6-4-5838---53----9-81--2-1-32-78--679432158531986274482571639948325761357168492216749583824653917795814326163297845 +19-86--2--3--9--8-8--72---3---48-35---59-2-7--4-51-8--47------9---371---2-86497--194863527732195684856724913921487356685932471347516892473258169569371248218649735 +----718---36-54129184-32-67-----69--5-13----2-672-8----5-1-----6-8---39------3-56925671834736854129184932567842516973591347682367298415253169748678425391419783256 +231----------9--15985--17-6-16-3---7-786---92--97---3-69-1--4---42--7-5--574-3---231576984764892315985341726516239847378614592429758631693125478842967153157483269 diff --git a/apps/sudoku/sudoku.medium.txt b/apps/sudoku/sudoku.medium.txt new file mode 100644 index 00000000000..bb9b3a6c68d --- /dev/null +++ b/apps/sudoku/sudoku.medium.txt @@ -0,0 +1,200 @@ +52-9647-1--4---9-5879-216-3--8---2--7--39--1-----5247------3-9--8124----23----1--523964781614837925879521643158476239742398516396152478465713892981245367237689154 +-4-9-3--57--28-9--96-5-4-----67-8-4-4----2--68--4-1-32---637----7-12548---2----57248913765753286914961574328326758149415392876897461532584637291679125483132849657 +--92---58-1---742--62---17---8-4531---1--65--6---1-89--9-18-7355---79---------964479231658815967423362458179928745316731896542654312897296184735543679281187523964 +16-2-4----5-39-6--------572--186-9-7-83---146-96-7---3-2978536--------98---9-67-5167254839852397614934618572241863957783529146596471283429785361675132498318946725 +87--541-22----975-6--127-38--9---8-7-5-27-3---16-3-2-5-875-36----4---------7415--873654192241389756695127438329415867458276319716938245187593624534862971962741583 +9---851-48-4-129-----4--68--75-----8--983---5---52--163-8----2-7----1-6969-2-8573926785134834612957517493682275164398169837245483529716358976421742351869691248573 +---83-69--7-----8---6-245-----4--2--4-8----5-75--98---62758--148-3912-65-9-----23214835697375169482986724531139456278468271359752398146627583914843912765591647823 +53-7-91--78-6--9---6-38574-37-9-85--4-5--386---------965---149-------27--1-49-635532749186784612953169385742371968524495123867826574319657231498943856271218497635 +3-4-682592----134-58----6--87-1-6--44--8-9-71----7-8-3-92----8--4-58--9----69-13-314768259267951348589243617875136924436829571921475863692317485143582796758694132 +-895-4--31--78-9--3------485269---8----6--23-943-78-5---58---1-47----8-5-314---26289564173154783962367192548526931487718645239943278651695827314472316895831459726 +82--349----529--3--9-7-8---2--95--4--1-863-7---947-18-9--3-7---48----65-1--6--798821534967745296831693718524278951346514863279369472185956387412487129653132645798 +----5--6-93----4-86-4--3----8-2-5---1596-7-344-23-1587-9---4-----1-3-6-5----18-42728459163935176428614823759387245916159687234462391587293564871841732695576918342 +91-38----6-8-----1-----6-5--3----7-54598-16-28-72531-4-9------8---7-8-43--456--1-915387426648925371273146859132694785459871632867253194791432568526718943384569217 +287-43-1---1--9-839-3--5-725---94-21----36----94271-5----9-----8-9--2-377---182-4287643915651729483943185672576894321128536749394271856432957168819462537765318294 +3-6---21-----9--6-48---25------1--436-5249-787416-3-2516-95-------8-6-5---8---4--356478219217395864489162537892517643635249178741683925163954782974826351528731496 +--958--1-2--463-7--8-71-26--5-89--3-9-63-18--8---76-----2-4-7866-1---45---8-37---769582314215463978483719265157894632926351847834276591392145786671928453548637129 +-----1-----235---43547-2-1-2-38-7--9-98-----7517--46-392-5-834--4516--9------9--5679481532182356974354792816263817459498635127517924683926578341745163298831249765 +39----24--584---6-14--9-3--9753-86--621----------69--573--51-8-86---3--25---2--3-396185247258437961147692358975318624621574893483269175732951486869743512514826739 +--869--722-1--7----7952---8-2----45-91--65----5--32-8-4352-68-16------2318-9----4548691372261387945379524618823719456914865237756432189435276891697148523182953764 +4-7----25--8-7-3-12----6---15---4---93-761-8278-25-149--1----3----6-82-48--32----467139825598472361213586497152894673934761582786253149621945738379618254845327916 +7--4-8------27-8-6--1----4-15--6----34-912-7897-8-51638---2------7--94-16-9----85765498312493271856281356947158763294346912578972845163814527639537689421629134785 +519----24--2-5-----4-23---8--64-38-----1-6-477-4----36--3---972965--74--2-1349-8-519768324832954761647231598126473859358196247794582136483615972965827413271349685 +--5-876--4--2-6--93-64-9-----47----3--81-4-27-3-8-5-4----523----7-----955--97148-925387614487216539316459278194762853658134927732895146849523761271648395563971482 +7-1-3---48-365-7--6--4--3---76--21--5-29---3-3-9---24-968-73-1----19---6154------791238564843659721625417389476382195582941637319765248968573412237194856154826973 +---91-4---8-5--37-41-3-7596----65-1-1-9-7--6-6-4---83--4812---7-617---282-----1-3735916482986542371412387596823465719159873264674291835348129657561734928297658143 +--83-15--6-529----9-------78-----91----6-9-78--3-1----32------641-98-75358-46329-248371569675298134931546827862734915154629378793815642329157486416982753587463291 +3--2-4918--2------8-71--3-22-9761534--1538-7--5---2--------5-9-9-84---255----7183365274918412389756897156342289761534641538279753942861136825497978413625524697183 +---1-62--1-3-24----6-----8--15---37-----4-1--6-87---2-8395-17-2-214879-6----3-8-5984176253153824697762359481215698374397245168648713529839561742521487936476932815 +9----4---2--9------372-8-497-865-4--4-1--925-5-3--7-68859-4--16-1-7--9------9583-986514372245973681137268549728651493461839257593427168859342716314786925672195834 +--1--9-269-2--3-47467-82--13---98-14----25----98471--36-9--4-72---9-----7---1648-531749826982163547467582931375698214146325798298471653619854372824937165753216489 +------9587---86-----81-2476-1--9---7-2--751-49----18-2-8-3--72---1-6-3-5-39---6-1162743958745986213398152476614298537823675194957431862586314729271869345439527681 +7---5832-9--2-146---63-915723-91-7------8-29----53281-----25--158--94-3----8-----741658329953271468826349157238916745615487293479532816364725981587194632192863574 +28-7----4--6------1-7428-6-8-9-3724-65-8-4-3---3-----89-127---3---9-3--1--41865-2285769314496351827137428965819537246652814739743692158961275483528943671374186592 +--5------2---159639-7--352-5-6437182--3298--7-8--5----8---7-239----8---66-9--18-5135962478248715963967843521596437182413298657782156394851674239324589716679321845 +---7-----2---6817---3-41---37-124----9-63-42-64--7----1392-6--542--179--58-4-36--918752364254368179763941258375124896891635427642879531139286745426517983587493612 +1------7--2-6-85--95-31----6-3----9-5-24963-14-812-765---9-1-272-----1-8-6--8----186549273324678519957312846613857492572496381498123765845931627239764158761285934 +7-6--5219------435-59-1-----136--7-2--7-4-5-6-4-7----1---8-49-78--5--16--9---78-3736485219128976435459213678913658742287341596645792381361824957872539164594167823 +----5-9--3-1--6--8-94---7-6----7-14--8961523-1729-468----3-98---3------19-758----726458913351796428894123756563872149489615237172934685215369874638247591947581362 +-----5---2497--3-5-759-1--21----29767635-4281----6-5--9276--1--4-----6--5-64-9--3618325497249786315375941862154832976763594281892167534927653148431278659586419723 +2-16--9--6-9---52-37---2-8---35---9-9-431--7-8-7-9---5518---------86---3436-798--241658937689731524375942681123587496954316278867294315518423769792865143436179852 +9-8-21-----567--8-1-----4--5------16---19-5-4--7--6---85-739-2136--1574872----9--948521367235674189176983452592347816683192574417856293854739621369215748721468935 +-9--------15-4-926-231--7----98-1-7-----5-1--1769----82--6-9-4----41-23543--82691894276513715348926623195784549861372382754169176923458251639847968417235437582691 +--3-89524-8--571-3-2-46-9-7-----6---64-81---9---74--5----6--7-8---9746-597-5-82--763189524489257163125463987857396412642815379391742856534621798218974635976538241 +--945--8---3----2------7---9--215-683218---598-5-932--294361---15-978-3------4--1679452183413689527582137946947215368321846759865793214294361875156978432738524691 +--3-456-9------8----5826-----46-1--55-14--3-26-9---7--94-162-3--56-7--1-1-258--96813745629267319854495826173724631985581497362639258741948162537356974218172583496 +----8--5323----87---56-----4-312--------3-7--65-8----13-8-95617----642--962-18-34796482153234951876815673492483127965129536748657849321348295617571364289962718534 +542-76--3--3--8-648-6--1-52-87523--1----69---1---87-35---8-----2---3457-4-8--5-26542976813913258764876341952687523491354169287129487635765812349291634578438795126 +---75--262-----7-9-1---9---1-3----5-4-21853-78-9-72614-2-91-4--7------6-54--37---984753126235861749617429538173694852462185397859372614328916475791548263546237981 +---418----726594--4-6----9-9-857---21--9----7--724--1-6--83-7---3--92--4---76-1-3593418276872659431416327895968571342124983567357246918641835729735192684289764153 +7-9-35264---96-587--52-4--9-4-3-6--1----8-6--1264---3-4--------68--9-42557-6--1--719835264234961587865274319948326751357189642126457938493512876681793425572648193 +1--85--6---3974-2--8-62--93--82-9----5-18--4-9-1-46--83--7--9826-9----578--4-2---192853764563974821487621593748239615256187349931546278314765982629318457875492136 +--8-7----95--2387---3--8----67-8--43-94-5-21--254-1--74827--16-6----5--8---84--92218674359956123874743598621167982543894357216325461987482739165679215438531846792 +-3-87-495-873--16---65--3-73---8-546-681-------5---2---1345---9-2--3----6-97-18-4132876495587394162946512387391287546268145973475963218713458629824639751659721834 +16-2---57-274----198457--2-841-5-2-----6---15-3------4-587-61-9--984--62----2--3-163298457527463981984571623841357296792684315635912874258736149319845762476129538 +7--6-34---1-----9-48--12---3---6-----7----1-6---1-8-79-32----8--56-71934-473852-1725693418613854792489712653391467825278539146564128379132946587856271934947385261 +94--5--611---4---857---8-4-62-4----3-15-7-2--43-82----3917--45-786-----------1-37948257361162943578573168942629415783815376294437829615391782456786534129254691837 +741--58--3-----1529-2831-6-----94-854---836--8-5----34-8-32---62--7-----197----28741265893368947152952831467673194285429583671815672934584329716236718549197456328 +8493---5----8---29231-75-4-3-54-12---6-75---3-2----51--17---4-56-21--89-4--5---6-849326751576814329231975648395481276164752983728639514917268435652143897483597162 +189-736-5--3---17-5-6-4-9--7------898--1-7-5-6-43-8----5-43-72--67--2---24-78-5--189273645423965178576841932715624389832197456694358217958436721367512894241789563 +3-4-----9--713-6--6-1-7-2-547-213-5--63--9-1-1-2-6834---6382-----------8--56-74-3354826179927135684681974235478213956563749812192568347746382591239451768815697423 +3--548--94------82-19327--5---2--9-719-6---3-5-7-392--7---624-89---5---6---7-159-326548179475196382819327645638214957192675834547839261753962418981453726264781593 +------7---8-72569---63--24--9-6-------7--13566-1-3--7--68249---21-5764-87-5-8---2532964781184725693976318245893657124427891356651432879368249517219576438745183962 +-9135----5-7----9------74--8-5643-291425-9-67-3-----48---8-523--1-----5-2--47-9--491358672527164893386927415875643129142589367639712548764895231918236754253471986 +1--64-7-24--7--5---5-13---4---352----7----3-9--3967-413---71-8-8-549------428-9--138645792496728513257139864941352678672814359583967241329571486865493127714286935 +-4-38271--2--9--6887--562-33-4--16-2--9---8-76--2-8--17-861---4--5---------835--6946382715523197468871456293384971652219563847657248931738619524165724389492835176 +6-8----147126----5---3-7--2---7-1-2---392-8--2---34-915-147-2----7163-5---428---9638592714712648935495317682849751326153926847276834591581479263927163458364285179 +5821976-37--4581-----3---8-3-8--24-66--8-----4157----81642-3--5------3---53--17-4582197643736458129941326587398512476627834951415769238164273895879645312253981764 +-63----71----51-36--1-374----89-----592----833--78---4--7---268-85372-4-129--63--263498571974251836851637492748923615592164783316785924437519268685372149129846357 +9-4--78--3-7-2-514--5----------72439-2946-175-4-5-1--25--7-6--8----3-7--178--5-6-914357826387629514265184397651872439829463175743591682532716948496238751178945263 +7--2---3--3-54---729-83--5---1-25-4----36-71-6--91-3--46------2---479----536824--745291836138546297296837154381725649529364718674918325467153982812479563953682471 +6--92-431--917-6-8--35-47-2-548-92-----4-7-1-----5-----27-91--3-----59-7---7421-5675928431249173658183564792354819276862437519791256384527691843416385927938742165 +-19-----23-8294-1----615-------3975--9--67-3-7--8-21---5--2-3---26-438----3-81--5519378462368294517247615983682139754195467238734852196851726349926543871473981625 +532-4--964-9--7--217--69--4----76--18----2---2574---6---3-14-25----8--4-6-57-31-9532148796469357812178269534394876251816592473257431968783914625921685347645723189 +-2--9-6--9----28-136--8-4-9--5-1--86-7-9--3-5---25-9-7------13271---6---8-91--764128497653954632871367581429495713286271968345683254917546879132712346598839125764 +7-18-3---95-6---8------12------793--1-6-54928493-68-71--59-----31----6-2-----6-15761823459952647183834591267528179346176354928493268571685912734317485692249736815 +----6---36-1--345--378-16-27---1-86-186--49-7--------496458---12-3-9----87--3-2-9428965713691723458537841692742319865186254937359678124964582371213497586875136249 +-8----1--3-5-47------3-8--4----5--61-43712-891596-3-42-36---2-5----7---38-12--4--284569137365147928917328654728954361643712589159683742436891275592476813871235496 +-6--43--2------716-295-7---------84----2-46-147-681-2324--1-3--38----2599---281-4768143592534892716129567438612739845893254671475681923246915387381476259957328164 +2-6---5-3-------275739-286--5-2-6--8---7-814676---12-582-3--6--------3599-461----246187593189563427573942861451236978392758146768491235825379614617824359934615782 +75-8123-9-29374---8-19----7------8----2-6-73--9-78124-2-56---8--4--2------8--5612754812369629374158831956427167243895482569731593781246215637984946128573378495612 +7-38---256-94--1-32-8-539----49-------1-4----87-21--49432--9-56---3-42-7-6--8-4--743891625659427183218653974524936718391748562876215349432179856185364297967582431 +4----9687-6--2------76-4-9---19-85--253-61---68954-1-3--------9895-1--26-7---6-35412359687968127354537684291741938562253761948689542173326875419895413726174296835 +784----------812--5123-9--889---37--35--24-9--2--7--3-2-96---8-64--1---313-----67784256319963781254512349678891563742357124896426978135279635481645817923138492567 +---61---856-39-7-------5----2-56-17--9-8-143---49-7682----5-91----17685-71--89-2-473612598562398741981745263328564179697821435154937682846253917239176854715489326 +8-3--416---2-----------6532--93-8---5-46-7--16----1-73-7--639--38-7-52-6-4-81-357853274169162539784497186532719348625534627891628951473275463918381795246946812357 +15-4-7-2-739--54--28---1--69-5-----2---3-87-13--572--45-7---2--62---9-8--912--6-7156487329739625418284931576975164832462398751318572964547816293623749185891253647 +1-967528----9-2-65------9-7--472--967-8---3429-2-6---824-1-3---------6515--89--2-139675284487932165625481937314728596768519342952364718246153879893247651571896423 +43-21-6-5-8--542--2516-97--9--42--715-2-9---4---56--8--94-7--56-------3-315-4----437218695689754213251639748968423571572891364143567982894372156726185439315946827 +7---14-583---8---6---3-672-6-7--5-39----735--23-9--8--4--15----9---3-614-23-6-975769214358312587496584396721647825139891673542235941867476159283958732614123468975 +81247--5--4---8--9---3-218---8---5----6-----893-58-2-64-51-68--3-172-9--2-9--5-17812479653543618729697352184728963541156247398934581276475196832381724965269835417 +6------7----3-21-4--271-----2915-648-78936-21-56--4---9-4----152---9-7-6--1--3---613845972897362154542719863329157648478936521156284397934678215285491736761523489 +--53--12--2---9-84---6-235-1-8--473-3---6-49---6--38--5-9-8----43-9--578------961695348127723519684814672359158294736372861495946753812569187243431926578287435961 +316-47--2-----1----9--83-7-834----272--3--16-1672-83-5-7------4--5769-1-9---1-75-316947582748521639592683471834156927259374168167298345671835294425769813983412756 +7------3--3-8-72-4-8613-79--2-76851-8----16-7-------2-6-4275-8-3---1695-5--3-9---745692138931857264286134795429768513853921647167543829694275381378416952512389476 +47219------18--69--9----4-----31--25-5---8-1631-56----745--1--392--8-167-6-937---472196538531874692896253471684319725259748316317562849745621983923485167168937254 +8-36---29-965----845129--6----3---82--7-----5185-2-6---4-15--36----6--7--129-38-4873641529296537418451298367964315782327486195185729643748152936539864271612973854 +6--284-1-58-----4-2--1756-97-65------1-3---96--5-6172--6279----3----2-6-8-4-53-7-679284315581936247243175689726549831418327596935861724162798453357412968894653172 +6-5-41--2---385--1--3------56-13-9-8-9--7--15-2-95864-8-24--1-91--5-9--4--7---5-6685741392279385461413296857564132978398674215721958643852467139136529784947813526 +6---215---3-----7----7-468--53-78---7-2----5----2--1--4-7819-653165-7-92-8-----14678321549534986271291754683153478926762193458849265137427819365316547892985632714 +3------61-9-8-1-2-57---2-894-----------174-9-16-92--5--16-49-78--8-3-91---57182-6382497561694851723571362489429685137853174692167923854216549378748236915935718246 +5-932-8---1274-6---4-58--92----6-4------1--6-6-48-351--6---7-8--53---2-69-7652--4579326841812749653346581792138965427795214368624873519261437985453198276987652134 +--2-5------32-----17-38--25248--5-69-9-1--2------428-77-4-1--869-5-2-3-48-16-45--682459731453271698179386425248735169597168243316942857724513986965827314831694572 +3---154---1-86--9-----3421-6-5-47-8-2----6-4---4-98--29-3-----6-486739-----529---392715468417862395856934217635247189289156743174398652923481576548673921761529834 +3------5----46-9-1-6-5-9----9--4----6----85-381-----97-25834-69-869-7312-37-1----349271856258463971761589234593746128672198543814325697125834769486957312937612485 +8-63172---27-----1---952----158-3-6---82-6--9-9---1-8-4--16--2--7-4-58-----7-894-856317294927684531134952678715893462348276159692541387483169725279435816561728943 +-51-3-7-279---2-8----17--3--4-3-6---9-75--123-2-7--654-1-64-3-8-7-8----5----5791-451938762793462581286175439145326897967584123328791654512649378679813245834257916 +--34--1---1-59---3-2471-5---69-----415-674-9----932---8---459----628--1----16-83-593428176718596243624713589369851724152674398487932651871345962936287415245169837 +-7384---2-8--5----4-92-61-3---7--5----416-----1---8736--891-46---76--8-9-91-8-327173849652286351974459276183862793541734165298915428736328917465547632819691584327 +46-72-1--78-1--42---25-4--------894--7--153---486935-1----4--638-6-57---9-4-6--1-463729158785136429192584637351278946679415382248693571527941863816357294934862715 +-4-6-------374-5--612---34--8--37--5----2893-93----87-168--9--342-371-5--7----491547613289893742516612895347284937165756128934931564872168459723429371658375286491 +7-643------98-26--3------5-84-----7-12-39-58669-1784-3---7-3-95--8-2----9-----3-2756439218419852637382617954843265179127394586695178423261743895538926741974581362 +7-6--8----8957-3----319-7-8-7-----4596--15----5--27--34257-163-1-----2-763-9--4--716238594289574316543196728372869145964315872851427963425781639198643257637952481 +-1--684--5247-1---76834-12--9--73--6--75-----3----6798-------6---9--7-428461---75913268457524791683768345129492873516687519234351426798275984361139657842846132975 +7-------5-91-857--4-572-86-1---------56--2--82-36581--3-42-6--78--513-96----74--3782461935691385724435729861148937652956142378273658149314296587827513496569874213 +2-5--7-----931-7-2-7142---959-1----83-----2-68642-3-9515--34----4--629---2----48-235697814489315762671428539592146378317589246864273195158934627743862951926751483 +----1-5-44815---27596------75--9---21----29--82---71-6-17--5-3-24-9-3---63-2--4--372618594481539627596724813754196382163842975829357146917465238245983761638271459 +867---------2--61-912--6-5414--38---2-5-6---337---41---2--4-8--65-8---4-49--5-27-867415932534297618912386754146938527285761493379524186723149865651872349498653271 +-6-3---9-9--51---623-49--5---7-35-1--8-27-9-----98-67-5-98431-----162---81------3165327498974518326238496751497635812681274935352981674529843167743162589816759243 +----625-7--81----6672-4-83-1-59-746--6---4----9-6-----71-32---452---137-84---62-9931862547458173926672549831185937462367284195294615783719328654526491378843756219 +---7----592---86--1-5---8-3---3---195-6987-24493-51-6835-67------2---9------25--6834716295927538641165492873278364519516987324493251768351679482682143957749825136 +1---62-5-7------8----4-------169853-987--516-6-571---8218937----69541-7----2--9--143862759792153486856479321421698537987325164635714298218937645369541872574286913 +17-----824-6--73-5--2--86---6-8-1-9-8-9-72--4-4----7-879418-2-------543-325--98--173654982486297315952318647267841593839572164541936728794183256618725439325469871 +-----5--65-86--19--6482-5-3--------14----825-8251--7-4751-92--83-6--7---24---63-7132975486578643192964821573697254831413768259825139764751392648386417925249586317 +61-28-75------56---85-6--43--1--8-25------4--258-4-19-5493-28--1-2--697--67--9---613284759724935618985167243471698325396521487258743196549372861132856974867419532 +--9--38-4-3--9---5-57-4-9-16---8-54--2-9--6-7---36-2-99-48--152------378-82--5---169573824438192765257648931691287543823954617745361289974836152516429378382715496 +-235-4-----56-24---7--98-2---7481-59---763---8-----7-4-5-8--3--3--9-7--5-9-1-58-6123574968985612473674398521237481659549763182816259734451826397368947215792135846 +32----8---8-3-5-24--4-216--5--21-4388-7--9---2----457979---3-866----2--5-52---31-325746891186395724974821653569217438847539162213684579791453286638172945452968317 +-163-52------8----4-2--15-82-1--98-45-4--8--33--6-41521-38-69-----4-7---9--213-86816345279735982641492761538271539864564128793389674152143856927628497315957213486 +2-9--17-3---3--2--3--5--986--89635---3-7-----7-28456319-5--8-67--7------6--1-7829259681743864379215371524986418963572536712498792845631925438167187296354643157829 +6---781-93----48-----65--344-6-32--753-8---2----7--6-32--4193--9-----71--532674--642378159315924876789651234496132587537846921821795643278419365964583712153267498 +--15--43-24836-1--5-39--82----73-----561829--9--65-21-8--41--62-----5---4-52--38-791528436248367195563941827124739658356182974987654213879413562632895741415276389 +9----63-882-4356--7--9-85-429-7--4-618-------654-927--36-5---42--9------4--3-98-5945176328821435697736928514293751486187643259654892731368517942579284163412369875 +2357-4--8------4---84--26-58172963-46--5812-----4---1-4-1--75-33--1-----5286----1235764198169358427784912635817296354643581279952473816491827563376145982528639741 +5----9762--7-8-----6-7-5--979235-14--1-9-23--843-71---239-1--78-------9---6--7-34581439762927186453364725819792358146615942387843671925239514678478263591156897234 +----138--12-8-7-----3----5--41---26-35--6--8----7--1--592-416-8---2--5-4-185769-3975613842124857396683429751841935267357162489269784135592341678736298514418576923 +47-3---1-6-------7---17-628--9--1856148-3-7-2---798--4-14--3--5-2591-------54-9-1472386519681259347593174628739421856148635792256798134914863275825917463367542981 +--5---7--23-7-6-5-7-9-51-68--2------87-1--6--4-1687-2-9-481-5-----9-54----64728-3165298734238746951749351268692534187873129645451687329924813576387965412516472893 +-1-76-3--9--4528----738-4-914--23--7--617-2--7--8-4---43----6-5-9-5--748-7-2-8---814769352963452871527381469149623587386175294752894136438917625291536748675248913 +-8----2--3-4-51------48---1-----5--42-87--1--94----7-341-572-8663294--17-----3-92187369245394251678526487931763195824258734169941826753419572386632948517875613492 +5--3--46--1--7-------59-8-78-7-53249145-267-3-9--48------4----6-31---97-7-6-3----579382461318674592624591837867153249145926783293748615982417356431265978756839124 +75-21936-86935-41---2---79-54-----3--83-25------4----9--8----5-6---94--3---57--26754219368869357412132648795546981237983725641217436589378162954625894173491573826 +39---74---14--936-758-36-9-475-6---9-----164--2----7--56-1-38-48---7591-----9--2-396217458214589367758436291475362189983751642621948735569123874842675913137894526 +-6-2--49-8---7-2-352----7-8-8--5---4-9--438-1--5--86-9--4-67---6--8-9147------536763281495849675213521394768187956324296743851435128679314567982652839147978412536 +23--8-4-5------2--56872---37138496-2--45138-----2---1-1-2-7-5-6--61-----3854----1237981465941635287568724193713849652624513879859267314192378546476152938385496721 +--6239-145-3---7----45769---3-49-6-29----814--42--3---46-1-2-----8-6-4---7538-2--786239514593841726214576938831495672957628143642713895469152387328967451175384269 +8932-51--641----------13--97-4-3-2--95-7---1-3-2---67-1-5--2--62-8-94-5---9-6--2-893245167641987532527613489784136295956728314312459678135872946268394751479561823 +7---9------6--83-14-8----7586-7-514223-819-6715--4----6--3-7------96-7-4--1----3-713596428526478391498123675869735142234819567157642983645387219382961754971254836 +-----3-9-78---5-6---2------348-51--65---68349-693---85914---673--7-4----625--98-4156823497783495261492617538348951726571268349269374185914582673837146952625739814 +52316---7847---------3-72--3-6----9821--9--7-9-4--3--67-16--8--6-54-2-1---2--8-6-523164987847925631169387254376241598218596473954873126731659842685432719492718365 +-64-58--1--1-43-65---6--4-723-----4--1-49--3----38-57---2--571--49---8--1-78-4293964758321871243965523619487238576149715492638496381572682935714349127856157864293 +-5-3-4217--48-1-65--2-79-38---9-----9-7-46--3----871-----738-91----9--843-841--2-859364217734821965612579438481953672927146853563287149246738591175692384398415726 +--5-9----6--2---182-3---54--624-5371-41-3-----8791265---65-8-------69-351-----8--815694723674253918293871546962485371541736289387912654436528197728169435159347862 +-7--6----63-49--8-8-52-3-4121-6--5-35--9---26-6-12-89415-3-------6-1-4599-------7471568932632491785895273641219684573548937126763125894157349268386712459924856317 +-1-8-----987---136325-9--4864827---3-93--64-22--34-869-5-----------6-9--1-4-2-3--416837295987452136325691748648279513593186472271345869859713624732564981164928357 +1--98-3--932-674--58-2-379-2598-------------56-84---79---7-9--1-936---8--6-3-8-24176984352932567418584213796259876143347192865618435279825749631493621587761358924 +-73--48-5--2--63--41-----62-69-42--73--6-1-9-7-----4-694716-2-------578-285--96--673294815592816374418357962869542137324671598751983426947168253136425789285739641 +-584----9-49----5326--5--1---63---9--12--93---976-8-2-674-92--1---1-46--831------758413269149286753263957814586321497412579386397648125674892531925134678831765942 +---4-56-119----5-465---1-8------64727652-98--4--713-5----3972-5-26-5---8--3--2---238475691197638524654921387319586472765249813482713956841397265926154738573862149 +8-62--4717-5--8-3291---4-65--9------38--91--615----7--561----97-9-----58-78-65-4-836259471745618932912734865629587314387491526154326789561843297493172658278965143 +4-------6-1-25--9-79--84----5---2------47-6-11-----24-9-153748-5-8-----73-2-41965425793816813256794796184523654912378239478651187365249961537482548629137372841965 +9--4--6314-6-1--9--7---6---3-9-5-2--56-782----426935-86----1-82-5-329-76--------9928475631436218795175936824389154267561782943742693518697541382854329176213867459 +-84-9-5-73-765-19-9----7----76--5--11-2-4-7654-------------29-32-3--9-165--8-6472684193527327654198951287634876925341192348765435761289768412953243579816519836472 +52-6-1---------9363--74--5-4-5-9---78-7---125--285--49------4-86-498357----4-5-93529631784741528936386749251435192867897364125162857349953276418614983572278415693 +-8--64-9596--57--8-259-----5-----37-7--51--8-2-674----8-2--6--3--4----511734-58-2387264195961357428425981637518629374749513286236748519852176943694832751173495862 +5-2--36-7---6----2--61--4952-79813649--546--1-6-7-----1-5--974-7----------43-7529512493687849675132376128495257981364938546271461732958125869743793254816684317529 +--256----15--72--497--4--25-----531--85--1-4--917-6---5-93184-6---9---587--6-4--3842569731153872964976143825267485319385291647491736582529318476634927158718654293 +1365----8---1---37725-48--6--7---8-2--948--5-58-6-27---42---68-6--8----997-2--1-3136579428894126537725348916417953862269487351583612794342791685651834279978265143 +-98-----5---397---1-42859-----81-36-6--5-4-9--8-67-1----194---3-5712--4--3--5--1-398461725526397481174285936745819362612534897983672154261948573857123649439756218 +-1---42786--1583-9489---5--5-7---1-4-6--157--1-4-37-----659--1----2--9--9-1---832315964278672158349489372561537629184268415793194837625826593417743281956951746832 +476-58-3--1-7-9-4-92-64-75-8--49-6-37-48--9-----57---1-893--5-7--------22679-----476258139518739246923641758851492673734816925692573481189324567345167892267985314 +4-8--61-5---5--8----53--429--96-12841--------3-4--2-91-5-1-----2--4953--8-1273956438926175792514863615387429579631284126849537384752691953168742267495318841273956 +-9-185-732--79---173--42--9--9218-3-32------41---6-----6-----9-94-5---185-283-4-7694185273285793641731642859459218736326957184178364925863471592947526318512839467 +--34-8---9--13-6---81-62--3-1-39-2----58764--3--24-8-5-28---9-7-5-7--384-3-6-4---673458129942137658581962743814395276295876431367241895428513967156729384739684512 +------7---5---6----1---2-8419-2--835--51-862-28-653--1-6-38-172---5243963-----4--942815763758436219613972584196247835435198627287653941564389172871524396329761458 +--129-6---8------7-564-8---93-8-176216-32548-42------5-1----89----58--71--2--9---341297658289653147756418923935841762167325489428976315514732896693584271872169534 +-----16--9--5--21-51-863-----9--4-5242--75---75-----84--5436--7-9--18523173--2---847291635936547218512863479369184752428375961751629384285436197694718523173952846 +-98-5-7-6---8------7--9215--3--182-5----46---8-1527--3-86-3-5-7--2-8-6-9957-61--2298154736615873924473692158734918265529346871861527493186239547342785619957461382 +1---7629-79--251--8-29------8756-----5-23--1--2-----54-18--74----6---32-5346-28-1145876293793425186862913547487561932659234718321789654218357469976148325534692871 +9-72--54--386--17-4---8736--2439-6-1---4---2-----2--9--85--42372---6---53-17-2---967231548538649172412587369724398651196475823853126794685914237279863415341752986 +92-1-6-47----3-8---4--5213-8------5-572-9---3-----179-254-693--36---5-7-1-7--396-923186547615437829748952136891374652572698413436521798254769381369815274187243965 +42-3--1788--------79--4---6---2----4614-8-5---8--54-6---7-18-3----43-2979-35-7481426395178835671942791842356579263814614789523382154769247918635158436297963527481 +----638-5-------6976-98523-5--62-3--------5873-1-74---63-8----292----143-1-39-6-8192463875853217469764985231579628314246139587381574926635841792928756143417392658 +297-5-6-----93-2--346-7--1583--924--7---8-5---145-7-----3-45-----86--15-65---37-4297451638581936247346278915835192476762384591914567382123745869478629153659813724 +39---5-8-51-2--7434-----------1---5--4--56--8875--46----3-47--29-263-574---5-2139397415286518269743426873915639128457241756398875394621153947862982631574764582139 +5-8--4-31---5-------3-7849---6-59-74----12---95-437--61-5--6-437----5-18384-91--7578924631419563782623178495236859174847612359951437826195786243762345918384291567 +-----7-14749-1-3-2618-------932---76-7-3---8--21--8--3-3458----2-71--5---65-3--4-352967814749815362618423795893251476576394281421678953134589627287146539965732148 +-3-17--45-9--46-287-4--2-319------6-61-92-5-3-2-----9---278-4193----98---49-51---236178945195346728784592631953817264617924583428635197562783419371469852849251376 +2--1659--81----5--6--798-42--82-96-7-9--3-42-7-2-8-----2647----3----62--1-58-37--274165983819342576653798142438219657591637428762584391926471835387956214145823769 +82-4-3-69-516--2-46---2----5---------32-4-9--97-5--432----7-8-64---3172578--6-39-827453169351689274694127583548392617132746958976518432213975846469831725785264391 +-93--6---1-89--367------9425---9--86-3-1--4-5---25-1-3-64-8-7-1--1--28-9-2--1-6--293476518148925367675831942517394286932168475486257193364589721751642839829713654 +--5---49----432---4--915-78-8-5--3---7-18-52---374--8-36-89-----4--57--68--26-9--215678493798432165436915278189526347674183529523749681361894752942357816857261934 +87--13--2--972--1--2-6-8-----236--84-4-851-6-7--29--3-4--5--82638-----952--1-6---874913652639725418521648379152367984943851267768294531417539826386472195295186743 +-968-7---4--9-3--7-37----69-19---852--413-9------5---1261-----3-4-392-189----6725196827534452963187837541269319674852524138976678259341261785493745392618983416725 +1247965-3968--1--4--5----9---16489----9--3---7--9-53-84--56-8-1--------55-78346--124796583968351274375482196231648957859173462746925318492567831683219745517834629 +3-67----4--438-5695-92--7-34-587-2-----13------2495-7885-64-9-------7---9-35--6-7386759124274381569519264783435876291798132456162495378857643912641927835923518647 +------593-7-25------54-8271-3-8--4-54--97-1-88---3-7--6-3---8-2--8-2-9-65----6-47284617593179253684365498271937861425456972138821534769613749852748325916592186347 +--7--4---394---587816-3-42-542-968--6---28354-835--6-272--6---8--1----------5---3257984136394612587816735429542396871679128354183547692725463918431879265968251743 +---3---4-7-6-28----83---7-----81-25--5--43-7-6-----8---182945-746578-9-32-----4-1129375648746128395583469712934817256852643179671952834318294567465781923297536481 +6--4-2-97-549--632-297634----3-----8---698753-7-32-914-4---982--6---7-----------1638452197754981632129763485593174268412698753876325914347519826261837549985246371 +---5-41--6--1739-81-592-4--3--------2-1697-3--792--6--4-----7---837-6-4-5-7-42-69798564123624173958135928476356481297241697835879235614462359781983716542517842369 From 257d88dc2e8918c2c7700a4dd830026e27d6506e Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 29 Oct 2024 16:45:26 +0100 Subject: [PATCH 27/63] dtlaunch: postpone load icons not initially needed Draw the first screen, then load in the rest of the icons from storage. --- apps/dtlaunch/ChangeLog | 1 + apps/dtlaunch/app-b2.js | 13 +++++++++---- apps/dtlaunch/metadata.json | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index 5cac5770ee1..585e89ef957 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -30,3 +30,4 @@ when moving pages. Add caching for faster startups. 0.23: Bangle 1: Fix issue with missing icons, added touch screen interactions 0.24: Add buzz-on-interaction setting 0.25: Minor code improvements +0.26: Bangle 2: Postpone loading icons that are not needed initially. diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index 2108910fcc9..9da91498086 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -33,10 +33,10 @@ s.writeJSON("launch.cache.json", launchCache); } let apps = launchCache.apps; - apps.forEach(app=>{ - if (app.icon) - app.icon = s.read(app.icon); // should just be a link to a memory area - }); + for (let i = 0; i < 4; i++) { // Initially only load icons for the current page. + if (apps[i].icon) + apps[i].icon = s.read(apps[i].icon); // should just be a link to a memory area + } let Napps = apps.length; let Npages = Math.ceil(Napps/4); @@ -101,6 +101,11 @@ Bangle.loadWidgets(); drawPage(0); + for (let i = 4; i < apps.length; i++) { // Load the rest of the app icons that were not initially. + if (apps[i].icon) + apps[i].icon = s.read(apps[i].icon); // should just be a link to a memory area + } + let swipeListenerDt = function(dirLeftRight, dirUpDown){ updateTimeoutToClock(); selected = -1; diff --git a/apps/dtlaunch/metadata.json b/apps/dtlaunch/metadata.json index bac0ed36934..0f64308293c 100644 --- a/apps/dtlaunch/metadata.json +++ b/apps/dtlaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.25", + "version": "0.26", "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", From b721023daa3eea4647fe76efe81026307e6d2253 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 29 Oct 2024 21:21:17 +0000 Subject: [PATCH 28/63] drained: only check for power-restore when charging --- apps/drained/app.js | 12 +++++++++--- apps/drained/app.ts | 13 ++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/drained/app.js b/apps/drained/app.js index 57acadf25d2..d4cb97db842 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -101,14 +101,20 @@ function drainedRestore() { load(); } var checkCharge = function () { - if (!Bangle.isCharging() || E.getBattery() < restore) { + if (E.getBattery() < restore) { draw(); return; } drainedRestore(); }; -checkCharge(); -drainedInterval = setInterval(checkCharge, interval * 60 * 1000); +if (Bangle.isCharging()) + checkCharge(); +Bangle.on("charging", function (charging) { + if (drainedInterval) + drainedInterval = clearInterval(drainedInterval); + if (charging) + drainedInterval = setInterval(checkCharge, interval * 60 * 1000); +}); if (!keepStartup) { var storage = require("Storage"); for (var _i = 0, exceptions_1 = exceptions; _i < exceptions_1.length; _i++) { diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 343fa10692f..fd39b11bdf4 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -131,15 +131,22 @@ function drainedRestore() { // "public", to allow users to call } const checkCharge = () => { - if(!Bangle.isCharging() || E.getBattery() < restore) { + if(E.getBattery() < restore) { draw(); return; } drainedRestore(); }; -checkCharge(); -drainedInterval = setInterval(checkCharge, interval * 60 * 1000); +if (Bangle.isCharging()) + checkCharge(); + +Bangle.on("charging", charging => { + if(drainedInterval) + drainedInterval = clearInterval(drainedInterval) as undefined; + if(charging) + drainedInterval = setInterval(checkCharge, interval * 60 * 1000); +}); if(!keepStartup){ const storage = require("Storage"); From 2d25812228a782c4fb9d96773c91ece00ac15296 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Mon, 28 Oct 2024 20:16:14 +0100 Subject: [PATCH 29/63] chore: rm semicolons at end of clkinfo + settings This was done in response to https://github.com/espruino/BangleApps/commit/9185793042c7bfddba13333d33f678c2ca246e5d#commitcomment-148439450 . --- apps/a_dndtoggle/settings.js | 3 +-- apps/activepedom/settings.js | 2 +- apps/agpsdata/settings.js | 2 +- apps/alarm/settings.js | 2 +- apps/andark/settings.js | 2 +- apps/antonclkplus/settings.js | 2 +- apps/banglexercise/settings.js | 2 +- apps/barclock/settings.js | 2 +- apps/berlinc/settings.js | 2 +- apps/bikespeedo/settings.js | 2 +- apps/blc/blc.settings.js | 2 +- apps/blecsc/clkinfo.js | 2 -- apps/boxclk/settings.js | 2 +- apps/bthrm/settings.js | 2 +- apps/carcrazy/settings.js | 2 +- apps/chimer/settings.js | 2 +- apps/circlesclock/settings.js | 2 +- apps/clicompleteclk/settings.js | 2 +- apps/clkinfocal/settings.js | 2 +- apps/clkinfogps/clkinfo.js | 2 +- apps/clkinfom/clkinfo.js | 2 +- apps/clkinfostopw/clkinfo.js | 2 +- apps/clkinfostopw/clkinfo.ts | 2 +- apps/clockcal/settings.js | 2 +- apps/cogclock/settings.js | 2 +- apps/counter2/settings.js | 2 +- apps/cprassist/settings.js | 2 +- apps/daisy/settings.js | 1 - apps/dane_tcr/settings.js | 2 +- apps/dragboard/settings.js | 2 +- apps/draguboard/settings.js | 2 +- apps/drained/settings.js | 2 +- apps/drinkcounter/settings.js | 2 +- apps/dtlaunch/settings-b2.js | 2 +- apps/ffcniftyb/settings.js | 2 +- apps/folderlaunch/settings.js | 2 +- apps/gassist/settings.js | 2 +- apps/gbmusic/settings.js | 2 +- apps/getup/settings.js | 2 +- apps/gipy/settings.js | 2 +- apps/gpsrec/settings.js | 2 +- apps/gpssetup/settings.js | 2 +- apps/iconlaunch/settings.js | 2 +- apps/infoclk/settings.js | 2 +- apps/largeclock/settings.js | 2 +- apps/launch/settings.js | 2 +- apps/messagelist/settings.js | 2 +- apps/messages/settings.js | 2 +- apps/messages_light/messages_light.settings.js | 3 +-- apps/messagesoverlay/settings.js | 2 +- apps/metronome/settings.js | 2 +- apps/multitimer/settings.js | 2 +- apps/nesclock/settings.js | 2 +- apps/nightwatch/nightwatch.settings.js | 2 +- apps/owmweather/settings.js | 2 +- apps/pebble/pebble.settings.js | 2 +- apps/pebbled/pebbled.settings.js | 2 +- apps/popconlaunch/settings.js | 2 +- apps/poweroff/settings.js | 2 +- apps/puzzle15/puzzle15.settings.js | 4 ++-- apps/qcenter/settings.js | 2 +- apps/rebbleagenda/settings.js | 2 +- apps/recorder/clkinfo.js | 2 +- apps/rep/settings.js | 2 +- apps/saclock/settings.js | 2 +- apps/sched/settings.js | 2 +- apps/score/score.settings.js | 2 +- apps/sensortools/settings.js | 2 +- apps/shadowclk/settings.js | 2 +- apps/shortcuts/settings.js | 3 +-- apps/simplebgclock/settings.js | 2 +- apps/slomoclock/settings.js | 2 +- apps/slopeclockpp/settings.js | 2 +- apps/smclock/settings.js | 2 +- apps/speedalt/settings.js | 2 +- apps/speedalt2/settings.js | 2 +- apps/swp2clk/settings.js | 2 +- apps/taglaunch/settings.js | 2 +- apps/thunder/settings.js | 2 +- apps/timecal/timecal.settings.js | 2 +- apps/timerclk/settings.js | 2 +- apps/timestamplog/settings.js | 2 +- apps/toucher/settings.js | 2 +- apps/touchtimer/settings.js | 2 +- apps/trex/settings.js | 2 +- apps/usgs/settings.js | 2 +- apps/weatherClock/settings.js | 2 +- apps/wid_edit/settings.js | 2 +- apps/widalarmeta/settings.js | 2 +- apps/widbaroalarm/settings.js | 2 +- apps/widbatwarn/settings.js | 2 +- apps/widbgjs/settings.js | 2 +- apps/widdst/settings.js | 2 +- apps/widgps/settings.js | 2 +- apps/widhrm/settings.js | 2 +- apps/widmp/settings.js | 2 +- apps/widshipbell/settings.js | 1 - apps/widsleepstatus/settings.js | 2 +- 98 files changed, 96 insertions(+), 103 deletions(-) diff --git a/apps/a_dndtoggle/settings.js b/apps/a_dndtoggle/settings.js index 5316525b3ce..483af8c97a4 100644 --- a/apps/a_dndtoggle/settings.js +++ b/apps/a_dndtoggle/settings.js @@ -29,5 +29,4 @@ } E.showMenu(buildMainMenu()); - }); - \ No newline at end of file + }) diff --git a/apps/activepedom/settings.js b/apps/activepedom/settings.js index 3b64d8735b2..16799f0dbe9 100644 --- a/apps/activepedom/settings.js +++ b/apps/activepedom/settings.js @@ -109,4 +109,4 @@ }, }; E.showMenu(menu); -}); +}) diff --git a/apps/agpsdata/settings.js b/apps/agpsdata/settings.js index 64fa25330a6..95b06fe55a2 100644 --- a/apps/agpsdata/settings.js +++ b/apps/agpsdata/settings.js @@ -68,4 +68,4 @@ function buildMainMenu() { } E.showMenu(buildMainMenu()); -}); +}) diff --git a/apps/alarm/settings.js b/apps/alarm/settings.js index 765e5a5fa37..2843fbdb13c 100644 --- a/apps/alarm/settings.js +++ b/apps/alarm/settings.js @@ -48,4 +48,4 @@ }; E.showMenu(appMenu); -}); +}) diff --git a/apps/andark/settings.js b/apps/andark/settings.js index 7089137050f..7bbceb2c254 100644 --- a/apps/andark/settings.js +++ b/apps/andark/settings.js @@ -25,4 +25,4 @@ }; E.showMenu(appMenu); -}); +}) diff --git a/apps/antonclkplus/settings.js b/apps/antonclkplus/settings.js index 4448c00ed74..70851e98395 100644 --- a/apps/antonclkplus/settings.js +++ b/apps/antonclkplus/settings.js @@ -94,4 +94,4 @@ E.showMenu(mainmenu); -}); +}) diff --git a/apps/banglexercise/settings.js b/apps/banglexercise/settings.js index 0b52acd7275..a52634faf00 100644 --- a/apps/banglexercise/settings.js +++ b/apps/banglexercise/settings.js @@ -17,4 +17,4 @@ } } }); -}); +}) diff --git a/apps/barclock/settings.js b/apps/barclock/settings.js index 04f0a38ba11..bc292ef6f0d 100644 --- a/apps/barclock/settings.js +++ b/apps/barclock/settings.js @@ -32,4 +32,4 @@ } require("ClockFace_menu").addItems(menu, save, items); E.showMenu(menu); -}); +}) diff --git a/apps/berlinc/settings.js b/apps/berlinc/settings.js index a1b655a6278..b240a5f460e 100644 --- a/apps/berlinc/settings.js +++ b/apps/berlinc/settings.js @@ -23,4 +23,4 @@ }; E.showMenu(mainmenu); -}); +}) diff --git a/apps/bikespeedo/settings.js b/apps/bikespeedo/settings.js index bb943c081c1..0326d7529a5 100644 --- a/apps/bikespeedo/settings.js +++ b/apps/bikespeedo/settings.js @@ -68,4 +68,4 @@ E.showMenu(appMenu); -}); +}) diff --git a/apps/blc/blc.settings.js b/apps/blc/blc.settings.js index 00e9c284bbe..9143fc16ec8 100644 --- a/apps/blc/blc.settings.js +++ b/apps/blc/blc.settings.js @@ -69,4 +69,4 @@ //}; E.showMenu(mainmenu); -}); +}) diff --git a/apps/blecsc/clkinfo.js b/apps/blecsc/clkinfo.js index 9a9515c3a9f..69cd022afd7 100644 --- a/apps/blecsc/clkinfo.js +++ b/apps/blecsc/clkinfo.js @@ -70,5 +70,3 @@ }; return ci; }) - - diff --git a/apps/boxclk/settings.js b/apps/boxclk/settings.js index e35db455da1..c4b41101b41 100644 --- a/apps/boxclk/settings.js +++ b/apps/boxclk/settings.js @@ -91,4 +91,4 @@ }); E.showMenu(menu); -}); +}) diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js index 68e958db88a..310816ddabc 100644 --- a/apps/bthrm/settings.js +++ b/apps/bthrm/settings.js @@ -371,4 +371,4 @@ }; E.showMenu(buildMainMenu()); -}); +}) diff --git a/apps/carcrazy/settings.js b/apps/carcrazy/settings.js index ee3bbd417e7..48301a86513 100644 --- a/apps/carcrazy/settings.js +++ b/apps/carcrazy/settings.js @@ -17,4 +17,4 @@ } }; E.showMenu(menu); -}); +}) diff --git a/apps/chimer/settings.js b/apps/chimer/settings.js index 55160c9be0e..1cfb980f4e3 100644 --- a/apps/chimer/settings.js +++ b/apps/chimer/settings.js @@ -91,4 +91,4 @@ settings = readSettings(); showMainMenu(); -}); +}) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 714b48f2e34..0a92f5a5ae5 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -92,4 +92,4 @@ } showMainMenu(); -}); +}) diff --git a/apps/clicompleteclk/settings.js b/apps/clicompleteclk/settings.js index 0213ead6e55..f062b98b1bb 100644 --- a/apps/clicompleteclk/settings.js +++ b/apps/clicompleteclk/settings.js @@ -47,4 +47,4 @@ }, '< Back': back, }); -}); +}) diff --git a/apps/clkinfocal/settings.js b/apps/clkinfocal/settings.js index 6fe8f281711..508de5ddc50 100644 --- a/apps/clkinfocal/settings.js +++ b/apps/clkinfocal/settings.js @@ -34,4 +34,4 @@ } }); -}); +}) diff --git a/apps/clkinfogps/clkinfo.js b/apps/clkinfogps/clkinfo.js index 7db9bbdaeb0..740e05eda8c 100644 --- a/apps/clkinfogps/clkinfo.js +++ b/apps/clkinfogps/clkinfo.js @@ -124,4 +124,4 @@ }; return info; -}); +}) diff --git a/apps/clkinfom/clkinfo.js b/apps/clkinfom/clkinfo.js index a3dae43e1d1..f01649c4cf3 100644 --- a/apps/clkinfom/clkinfo.js +++ b/apps/clkinfom/clkinfo.js @@ -58,4 +58,4 @@ }; return info; -}); +}) diff --git a/apps/clkinfostopw/clkinfo.js b/apps/clkinfostopw/clkinfo.js index fbbe80a555e..caf460da330 100644 --- a/apps/clkinfostopw/clkinfo.js +++ b/apps/clkinfostopw/clkinfo.js @@ -74,4 +74,4 @@ } ] }; -}); +}); // FIXME: semi-colon added automatically when Typescript generates Javascript file? diff --git a/apps/clkinfostopw/clkinfo.ts b/apps/clkinfostopw/clkinfo.ts index f0c2a6ccb58..78794205e1d 100644 --- a/apps/clkinfostopw/clkinfo.ts +++ b/apps/clkinfostopw/clkinfo.ts @@ -80,4 +80,4 @@ } ] }; -}) satisfies ClockInfoFunc +}) satisfies ClockInfoFunc // FIXME: semi-colon added automatically when Typescript generates Javascript file? diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index ea613f5c0fb..ddacb4a1617 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -114,4 +114,4 @@ }; // Show the menu E.showMenu(menu); -}); +}) diff --git a/apps/cogclock/settings.js b/apps/cogclock/settings.js index fb1dd761c8b..deae484c913 100644 --- a/apps/cogclock/settings.js +++ b/apps/cogclock/settings.js @@ -7,4 +7,4 @@ "showDate", "hideWidgets" ]); E.showMenu(menu); -}); +}) diff --git a/apps/counter2/settings.js b/apps/counter2/settings.js index b38df18247c..f97d49ad322 100644 --- a/apps/counter2/settings.js +++ b/apps/counter2/settings.js @@ -52,4 +52,4 @@ }; // Show the menu E.showMenu(menu); -}); +}) diff --git a/apps/cprassist/settings.js b/apps/cprassist/settings.js index 5776baa0b99..5099d0b7d3f 100644 --- a/apps/cprassist/settings.js +++ b/apps/cprassist/settings.js @@ -61,4 +61,4 @@ } }; E.showMenu(menu); -}); +}) diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index c0a2ffeea5b..250633dea16 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -56,4 +56,3 @@ } }); }) - diff --git a/apps/dane_tcr/settings.js b/apps/dane_tcr/settings.js index 46988ec2622..c13a0825da7 100644 --- a/apps/dane_tcr/settings.js +++ b/apps/dane_tcr/settings.js @@ -54,4 +54,4 @@ }, '< Back': back }); -}); \ No newline at end of file +}) diff --git a/apps/dragboard/settings.js b/apps/dragboard/settings.js index 59a13c44353..2aac13b2889 100644 --- a/apps/dragboard/settings.js +++ b/apps/dragboard/settings.js @@ -45,4 +45,4 @@ }; E.showMenu(appMenu); -}); \ No newline at end of file +}) diff --git a/apps/draguboard/settings.js b/apps/draguboard/settings.js index ff4ede637f6..58634b1b380 100644 --- a/apps/draguboard/settings.js +++ b/apps/draguboard/settings.js @@ -41,4 +41,4 @@ }; E.showMenu(appMenu); -}); \ No newline at end of file +}) diff --git a/apps/drained/settings.js b/apps/drained/settings.js index ce72f215f83..d82a9f6d450 100644 --- a/apps/drained/settings.js +++ b/apps/drained/settings.js @@ -87,4 +87,4 @@ }); }; updateAndRedraw(); -}); +}) diff --git a/apps/drinkcounter/settings.js b/apps/drinkcounter/settings.js index 336229b7343..8353103e3f2 100644 --- a/apps/drinkcounter/settings.js +++ b/apps/drinkcounter/settings.js @@ -55,4 +55,4 @@ E.showMenu(mainmenu); -}); +}) diff --git a/apps/dtlaunch/settings-b2.js b/apps/dtlaunch/settings-b2.js index 6a50f90d4d6..f6894e289f0 100644 --- a/apps/dtlaunch/settings-b2.js +++ b/apps/dtlaunch/settings-b2.js @@ -65,4 +65,4 @@ } }, }); -}); +}) diff --git a/apps/ffcniftyb/settings.js b/apps/ffcniftyb/settings.js index da350edd860..8c3bb6e4d37 100644 --- a/apps/ffcniftyb/settings.js +++ b/apps/ffcniftyb/settings.js @@ -28,4 +28,4 @@ }); E.showMenu(menu); -}); +}) diff --git a/apps/folderlaunch/settings.js b/apps/folderlaunch/settings.js index b589bb3f747..98720a1db7d 100644 --- a/apps/folderlaunch/settings.js +++ b/apps/folderlaunch/settings.js @@ -248,4 +248,4 @@ }); }; showMainMenu(); -}); +}) diff --git a/apps/gassist/settings.js b/apps/gassist/settings.js index 20634ed5ecb..0b54c350ff2 100644 --- a/apps/gassist/settings.js +++ b/apps/gassist/settings.js @@ -29,4 +29,4 @@ } // Initially show the menu showMenu(); -}); +}) diff --git a/apps/gbmusic/settings.js b/apps/gbmusic/settings.js index 9b8d35be93c..70d96c1e9a0 100644 --- a/apps/gbmusic/settings.js +++ b/apps/gbmusic/settings.js @@ -38,4 +38,4 @@ }; E.showMenu(menu); -}); +}) diff --git a/apps/getup/settings.js b/apps/getup/settings.js index f34262f2ab0..db84fd84dfd 100644 --- a/apps/getup/settings.js +++ b/apps/getup/settings.js @@ -45,4 +45,4 @@ }, }; E.showMenu(menu); -}); +}) diff --git a/apps/gipy/settings.js b/apps/gipy/settings.js index e3b00359c87..9562bc3c139 100644 --- a/apps/gipy/settings.js +++ b/apps/gipy/settings.js @@ -99,4 +99,4 @@ } } }); -}); +}) diff --git a/apps/gpsrec/settings.js b/apps/gpsrec/settings.js index 23a58d58f5f..25feadd7c86 100644 --- a/apps/gpsrec/settings.js +++ b/apps/gpsrec/settings.js @@ -1,4 +1,4 @@ (function(back) { // just go right to our app - we need all the memory load("gpsrec.app.js"); -})(); +})() // FIXME: Since this is called directly, should it still have a semi-colon? diff --git a/apps/gpssetup/settings.js b/apps/gpssetup/settings.js index 0e3c621d1de..71a64f69bc7 100644 --- a/apps/gpssetup/settings.js +++ b/apps/gpssetup/settings.js @@ -1,4 +1,4 @@ (function(back) { // just go right to our app load("gpssetup.app.js"); -})(); +})() // FIXME: Since this is called directly, should it still have a semi-colon? diff --git a/apps/iconlaunch/settings.js b/apps/iconlaunch/settings.js index 3278075e45a..ef2c188d7b4 100644 --- a/apps/iconlaunch/settings.js +++ b/apps/iconlaunch/settings.js @@ -50,4 +50,4 @@ }, }; E.showMenu(appMenu); -}); +}) diff --git a/apps/infoclk/settings.js b/apps/infoclk/settings.js index a9adf87fc1a..44182540ba5 100644 --- a/apps/infoclk/settings.js +++ b/apps/infoclk/settings.js @@ -744,4 +744,4 @@ } showMainMenu(); -}); \ No newline at end of file +}) diff --git a/apps/largeclock/settings.js b/apps/largeclock/settings.js index 4ebf842ce4d..a5e35192a2a 100644 --- a/apps/largeclock/settings.js +++ b/apps/largeclock/settings.js @@ -82,4 +82,4 @@ }; E.showMenu(mainMenu); -}); +}) diff --git a/apps/launch/settings.js b/apps/launch/settings.js index 496a6d77e4a..f4f3bb31b57 100644 --- a/apps/launch/settings.js +++ b/apps/launch/settings.js @@ -34,4 +34,4 @@ } }; E.showMenu(appMenu); -}); +}) diff --git a/apps/messagelist/settings.js b/apps/messagelist/settings.js index 1dc80ade114..1bf60c74434 100644 --- a/apps/messagelist/settings.js +++ b/apps/messagelist/settings.js @@ -136,4 +136,4 @@ } showMainMenu(); -}); +}) diff --git a/apps/messages/settings.js b/apps/messages/settings.js index 1d429580c80..4ccc47237e7 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -97,4 +97,4 @@ }, }; E.showMenu(mainmenu); -}); +}) diff --git a/apps/messages_light/messages_light.settings.js b/apps/messages_light/messages_light.settings.js index cd813d928b0..890c236924c 100644 --- a/apps/messages_light/messages_light.settings.js +++ b/apps/messages_light/messages_light.settings.js @@ -23,5 +23,4 @@ }, }; E.showMenu(mainmenu); - }); - \ No newline at end of file + }) diff --git a/apps/messagesoverlay/settings.js b/apps/messagesoverlay/settings.js index cd76bf11530..93e57fae037 100644 --- a/apps/messagesoverlay/settings.js +++ b/apps/messagesoverlay/settings.js @@ -63,4 +63,4 @@ } E.showMenu(buildMainMenu()); -}); +}) diff --git a/apps/metronome/settings.js b/apps/metronome/settings.js index 1dd4d92df06..3eacd737d4a 100644 --- a/apps/metronome/settings.js +++ b/apps/metronome/settings.js @@ -45,4 +45,4 @@ }, }; E.showMenu(menu); -}); +}) diff --git a/apps/multitimer/settings.js b/apps/multitimer/settings.js index 4faeb2573ee..fbed187a994 100644 --- a/apps/multitimer/settings.js +++ b/apps/multitimer/settings.js @@ -29,4 +29,4 @@ } }, }); -}); +}) diff --git a/apps/nesclock/settings.js b/apps/nesclock/settings.js index 0bbecc2cef4..154b3b6b634 100644 --- a/apps/nesclock/settings.js +++ b/apps/nesclock/settings.js @@ -39,4 +39,4 @@ E.showMenu(mainmenu); -}); +}) diff --git a/apps/nightwatch/nightwatch.settings.js b/apps/nightwatch/nightwatch.settings.js index 744ebd8dcfb..f4afe2e85be 100644 --- a/apps/nightwatch/nightwatch.settings.js +++ b/apps/nightwatch/nightwatch.settings.js @@ -22,4 +22,4 @@ } }, }); -}); +}) diff --git a/apps/owmweather/settings.js b/apps/owmweather/settings.js index f6b84c78519..69aabfad07a 100644 --- a/apps/owmweather/settings.js +++ b/apps/owmweather/settings.js @@ -81,4 +81,4 @@ } E.showMenu(buildMainMenu()); -}); +}) diff --git a/apps/pebble/pebble.settings.js b/apps/pebble/pebble.settings.js index 83032270ace..c4b86079293 100644 --- a/apps/pebble/pebble.settings.js +++ b/apps/pebble/pebble.settings.js @@ -54,4 +54,4 @@ } }, }); -}); +}) diff --git a/apps/pebbled/pebbled.settings.js b/apps/pebbled/pebbled.settings.js index d54517a7009..29f8c85bc98 100644 --- a/apps/pebbled/pebbled.settings.js +++ b/apps/pebbled/pebbled.settings.js @@ -55,4 +55,4 @@ }, } }); -}); +}) diff --git a/apps/popconlaunch/settings.js b/apps/popconlaunch/settings.js index 29528c5dd55..fa27f816ba3 100644 --- a/apps/popconlaunch/settings.js +++ b/apps/popconlaunch/settings.js @@ -12,4 +12,4 @@ }, }; E.showMenu(menu); -}); +}) diff --git a/apps/poweroff/settings.js b/apps/poweroff/settings.js index b22a7918af1..5103d08f336 100644 --- a/apps/poweroff/settings.js +++ b/apps/poweroff/settings.js @@ -43,4 +43,4 @@ } }; E.showMenu(mainmenu); -}); +}) diff --git a/apps/puzzle15/puzzle15.settings.js b/apps/puzzle15/puzzle15.settings.js index 352ec43150a..cd5d9ad2624 100644 --- a/apps/puzzle15/puzzle15.settings.js +++ b/apps/puzzle15/puzzle15.settings.js @@ -45,6 +45,6 @@ // Actually display the menu E.showMenu(mainmenu); -}); +}) -// end of file \ No newline at end of file +// end of file diff --git a/apps/qcenter/settings.js b/apps/qcenter/settings.js index ab7d561d1bb..2db1f28cc48 100644 --- a/apps/qcenter/settings.js +++ b/apps/qcenter/settings.js @@ -152,4 +152,4 @@ } showMainMenu(); -}); +}) diff --git a/apps/rebbleagenda/settings.js b/apps/rebbleagenda/settings.js index 8ed2ceae50e..40be2792013 100644 --- a/apps/rebbleagenda/settings.js +++ b/apps/rebbleagenda/settings.js @@ -66,4 +66,4 @@ }, } }); -}); \ No newline at end of file +}) diff --git a/apps/recorder/clkinfo.js b/apps/recorder/clkinfo.js index 6ca4f59d556..cde5c8ef410 100644 --- a/apps/recorder/clkinfo.js +++ b/apps/recorder/clkinfo.js @@ -35,4 +35,4 @@ }, ] : [], }; -}); +}) diff --git a/apps/rep/settings.js b/apps/rep/settings.js index bfadacda11b..8643f427436 100644 --- a/apps/rep/settings.js +++ b/apps/rep/settings.js @@ -41,4 +41,4 @@ }; } E.showMenu(menu); -}); +}) diff --git a/apps/saclock/settings.js b/apps/saclock/settings.js index fc50d04dc33..10d0489a7ef 100644 --- a/apps/saclock/settings.js +++ b/apps/saclock/settings.js @@ -20,4 +20,4 @@ hideWidgets: settings.hideWidgets, }); E.showMenu(menu); -}); +}) diff --git a/apps/sched/settings.js b/apps/sched/settings.js index 76036db2bea..c03cd6679ea 100644 --- a/apps/sched/settings.js +++ b/apps/sched/settings.js @@ -76,4 +76,4 @@ require("sched").setSettings(settings); }) }); -}); +}) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 88e36782165..f32bb618917 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -216,4 +216,4 @@ } }); -})(); +})() diff --git a/apps/sensortools/settings.js b/apps/sensortools/settings.js index ae631e60cbe..a5d3dfad1eb 100644 --- a/apps/sensortools/settings.js +++ b/apps/sensortools/settings.js @@ -102,4 +102,4 @@ } E.showMenu(buildMainMenu()); -}); +}) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index 1472cb0992c..183370082e6 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -155,4 +155,4 @@ } // Initially show the menu showMenu(); -}); +}) diff --git a/apps/shortcuts/settings.js b/apps/shortcuts/settings.js index 419b186d6d6..2c9ebd87a80 100644 --- a/apps/shortcuts/settings.js +++ b/apps/shortcuts/settings.js @@ -62,5 +62,4 @@ "BTN3 app": () => showApps("BTN3") }; E.showMenu(mainMenu); -}); - \ No newline at end of file +}) diff --git a/apps/simplebgclock/settings.js b/apps/simplebgclock/settings.js index 8fd042b3b0f..17524ca8df9 100644 --- a/apps/simplebgclock/settings.js +++ b/apps/simplebgclock/settings.js @@ -27,4 +27,4 @@ } } }); -}); +}) diff --git a/apps/slomoclock/settings.js b/apps/slomoclock/settings.js index dcaf0aff665..fd27179278b 100644 --- a/apps/slomoclock/settings.js +++ b/apps/slomoclock/settings.js @@ -35,4 +35,4 @@ E.showMenu(appMenu); -}); +}) diff --git a/apps/slopeclockpp/settings.js b/apps/slopeclockpp/settings.js index 2c2d2c463ea..71c2727532f 100644 --- a/apps/slopeclockpp/settings.js +++ b/apps/slopeclockpp/settings.js @@ -57,4 +57,4 @@ showMainMenu(); -}); +}) diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index 30119e48d2d..981c834a2c0 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -87,6 +87,6 @@ // Actually display the menu E.showMenu(mainmenu); -}); +}) // end of file diff --git a/apps/speedalt/settings.js b/apps/speedalt/settings.js index aeaa84f2c6d..a4e70c2c031 100644 --- a/apps/speedalt/settings.js +++ b/apps/speedalt/settings.js @@ -79,4 +79,4 @@ E.showMenu(appMenu); -}); +}) diff --git a/apps/speedalt2/settings.js b/apps/speedalt2/settings.js index 63fa424ba0c..d0e6c2fda81 100644 --- a/apps/speedalt2/settings.js +++ b/apps/speedalt2/settings.js @@ -99,4 +99,4 @@ E.showMenu(appMenu); -}); +}) diff --git a/apps/swp2clk/settings.js b/apps/swp2clk/settings.js index 4f8db5eb816..21752e58a92 100644 --- a/apps/swp2clk/settings.js +++ b/apps/swp2clk/settings.js @@ -180,4 +180,4 @@ settings = readSettings(); showMainMenu(); -}); +}) diff --git a/apps/taglaunch/settings.js b/apps/taglaunch/settings.js index 94ec34a36e5..b85ff65f60b 100644 --- a/apps/taglaunch/settings.js +++ b/apps/taglaunch/settings.js @@ -34,4 +34,4 @@ } }; E.showMenu(appMenu); -}); +}) diff --git a/apps/thunder/settings.js b/apps/thunder/settings.js index 1a2959227cd..90e3c423188 100644 --- a/apps/thunder/settings.js +++ b/apps/thunder/settings.js @@ -37,4 +37,4 @@ loadSettings(); showMenu(); -}); +}) diff --git a/apps/timecal/timecal.settings.js b/apps/timecal/timecal.settings.js index 3a38eed0979..d7824815a6d 100644 --- a/apps/timecal/timecal.settings.js +++ b/apps/timecal/timecal.settings.js @@ -104,4 +104,4 @@ }; showMainMenu(); -}); +}) diff --git a/apps/timerclk/settings.js b/apps/timerclk/settings.js index 1a8500add56..0f4acfc70cb 100644 --- a/apps/timerclk/settings.js +++ b/apps/timerclk/settings.js @@ -312,4 +312,4 @@ } }; E.showMenu(mainMenu); -}); +}) diff --git a/apps/timestamplog/settings.js b/apps/timestamplog/settings.js index 137ed31dbea..ffdaa4665d3 100644 --- a/apps/timestamplog/settings.js +++ b/apps/timestamplog/settings.js @@ -4,4 +4,4 @@ const tsl = require('timestamplog'); function(backCb) { tsl.launchSettingsMenu(backCb); } -); +) diff --git a/apps/toucher/settings.js b/apps/toucher/settings.js index f3004000a73..a8a17125c9d 100644 --- a/apps/toucher/settings.js +++ b/apps/toucher/settings.js @@ -54,4 +54,4 @@ }, '< Back': back }); -}); +}) diff --git a/apps/touchtimer/settings.js b/apps/touchtimer/settings.js index d3de4e6d32c..4a7464f063c 100644 --- a/apps/touchtimer/settings.js +++ b/apps/touchtimer/settings.js @@ -81,4 +81,4 @@ settings = readSettings(); showMainMenu(); -}); +}) diff --git a/apps/trex/settings.js b/apps/trex/settings.js index 67aa9a518ac..f435b0ba497 100644 --- a/apps/trex/settings.js +++ b/apps/trex/settings.js @@ -16,4 +16,4 @@ } }; E.showMenu(menu); -}); +}) diff --git a/apps/usgs/settings.js b/apps/usgs/settings.js index 8a12197dc3f..448e178d816 100644 --- a/apps/usgs/settings.js +++ b/apps/usgs/settings.js @@ -78,4 +78,4 @@ function getDataStreams() { // Show the menu E.showMenu(menu); -}); +}) diff --git a/apps/weatherClock/settings.js b/apps/weatherClock/settings.js index 0aa7330c102..8a2127ba75c 100644 --- a/apps/weatherClock/settings.js +++ b/apps/weatherClock/settings.js @@ -55,4 +55,4 @@ }, } }); -}); +}) diff --git a/apps/wid_edit/settings.js b/apps/wid_edit/settings.js index a632850d6b0..cf445fe4875 100644 --- a/apps/wid_edit/settings.js +++ b/apps/wid_edit/settings.js @@ -194,4 +194,4 @@ E.showMenu(menu); } mainMenu(); -}); +}) diff --git a/apps/widalarmeta/settings.js b/apps/widalarmeta/settings.js index 8dd0d81fa41..5e83c6f3abf 100644 --- a/apps/widalarmeta/settings.js +++ b/apps/widalarmeta/settings.js @@ -60,4 +60,4 @@ } }, }); -}); +}) diff --git a/apps/widbaroalarm/settings.js b/apps/widbaroalarm/settings.js index 68e7bab6b53..4762e1e8077 100644 --- a/apps/widbaroalarm/settings.js +++ b/apps/widbaroalarm/settings.js @@ -155,4 +155,4 @@ } showMainMenu(); -}); +}) diff --git a/apps/widbatwarn/settings.js b/apps/widbatwarn/settings.js index c3464a82bbe..352dca46704 100644 --- a/apps/widbatwarn/settings.js +++ b/apps/widbatwarn/settings.js @@ -42,4 +42,4 @@ }, }; E.showMenu(menu); -}); \ No newline at end of file +}) diff --git a/apps/widbgjs/settings.js b/apps/widbgjs/settings.js index c599183dc9f..077efaf8a78 100644 --- a/apps/widbgjs/settings.js +++ b/apps/widbgjs/settings.js @@ -50,4 +50,4 @@ }, '< Back': back, }); -}); +}) diff --git a/apps/widdst/settings.js b/apps/widdst/settings.js index 0017cc49922..5ed8b0a37ee 100644 --- a/apps/widdst/settings.js +++ b/apps/widdst/settings.js @@ -190,4 +190,4 @@ E.showMenu(dstMenu); -}); +}) diff --git a/apps/widgps/settings.js b/apps/widgps/settings.js index 7a1c186c963..8f1d99f0677 100644 --- a/apps/widgps/settings.js +++ b/apps/widgps/settings.js @@ -29,4 +29,4 @@ var mainmenu = { }, }; E.showMenu(mainmenu); -}); \ No newline at end of file +}) diff --git a/apps/widhrm/settings.js b/apps/widhrm/settings.js index 0b8c989ac50..1c696939b79 100644 --- a/apps/widhrm/settings.js +++ b/apps/widhrm/settings.js @@ -33,4 +33,4 @@ }, }; E.showMenu(menu); -}); +}) diff --git a/apps/widmp/settings.js b/apps/widmp/settings.js index a389f7918c4..e671d9900f3 100644 --- a/apps/widmp/settings.js +++ b/apps/widmp/settings.js @@ -69,4 +69,4 @@ E.showMenu(mainmenu); -}); +}) diff --git a/apps/widshipbell/settings.js b/apps/widshipbell/settings.js index bb47e9b208f..fa1ada63070 100644 --- a/apps/widshipbell/settings.js +++ b/apps/widshipbell/settings.js @@ -24,4 +24,3 @@ }, }); }) - diff --git a/apps/widsleepstatus/settings.js b/apps/widsleepstatus/settings.js index da402e08e61..e758a176063 100644 --- a/apps/widsleepstatus/settings.js +++ b/apps/widsleepstatus/settings.js @@ -29,4 +29,4 @@ }, }; E.showMenu(menu); -}); +}) From e749735b8964aff45e95ea29e4b88f1af21beaad Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Mon, 28 Oct 2024 20:32:51 +0100 Subject: [PATCH 30/63] infoclk: Make sure varibales are properly defined --- apps/infoclk/ChangeLog | 1 + apps/infoclk/metadata.json | 4 ++-- apps/infoclk/settings.js | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/infoclk/ChangeLog b/apps/infoclk/ChangeLog index def5128565f..911e64894b3 100644 --- a/apps/infoclk/ChangeLog +++ b/apps/infoclk/ChangeLog @@ -12,3 +12,4 @@ Broke out config loading into separate file to avoid duplicating a whole bunch of code Added support for fast loading 0.10: Minor code improvements +0.11: Make sure variables are properly defined in settings.js diff --git a/apps/infoclk/metadata.json b/apps/infoclk/metadata.json index 1b1b6e6041e..ddd16c4a693 100644 --- a/apps/infoclk/metadata.json +++ b/apps/infoclk/metadata.json @@ -1,7 +1,7 @@ { "id": "infoclk", "name": "Informational clock", - "version": "0.10", + "version": "0.11", "description": "A configurable clock with extra info and shortcuts when unlocked, but large time when locked", "readme": "README.md", "icon": "icon.png", @@ -41,4 +41,4 @@ "dependencies": { "weather": "app" } -} \ No newline at end of file +} diff --git a/apps/infoclk/settings.js b/apps/infoclk/settings.js index 44182540ba5..dd18626e148 100644 --- a/apps/infoclk/settings.js +++ b/apps/infoclk/settings.js @@ -17,6 +17,9 @@ } else return '' + hour; } + let minute; // Is used in onchange functions. Defined here to appease the linter. + let hour; // Is used in onchange functions. Defined here to appease the linter. + // The menu for configuring when the seconds are shown function showSecondsMenu() { E.showMenu({ From ca69ca5342de3cbbaf80f7e4be7dc154486ef838 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Mon, 28 Oct 2024 20:39:46 +0100 Subject: [PATCH 31/63] poweroff: comment out unused fn in settings.js --- apps/poweroff/ChangeLog | 1 + apps/poweroff/metadata.json | 2 +- apps/poweroff/settings.js | 40 ++++++++++++++++++------------------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/poweroff/ChangeLog b/apps/poweroff/ChangeLog index a62a1bc4389..d39fb5a31fb 100644 --- a/apps/poweroff/ChangeLog +++ b/apps/poweroff/ChangeLog @@ -2,3 +2,4 @@ 0.02: Add prompt before shutdown 0.03: Add settings to configure prompt 0.04: Minor code improvements +0.05: Comment out unused function in settings.js diff --git a/apps/poweroff/metadata.json b/apps/poweroff/metadata.json index 9c558bc5bf5..218e4b441cd 100644 --- a/apps/poweroff/metadata.json +++ b/apps/poweroff/metadata.json @@ -1,7 +1,7 @@ { "id": "poweroff", "name": "Poweroff", "shortName":"Poweroff", -"version": "0.04", +"version": "0.05", "description": "Simple app to power off your Bangle.js", "icon": "app.png", "tags": "tool, poweroff, shutdown", diff --git a/apps/poweroff/settings.js b/apps/poweroff/settings.js index 5103d08f336..8c700c8cdba 100644 --- a/apps/poweroff/settings.js +++ b/apps/poweroff/settings.js @@ -8,26 +8,26 @@ require('Storage').writeJSON(FILE, settings); } - // Helper method which uses int-based menu item for set of string values - function stringItems(startvalue, writer, values) { - return { - value: (startvalue === undefined ? 0 : values.indexOf(startvalue)), - format: v => values[v], - min: 0, - max: values.length - 1, - wrap: true, - step: 1, - onchange: v => { - writer(values[v]); - writeSettings(); - } - }; - } - - // Helper method which breaks string set settings down to local settings object - function stringInSettings(name, values) { - return stringItems(settings[name], v => settings[name] = v, values); - } + //// Helper method which uses int-based menu item for set of string values + //function stringItems(startvalue, writer, values) { + // return { + // value: (startvalue === undefined ? 0 : values.indexOf(startvalue)), + // format: v => values[v], + // min: 0, + // max: values.length - 1, + // wrap: true, + // step: 1, + // onchange: v => { + // writer(values[v]); + // writeSettings(); + // } + // }; + //} + // + //// Helper method which breaks string set settings down to local settings object + //function stringInSettings(name, values) { + // return stringItems(settings[name], v => settings[name] = v, values); + //} var mainmenu = { "": { From a230a3482213abb57f56147ffcb254c898c9180b Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Mon, 28 Oct 2024 20:44:36 +0100 Subject: [PATCH 32/63] swp2clk: fix to use Storage lib correctly --- apps/swp2clk/ChangeLog | 1 + apps/swp2clk/metadata.json | 2 +- apps/swp2clk/settings.js | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/swp2clk/ChangeLog b/apps/swp2clk/ChangeLog index d6f9f6e8c36..975da580087 100644 --- a/apps/swp2clk/ChangeLog +++ b/apps/swp2clk/ChangeLog @@ -2,3 +2,4 @@ 0.02: Fix deleting from white and black lists. 0.03: Adapt to availability of Bangle.showClock and Bangle.load 0.04: Fix 'Uncaught ReferenceError: "__FILE__" is not defined' error (fix #2326) +0.05: Fix settings didn't call the Storage class correctly. diff --git a/apps/swp2clk/metadata.json b/apps/swp2clk/metadata.json index b4436bd3915..a4ef71488ed 100644 --- a/apps/swp2clk/metadata.json +++ b/apps/swp2clk/metadata.json @@ -2,7 +2,7 @@ "id": "swp2clk", "name": "Swipe back to the Clock", "shortName": "Swipe to Clock", - "version": "0.04", + "version": "0.05", "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": "bootloader", diff --git a/apps/swp2clk/settings.js b/apps/swp2clk/settings.js index 21752e58a92..0503a455ae9 100644 --- a/apps/swp2clk/settings.js +++ b/apps/swp2clk/settings.js @@ -150,10 +150,10 @@ }; var getAppList = () => { - var appList = storage + var appList = require("Storage") .list(/\.info$/) .map((appInfoFileName) => { - var appInfo = storage.readJSON(appInfoFileName, 1); + var appInfo = require("Storage").readJSON(appInfoFileName, 1); return ( appInfo && { name: appInfo.name, From 970cb199d1647853c62f6ce0a56bbe96c9e766d7 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Mon, 28 Oct 2024 20:48:59 +0100 Subject: [PATCH 33/63] usgs: add FIXME comment re `data` The logic for passing data around seems to be broken to me. --- apps/lint_exemptions.js | 2 +- apps/usgs/settings.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 3bcbf6fd3dd..1b3a3cc11bf 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -528,7 +528,7 @@ module.exports = { ] }, "apps/usgs/settings.js": { - "hash": "af1b7bc7e041c1e6988b407b6c8ee66dbd6a0e181a20caf102d2abdb6dbd5ac0", + "hash": "00ee672a6920f5667bfbd2988fd2853cfd579895a843ae036a00028dcb13878d", "rules": [ "no-undef" ] diff --git a/apps/usgs/settings.js b/apps/usgs/settings.js index 448e178d816..710d071ea63 100644 --- a/apps/usgs/settings.js +++ b/apps/usgs/settings.js @@ -19,6 +19,9 @@ } function popSubMenu() { + // FIXME: Linter complains that `data` is not defined. When I defined it + // instead complained that it's not used (no-unused-vars). + // Also looking at `getDataStreams` it doesn't return anything so this seems wrong. data = getDataStreams(); } function popSubMenuData(data) { From 8c0380f48e5198f23d8e75689b2b72088e95face Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Wed, 30 Oct 2024 20:24:21 +0100 Subject: [PATCH 34/63] gpsrec + gpssetup: tweak comments --- apps/gpsrec/settings.js | 4 ++-- apps/gpssetup/settings.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/gpsrec/settings.js b/apps/gpsrec/settings.js index 25feadd7c86..287073b0c3d 100644 --- a/apps/gpsrec/settings.js +++ b/apps/gpsrec/settings.js @@ -1,4 +1,4 @@ (function(back) { - // just go right to our app - we need all the memory + // just go right to our app - we need all the memory */ load("gpsrec.app.js"); -})() // FIXME: Since this is called directly, should it still have a semi-colon? +})() diff --git a/apps/gpssetup/settings.js b/apps/gpssetup/settings.js index 71a64f69bc7..59988b788af 100644 --- a/apps/gpssetup/settings.js +++ b/apps/gpssetup/settings.js @@ -1,4 +1,4 @@ (function(back) { - // just go right to our app + /* just go right to our app*/ load("gpssetup.app.js"); -})() // FIXME: Since this is called directly, should it still have a semi-colon? +})() From f46e8359c7ddf09192190a946958036450032812 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 23 Oct 2024 21:42:48 +0100 Subject: [PATCH 35/63] sched interface: display appid of an alarm --- apps/sched/interface.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sched/interface.html b/apps/sched/interface.html index 73ceff3c1a3..185e9034fe1 100644 --- a/apps/sched/interface.html +++ b/apps/sched/interface.html @@ -173,7 +173,7 @@ }; } } - tdType.textContent = type; + tdType.textContent = type + (alarm.appid ? `\n(${alarm.appid})` : ""); if (!exists) { const asterisk = document.createElement('sup'); asterisk.textContent = '*'; From e9969e6d85c17d73d013dfbeca94d3b227b24341 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 23 Oct 2024 21:42:58 +0100 Subject: [PATCH 36/63] sched interface: rank app-alarms to the bottom --- apps/sched/interface.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/sched/interface.html b/apps/sched/interface.html index 185e9034fe1..fa413257460 100644 --- a/apps/sched/interface.html +++ b/apps/sched/interface.html @@ -331,6 +331,10 @@ alarms.sort((a, b) => { let x; + // move app specific alarms to the bottom + x = !!a.appid - !!b.appid; + if(x) return x; + x = !!b.date - !!a.date; if(x) return x; From 3e67088354e0dd4ee3e5429d3ffc5069ec65350c Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 30 Oct 2024 20:32:22 +0000 Subject: [PATCH 37/63] typescript: add build script to post-process --- apps/clkinfostopw/clkinfo.js | 2 +- typescript/build.sh | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100755 typescript/build.sh diff --git a/apps/clkinfostopw/clkinfo.js b/apps/clkinfostopw/clkinfo.js index caf460da330..8b7a6a9adf5 100644 --- a/apps/clkinfostopw/clkinfo.js +++ b/apps/clkinfostopw/clkinfo.js @@ -74,4 +74,4 @@ } ] }; -}); // FIXME: semi-colon added automatically when Typescript generates Javascript file? +}) diff --git a/typescript/build.sh b/typescript/build.sh new file mode 100755 index 00000000000..bf5493745c5 --- /dev/null +++ b/typescript/build.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e + +usage(){ + echo >&2 "Usage: $0" + exit 2 +} + +if test $# -ne 0 +then usage +fi + +cd "$(dirname "$0")" + +npm run build + +find ../apps -iname '*.ts' | + sed 's/\.ts$/.js/' | + grep -E 'clkinfo|setting' | + xargs perl -i -pe 's/;$// if eof' From 34c35532ed17a7d30251ddf6c54d58a2a5546a28 Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Thu, 31 Oct 2024 15:21:17 +0000 Subject: [PATCH 38/63] Accented characters and extended mode --- apps/kbedgewrite/ChangeLog | 1 + apps/kbedgewrite/README.md | 11 +- apps/kbedgewrite/characterset.json | 78 +++++++++++- apps/kbedgewrite/lib.js | 192 ++++++++++++++++++++++++----- apps/kbedgewrite/metadata.json | 9 +- apps/kbedgewrite/screenshot.png | Bin 0 -> 2878 bytes apps/kbedgewrite/settings.js | 40 ++++++ 7 files changed, 298 insertions(+), 33 deletions(-) create mode 100644 apps/kbedgewrite/screenshot.png create mode 100644 apps/kbedgewrite/settings.js diff --git a/apps/kbedgewrite/ChangeLog b/apps/kbedgewrite/ChangeLog index 5560f00bce7..e6dd4b19e7b 100644 --- a/apps/kbedgewrite/ChangeLog +++ b/apps/kbedgewrite/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Accents and extended mode characters diff --git a/apps/kbedgewrite/README.md b/apps/kbedgewrite/README.md index 8d0ca5dc5dc..2f668d4cf6f 100644 --- a/apps/kbedgewrite/README.md +++ b/apps/kbedgewrite/README.md @@ -12,7 +12,14 @@ To display the in app character chart, long press the screen; you can scroll thr For a full character chart see [EwChart.pdf](EwChart.pdf) -**Supported:** Letters (including capitals), numbers, backspace, word backspace, space, punctuation, new line, and some cursor controls (left, right, word left/right, home, end). +**Supported:** Letters (including capitals), numbers, backspace, word backspace, space, punctuation, new line, accents, extended mode (if characters are supported by the vector font), and some cursor controls (left, right, word left/right, home, end). -**Unsupported:** Extended mode, accents, and word-level stroking. +**Unsupported:** Word-level stroking. +## Settings + +Font size can be selected in Settings app > "Apps" > "EdgeWrite Keyboard" + +## Author + +Woogal [github](https://github.com/retcurve) diff --git a/apps/kbedgewrite/characterset.json b/apps/kbedgewrite/characterset.json index 74276b683ec..9aa70ae71d0 100644 --- a/apps/kbedgewrite/characterset.json +++ b/apps/kbedgewrite/characterset.json @@ -193,17 +193,93 @@ "2425": "`", "31": " \n", "24": " ", + "46": "\xb7", + "432146": "\xb0", + "412346": "\xb0", + "123246": "\xae", + "2123246": "\xae", + "123146": "\xae", + "2123146": "\xae", + "2346": "\xac", + "32146": "\xa9", + "41236": "\xa2", + "24316": "\xd7", + "31246": "\xd7", + "316": "\xf7", + "136": "\xf7", + "232146": "\x80", + "23246": "\x80", + "132146": "\x80", + "412316": "\x80", + "323146": "\x80", + "324146": "\x80", + "24346": "\xa5", + "243416": "\xa5", + "2143416": "\xa5", + "34146": "\xf0", + "342146": "\xf0", + "343146": "\xf0", + "4214346": "\xf0", + "414346": "\xf0", + "434146": "\xf0", + "123416": "\xf0", + "2123416": "\xf0", + "1346": "\xe6", + "1246": "\xe6", + "13416": "\xe6", + "12416": "\xe6", + "3214346": "\xe6", + "21416": "\xdf", + "213416": "\xdf", + "212416": "\xdf", + "141216": "\xdf", + "1341216": "\xdf", + "121416": "\xdf", + "1232416": "\xdf", + "1231416": "\xdf", + "21232416": "\xdf", + "21231416": "\xdf", + "2321416": "\xdf", + "2146": "\xa3", + "21436": "\xb5", + "214346": "\xb5", + "121436": "\xb5", + "1214346": "\xb5", + "3214316": "\xf8", + "3412316": "\xf8", + "4126": "\xbf", + "216": "\xa1", + "346": "\xa6", + "21236": "\xb1", + "212326": "\xb1", + "31426": "\xa4", + "24136": "\xa4", + "3146": "\xab", + "2416": "\xbb", "32": "#bs", "41": "#wbs", "12": "#pu-on", "43": "#pu-on", "325": "#pu-off", "415": "#pu-off", + "42": "#ex-on", + "326": "#ex-off", + "416": "#ex-off", "323": "#cur-left", "232": "#cur-right", "414": "#cur-word-left", "141": "#cur-word-right", "4141": "#cur-home", - "1414": "#cur-end" + "1414": "#cur-end", + "242": "#grave", + "313": "#acute", + "431": "#circumflex", + "421": "#circumflex", + "3421": "#tilde", + "43412": "#umlaut", + "43214": "#ring", + "41234": "#ring", + "142": "#cedilla", + "143": "#cedilla" } diff --git a/apps/kbedgewrite/lib.js b/apps/kbedgewrite/lib.js index a69eabc2c94..d71ad5c7364 100644 --- a/apps/kbedgewrite/lib.js +++ b/apps/kbedgewrite/lib.js @@ -7,10 +7,20 @@ exports.input = function(options) { let chartX = 0; let chartY = 0; + let settings = Object.assign({ + fontSize: 32, + }, require('Storage').readJSON("kbedgewrite.json", true)); + let shouldShowWidgetBar = Bangle.appRect.y > 0; options = options||{}; let text = options.text; + // Substring doesn't play well with UTF8 + if (E.isUTF8(text)) { + text = E.decodeUTF8(text); + } + let wrappedText = ''; + if ('string' != typeof text) text=''; // Colours for number of corner occurrences @@ -18,40 +28,140 @@ exports.input = function(options) { const cornerSize = g.getWidth() / 3; let punctuationMode = false; + let extendedMode = false; let path = ''; let cursorPos = text.length; let chartShown = false; let characterSet = Object.assign({}, require('Storage').readJSON('kbedgewrite.charset.json', true) || {}); - function draw() { - g.clearRect(Bangle.appRect).setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); + const accentedCharacters = { + '#grave': { + 'a': String.fromCharCode(0xE0), + 'A': String.fromCharCode(0xC0), + 'e': String.fromCharCode(0xE8), + 'E': String.fromCharCode(0xC8), + 'i': String.fromCharCode(0xEC), + 'I': String.fromCharCode(0xCC), + 'o': String.fromCharCode(0xF2), + 'O': String.fromCharCode(0xD2), + 'u': String.fromCharCode(0xF9), + 'U': String.fromCharCode(0xD9) + }, + '#acute': { + 'a': String.fromCharCode(0xE1), + 'A': String.fromCharCode(0xC1), + 'e': String.fromCharCode(0xE9), + 'E': String.fromCharCode(0xC9), + 'i': String.fromCharCode(0xED), + 'I': String.fromCharCode(0xCD), + 'o': String.fromCharCode(0xF3), + 'O': String.fromCharCode(0xD3), + 'u': String.fromCharCode(0xFA), + 'U': String.fromCharCode(0xDA), + 'y': String.fromCharCode(0xFD), + 'Y': String.fromCharCode(0xDD) + }, + '#circumflex': { + 'a': String.fromCharCode(0xE2), + 'A': String.fromCharCode(0xC2), + 'e': String.fromCharCode(0xEA), + 'E': String.fromCharCode(0xCA), + 'i': String.fromCharCode(0xEE), + 'I': String.fromCharCode(0xCE), + 'o': String.fromCharCode(0xF4), + 'O': String.fromCharCode(0xD4), + 'u': String.fromCharCode(0xFB), + 'U': String.fromCharCode(0xDB) + }, + '#umlaut': { + 'a': String.fromCharCode(0xE4), + 'A': String.fromCharCode(0xC4), + 'e': String.fromCharCode(0xEB), + 'E': String.fromCharCode(0xCB), + 'i': String.fromCharCode(0xEF), + 'I': String.fromCharCode(0xCF), + 'o': String.fromCharCode(0xF6), + 'O': String.fromCharCode(0xD6), + 'u': String.fromCharCode(0xFC), + 'U': String.fromCharCode(0xDC), + 'y': String.fromCharCode(0xFF) + }, + '#tilde': { + 'a': String.fromCharCode(0xE3), + 'A': String.fromCharCode(0xC3), + 'n': String.fromCharCode(0xF1), + 'N': String.fromCharCode(0xD1), + 'o': String.fromCharCode(0xF5), + 'O': String.fromCharCode(0xD5) + }, + '#ring': { + 'a': String.fromCharCode(0xE5), + 'A': String.fromCharCode(0xC5) + }, + '#cedilla': { + 'c': String.fromCharCode(0xE7), + 'C': String.fromCharCode(0xC7) + }, + + }; + + function wrapText() { + let stringToWrap = text.substring(0, cursorPos) + '_' + text.substring(cursorPos); + let l = []; + let startPos = 0; - // Draw the text string - let l = g.setFont('6x8:4').wrapString(text.substring(0, cursorPos) + '_' + text.substring(cursorPos), g.getWidth()); - if (!l) l = []; - if (l.length>5) { + g.setFont("Vector", settings.fontSize); // set the font so we can calculate a string width + + // Wrap the string into array of lines that will fit the screen width + for (let i = 0; i < stringToWrap.length; i++) { + // wrap if string is too long or we hit a line break + if (stringToWrap.charCodeAt(i) == 10 || g.stringWidth(stringToWrap.substring(startPos, i+1)) > 176) { + l.push(stringToWrap.substring(startPos, i)); + // skip the line break + if (stringToWrap.charCodeAt(i) == 10) { + i++; + } + startPos = i; + } + } + // Add the final line + l.push(stringToWrap.substring(startPos)); + + // Number of lines that can fit on the screen + let numLines = Math.floor(g.getHeight() / g.getFontHeight()); + + // If too many lines, reposition so the cursor can be seen + if (l.length > numLines) { let textPos = 0; let lineNum; for (lineNum = 0; lineNum < l.length; lineNum++) { - textPos = textPos + l[lineNum].length - 1; + textPos = textPos + l[lineNum].length; if (textPos >= cursorPos) break; } - l=l.slice(lineNum - l.length - 5); + l=l.slice(lineNum - l.length - numLines + 1); } + + wrappedText = l.join('\n'); + } + + function draw() { + g.clearRect(Bangle.appRect).setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); + g.setColor(g.theme.fg); + g.setFont("Vector", settings.fontSize); g.setFontAlign(-1, -1, 0); - g.drawString(l.join('\n'), Bangle.appRect.x, Bangle.appRect.y); + g.drawString(wrappedText, Bangle.appRect.x, Bangle.appRect.y); - // Draw punctuation flag - if (punctuationMode > 0) { + // Draw punctuation or extended flags + if (punctuationMode || extendedMode) { let x = (g.getWidth() / 2) - 12; let y = g.getHeight() - 32; - g.setColor('#F00'); + g.setColor(punctuationMode ? '#F00' : '#0F0'); g.fillRect(x,y,x+24,y+32); g.setColor('#FFF'); g.setFont('6x8:4'); - g.drawString('P', x+4, y+4, false); + g.drawString(punctuationMode ? 'P' : 'E', x+4, y+4, false); } // Draw corners @@ -69,30 +179,27 @@ exports.input = function(options) { } function processPath() { - let capital = false; - // Punctuation paths end in 5 if (punctuationMode) { path = path + '5'; } - - // Capital letters end in 2, remove that and set a capital flag - // but only if the path isn't 232 (cursor right) - if (path != '232' && path.length > 2 && path.slice(-1) == '2') { - path = path.slice(0,-1); - capital = true; + // Extended paths end in 6 + if (extendedMode) { + path = path + '6'; } // Find character from path let char = characterSet[path]; - // Handle capitals - if (capital && char != 'undefined') { - if (char.charCodeAt(0)>96 && char.charCodeAt(0)<123) { - char = char.toUpperCase(); - } else { - // Anything that can't be capitalised is an invalid path - char = undefined; + // Unknown character, but ends in a 2 so may be a capital letter + if (char == 'undefined' && path.slice(-1) == '2') { + // Remove the 2 and look for a letter + char = characterSet[path.slice(0,-1)]; + // Handle capitals + if (char != 'undefined') { + if (char.charCodeAt(0)>96 && char.charCodeAt(0)<123) { + char = char.toUpperCase(); + } } } @@ -129,6 +236,17 @@ exports.input = function(options) { punctuationMode = false; break; } + // Enable extended mode + case '#ex-on': { + extendedMode = true; + break; + } + // Disable extended mode + case '#ex-off': { + extendedMode = false; + break; + } + // Cursor controls case '#cur-left': { if (cursorPos > 0) { cursorPos--; @@ -168,6 +286,22 @@ exports.input = function(options) { cursorPos = text.length; break; } + // Accents + case '#grave': + case '#acute': + case '#circumflex': + case '#umlaut': + case '#tilde': + case '#ring': + case '#cedilla': + // If the previous character can be accented, replace it with the accented version + if (cursorPos > 0) { + char = accentedCharacters[char][text.substring(cursorPos-1, cursorPos)]; + if (char != 'undefined') { + text = text.substring(0, cursorPos-1) + char + text.substring(cursorPos); + } + } + break; // Append character default: { text = text.substring(0, cursorPos) + char + text.substring(cursorPos); @@ -184,6 +318,7 @@ exports.input = function(options) { if (!chartShown) { if (e.b == 0) { // Finger lifted, process completed path processPath(); + wrapText(); draw(); } else { let corner = 0; @@ -220,6 +355,7 @@ exports.input = function(options) { // Draw initial string require("widget_utils").hide(); g.setBgColor(g.theme.bg); + wrapText(); draw(); return new Promise((resolve,reject) => { diff --git a/apps/kbedgewrite/metadata.json b/apps/kbedgewrite/metadata.json index cbf873a09e6..717cdbcba99 100644 --- a/apps/kbedgewrite/metadata.json +++ b/apps/kbedgewrite/metadata.json @@ -1,14 +1,19 @@ { "id": "kbedgewrite", "name": "EdgeWrite keyboard", - "version":"0.01", + "version":"0.02", "description": "A library for text input via EdgeWrite swipe gestures", "icon": "app.png", "type":"textinput", "tags": "keyboard", "supports" : ["BANGLEJS2"], "readme": "README.md", + "screenshots" : [ { "url":"screenshot.png" } ], "storage": [ {"name":"textinput","url":"lib.js"}, - {"name":"kbedgewrite.charset.json","url":"characterset.json"} + {"name":"kbedgewrite.charset.json","url":"characterset.json"}, + {"name":"kbedgewrite.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"kbedgewrite.json"} ] } diff --git a/apps/kbedgewrite/screenshot.png b/apps/kbedgewrite/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..48db615e10c08dd8d4e5798abf5ea3e7e694c013 GIT binary patch literal 2878 zcmb7`i8s{y8^^yhjAf9nvL?%Q$yQmS1(C6YuBB$i&V)i^t?XhZ>mY8FwJZr^U&ct$ z7-Eohay15-v1Cax$k?La+&|%WKIi#7=e*B(&iS14yq@>x!P#1y3qhrz000PCTsOJN z$qoMn9}nlQf3x7mNuUQe&5eP&Vd)hBfbLqDT!V+Z{doB$bX8R_erzXp`Nh|@^4?%g zZ4r@K??|+K_cDyfqs@I}X?|~FVSN>yg$>A}_Rd=Y=lO_$n?_|uuV)YRS2SsCKSb~* zAi#7yd7SLTHPUrY(;B3Xfv~!vJ|`{)ZwA0hR|RQwJ4dByOeNl0ewxpHw(|1+5%wC;MkJx}(C^Rw1+P;RfKaGV zK0hj{4jB$o=|pZ;uJs!0hcQ{)(hj-!(~T4 zPvjZRjL0%Pk7iU_qHcVRtp8jyPTQs<$B*&%^;@WTC$7f=HPP^@z<~s+0qo8B|Q=Ia~IDaH|$Org(In_bD26 z0a$Dm+6!_QCkLz~1}I~atTWUu`OmpD&6-t_9ZLBGK++{1ok@VT2zw3*oLN!FWW|e; zAH^T~oS*D|1V3sXjtZFj#M606jGSh+tnYLe6HxDbUzumIqo8jul(^8#E#K^VKW79`Y*aA1#jl)hOki62?<+{uKk4ZZYb zz^%f_!$`UaDx-ZFIf6ug9zHQ2cVPO4vl*jgTa?xTTH93s=aJokvlnUEX-?W4G5SB3X{PluUE+g;vHyORp_6HPp9 z`fGC_Ms{eGmk6UdhP%g1Y&1`nwC2>3m!sOtOrB--fz$T4lrn35vP}r9`)zu~A-IGY zcKSPl`Yo)%sAFc2QO^w?%A&MA{1r75Z`$!G(hV?VFm$$|T^R8^;9uDXQ^Swhf|@B= zUs5$p$y&a(Vb9CdG`N%s@O|;x$4i}Cbf|?;KWhEmfqP4mS-_E<5H78baH0eWvEm=B zq8LyfghfkURs#LHhC#n!ym=YgCGMyNoI}j6zD|qZIXI^?cUgmQH^my*OsZoj*0)^t zxM(dofa}|ESW_M2O8blmTm3-Q4YtSUTJ#zX?{CzIpIt=-O8Y$O_=|i)%Zyv1$G@^c z$DL~7opWwx%FsFfpP0ezHLGOhja+BBDmKwsHeciVwA4eq<(>N2vu}Ro)ZP*C2Wb$P z^@{hsFmx}4e;f^cv`SW~!G2sUSDmXONq{L0&1s(LktNOU6nDCg+27tKXmlRmPq zegfS1-4G}}hxbmefp)2OaI1JaJH{B~_Qy2U8v0$ut<6-Mj2b1G6t}e`YLi0 z;A|sQ!!CV5oD5(4DMmK@Sd+~frzl`LVYAhW(Zmft&fM%*^@%$ddO6H&u=dG?~@2yKUezY zt9NvU@x8}p0JF|PR-w2Qmq3t^95VW(z-liS0fIWY^fvaw2Hl~QawMRkm)w?4XNLie zT;`#E(zQ4veij8w>2>o4-JMU%-6i74>8m!1zjsPlJHjjS-U=P(hSSSLnXuBQXSBIA zs>fNPt-2GRA|_UEfJaES(aVuTv@;J;l)#}V|4-SQ_b*->{gOJg5vEVu zT*Yn$dHtb&AFwNsu=IL_)nZXhXqmyn}Z`8IA%XV*S| zLgjrT>l(Y=Ia$)?NRfcBEJAec`U1i*QHUA)Z%69#xpde3zm*$n7|MER{ThR&DM{uG zs|s8V{;f(b#5aU?h-%GFQ39im-#yU_H-+a($UfEm9PSY1l~iY*-nb~xgRPS#(X(=F z;4=*Vn^$<*FGMsR|FkUh=IWx1Ola!nIZ0$}Yr`yd4iBxQ2>~$M*ekw@W%uSc3twr> zr;QR6x28bRVQsA`J`o%);(*n*=zvIe;dCm06#3!jilUUkWHhcX^bY}<_xun7_TXNW;AXbR?e}n zTdsT7_C`R3Rn0Li(c|R2Zy&?nab#DIkbf#Mz%bmNG{%uvM5^O%a7?fKT_=g|KKi)r z^yEuG=8D03CqJ{J|38lYgm5?fC_Nrmh7@(+tQVb1chHxdjGI*_8sDona86J!Kdn>^ z!IV+u-7bN)M?l!5=fC)aEFVSAv6}hw16`;6?6I}{#K|{zpF~(}jwgL3R-j!<+k0ts z_SH!dlj00ZGu(In2FMJIot>kO{;_1SvXQ@cgWA#)d4NTWadSsmg(Jh)f#&^w>07BX ze$F62yjNa-9U_t)vZt_uG|cn#koRkx5lR&w7aJ!gSl<^NEEdULJx|VEtd`h+nMswe23bmUb_^E)g`9`V=TIVJl%IiIJ z1-z}xq8a}hUTIIHdS;z~xIHWS1@GQ&2!WhCt6&DnrAKQ5+A(vik2}o^W+~=hqi{dQrTHe~=ARG~c*aw;~Vl?oy#r|bWL>n labels[v], + min: 0, + max: values.length - 1, + wrap: true, + step: 1, + onchange: v => { + setSetting(key,values[v]); + } + }; + } + + // Helper method which breaks string set settings down to local settings object + function stringInSettings(name, values, labels) { + return stringItems(name,settings[name], values, labels); + } + + // Show the menu + E.showMenu({ + '' : { 'title' : 'EdgeWrite' }, + '< Back' : () => back(), + 'Font Size': stringInSettings('fontSize', [24, 32, 48], ['Small', 'Medium', 'Large']) + }); +}) \ No newline at end of file From 8903215f3b0071a9ca48f06d0797bcbb69fbe894 Mon Sep 17 00:00:00 2001 From: michele Date: Fri, 1 Nov 2024 15:38:01 +0100 Subject: [PATCH 39/63] tinyhead: change widget bg and fg colour so that widgets blend in with the rest of the face --- apps/tinyheads/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/tinyheads/app.js b/apps/tinyheads/app.js index a3f79c0818e..492929f10ca 100644 --- a/apps/tinyheads/app.js +++ b/apps/tinyheads/app.js @@ -214,6 +214,8 @@ }; let init = function init() { + g.setTheme({bg:lib.settings.hairColour,fg:lib.settings.faceColour,dark:true}).clear(); + Bangle.on('lock', lockHandler); Bangle.on('charging', chargingHandler); if (lib.settings.btStatusEyes) { @@ -227,7 +229,7 @@ activeEyesNum = disconnectedEyes; } - Bangle.setUI({ + Bangle.setUI("clock", { mode:"custom", clock: true, touch: (button, xy) => { From 71f3f6930469d81d27699b5bec3d4feb9963b223 Mon Sep 17 00:00:00 2001 From: michele Date: Fri, 1 Nov 2024 17:06:33 +0100 Subject: [PATCH 40/63] tinyhead: change the side screen's colour, so it blends in with the rest of the face --- apps/tinyheads/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tinyheads/lib.js b/apps/tinyheads/lib.js index cbb139d8c2f..1c4ee42a58b 100644 --- a/apps/tinyheads/lib.js +++ b/apps/tinyheads/lib.js @@ -135,7 +135,7 @@ exports.drawFace = function(scale, eyesNum, mouthNum, peek, offset) { // Draw face let xOffset = (g.getWidth() - (exports.faceW * scale)) / 2; let yOffset = (offset ? offset : 0) + ((g.getHeight() - (exports.faceH * scale)) / 2); - g.setBgColor(0, 0, 0); + g.setBgColor(settings.hairColour); g.clearRect(Bangle.appRect); g.setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); From 9306de32eb1afb1f8c989d9615477529b9c422d1 Mon Sep 17 00:00:00 2001 From: michele Date: Fri, 1 Nov 2024 17:51:37 +0100 Subject: [PATCH 41/63] tinyhead: fix the touch handler --- apps/tinyheads/app.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/tinyheads/app.js b/apps/tinyheads/app.js index 492929f10ca..c38ac24216b 100644 --- a/apps/tinyheads/app.js +++ b/apps/tinyheads/app.js @@ -22,7 +22,8 @@ let helpShown = false; let tapCount = 0; let centerX, centerY, minuteHandLength, hourHandLength, handOutline; - + let originalTheme = Object.assign({}, g.theme); + // Open the eyes and schedule the next blink let blinkOpen = function blinkOpen() { if (blinkTimeout) clearTimeout(blinkTimeout); @@ -229,13 +230,14 @@ activeEyesNum = disconnectedEyes; } - Bangle.setUI("clock", { + Bangle.setUI({ mode:"custom", clock: true, touch: (button, xy) => { // Go direct to feature select in settings on long screen press if (xy.type == 2) { eval(require("Storage").read("tinyheads.settings.js"))(()=> { + g.setTheme(originalTheme); E.showMenu(); init(); }, true, helpShown); @@ -253,6 +255,7 @@ } }, remove: function() { + g.setTheme(originalTheme); // Clear timeouts and listeners for fast loading if (drawTimeout) clearTimeout(drawTimeout); if (blinkTimeout) clearTimeout(blinkTimeout); From 4faaf29f830e3b93058420fc148337ce3e8890e3 Mon Sep 17 00:00:00 2001 From: michele Date: Fri, 1 Nov 2024 17:53:01 +0100 Subject: [PATCH 42/63] tinyhead: fix variable reference --- apps/tinyheads/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tinyheads/lib.js b/apps/tinyheads/lib.js index 1c4ee42a58b..a80f1059a3a 100644 --- a/apps/tinyheads/lib.js +++ b/apps/tinyheads/lib.js @@ -135,7 +135,7 @@ exports.drawFace = function(scale, eyesNum, mouthNum, peek, offset) { // Draw face let xOffset = (g.getWidth() - (exports.faceW * scale)) / 2; let yOffset = (offset ? offset : 0) + ((g.getHeight() - (exports.faceH * scale)) / 2); - g.setBgColor(settings.hairColour); + g.setBgColor(exports.settings.hairColour); g.clearRect(Bangle.appRect); g.setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); From fe17e264e31fbaac961638ff07275cc0046f5216 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Fri, 1 Nov 2024 12:20:02 -0500 Subject: [PATCH 43/63] Rebble Watchface: Possibly fix steps counter text white when it should be black. --- apps/rebble/rebble.app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js index 3f97dc5cb9b..68cb909ef35 100644 --- a/apps/rebble/rebble.app.js +++ b/apps/rebble/rebble.app.js @@ -219,6 +219,8 @@ Graphics.prototype.setFontKdamThmor = function(scale) { } let drawSideBar2Alt=function() { + setTextColor(); + // steps g.drawImage(boot_img, 113, 59, { scale: 1 }); setSmallFont(); From a736c662bcbd28109ba12d3fac4fd5a3af2344f5 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sat, 2 Nov 2024 01:06:51 +0100 Subject: [PATCH 44/63] setuichange: Bangle.js 1 support In step with https://github.com/espruino/Espruino/commit/12dacead0d02fb3671fb9c7b7b01e18ff0c0119d on PR https://github.com/espruino/Espruino/pull/2571 This is currently untested since I don't have a Bangle.js 1 myself. --- apps/setuichange/ChangeLog | 7 +- apps/setuichange/boot-b1.js | 118 +++++++++++++++++++++++ apps/setuichange/{boot.js => boot-b2.js} | 0 apps/setuichange/metadata.json | 7 +- 4 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 apps/setuichange/boot-b1.js rename apps/setuichange/{boot.js => boot-b2.js} (100%) diff --git a/apps/setuichange/ChangeLog b/apps/setuichange/ChangeLog index 89a3d196427..8a8e531318b 100644 --- a/apps/setuichange/ChangeLog +++ b/apps/setuichange/ChangeLog @@ -1,5 +1,4 @@ 0.01: New App! -0.02: Fix case where we tried to push to Bangle.btnWatches but it wasn't - defined. -0.03: Throw exception if trying to add custom drag handler on mode updown and - leftright. +0.02: Fix case where we tried to push to Bangle.btnWatches but it wasn't defined. +0.03: Throw exception if trying to add custom drag handler on mode updown and leftright. +0.04: Bangle.js 1 support. No change to Bangle.js 2. diff --git a/apps/setuichange/boot-b1.js b/apps/setuichange/boot-b1.js new file mode 100644 index 00000000000..df2bde62edf --- /dev/null +++ b/apps/setuichange/boot-b1.js @@ -0,0 +1,118 @@ +Bangle.setUI = (function(mode, cb) { + var options = {}; + if ("object"==typeof mode) { + options = mode; + mode = options.mode; + if (!mode) throw new Error("Missing mode in setUI({...})"); + } + var redraw = true; + if (global.WIDGETS && WIDGETS.back) { + redraw = false; + WIDGETS.back.remove(mode && options.back); + } + if (Bangle.btnWatches) { + Bangle.btnWatches.forEach(clearWatch); + delete Bangle.btnWatches; + } + if (Bangle.swipeHandler) { + Bangle.removeListener("swipe", Bangle.swipeHandler); + delete Bangle.swipeHandler; + } + if (Bangle.touchHandler) { + Bangle.removeListener("touch", Bangle.touchHandler); + delete Bangle.touchHandler; + } + delete Bangle.uiRedraw; + delete Bangle.CLOCK; + if (Bangle.uiRemove) { + let r = Bangle.uiRemove; + delete Bangle.uiRemove; // stop recursion if setUI is called inside uiRemove + r(); + } + g.reset();// reset graphics state, just in case + if (!mode) return; + if (mode=="updown") { + Bangle.btnWatches = [ + setWatch(function() { cb(-1); }, BTN1, {repeat:1,edge:"rising"}), + setWatch(function() { cb(1); }, BTN3, {repeat:1,edge:"rising"}), + setWatch(function() { cb(); }, BTN2, {repeat:1,edge:"rising"}) + ]; + } else if (mode=="leftright") { + Bangle.btnWatches = [ + setWatch(function() { cb(-1); }, BTN1, {repeat:1,edge:"rising"}), + setWatch(function() { cb(1); }, BTN3, {repeat:1,edge:"rising"}), + setWatch(function() { cb(); }, BTN2, {repeat:1,edge:"rising"}) + ]; + Bangle.swipeHandler = d => {cb(d);}; + Bangle.on("swipe", Bangle.swipeHandler); + Bangle.touchHandler = d => {cb();}; + Bangle.on("touch", Bangle.touchHandler); + } else if (mode=="clock") { + Bangle.CLOCK=1; + Bangle.btnWatches = [ + setWatch(Bangle.showLauncher, BTN2, {repeat:1,edge:"rising"}) + ]; + } else if (mode=="clockupdown") { + Bangle.CLOCK=1; + Bangle.btnWatches = [ + setWatch(function() { cb(-1); }, BTN1, {repeat:1,edge:"rising"}), + setWatch(function() { cb(1); }, BTN3, {repeat:1,edge:"rising"}), + setWatch(Bangle.showLauncher, BTN2, {repeat:1,edge:"rising"}) + ]; + } else if (mode=="custom") { + if (options.clock) { + Bangle.btnWatches = [ + setWatch(Bangle.showLauncher, BTN2, {repeat:1,edge:"rising"}) + ]; + } + } else + throw new Error("Unknown UI mode "+E.toJS(mode)); + if (options.clock) Bangle.CLOCK=1; + if (options.touch) { + Bangle.touchHandler = options.touch; + Bangle.on("touch", Bangle.touchHandler); + } + if (options.swipe) { + Bangle.swipeHandler = options.swipe; + Bangle.on("swipe", Bangle.swipeHandler); + } + if ((options.btn || options.btnRelease) && !Bangle.btnWatches) Bangle.btnWatches = []; + if (options.btn) Bangle.btnWatches.push( + setWatch(function() { options.btn(1); }, BTN1, {repeat:1,edge:"rising"}), + setWatch(function() { options.btn(2); }, BTN2, {repeat:1,edge:"rising"}), + setWatch(function() { options.btn(3); }, BTN3, {repeat:1,edge:"rising"}) + ); + if (options.btnRelease) Bangle.btnWatches.push( + setWatch(function() { options.btn(1); }, BTN1, {repeat:1,edge:"falling"}), + setWatch(function() { options.btn(2); }, BTN2, {repeat:1,edge:"falling"}), + setWatch(function() { options.btn(3); }, BTN3, {repeat:1,edge:"falling"}) + ); + if (options.remove) // handler for removing the UI (intervals/etc) + Bangle.uiRemove = options.remove; + if (options.redraw) // handler for redrawing the UI + Bangle.uiRedraw = options.redraw; + if (options.back) { + var touchHandler = (z) => { + if (z==1) options.back(); + }; + Bangle.on("touch", touchHandler); + var btnWatch; + if (Bangle.btnWatches===undefined) // only add back button handler if there's no existing watch on BTN1 + btnWatch = setWatch(function() { + btnWatch = undefined; + options.back(); + }, BTN3, {edge:"rising"}); + WIDGETS = Object.assign({back:{ + area:"tl", width:24, + draw:e=>g.reset().setColor("#f00").drawImage(atob("GBiBAAAYAAH/gAf/4A//8B//+D///D///H/P/n+H/n8P/n4f/vwAP/wAP34f/n8P/n+H/n/P/j///D///B//+A//8Af/4AH/gAAYAA=="),e.x,e.y), + remove:(noclear)=>{ + if (btnWatch) clearWatch(btnWatch); + Bangle.removeListener("touch", touchHandler); + if (!noclear) g.reset().clearRect({x:WIDGETS.back.x, y:WIDGETS.back.y, w:24,h:24}); + delete WIDGETS.back; + if (!noclear) Bangle.drawWidgets(); + } + }},global.WIDGETS); + if (redraw) Bangle.drawWidgets(); + } +}) diff --git a/apps/setuichange/boot.js b/apps/setuichange/boot-b2.js similarity index 100% rename from apps/setuichange/boot.js rename to apps/setuichange/boot-b2.js diff --git a/apps/setuichange/metadata.json b/apps/setuichange/metadata.json index c5aad692984..f21c784eceb 100644 --- a/apps/setuichange/metadata.json +++ b/apps/setuichange/metadata.json @@ -1,13 +1,14 @@ { "id": "setuichange", "name": "SetUI Proposals preview", - "version":"0.03", + "version":"0.04", "description": "Try out potential future changes to `Bangle.setUI`. Makes hardware button interaction snappier. Makes it possible to set custom event handlers on any type/mode, not just `\"custom\"`. Please provide feedback - see `Read more...` below.", "icon": "app.png", "tags": "", "type": "bootloader", - "supports" : ["BANGLEJS2"], + "supports" : ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ - {"name":"setuichange.0.boot.js","url":"boot.js"} + {"name":"setuichange.0.boot.js","url":"boot-b1.js", "supports": ["BANGLEJS"]}, + {"name":"setuichange.0.boot.js","url":"boot-b2.js", "supports": ["BANGLEJS2"]} ] } From 70aa6aea1797011d0efa8a8d19b253e167644dbb Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Sat, 2 Nov 2024 19:04:36 -0500 Subject: [PATCH 45/63] Rebble Watchface: Bump version --- apps/rebble/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json index 3a06bebce5f..0a76c65a8b5 100644 --- a/apps/rebble/metadata.json +++ b/apps/rebble/metadata.json @@ -2,7 +2,7 @@ "id": "rebble", "name": "Rebble Clock", "shortName": "Rebble", - "version": "0.18", + "version": "0.19", "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", "readme": "README.md", "icon": "rebble.png", From 759971f53bee41d125216ce45f8ac1d5f85b0d3a Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Sat, 2 Nov 2024 19:05:54 -0500 Subject: [PATCH 46/63] Rebble Watchface: Update ChangeLog --- apps/rebble/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/rebble/ChangeLog b/apps/rebble/ChangeLog index 587c02ac837..0985cd3d5c4 100644 --- a/apps/rebble/ChangeLog +++ b/apps/rebble/ChangeLog @@ -16,3 +16,4 @@ 0.16: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps 0.17: Add fullscreen option (on by default) to show widgets, adjust sidebar 1 and 2 when fullscreen is off 0.18: Minor code improvements +0.19: Fix steps counter text white when it should be black From 97113d14be0b2ad672262c23e87f6be16788fcfe Mon Sep 17 00:00:00 2001 From: michele Date: Sun, 3 Nov 2024 14:32:01 +0100 Subject: [PATCH 47/63] tinyeads: show the side bands of the same color of the hair only when the widgets are showing --- apps/tinyheads/lib.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/tinyheads/lib.js b/apps/tinyheads/lib.js index a80f1059a3a..d772e208d6c 100644 --- a/apps/tinyheads/lib.js +++ b/apps/tinyheads/lib.js @@ -135,7 +135,13 @@ exports.drawFace = function(scale, eyesNum, mouthNum, peek, offset) { // Draw face let xOffset = (g.getWidth() - (exports.faceW * scale)) / 2; let yOffset = (offset ? offset : 0) + ((g.getHeight() - (exports.faceH * scale)) / 2); - g.setBgColor(exports.settings.hairColour); + + if (exports.settings.showWidgets == 'on' || (exports.settings.showWidgets == 'unlock' && !Bangle.isLocked())) { + g.setBgColor(exports.settings.hairColour); + } else { + g.setBgColor(0,0,0); + } + g.clearRect(Bangle.appRect); g.setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); From a70030c32e1880981bcb97895cc0a35469243e24 Mon Sep 17 00:00:00 2001 From: Brian Whelan Date: Mon, 4 Nov 2024 09:44:11 +0000 Subject: [PATCH 48/63] Update metadata.json to support Bangle JS 1 --- apps/reply/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/reply/metadata.json b/apps/reply/metadata.json index 7f1dd6812aa..fa1abe92053 100644 --- a/apps/reply/metadata.json +++ b/apps/reply/metadata.json @@ -6,11 +6,11 @@ "type": "module", "provides_modules" : ["reply"], "tags": "", - "supports" : ["BANGLEJS2"], + "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "interface": "interface.html", "storage": [ {"name":"reply","url":"lib.js"} ], "data": [{"name":"replies.json"}] -} \ No newline at end of file +} From 83d966bde94f2933e8afce92062f5e9b62ef8ca0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 4 Nov 2024 09:52:54 +0000 Subject: [PATCH 49/63] remove 'end of file' comment --- apps/puzzle15/puzzle15.settings.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/puzzle15/puzzle15.settings.js b/apps/puzzle15/puzzle15.settings.js index cd5d9ad2624..152b354b527 100644 --- a/apps/puzzle15/puzzle15.settings.js +++ b/apps/puzzle15/puzzle15.settings.js @@ -46,5 +46,3 @@ E.showMenu(mainmenu); }) - -// end of file From 8d859f448fff9a91bbb7bf8b143e86e4039e44b9 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 4 Nov 2024 09:54:14 +0000 Subject: [PATCH 50/63] remove 'end of file' comment --- apps/smclock/settings.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/smclock/settings.js b/apps/smclock/settings.js index 981c834a2c0..3dff0a30c2a 100644 --- a/apps/smclock/settings.js +++ b/apps/smclock/settings.js @@ -1,8 +1,8 @@ -// settings menu for Monogram Watch Face -// Anton Clock settings were used as template -// helper functions taken from Anton Clock - (function (back) { + // settings menu for Monogram Watch Face + // Anton Clock settings were used as template + // helper functions taken from Anton Clock + var FILE = "smclock.json"; // load settings from the file // assign default values if it doesn't exist @@ -88,5 +88,3 @@ // Actually display the menu E.showMenu(mainmenu); }) - -// end of file From c094d33ef47977cc75742ef232b4432731d05b1e Mon Sep 17 00:00:00 2001 From: michele Date: Mon, 4 Nov 2024 23:10:58 +0100 Subject: [PATCH 51/63] tinyhead: fix background colour on the settings screen --- apps/tinyheads/app.js | 4 ++-- apps/tinyheads/lib.js | 13 +++++++++++-- apps/tinyheads/settings.js | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/tinyheads/app.js b/apps/tinyheads/app.js index c38ac24216b..fb5c1a9cb4b 100644 --- a/apps/tinyheads/app.js +++ b/apps/tinyheads/app.js @@ -5,8 +5,7 @@ // Read 12/24 from system settings const is12Hour=(require("Storage").readJSON("setting.json",1)||{})["12hour"] || false; - // Tinyhead features are stored at a resolution of 18x21, this scales them to the best fit for the Banglejs2 screen - const scale=9; + const scale=lib.appScale; const closedEyes = 25; const scaredEyes = 26; @@ -215,6 +214,7 @@ }; let init = function init() { + // change the system theme, so that the widget bar blends in with the clock face g.setTheme({bg:lib.settings.hairColour,fg:lib.settings.faceColour,dark:true}).clear(); Bangle.on('lock', lockHandler); diff --git a/apps/tinyheads/lib.js b/apps/tinyheads/lib.js index d772e208d6c..6ed42f2f437 100644 --- a/apps/tinyheads/lib.js +++ b/apps/tinyheads/lib.js @@ -5,6 +5,14 @@ exports.maxEyes = 25; exports.faceW = 18; exports.faceH = 21; +// Scale used when showing the main clock screen. +// Tinyhead features are stored at a resolution of 18x21, this scales them to the best fit for the Banglejs2 screen +exports.appScale=9; + +// Scale used when showing the face on the settings page. +// It's smaller than on the clock itself, so that selection arrows can be shown down the sides +exports.settingsScale=6; + exports.settingsFile = 'tinyheads.json'; let faceCanvas; @@ -136,10 +144,11 @@ exports.drawFace = function(scale, eyesNum, mouthNum, peek, offset) { let xOffset = (g.getWidth() - (exports.faceW * scale)) / 2; let yOffset = (offset ? offset : 0) + ((g.getHeight() - (exports.faceH * scale)) / 2); - if (exports.settings.showWidgets == 'on' || (exports.settings.showWidgets == 'unlock' && !Bangle.isLocked())) { + // On the main screen, if the widgets are displayed, the background color matches the color of the hair and widget bar + if (scale == exports.appScale && (exports.settings.showWidgets == 'on' || (exports.settings.showWidgets == 'unlock' && !Bangle.isLocked()))) { g.setBgColor(exports.settings.hairColour); } else { - g.setBgColor(0,0,0); + g.setBgColor(0, 0, 0); } g.clearRect(Bangle.appRect); diff --git a/apps/tinyheads/settings.js b/apps/tinyheads/settings.js index 38558bbc29c..e9f8bdb2f6f 100644 --- a/apps/tinyheads/settings.js +++ b/apps/tinyheads/settings.js @@ -6,7 +6,7 @@ let featureColour = 'faceColour'; let colourSelectTimeout; - let scale = 6; // Smaller scale than on the clock itself, so that selection arrows can be shown down the sides + const scale = lib.settingsScale; // 27 colours let colours = [ From 34bf96377c50b5e6f3c87b286be77918164872fa Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Tue, 5 Nov 2024 13:00:07 +0000 Subject: [PATCH 52/63] Draw initial text after setUI in case it removes a back button --- apps/kbedgewrite/ChangeLog | 1 + apps/kbedgewrite/lib.js | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/kbedgewrite/ChangeLog b/apps/kbedgewrite/ChangeLog index e6dd4b19e7b..93f9336cf0d 100644 --- a/apps/kbedgewrite/ChangeLog +++ b/apps/kbedgewrite/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Accents and extended mode characters +0.03: Bugfix - draw initial text after the back button has been removed diff --git a/apps/kbedgewrite/lib.js b/apps/kbedgewrite/lib.js index d71ad5c7364..62e699fa79f 100644 --- a/apps/kbedgewrite/lib.js +++ b/apps/kbedgewrite/lib.js @@ -352,11 +352,6 @@ exports.input = function(options) { } }; - // Draw initial string - require("widget_utils").hide(); - g.setBgColor(g.theme.bg); - wrapText(); - draw(); return new Promise((resolve,reject) => { Bangle.setUI({ @@ -385,6 +380,13 @@ exports.input = function(options) { } } }); + + // Draw initial string + require("widget_utils").hide(); + g.setBgColor(g.theme.bg); + wrapText(); + draw(); + }); From 7e76c83254ffe728064097c79ce8d5cb8094522a Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Tue, 5 Nov 2024 13:08:43 +0000 Subject: [PATCH 53/63] forgot to update version in metadata --- apps/kbedgewrite/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbedgewrite/metadata.json b/apps/kbedgewrite/metadata.json index 717cdbcba99..01436c6aac2 100644 --- a/apps/kbedgewrite/metadata.json +++ b/apps/kbedgewrite/metadata.json @@ -1,6 +1,6 @@ { "id": "kbedgewrite", "name": "EdgeWrite keyboard", - "version":"0.02", + "version":"0.03", "description": "A library for text input via EdgeWrite swipe gestures", "icon": "app.png", "type":"textinput", From c605da645b892572f9f904fd4b896deac06b8ec1 Mon Sep 17 00:00:00 2001 From: michele Date: Tue, 5 Nov 2024 17:32:55 +0100 Subject: [PATCH 54/63] tinyheads: changelog, bump version --- apps/tinyheads/ChangeLog | 1 + apps/tinyheads/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/tinyheads/ChangeLog b/apps/tinyheads/ChangeLog index 1a3bc175736..581b18b40d1 100644 --- a/apps/tinyheads/ChangeLog +++ b/apps/tinyheads/ChangeLog @@ -1 +1,2 @@ 0.01: New app! +0.02: Make the widget bar the same colour as the hair. \ No newline at end of file diff --git a/apps/tinyheads/metadata.json b/apps/tinyheads/metadata.json index 3f0e7abf91b..6ab060416b8 100644 --- a/apps/tinyheads/metadata.json +++ b/apps/tinyheads/metadata.json @@ -4,7 +4,7 @@ "shortName":"Tinyheads", "icon": "app.png", "screenshots" : [ { "url":"tinyhead1.png" }, {"url":"tinyhead2.png"}, {"url":"tinyhead3.png"}, {"url":"tinyhead4.png"}, {"url":"editing.png"} ], - "version":"0.01", + "version":"0.02", "description": "Choose from a variety of hairstyles, eyes, noses, and mouths to customize your pixel art style Tinyhead.", "readme":"README.md", "type": "clock", From 39cd1c73d26da1886e03c1c1e7eb14a29f3aadd9 Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Tue, 5 Nov 2024 21:21:18 -0700 Subject: [PATCH 55/63] Added pokertimer --- .gitmodules | 3 +++ apps/pokertimer | 1 + 2 files changed, 4 insertions(+) create mode 160000 apps/pokertimer diff --git a/.gitmodules b/.gitmodules index c2c1104c238..5002b324b20 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "webtools"] path = webtools url = https://github.com/espruino/EspruinoWebTools.git +[submodule "apps/pokertimer"] + path = apps/pokertimer + url = https://gitea.gf4.pw/ki9/pokertimer.git diff --git a/apps/pokertimer b/apps/pokertimer new file mode 160000 index 00000000000..bdd82cc2601 --- /dev/null +++ b/apps/pokertimer @@ -0,0 +1 @@ +Subproject commit bdd82cc2601f6904f1f45936e4830e38e53b1865 From ec34fcb2bfd7dcfffb4ae9e0678ed48fa4eef719 Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Tue, 5 Nov 2024 21:44:03 -0700 Subject: [PATCH 56/63] Updated pokertimer documentation --- apps/pokertimer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pokertimer b/apps/pokertimer index bdd82cc2601..5fae11bd67a 160000 --- a/apps/pokertimer +++ b/apps/pokertimer @@ -1 +1 @@ -Subproject commit bdd82cc2601f6904f1f45936e4830e38e53b1865 +Subproject commit 5fae11bd67a41c86f45168f71268cdeb8a194549 From 8e794e6c53cdcea011fbb0f5fd3517a318c44135 Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Tue, 5 Nov 2024 21:45:49 -0700 Subject: [PATCH 57/63] Polished pokertimer comments --- apps/pokertimer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pokertimer b/apps/pokertimer index 5fae11bd67a..6dc2e3fb9af 160000 --- a/apps/pokertimer +++ b/apps/pokertimer @@ -1 +1 @@ -Subproject commit 5fae11bd67a41c86f45168f71268cdeb8a194549 +Subproject commit 6dc2e3fb9af28740b6cd9f8535dcab44d8125ac0 From 7f118fc5d178ccb4a53126a89a460b9b3cde2455 Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Tue, 5 Nov 2024 21:49:56 -0700 Subject: [PATCH 58/63] Compliant changelog --- apps/pokertimer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pokertimer b/apps/pokertimer index 6dc2e3fb9af..f78041a2064 160000 --- a/apps/pokertimer +++ b/apps/pokertimer @@ -1 +1 @@ -Subproject commit 6dc2e3fb9af28740b6cd9f8535dcab44d8125ac0 +Subproject commit f78041a20643d801ce4ab027effef23205e0050a From 41d57e55558cefe8c733ab3fa30accec2dede7d2 Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Tue, 5 Nov 2024 21:55:15 -0700 Subject: [PATCH 59/63] Reminder for screenshots --- apps/pokertimer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pokertimer b/apps/pokertimer index f78041a2064..bcfc295917c 160000 --- a/apps/pokertimer +++ b/apps/pokertimer @@ -1 +1 @@ -Subproject commit f78041a20643d801ce4ab027effef23205e0050a +Subproject commit bcfc295917c6fc9faadf89e3bb718a0bf533905a From dac46fd46416eb9ce5af367b469348c125328b75 Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Wed, 6 Nov 2024 07:18:47 -0700 Subject: [PATCH 60/63] Revert "Added pokertimer" Apps can not be submodules, for good reasons. Reverting to re-add as a proper package. This reverts commit 39cd1c73d26da1886e03c1c1e7eb14a29f3aadd9. --- .gitmodules | 3 --- apps/pokertimer | 1 - 2 files changed, 4 deletions(-) delete mode 160000 apps/pokertimer diff --git a/.gitmodules b/.gitmodules index 5002b324b20..c2c1104c238 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "webtools"] path = webtools url = https://github.com/espruino/EspruinoWebTools.git -[submodule "apps/pokertimer"] - path = apps/pokertimer - url = https://gitea.gf4.pw/ki9/pokertimer.git diff --git a/apps/pokertimer b/apps/pokertimer deleted file mode 160000 index bcfc295917c..00000000000 --- a/apps/pokertimer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bcfc295917c6fc9faadf89e3bb718a0bf533905a From 30a349f3feb8bb757670b7d683f88e44b850b2bd Mon Sep 17 00:00:00 2001 From: Keith Irwin Date: Wed, 6 Nov 2024 07:25:14 -0700 Subject: [PATCH 61/63] Re-added pokertimer not as a submodule --- apps/pokertimer/ChangeLog | 1 + apps/pokertimer/LICENSE | 9 +++ apps/pokertimer/README.md | 32 +++++++++ apps/pokertimer/ROADMAP.md | 17 +++++ apps/pokertimer/app-icon.js | 1 + apps/pokertimer/app.img | Bin 0 -> 714 bytes apps/pokertimer/app.js | 124 ++++++++++++++++++++++++++++++++++ apps/pokertimer/app.png | Bin 0 -> 1132 bytes apps/pokertimer/metadata.json | 15 ++++ 9 files changed, 199 insertions(+) create mode 100644 apps/pokertimer/ChangeLog create mode 100644 apps/pokertimer/LICENSE create mode 100644 apps/pokertimer/README.md create mode 100644 apps/pokertimer/ROADMAP.md create mode 100644 apps/pokertimer/app-icon.js create mode 100644 apps/pokertimer/app.img create mode 100644 apps/pokertimer/app.js create mode 100644 apps/pokertimer/app.png create mode 100644 apps/pokertimer/metadata.json diff --git a/apps/pokertimer/ChangeLog b/apps/pokertimer/ChangeLog new file mode 100644 index 00000000000..642dbcc7eee --- /dev/null +++ b/apps/pokertimer/ChangeLog @@ -0,0 +1 @@ +0.0.1: Packaged app diff --git a/apps/pokertimer/LICENSE b/apps/pokertimer/LICENSE new file mode 100644 index 00000000000..a2bb2da017d --- /dev/null +++ b/apps/pokertimer/LICENSE @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright © 2024 Keith Irwin + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/apps/pokertimer/README.md b/apps/pokertimer/README.md new file mode 100644 index 00000000000..09aa2d6a14e --- /dev/null +++ b/apps/pokertimer/README.md @@ -0,0 +1,32 @@ +# Poker Timer + +A blinds timer for poker. Don't know what that means? See [Wikipedia: Blind (poker)](https://en.wikipedia.org/wiki/Blind_(poker)) and [Wikipedia: Texas hold 'em](https://en.wikipedia.org/wiki/Texas_hold_%27em). + +The blinds are hardcoded and go up every ten minutes: + +- 1, 2 +- 2, 4 +- 4, 8 +- 5, 10 +- 10, 20 +- 20, 40 +- 40, 80 + +... and so on, doubling each round. + +## Usage + +The timer will start as soon as you open the app. Time left in the round is on the top of the screen, currnt small and big blinds are shown below. After ten minutes, it will vibrate and flash and show the new blind. Then it starts over. + +## Controls + + - **Pause/Resume:** Press the button + - **Exit:** hold down the button. + +## Requests + +[Contact Keith Irwin](https://www.ki9.us/contact/) + +## Creator + +[Keith Irwin](https://www.ki9.us) diff --git a/apps/pokertimer/ROADMAP.md b/apps/pokertimer/ROADMAP.md new file mode 100644 index 00000000000..b182c5b3868 --- /dev/null +++ b/apps/pokertimer/ROADMAP.md @@ -0,0 +1,17 @@ +# Roadmap + +## Bugs + +- Unlock before vibrate/flash + +## Improvements + +- Screenshots in README +- Start app paused +- Indicate when paused +- 20-second warning + +## Long-term projects + +- Set settings +- Better graphics diff --git a/apps/pokertimer/app-icon.js b/apps/pokertimer/app-icon.js new file mode 100644 index 00000000000..bf7227a8013 --- /dev/null +++ b/apps/pokertimer/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("kso4cB7nW///7fWm2Vw8p7fOgH6lM6hEqgQCDkNCgmSpMkyUQqkEAQsJBYIOBkGohACD8dIiQaCpFBhUQAQVD+9qDQeQwWgkGCikg1lxknZBwUhgkooICCnMjpO1qIOBoUKwGCAQXt32TtMkwUkwkVgIdFg3SGQOBNYoCChuklfAgBQCPokqjdBluCNAJTBkN4UwVBm2C5ckxFBqEQq/+BYKMBtstz1JiBuC/+T2gjC7VYlmSkMFoFOQQON0mShO0iFNkhuC8iCBk4aBwdpFgNENwMOVgft1Ms9uiwNJLIM/VgWTxUFjdrtsUiUQ0NPXYe0qE27XRoLdC/wpCpxvBtuzpMiboX8DQXtQYPbtto0jdCm87zvOIwMh23YgDdBNwNBh/bYoL7BtuapDdE2VGWYMgw3brUpbocF/mcIYMIlu10WCpL4FihEB3PboBaBiFUGQOhAQcbqkgLQL1CdIYCBm2oIgNIru36VJkD+BboUgxMkyGcyOk1VIkGFboWhiRuBrHiqpBBIgUVboJEBoUf3dSK4IpBhUTtEiIgOEjlpGolBg3QoiuBJoZWCAQMN0kJFIIyCIIQCBkNb1JEBc4Ul2zKBAQW7qLzDBw7pBBYYCDwgpCoUEBYoCC0A7CBY4CCykooALIBwcRAoQ")) diff --git a/apps/pokertimer/app.img b/apps/pokertimer/app.img new file mode 100644 index 0000000000000000000000000000000000000000..e2e05ea17aef14d8efd6130ffe6d010ade2347b4 GIT binary patch literal 714 zcmb7?KTE?<6va;(trRIj1qG`RC4*9QYmwrRL7`C*ovo0;L7@TNT5xy;LEK7Eadhwl zbgBg%3WDI`Bt;2GR~`KV_1<^WKda&8a?kDWop+KnlX*76w{G`hK6|~C_dciF!MPo{ z|6B$1u4rRVA|+OlK2`|5Ib zY$f(P7@A_V9*EEOeN!QM<57#qa^*3)IT>r2U8A0Q33{Xdtb5 zH+I?)KB?H>uD%yV$6K0r5_h6akNsV1VpX(J*L=;~7EPak{RaU`nja3p{=7oJLF-HN ddcra+3onfJ?D5R-Alfb_bdWUtN`C;?`UC5bn?C>m literal 0 HcmV?d00001 diff --git a/apps/pokertimer/app.js b/apps/pokertimer/app.js new file mode 100644 index 00000000000..26b72c4811c --- /dev/null +++ b/apps/pokertimer/app.js @@ -0,0 +1,124 @@ +const BLIND_INTERVAL = 600; // 10 minutes +const BLINDSUP_ALERT_DURATION = 5000; // 30 seconds + +// Convert seconds to mm:ss +const secondsToMinutes = (s) => { + const mm = Math.floor(s/60); + const ss = s - mm * 60; + return `${mm}:${String(ss).padStart(2,'0')}`; +}; + +// Format screen +const fmtDark = () => { + g.clear(); + g.setFontAlign(0,0); + g.setBgColor(0,0.5,0); + g.setColor(1,1,1); +}; +const fmtLight = () => { + g.clear(); + g.setFontAlign(0,0); + g.setBgColor(0.5,1,0.5); + g.setColor(0,0,0); +}; + +// Start/stop/pause/resume timer +const startTimer = () => { + timer_running = true; tick(); + timer = setInterval(tick, 1000); +}; +const stopTimer = () => { + clearInterval(timer); + timer_running = false; +}; +const pauseResume = () => { + if (timer_running) stopTimer(); + else startTimer(); +}; + +// Calculate blinds for a round +const getBlinds = (i) => { + let small; + if (i===0) small = 1; + else if (i===1) small = 2; + else if (i===2) small = 4; + else small = 5*(Math.pow(2,(i-3))); + return [small, small*2]; +}; + +// Sound the alarm +const blindsUp = () => { + // Display message + const showMessage = () => { + g.clear(); + g.setFont('Vector',34); + g.drawString('Blinds Up!', + g.getWidth()/2, g.getHeight()/3); + g.setFont('Vector',40); + g.drawString(`${blinds[0]}/${blinds[1]}`, + g.getWidth()/2, g.getHeight()*2/3); + }; + stopTimer(); + // Increase blinds + b++; + // TODO: Kill program between round 25 and 26 + blinds = getBlinds(b); + console.log(`Blinds for round ${b} are ${blinds[0]} / ${blinds[1]}`); + // Buzz and light up every second + const buzzInterval = setInterval(() => { + Bangle.buzz(); + Bangle.setLCDPower(1); + }, 1000); + // Invert colors every second + fmtLight(); showMessage(); let dark = false; + const flashInterval = setInterval(() => { + if (dark) { + fmtLight(); + dark = false; + } else { + fmtDark(); + dark = true; + } showMessage(); + }, 500); + // Restart timer + setTimeout(() => { + fmtDark(); tick(); + clearInterval(buzzInterval); + clearInterval(flashInterval); + time_left = BLIND_INTERVAL + 1; + startTimer(); + }, BLINDSUP_ALERT_DURATION); +}; + +// Tick every second +const tick = () => { + if (!timer_running) return; + time_left--; + if (time_left<=0) blindsUp(); + else { + g.clear(); + g.setFont('Vector',40); + g.drawString( + secondsToMinutes(time_left), + g.getWidth()/2, g.getHeight()/3); + g.drawString( + `${blinds[0]}/${blinds[1]}`, + g.getWidth()/2, g.getHeight()*2/3); + } + return; +}; + +// button listener +Bangle.setUI({ + mode: 'custom', + btn: pauseResume, +}); + +// RUNTIME +fmtDark(); +let time_left = BLIND_INTERVAL + 1; +let b = 0; +let blinds = getBlinds(b); +let timer_running = true; +let timer = setInterval(tick, 1000); +tick(); diff --git a/apps/pokertimer/app.png b/apps/pokertimer/app.png new file mode 100644 index 0000000000000000000000000000000000000000..31a48dbb0a211500937af6a7bb7fc058d2f3164f GIT binary patch literal 1132 zcmV-y1e5!TP)Ic-y-^{?acbn_=_PT5Dl6#UTlbzX1p5M&P?Ch*0WtCM{afJvwjR*s~EMqz(*(p22 z>y|PF;9yG|JpAM`XlnIjCcyf4wm?q78Yr)PH}e1n10i_qnOrz;fyJpngX&Vy@}c>)0Uci-xLdILow z4_Xdz*yDp``Gq39?&Srm;mC2HX#nNNQ*gQZWf(tm8kna^fT-S|Mj%NPF1`BZ69uh@YwkT0Q4dN+-4a-eo=`jfP%GCPhO+7$0gzG>lT1A z&=dbY%ot7Y^+*EEeoK z#(2J^0LQ*R2@9WE5fhT{GNVh~{64p@D`|jVKYBeDfUvHV!Y2aY_H^}$my}g&)O(i%0$_B-ruPH@-%gnMon`>g+>J5q z0abm-c7V>l0a)~Ot^nX=r++XdfZsRf82>)wDThxMAgHL5`yk!LrRAdD48XO@JP3zJ z4HKB|upMBwK3BL1j?`|C+ZK*!jFx=w1D-uh-ky-g(v4>`6K}@A;0NLB3_a8J@5|R8_r8noIHZ8xdN9F#ATv z^fxnqDVflADV^j7m=_{iF5gv(qw*O5LRfo4N@s-#S-?MD$b@?NyKYSHWBTv#_|FeW ynWD3*dbf<#b%@X=nb1r8%gkJ7$|@@ Date: Wed, 6 Nov 2024 10:02:16 -0700 Subject: [PATCH 62/63] Bug fixes and upgrades to pokertimer --- apps/pokertimer/ChangeLog | 7 ++++- apps/pokertimer/README.md | 27 ++++++++++++++++-- apps/pokertimer/ROADMAP.md | 17 ----------- apps/pokertimer/app.img | Bin 714 -> 0 bytes apps/pokertimer/app.js | 26 ++++++++++++++--- apps/pokertimer/metadata.json | 6 ++-- .../screenshots/01_paused-start.png | Bin 0 -> 2820 bytes .../screenshots/02_counting-down.png | Bin 0 -> 3322 bytes apps/pokertimer/screenshots/03_blinds-up.png | Bin 0 -> 3551 bytes 9 files changed, 56 insertions(+), 27 deletions(-) delete mode 100644 apps/pokertimer/ROADMAP.md delete mode 100644 apps/pokertimer/app.img create mode 100644 apps/pokertimer/screenshots/01_paused-start.png create mode 100644 apps/pokertimer/screenshots/02_counting-down.png create mode 100644 apps/pokertimer/screenshots/03_blinds-up.png diff --git a/apps/pokertimer/ChangeLog b/apps/pokertimer/ChangeLog index 642dbcc7eee..ff87a170821 100644 --- a/apps/pokertimer/ChangeLog +++ b/apps/pokertimer/ChangeLog @@ -1 +1,6 @@ -0.0.1: Packaged app +0.06: Fix bug when play/pause during alert +0.05: Added screenshots +0.04: Added 20-second warning buzz +0.03: Start app with paused timer +0.02: Fix alert buzz time, Indicate when paused +0.01: Packaged app diff --git a/apps/pokertimer/README.md b/apps/pokertimer/README.md index 09aa2d6a14e..ce8316def60 100644 --- a/apps/pokertimer/README.md +++ b/apps/pokertimer/README.md @@ -1,7 +1,12 @@ # Poker Timer +*v.0.06* A blinds timer for poker. Don't know what that means? See [Wikipedia: Blind (poker)](https://en.wikipedia.org/wiki/Blind_(poker)) and [Wikipedia: Texas hold 'em](https://en.wikipedia.org/wiki/Texas_hold_%27em). +![Screenshot showing countdown paused on start](screenshots/01_paused-start.png) +![Screenshot showing active countdown](screenshots/02_counting-down.png) +![Screenshot showing blinds up alert](screenshots/03_blinds-up.png) + The blinds are hardcoded and go up every ten minutes: - 1, 2 @@ -14,14 +19,32 @@ The blinds are hardcoded and go up every ten minutes: ... and so on, doubling each round. +## Features + +- Starts paused +- Button to pause/resume +- 20-second warning buzz +- Auto-exit after round 25 + ## Usage -The timer will start as soon as you open the app. Time left in the round is on the top of the screen, currnt small and big blinds are shown below. After ten minutes, it will vibrate and flash and show the new blind. Then it starts over. +The timer will start as soon as you open the app. Time left in the round is on the top of the screen, currnt small and big blinds are shown below. After ten minutes, it will vibrate and flash and show the new blind. Then it starts over. + +### Auto-exit + +The program will automatically exit after the 25 round. This is not a bug. If the blinds double again, it will perform some kind of overflow and convert the blind values to floats. + +The blinds in round 25 are `20971520 / 41943040`. You probably aren't still playing poker at that point and just forgot to exit the program. ## Controls - **Pause/Resume:** Press the button - - **Exit:** hold down the button. + - **Exit:** hold down the button + +## Roadmap + +- Set settings +- Better graphics ## Requests diff --git a/apps/pokertimer/ROADMAP.md b/apps/pokertimer/ROADMAP.md deleted file mode 100644 index b182c5b3868..00000000000 --- a/apps/pokertimer/ROADMAP.md +++ /dev/null @@ -1,17 +0,0 @@ -# Roadmap - -## Bugs - -- Unlock before vibrate/flash - -## Improvements - -- Screenshots in README -- Start app paused -- Indicate when paused -- 20-second warning - -## Long-term projects - -- Set settings -- Better graphics diff --git a/apps/pokertimer/app.img b/apps/pokertimer/app.img deleted file mode 100644 index e2e05ea17aef14d8efd6130ffe6d010ade2347b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 714 zcmb7?KTE?<6va;(trRIj1qG`RC4*9QYmwrRL7`C*ovo0;L7@TNT5xy;LEK7Eadhwl zbgBg%3WDI`Bt;2GR~`KV_1<^WKda&8a?kDWop+KnlX*76w{G`hK6|~C_dciF!MPo{ z|6B$1u4rRVA|+OlK2`|5Ib zY$f(P7@A_V9*EEOeN!QM<57#qa^*3)IT>r2U8A0Q33{Xdtb5 zH+I?)KB?H>uD%yV$6K0r5_h6akNsV1VpX(J*L=;~7EPak{RaU`nja3p{=7oJLF-HN ddcra+3onfJ?D5R-Alfb_bdWUtN`C;?`UC5bn?C>m diff --git a/apps/pokertimer/app.js b/apps/pokertimer/app.js index 26b72c4811c..9d584b3b2a6 100644 --- a/apps/pokertimer/app.js +++ b/apps/pokertimer/app.js @@ -1,5 +1,5 @@ -const BLIND_INTERVAL = 600; // 10 minutes -const BLINDSUP_ALERT_DURATION = 5000; // 30 seconds +const BLIND_INTERVAL = 600; // 10 minutes in seconds +const BLINDSUP_ALERT_DURATION = 10000; // 10 seconds in ms // Convert seconds to mm:ss const secondsToMinutes = (s) => { @@ -32,7 +32,13 @@ const stopTimer = () => { timer_running = false; }; const pauseResume = () => { - if (timer_running) stopTimer(); + if (is_alerting) return; + if (timer_running) { + stopTimer(); + g.setFont('Vector',15); + g.drawString('(PAUSED)', + g.getWidth()/2, g.getHeight()*7/8); + } else startTimer(); }; @@ -48,6 +54,7 @@ const getBlinds = (i) => { // Sound the alarm const blindsUp = () => { + is_alerting = true; // Display message const showMessage = () => { g.clear(); @@ -66,7 +73,7 @@ const blindsUp = () => { console.log(`Blinds for round ${b} are ${blinds[0]} / ${blinds[1]}`); // Buzz and light up every second const buzzInterval = setInterval(() => { - Bangle.buzz(); + Bangle.buzz(500); Bangle.setLCDPower(1); }, 1000); // Invert colors every second @@ -82,6 +89,7 @@ const blindsUp = () => { }, 500); // Restart timer setTimeout(() => { + is_alerting = false; fmtDark(); tick(); clearInterval(buzzInterval); clearInterval(flashInterval); @@ -94,6 +102,13 @@ const blindsUp = () => { const tick = () => { if (!timer_running) return; time_left--; + // 20-second warning buzz + if (time_left==20) { + const buzzInterval = setInterval(Bangle.buzz, 500); + setTimeout(() => { + clearInterval(buzzInterval); + }, 5000); + } if (time_left<=0) blindsUp(); else { g.clear(); @@ -120,5 +135,8 @@ let time_left = BLIND_INTERVAL + 1; let b = 0; let blinds = getBlinds(b); let timer_running = true; +let is_alerting = false; let timer = setInterval(tick, 1000); tick(); +// Start paused +pauseResume(); diff --git a/apps/pokertimer/metadata.json b/apps/pokertimer/metadata.json index abdc6e81f24..a22229e4fb6 100644 --- a/apps/pokertimer/metadata.json +++ b/apps/pokertimer/metadata.json @@ -4,12 +4,12 @@ "shortName":"Poker Timer", "readme":"README.md", "icon": "app.png", - "version":"0.0.1", + "version":"0.06", "description": "A blinds timer for use with Texas Hold 'Em", "tags": "poker", "supports": ["BANGLEJS2"], "storage": [ - {"name":"timer.app.js","url":"app.js"}, - {"name":"timer.img","url":"app-icon.js","evaluate":true} + {"name":"pokertimer.app.js","url":"app.js"}, + {"name":"pokertimer.img","url":"app-icon.js","evaluate":true} ] } diff --git a/apps/pokertimer/screenshots/01_paused-start.png b/apps/pokertimer/screenshots/01_paused-start.png new file mode 100644 index 0000000000000000000000000000000000000000..929bd473eb3314b795962c227087d047ca66b673 GIT binary patch literal 2820 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 Date: Wed, 6 Nov 2024 10:54:28 -0700 Subject: [PATCH 63/63] Fixed ChangeLog order --- apps/pokertimer/ChangeLog | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/pokertimer/ChangeLog b/apps/pokertimer/ChangeLog index ff87a170821..ceddbf5337f 100644 --- a/apps/pokertimer/ChangeLog +++ b/apps/pokertimer/ChangeLog @@ -1,6 +1,6 @@ -0.06: Fix bug when play/pause during alert -0.05: Added screenshots -0.04: Added 20-second warning buzz -0.03: Start app with paused timer -0.02: Fix alert buzz time, Indicate when paused 0.01: Packaged app +0.02: Fix alert buzz time, Indicate when paused +0.03: Start app with paused timer +0.04: Added 20-second warning buzz +0.05: Added screenshots +0.06: Fix bug when play/pause during alert