From 007abce71f427d1518375ed8716efb8c4e503ad4 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Mon, 1 Feb 2021 01:37:42 +0000 Subject: [PATCH 01/32] First version of word clock --- apps/wordyclock/wordyclock.js | 92 +++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 apps/wordyclock/wordyclock.js diff --git a/apps/wordyclock/wordyclock.js b/apps/wordyclock/wordyclock.js new file mode 100644 index 000000000..856c5eab2 --- /dev/null +++ b/apps/wordyclock/wordyclock.js @@ -0,0 +1,92 @@ +// The interval reference for updating the clock +let intervalRef = null; + +// String numbers +const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", + "SIX", "SEVEN","EIGHT", "NINE", "TEN", + "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", + "FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", + "NINETEEN", "TWENTY"]; +const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", + "FIFTY"]; + +function draw_clock(){ + console.log("draw_clock"); + let date = new Date(); + // First display the hours as a text number + let hours = date.getHours(); + if(hours == 0 ){ + hours = 12; + } else if(hours > 12){ + hours = hours - 12; + } + g.clear(); + g.setFont("Vector",40); + g.drawString(numberStr[hours], 20, 50); + // Now display the minutes on 2 lines + let mins = date.getMinutes(); + g.setFont("Vector",20); + if(mins > 20){ + let tens = (mins / 10 | 0); + g.drawString(tensStr[tens], 20, 100); + let remainder = mins - tens * 10; + g.drawString(numberStr[remainder], 20, 125); + + } else if(mins > 0) { + g.drawString(numberStr[mins], 20, 100); + } + console.log(date); +} + +function clearTimers(){ + //console.log("clearTimers"); + if(intervalRef) { + clearInterval(intervalRef); + intervalRef = null; + //console.log("interval is cleared"); + } +} + +function startTimers(){ + console.log("startTimers"); + let date = new Date(); + let secs = date.getSeconds(); + let nextMinuteStart = 60 - secs; + console.log("scheduling clock draw in " + nextMinuteStart + " seconds"); + setTimeout(scheduleDrawClock,nextMinuteStart * 1000); + draw_clock(); +} + +function scheduleDrawClock(){ + console.log("scheduleDrawClock"); + if(intervalRef) clearTimers(); + intervalRef = setInterval(draw_clock, 60*1000); + console.log("scheduleDrawClock is set"); + draw_clock(); +} + +Bangle.on('lcdPower', (on) => { + if (on) { + console.log("lcdPower: on"); + Bangle.drawWidgets(); + startTimers(); + } else { + console.log("lcdPower: off"); + clearTimers(); + } +}); +Bangle.on('faceUp',function(up){ + console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); + if (up && !Bangle.isLCDOn()) { + //console.log("faceUp and LCD off"); + clearTimers(); + Bangle.setLCDPower(true); + } +}); + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +startTimers(); +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2,{repeat:false,edge:"falling"}); From 14e19413a98ae358376d18fe632fad6a7d5093d0 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Mon, 1 Feb 2021 01:44:45 +0000 Subject: [PATCH 02/32] Added wordy clock files for app store --- apps/wordyclock/wordyclock-icon.js | 1 + apps/wordyclock/wordyclock.png | Bin 0 -> 843 bytes 2 files changed, 1 insertion(+) create mode 100644 apps/wordyclock/wordyclock-icon.js create mode 100644 apps/wordyclock/wordyclock.png diff --git a/apps/wordyclock/wordyclock-icon.js b/apps/wordyclock/wordyclock-icon.js new file mode 100644 index 000000000..920b490b8 --- /dev/null +++ b/apps/wordyclock/wordyclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIIFiOAgEgoN4n+AsEw4f8mEAoEwwIaBAok/AoMZwP4AocBwARCjYuBAoUPAodgh0D/kQBYMGgP8IIseF4f8FINgnIFBmOAoEfBAM4AQMPAQIIBoEOAoMHCIILCkIFBjYFBDoUZNAJrCmPAsA4CkCMHn+Y8U/4MAl2M80/O4MEhnmTQQFB8gFDhu0CIcF3gLDg8cAokYAoOAAoQvB/A9H4BBDwPwX4P4nEDnAFBEAMGFIPDhk4g0MAoN8n4FD/ARBAoODuAFBjExwYdBEYMZwYOBgPwh8DhhBHACo")) diff --git a/apps/wordyclock/wordyclock.png b/apps/wordyclock/wordyclock.png new file mode 100644 index 0000000000000000000000000000000000000000..f8cbdbf046f4fd8b6f1717736221719e18289079 GIT binary patch literal 843 zcmV-R1GM~!P)aG&CtGDLy_vARr((I5=TpVM9YhSXfwoetvIn zZ!Ik?FE1~3b#-TFXRxraQc_Y+PfvMyc}hx3ii(Pzot=`Bl7xhWQ}IOn0007}Nklfg7)YND{jSK$MFpzyPQya55IrWZ*1H0PysD2tAPvD$w#f17D)Z z{6zwr;aN<8B^-bi0F6d*79&>ysRnX3F~TVWw{g4#1v-O=ka%IFJS3#94rzGH;gQwE z=c2%*o9Zdm9-z)nH@?=#I!P`nR-)G00jgF525kz3z@qS<4zS*HlN07qj>7X%Cn?gY z@_?d_C5MuMwE&UyX9Yx>D`pmE)#6)yw1nzmYFxj2_!ULBH3z`>V{4SHLIsrkIqf6R z&@>)^I~BUs#yYmfZ~zu6XW;D0_n=2f^Y#!Dh~S=)RBdIaCDsxhw&U0A_R(EqYhfXN z98t&Tz0xFT(RfclgJfq(^G&m@h+}z`QzifOk5_W-s3COz`q`59Mc>~H-drThP2+|j zW6)!2;9@F?azs4<_i>U0i7X9ztAPNmwyk|o=UT1>z&-SRkFqq?Ku-XhB!JCN%W;56 zlYyfLGj6H;vY}_7YhsM*VKjIE_^V&dovZkn!}D(*8g5Sql%eF{ob#Gq-14ysIK4NJ zf+1{SK&2F`Tu!+$Vi#$3MK((9Fsv!cxwz!g;>BupVH?^U)f6ObN2cgJKV1l+7dE?I z4d(l2qHc8@%)n2pHZ}vx(5_ZObv^JsuRxc9Q%d=2dAk{$?11LegM4bJ9@5Z~10<(t zdiEXPf$oP-OaYCeg%?HdbK&qahhBj>I<83~8#K54L&$qf0&HadCS-S2S3cR% Date: Mon, 1 Feb 2021 01:58:08 +0000 Subject: [PATCH 03/32] typo in config --- apps.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps.json b/apps.json index 09462a8ba..833c9b165 100644 --- a/apps.json +++ b/apps.json @@ -213,6 +213,19 @@ {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} ] }, + { "id": "wordyclock", + "name": "Wordy Clock", + "icon": "wordyclock.png", + "version":"0.01", + "description": "Text Readable Time", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"wordyclock.app.js","url":"wordyclock.js"}, + {"name":"wordyclock.img","url":"wordyclock-icon.js","evaluate":true} + ] + }, { "id": "imgclock", "name": "Image background clock", "shortName":"Image Clock", From 8881b0604e29f29dac0a41512ed523009a2831f1 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Mon, 1 Feb 2021 02:16:56 +0000 Subject: [PATCH 04/32] renaming clock --- apps/xclock/xclock-icon.js | 1 + apps/xclock/xclock.js | 92 +++++++++++++++++++++++++++++++++++++ apps/xclock/xclock.png | Bin 0 -> 843 bytes 3 files changed, 93 insertions(+) create mode 100644 apps/xclock/xclock-icon.js create mode 100644 apps/xclock/xclock.js create mode 100644 apps/xclock/xclock.png diff --git a/apps/xclock/xclock-icon.js b/apps/xclock/xclock-icon.js new file mode 100644 index 000000000..920b490b8 --- /dev/null +++ b/apps/xclock/xclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIIFiOAgEgoN4n+AsEw4f8mEAoEwwIaBAok/AoMZwP4AocBwARCjYuBAoUPAodgh0D/kQBYMGgP8IIseF4f8FINgnIFBmOAoEfBAM4AQMPAQIIBoEOAoMHCIILCkIFBjYFBDoUZNAJrCmPAsA4CkCMHn+Y8U/4MAl2M80/O4MEhnmTQQFB8gFDhu0CIcF3gLDg8cAokYAoOAAoQvB/A9H4BBDwPwX4P4nEDnAFBEAMGFIPDhk4g0MAoN8n4FD/ARBAoODuAFBjExwYdBEYMZwYOBgPwh8DhhBHACo")) diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js new file mode 100644 index 000000000..856c5eab2 --- /dev/null +++ b/apps/xclock/xclock.js @@ -0,0 +1,92 @@ +// The interval reference for updating the clock +let intervalRef = null; + +// String numbers +const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", + "SIX", "SEVEN","EIGHT", "NINE", "TEN", + "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", + "FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", + "NINETEEN", "TWENTY"]; +const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", + "FIFTY"]; + +function draw_clock(){ + console.log("draw_clock"); + let date = new Date(); + // First display the hours as a text number + let hours = date.getHours(); + if(hours == 0 ){ + hours = 12; + } else if(hours > 12){ + hours = hours - 12; + } + g.clear(); + g.setFont("Vector",40); + g.drawString(numberStr[hours], 20, 50); + // Now display the minutes on 2 lines + let mins = date.getMinutes(); + g.setFont("Vector",20); + if(mins > 20){ + let tens = (mins / 10 | 0); + g.drawString(tensStr[tens], 20, 100); + let remainder = mins - tens * 10; + g.drawString(numberStr[remainder], 20, 125); + + } else if(mins > 0) { + g.drawString(numberStr[mins], 20, 100); + } + console.log(date); +} + +function clearTimers(){ + //console.log("clearTimers"); + if(intervalRef) { + clearInterval(intervalRef); + intervalRef = null; + //console.log("interval is cleared"); + } +} + +function startTimers(){ + console.log("startTimers"); + let date = new Date(); + let secs = date.getSeconds(); + let nextMinuteStart = 60 - secs; + console.log("scheduling clock draw in " + nextMinuteStart + " seconds"); + setTimeout(scheduleDrawClock,nextMinuteStart * 1000); + draw_clock(); +} + +function scheduleDrawClock(){ + console.log("scheduleDrawClock"); + if(intervalRef) clearTimers(); + intervalRef = setInterval(draw_clock, 60*1000); + console.log("scheduleDrawClock is set"); + draw_clock(); +} + +Bangle.on('lcdPower', (on) => { + if (on) { + console.log("lcdPower: on"); + Bangle.drawWidgets(); + startTimers(); + } else { + console.log("lcdPower: off"); + clearTimers(); + } +}); +Bangle.on('faceUp',function(up){ + console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); + if (up && !Bangle.isLCDOn()) { + //console.log("faceUp and LCD off"); + clearTimers(); + Bangle.setLCDPower(true); + } +}); + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +startTimers(); +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2,{repeat:false,edge:"falling"}); diff --git a/apps/xclock/xclock.png b/apps/xclock/xclock.png new file mode 100644 index 0000000000000000000000000000000000000000..f8cbdbf046f4fd8b6f1717736221719e18289079 GIT binary patch literal 843 zcmV-R1GM~!P)aG&CtGDLy_vARr((I5=TpVM9YhSXfwoetvIn zZ!Ik?FE1~3b#-TFXRxraQc_Y+PfvMyc}hx3ii(Pzot=`Bl7xhWQ}IOn0007}Nklfg7)YND{jSK$MFpzyPQya55IrWZ*1H0PysD2tAPvD$w#f17D)Z z{6zwr;aN<8B^-bi0F6d*79&>ysRnX3F~TVWw{g4#1v-O=ka%IFJS3#94rzGH;gQwE z=c2%*o9Zdm9-z)nH@?=#I!P`nR-)G00jgF525kz3z@qS<4zS*HlN07qj>7X%Cn?gY z@_?d_C5MuMwE&UyX9Yx>D`pmE)#6)yw1nzmYFxj2_!ULBH3z`>V{4SHLIsrkIqf6R z&@>)^I~BUs#yYmfZ~zu6XW;D0_n=2f^Y#!Dh~S=)RBdIaCDsxhw&U0A_R(EqYhfXN z98t&Tz0xFT(RfclgJfq(^G&m@h+}z`QzifOk5_W-s3COz`q`59Mc>~H-drThP2+|j zW6)!2;9@F?azs4<_i>U0i7X9ztAPNmwyk|o=UT1>z&-SRkFqq?Ku-XhB!JCN%W;56 zlYyfLGj6H;vY}_7YhsM*VKjIE_^V&dovZkn!}D(*8g5Sql%eF{ob#Gq-14ysIK4NJ zf+1{SK&2F`Tu!+$Vi#$3MK((9Fsv!cxwz!g;>BupVH?^U)f6ObN2cgJKV1l+7dE?I z4d(l2qHc8@%)n2pHZ}vx(5_ZObv^JsuRxc9Q%d=2dAk{$?11LegM4bJ9@5Z~10<(t zdiEXPf$oP-OaYCeg%?HdbK&qahhBj>I<83~8#K54L&$qf0&HadCS-S2S3cR% Date: Mon, 1 Feb 2021 02:17:53 +0000 Subject: [PATCH 05/32] renamed clock --- apps.json | 10 ++-- apps/wordyclock/wordyclock-icon.js | 1 - apps/wordyclock/wordyclock.js | 92 ----------------------------- apps/wordyclock/wordyclock.png | Bin 843 -> 0 bytes 4 files changed, 5 insertions(+), 98 deletions(-) delete mode 100644 apps/wordyclock/wordyclock-icon.js delete mode 100644 apps/wordyclock/wordyclock.js delete mode 100644 apps/wordyclock/wordyclock.png diff --git a/apps.json b/apps.json index 833c9b165..38d4bf57b 100644 --- a/apps.json +++ b/apps.json @@ -213,17 +213,17 @@ {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} ] }, - { "id": "wordyclock", - "name": "Wordy Clock", - "icon": "wordyclock.png", + { "id": "xclock", + "name": "X Clock", + "icon": "xclock.png", "version":"0.01", "description": "Text Readable Time", "tags": "clock", "type":"clock", "allow_emulator":true, "storage": [ - {"name":"wordyclock.app.js","url":"wordyclock.js"}, - {"name":"wordyclock.img","url":"wordyclock-icon.js","evaluate":true} + {"name":"xclock.app.js","url":"xclock.js"}, + {"name":"xclock.img","url":"xclock-icon.js","evaluate":true} ] }, { "id": "imgclock", diff --git a/apps/wordyclock/wordyclock-icon.js b/apps/wordyclock/wordyclock-icon.js deleted file mode 100644 index 920b490b8..000000000 --- a/apps/wordyclock/wordyclock-icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("mEwgIIFiOAgEgoN4n+AsEw4f8mEAoEwwIaBAok/AoMZwP4AocBwARCjYuBAoUPAodgh0D/kQBYMGgP8IIseF4f8FINgnIFBmOAoEfBAM4AQMPAQIIBoEOAoMHCIILCkIFBjYFBDoUZNAJrCmPAsA4CkCMHn+Y8U/4MAl2M80/O4MEhnmTQQFB8gFDhu0CIcF3gLDg8cAokYAoOAAoQvB/A9H4BBDwPwX4P4nEDnAFBEAMGFIPDhk4g0MAoN8n4FD/ARBAoODuAFBjExwYdBEYMZwYOBgPwh8DhhBHACo")) diff --git a/apps/wordyclock/wordyclock.js b/apps/wordyclock/wordyclock.js deleted file mode 100644 index 856c5eab2..000000000 --- a/apps/wordyclock/wordyclock.js +++ /dev/null @@ -1,92 +0,0 @@ -// The interval reference for updating the clock -let intervalRef = null; - -// String numbers -const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", - "SIX", "SEVEN","EIGHT", "NINE", "TEN", - "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", - "FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", - "NINETEEN", "TWENTY"]; -const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", - "FIFTY"]; - -function draw_clock(){ - console.log("draw_clock"); - let date = new Date(); - // First display the hours as a text number - let hours = date.getHours(); - if(hours == 0 ){ - hours = 12; - } else if(hours > 12){ - hours = hours - 12; - } - g.clear(); - g.setFont("Vector",40); - g.drawString(numberStr[hours], 20, 50); - // Now display the minutes on 2 lines - let mins = date.getMinutes(); - g.setFont("Vector",20); - if(mins > 20){ - let tens = (mins / 10 | 0); - g.drawString(tensStr[tens], 20, 100); - let remainder = mins - tens * 10; - g.drawString(numberStr[remainder], 20, 125); - - } else if(mins > 0) { - g.drawString(numberStr[mins], 20, 100); - } - console.log(date); -} - -function clearTimers(){ - //console.log("clearTimers"); - if(intervalRef) { - clearInterval(intervalRef); - intervalRef = null; - //console.log("interval is cleared"); - } -} - -function startTimers(){ - console.log("startTimers"); - let date = new Date(); - let secs = date.getSeconds(); - let nextMinuteStart = 60 - secs; - console.log("scheduling clock draw in " + nextMinuteStart + " seconds"); - setTimeout(scheduleDrawClock,nextMinuteStart * 1000); - draw_clock(); -} - -function scheduleDrawClock(){ - console.log("scheduleDrawClock"); - if(intervalRef) clearTimers(); - intervalRef = setInterval(draw_clock, 60*1000); - console.log("scheduleDrawClock is set"); - draw_clock(); -} - -Bangle.on('lcdPower', (on) => { - if (on) { - console.log("lcdPower: on"); - Bangle.drawWidgets(); - startTimers(); - } else { - console.log("lcdPower: off"); - clearTimers(); - } -}); -Bangle.on('faceUp',function(up){ - console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); - if (up && !Bangle.isLCDOn()) { - //console.log("faceUp and LCD off"); - clearTimers(); - Bangle.setLCDPower(true); - } -}); - -g.clear(); -Bangle.loadWidgets(); -Bangle.drawWidgets(); -startTimers(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2,{repeat:false,edge:"falling"}); diff --git a/apps/wordyclock/wordyclock.png b/apps/wordyclock/wordyclock.png deleted file mode 100644 index f8cbdbf046f4fd8b6f1717736221719e18289079..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 843 zcmV-R1GM~!P)aG&CtGDLy_vARr((I5=TpVM9YhSXfwoetvIn zZ!Ik?FE1~3b#-TFXRxraQc_Y+PfvMyc}hx3ii(Pzot=`Bl7xhWQ}IOn0007}Nklfg7)YND{jSK$MFpzyPQya55IrWZ*1H0PysD2tAPvD$w#f17D)Z z{6zwr;aN<8B^-bi0F6d*79&>ysRnX3F~TVWw{g4#1v-O=ka%IFJS3#94rzGH;gQwE z=c2%*o9Zdm9-z)nH@?=#I!P`nR-)G00jgF525kz3z@qS<4zS*HlN07qj>7X%Cn?gY z@_?d_C5MuMwE&UyX9Yx>D`pmE)#6)yw1nzmYFxj2_!ULBH3z`>V{4SHLIsrkIqf6R z&@>)^I~BUs#yYmfZ~zu6XW;D0_n=2f^Y#!Dh~S=)RBdIaCDsxhw&U0A_R(EqYhfXN z98t&Tz0xFT(RfclgJfq(^G&m@h+}z`QzifOk5_W-s3COz`q`59Mc>~H-drThP2+|j zW6)!2;9@F?azs4<_i>U0i7X9ztAPNmwyk|o=UT1>z&-SRkFqq?Ku-XhB!JCN%W;56 zlYyfLGj6H;vY}_7YhsM*VKjIE_^V&dovZkn!}D(*8g5Sql%eF{ob#Gq-14ysIK4NJ zf+1{SK&2F`Tu!+$Vi#$3MK((9Fsv!cxwz!g;>BupVH?^U)f6ObN2cgJKV1l+7dE?I z4d(l2qHc8@%)n2pHZ}vx(5_ZObv^JsuRxc9Q%d=2dAk{$?11LegM4bJ9@5Z~10<(t zdiEXPf$oP-OaYCeg%?HdbK&qahhBj>I<83~8#K54L&$qf0&HadCS-S2S3cR% Date: Mon, 1 Feb 2021 02:35:49 +0000 Subject: [PATCH 06/32] BUGFIX: thurty does not need trailing zero --- apps/xclock/xclock.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index 856c5eab2..70c58e976 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -30,7 +30,9 @@ function draw_clock(){ let tens = (mins / 10 | 0); g.drawString(tensStr[tens], 20, 100); let remainder = mins - tens * 10; - g.drawString(numberStr[remainder], 20, 125); + if(remainder > 0){ + g.drawString(numberStr[remainder], 20, 125); + } } else if(mins > 0) { g.drawString(numberStr[mins], 20, 100); From df39fcae20e36c7236e17e1ad9cd90801f1c1355 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 3 Feb 2021 00:30:34 +0000 Subject: [PATCH 07/32] clock now shifts between times --- apps.json | 2 +- apps/xclock/xclock.js | 171 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 157 insertions(+), 16 deletions(-) diff --git a/apps.json b/apps.json index 38d4bf57b..5d6487cbb 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.01", + "version":"0.02", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index 70c58e976..c84fa3e33 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -9,6 +9,102 @@ const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", "NINETEEN", "TWENTY"]; const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", "FIFTY"]; +/** +* This is a object that initializes itself with a position and +* text after which you can tell it where you want to move to +* using the moveTo method and it will smoothly move the text across +*/ +class ShiftText { + constructor(x,y,txt,font_name, + font_size,speed_x,speed_y,freq_millis){ + this.x = x; + this.tgt_x = x; + this.y = y; + this.tgt_y = y; + this.txt = txt; + this.font_name = font_name; + this.font_size = font_size; + this.speed_x = Math.abs(speed_x); + this.speed_y = Math.abs(speed_y); + this.freq_millis = freq_millis; + this.finished_callback=null; + } + show() { + g.setFont(this.font_name,this.font_size); + g.setColor(1,1,1); + g.drawString(this.txt, this.x, this.y); + } + hide(){ + g.setFont(this.font_name,this.font_size); + g.setColor(0,0,0); + g.drawString(this.txt, this.x, this.y); + } + setText(txt){ + this.txt = txt; + } + setTextPosition(txt,x,y){ + this.hide(); + this.x = x; + this.y = y; + this.txt = txt; + this.show(); + } + moveTo(new_x,new_y){ + this.tgt_x = new_x; + this.tgt_y = new_y; + this._doMove(); + } + onFinished(finished_callback){ + this.finished_callback = finished_callback; + } + /** + * private internal method for directing the text move. + * It will see how far away we are from the target coords + * and move towards the target at the defined speed. + */ + _doMove(){ + this.hide(); + // move closer to the target in the x direction + diff_x = this.tgt_x - this.x; + finished_x = false; + if(Math.abs(diff_x) <= this.speed_x){ + this.x = this.tgt_x; + finished_x = true; + } else { + if(diff_x > 0){ + this.x += this.speed_x; + } else { + this.x -= this.speed_x; + } + } + // move closer to the target in the y direction + diff_y = this.tgt_y - this.y; + finished_y = false; + if(Math.abs(diff_y) <= this.speed_y){ + this.y = this.tgt_y; + finished_y = true; + } else { + if(diff_y > 0){ + this.y += this.speed_y; + } else { + this.y -= this.speed_y; + } + } + this.show(); + finished = finished_x & finished_y; + if(!finished){ + setTimeout(this._doMove.bind(this), this.freq_millis); + } else if(this.finished_callback != null){ + this.finished_callback.call(); + this.finished_callback = null; + } + } +} + + +let hour_shift_txt = new ShiftText(240,50,'',"Vector",40,5,5,100); +let min_shift_txt = new ShiftText(240,100,'',"Vector",20,5,5,100); +let min_remainder_shift_txt = new ShiftText(240,120,'',"Vector",20,5,5,125); function draw_clock(){ console.log("draw_clock"); @@ -20,37 +116,83 @@ function draw_clock(){ } else if(hours > 12){ hours = hours - 12; } - g.clear(); - g.setFont("Vector",40); - g.drawString(numberStr[hours], 20, 50); - // Now display the minutes on 2 lines + // If the hour string has changed then we move out the old + // hours and move in the new hour string + // If its the first time through the text is empty + // so we just display without movement (otherewise the user + // will think its not working + new_hours = numberStr[hours]; + if(new_hours != hour_shift_txt.txt && hour_shift_txt.txt != ''){ + hour_shift_txt.moveTo(-100,50); + hour_shift_txt.onFinished( + function(){ + hour_shift_txt.setTextPosition(new_hours,240,50); + hour_shift_txt.moveTo(20,50); + hour_shift_txt.onFinished(function(){console.log("hour finished");}); + } + ); + } else { + hour_shift_txt.setTextPosition(new_hours,20,50); + } + // If the mins is over 20 we have to display the text on 2 lines + // Otherwise we just output our defined numbers from 1 to 20 let mins = date.getMinutes(); - g.setFont("Vector",20); + new_mins = ''; + new_mins_remainder = ''; if(mins > 20){ - let tens = (mins / 10 | 0); - g.drawString(tensStr[tens], 20, 100); + tens = (mins / 10 | 0); + new_mins = tensStr[tens]; let remainder = mins - tens * 10; if(remainder > 0){ - g.drawString(numberStr[remainder], 20, 125); + new_mins_remainder = numberStr[remainder]; } - } else if(mins > 0) { - g.drawString(numberStr[mins], 20, 100); + new_mins = numberStr[mins]; + } + // If its the first time through the the text is moved in from + // the right + // If the minute text has changed we move the old text + // off screen and the new text on. + if(min_shift_txt.txt == ''){ + min_shift_txt.setTextPosition(new_mins,240,100); + min_shift_txt.moveTo(20,100); + } else if(new_mins != min_shift_txt.txt){ + min_shift_txt.moveTo(-100,100); + min_shift_txt.onFinished( + function(){ + min_shift_txt.setTextPosition(new_mins,240,100); + min_shift_txt.moveTo(20,100); + } + ); + } else { + min_shift_txt.setTextPosition(new_mins,20,100); + } + // finally we deal with the remainder line in the same way. + if(min_remainder_shift_txt.txt == ''){ + min_remainder_shift_txt.setTextPosition(new_mins_remainder,240,125); + min_remainder_shift_txt.moveTo(20,125); + } else if(new_mins_remainder != min_remainder_shift_txt.txt){ + min_remainder_shift_txt.moveTo(-100,125); + min_remainder_shift_txt.onFinished( + function(){ + min_remainder_shift_txt.setTextPosition(new_mins_remainder,240,125); + min_remainder_shift_txt.moveTo(20,125); + } + ); + } else { + min_remainder_shift_txt.setTextPosition(new_mins_remainder,240,125); } console.log(date); } function clearTimers(){ - //console.log("clearTimers"); if(intervalRef) { clearInterval(intervalRef); intervalRef = null; - //console.log("interval is cleared"); } } function startTimers(){ - console.log("startTimers"); let date = new Date(); let secs = date.getSeconds(); let nextMinuteStart = 60 - secs; @@ -59,11 +201,10 @@ function startTimers(){ draw_clock(); } -function scheduleDrawClock(){ +function scheduleDrawClock(){ console.log("scheduleDrawClock"); if(intervalRef) clearTimers(); intervalRef = setInterval(draw_clock, 60*1000); - console.log("scheduleDrawClock is set"); draw_clock(); } From 3d7ddfca15adf4a294a9d016ad0f6776d115a646 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Thu, 4 Feb 2021 00:29:35 +0000 Subject: [PATCH 08/32] - Bug fix to onTap behviour - Generaization so that more languages can be added --- apps.json | 2 +- apps/xclock/xclock.js | 184 ++++++++++++++++++++++++------------------ 2 files changed, 107 insertions(+), 79 deletions(-) diff --git a/apps.json b/apps.json index 5d6487cbb..db72e1f03 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.02", + "version":"0.03", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index c84fa3e33..aa494ff7d 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -16,22 +16,37 @@ const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", */ class ShiftText { constructor(x,y,txt,font_name, - font_size,speed_x,speed_y,freq_millis){ + font_size,speed_x,speed_y,freq_millis, color){ this.x = x; this.tgt_x = x; + this.init_x = x; this.y = y; this.tgt_y = y; + this.init_y = y; this.txt = txt; + this.init_txt = txt; this.font_name = font_name; this.font_size = font_size; this.speed_x = Math.abs(speed_x); this.speed_y = Math.abs(speed_y); this.freq_millis = freq_millis; + this.colour = color; this.finished_callback=null; + this.timeoutId = null; + } + reset(){ + this.hide(); + this.x = this.init_x; + this.y = this.init_y; + this.txt = this.init_txt; + this.show(); + if(this.timeoutId != null){ + clearTimeout(this.timeoutId); + } } show() { g.setFont(this.font_name,this.font_size); - g.setColor(1,1,1); + g.setColor(this.colour[0],this.colour[1],this.colour[2]); g.drawString(this.txt, this.x, this.y); } hide(){ @@ -49,11 +64,25 @@ class ShiftText { this.txt = txt; this.show(); } + setTextXPosition(txt,x){ + this.hide(); + this.x = x; + this.txt = txt; + this.show(); + } moveTo(new_x,new_y){ this.tgt_x = new_x; this.tgt_y = new_y; this._doMove(); } + moveToX(new_x){ + this.tgt_x = new_x; + this._doMove(); + } + moveToY(new_y){ + this.tgt_y = new_y; + this._doMove(); + } onFinished(finished_callback){ this.finished_callback = finished_callback; } @@ -91,9 +120,10 @@ class ShiftText { } } this.show(); + this.timeoutId = null; finished = finished_x & finished_y; if(!finished){ - setTimeout(this._doMove.bind(this), this.freq_millis); + this.timeoutId = setTimeout(this._doMove.bind(this), this.freq_millis); } else if(this.finished_callback != null){ this.finished_callback.call(); this.finished_callback = null; @@ -102,89 +132,85 @@ class ShiftText { } -let hour_shift_txt = new ShiftText(240,50,'',"Vector",40,5,5,100); -let min_shift_txt = new ShiftText(240,100,'',"Vector",20,5,5,100); -let min_remainder_shift_txt = new ShiftText(240,120,'',"Vector",20,5,5,125); +class DateFormatter { + formatDate(date){ + return ["","",""]; + } +} + +class EnglishDateFormatter extends DateFormatter{ + formatDate(date){ + // First display the hours as a text number + let hours = date.getHours(); + if(hours == 0){ + hours = 12; + } else if(hours > 12){ + hours = hours - 12; + } + new_hours = numberStr[hours]; + // If the mins is over 20 we have to display the text on 2 lines + // Otherwise we just output our defined numbers from 1 to 20 + let mins = date.getMinutes(); + new_mins = ''; + new_mins_remainder = ''; + if(mins > 20){ + tens = (mins / 10 | 0); + new_mins = tensStr[tens]; + let remainder = mins - tens * 10; + if(remainder > 0){ + new_mins_remainder = numberStr[remainder]; + } + } else if(mins > 0) { + new_mins = numberStr[mins]; + } + return [new_hours,new_mins,new_mins_remainder]; + } +} + +let row_displays = [ new ShiftText(240,50,'',"Vector",40,10,10,50,[1,1,1]), + new ShiftText(240,100,'',"Vector",20,10,10,50,[0.85,0.85,0.85]), + new ShiftText(240,120,'',"Vector",20,10,10,50,[0.85,0.85,0.85]) +]; + +let date_formatter = new EnglishDateFormatter(); + +function reset_clock(){ + console.log("reset_clock"); + this.hour_shift_txt.reset(); + this.min_shift_txt.reset(); + this.min_remainder_shift_txt.reset(); +} function draw_clock(){ console.log("draw_clock"); let date = new Date(); - // First display the hours as a text number - let hours = date.getHours(); - if(hours == 0 ){ - hours = 12; - } else if(hours > 12){ - hours = hours - 12; - } - // If the hour string has changed then we move out the old - // hours and move in the new hour string - // If its the first time through the text is empty - // so we just display without movement (otherewise the user - // will think its not working - new_hours = numberStr[hours]; - if(new_hours != hour_shift_txt.txt && hour_shift_txt.txt != ''){ - hour_shift_txt.moveTo(-100,50); - hour_shift_txt.onFinished( - function(){ - hour_shift_txt.setTextPosition(new_hours,240,50); - hour_shift_txt.moveTo(20,50); - hour_shift_txt.onFinished(function(){console.log("hour finished");}); - } - ); - } else { - hour_shift_txt.setTextPosition(new_hours,20,50); - } - // If the mins is over 20 we have to display the text on 2 lines - // Otherwise we just output our defined numbers from 1 to 20 - let mins = date.getMinutes(); - new_mins = ''; - new_mins_remainder = ''; - if(mins > 20){ - tens = (mins / 10 | 0); - new_mins = tensStr[tens]; - let remainder = mins - tens * 10; - if(remainder > 0){ - new_mins_remainder = numberStr[remainder]; - } - } else if(mins > 0) { - new_mins = numberStr[mins]; - } - // If its the first time through the the text is moved in from - // the right - // If the minute text has changed we move the old text - // off screen and the new text on. - if(min_shift_txt.txt == ''){ - min_shift_txt.setTextPosition(new_mins,240,100); - min_shift_txt.moveTo(20,100); - } else if(new_mins != min_shift_txt.txt){ - min_shift_txt.moveTo(-100,100); - min_shift_txt.onFinished( - function(){ - min_shift_txt.setTextPosition(new_mins,240,100); - min_shift_txt.moveTo(20,100); - } - ); - } else { - min_shift_txt.setTextPosition(new_mins,20,100); - } - // finally we deal with the remainder line in the same way. - if(min_remainder_shift_txt.txt == ''){ - min_remainder_shift_txt.setTextPosition(new_mins_remainder,240,125); - min_remainder_shift_txt.moveTo(20,125); - } else if(new_mins_remainder != min_remainder_shift_txt.txt){ - min_remainder_shift_txt.moveTo(-100,125); - min_remainder_shift_txt.onFinished( - function(){ - min_remainder_shift_txt.setTextPosition(new_mins_remainder,240,125); - min_remainder_shift_txt.moveTo(20,125); - } - ); - } else { - min_remainder_shift_txt.setTextPosition(new_mins_remainder,240,125); + rows = date_formatter.formatDate(date); + var i; + for (i = 0; i < rows.length; i++) { + display = row_displays[i]; + txt = rows[i]; + display_row(display,txt); } console.log(date); } +function display_row(display,txt){ + if(display.txt == ''){ + display.setTextXPosition(txt,240); + display.moveToX(20); + } else if(txt != display.txt){ + display.moveToX(-100); + display.onFinished( + function(){ + display.setTextXPosition(txt,240); + display.moveToX(20); + } + ); + } else { + display.setTextXPosition(txt,20); + } +} + function clearTimers(){ if(intervalRef) { clearInterval(intervalRef); @@ -212,9 +238,11 @@ Bangle.on('lcdPower', (on) => { if (on) { console.log("lcdPower: on"); Bangle.drawWidgets(); + reset_clock(); startTimers(); } else { console.log("lcdPower: off"); + reset_clock(); clearTimers(); } }); From 788642404bfa90bf67973b872e1a7ae84bf113a8 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Thu, 4 Feb 2021 01:39:43 +0000 Subject: [PATCH 09/32] Bug fix to reset_clock --- apps.json | 2 +- apps/xclock/xclock.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index db72e1f03..9197075a7 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.03", + "version":"0.04", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index aa494ff7d..4349ec8bd 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -176,9 +176,10 @@ let date_formatter = new EnglishDateFormatter(); function reset_clock(){ console.log("reset_clock"); - this.hour_shift_txt.reset(); - this.min_shift_txt.reset(); - this.min_remainder_shift_txt.reset(); + var i; + for (i = 0; i < row_displays.length; i++) { + row_displays[i].reset(); + } } function draw_clock(){ From c84617629026447b7583a407c430006595020caa Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sat, 6 Feb 2021 00:36:22 +0000 Subject: [PATCH 10/32] Added different language support --- apps.json | 2 +- apps/xclock/xclock.js | 148 +++++++++++++++++++++++++++++++----------- 2 files changed, 111 insertions(+), 39 deletions(-) diff --git a/apps.json b/apps.json index 9197075a7..b9b8530f1 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.04", + "version":"0.05", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index 4349ec8bd..4a2088f65 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -1,14 +1,3 @@ -// The interval reference for updating the clock -let intervalRef = null; - -// String numbers -const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", - "SIX", "SEVEN","EIGHT", "NINE", "TEN", - "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", - "FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", - "NINETEEN", "TWENTY"]; -const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", - "FIFTY"]; /** * This is a object that initializes itself with a position and * text after which you can tell it where you want to move to @@ -70,6 +59,12 @@ class ShiftText { this.txt = txt; this.show(); } + setTextYPosition(txt,y){ + this.hide(); + this.y = y; + this.txt = txt; + this.show(); + } moveTo(new_x,new_y){ this.tgt_x = new_x; this.tgt_y = new_y; @@ -132,47 +127,120 @@ class ShiftText { } -class DateFormatter { +class DateFormatter { + name(){"no name";} formatDate(date){ return ["","",""]; } } +// String numbers +const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", + "SIX", "SEVEN","EIGHT", "NINE", "TEN", + "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", + "FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", + "NINETEEN", "TWENTY"]; +const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", + "FIFTY"]; + +function hoursToText(hours){ + if(hours == 0){ + hours = 12; + } else if(hours > 12){ + hours = hours - 12; + } + return numberStr[hours]; +} + +function numberToText(value){ + word1 = ''; + word2 = ''; + if(value > 20){ + tens = (value / 10 | 0); + word1 = tensStr[tens]; + remainder = value - tens * 10; + if(remainder > 0){ + word2 = numberStr[remainder]; + } + } else if(value > 0) { + word1 = numberStr[value]; + } + return [word1,word2]; +} + class EnglishDateFormatter extends DateFormatter{ + name(){return "English";} formatDate(date){ - // First display the hours as a text number - let hours = date.getHours(); - if(hours == 0){ - hours = 12; - } else if(hours > 12){ - hours = hours - 12; - } - new_hours = numberStr[hours]; - // If the mins is over 20 we have to display the text on 2 lines - // Otherwise we just output our defined numbers from 1 to 20 - let mins = date.getMinutes(); - new_mins = ''; - new_mins_remainder = ''; - if(mins > 20){ - tens = (mins / 10 | 0); - new_mins = tensStr[tens]; - let remainder = mins - tens * 10; - if(remainder > 0){ - new_mins_remainder = numberStr[remainder]; - } - } else if(mins > 0) { - new_mins = numberStr[mins]; - } - return [new_hours,new_mins,new_mins_remainder]; + hours_txt = hoursToText(date.getHours()); + mins_txt = numberToText(date.getMinutes()); + return [hours_txt,mins_txt[0],mins_txt[1]]; } } -let row_displays = [ new ShiftText(240,50,'',"Vector",40,10,10,50,[1,1,1]), +class EnglishTraditionalDateFormatter extends DateFormatter { + constructor() { + super(); + } + name(){return "English Traditional";} + formatDate(date){ + hours = hoursToText(date.getHours()); + mins = date.getMinutes(); + if(mins == 0){ + return [hours, "o'","clock"]; + } else if(mins == 30){ + return ["HALF", "PAST", hours]; + } + mins_txt = ['','']; + if(mins == 15 || mins == 45){ + mins_txt[0] = "QUARTER"; + } + from_to = ''; + if(mins > 30){ + from_to = "TO"; + mins_txt = numberToText(60-mins); + } else { + from_to = "PAST"; + mins_txt = numberToText(mins); + } + return [ mins_txt[0], mins_txt[1] + ' ' + from_to , hours ]; + } +} + + +let row_displays = [ + new ShiftText(240,50,'',"Vector",40,10,10,50,[1,1,1]), new ShiftText(240,100,'',"Vector",20,10,10,50,[0.85,0.85,0.85]), new ShiftText(240,120,'',"Vector",20,10,10,50,[0.85,0.85,0.85]) ]; -let date_formatter = new EnglishDateFormatter(); +let date_formatters = [ + new EnglishDateFormatter(), + new EnglishTraditionalDateFormatter() + ]; + +let date_formatter_idx = 0; +let date_formatter = date_formatters[date_formatter_idx]; + +let format_name_display = new ShiftText(20,0,'',"Vector",10,1,1,50,[1,1,1]); + +function changeFormatter(){ + date_formatter_idx += 1; + if(date_formatter_idx >= date_formatters.length){ + date_formatter_idx = 0; + } + console.log("changing to formatter " + date_formatter_idx); + date_formatter = date_formatters[date_formatter_idx]; + reset_clock(); + draw_clock(); + // now announce the formatter by name + format_name_display.setTextYPosition(date_formatter.name(),-10); + format_name_display.moveToY(15); + format_name_display.onFinished( + function(){ + format_name_display.moveToY(-10); + } + ); +} function reset_clock(){ console.log("reset_clock"); @@ -212,6 +280,9 @@ function display_row(display,txt){ } } +// The interval reference for updating the clock +let intervalRef = null; + function clearTimers(){ if(intervalRef) { clearInterval(intervalRef); @@ -262,3 +333,4 @@ Bangle.drawWidgets(); startTimers(); // Show launcher when middle button pressed setWatch(Bangle.showLauncher, BTN2,{repeat:false,edge:"falling"}); +setWatch(changeFormatter, BTN1,{repeat:true,edge:"falling"}); From 8cedf2d09b4010ccd17f09f169f31e932c2ed024 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Tue, 9 Feb 2021 07:22:12 +0000 Subject: [PATCH 11/32] Now supports French and Japanese --- apps.json | 2 +- apps/xclock/xclock.js | 136 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 128 insertions(+), 10 deletions(-) diff --git a/apps.json b/apps.json index b9b8530f1..c05561bf5 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.05", + "version":"0.06", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index 4a2088f65..00a32980e 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -126,7 +126,6 @@ class ShiftText { } } - class DateFormatter { name(){"no name";} formatDate(date){ @@ -134,7 +133,7 @@ class DateFormatter { } } -// String numbers +// English String Numbers const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN","EIGHT", "NINE", "TEN", "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", @@ -144,10 +143,9 @@ const tensStr = ["ZERO", "TEN", "TWENTY", "THIRTY", "FOURTY", "FIFTY"]; function hoursToText(hours){ + hours = hours % 12; if(hours == 0){ hours = 12; - } else if(hours > 12){ - hours = hours - 12; } return numberStr[hours]; } @@ -198,30 +196,150 @@ class EnglishTraditionalDateFormatter extends DateFormatter { if(mins > 30){ from_to = "TO"; mins_txt = numberToText(60-mins); + hours = hoursToText(date.getHours() + 1 ); } else { from_to = "PAST"; mins_txt = numberToText(mins); } - return [ mins_txt[0], mins_txt[1] + ' ' + from_to , hours ]; + if(mins_txt[1] != ''){ + return [ mins_txt[0], mins_txt[1] + ' ' + from_to , hours ]; + } else { + return [ mins_txt[0], from_to , hours ]; + } + } +} + +// French date formatting +const frenchNumberStr = [ "ZERO", "UNE", "DEUX", "TROIS", "QUATRE", + "CINQ", "SIX", "SEPT", "HUIT", "NEUF", "DIX", + "ONZE", "DOUZE", "TREIZE", "QUATORZE","QUINZE", + "SEIZE", "DIX SEPT", "DIX HUIT","DIX NEUF", "VINGT", + "VINGT ET UN", "VINGT DEUX", "VINGT TROIS", + "VINGT QUATRE", "VINGT CINQ", "VINGT SIX", + "VINGT SEPT", "VINGT HUIT", "VINGT NEUF" + ]; + +function frenchHoursToText(hours){ + hours = hours % 12; + if(hours == 0){ + hours = 12; + } + return frenchNumberStr[hours]; +} + +function frenchHeures(hours){ + if(hours % 12 == 1){ + return 'HEURE'; + } else { + return 'HEURES'; + } +} + +class FrenchDateFormatter extends DateFormatter { + constructor() { + super(); + } + name(){return "French";} + formatDate(date){ + hours = frenchHoursToText(date.getHours()); + heures = frenchHeures(date.getHours()); + mins = date.getMinutes(); + if(mins == 0){ + if(hours == 0){ + return ["MINUIT", "",""]; + } else if(hours == 12){ + return ["MIDI", "",""]; + } else { + return [hours, heures,""]; + } + } else if(mins == 30){ + return [hours, heures,"ET DEMIE"]; + } else if(mins == 15){ + return [hours, heures,"ET QUERT"]; + } else if(mins == 45){ + hours = frenchHoursToText(date.getHours() + 1 ); + heures = frenchHeures(date.getHours() + 1); + return [hours, heures,"MOINS LET QUERT"]; + } + if(mins > 30){ + mins_txt = frenchNumberStr[60-mins]; + hours = frenchHoursToText(date.getHours() + 1 ); + heures = frenchHeures(date.getHours() + 1); + return [ hours, heures , "MOINS " + mins_txt ]; + } else { + mins_txt = frenchNumberStr[mins]; + return [ hours, heures , mins_txt ]; + } + } +} + +// Japanese Date formatting +const japaneseHourStr = [ "ZERO", "ICHII", "NI", "SAN", "YO", + "GO", "ROKU", "SHICHI", "HACHI", "KU", "JUU", + "JUUICHI", "JUINI"]; + +const japaneseNumerStr = [ "ZERO", "ICHII", "NI", "SAN", "SHI", + "GO", "ROKU", "SHICHI", "HACHI", "KU", "JUU"]; + +function japaneseHoursToText(hours){ + hours = hours % 12; + if(hours == 0){ + hours = 12; + } + return japaneseHourStr[hours] + 'JI'; +} + +function japaneseNumberToText(value){ + units = value % 10; + tens = (value/10) | 0; + console.log("tens=" + tens); + if(tens > 0){ + return "JUU" + japaneseNumerStr[units]; + } if(tens > 1){ + return japaneseNumerStr[tens] + "JUU" + japaneseNumerStr[units]; + } else { + return japaneseNumerStr[units]; + } +} + +function japaneseMinsToText(mins){ + if(mins == 30) + return "HAN"; + else + return japaneseNumberToText(mins) + "FUN"; +} + +class JapaneseDateFormatter extends DateFormatter { + constructor() { + super(); + } + name(){return "Japanese (Romanji)";} + formatDate(date){ + hours_txt = japaneseHoursToText(date.getHours()); + mins_txt = japaneseMinsToText(date.getMinutes()); + return [hours_txt,mins_txt]; } } + let row_displays = [ - new ShiftText(240,50,'',"Vector",40,10,10,50,[1,1,1]), + new ShiftText(240,50,'',"Vector",40,10,10,40,[1,1,1]), new ShiftText(240,100,'',"Vector",20,10,10,50,[0.85,0.85,0.85]), - new ShiftText(240,120,'',"Vector",20,10,10,50,[0.85,0.85,0.85]) + new ShiftText(240,120,'',"Vector",20,10,10,60,[0.85,0.85,0.85]) ]; let date_formatters = [ new EnglishDateFormatter(), - new EnglishTraditionalDateFormatter() + new EnglishTraditionalDateFormatter(), + new FrenchDateFormatter(), + new JapaneseDateFormatter() ]; let date_formatter_idx = 0; let date_formatter = date_formatters[date_formatter_idx]; -let format_name_display = new ShiftText(20,0,'',"Vector",10,1,1,50,[1,1,1]); +let format_name_display = new ShiftText(55,0,'',"Vector",10,1,1,50,[1,1,1]); function changeFormatter(){ date_formatter_idx += 1; From b393b7d32b90d0ebcd7dd32cb8e178ea46380478 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Tue, 9 Feb 2021 19:48:30 +0000 Subject: [PATCH 12/32] bugfixes to Japanese clock --- apps.json | 2 +- apps/xclock/xclock.js | 51 +++++++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/apps.json b/apps.json index c05561bf5..9eb19ea69 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.06", + "version":"0.07", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index 00a32980e..56fc4e251 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -257,14 +257,17 @@ class FrenchDateFormatter extends DateFormatter { } else if(mins == 15){ return [hours, heures,"ET QUERT"]; } else if(mins == 45){ - hours = frenchHoursToText(date.getHours() + 1 ); - heures = frenchHeures(date.getHours() + 1); + next_hour = date.getHours() + 1; + hours = frenchHoursToText(next_hour); + heures = frenchHeures(next_hour); return [hours, heures,"MOINS LET QUERT"]; } if(mins > 30){ - mins_txt = frenchNumberStr[60-mins]; - hours = frenchHoursToText(date.getHours() + 1 ); - heures = frenchHeures(date.getHours() + 1); + to_mins = 60-mins; + mins_txt = frenchNumberStr[to_mins]; + next_hour = date.getHours() + 1; + hours = frenchHoursToText(next_hour); + heures = frenchHeures(next_hour); return [ hours, heures , "MOINS " + mins_txt ]; } else { mins_txt = frenchNumberStr[mins]; @@ -276,37 +279,46 @@ class FrenchDateFormatter extends DateFormatter { // Japanese Date formatting const japaneseHourStr = [ "ZERO", "ICHII", "NI", "SAN", "YO", "GO", "ROKU", "SHICHI", "HACHI", "KU", "JUU", - "JUUICHI", "JUINI"]; + "JUU ICHI", "JUU NI"]; -const japaneseNumerStr = [ "ZERO", "ICHII", "NI", "SAN", "SHI", - "GO", "ROKU", "SHICHI", "HACHI", "KU", "JUU"]; +const japaneseNumberStr = [ "ZERO", "ICHII", "NI", "SAN", "SHI", + "GO", "ROKU", "NANA", "HACHI", "KU", "JUU"]; function japaneseHoursToText(hours){ hours = hours % 12; if(hours == 0){ hours = 12; } - return japaneseHourStr[hours] + 'JI'; + return japaneseHourStr[hours]; } function japaneseNumberToText(value){ units = value % 10; tens = (value/10) | 0; - console.log("tens=" + tens); - if(tens > 0){ - return "JUU" + japaneseNumerStr[units]; + if(tens == 1){ + if(units > 0){ + return "JUU " + japaneseNumberStr[units]; + } else { + return "JUU "; + } } if(tens > 1){ - return japaneseNumerStr[tens] + "JUU" + japaneseNumerStr[units]; + if(units > 0){ + return japaneseNumberStr[tens] + " JUU " + japaneseNumberStr[units]; + } else { + return japaneseNumberStr[tens] + " JUU"; + } } else { - return japaneseNumerStr[units]; + return japaneseNumberStr[units]; } } function japaneseMinsToText(mins){ - if(mins == 30) - return "HAN"; + if(mins == 0){ + return ["",""]; + } else if(mins == 30) + return ["HAN",""]; else - return japaneseNumberToText(mins) + "FUN"; + return [japaneseNumberToText(mins),"FUN"]; } class JapaneseDateFormatter extends DateFormatter { @@ -317,7 +329,7 @@ class JapaneseDateFormatter extends DateFormatter { formatDate(date){ hours_txt = japaneseHoursToText(date.getHours()); mins_txt = japaneseMinsToText(date.getMinutes()); - return [hours_txt,mins_txt]; + return [hours_txt,"JI", mins_txt[0], mins_txt[1] ]; } } @@ -326,7 +338,8 @@ class JapaneseDateFormatter extends DateFormatter { let row_displays = [ new ShiftText(240,50,'',"Vector",40,10,10,40,[1,1,1]), new ShiftText(240,100,'',"Vector",20,10,10,50,[0.85,0.85,0.85]), - new ShiftText(240,120,'',"Vector",20,10,10,60,[0.85,0.85,0.85]) + new ShiftText(240,120,'',"Vector",20,10,10,60,[0.85,0.85,0.85]), + new ShiftText(240,140,'',"Vector",20,10,10,60,[0.85,0.85,0.85]) ]; let date_formatters = [ From bf0feecb3dca6b1b96db2882d4e6040ba44dc84d Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Thu, 11 Feb 2021 22:54:53 +0000 Subject: [PATCH 13/32] corrected Japanese clock --- apps.json | 2 +- apps/xclock/xclock.js | 79 +++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/apps.json b/apps.json index 9eb19ea69..938e3face 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.07", + "version":"0.08", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index 56fc4e251..354d4bd76 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -184,9 +184,9 @@ class EnglishTraditionalDateFormatter extends DateFormatter { hours = hoursToText(date.getHours()); mins = date.getMinutes(); if(mins == 0){ - return [hours, "o'","clock"]; + return [hours, "o'","clock","",""]; } else if(mins == 30){ - return ["HALF", "PAST", hours]; + return ["","HALF", "PAST", "", hours]; } mins_txt = ['','']; if(mins == 15 || mins == 45){ @@ -202,9 +202,9 @@ class EnglishTraditionalDateFormatter extends DateFormatter { mins_txt = numberToText(mins); } if(mins_txt[1] != ''){ - return [ mins_txt[0], mins_txt[1] + ' ' + from_to , hours ]; + return ["", mins_txt[0], mins_txt[1] + ' ' + from_to , "",hours ]; } else { - return [ mins_txt[0], from_to , hours ]; + return ["", mins_txt[0], from_to ,"", hours ]; } } } @@ -253,14 +253,14 @@ class FrenchDateFormatter extends DateFormatter { return [hours, heures,""]; } } else if(mins == 30){ - return [hours, heures,"ET DEMIE"]; + return [hours, heures,'ET DEMIE']; } else if(mins == 15){ - return [hours, heures,"ET QUERT"]; + return [hours, heures,'ET QUERT']; } else if(mins == 45){ next_hour = date.getHours() + 1; hours = frenchHoursToText(next_hour); heures = frenchHeures(next_hour); - return [hours, heures,"MOINS LET QUERT"]; + return [hours, heures,"MOINS",'LET QUERT']; } if(mins > 30){ to_mins = 60-mins; @@ -268,7 +268,7 @@ class FrenchDateFormatter extends DateFormatter { next_hour = date.getHours() + 1; hours = frenchHoursToText(next_hour); heures = frenchHeures(next_hour); - return [ hours, heures , "MOINS " + mins_txt ]; + return [ hours, heures , "MOINS", mins_txt ]; } else { mins_txt = frenchNumberStr[mins]; return [ hours, heures , mins_txt ]; @@ -279,10 +279,26 @@ class FrenchDateFormatter extends DateFormatter { // Japanese Date formatting const japaneseHourStr = [ "ZERO", "ICHII", "NI", "SAN", "YO", "GO", "ROKU", "SHICHI", "HACHI", "KU", "JUU", - "JUU ICHI", "JUU NI"]; + 'JUU ICHI', 'JUU NI']; +const tensPrefixStr = [ "", + "JUU", + 'NIJUU', + 'SAN JUU', + 'YON JUU', + 'GO JUU']; -const japaneseNumberStr = [ "ZERO", "ICHII", "NI", "SAN", "SHI", - "GO", "ROKU", "NANA", "HACHI", "KU", "JUU"]; +const japaneseMinuteStr = [ ["", "PUN"], + ["IP","PUN" ], + ["NI", "FUN"], + ["SAN", "PUN"], + ["YON","FUN"], + ["GO", "HUN"], + ["RO", "PUN"], + ["NANA", "FUN"], + ["HAP", "PUN"], + ["KYU","FUN"], + ["JUP", "PUN"] + ]; function japaneseHoursToText(hours){ hours = hours % 12; @@ -292,33 +308,18 @@ function japaneseHoursToText(hours){ return japaneseHourStr[hours]; } -function japaneseNumberToText(value){ - units = value % 10; - tens = (value/10) | 0; - if(tens == 1){ - if(units > 0){ - return "JUU " + japaneseNumberStr[units]; - } else { - return "JUU "; - } - } if(tens > 1){ - if(units > 0){ - return japaneseNumberStr[tens] + " JUU " + japaneseNumberStr[units]; - } else { - return japaneseNumberStr[tens] + " JUU"; - } - } else { - return japaneseNumberStr[units]; - } -} - function japaneseMinsToText(mins){ if(mins == 0){ return ["",""]; } else if(mins == 30) return ["HAN",""]; - else - return [japaneseNumberToText(mins),"FUN"]; + else { + units = mins % 10; + mins_txt = japaneseMinuteStr[units]; + tens = mins /10 | 0; + tens_txt = tensPrefixStr[tens]; + return [tens_txt + ' ' + mins_txt[0], mins_txt[1]]; + } } class JapaneseDateFormatter extends DateFormatter { @@ -329,6 +330,7 @@ class JapaneseDateFormatter extends DateFormatter { formatDate(date){ hours_txt = japaneseHoursToText(date.getHours()); mins_txt = japaneseMinsToText(date.getMinutes()); + console.log("mins=" + mins_txt); return [hours_txt,"JI", mins_txt[0], mins_txt[1] ]; } } @@ -336,10 +338,11 @@ class JapaneseDateFormatter extends DateFormatter { let row_displays = [ - new ShiftText(240,50,'',"Vector",40,10,10,40,[1,1,1]), + new ShiftText(240,60,'',"Vector",40,10,10,40,[1,1,1]), new ShiftText(240,100,'',"Vector",20,10,10,50,[0.85,0.85,0.85]), new ShiftText(240,120,'',"Vector",20,10,10,60,[0.85,0.85,0.85]), - new ShiftText(240,140,'',"Vector",20,10,10,60,[0.85,0.85,0.85]) + new ShiftText(240,140,'',"Vector",20,10,10,70,[0.85,0.85,0.85]), + new ShiftText(240,140,'',"Vector",40,10,10,80,[1,1,1]) ]; let date_formatters = [ @@ -383,7 +386,7 @@ function reset_clock(){ function draw_clock(){ console.log("draw_clock"); - let date = new Date(); + date = new Date(); rows = date_formatter.formatDate(date); var i; for (i = 0; i < rows.length; i++) { @@ -391,6 +394,10 @@ function draw_clock(){ txt = rows[i]; display_row(display,txt); } + for (j = i; j < row_displays.length; j++) { + display = row_displays[j]; + display_row(display,''); + } console.log(date); } From db79b4f77cdc14bf9324d75528fe7032138d4b7b Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Thu, 11 Feb 2021 23:42:53 +0000 Subject: [PATCH 14/32] had to take out 1 clock face due to lack of memory --- apps.json | 2 +- apps/xclock/xclock.js | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index 938e3face..19a11b723 100644 --- a/apps.json +++ b/apps.json @@ -216,7 +216,7 @@ { "id": "xclock", "name": "X Clock", "icon": "xclock.png", - "version":"0.08", + "version":"0.09", "description": "Text Readable Time", "tags": "clock", "type":"clock", diff --git a/apps/xclock/xclock.js b/apps/xclock/xclock.js index 354d4bd76..8bed6539e 100644 --- a/apps/xclock/xclock.js +++ b/apps/xclock/xclock.js @@ -175,6 +175,7 @@ class EnglishDateFormatter extends DateFormatter{ } } +/* class EnglishTraditionalDateFormatter extends DateFormatter { constructor() { super(); @@ -208,6 +209,7 @@ class EnglishTraditionalDateFormatter extends DateFormatter { } } } +*/ // French date formatting const frenchNumberStr = [ "ZERO", "UNE", "DEUX", "TROIS", "QUATRE", @@ -317,8 +319,12 @@ function japaneseMinsToText(mins){ units = mins % 10; mins_txt = japaneseMinuteStr[units]; tens = mins /10 | 0; - tens_txt = tensPrefixStr[tens]; - return [tens_txt + ' ' + mins_txt[0], mins_txt[1]]; + if(tens > 0){ + tens_txt = tensPrefixStr[tens]; + return [tens_txt + ' ' + mins_txt[0], mins_txt[1]]; + } else { + return [mins_txt[0], mins_txt[1]]; + } } } @@ -342,12 +348,12 @@ let row_displays = [ new ShiftText(240,100,'',"Vector",20,10,10,50,[0.85,0.85,0.85]), new ShiftText(240,120,'',"Vector",20,10,10,60,[0.85,0.85,0.85]), new ShiftText(240,140,'',"Vector",20,10,10,70,[0.85,0.85,0.85]), - new ShiftText(240,140,'',"Vector",40,10,10,80,[1,1,1]) + //new ShiftText(240,140,'',"Vector",40,10,10,80,[1,1,1]) ]; let date_formatters = [ new EnglishDateFormatter(), - new EnglishTraditionalDateFormatter(), + //new EnglishTraditionalDateFormatter(), new FrenchDateFormatter(), new JapaneseDateFormatter() ]; From 32b91e4d574bf5f90afcb265d216fda721947bf9 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Tue, 16 Feb 2021 21:15:00 +0000 Subject: [PATCH 15/32] adjusted a few sentences in walkersclock README.md --- apps/walkersclock/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/walkersclock/README.md b/apps/walkersclock/README.md index 0c10f79eb..7ff45a06a 100644 --- a/apps/walkersclock/README.md +++ b/apps/walkersclock/README.md @@ -57,7 +57,5 @@ on the second line of the watch. ![](gps_alt.jpg) ## Future Enhancements -* Ability to turn on the Heart Rate monitor +* Ability to turn on the heart rate monitor and display the rate on the info line * Maybe a simple stopwatch capability -* Fix the screen flicker - From c980a68a1f4b157c581c032dfba2532258f4dfe8 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Tue, 16 Feb 2021 21:15:43 +0000 Subject: [PATCH 16/32] reduced flicker in walkersclock --- apps/walkersclock/app.js | 71 +++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/apps/walkersclock/app.js b/apps/walkersclock/app.js index df009534a..5e4b114a9 100644 --- a/apps/walkersclock/app.js +++ b/apps/walkersclock/app.js @@ -46,6 +46,10 @@ let gpsPowerState = false; let infoMode = INFO_NONE; let functionMode = FN_MODE_OFF; let gpsDisplay = GDISP_OS; +let prevInfoStr = "clear"; +let prevActivityStr = "clear"; +let prevSteps = "clear"; +let clearActivityArea = true; let last_steps = undefined; let firstPress = 0; @@ -66,7 +70,8 @@ function drawTime() { var time = da[4].substr(0,5); g.reset(); - g.clearRect(0,24,239,239); + g.clearRect(0,Y_TIME, 239, Y_ACTIVITY - 1); + g.setColor(1,1,1); // white g.setFontAlign(0, -1); @@ -81,15 +86,22 @@ function drawTime() { g.drawString(time, g.getWidth()/2, Y_TIME); } -function drawSteps() { - g.setColor(0,255,0); // green - g.setFont("Vector", 60); - g.drawString(getSteps(), g.getWidth()/2, Y_ACTIVITY); -} - function drawActivity() { + var steps = getSteps(); + if (!gpsPowerState && steps != prevSteps) + clearActivityArea = true; + + prevSteps = steps; + + if (clearActivityArea) { + g.clearRect(0, Y_ACTIVITY, 239, Y_MODELINE - 1); + clearActivityArea = false; + } + if (!gpsPowerState) { - drawSteps(); + g.setColor(0,255,0); // green + g.setFont("Vector", 60); + g.drawString(getSteps(), g.getWidth()/2, Y_ACTIVITY); return; } @@ -116,6 +128,7 @@ function drawActivity() { let os = OsGridRef.latLongToOsGrid(last_fix); let ref = to_map_ref(6, os.easting, os.northing); let speed; + let activityStr = ""; if (age < 0) age = 0; g.setFontVector(40); @@ -123,18 +136,20 @@ function drawActivity() { switch(gpsDisplay) { case GDISP_OS: - g.drawString(ref, 120, Y_ACTIVITY, true); + activityStr = ref; break; case GDISP_SPEED: speed = last_fix.speed; speed = speed.toFixed(1); - g.drawString(speed + "kph", 120, Y_ACTIVITY, true); + activityStr = speed + "kph" break; case GDISP_ALT: - g.drawString(last_fix.alt + "m" , 120, Y_ACTIVITY, true); + activityStr = last_fix.alt + "m"; break; } + g.clearRect(0, Y_ACTIVITY, 239, Y_MODELINE - 1); + g.drawString(activityStr, 120, Y_ACTIVITY); g.setFont("6x8",2); g.setColor(1,1,1); g.drawString(age, 120, Y_ACTIVITY + 46); @@ -174,8 +189,6 @@ function drawInfo() { let str = ""; let col = 0x07E0; // green - //console.log("drawInfo(), infoMode=" + infoMode + " funcMode=" + functionMode); - switch(functionMode) { case FN_MODE_OFF: break; @@ -213,11 +226,17 @@ function drawInfo() { default: str = "Battery: " + E.getBattery() + "%"; } - + drawModeLine(str,col); } -function drawModeLine(str, col) { +function drawModeLine(str,col) { + // check if we need to draw, avoid flicker + if (str == prevInfoStr) + return; + + prevInfoStr = str; + drawModeLine(str,col); g.setFont("6x8", 3); g.setColor(col); g.fillRect(0, Y_MODELINE - 3, 239, Y_MODELINE + 25); @@ -249,7 +268,7 @@ function changeInfoMode() { } functionMode = FN_MODE_OFF; infoMode = INFO_NONE; - //drawInfo(); + clearActivityArea = true; return; case FN_MODE_GDISP: @@ -281,7 +300,8 @@ function changeInfoMode() { default: infoMode = INFO_NONE; } - //drawInfo(); + + clearActivityArea = true; } function changeFunctionMode() { @@ -331,11 +351,16 @@ function resetLastFix() { function processFix(fix) { last_fix.time = fix.time; - if (gpsState == GPS_TIME) + if (gpsState == GPS_TIME) { gpsState = GPS_SATS; + clearActivityArea = true; + } if (fix.fix) { - if (!last_fix.fix) Bangle.buzz(); // buzz on first position + if (!last_fix.fix) { + Bangle.buzz(); // buzz on first position + clearActivityArea = true; + } gpsState = GPS_RUNNING; last_fix = fix; } @@ -508,7 +533,13 @@ drawAll(); Bangle.on('lcdPower',function(on) { functionMode = FN_MODE_OFF; infoMode = INFO_NONE; - if (on) drawAll(); + if (on) { + prevInfoStr = "on"; // forces are redraw + drawAll(); + } else { + prevInfoStr = "off"; // forces are redraw + drawInfo(); + } }); var click = setInterval(onTick, 5000); From 49e964506a7b4e70ad2eaa511081779a4111d682 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Tue, 16 Feb 2021 21:16:45 +0000 Subject: [PATCH 17/32] added ChangeLog for walkersclock --- apps/walkersclock/ChangeLog | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/walkersclock/ChangeLog diff --git a/apps/walkersclock/ChangeLog b/apps/walkersclock/ChangeLog new file mode 100644 index 000000000..411b8503c --- /dev/null +++ b/apps/walkersclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: First version of the Walkers Clock +0.02: Fixed screen flicker From e3ee8142bf727fdeb601ba9a160934c2e7b85c61 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 01:07:30 +0000 Subject: [PATCH 18/32] Renamed xclock to sliding text clock --- apps.json | 14 +++++++------- apps/slidingtext/README.md | 18 ++++++++++++++++++ apps/slidingtext/app.png | Bin 0 -> 15777 bytes apps/slidingtext/slidingtext-icon.js | 1 + .../xclock.js => slidingtext/slidingtext.js} | 0 apps/slidingtext/slidingtext.png | Bin 0 -> 6097 bytes apps/xclock/xclock-icon.js | 1 - apps/xclock/xclock.png | Bin 843 -> 0 bytes 8 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 apps/slidingtext/README.md create mode 100644 apps/slidingtext/app.png create mode 100644 apps/slidingtext/slidingtext-icon.js rename apps/{xclock/xclock.js => slidingtext/slidingtext.js} (100%) create mode 100644 apps/slidingtext/slidingtext.png delete mode 100644 apps/xclock/xclock-icon.js delete mode 100644 apps/xclock/xclock.png diff --git a/apps.json b/apps.json index 19a11b723..f87eb2a0f 100644 --- a/apps.json +++ b/apps.json @@ -213,17 +213,17 @@ {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} ] }, - { "id": "xclock", - "name": "X Clock", - "icon": "xclock.png", - "version":"0.09", - "description": "Text Readable Time", + { "id": "shifttext", + "name": "Shift Text Clock", + "icon": "shifttext.png", + "version":"0.01", + "description": "Shifting Text Clock", "tags": "clock", "type":"clock", "allow_emulator":true, "storage": [ - {"name":"xclock.app.js","url":"xclock.js"}, - {"name":"xclock.img","url":"xclock-icon.js","evaluate":true} + {"name":"shifttext.app.js","url":"shifttext.js"}, + {"name":"shifttext.img","url":"shifttext-icon.js","evaluate":true} ] }, { "id": "imgclock", diff --git a/apps/slidingtext/README.md b/apps/slidingtext/README.md new file mode 100644 index 000000000..5701b108d --- /dev/null +++ b/apps/slidingtext/README.md @@ -0,0 +1,18 @@ +# Sliding Text Clock - See the time in different languages + +Inspired by the Pebble sliding clock the shift clock shifts changes the time by scrolling the old time off the screen and the new time on. You are also able to change language on the fly so you can see the time as written in other languages. Currently only English, French and Japanese are supported + +![](app.png) + +## Usage + +Use Button 1 (the top right button) to change the language + + +## Requests + +[Reach out to Adrian](https://www.github.com/awkirk71) if you have feature requests or notice bugs. + +## Creator + +Made by [Adrian Kirk](https://www.github.com/awkirk71). diff --git a/apps/slidingtext/app.png b/apps/slidingtext/app.png new file mode 100644 index 0000000000000000000000000000000000000000..7ded6493781648d2b1fcc9a707fd6aa118cb2f1e GIT binary patch literal 15777 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 Date: Wed, 17 Feb 2021 01:14:23 +0000 Subject: [PATCH 19/32] Typos in the apps loader --- apps.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index f87eb2a0f..dfd7c67b9 100644 --- a/apps.json +++ b/apps.json @@ -213,17 +213,17 @@ {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} ] }, - { "id": "shifttext", - "name": "Shift Text Clock", - "icon": "shifttext.png", + { "id": "text", + "name": "Sliding Text Clock", + "icon": "slidingtext.png", "version":"0.01", - "description": "Shifting Text Clock", + "description": "Sliding Text Clock", "tags": "clock", "type":"clock", "allow_emulator":true, "storage": [ - {"name":"shifttext.app.js","url":"shifttext.js"}, - {"name":"shifttext.img","url":"shifttext-icon.js","evaluate":true} + {"name":"slidingtext.app.js","url":"slidingtext.js"}, + {"name":"slidingtext.img","url":"slidingtext-icon.js","evaluate":true} ] }, { "id": "imgclock", From 8c8ade85287f96307bcb77822ac34cc3564ce2a5 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 01:20:18 +0000 Subject: [PATCH 20/32] More typos in apps file --- apps/slidingtext/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/slidingtext/ChangeLog diff --git a/apps/slidingtext/ChangeLog b/apps/slidingtext/ChangeLog new file mode 100644 index 000000000..d53df991b --- /dev/null +++ b/apps/slidingtext/ChangeLog @@ -0,0 +1 @@ +0.01: Initial Release From 49e20dee9566254ee58c1981572c32fe98e515cf Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 01:24:48 +0000 Subject: [PATCH 21/32] typos in apps file --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index dfd7c67b9..17df60f86 100644 --- a/apps.json +++ b/apps.json @@ -213,7 +213,7 @@ {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} ] }, - { "id": "text", + { "id": "slidingtext", "name": "Sliding Text Clock", "icon": "slidingtext.png", "version":"0.01", From b6555d8a3b21d48a1e86d6a6c6e312968cb34a6f Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 01:43:21 +0000 Subject: [PATCH 22/32] tidied up code --- apps/slidingtext/slidingtext.js | 97 ++++++++++++++++----------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/apps/slidingtext/slidingtext.js b/apps/slidingtext/slidingtext.js index 8bed6539e..267cef822 100644 --- a/apps/slidingtext/slidingtext.js +++ b/apps/slidingtext/slidingtext.js @@ -1,9 +1,19 @@ /** -* This is a object that initializes itself with a position and -* text after which you can tell it where you want to move to -* using the moveTo method and it will smoothly move the text across +* Adrian Kirk 2021-02 +* Sliding text clock inspired by the Pebble +* clock with the same name */ + + class ShiftText { + /** + * Class Responsible for shifting text around the screen + * + * This is a object that initializes itself with a position and + * text after which you can tell it where you want to move to + * using the moveTo method and it will smoothly move the text across + * at the selected frame rate and speed + */ constructor(x,y,txt,font_name, font_size,speed_x,speed_y,freq_millis, color){ this.x = x; @@ -127,12 +137,23 @@ class ShiftText { } class DateFormatter { + /** + * A pure virtual class which all the other date formatters will + * inherit from. + * The name will be used to declare the date format when selected + * and the date formatDate methid will return the time formated + * to the lines of text on the screen + */ name(){"no name";} formatDate(date){ return ["","",""]; } } +/** +* English date formatting +*/ + // English String Numbers const numberStr = ["ZERO","ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN","EIGHT", "NINE", "TEN", @@ -175,43 +196,9 @@ class EnglishDateFormatter extends DateFormatter{ } } -/* -class EnglishTraditionalDateFormatter extends DateFormatter { - constructor() { - super(); - } - name(){return "English Traditional";} - formatDate(date){ - hours = hoursToText(date.getHours()); - mins = date.getMinutes(); - if(mins == 0){ - return [hours, "o'","clock","",""]; - } else if(mins == 30){ - return ["","HALF", "PAST", "", hours]; - } - mins_txt = ['','']; - if(mins == 15 || mins == 45){ - mins_txt[0] = "QUARTER"; - } - from_to = ''; - if(mins > 30){ - from_to = "TO"; - mins_txt = numberToText(60-mins); - hours = hoursToText(date.getHours() + 1 ); - } else { - from_to = "PAST"; - mins_txt = numberToText(mins); - } - if(mins_txt[1] != ''){ - return ["", mins_txt[0], mins_txt[1] + ' ' + from_to , "",hours ]; - } else { - return ["", mins_txt[0], from_to ,"", hours ]; - } - } -} +/** +* French date formatting */ - -// French date formatting const frenchNumberStr = [ "ZERO", "UNE", "DEUX", "TROIS", "QUATRE", "CINQ", "SIX", "SEPT", "HUIT", "NEUF", "DIX", "ONZE", "DOUZE", "TREIZE", "QUATORZE","QUINZE", @@ -278,7 +265,9 @@ class FrenchDateFormatter extends DateFormatter { } } -// Japanese Date formatting +/** +* Japanese date formatting +*/ const japaneseHourStr = [ "ZERO", "ICHII", "NI", "SAN", "YO", "GO", "ROKU", "SHICHI", "HACHI", "KU", "JUU", 'JUU ICHI', 'JUU NI']; @@ -336,31 +325,34 @@ class JapaneseDateFormatter extends DateFormatter { formatDate(date){ hours_txt = japaneseHoursToText(date.getHours()); mins_txt = japaneseMinsToText(date.getMinutes()); - console.log("mins=" + mins_txt); return [hours_txt,"JI", mins_txt[0], mins_txt[1] ]; } } +/** +* The Watch Display +*/ - +// a list of display rows let row_displays = [ new ShiftText(240,60,'',"Vector",40,10,10,40,[1,1,1]), new ShiftText(240,100,'',"Vector",20,10,10,50,[0.85,0.85,0.85]), new ShiftText(240,120,'',"Vector",20,10,10,60,[0.85,0.85,0.85]), - new ShiftText(240,140,'',"Vector",20,10,10,70,[0.85,0.85,0.85]), - //new ShiftText(240,140,'',"Vector",40,10,10,80,[1,1,1]) + new ShiftText(240,140,'',"Vector",20,10,10,70,[0.85,0.85,0.85]) ]; +// a list of the formatters to cycle through let date_formatters = [ new EnglishDateFormatter(), - //new EnglishTraditionalDateFormatter(), new FrenchDateFormatter(), new JapaneseDateFormatter() ]; +// current index of the date formatter to display let date_formatter_idx = 0; let date_formatter = date_formatters[date_formatter_idx]; +// The small display at the top which announces the date format let format_name_display = new ShiftText(55,0,'',"Vector",10,1,1,50,[1,1,1]); function changeFormatter(){ @@ -375,6 +367,7 @@ function changeFormatter(){ // now announce the formatter by name format_name_display.setTextYPosition(date_formatter.name(),-10); format_name_display.moveToY(15); + // and then move back format_name_display.onFinished( function(){ format_name_display.moveToY(-10); @@ -383,7 +376,7 @@ function changeFormatter(){ } function reset_clock(){ - console.log("reset_clock"); + //console.log("reset_clock"); var i; for (i = 0; i < row_displays.length; i++) { row_displays[i].reset(); @@ -391,7 +384,7 @@ function reset_clock(){ } function draw_clock(){ - console.log("draw_clock"); + //console.log("draw_clock"); date = new Date(); rows = date_formatter.formatDate(date); var i; @@ -400,11 +393,13 @@ function draw_clock(){ txt = rows[i]; display_row(display,txt); } + // If the dateformatter has not returned enough + // rows then treat the reamining rows as empty for (j = i; j < row_displays.length; j++) { display = row_displays[j]; display_row(display,''); } - console.log(date); + //console.log(date); } function display_row(display,txt){ @@ -438,13 +433,13 @@ function startTimers(){ let date = new Date(); let secs = date.getSeconds(); let nextMinuteStart = 60 - secs; - console.log("scheduling clock draw in " + nextMinuteStart + " seconds"); + //console.log("scheduling clock draw in " + nextMinuteStart + " seconds"); setTimeout(scheduleDrawClock,nextMinuteStart * 1000); draw_clock(); } function scheduleDrawClock(){ - console.log("scheduleDrawClock"); + //console.log("scheduleDrawClock"); if(intervalRef) clearTimers(); intervalRef = setInterval(draw_clock, 60*1000); draw_clock(); @@ -463,7 +458,7 @@ Bangle.on('lcdPower', (on) => { } }); Bangle.on('faceUp',function(up){ - console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); + //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); if (up && !Bangle.isLCDOn()) { //console.log("faceUp and LCD off"); clearTimers(); From e065a9aaf0fce5089cf81a037e0ffa005b82297d Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 02:06:09 +0000 Subject: [PATCH 23/32] BUGFIX: icon not working on watch --- apps.json | 2 +- apps/slidingtext/slidingtext-icon.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 17df60f86..06b43ea0a 100644 --- a/apps.json +++ b/apps.json @@ -214,7 +214,7 @@ ] }, { "id": "slidingtext", - "name": "Sliding Text Clock", + "name": "Sliding Clock", "icon": "slidingtext.png", "version":"0.01", "description": "Sliding Text Clock", diff --git a/apps/slidingtext/slidingtext-icon.js b/apps/slidingtext/slidingtext-icon.js index aae4163b2..d315f73b7 100644 --- a/apps/slidingtext/slidingtext-icon.js +++ b/apps/slidingtext/slidingtext-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("////////////////////////////////////////////////////////////////////////4C2gXzoH4CggHzIH/eAnnzJ/+eAhn5If+eAgn4YP+fBnn4Z/+fBggcYH+fJgQc4H////////////////4gGFf///9gRs////9iRs////9yFv////////////7CH/////4AP/////4gf/////6kP/////////////////////////////////////////////////////////////")) +require("heatshrink").decompress(atob("mEwwkE/4A/AH4A/AHPyiU/AgPzC6MggEBDAMwl4RKmczFIX/iEAAAM/gEDCxMwCAUAkYXDiEDiIXK+UQifzmUggZHBJAIEBj5HK+cgFoI1BgIuBIoJ3NDAJuCiEQmchgSLO+YQC+MAl8yC5//+CRCPwcAYgYAH+MSPYKHCkECmcBkchgETFhKMBgMBJYMBIoKZBNYSqFl8z+XxFQJaBAYMQUYMxa4cwDAkDkUwmIkBYoQuCAAMxAgcgMYwvBeocQVYQABCQfzGAUvI4gXDUZPyh4aBh5HE+QkCUBHziBHIkETDYL8MU4qeBiBFImSrCJ48jKQf/kMjmczkUQbQLwJOoRSB+cCiEAgESCpguBZwZ4INRMAFwYWQmUBCwTkHABPxgETmchgBYNC4kROAMSLiIA/AH4A/AH4A0A")) From a4efb807f69cdc70f45846995c628e3040b0b488 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 02:13:29 +0000 Subject: [PATCH 24/32] Text not fitting on watch screen --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 06b43ea0a..90f32f92e 100644 --- a/apps.json +++ b/apps.json @@ -217,7 +217,7 @@ "name": "Sliding Clock", "icon": "slidingtext.png", "version":"0.01", - "description": "Sliding Text Clock", + "description": "Sliding Clock", "tags": "clock", "type":"clock", "allow_emulator":true, From 8c3d0febf9d9b108d34a49348ffc7b175b5c414b Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 02:20:25 +0000 Subject: [PATCH 25/32] Added a proper description --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 90f32f92e..17a73365f 100644 --- a/apps.json +++ b/apps.json @@ -217,7 +217,7 @@ "name": "Sliding Clock", "icon": "slidingtext.png", "version":"0.01", - "description": "Sliding Clock", + "description": "Inspired by the Pebble sliding clock the shift clock shifts changes the time by scrolling the old time off the screen and the new time on. You are also able to change language on the fly so you can see the time as written in other languages. Currently only English, French and Japanese are supported", "tags": "clock", "type":"clock", "allow_emulator":true, From 993f9093351a6766fbd866cb577c66b4384db885 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 17 Feb 2021 16:46:58 +0000 Subject: [PATCH 26/32] add geiss clock --- apps.json | 24 ++++++ apps/geissclk/ChangeLog | 1 + apps/geissclk/clock-icon.js | 1 + apps/geissclk/clock.js | 148 ++++++++++++++++++++++++++++++++++++ apps/geissclk/clock.png | Bin 0 -> 2074 bytes apps/geissclk/precompute.js | 108 ++++++++++++++++++++++++++ 6 files changed, 282 insertions(+) create mode 100644 apps/geissclk/ChangeLog create mode 100644 apps/geissclk/clock-icon.js create mode 100644 apps/geissclk/clock.js create mode 100644 apps/geissclk/clock.png create mode 100644 apps/geissclk/precompute.js diff --git a/apps.json b/apps.json index 1f7078fe8..fbe8b953f 100644 --- a/apps.json +++ b/apps.json @@ -269,6 +269,30 @@ {"name":"clock2x3.img","url":"clock2x3-icon.js","evaluate":true} ] }, + { "id": "geissclk", + "name": "Geiss Clock", + "icon": "clock.png", + "version":"0.01", + "description": "7 segment clock with animated background in the style of Ryan Geiss' music visualisation. NOTE: The first run will take ~1 minute to do some precalculation", + "tags": "clock", + "type":"clock", + "storage": [ + {"name":"geissclk.app.js","url":"clock.js"}, + {"name":"geissclk.precompute.js","url":"precompute.js"}, + {"name":"geissclk.img","url":"clock-icon.js","evaluate":true} + ], + "data": [ + {"name":"geissclk.0.map"}, + {"name":"geissclk.1.map"}, + {"name":"geissclk.2.map"}, + {"name":"geissclk.3.map"}, + {"name":"geissclk.4.map"}, + {"name":"geissclk.5.map"}, + {"name":"geissclk.0.pal"}, + {"name":"geissclk.1.pal"}, + {"name":"geissclk.2.pal"} + ] + }, { "id": "trex", "name": "T-Rex", "icon": "trex.png", diff --git a/apps/geissclk/ChangeLog b/apps/geissclk/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/geissclk/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/geissclk/clock-icon.js b/apps/geissclk/clock-icon.js new file mode 100644 index 000000000..723d17cc0 --- /dev/null +++ b/apps/geissclk/clock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X/AoMF/3G/2m/wOCmoaKmtAAgVQBYsFoECwALMAA0JBZQABBYIbBBaVUBYMVBYkBIIILDgEKGYUBqkA6oLB6sAlQLDqsAioLBCAOq4AkCqtAivCBYMC1YwDitQgtCwNUhWsOwlUBYVQlWwJAlVgtSxNQFwnwGANBqWFqQuE1QwBqNewtKFwgLBGANWytq2EFWoU6gWBqoLBFwNVYIZZBqtXyurioLF1W1q/W1tVPIIxE1NV72VqpTDDAleEIgADnWq3qgBTIYADvQuBAAVUBYla1XVBYYbDyt632qd40Fqulquq0ALFOwO16t6BYpxBvWX6tW0aoDXwNU1XXNQMD1T7CAwPC1abBegPqFodQdQILCO4hxBlWxq2FoqaFBYOBcYNxQggLCToOBqAwBTgwLCiqoGgtCJ4L0BBYsVBYRmBBY0CwEUJ4IwFBYkVBYsMBYI0CJAwLDAA4L2A=")) diff --git a/apps/geissclk/clock.js b/apps/geissclk/clock.js new file mode 100644 index 000000000..de880d808 --- /dev/null +++ b/apps/geissclk/clock.js @@ -0,0 +1,148 @@ +var W = 79, H = 64; +/*var compiled = E.compiledC(` +// void transl(int, int, int ) +int transl(unsigned char *map, unsigned char *imgfrom, unsigned char *imgto) { + int n = 0; + const int W = 79; + const int H = 64; + for (int y=0;y>4)&0x0F) - 8; + int ax = nx&7; + int ay = ny&7; + int a = (nx>>3) + ((ny>>3)*W); + int c = 0; + if (a>=0 && a<(W*H-(W+1))) { + c = imgfrom[a]*(8-ax)*(8-ay) + + imgfrom[a+1]*(ax)*(8-ay) + + imgfrom[a+W]*(8-ax)*(ay) + + imgfrom[a+W+1]*(ax)*(ay); + c = (c>>6) - 4; + if (c<0) c=0; + } + imgto[n] = c; + n++; + } +} +`);*/ +var compiled = (function(){ + var bin=atob("Len3TwAnT/BPCPsAAJMI+wfzAOsDCdMYAZMAJhn4BkAAnQTwDwMD68YDBesUFAg7CDzdEE/q5AoI+wpaQfJvNapFItgB6woOA/AHAxH4CsCe+AGww/EIBQX7DPwD+wvMnvhPsATwBwQF+wv1ZUPE8QgKCvsMXJ74UFBrQwT7A8SkEQQ8JOrkdADgACQBm5xVATZPLsLRATdAL7bRA7C96PCPAAA="); + return { + transl:E.nativeCall(1, "void(int, int, int )", bin), + }; +})(); + +require("Font7x11Numeric7Seg").add(Graphics); + +// Allocate the data +var dataa = new Uint8Array(W*H); +var datab = new Uint8Array(W*H); +var map = new Uint8Array(W*H); +var pal = new Uint16Array(256); +var PALETTES = 3; +var MAPS = 6; + +// If we're missing any maps, compute them! +(function() { + var files = require("Storage").list(/^geissclk/); + var allOk = true; + for (var n=0;nCh6Mfqh-1u#LiK`lb9az#-dnsi zwICXW13;oW`pL!?(A^5}#aeskxtaYL>6rb0q)AwUSNj^y%prSagL~t zA}I8(jp`rlYIsmpICxPFU(y6h!84(1wO52Iy ze0B8gWwUMIzoy8LTX&$PU|Yqz(kfta;A^LLH_pyi!UAlY0ZR6`meP0&X0$_~UJduF#tXT`p0#dP+ zM-E>H|JI^eHt=5u8i2GD^5w_^%&9Ql zyhYzyyy!+mST)a$RNJ5jo4l+2RMm;ep>ukeZaxFd6f|iuzjm&KuQF(-UKYm=S+$JiNX(FCNxZuThaFP+dOKodtFZbU0_~w#)i$Vfg}% zH9v*O_dsh$irz2n-@V|3>|&Cs-^dxiI{FUQ_}SENmjEDA^KgA#*tzxmc7A6e~x6rIU<}?<#urd z;to0(V5*%Dnc~d=(%PT>u?F@5U>&)+2ErkQ4)2!O7Fm2~uvDJ1QawGkw8+Pm~)*3(CU z#~=qM-h8BXHCV--eighE)_#~ZSViC+6*^oSd+zETIg$WBndkdl z%;a2IaEb7}U!a3|=V3Gx>GoEpR+!wiMg=Wnu@`-~`l3WYCVQCKRmc<%aVwC?YL2_? zA*6~4l8IFa?Z7$=j!cguW-eyh8UVunKY{*xNMcew;$}tJX+=7mQ#F5-wqy{s|HuNg z>+Y$(u^Wu);|g;DaLCGx_>dTxV*4{$0*xU8nhS@Cn-ffn?FZH}I_cqriu}~Q>%evS z!A%j6-I-`IhIWNV$nCDVNf~3SnO^+>=mIkKU3)$|2S<>RWmMpt!gL_*PV&~-8s|$G z`8KNafb&jW&-5q)O1c*szf+D3ZwtIG(BaIg+G8F53c3JD>qY-CFh{BkR68&js6q_r z1L}jz{&sg@XcaBTeiVW3rj8vM@DJjIC${hW8}qPP9{A zcdES1>R@2_@4zIP8An{felWZbSf=RXf_#&42f(op)mL9@om-BMF2%sV%w0Y6bC+oO z?fQH`F@9I#K0ldw*$Fw0@Fd7gghMKP%dL%l+-prekrzIs%^w_U1ttNz#m#-6(QHj% zeX*oS>ie#kaNskl@^ytIaHtr3-U#@~#2dipMuQ;mlEwZi*4o!|jnD$;`H{P%<*ICS zZmW78z`UEO4dVJfFxiTJHYQ$wzN2_C&_b4HL6#wbw?TgB2L31A*4~Y!!Vh;g+==Qk z;IfyMZDTFopBfPOJ%CX*mU`P!ibYyR!*ugOpb0o?T<>0)x9<#q?ybKg2+V#&pYc{6 zed_A#_3X~ZrDF6=;IvyCyImF^@(U$JH(fxGUa|+Y%5lBbqwocUUh_WSCle_kAtGzt zm8l(2II}C2CDNYm)*WbZ>w21t!RIqUeg>RV^ukzKnZv1KFDKb#!;1!Kanv?STi+G9 zu@{=Ck*LV~z);uSpAzH|gw0n@aFm>g9Tj1m5NY4%tH+mx>1G|B2RGbacjIh7ndtG8iQVPX zMYM7RlxiQ@BVVQL{{lX0`=1vO`K7)TQ)KU0LVT0#zmg^!hBs(c_5c6?07*qoM6N<$ Eg0xHPyZ`_I literal 0 HcmV?d00001 diff --git a/apps/geissclk/precompute.js b/apps/geissclk/precompute.js new file mode 100644 index 000000000..91f41229b --- /dev/null +++ b/apps/geissclk/precompute.js @@ -0,0 +1,108 @@ +// PALETTES --------------------------- +E.showMessage("Precomputing\npalettes\n\nPlease wait...\n0 / 3"); +(function() { // fire + for (var i=0;i<256;i++) { + var r = Math.min(i*6,240); + var g = Math.min(i*3,240); + var b = E.clip((i-192)*8,0,240); + pal[i] = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8); + }pal[255] = 65535; +})() +require("Storage").write("geissclk.0.pal",pal.buffer); +E.showMessage("Precomputing\npalettes\n\nPlease wait...\n1 / 3"); +(function() { // gunge + for (var i=0;i<256;i++) { + var r = 0; + var g = Math.min(i*3,255); + var b = Math.min(i,255); + pal[i] = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8); + }pal[255] = 65535; +})() +require("Storage").write("geissclk.1.pal",pal.buffer); +E.showMessage("Precomputing\npalettes\n\nPlease wait...\n2 / 3"); +(function() { // rainbow + for (var i=0;i<256;i++) { + var cl = E.HSBtoRGB((48+i)/128,1,Math.min(i/16,0.9),true); + var r = cl[0]; + var g = cl[1]; + var b = cl[2]; + pal[i] = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8); + }pal[255] = 65535;pal[255] = 65535; +})() +require("Storage").write("geissclk.2.pal",pal.buffer); + + +// MAPS ---------------------------------------------- +E.showMessage("Precomputing\nmaps\n\nPlease wait...\n0"); +// straight out +(function() { "ram"; var n = 0; for (var y=0;y3)?0.5:-0.5); + dy = (-dy/d) + (((x&7)>3)?0.5:-0.5); + map[n++] = ((dx*3 + 8) & 0x0F) | (((dy*3 + 8) & 0x0F)<<4); + } +}})() +require("Storage").write("geissclk.2.map",map); +E.showMessage("Precomputing\nmaps\n\nPlease wait...\n3 / 5"); +// spiral +(function() { "ram"; var n = 0; for (var y=0;y Date: Wed, 17 Feb 2021 16:47:23 +0000 Subject: [PATCH 27/32] bump locale to fix warning --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index fbe8b953f..d1f824126 100644 --- a/apps.json +++ b/apps.json @@ -65,7 +65,7 @@ { "id": "locale", "name": "Languages", "icon": "locale.png", - "version":"0.08", + "version":"0.09", "description": "Translations for different countries", "tags": "tool,system,locale,translate", "type": "locale", From 8c0cae87edc0d230b8293e0ce6ecc3be9ab6e397 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 17 Feb 2021 16:51:34 +0000 Subject: [PATCH 28/32] oops - remove debug --- apps/geissclk/clock.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/geissclk/clock.js b/apps/geissclk/clock.js index de880d808..e42fb3743 100644 --- a/apps/geissclk/clock.js +++ b/apps/geissclk/clock.js @@ -88,10 +88,6 @@ var im = { palette: pal, buffer : dataa.buffer }; -Bangle.setLCDPower(1);Bangle.setLCDTimeout(0); -g.clear(); - - var lastSeconds = -1; function iterate() { "ram" @@ -142,6 +138,7 @@ Bangle.on('lcdPower',function(on) { animInterval = setInterval(iterate, 50); } }); +g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); iterate(); From 54aed92f46e6a386a3ca78aefa588e428eef7783 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 17 Feb 2021 16:56:10 +0000 Subject: [PATCH 29/32] tweak --- apps/geissclk/precompute.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/geissclk/precompute.js b/apps/geissclk/precompute.js index 91f41229b..0518b6cd8 100644 --- a/apps/geissclk/precompute.js +++ b/apps/geissclk/precompute.js @@ -33,7 +33,7 @@ require("Storage").write("geissclk.2.pal",pal.buffer); // MAPS ---------------------------------------------- -E.showMessage("Precomputing\nmaps\n\nPlease wait...\n0"); +E.showMessage("Precomputing\nmaps\n\nPlease wait...\n0 / 5"); // straight out (function() { "ram"; var n = 0; for (var y=0;y Date: Wed, 17 Feb 2021 18:05:16 +0000 Subject: [PATCH 30/32] bumped version for walkersclock --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index d1f824126..670cf342f 100644 --- a/apps.json +++ b/apps.json @@ -2809,7 +2809,7 @@ "name": "Walkers Clock", "shortName":"Walkers Clock", "icon": "walkersclock48.png", - "version":"0.01", + "version":"0.02", "description": "A larg font watch, displays steps, can switch GPS on/off, displays grid reference", "type":"clock", "tags": "clock, gps, tools, outdoors", From ac87020621fd160c4abcf92fce1d3a10ad1e2fd4 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Wed, 17 Feb 2021 21:09:38 +0000 Subject: [PATCH 31/32] Updated with new icon --- apps.json | 2 +- apps/slidingtext/README.md | 2 +- apps/slidingtext/app.png | Bin 15777 -> 22651 bytes apps/slidingtext/slidingtext-icon.js | 2 +- apps/slidingtext/slidingtext.png | Bin 6097 -> 2944 bytes 5 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 17a73365f..7d782041e 100644 --- a/apps.json +++ b/apps.json @@ -217,7 +217,7 @@ "name": "Sliding Clock", "icon": "slidingtext.png", "version":"0.01", - "description": "Inspired by the Pebble sliding clock the shift clock shifts changes the time by scrolling the old time off the screen and the new time on. You are also able to change language on the fly so you can see the time as written in other languages. Currently only English, French and Japanese are supported", + "description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently only English, French and Japanese are supported", "tags": "clock", "type":"clock", "allow_emulator":true, diff --git a/apps/slidingtext/README.md b/apps/slidingtext/README.md index 5701b108d..00f716e4a 100644 --- a/apps/slidingtext/README.md +++ b/apps/slidingtext/README.md @@ -1,6 +1,6 @@ # Sliding Text Clock - See the time in different languages -Inspired by the Pebble sliding clock the shift clock shifts changes the time by scrolling the old time off the screen and the new time on. You are also able to change language on the fly so you can see the time as written in other languages. Currently only English, French and Japanese are supported +Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently only English, French and Japanese are supported ![](app.png) diff --git a/apps/slidingtext/app.png b/apps/slidingtext/app.png index 7ded6493781648d2b1fcc9a707fd6aa118cb2f1e..3680c3ce6043399affba29faae9712cc283c7a9c 100644 GIT binary patch literal 22651 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 Z>57pLf7UNFR9qo-wKeqAD<9at{vRnE{6+u( literal 15777 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 N002ovPDHLkV1o2YSyBK1 delta 5518 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 Date: Thu, 18 Feb 2021 10:21:28 +0000 Subject: [PATCH 32/32] geissclk 0.02: BTN2->launcher, use smaller text to allow "20:00" to fit on screen --- apps.json | 4 ++-- apps/geissclk/ChangeLog | 1 + apps/geissclk/clock.js | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps.json b/apps.json index 92081847f..a7517fb27 100644 --- a/apps.json +++ b/apps.json @@ -285,7 +285,7 @@ { "id": "geissclk", "name": "Geiss Clock", "icon": "clock.png", - "version":"0.01", + "version":"0.02", "description": "7 segment clock with animated background in the style of Ryan Geiss' music visualisation. NOTE: The first run will take ~1 minute to do some precalculation", "tags": "clock", "type":"clock", @@ -2792,7 +2792,7 @@ { "id": "testuserinput", "name": "Test User Input", "shortName":"Test User Input", - "icon": "app.png", + "icon": "app.png", "version":"0.03", "description": "Basic app to test the bangle.js input interface. It displays the user action in text or an on/off switch image for swipe movement.", "readme": "README.md", diff --git a/apps/geissclk/ChangeLog b/apps/geissclk/ChangeLog index 5560f00bc..bd718a5b1 100644 --- a/apps/geissclk/ChangeLog +++ b/apps/geissclk/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: BTN2->launcher, use smaller text to allow "20:00" to fit on screen diff --git a/apps/geissclk/clock.js b/apps/geissclk/clock.js index e42fb3743..7d63b815e 100644 --- a/apps/geissclk/clock.js +++ b/apps/geissclk/clock.js @@ -34,7 +34,10 @@ var compiled = (function(){ }; })(); -require("Font7x11Numeric7Seg").add(Graphics); +//require("Font5x9Numeric7Seg").add(Graphics); +Graphics.prototype.setFont5x9Numeric7Seg = function() { + this.setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 9); + } // Allocate the data var dataa = new Uint8Array(W*H); @@ -92,7 +95,7 @@ var lastSeconds = -1; function iterate() { "ram" var d = new Date(); - var time = d.getHours().toString().padStart(2," ")+":"+d.getMinutes().toString().padStart(2,0); + var time = require("locale").time(d,1); var seconds = d.getSeconds().toString().padStart(2,0); t = addra; addra = addrb; addrb = t; t = dataa; dataa = datab; datab = t; @@ -117,10 +120,11 @@ function iterate() { "ram" compiled.transl(addrmap, addra, addrb); - gfx.setFont("7x11Numeric7Seg",2); - gfx.drawString(time, -5, 20); - gfx.setFont("7x11Numeric7Seg"); - gfx.drawString(seconds, 62, 30); + x = 8; + gfx.setFont("5x9Numeric7Seg",2); + gfx.drawString(time, x, 20); + gfx.setFont("5x9Numeric7Seg"); + gfx.drawString(seconds, x+55, 30); // firmwares pre-2v09 wouldn't accelerate a 3x blit if it went right to the RHS - hence we're 79px not 80 g.drawImage(im,1,24,{scale:3}); } @@ -143,3 +147,5 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); iterate(); animInterval = setInterval(iterate, 50); + +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});