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 8276321ac..4fb438097 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 a9ca7de31..7e0653c22 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 3d47c5062..46e230a60 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 7e5ac0271..97ba43366 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 1d8e44b72..dd47229f7 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 aa4a7e7b5..416d5939c 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 dcc55da58..c71de37c7 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 4fb438097..7d2043899 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 7e0653c22..1134749c2 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 46e230a60..1d9a73ce3 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 416d5939c..a10a0cb15 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 1e62173dc..f1107fc84 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 53cf51ff2..18297d84f 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 000000000..71d7f6043 --- /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 b1c3ecfaa..584c071cf 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 6a3ed6faf..0f503ad37 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 2ecbb9a94..83eb2ca20 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 73ba4a259..8d4d747c0 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 fcd971fc4..e11448a18 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 4141c7797..274b83d14 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 314b1490c..35bde7bbd 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 436b77d3e..95a34e892 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 0351fbead..3212ee649 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 3c681a638..a370befc0 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 59345340f..256f2f372 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 85b1f8a5a..ba6fb6712 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 dd47229f7..5b0fcc583 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 a10a0cb15..07d8d2031 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 c71de37c7..afe576e71 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 aa06d9e1d..601a9f089 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 097869de3..ae1c44012 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 3cb9672c7..0981d6dbe 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 42e785b0a..ad327831a 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 422ef6b89..aeae2d254 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 98b91dc7b..457bc47b3 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 13f928f18..89b1c80f8 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 994f6d053..a51219346 100644 --- a/apps/assistedgps/custom.html +++ b/apps/assistedgps/custom.html @@ -60,6 +60,7 @@ diff --git a/apps/assistedgps/metadata.json b/apps/assistedgps/metadata.json index 8d4e07fa3..73f775a72 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 97ba43366..cbf53ec34 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 82856b639..0df4625f5 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 | 94 +++++++++++++++++++------------------- 3 files changed, 90 insertions(+), 81 deletions(-) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 7e4105f3d..c704e0f90 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 06c7ad3d6..ceca89b8d 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 0df4625f5..ec2644f6b 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 fr_BE, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fr_CH, 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 sl_SI, meridian must be shorter than 4 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, 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 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 639173f4d..5c66fc313 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 8dd7f8c87..4c64d078a 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 d48cdca63..74f8515db 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 5e3f15af2..4eda86941 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 4730db5b5..bde218236 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 62542be60..a4b22db22 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 86e1face0..1dbb2e1de 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 692822b39..c805b0f39 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 b5c6bc640..3bcbf6fd3 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 e9326fd2c..34873124c 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 4c364a864..5e160b5d4 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 7ba060d6d..163c0f541 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 ec2644f6b..b2332b16f 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 b2332b16f..61a251bb5 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 3767ad71e..0667d8ff6 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 deafe7d68..57acadf25 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 a779a8660..343fa1069 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 a5389a91b..eff9a331b 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 71d7f6043..038d154b3 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 f97d7b85f..d0676ec9b 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 54d79866a..1dcb30ed8 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 ff8376bae..4e3ca6057 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 1dcb30ed8..43141531f 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 1134749c2..0e20ab855 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 51c31cc81..450ad4f26 100644 --- a/apps/powermanager/interface.html +++ b/apps/powermanager/interface.html @@ -148,7 +148,7 @@ function viewDeferredTable(filename) { //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 000000000..5560f00bc --- /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 000000000..6762e0c1a --- /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 000000000..5a7f9cd1f --- /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 000000000..5937edea3 --- /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 000000000..2a70aad75 --- /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 000000000..bb9b3a6c6 --- /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 5cac5770e..585e89ef9 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 2108910fc..9da914980 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 bac0ed369..0f6430829 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 57acadf25..d4cb97db8 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 343fa1069..fd39b11bd 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 5316525b3..483af8c97 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 3b64d8735..16799f0db 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 64fa25330..95b06fe55 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 765e5a5fa..2843fbdb1 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 708913705..7bbceb2c2 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 4448c00ed..70851e983 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 0b52acd72..a52634faf 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 04f0a38ba..bc292ef6f 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 a1b655a62..b240a5f46 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 bb943c081..0326d7529 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 00e9c284b..9143fc16e 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 9a9515c3a..69cd022af 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 e35db455d..c4b41101b 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 68e958db8..310816dda 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 ee3bbd417..48301a865 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 55160c9be..1cfb980f4 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 714b48f2e..0a92f5a5a 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 0213ead6e..f062b98b1 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 6fe8f2817..508de5ddc 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 7db9bbdae..740e05eda 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 a3dae43e1..f01649c4c 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 fbbe80a55..caf460da3 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 f0c2a6ccb..78794205e 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 ea613f5c0..ddacb4a16 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 fb1dd761c..deae484c9 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 b38df1824..f97d49ad3 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 5776baa0b..5099d0b7d 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 c0a2ffeea..250633dea 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 46988ec26..c13a0825d 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 59a13c443..2aac13b28 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 ff4ede637..58634b1b3 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 ce72f215f..d82a9f6d4 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 336229b73..8353103e3 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 6a50f90d4..f6894e289 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 da350edd8..8c3bb6e4d 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 b589bb3f7..98720a1db 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 20634ed5e..0b54c350f 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 9b8d35be9..70d96c1e9 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 f34262f2a..db84fd84d 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 e3b00359c..9562bc3c1 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 23a58d58f..25feadd7c 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 0e3c621d1..71a64f69b 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 3278075e4..ef2c188d7 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 a9adf87fc..44182540b 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 4ebf842ce..a5e35192a 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 496a6d77e..f4f3bb31b 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 1dc80ade1..1bf60c744 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 1d429580c..4ccc47237 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 cd813d928..890c23692 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 cd76bf115..93e57fae0 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 1dd4d92df..3eacd737d 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 4faeb2573..fbed187a9 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 0bbecc2ce..154b3b6b6 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 744ebd8dc..f4afe2e85 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 f6b84c785..69aabfad0 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 83032270a..c4b860792 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 d54517a70..29f8c85bc 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 29528c5dd..fa27f816b 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 b22a7918a..5103d08f3 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 352ec4315..cd5d9ad26 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 ab7d561d1..2db1f28cc 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 8ed2ceae5..40be27920 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 6ca4f59d5..cde5c8ef4 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 bfadacda1..8643f4274 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 fc50d04dc..10d0489a7 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 76036db2b..c03cd6679 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 88e367821..f32bb6189 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 ae631e60c..a5d3dfad1 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 1472cb099..183370082 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 419b186d6..2c9ebd87a 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 8fd042b3b..17524ca8d 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 dcaf0aff6..fd2717927 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 2c2d2c463..71c272753 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 30119e48d..981c834a2 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 aeaa84f2c..a4e70c2c0 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 63fa424ba..d0e6c2fda 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 4f8db5eb8..21752e58a 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 94ec34a36..b85ff65f6 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 1a2959227..90e3c4231 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 3a38eed09..d7824815a 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 1a8500add..0f4acfc70 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 137ed31db..ffdaa4665 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 f3004000a..a8a17125c 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 d3de4e6d3..4a7464f06 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 67aa9a518..f435b0ba4 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 8a12197dc..448e178d8 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 0aa7330c1..8a2127ba7 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 a632850d6..cf445fe48 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 8dd0d81fa..5e83c6f3a 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 68e7bab6b..4762e1e80 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 c3464a82b..352dca467 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 c599183dc..077efaf8a 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 0017cc499..5ed8b0a37 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 7a1c186c9..8f1d99f06 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 0b8c989ac..1c696939b 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 a389f7918..e671d9900 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 bb47e9b20..fa1ada630 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 da402e08e..e758a1760 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 def512856..911e64894 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 1b1b6e604..ddd16c4a6 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 44182540b..dd18626e1 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 a62a1bc43..d39fb5a31 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 9c558bc5b..218e4b441 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 5103d08f3..8c700c8cd 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 d6f9f6e8c..975da5800 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 b4436bd39..a4ef71488 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 21752e58a..0503a455a 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 3bcbf6fd3..1b3a3cc11 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 448e178d8..710d071ea 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 25feadd7c..287073b0c 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 71a64f69b..59988b788 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 73ceff3c1..185e9034f 100644 --- a/apps/sched/interface.html +++ b/apps/sched/interface.html @@ -173,7 +173,7 @@ function renderAlarm(alarm, exists) { }; } } - 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 185e9034f..fa4132574 100644 --- a/apps/sched/interface.html +++ b/apps/sched/interface.html @@ -331,6 +331,10 @@ function getData() { 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 caf460da3..8b7a6a9ad 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 000000000..bf5493745 --- /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 | 196 ++++++++++++++++++++++++----- apps/kbedgewrite/metadata.json | 9 +- apps/kbedgewrite/screenshot.png | Bin 0 -> 2878 bytes apps/kbedgewrite/settings.js | 40 ++++++ 7 files changed, 300 insertions(+), 35 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 5560f00bc..e6dd4b19e 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 8d0ca5dc5..2f668d4cf 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 74276b683..9aa70ae71 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 a69eabc2c..d71ad5c73 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) + }, - // 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) { + }; + + function wrapText() { + let stringToWrap = text.substring(0, cursorPos) + '_' + text.substring(cursorPos); + let l = []; + let startPos = 0; + + 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); } - g.setColor(g.theme.fg); - g.setFontAlign(-1, -1, 0); - g.drawString(l.join('\n'), Bangle.appRect.x, Bangle.appRect.y); - // Draw punctuation flag - if (punctuationMode > 0) { + 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(wrappedText, Bangle.appRect.x, Bangle.appRect.y); + + // 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 cbf873a09..717cdbcba 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 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 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 a3f79c081..492929f10 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 cbb139d8c..1c4ee42a5 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 492929f10..c38ac2421 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 1c4ee42a5..a80f1059a 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 3f97dc5cb..68cb909ef 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 89a3d1964..8a8e53131 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 000000000..df2bde62e --- /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 c5aad6929..f21c784ec 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 3a06bebce..0a76c65a8 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 587c02ac8..0985cd3d5 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 a80f1059a..d772e208d 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 7f1dd6812..fa1abe920 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 cd5d9ad26..152b354b5 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 981c834a2..3dff0a30c 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 c38ac2421..fb5c1a9cb 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 d772e208d..6ed42f2f4 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 38558bbc2..e9f8bdb2f 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 e6dd4b19e..93f9336cf 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 d71ad5c73..62e699fa7 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 717cdbcba..01436c6aa 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 1a3bc1757..581b18b40 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 3f0e7abf9..6ab060416 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 c2c1104c2..5002b324b 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 000000000..bdd82cc26 --- /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 bdd82cc26..5fae11bd6 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 5fae11bd6..6dc2e3fb9 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 6dc2e3fb9..f78041a20 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 f78041a20..bcfc29591 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 5002b324b..c2c1104c2 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 bcfc29591..000000000 --- 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 000000000..642dbcc7e --- /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 000000000..a2bb2da01 --- /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 000000000..09aa2d6a1 --- /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 000000000..b182c5b38 --- /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 000000000..bf7227a80 --- /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 000000000..26b72c481 --- /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 642dbcc7e..ff87a1708 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 09aa2d6a1..ce8316def 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 b182c5b38..000000000 --- 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 26b72c481..9d584b3b2 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 abdc6e81f..a22229e4f 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 zcmV+f3;XnmP)&smzif!h(Tb2cj(}Sz=M(p+xN9*gTN3N0^_0EFRBLz4$+d_jXeFnM6|z&)n3$KqW-5#P|_^Uw_hCJ2TO0TNe6Fa(Cctq5$t&vHi7V>zP<(GD%z{rEv(#5}Z^$wJ_%hn|rjFa(Cc zc*=PBQSa4$)bb!O1cty67y|bqGz5mgasmfDDV{6@SqQQay`~TD%ZGU&Fa(CckPs5~ zTF8ed@Yg4le*W|LKG8zH07;Pc^Yi2$kL3p)7I=4SuN8iwvk+&4xk~xrB(AIS_u=9l zELTBs7DT@S*Vyhz?e&5~NCM{u(<-W5`M;3w7&J%XNJM3wfg-inO5Ee`!x320*%ksz z%0CnE_Gi}M*^{S4ygz0K0g)rM*IT@y&PLM=rbR@W`_v|J3voqiua|8I_dc+;lS>J# z@zg1CmEM0(psVuFf-}`WsbG%O-WuW!L*Ue4dalZ~*#?csw9})uT^ccNVu{pVZU0EG z58;82gR>``b`UhHd-ohx9t{`qdQcS+Ip5aH`Rk z!Oo?uya_B7jr2N;xGeoP$;HQZaa6XPMqxw70cbry=nB>U@-M zkx9kXLNqPJ)uO!?a(am$0t;T)k&40lx)#A?u_<06w3LGf7LZ&@Oz-O~;*tiFB}gE! zqj++iDHWGRG*XhZ5Lcx3O8cecy4w+WIT`J3-JAG&E%WJhw1 zLms&PZf!iUqX(7}1Oof*V7VQEOI}vDOvm0HQ!0Mxb>8)p2C>(55EuggvQHNA=hhiZaPI@p@+3|=Ew&JsMTD06)fDSAPvWH6gA#JJ@PsYI zWf7sJe$pWJx^8F>{K{krJnY(8rGrxA{n%1*@jmeH?8R+7aEXX(h<788R>T_dmU``) z?e!w=v78VDz8aj=?%?Fk;fse1UiZ1$$)OSDl~}ZGF4+^OzK7wVO>Ivcg1}ybDcSmN z6>(}ClGdhJ+bvlO)NF5UaZ1X+6@jm8goa33;%To})kQ$Y7C}%g1`_M0((sdl;gKotQQem-xmTyUNuPIRG%an0nMNz6W;55=0S=S3SJSnPKLfp1>vFmZ(J%t9_81 z^J_hVbu>{=OW@pKw>}5gB3{Y4zLs;1M-%P7zEcu7C*F0iYmw@G>Cxwj?J1r1OT_!* zd(eW<5Y(D+T9i8#fi;8OlE9_nt^G}pk;yyVxeyxh)+F$mC`#>v=DTgF_O}dHdr&M> z*!uNKVRmR50;dMsLO|;@SSsH2zS??6TCiICP5S$3Jn(Vw_8!+FA}I;3uG5NeE64M9 zt!Esm_&lzglEB9WTB#U%iFefdTI-$s{c{P!^+c${0(mL|UwOS=1issSJ&39ef@uhx z>bxEV?j_z5@2nL~r0b_4aH>;#h^a@=l#7=g8KGavYb~bM_e(AOW?sOp?S{a@e4}RC zj6(d`#kgU}pliv=4U|F9b%sq1P@F+XjIhMcl$Z zNZ$FF-8Sq~rg&f{4;(?fwO$dGkg&%?46+bT;w{g=%FlJkk@t?`oy!AXJS*=dF0W}k zw@|x7sw_1F;DH@Ha83I#&wIZ56q&@9Ozwe~N2H%m^?S8q&$pZy^!c&+ke~l}P3MR= zFZyZ(zSxCoEPDv zi&Ij+Y6O-#gRr;@aKJy0>k+deewhedKojeVJC98Ff0CLlGP4VUktZBz~ZLU3@ zFlh-d2z;T29D!@vhb!AtBHaH1p7eYO2z({r@5em9ws_YTF9gnKA8vmx#DCpxPvaD+ zu-f(k0?VIJPD9{U9NCFa(Cc5Ev2;O~PIfBMZ@KCqXY_&30crFytSa{16xd5B+2n0z=?C5_sGby=U`) zcW(~_hQN0uFnQ0rlP^m9rzP;Vb7I!rxT(DB_TF-CV`>x;TI!L`LL?5%v)r^r()(-> zHQyfI+LsbTDoEDf9fRk1|NY-fj*-&T|1Kh)lE7DkClSd$xc1kdkvu2v+~;mzCrkd@ z{hT`2Vk@V#{xg$!$~^ED8PEPaC&JXZ3Q__~?kgc?s+@f=Y(aPj8&!wE%c+fT>$aH= z4+(OjdJXj9kdL$Je%so<5;8~hGs3O)IFd6(LW$V4^^gQb3p-a+2h$N)Lew*Fdi8JYdCc_q_kYGHS^;M$8YCGz8-?FoE!(vHR> z?+-i45q~dE3E4*$^DPN{cAC_cIFHw!iSBBFmrCIsgULeRz1=yAQBrP8VtNP5?FoD~ zc+%B=&aUKE|9kH(A*I#>@5w)FKKzyh&JAYDYf1=w{C%%1M9y}MOx}&;wl z;Mr4IiQ|GulE1z3!1g@w_sN9XJoOCX{g*=jmnG`B@bd1=lGS?Ylea6oA@S5TpTyn4 zKCHT#j=*=AHl+)ptC>Xl`w_02&I3zG>P`HJ<;|XbnAQVJ^1&mJ#S#>E5%07f*fRLD zi+i^AP3eJW8zkCueJ=5|9+*LocNleznGpg{z9;T1&plIcL*R+>-!%vqUF;BeastmT zY6uL0IhiN=G(-L7UC=>b2n>NC+`NQ~?x7(t1cty67y|bqH3Wvh5EugAkibEX9s3LI WvrQR426@<`#|W4NsZAJB-lMa&a4&37})wGgiP+Y+wHOZce~xUf8qb4arj!s z?fYW+xx7KdB&sPYoFmm+pF$qkW{B3Y*v8V6gfvEk*7X+pliz7kY zj9`*5EH8mGifUA2>DVt2xZ~h^#)fWW4>n!|0{^T?Ks@BhgNb)FQV{rLQn*@4m$V?RM)id$@u&&(*E2*d_~6S_@^{gr5z@2oyIj z7AYaT%THiJCwmVv+V`tk1A!3(>pW2B@dJTD@YFFh2y9A_yfp=~FsEOk*IwHJ0#8HW zeqxgu2dxGN1U4lwZO}be<(^_uJ$ETvqa6Ri2#j~+R3cM~sfY1^zzHX}^8Y5VQ>-%6p!S-~8QZ;#foD2ni#z#W%gBAhb9LVYK@6Ntgs8E2Gn&D& z5Po~^TtegeHfxbk1cqB~GwCB47YIDfPTZKr5sJVgks*85<q zT!6qs5ZIr*QNx#11dck0Vlw}{8ZQ2RC*wQM*Y_!99g@J0?H5+w|L&XmW5kN(=aZ4t z`hGEE>GQB96@hD{dj4M6_1}HHNhfmc?VdfS@#R=_kR++U)l}zSQ+!FFhC*_Km)aS_5U+Fk;zL$!?XJV$f(JLBr z$X7F_+UKkI_Whsp7`;y5O#Q8mhsEcqV_=Ruz9Lr(5!c8`A#kStT8NWE;x+`n+;*04 zLvmN&B@t1?LmAA{q}9Z`(wJgIS^E1n4$i5Hh~N7OCx@c zh)V6WYTr8VY${G-%CI)xbpi)H0bL^kDv_wyak3*TX*Ktih^TdY|5GhSBE1sv*aR+w zEmZMSuR9afm1s2gtr6+-^XB5Eiq@!}yiQ=_*i}LhD&cAiq33!%|yXHq4kq=@s^eb*l=SxdYGB3(s5T`0E8K9p0V z)`#U(2^_hEks_9(D7c#$R`>t(4BY$HNJUN6QS;5U_L_W7TzfSku-ADH9P(6)dyaWn zQSyBWO>QTl$w_`!LiQ`sP{+YDRo6t+CmyOwV5wVc^*!q3RRzqb2Ghpm?FqcEtY|xa zy~HSKw+Vqg#msS^mqk5_I$@*a~(HbS^_C=D0VWg%)7$rW(~@oH)zvi7$& zkDAZZ5}2BG(5(6;q@+xS^uC;YZ)BuG z^GCWaHGxa+m_ptCnyXk)O3D{e&a(xY`)X5mwAh!I<ws?t}Z!)BAHZ5 z*5P$u+gbt*fu%-E=`Tr40Tyn@=S)xFV`nJtl}4avEr5oU-0CsTb6vgb_N!1|QRBgZ zNH6h+BXH#U<6e`5cFUV%LlHOwF(5|Uomz7OyA-cG?xjQYmD0&zG4JPm%|+lqb*vz< z4T;SO45H;D8nx~^qS4Jo;Nb2M#?Lo?Ie~k+W5mSbSMWzO5)e4ZW=ur)oI&hz0(-jS z05ujFCXXw6k5fW>j}r(C0;di~ViNdLRKW^OJUtP{p=w+p@R>-6#~Sr^pJ;#AH{58| z(jgXpii;bgORfijVZ5o0H(?AMlLR1ipLqd+e+Vo~F_q83UEQHeVG}&Yo5uiwyJZpj z5Nk9~VL;%VC%Q-$45Ll{2>nqK7~&m41euN5fWS6&otXy_BJLLsDG3bmLcIONoBC`t z5Ia9SEV49B2rNrc^|fq})qeav-uyre93roJolk}_m5s@jz#bNd$+Rb9=5P!I4ng3F zMX7vw!Ii+7EqfHwkABh-2;7*!+JpUQP?#sC27w#bLUbV*Kw zRXkm@dLUmXI z*ABf_6PS6piblMYbB|{`7kD?CI)M|u;8+vyI@zsBB@G`W;ysGFbw9OX7WexB2`n$s zMsLRJ`kCQjGEP7m3!JG+wAm+LLa2)d`%S^QE5yi1JfY((r-vyLMN`D>K#{ zskndymQ`6@O}2)B+69VKyprGOh_qnUjvMv+_5^l1wX&A|_?*1|vELHIKmM-%{{632 zY$!Dz%kQl}S98CwCmPA%5czvU68I?2HMaWRX5d4>Zn5DjZz>g`B!)bStVO%_`DU4M z*%P=^%)CxoDb~}tajKZkJVc9j&z`SWyPu?fF3fym>0tp!t>9c*Vh%AYA?C-wG zAzR4#Y(7w-uw7TFRvU)ETW1TK3tTZ-#C$!BMzZi@i78+VO(yU)A>tf)diI>H#nigJ zU4*7t2xXnF1q3L@H5P#jgy0iczL`?meDKbCn2I+bX-i@z6S$Q{d9<@m?y=xy+e&uI zLhy}6w))=3skT$+(NBxFiLK@t1UAl^vpIJxpuk@Z5xHnLV)b$RM!7o%IlJj~7y{#O86IVF*mg zk6yhaCwXI|SM1B_$9nCWS^TrrP68i755x#vi5uP?-`tqDvEALLbSt@{&6lpHaqA#m;7fR+TNiI?cE86}`xFY>n0 z;Z%Lc5u1mR*b`W}s+V@MC9%B2htiuBDgkq1U`7loov*9!ajNGQ0xy@}moUHcLuYBf zg?K$gk!5_j&&eimq+(`nXDzO85k6Qv=PX80h=Ds)ktOf|5N~~FthMp63A`NfvYt4X z;=s7pgNgQZ3s=ebrO84_IyZ|Oow=U^0+-xKo7aOzoGi|&yJ!C+J|_sAAolJl+UTCo zkihW*{OE&^=hMf`ISA}@WGjtqF@L28;(v-?NMQLMKTR}x%S1bKc*Gn8?zBA(BXBSR z<1^QU1RkG|wG-ia;&u!}x`tQ%b>L3mh^ZHz`1()M6wfOxqAwCSWzBE{?_-n7~O2 zhEDR}Q^w+*_5*APjF^oavxOq$0P_}@zz7E*_WA-D1V$F3<4&ADOk@yP-x!EeCkhs@ zJkL83f$`S#?J*vN7zE~721tVOYT> z-az0GLNhrr+KH7v|2(e)1P&I{#Sm?tFh)S&Je`9W#t%>864){IlHaWZB0HR75jc82 z6X8a)4z|m^bh{~v_rDU z+goINd?s&wz+angztbPY8(FM?OHH3Yo&$LylA#c58S&Tz{z^`M2dS>X{+S5yf%J<` zXPoo{0z-VX_#)4d*aVK;35alR5jOY_1a2@M<_-bo4j^yx| z`8%e0y$Sr4jQlBjGuAKBYC-C4>n3L$HD^<4GVHkl`xmdg$48#4{5&Gr?9&7ym;$LvY8Ajli zVFS4~a_y&nKwt#J+`#|>r!=C&MkGAB;gha`z##D21O_>L$kBfSw`MHh0YW5_yq2-$gmcPD_asZgcGJG-8a31z#wpU(HRCsd;%MGb}iCs zx0cE`jfb`y2n+&)z)>b1cWg(m6)$2W99EhGfkEJY1l~?E+BVf|)1TMxAqO@zX6RgT zKtJ8~bR0{3V+kya$YI0O0OwB?3BFbL>-VYaeMRwqko9QSc7pvj(pXGfR~X4e^ikVYvPVOEwW3nlS=&w#fh(fSrW=CKOLJ(I zkqkuN)v2S~s}+@^-CDbf2uz7g)QFD8F%|o4?QUqV$e#+)p8TS1rxk(s#&A2${hX=z zT8+Flny8*k)m~~3gH}`uJ8SJ~O5h*oaXZcZoWdBcBATt;4eiy6N@ag-JMT;2%VE#V zr*OMERTRAWY^` z+52{@r^wIsy<>5oC!(M4Yum*U$8iyavSa0bl&G@TGmBr;+(|TYU)yU%VCyP`)Oge) z3(JU^9JlGdM`v!ia}w?KkJ~QQu-uxnQ{oq_)KWo9`McDA5rHXZiku@g&XrhFVAYNYewx=P5f@$xex10g)1kwe55zaCO*_8iz~Z!{vyUCGsMYC zD;j=>5>+YaPr*ppb?>LPovs9~EGtWmL+w`MMt1gdS|exD5|&dB;{5qMIb3qLNWN}O zrR>Zm@Yc>WJFhN2l+rYYeYNc*34Ba(Si>Bnv8-7q6_M2St4NNS&1JY28ISs1#<0q= zV{ZayHqTRbp{|Qo+9>(mBNs1={7$T-R-+JB4cvQQx!CA`9U+k$TZHc6;_Ljs! ziHf>z43XS!L6X2n+l$CSbeIEiFx?n2a)Nc`i8S4buk7UUrbuv{4Zrwc380Pbxqf1LHyKyJTlvugx0IN~;MXBtF z#JI0Y52b#K2+U~Q^&{M2lp>z=x+n+Ujq{Nb_w%E8WRF?Spzh)*-s&(;wX0IcuUA{j z>&tmPq|c|9B5Dc-{sh*peYX-?P{L_)GPi#fvAE>EjGT6B5@#y|7ecIf;M$8D)LsNW zb~<;eB$dOqURM$LFacvZqm&zROKDsuDbfaRUAWp$s(qZaYoB%yr9#Tzirr|hSZ6tv z>U2pY(j1o}w1U7_Bb|)8w@>i9r6B4;TuSss@ukI-?`>Z*ePU8cbXmJm_tV<7O5nqf zc0H4fdRB`v2CloEpwl$6Irs%-dTaAkEcOdNL znZevyZQ5Z!`Ohk-L12SmuyRHVBsj-nwcJ0K6LSgdntrZGV7yC%o`9K%xq-kYzrRm4 zt!_5meejM9R<(g!k{eQ8S&_h;63}$PW^`UK-S7O-0QC2Kp6R207dfy&4on#t*B!+T z0y`R46&#G&zv{l6e%e0~;vKvou$veRCQ{7fuDnIUzW<0h1qjR`lYtn!<*=pxj3m3C z{W1ie^X)Y#o%xA`P2dqh3IgASz-#uikOR+EN(oJf$T{{1Vp`h+1lEvgzS;V!L0+#y z%r*;dAj*in1gnawYrm!?@Q9L)_3+ntzomjs2}{(08%2a=>%rBJX$jnrEN z5ZKU|U2{LQ`*%~nguqMXTp)PUR>~;B3Ic;<9Uf0Qmnu!4V380QxuZOHbbXu#!S`!{ zD8m8T@gx;Wg#7eIN?=p`zYt{3jYJrken%$t94Yg911`)!U<||Eb6~DGS)Y>jiu# z%<__8$l&lGaJX5yKr}}unU5sOc5v)D8`-Vu<4Y4b>(rNbAY9&Y;h3|!ip()MLXvm) z(~<<{oE&};viGq_y~TT%+Yq@1St_y(x5YuN?StrkU3S&OuBRVX5m=h*1Ht`{ux2;w>#M5bu!A zSATwI+bnT91WixTt4F$f5tvxHV!VBxawSyh`T8sj_?7!be;K?R@ zRQ=Rs<;t3b)cy7cBB{?Q#L*&R&K6LU``?AYON#d(%18w6Cf-|AAsD;UOvtOueT&YP z5>@*7RfxPafhqA46DtWxtO-bs7?llm`9--N%gPPsJ8091wj4O}vvD28>#}T2wO_1Y zr+v<&Nxm9^S>!S#uZws~>4;RchtI3iq~J#=tViGhPbgTY52c`J&~G|N_wm>sq?DvZ zykULtabQakcop$RBCw0-?H=i0ioo2WKaVU-BS)G2M`=gzoVY|_tLOGj#Zoa&HTSj7 zdG~e%5{*k5(_4&+-&=>k17_`^L=z~OdO<6{A2{VaF&`_cPe54J2f-|enzeh2SGw8V zyFFb+DIoDWZ|dw#;Aq5))*gWfb;0r68oNprqAP&|iUkCAj~M2xUfYh21ip%8J6j~J z)Q&yWI$%)g$STyyDg-t)R^`#}yOPe-zFJ6Sz8AI%!QK?zdjrW`NoOcJ(_jFB1I1e?8GZUhd#i^+5tizb5JX_dDB48l@=suEaQ zOs9Sf*9GZ{Rup&po*RMLyO_oezca2l0s?0UER+Ke-j{ke@VF{V~X_3gTQd2eY!B)NlCrL4+1YRk?AFt zkiP>0Bkh@a#GIeNqgH@GZkrXnRy%^gATS8bethUCmhB0Oe<}X9|3XAFi)g6-K;XW? zgKC12y`PIK^XI^=ITXG>Lma_ns3}2Ld0@X8`Fuowo!*TcHF38_kMQ3QSV8-vdGgsRMxzvo+|C^AL4?tMUHJOU3GhN3uoY&#}BTMh)ChrlCp%&|d5r=#rzMiCx4t0ZT& z9$`UX5O`*?w-eYpqHsSY(I?GeTm20JPe$P3%kZ)61p>Dc0N+=R81w{ 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 ff87a1708..ceddbf533 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