From b3f37a7c671c0bf5781ae85cc84097a329e6656f Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:01:22 -0800 Subject: [PATCH 01/50] Update metadata.json --- apps/widbatpc/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/widbatpc/metadata.json b/apps/widbatpc/metadata.json index cf4f2e13a..718b7e083 100644 --- a/apps/widbatpc/metadata.json +++ b/apps/widbatpc/metadata.json @@ -9,6 +9,7 @@ "tags": "widget,battery", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", + "screenshots": [{"url":"widbatpc.full.jpg"},{"widbatpc.part.jpg"}], "storage": [ {"name":"widbatpc.wid.js","url":"widget.js"}, {"name":"widbatpc.settings.js","url":"settings.js"} From 8631c0495c61c553eb3c1f9706d556bd18b3eb93 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:03:34 -0800 Subject: [PATCH 02/50] Update metadata.json --- apps/activepedom/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/activepedom/metadata.json b/apps/activepedom/metadata.json index 22861ed9c..4deb7006d 100644 --- a/apps/activepedom/metadata.json +++ b/apps/activepedom/metadata.json @@ -8,6 +8,7 @@ "tags": "outdoors,widget", "supports": ["BANGLEJS"], "readme": "README.md", + "screenshots": [{"url":"600.png"},{"url":"10600.png"},{"url":"1600.png"}], "storage": [ {"name":"activepedom.wid.js","url":"widget.js"}, {"name":"activepedom.settings.js","url":"settings.js"}, From bf633ce11462c2887ebb71da706b00219c22e9c7 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:05:03 -0800 Subject: [PATCH 03/50] Update metadata.json --- apps/toucher/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/toucher/metadata.json b/apps/toucher/metadata.json index 5d41c3fe0..8b2715f0c 100644 --- a/apps/toucher/metadata.json +++ b/apps/toucher/metadata.json @@ -7,6 +7,7 @@ "icon": "app.png", "type": "launch", "tags": "tool,system,launcher", + "screenshots": [{"url":"screenshot1.jpg"}], "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ From fde04f0346d2fcd917dd4d0d68af414394db659e Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:06:33 -0800 Subject: [PATCH 04/50] Update metadata.json --- apps/widhwt/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/widhwt/metadata.json b/apps/widhwt/metadata.json index 957940c73..375ddf498 100644 --- a/apps/widhwt/metadata.json +++ b/apps/widhwt/metadata.json @@ -7,6 +7,7 @@ "type": "widget", "tags": "widget,tool", "allow_emulator": true, + "screenshots": [{"url":"wash-hand-timer-screenshot.png"}], "supports": ["BANGLEJS", "BANGLEJS2"], "storage": [ {"name":"widhwt.app.js","url":"app.js"}, From 6f1885272b875934a1ccf567d94919dfa10684ae Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:06:42 -0800 Subject: [PATCH 05/50] Add files via upload --- apps/widhwt/wash-hand-timer-screenshot.png | Bin 0 -> 2097 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/widhwt/wash-hand-timer-screenshot.png diff --git a/apps/widhwt/wash-hand-timer-screenshot.png b/apps/widhwt/wash-hand-timer-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..05859cd7a1f428a177409de20a6082093dc0a605 GIT binary patch literal 2097 zcmeH}`&-g?9K}CCh+!9Dp|zTsR(k@=oXeqDYO~BpTqTN_WELW!;=~K1%r9n|^`N%4 z(0R+8Q!;^aiW70Pxme!1c)?UIi^`OkHbrM<&HVxU5B9_RoaZ^`x7QEv=j4Au30jH% z5DfrW8GIn{$db$dJzJY4l_{PvmJG%_60{dcdpC>&fHDUM288h$mhwNo8^Ny#%rLyK zQXFqCy>=uABIaJ9Wa+jxUx_O~{{GrBrqO7$sH`vi!-S#0A+13EGY-V~7li|;#^TBc zxiB^o(1!P9qhi+nAO05*N{3pj)uuLAR;~{0T|}tI1U&XB!qgr(Fp?9EvGwR%@UuQ0 zVMeM;M=v7A<5%0c<4Ca9<@+Vn>;+pV=!8EV2Cg+18msZisg6&-y@?r+M}Jj5yxPVX z9e7b>r?$&IEOZP!)3*(@IlBS(i?cr*1^fUSVAxwiYQa>td?_C;rF;e6&X_hAa}6CL z|M@lX&xSsm|BXpN9)va?FNeQ&fK<;m8V9oj`WZ<2IsP6!#se6tQXmg{qYEJ2yOTrA zdy5@>EY{g?j1*Qj!=_4r-whw;=P32q&Xm;6X*IiR&>NTUENz*lC2hx1>V5%dod`ku z`w@Irl!XXY4k(VXbmQ@=k=b|c*wWa_^-xxsldjk@fjFaPU?SE)p+nstMF_htd7&2$ z;$D^a2@(X)yX`T?=q_83RFn`RcHp~`X7tibt;mOGidxj`bhh9e%vd35RL=Ho`g6B@ z=!pmz1E8qY5dt&Qe4pw)FnF(Wg$HmfZF!_AB&{qj`DD9&L(K)n;j)t9NuTunh054B zJ8TMTvoluFl5*R=3#N~t#;mOO}tp=xr$-ngo zermYN#|tm7ikD>%*7}YlHSE||&-J~NE*(i%MsZak<5GtY$rtOp0*q#ud^j;-kKgbbf@jx@m^1=O=}!wVO*_iijXaH3%W?C ztLYnR6&WK@kBx>s2HH>PoRL<#ma0_bPkUvK(MmkAkq~cq-yj}+i2F1Q>)M-z<1@X} zPg@rmU+Whs8)7Vn0p$KrCy3~7P30oSFHCp-q;JCg9BP+LcpdS>H|yka1&K{YM*dOE zV@9_GHp}?2QN!hFwzI zsO`CZ@AdGFYGYYSnO$;d-L)#!ssM9F2lKP)SD*U!$ovR?vITWb9YYh_Z)_boqS}uk5d!vu7n(~%lf^Cq1 zc)m->TV_ Date: Wed, 19 Jan 2022 08:06:57 -0800 Subject: [PATCH 06/50] Add files via upload --- wash-hand-timer-screenshot.png | Bin 0 -> 2097 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 wash-hand-timer-screenshot.png diff --git a/wash-hand-timer-screenshot.png b/wash-hand-timer-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..05859cd7a1f428a177409de20a6082093dc0a605 GIT binary patch literal 2097 zcmeH}`&-g?9K}CCh+!9Dp|zTsR(k@=oXeqDYO~BpTqTN_WELW!;=~K1%r9n|^`N%4 z(0R+8Q!;^aiW70Pxme!1c)?UIi^`OkHbrM<&HVxU5B9_RoaZ^`x7QEv=j4Au30jH% z5DfrW8GIn{$db$dJzJY4l_{PvmJG%_60{dcdpC>&fHDUM288h$mhwNo8^Ny#%rLyK zQXFqCy>=uABIaJ9Wa+jxUx_O~{{GrBrqO7$sH`vi!-S#0A+13EGY-V~7li|;#^TBc zxiB^o(1!P9qhi+nAO05*N{3pj)uuLAR;~{0T|}tI1U&XB!qgr(Fp?9EvGwR%@UuQ0 zVMeM;M=v7A<5%0c<4Ca9<@+Vn>;+pV=!8EV2Cg+18msZisg6&-y@?r+M}Jj5yxPVX z9e7b>r?$&IEOZP!)3*(@IlBS(i?cr*1^fUSVAxwiYQa>td?_C;rF;e6&X_hAa}6CL z|M@lX&xSsm|BXpN9)va?FNeQ&fK<;m8V9oj`WZ<2IsP6!#se6tQXmg{qYEJ2yOTrA zdy5@>EY{g?j1*Qj!=_4r-whw;=P32q&Xm;6X*IiR&>NTUENz*lC2hx1>V5%dod`ku z`w@Irl!XXY4k(VXbmQ@=k=b|c*wWa_^-xxsldjk@fjFaPU?SE)p+nstMF_htd7&2$ z;$D^a2@(X)yX`T?=q_83RFn`RcHp~`X7tibt;mOGidxj`bhh9e%vd35RL=Ho`g6B@ z=!pmz1E8qY5dt&Qe4pw)FnF(Wg$HmfZF!_AB&{qj`DD9&L(K)n;j)t9NuTunh054B zJ8TMTvoluFl5*R=3#N~t#;mOO}tp=xr$-ngo zermYN#|tm7ikD>%*7}YlHSE||&-J~NE*(i%MsZak<5GtY$rtOp0*q#ud^j;-kKgbbf@jx@m^1=O=}!wVO*_iijXaH3%W?C ztLYnR6&WK@kBx>s2HH>PoRL<#ma0_bPkUvK(MmkAkq~cq-yj}+i2F1Q>)M-z<1@X} zPg@rmU+Whs8)7Vn0p$KrCy3~7P30oSFHCp-q;JCg9BP+LcpdS>H|yka1&K{YM*dOE zV@9_GHp}?2QN!hFwzI zsO`CZ@AdGFYGYYSnO$;d-L)#!ssM9F2lKP)SD*U!$ovR?vITWb9YYh_Z)_boqS}uk5d!vu7n(~%lf^Cq1 zc)m->TV_ Date: Wed, 19 Jan 2022 08:09:17 -0800 Subject: [PATCH 07/50] Update metadata.json --- apps/UI4swatch/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/UI4swatch/metadata.json b/apps/UI4swatch/metadata.json index b142c1e7d..379d173c3 100644 --- a/apps/UI4swatch/metadata.json +++ b/apps/UI4swatch/metadata.json @@ -8,6 +8,7 @@ "tags": "Color,input,buttons,touch,UI", "supports": ["BANGLEJS"], "readme": "README.md", + "screenshots": [{"url":"UI4swatch_icon.png"},{"url":"UI4swatch_s1.png"}], "storage": [ {"name":"UI4swatch.app.js","url":"app.js"}, {"name":"UI4swatch.img","url":"app-icon.js","evaluate":true} From f033cbc3a1a9e3871a4f62fcc0fcbe093c54adba Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:09:51 -0800 Subject: [PATCH 08/50] Add files via upload --- ...ier-go-direct-respiration-belt-screenshot.png | Bin 0 -> 3741 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/vernierrespirate/Vernier-go-direct-respiration-belt-screenshot.png diff --git a/apps/vernierrespirate/Vernier-go-direct-respiration-belt-screenshot.png b/apps/vernierrespirate/Vernier-go-direct-respiration-belt-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f5d0955828aa2be63e129a8de7cce3f696ba2fc9 GIT binary patch literal 3741 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 avERm-T}mT${D1yU0Dr~QpjyxQ{(k`ZdLK0a literal 0 HcmV?d00001 From 12d1d4d5f38129717963c4975c673fe95e0f427e Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:11:07 -0800 Subject: [PATCH 09/50] Update metadata.json --- apps/vernierrespirate/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/vernierrespirate/metadata.json b/apps/vernierrespirate/metadata.json index a51dc8c70..5e2baf2bb 100644 --- a/apps/vernierrespirate/metadata.json +++ b/apps/vernierrespirate/metadata.json @@ -8,6 +8,7 @@ "tags": "health,bluetooth", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", + "screenshots": [{"url":"Vernier-go-direct-respiration-belt-screenshot.png"}], "storage": [ {"name":"vernierrespirate.app.js","url":"app.js"}, {"name":"vernierrespirate.img","url":"app-icon.js","evaluate":true} From 7f1f1a5dbede398b5fd92ae41cdfd57f410797d7 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:11:54 -0800 Subject: [PATCH 10/50] fix version number --- apps/ruuviwatch/ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/ruuviwatch/ChangeLog b/apps/ruuviwatch/ChangeLog index ebde871fa..7953548cb 100644 --- a/apps/ruuviwatch/ChangeLog +++ b/apps/ruuviwatch/ChangeLog @@ -1,2 +1,2 @@ -1.00: Hello Ruuvi Watch! -1.01: Clear gfx on startup. \ No newline at end of file +0.01: Hello Ruuvi Watch! +0.02: Clear gfx on startup. From 43f1fb8492a57ab0313696ede8f8e37a8b089045 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:12:20 -0800 Subject: [PATCH 11/50] fix version number --- apps/ruuviwatch/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ruuviwatch/metadata.json b/apps/ruuviwatch/metadata.json index 215df105a..12f9ff4a0 100644 --- a/apps/ruuviwatch/metadata.json +++ b/apps/ruuviwatch/metadata.json @@ -2,7 +2,7 @@ "name": "Ruuvi Watch", "shortName":"Ruuvi Watch", "icon": "ruuviwatch.png", - "version":"1.01", + "version":"0.02", "description": "Keep an eye on RuuviTag devices (https://ruuvi.com). Only shows RuuviTags using the v5 format.", "readme":"README.md", "tags": "bluetooth", From d6d7b07d4715945e42e9e454d848e1aede7ffd4b Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:13:23 -0800 Subject: [PATCH 12/50] fix version number --- apps/sonicclk/Changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sonicclk/Changelog b/apps/sonicclk/Changelog index 7c83f6988..1f1fc7386 100644 --- a/apps/sonicclk/Changelog +++ b/apps/sonicclk/Changelog @@ -1,2 +1,2 @@ -1.00 Added sonic clock app -1.01 Fixed text alignment issue; Increased acceleration required to activate twist; \ No newline at end of file +0.01 Added sonic clock app +0.02 Fixed text alignment issue; Increased acceleration required to activate twist; From e8db13f2882e78dd83eecb37d4037ab4ee25906a Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:13:53 -0800 Subject: [PATCH 13/50] fix version number --- apps/sonicclk/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sonicclk/metadata.json b/apps/sonicclk/metadata.json index 68a4090ed..5c907347f 100644 --- a/apps/sonicclk/metadata.json +++ b/apps/sonicclk/metadata.json @@ -1,7 +1,7 @@ { "id": "sonicclk", "name": "Sonic Clock", - "version": "1.01", + "version": "0.02", "description": "A classic sonic clock featuring run, stop and wait animations.", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], From 4ddb082bb1e574141d22815de712f21464d732c4 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:15:34 -0800 Subject: [PATCH 14/50] fix version number --- apps/teatimer/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/teatimer/metadata.json b/apps/teatimer/metadata.json index d82f10322..acace0402 100644 --- a/apps/teatimer/metadata.json +++ b/apps/teatimer/metadata.json @@ -1,7 +1,7 @@ { "id": "teatimer", "name": "Tea Timer", - "version": "1.00", + "version": "0.01", "description": "A simple timer. You can easyly set up the time.", "icon": "teatimer.png", "type": "app", From d32b518f59774049afda2d7488993643d6d5d602 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:16:26 -0800 Subject: [PATCH 15/50] fix version number --- apps/presentor/ChangeLog | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/presentor/ChangeLog b/apps/presentor/ChangeLog index 00833cf91..807f41e79 100644 --- a/apps/presentor/ChangeLog +++ b/apps/presentor/ChangeLog @@ -1,8 +1,8 @@ -0.1: Start of app. -0.5: BLE keyboard functionality. -1.0: BLE mouse functionality to scroll back/forward. -1.5: Added accelerator style mouse. -2.0: Added touchpad style mouse. -2.1: Initial internal git(hub) release. Added icon and such. -2.2: Begin work on presentation parts. -3.0: Presentation parts! \ No newline at end of file +0.01: Start of app. +0.02: BLE keyboard functionality. +0.03: BLE mouse functionality to scroll back/forward. +0.04: Added accelerator style mouse. +0.05: Added touchpad style mouse. +0.06: Initial internal git(hub) release. Added icon and such. +0.07: Begin work on presentation parts. +0.08: Presentation parts! From 1e70740fa58f108577ec3ddd206fff861b030cf2 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:16:42 -0800 Subject: [PATCH 16/50] Update metadata.json --- apps/presentor/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/presentor/metadata.json b/apps/presentor/metadata.json index 139a81d90..e5b5e289f 100644 --- a/apps/presentor/metadata.json +++ b/apps/presentor/metadata.json @@ -1,7 +1,7 @@ { "id": "presentor", "name": "Presentor", - "version": "3.0", + "version": "0.08", "description": "Use your Bangle to present!", "icon": "app.png", "type": "app", From 7f54166eb18b0a0339aae85b2f595414fa33c3c1 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:17:27 -0800 Subject: [PATCH 17/50] fix version number --- apps/pebbled/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pebbled/ChangeLog b/apps/pebbled/ChangeLog index a678cffdb..9db0e26c5 100644 --- a/apps/pebbled/ChangeLog +++ b/apps/pebbled/ChangeLog @@ -1 +1 @@ -0.1: first release +0.01: first release From e905c691192f4298eaf02a806d52219a46701919 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:17:44 -0800 Subject: [PATCH 18/50] fix version number --- apps/pebbled/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pebbled/metadata.json b/apps/pebbled/metadata.json index cf80bd73b..c16025f6f 100644 --- a/apps/pebbled/metadata.json +++ b/apps/pebbled/metadata.json @@ -2,7 +2,7 @@ "id": "pebbled", "name": "Pebble Clock with distance", "shortName": "Pebble + distance", - "version": "0.1", + "version": "0.01", "description": "Fork of Pebble Clock with distance in KM. Both step count and the distance are on the main screen. Default step length = 0.75m (can be changed in settings).", "readme": "README.md", "icon": "pebbled.png", From 7cdef418cd747b8cc2d0d76dd24ff9baed0c3cd7 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:18:41 -0800 Subject: [PATCH 19/50] Update ChangeLog --- apps/showimg/ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/showimg/ChangeLog b/apps/showimg/ChangeLog index 296bc78d0..e8d890f83 100644 --- a/apps/showimg/ChangeLog +++ b/apps/showimg/ChangeLog @@ -1,2 +1,2 @@ -0.1: Initial release -0.2: Fixed launcher image +0.01: Initial release +0.02: Fixed launcher image From 67f0cbd0b7a7326d9fba9ff99c982e30a17f0c74 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:19:03 -0800 Subject: [PATCH 20/50] fix version number --- apps/showimg/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/showimg/metadata.json b/apps/showimg/metadata.json index 56b2f5057..d5e44c0ee 100644 --- a/apps/showimg/metadata.json +++ b/apps/showimg/metadata.json @@ -2,7 +2,7 @@ "id": "showimg", "name": "simple image viewer", "shortName":"showImage", - "version":"0.2", + "version":"0.02", "description": "Displays the image in \"showimg.user.img\". The file has to be uploaded via the espruino IDE. Returns to watch face after 60s or button push. I use it to display my vaccination certificate.", "icon": "app.png", "tags": "tool", From 12ce8447dba634078f3717603d064981d425acbe Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:19:36 -0800 Subject: [PATCH 21/50] fix version number --- apps/widChargingStatus/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widChargingStatus/ChangeLog b/apps/widChargingStatus/ChangeLog index d3175e1ab..1033c0cd3 100644 --- a/apps/widChargingStatus/ChangeLog +++ b/apps/widChargingStatus/ChangeLog @@ -1 +1 @@ -0.1: First release. \ No newline at end of file +0.01: First release. From 86dcfc88540f4b6b8dd4d4cd7b7207f841bb6856 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:19:58 -0800 Subject: [PATCH 22/50] fix version number --- apps/widChargingStatus/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widChargingStatus/metadata.json b/apps/widChargingStatus/metadata.json index 84879db01..f68ccf5b4 100644 --- a/apps/widChargingStatus/metadata.json +++ b/apps/widChargingStatus/metadata.json @@ -2,7 +2,7 @@ "name": "Charging Status", "shortName":"ChargingStatus", "icon": "widget.png", - "version":"0.1", + "version":"0.01", "type": "widget", "description": "A simple widget that shows a yellow lightning icon to indicate whenever the watch is charging. This way one can see the charging status at a glance, no matter which battery widget is being used.", "tags": "widget", From e68a40c3d88ce519c4a74a9ddbf6b810c635e344 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:21:00 -0800 Subject: [PATCH 23/50] fix version number --- apps/wid_a_battery_widget/ChangeLog | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/wid_a_battery_widget/ChangeLog b/apps/wid_a_battery_widget/ChangeLog index 8a1538479..a111d259a 100644 --- a/apps/wid_a_battery_widget/ChangeLog +++ b/apps/wid_a_battery_widget/ChangeLog @@ -1,4 +1,4 @@ -1.00: Release for Bangle 2 (2021/11/18) -1.01: Internal id update to wid_* as per Gordon's request (2021/11/21) -1.02: Support dark themes -1.03: Increase screen update rate when charging +0.01: Release for Bangle 2 (2021/11/18) +0.02: Internal id update to wid_* as per Gordon's request (2021/11/21) +0.03: Support dark themes +0.04: Increase screen update rate when charging From cb78c063d1d2d39cc3ac742eade4df05983c4ba3 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:21:30 -0800 Subject: [PATCH 24/50] fix version number --- apps/wid_a_battery_widget/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wid_a_battery_widget/metadata.json b/apps/wid_a_battery_widget/metadata.json index 6095a16fe..6c507b7b3 100644 --- a/apps/wid_a_battery_widget/metadata.json +++ b/apps/wid_a_battery_widget/metadata.json @@ -3,7 +3,7 @@ "name": "A Battery Widget (with percentage)", "shortName":"A Battery Widget", "icon": "widget.png", - "version":"1.03", + "version":"0.04", "type": "widget", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", From ab3022fb24b9ffd41a6a730bfa1796a9ecc1c76d Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:21:57 -0800 Subject: [PATCH 25/50] fix version number --- apps/fd6fdetect/ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/fd6fdetect/ChangeLog b/apps/fd6fdetect/ChangeLog index b85df5ace..2ab32d15a 100644 --- a/apps/fd6fdetect/ChangeLog +++ b/apps/fd6fdetect/ChangeLog @@ -1,2 +1,2 @@ -0.1: Added source code -0.2: Added a README file +0.01: Added source code +0.02: Added a README file From c7be324693a1502117a94bc9b9090363fa4cf72b Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:22:15 -0800 Subject: [PATCH 26/50] fix version number --- apps/fd6fdetect/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/fd6fdetect/metadata.json b/apps/fd6fdetect/metadata.json index c59b19db9..d795ef8da 100644 --- a/apps/fd6fdetect/metadata.json +++ b/apps/fd6fdetect/metadata.json @@ -2,7 +2,7 @@ "id": "fd6fdetect", "name": "fd6fdetect", "shortName": "fd6fdetect", - "version": "0.2", + "version": "0.02", "description": "Allows you to see 0xFD6F beacons near you.", "icon": "app.png", "tags": "tool", From 2ef2bf612c037b4f007d644a2c23dee03ab7ebea Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:22:50 -0800 Subject: [PATCH 27/50] fix version number --- apps/mysticdock/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mysticdock/ChangeLog b/apps/mysticdock/ChangeLog index 34fe53627..eacafb944 100644 --- a/apps/mysticdock/ChangeLog +++ b/apps/mysticdock/ChangeLog @@ -1 +1 @@ -1.00: First published version. +0.01: First published version. From f330288c3bdbb0c673611a9eadaed69de1a7465f Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:23:26 -0800 Subject: [PATCH 28/50] fix version number --- apps/mysticdock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mysticdock/metadata.json b/apps/mysticdock/metadata.json index f594c2f0a..54ebedd93 100644 --- a/apps/mysticdock/metadata.json +++ b/apps/mysticdock/metadata.json @@ -1,7 +1,7 @@ { "id": "mysticdock", "name": "Mystic Dock", - "version": "1.00", + "version": "0.01", "description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.", "icon": "mystic-dock.png", "type": "dock", From 7258ff3f2cbb6372653420827852def766bb1a20 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:25:00 -0800 Subject: [PATCH 29/50] fix version number --- apps/speedalt/ChangeLog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/speedalt/ChangeLog b/apps/speedalt/ChangeLog index de5c9c221..09d33f615 100644 --- a/apps/speedalt/ChangeLog +++ b/apps/speedalt/ChangeLog @@ -5,6 +5,6 @@ 0.05: Add setting to turn vibrate on/off. 0.06: Tweaks to vibration settings. 0.07: Switch to BTN1 for Max toggle and reset function. -1.00: New features. Added waypoints file and distance to selected waypoint display. Added integration with GPS Setup module to switch GPS to low power mode when screen off. Save display settings and restore when app restarted. -1.01: Add third screen mode with large clock and waypoint selection display to ease visibility in bright daylight. -1.02: Add Kalman filter to smooth the speed and altitude values. Can be disabled in settings. +0.08: New features. Added waypoints file and distance to selected waypoint display. Added integration with GPS Setup module to switch GPS to low power mode when screen off. Save display settings and restore when app restarted. +0.09: Add third screen mode with large clock and waypoint selection display to ease visibility in bright daylight. +0.10: Add Kalman filter to smooth the speed and altitude values. Can be disabled in settings. From 3e0a6b3848421c06c5fd44d07d9f26996bdcfbb5 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:25:18 -0800 Subject: [PATCH 30/50] fix version number --- apps/speedalt/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/speedalt/metadata.json b/apps/speedalt/metadata.json index e90770985..458023278 100644 --- a/apps/speedalt/metadata.json +++ b/apps/speedalt/metadata.json @@ -2,7 +2,7 @@ "id": "speedalt", "name": "GPS Adventure Sports", "shortName": "GPS Adv Sport", - "version": "1.02", + "version": "0.10", "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", "icon": "app.png", "type": "app", From 57ee7f59d1ce45d3e060b5b60ec1db77b6c73beb Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:25:50 -0800 Subject: [PATCH 31/50] Update ChangeLog --- apps/speedalt2/ChangeLog | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/speedalt2/ChangeLog b/apps/speedalt2/ChangeLog index fa2e32f5b..09a5eb8cc 100644 --- a/apps/speedalt2/ChangeLog +++ b/apps/speedalt2/ChangeLog @@ -1,4 +1,3 @@ 0.01: Initial import. -0.07: Add swipe to change screens. -1.06: Misc memory and screen optimisations. -1.10: ... +0.02: Add swipe to change screens. +0.03: Misc memory and screen optimisations. From c2b4525ab1f18fa6a32ac61ff931bb33663393a4 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:26:08 -0800 Subject: [PATCH 32/50] fix version number --- apps/speedalt2/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/speedalt2/metadata.json b/apps/speedalt2/metadata.json index f05611338..a78039f54 100644 --- a/apps/speedalt2/metadata.json +++ b/apps/speedalt2/metadata.json @@ -2,7 +2,7 @@ "id": "speedalt2", "name": "GPS Adventure Sports II", "shortName":"GPS Adv Sport II", - "version":"1.10", + "version":"0.03", "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", "icon": "app.png", "type": "app", From 1278884cad5e61c6653b0ad9abc5098dc08b86b8 Mon Sep 17 00:00:00 2001 From: Ronin0000 <89286474+Ronin0000@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:26:48 -0800 Subject: [PATCH 33/50] this was put here on accident --- wash-hand-timer-screenshot.png | Bin 2097 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 wash-hand-timer-screenshot.png diff --git a/wash-hand-timer-screenshot.png b/wash-hand-timer-screenshot.png deleted file mode 100644 index 05859cd7a1f428a177409de20a6082093dc0a605..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2097 zcmeH}`&-g?9K}CCh+!9Dp|zTsR(k@=oXeqDYO~BpTqTN_WELW!;=~K1%r9n|^`N%4 z(0R+8Q!;^aiW70Pxme!1c)?UIi^`OkHbrM<&HVxU5B9_RoaZ^`x7QEv=j4Au30jH% z5DfrW8GIn{$db$dJzJY4l_{PvmJG%_60{dcdpC>&fHDUM288h$mhwNo8^Ny#%rLyK zQXFqCy>=uABIaJ9Wa+jxUx_O~{{GrBrqO7$sH`vi!-S#0A+13EGY-V~7li|;#^TBc zxiB^o(1!P9qhi+nAO05*N{3pj)uuLAR;~{0T|}tI1U&XB!qgr(Fp?9EvGwR%@UuQ0 zVMeM;M=v7A<5%0c<4Ca9<@+Vn>;+pV=!8EV2Cg+18msZisg6&-y@?r+M}Jj5yxPVX z9e7b>r?$&IEOZP!)3*(@IlBS(i?cr*1^fUSVAxwiYQa>td?_C;rF;e6&X_hAa}6CL z|M@lX&xSsm|BXpN9)va?FNeQ&fK<;m8V9oj`WZ<2IsP6!#se6tQXmg{qYEJ2yOTrA zdy5@>EY{g?j1*Qj!=_4r-whw;=P32q&Xm;6X*IiR&>NTUENz*lC2hx1>V5%dod`ku z`w@Irl!XXY4k(VXbmQ@=k=b|c*wWa_^-xxsldjk@fjFaPU?SE)p+nstMF_htd7&2$ z;$D^a2@(X)yX`T?=q_83RFn`RcHp~`X7tibt;mOGidxj`bhh9e%vd35RL=Ho`g6B@ z=!pmz1E8qY5dt&Qe4pw)FnF(Wg$HmfZF!_AB&{qj`DD9&L(K)n;j)t9NuTunh054B zJ8TMTvoluFl5*R=3#N~t#;mOO}tp=xr$-ngo zermYN#|tm7ikD>%*7}YlHSE||&-J~NE*(i%MsZak<5GtY$rtOp0*q#ud^j;-kKgbbf@jx@m^1=O=}!wVO*_iijXaH3%W?C ztLYnR6&WK@kBx>s2HH>PoRL<#ma0_bPkUvK(MmkAkq~cq-yj}+i2F1Q>)M-z<1@X} zPg@rmU+Whs8)7Vn0p$KrCy3~7P30oSFHCp-q;JCg9BP+LcpdS>H|yka1&K{YM*dOE zV@9_GHp}?2QN!hFwzI zsO`CZ@AdGFYGYYSnO$;d-L)#!ssM9F2lKP)SD*U!$ovR?vITWb9YYh_Z)_boqS}uk5d!vu7n(~%lf^Cq1 zc)m->TV_ Date: Wed, 19 Jan 2022 16:52:52 +0100 Subject: [PATCH 34/50] Port firmwaremake*.js to metadata.json --- bin/firmwaremaker.js | 9 +++++---- bin/firmwaremaker_c.js | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 4bc2a70b2..9f7758ee5 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -10,7 +10,6 @@ var SETTINGS = { var path = require('path'); var ROOTDIR = path.join(__dirname, '..'); var APPDIR = ROOTDIR+'/apps'; -var APPJSON = ROOTDIR+'/apps.json'; var OUTFILE = ROOTDIR+'/firmware.js'; var DEVICE = "BANGLEJS"; var APPS = [ // IDs of apps to install @@ -28,7 +27,6 @@ global.Const = { }; var AppInfo = require(ROOTDIR+"/core/js/appinfo.js"); -var appjson = JSON.parse(fs.readFileSync(APPJSON).toString()); var appfiles = []; function fileGetter(url) { @@ -58,8 +56,11 @@ function fileGetter(url) { } Promise.all(APPS.map(appid => { - var app = appjson.find(app=>app.id==appid); - if (app===undefined) throw new Error(`App ${appid} not found`); + try { + var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "metadata.json").toString()); + } catch (e) { + throw new Error(`App ${appid} not found`); + } return AppInfo.getFiles(app, { fileGetter : fileGetter, settings : SETTINGS, diff --git a/bin/firmwaremaker_c.js b/bin/firmwaremaker_c.js index 14ced9ef8..e7042d2c3 100755 --- a/bin/firmwaremaker_c.js +++ b/bin/firmwaremaker_c.js @@ -16,7 +16,6 @@ var DEVICE = process.argv[2]; var path = require('path'); var ROOTDIR = path.join(__dirname, '..'); var APPDIR = ROOTDIR+'/apps'; -var APPJSON = ROOTDIR+'/apps.json'; var MINIFY = true; var OUTFILE, APPS; @@ -86,7 +85,6 @@ function atob(input) { } var AppInfo = require(ROOTDIR+"/core/js/appinfo.js"); -var appjson = JSON.parse(fs.readFileSync(APPJSON).toString()); var appfiles = []; function fileGetter(url) { @@ -134,8 +132,11 @@ function evaluateFile(file) { } Promise.all(APPS.map(appid => { - var app = appjson.find(app=>app.id==appid); - if (app===undefined) throw new Error(`App ${appid} not found`); + try { + var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "metadata.json").toString()); + } catch (e) { + throw new Error(`App ${appid} not found`); + } return AppInfo.getFiles(app, { fileGetter : fileGetter, settings : SETTINGS, From 03f8642f77920fad8262f76f67f5b074a5363452 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Wed, 19 Jan 2022 18:25:39 +0100 Subject: [PATCH 35/50] Offer an easy way to only have a restricted apps --- apps.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 1455a2b13..4efd5318a 100644 --- a/apps.json +++ b/apps.json @@ -1,4 +1,8 @@ --- +# uncomment the following line if you only want explicitly listed +# apps to be available on your site + +# restricted: ["boot", "launch", "antonclk", "health", "setting", "about", "widbat", "widbt", "widlock", "widid"] --- {% comment %} ================================================================= @@ -12,14 +16,21 @@ ================================================================= {% endcomment %} -{%- assign apps = site.static_files | where: "name", "metadata.json" -%} +{%- if page.restricted == nil -%} + {%- assign apps = site.static_files | where: "name", "metadata.json" | map: "path" -%} +{%- else -%} + {%- capture temp -%} + {%- for app in page.restricted %} /apps/{{app}}/metadata.json {%- endfor -%} + {%- endcapture -%} + {%- assign apps = temp | strip | split: " " -%} +{%- endif -%} [ -{%- include_relative {{ apps.first.path }} -%} +{%- include_relative {{ apps.first }} -%} {%- for app in apps offset:1 -%} -,{%- include_relative {{ app.path }} -%} +,{%- include_relative {{ app }} -%} {%- endfor -%} ] From 057ca686263ff6d797e40a61c1c3177a8ea68651 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Wed, 19 Jan 2022 18:30:01 +0100 Subject: [PATCH 36/50] Moved apps.json banner to top of file --- apps.json | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/apps.json b/apps.json index 4efd5318a..822af47f2 100644 --- a/apps.json +++ b/apps.json @@ -1,21 +1,20 @@ --- -# uncomment the following line if you only want explicitly listed +# ================================================================= +# ALL THE INFORMATION INSIDE APPS.JSON HAS NOW BEEN MOVED +# +# You'll find it inside a file called apps/yourapp/metadata.json +# +# Otherwise nothing has changed. GitHub Pages will automatically +# create apps.json as your site is hosted, or if you're hosting +# yourself you can run bin/create_apps_json.sh +# +# ================================================================= + +# Uncomment the following line if you only want explicitly listed # apps to be available on your site # restricted: ["boot", "launch", "antonclk", "health", "setting", "about", "widbat", "widbt", "widlock", "widid"] --- -{% comment %} -================================================================= - ALL THE INFORMATION INSIDE APPS.JSON HAS NOW BEEN MOVED - - You'll find it inside a file called apps/yourapp/metadata.json - - Otherwise nothing has changed. GitHub Pages will automatically - create apps.json as your site is hosted, or if you're hosting - yourself you can run bin/create_apps_json.sh - -================================================================= -{% endcomment %} {%- if page.restricted == nil -%} {%- assign apps = site.static_files | where: "name", "metadata.json" | map: "path" -%} {%- else -%} From e4c18eea20601601ff43f313dfdcd7bc7f211c78 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Wed, 19 Jan 2022 18:57:04 +0100 Subject: [PATCH 37/50] Update app.js --- apps/daysl/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/daysl/app.js b/apps/daysl/app.js index 56f85e615..af6486b1f 100644 --- a/apps/daysl/app.js +++ b/apps/daysl/app.js @@ -26,7 +26,7 @@ function showMenu() { '': { 'title': 'Set Date', 'predraw': function() { - datemenu.Date.value = settings.day; + datemenu.Day.value = settings.day; datemenu.Month.value = settings.month; datemenu.Year.value = settings.year; } @@ -64,4 +64,4 @@ function showMenu() { return E.showMenu(datemenu); } -showMenu(); \ No newline at end of file +showMenu(); From 5ba78438b35ce7c0782e92d18f16c5058d1651b7 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Wed, 19 Jan 2022 19:01:46 +0100 Subject: [PATCH 38/50] Update app.js --- apps/daysl/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/daysl/app.js b/apps/daysl/app.js index af6486b1f..51b5a84ad 100644 --- a/apps/daysl/app.js +++ b/apps/daysl/app.js @@ -65,3 +65,4 @@ function showMenu() { } showMenu(); + From 75b2a1e7ffecc21fb9725139acaaa4428a6c3625 Mon Sep 17 00:00:00 2001 From: Hilmar Strauch <56518493+HilmarSt@users.noreply.github.com> Date: Wed, 19 Jan 2022 19:35:11 +0100 Subject: [PATCH 39/50] Update metadata.json --- apps/daysl/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/daysl/metadata.json b/apps/daysl/metadata.json index f68e0e8ac..3dfeea745 100644 --- a/apps/daysl/metadata.json +++ b/apps/daysl/metadata.json @@ -5,7 +5,7 @@ "description": "Shows you the days left until a certain date. Date can be set with a settings app and is written to a file.", "icon": "app.png", "tags": "", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS", "BANGLEJS2"], "allow_emulator": false, "storage": [ {"name":"daysl.app.js","url":"app.js"}, From c4946c7a3cbe29321149f191d6996f5effae8484 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 19 Jan 2022 22:45:16 +0000 Subject: [PATCH 40/50] set widget sortorder through code for widpa,widpb,widbata,widlock --- apps/widbata/ChangeLog | 1 + apps/widbata/metadata.json | 2 +- apps/widbata/widbata.wid.js | 2 +- apps/widlock/ChangeLog | 1 + apps/widlock/metadata.json | 2 +- apps/widlock/widget.js | 2 +- apps/widpa/ChangeLog | 1 + apps/widpa/metadata.json | 2 +- apps/widpa/widpa.wid.js | 2 +- apps/widpb/ChangeLog | 1 + apps/widpb/metadata.json | 2 +- apps/widpb/widpb.wid.js | 2 +- 12 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/widbata/ChangeLog b/apps/widbata/ChangeLog index 42293a3aa..f23705341 100644 --- a/apps/widbata/ChangeLog +++ b/apps/widbata/ChangeLog @@ -1,2 +1,3 @@ 0.01: Created 0.02: Set sort order to -10 so always display in right hand corner +0.03: Set sort order from the code diff --git a/apps/widbata/metadata.json b/apps/widbata/metadata.json index fcfafd04e..12dc17012 100644 --- a/apps/widbata/metadata.json +++ b/apps/widbata/metadata.json @@ -4,7 +4,7 @@ "shortName":"Battery Theme", "icon": "widbata.png", "screenshots": [{"url":"screenshot_widbata_1.png"}], - "version":"0.02", + "version":"0.03", "type": "widget", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", diff --git a/apps/widbata/widbata.wid.js b/apps/widbata/widbata.wid.js index 1c04bf8ae..1de4c2fe9 100644 --- a/apps/widbata/widbata.wid.js +++ b/apps/widbata/widbata.wid.js @@ -2,7 +2,7 @@ setInterval(()=>WIDGETS["bata"].draw(), 60000); Bangle.on('lcdPower', function(on) { if (on) WIDGETS["bata"].draw(); }); -WIDGETS["bata"]={area:"tr",width:27,draw:function() { +WIDGETS["bata"]={area:"tr",sortorder:-10,width:27,draw:function() { var s = 26; var t = 13; // thickness var x = this.x, y = this.y; diff --git a/apps/widlock/ChangeLog b/apps/widlock/ChangeLog index 2ac70f875..bb84c2d44 100644 --- a/apps/widlock/ChangeLog +++ b/apps/widlock/ChangeLog @@ -3,3 +3,4 @@ 0.03: Don't try to be fancy - just bail out on firmwares without a lock event 0.04: Set sortorder to -1 so that widget always takes up the furthest left position 0.05: Set sortorder to -10 so that others can take -1 etc +0.06: Set sortorder to -10 in widget code diff --git a/apps/widlock/metadata.json b/apps/widlock/metadata.json index 0f642b192..35ec6c1c6 100644 --- a/apps/widlock/metadata.json +++ b/apps/widlock/metadata.json @@ -1,7 +1,7 @@ { "id": "widlock", "name": "Lock Widget", - "version": "0.05", + "version": "0.06", "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", "icon": "widget.png", "type": "widget", diff --git a/apps/widlock/widget.js b/apps/widlock/widget.js index 4c59e6575..06fc574f1 100644 --- a/apps/widlock/widget.js +++ b/apps/widlock/widget.js @@ -4,7 +4,7 @@ WIDGETS["lock"].width = Bangle.isLocked()?16:0; Bangle.drawWidgets(); }); - WIDGETS["lock"]={area:"tl",width:Bangle.isLocked()?16:0,draw:function(w) { + WIDGETS["lock"]={area:"tl",sortorder:-10,width:Bangle.isLocked()?16:0,draw:function(w) { if (Bangle.isLocked()) g.reset().drawImage(atob("DhABH+D/wwMMDDAwwMf/v//4f+H/h/8//P/z///f/g=="), w.x+1, w.y+4); }}; diff --git a/apps/widpa/ChangeLog b/apps/widpa/ChangeLog index eb7e543a5..4a8809923 100644 --- a/apps/widpa/ChangeLog +++ b/apps/widpa/ChangeLog @@ -1,3 +1,4 @@ 0.01: First release 0.02: Size widget after step count is reset 0.03: set sortorder to -1 +0.04: set sortorder through code diff --git a/apps/widpa/metadata.json b/apps/widpa/metadata.json index 9fd9311c1..bc3ee2241 100644 --- a/apps/widpa/metadata.json +++ b/apps/widpa/metadata.json @@ -4,7 +4,7 @@ "shortName":"Simple Pedometer", "icon": "screenshot_widpa.png", "screenshots": [{"url":"screenshot_widpa.png"}], - "version":"0.03", + "version":"0.04", "type": "widget", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", diff --git a/apps/widpa/widpa.wid.js b/apps/widpa/widpa.wid.js index 1c0f27394..8cde29bc1 100644 --- a/apps/widpa/widpa.wid.js +++ b/apps/widpa/widpa.wid.js @@ -2,7 +2,7 @@ Bangle.on('step', function(s) { WIDGETS["widpa"].draw(); }); Bangle.on('lcdPower', function(on) { if (on) WIDGETS["widpa"].draw(); }); -WIDGETS["widpa"]={area:"tl",width:13,draw:function() { +WIDGETS["widpa"]={area:"tl",sortorder:-1,width:13,draw:function() { if (!Bangle.isLCDOn()) return; // dont redraw if LCD is off var steps = Bangle.getHealthStatus("day").steps; var w = 1 + (steps.toString().length)*12; diff --git a/apps/widpb/ChangeLog b/apps/widpb/ChangeLog index 8f8b3c5e4..8a4a48b56 100644 --- a/apps/widpb/ChangeLog +++ b/apps/widpb/ChangeLog @@ -2,3 +2,4 @@ 0.02: Fixed widget id to wibpb, Size widget after step count is reset 0.03: Fixed widget id in onStep() come on get it right! 0.04: set sortorder to -1 +0.05: set sortorder through code diff --git a/apps/widpb/metadata.json b/apps/widpb/metadata.json index 222b96c83..9c7fc07df 100644 --- a/apps/widpb/metadata.json +++ b/apps/widpb/metadata.json @@ -4,7 +4,7 @@ "shortName":"Lato Pedometer", "icon": "screenshot_widpb.png", "screenshots": [{"url":"screenshot_widpb.png"}], - "version":"0.04", + "version":"0.05", "type": "widget", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", diff --git a/apps/widpb/widpb.wid.js b/apps/widpb/widpb.wid.js index cd830ae4f..ceebb9937 100644 --- a/apps/widpb/widpb.wid.js +++ b/apps/widpb/widpb.wid.js @@ -3,7 +3,7 @@ Bangle.on('step', function(s) { WIDGETS["widpb"].draw(); }); Bangle.on('lcdPower', function(on) { if (on) WIDGETS["widpb"].draw(); }); -WIDGETS["widpb"]={area:"tl",width:13,draw:function() { +WIDGETS["widpb"]={area:"tl",sortorder:-1,width:13,draw:function() { if (!Bangle.isLCDOn()) return; // dont redraw if LCD is off var steps = Bangle.getHealthStatus("day").steps; var w = 1 + (steps.toString().length)*12; From 3670ff2170005dcdde8e47b9df2a7ac6bf12204e Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 19 Jan 2022 23:09:52 +0000 Subject: [PATCH 41/50] set widget sortorder through code for widpa,widpb,widbata,widlock --- apps/widlock/metadata.json | 2 +- apps/widlock/widget.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widlock/metadata.json b/apps/widlock/metadata.json index 35ec6c1c6..468d6b1e0 100644 --- a/apps/widlock/metadata.json +++ b/apps/widlock/metadata.json @@ -7,7 +7,7 @@ "type": "widget", "tags": "widget,lock", "supports": ["BANGLEJS","BANGLEJS2"], - "sortorder": -10, + "sortorder": 10, "storage": [ {"name":"widlock.wid.js","url":"widget.js"} ] diff --git a/apps/widlock/widget.js b/apps/widlock/widget.js index 06fc574f1..592361cd9 100644 --- a/apps/widlock/widget.js +++ b/apps/widlock/widget.js @@ -4,7 +4,7 @@ WIDGETS["lock"].width = Bangle.isLocked()?16:0; Bangle.drawWidgets(); }); - WIDGETS["lock"]={area:"tl",sortorder:-10,width:Bangle.isLocked()?16:0,draw:function(w) { + WIDGETS["lock"]={area:"tl",sortorder:10,width:Bangle.isLocked()?16:0,draw:function(w) { if (Bangle.isLocked()) g.reset().drawImage(atob("DhABH+D/wwMMDDAwwMf/v//4f+H/h/8//P/z///f/g=="), w.x+1, w.y+4); }}; From b9522a3b652ead8dffce08030b03cb10f715f89f Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 19 Jan 2022 23:19:35 +0000 Subject: [PATCH 42/50] set widget sortorder through code for widpa,widpb,widbata,widlock --- apps/widbata/metadata.json | 1 - apps/widlock/metadata.json | 1 - apps/widpa/metadata.json | 1 - apps/widpb/metadata.json | 1 - 4 files changed, 4 deletions(-) diff --git a/apps/widbata/metadata.json b/apps/widbata/metadata.json index 12dc17012..d8149d13f 100644 --- a/apps/widbata/metadata.json +++ b/apps/widbata/metadata.json @@ -10,7 +10,6 @@ "readme": "README.md", "description": "Shows the current battery level status in the top right using the clocks colour theme", "tags": "widget,battery", - "sortorder": -10, "storage": [ {"name":"widbata.wid.js","url":"widbata.wid.js"} ] diff --git a/apps/widlock/metadata.json b/apps/widlock/metadata.json index 468d6b1e0..8635a5434 100644 --- a/apps/widlock/metadata.json +++ b/apps/widlock/metadata.json @@ -7,7 +7,6 @@ "type": "widget", "tags": "widget,lock", "supports": ["BANGLEJS","BANGLEJS2"], - "sortorder": 10, "storage": [ {"name":"widlock.wid.js","url":"widget.js"} ] diff --git a/apps/widpa/metadata.json b/apps/widpa/metadata.json index bc3ee2241..95a8a8a9c 100644 --- a/apps/widpa/metadata.json +++ b/apps/widpa/metadata.json @@ -10,7 +10,6 @@ "readme": "README.md", "description": "Displays the current step count from `Bangle.getHealthStatus(\"day\").steps` in 12x16 font, requires firmware v2.11.21 or later", "tags": "widget,battery", - "sortorder": -1, "storage": [ {"name":"widpa.wid.js","url":"widpa.wid.js"} ] diff --git a/apps/widpb/metadata.json b/apps/widpb/metadata.json index 9c7fc07df..0c2ed747a 100644 --- a/apps/widpb/metadata.json +++ b/apps/widpb/metadata.json @@ -10,7 +10,6 @@ "readme": "README.md", "description": "Displays the current step count from `Bangle.getHealthStatus(\"day\").steps` in the Lato font, requires firmware v2.11.21 or later", "tags": "widget,battery", - "sortorder": -1, "storage": [ {"name":"widpb.wid.js","url":"widpb.wid.js"} ] From 5e40f67fd7603a81743678bac6872d635e7889d3 Mon Sep 17 00:00:00 2001 From: EmVee381 Date: Thu, 20 Jan 2022 04:22:23 +0100 Subject: [PATCH 43/50] initial cs_CZ support --- lang/cs_CZ.json | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ lang/index.json | 1 + 2 files changed, 54 insertions(+) create mode 100644 lang/cs_CZ.json diff --git a/lang/cs_CZ.json b/lang/cs_CZ.json new file mode 100644 index 000000000..3f4fc87f1 --- /dev/null +++ b/lang/cs_CZ.json @@ -0,0 +1,53 @@ +{ + "//":"Czech language translations", + "GLOBAL": { + "//":"Translations that apply for all apps", + "Alarm" : "Budík", + "Hour" : "Hodina", + "Hours" : "Hodiny", + "Minute" : "Minuta", + "Minutes" : "Minuty", + "Second" : "Sekunda", + "Seconds" : "Sekundy", + "Month" : "Měsíc", + "Enabled" : "Povoleno", + "Background" : "Pozadí", + "Connected" : "Připojeno", + "Settings" : "Nastavení", + "Save" : "Uložit", + "Back" : "Zpět", + "Repeat" : "Opakovat", + "Delete" : "Smazat", + "Sleep" : "Uspat", + "Alarms" : "Budíky", + "ALARM!" : "BUDÍK!", + + " (repeat)" : " (opakovat)", + "< Back" : "< Zpět", + "> Delete" : "> Smazat", + "> Save" : " > Uložit", + "ALARM " : "BUDÍK ", + + "Add Device" : "Přidat zařízení", + "App Settings" : "Nast. Aplikací", + "Apps" : "Aplikace" + + }, + "alarm": { + "//":"App-specific overrides", + "Alarm/Timer" : "Budik/Časovač", + "rpt" : "Opk.", + "New Alarm" : "Nový budík", + "New Timer" : "Nový časovač", + "Auto snooze" : "Auto odložit" + }, + "setting" : { + "Quiet Mode" : "Tichý režim" + + }, + "messages": { + "Are you sure?" : "Opravdu?" + } + + +} diff --git a/lang/index.json b/lang/index.json index f17bf5e03..3d492783d 100644 --- a/lang/index.json +++ b/lang/index.json @@ -1,5 +1,6 @@ [ {"code":"en_GB","name":"British English","url":"en_GB.json"}, + {"code":"cs_CZ","name":"Czech","url":"cs_CZ.json"}, {"code":"de_DE","name":"German","url":"de_DE.json"}, {"code":"es_ES","name":"Spanish","url":"es_ES.json"}, {"code":"fi_FI","name":"Finnish","url":"fi_FI.json"}, From 72e9a576e04d9535c32d8e87024733f524260310 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 20 Jan 2022 17:07:56 +0000 Subject: [PATCH 44/50] fix regression in metadata --- apps/widbatpc/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widbatpc/metadata.json b/apps/widbatpc/metadata.json index 718b7e083..7da4e3e0c 100644 --- a/apps/widbatpc/metadata.json +++ b/apps/widbatpc/metadata.json @@ -9,7 +9,7 @@ "tags": "widget,battery", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", - "screenshots": [{"url":"widbatpc.full.jpg"},{"widbatpc.part.jpg"}], + "screenshots": [{"url":"widbatpc.full.jpg"},{"url":"widbatpc.part.jpg"}], "storage": [ {"name":"widbatpc.wid.js","url":"widget.js"}, {"name":"widbatpc.settings.js","url":"settings.js"} From e997ad59ed3635c59710b7afedbf294f3cd2c644 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 20 Jan 2022 17:08:31 +0000 Subject: [PATCH 45/50] more compatible app loader --- bin/apploader.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/bin/apploader.js b/bin/apploader.js index 6b4c2202d..427a0ef99 100755 --- a/bin/apploader.js +++ b/bin/apploader.js @@ -13,6 +13,7 @@ for Noble. var SETTINGS = { pretokenise : true }; +var APPSDIR = __dirname+"/../apps/"; var Utils = require("../core/js/utils.js"); var AppInfo = require("../core/js/appinfo.js"); var noble; @@ -29,18 +30,27 @@ if (!noble) { console.log(" npm install noble") } -var apps; +var apps = []; function ERROR(msg) { console.error(msg); process.exit(1); } -try { - apps = JSON.parse(require("fs").readFileSync(__dirname+"/../apps.json")); -} catch(e) { - ERROR("'apps.json' could not be loaded"); -} +var apps = []; +var dirs = require("fs").readdirSync(APPSDIR, {withFileTypes: true}); +dirs.forEach(dir => { + var appsFile; + if (dir.name.startsWith("_example") || !dir.isDirectory()) + return; + try { + appsFile = require("fs").readFileSync(APPSDIR+dir.name+"/metadata.json").toString(); + } catch (e) { + ERROR(dir.name+"/metadata.json does not exist"); + return; + } + apps.push(JSON.parse(appsFile)); +}); var args = process.argv; From a3b49a0d824625d847e7cc7fff3ab9dab7ff5bfd Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Wed, 19 Jan 2022 20:19:56 +0100 Subject: [PATCH 46/50] Support for localhost appstore - Adds a script to generate `apps.local.json` from all metadata - Makes the loader use `apps.local.json` when serving from localhost - Adds npm `local` script to watch for changed metadata, while serving from localhost --- .gitignore | 2 +- bin/update_local_apps_json.js | 62 +++++++++++++++++++++++++++++++++++ core | 2 +- loader.js | 5 +++ package.json | 8 +++++ 5 files changed, 77 insertions(+), 2 deletions(-) create mode 100755 bin/update_local_apps_json.js diff --git a/.gitignore b/.gitignore index 273fdeae4..523dc5f20 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ appdates.csv _config.yml tests/Layout/bin/tmp.* tests/Layout/testresult.bmp -apps.json +apps.local.json \ No newline at end of file diff --git a/bin/update_local_apps_json.js b/bin/update_local_apps_json.js new file mode 100755 index 000000000..3ba54f289 --- /dev/null +++ b/bin/update_local_apps_json.js @@ -0,0 +1,62 @@ +#!/usr/bin/nodejs +/* Merge all apps/metadata.json files into apps.local.json +*/ + +const fs = require("fs"); + +const BASEDIR = __dirname+"/../"; +const APPSDIR = BASEDIR+"apps/"; +const APPSFILE = "apps.local.json"; +const APPSPATH = BASEDIR+ APPSFILE; + +function ERROR(s) { + console.error("ERROR: "+s); + process.exit(1); +} +function INFO(s) { + console.info(s); +} + +const apps = []; +const dirs = fs.readdirSync(APPSDIR, {withFileTypes: true}); +dirs.forEach(dir => { + let appsFile; + if (dir.name.startsWith("_example")) { + return; + } + try { + appsFile = fs.readFileSync(APPSDIR+dir.name+"/metadata.json").toString(); + } catch(e) { + return; + } + try { + apps.push(JSON.parse(appsFile)); + } catch(e) { + console.log(e); + const m = e.toString().match(/in JSON at position (\d+)/); + if (m) { + const char = parseInt(m[1]); + console.log("==============================================="); + console.log("LINE "+appsFile.substr(0, char).split("\n").length); + console.log("==============================================="); + console.log(appsFile.substr(char-10, 20)); + console.log("==============================================="); + } + console.log(m); + ERROR(dir.name+"/metadata.json not valid JSON"); + } +}); +// order doesn't matter as the loader sorts apps, but sort by anyway +apps.sort((a, b) => ((0|a.sortorder)-(0|b.sortorder)) || a.id.localeCompare(b.id)); +const json = JSON.stringify(apps, null, 2); +let update = false; +if (fs.existsSync(APPSPATH)) { + const old = fs.readFileSync(APPSPATH).toString(); + if (old===json) { + INFO(`${APPSFILE} is already up-to-date`); + process.exit(); + } + update = true; +} +fs.writeFileSync(APPSPATH, json); +INFO(`${update ? 'Updated' : 'Wrote'} ${APPSFILE}`); \ No newline at end of file diff --git a/core b/core index 5023ee122..3093d78a5 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 5023ee1228030130ba9f026d5dbe920f7527ee7d +Subproject commit 3093d78a5d752cbf03ea8f9a1a7c0b50b9c8123b diff --git a/loader.js b/loader.js index 0355ea89c..d8ba26269 100644 --- a/loader.js +++ b/loader.js @@ -5,6 +5,11 @@ if (window.location.host=="banglejs.com") { document.title += " [Development]"; document.getElementById("apploaderlinks").innerHTML = 'This is the development Bangle.js App Loader - you can also try the Official Version for stable apps.'; +} else if (window.location.hostname==='localhost') { + document.title += " [Local]"; + Const.APPS_JSON_FILE = "apps.local.json"; + document.getElementById("apploaderlinks").innerHTML = + 'This is your local Bangle.js App Loader - you can try the Official Version here.'; } else { document.title += " [Unofficial]"; document.getElementById("apploaderlinks").innerHTML = diff --git a/package.json b/package.json index b796044c9..aa1b0b88a 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,17 @@ "scripts": { "lint-apps": "eslint ./apps --ext .js", "test": "node bin/sanitycheck.js && eslint ./apps --ext .js", + "update-local-apps": "node bin/update_local_apps_json.js", + "local": "npm-watch & npx http-server -a localhost -c-1", "start": "npx http-server -c-1" }, + "watch": { + "update-local-apps": "apps/*/metadata.json" + }, "dependencies": { "acorn": "^7.2.0" + }, + "devDpendencies": { + "npm-watch": "^0.11.0" } } From e75a828fce5f6cb243ce93c98a60f2ca44bebecf Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 20 Jan 2022 20:22:58 +0100 Subject: [PATCH 47/50] always use shell script to generate apps.json, remove js version Gets rid of duplicated functionality, but allows passing a filename argument to write to a different file instead of `apps.json`. --- apps.json | 5 ++- bin/create_apps_json.sh | 17 +++++++--- bin/update_local_apps_json.js | 62 ----------------------------------- package.json | 2 +- 4 files changed, 18 insertions(+), 68 deletions(-) delete mode 100755 bin/update_local_apps_json.js diff --git a/apps.json b/apps.json index 822af47f2..537a4f697 100644 --- a/apps.json +++ b/apps.json @@ -7,7 +7,10 @@ # Otherwise nothing has changed. GitHub Pages will automatically # create apps.json as your site is hosted, or if you're hosting # yourself you can run bin/create_apps_json.sh -# +# +# If you serve the store from localhost for development/testing, +# the loader looks for apps.local.json instead, you can run +# `bin/create_apps_json.sh apps.local.json` to create that file. # ================================================================= # Uncomment the following line if you only want explicitly listed diff --git a/bin/create_apps_json.sh b/bin/create_apps_json.sh index adc5f8a62..d61f7afe1 100755 --- a/bin/create_apps_json.sh +++ b/bin/create_apps_json.sh @@ -13,17 +13,26 @@ # # If you do this, please do not attempt to commit your modified # apps.json back into the main BangleApps repository! +# +# You can pass an optional filename to this script, and it will write +# to that instead, apps.local.json is used when opening the loader on localhost +outfile="${1:-apps.json}" cd `dirname $0`/.. -echo "[" > apps.json +echo "[" > "$outfile" +first=1 for app in apps/*/; do echo "Processing $app..."; if [[ "$app" =~ ^apps/_example.* ]]; then echo "Ignoring $app" else - cat ${app}metadata.json >> apps.json + if [ $first -eq 1 ]; then + first=0; + else + echo "," >> "$outfile" + fi; + cat ${app}metadata.json >> "$outfile" # echo ",\"$app\"," >> apps.json # DEBUG ONLY - echo "," >> apps.json fi done -echo "null]" >> apps.json +echo "]" >> "$outfile" diff --git a/bin/update_local_apps_json.js b/bin/update_local_apps_json.js deleted file mode 100755 index 3ba54f289..000000000 --- a/bin/update_local_apps_json.js +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/nodejs -/* Merge all apps/metadata.json files into apps.local.json -*/ - -const fs = require("fs"); - -const BASEDIR = __dirname+"/../"; -const APPSDIR = BASEDIR+"apps/"; -const APPSFILE = "apps.local.json"; -const APPSPATH = BASEDIR+ APPSFILE; - -function ERROR(s) { - console.error("ERROR: "+s); - process.exit(1); -} -function INFO(s) { - console.info(s); -} - -const apps = []; -const dirs = fs.readdirSync(APPSDIR, {withFileTypes: true}); -dirs.forEach(dir => { - let appsFile; - if (dir.name.startsWith("_example")) { - return; - } - try { - appsFile = fs.readFileSync(APPSDIR+dir.name+"/metadata.json").toString(); - } catch(e) { - return; - } - try { - apps.push(JSON.parse(appsFile)); - } catch(e) { - console.log(e); - const m = e.toString().match(/in JSON at position (\d+)/); - if (m) { - const char = parseInt(m[1]); - console.log("==============================================="); - console.log("LINE "+appsFile.substr(0, char).split("\n").length); - console.log("==============================================="); - console.log(appsFile.substr(char-10, 20)); - console.log("==============================================="); - } - console.log(m); - ERROR(dir.name+"/metadata.json not valid JSON"); - } -}); -// order doesn't matter as the loader sorts apps, but sort by anyway -apps.sort((a, b) => ((0|a.sortorder)-(0|b.sortorder)) || a.id.localeCompare(b.id)); -const json = JSON.stringify(apps, null, 2); -let update = false; -if (fs.existsSync(APPSPATH)) { - const old = fs.readFileSync(APPSPATH).toString(); - if (old===json) { - INFO(`${APPSFILE} is already up-to-date`); - process.exit(); - } - update = true; -} -fs.writeFileSync(APPSPATH, json); -INFO(`${update ? 'Updated' : 'Wrote'} ${APPSFILE}`); \ No newline at end of file diff --git a/package.json b/package.json index aa1b0b88a..32c96e3ea 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "lint-apps": "eslint ./apps --ext .js", "test": "node bin/sanitycheck.js && eslint ./apps --ext .js", - "update-local-apps": "node bin/update_local_apps_json.js", + "update-local-apps": "./bin/create_apps_json.sh apps.local.json", "local": "npm-watch & npx http-server -a localhost -c-1", "start": "npx http-server -c-1" }, From 46fbccf71123a96497d84251bdd31b17afe2ec8b Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 20 Jan 2022 20:39:06 +0100 Subject: [PATCH 48/50] tell git to ignore modified `apps.json` when running create_apps.json.sh Only if no arguments given: `create_apps_json.sh apps.json` will leave it alone if someone really wants to overwrite+commit apps.json. --- bin/create_apps_json.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bin/create_apps_json.sh b/bin/create_apps_json.sh index d61f7afe1..dd883b22a 100755 --- a/bin/create_apps_json.sh +++ b/bin/create_apps_json.sh @@ -36,3 +36,13 @@ for app in apps/*/; do fi done echo "]" >> "$outfile" + +if [ -z "$1"]; then + # Running with no arguments: prevent accidental commit of modified apps.json. + # You can use `create_apps.json.sh apps.json` if you really want to both + # overwrite and still commit apps.json + git update-index --skip-worktree apps.json + echo "Told git to ignore modified apps.json." + # If you want to unignore it, use + # 'git update-index --no-skip-worktree apps.json' +fi \ No newline at end of file From 3b80c5e6a6c377eba14aaf6c0d6ed055f9d27164 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 20 Jan 2022 23:29:37 +0000 Subject: [PATCH 49/50] Pastel: remove dependancy on widpedom --- apps/pastel/ChangeLog | 2 ++ apps/pastel/metadata.json | 6 +++--- apps/pastel/pastel.app.js | 16 +++++++++------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog index 00090fcd1..c81d0cacc 100644 --- a/apps/pastel/ChangeLog +++ b/apps/pastel/ChangeLog @@ -9,3 +9,5 @@ 0.09: Added dependancy on Pedometer Widget 0.10: Added Weather line, fixed issues on a Bangle 1, update every minute 0.11: Changed cycle on minute to prevInfo to avoid the 2nd one being the blank line +0.12: Removed dependancy on widpedom, now uses Bangle.getHealthStatus("day").steps + which requires 2.11.27 firmware to reset at midnight diff --git a/apps/pastel/metadata.json b/apps/pastel/metadata.json index ff0d11256..1a311599c 100644 --- a/apps/pastel/metadata.json +++ b/apps/pastel/metadata.json @@ -2,10 +2,10 @@ "id": "pastel", "name": "Pastel Clock", "shortName": "Pastel", - "version": "0.11", - "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", + "version": "0.12", + "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times. Requires firmware 2.11.27", "icon": "pastel.png", - "dependencies": {"mylocation":"app", "widpedom":"app","weather":"app"}, + "dependencies": {"mylocation":"app","weather":"app"}, "screenshots": [{"url":"screenshot_pastel.png"}, {"url":"weather_icons.png"}], "type": "clock", "tags": "clock, weather, tool", diff --git a/apps/pastel/pastel.app.js b/apps/pastel/pastel.app.js index 3e64cdd9c..d9dfb0da5 100644 --- a/apps/pastel/pastel.app.js +++ b/apps/pastel/pastel.app.js @@ -64,13 +64,15 @@ function loadFonts() { require("f_lato").add(Graphics); } -function stepsWidget() { - if (WIDGETS.activepedom !== undefined) { - return WIDGETS.activepedom; - } else if (WIDGETS.wpedom !== undefined) { - return WIDGETS.wpedom; +function getSteps() { + try { + return Bangle.getHealthStatus("day").steps; + } catch (e) { + if (WIDGETS.wpedom !== undefined) + return WIDGETS.wpedom.getSteps(); + else + return '???' } - return undefined; } const infoData = { @@ -79,7 +81,7 @@ const infoData = { ID_DAY: { calc: () => {var d = require("locale").dow(new Date).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} }, ID_SR: { calc: () => 'Sunrise: ' + sunRise }, ID_SS: { calc: () => 'Sunset: ' + sunSet }, - ID_STEP: { calc: () => 'Steps: ' + stepsWidget().getSteps() }, + ID_STEP: { calc: () => 'Steps: ' + getSteps() }, ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' }, ID_MEM: { calc: () => {var val = process.memory(); return 'Ram: ' + Math.round(val.usage*100/val.total) + '%';} }, ID_ID: { calc: () => {var val = NRF.getAddress().split(':'); return 'Id: ' + val[4] + val[5];} }, From dbdd731511eda6c007ae08efa3c8d199e6df4fa3 Mon Sep 17 00:00:00 2001 From: Bela Date: Fri, 21 Jan 2022 11:46:13 +0100 Subject: [PATCH 50/50] add timerclk app --- apps/timerclk/ChangeLog | 1 + apps/timerclk/README.md | 72 ++++++ apps/timerclk/alarm.alert.js | 57 +++++ apps/timerclk/alarm.info | 1 + apps/timerclk/alarm.js | 116 ++++++++++ apps/timerclk/app-icon.js | 1 + apps/timerclk/app-icon.png | Bin 0 -> 9025 bytes apps/timerclk/app.js | 151 ++++++++++++ apps/timerclk/boot.js | 48 ++++ apps/timerclk/lib.js | 127 +++++++++++ apps/timerclk/metadata.json | 38 +++ apps/timerclk/pause-24.png | Bin 0 -> 4688 bytes apps/timerclk/play-24.png | Bin 0 -> 4761 bytes apps/timerclk/remove-24.png | Bin 0 -> 4753 bytes apps/timerclk/reset-24.png | Bin 0 -> 4724 bytes apps/timerclk/screenshot.png | Bin 0 -> 18113 bytes apps/timerclk/screenshot_settings1.png | Bin 0 -> 3189 bytes apps/timerclk/screenshot_settings2.png | Bin 0 -> 3348 bytes apps/timerclk/screenshot_settings3.png | Bin 0 -> 3425 bytes apps/timerclk/screenshot_stopwatch1.png | Bin 0 -> 14735 bytes apps/timerclk/screenshot_stopwatch2.png | Bin 0 -> 14382 bytes apps/timerclk/settings.js | 292 ++++++++++++++++++++++++ apps/timerclk/stopwatch.info | 1 + apps/timerclk/stopwatch.js | 135 +++++++++++ apps/timerclk/timer.alert.js | 62 +++++ apps/timerclk/timer.info | 1 + apps/timerclk/timer.js | 139 +++++++++++ apps/timerclk/wid.js | 7 + 28 files changed, 1249 insertions(+) create mode 100644 apps/timerclk/ChangeLog create mode 100644 apps/timerclk/README.md create mode 100644 apps/timerclk/alarm.alert.js create mode 100644 apps/timerclk/alarm.info create mode 100644 apps/timerclk/alarm.js create mode 100644 apps/timerclk/app-icon.js create mode 100644 apps/timerclk/app-icon.png create mode 100644 apps/timerclk/app.js create mode 100644 apps/timerclk/boot.js create mode 100644 apps/timerclk/lib.js create mode 100644 apps/timerclk/metadata.json create mode 100644 apps/timerclk/pause-24.png create mode 100644 apps/timerclk/play-24.png create mode 100644 apps/timerclk/remove-24.png create mode 100644 apps/timerclk/reset-24.png create mode 100644 apps/timerclk/screenshot.png create mode 100644 apps/timerclk/screenshot_settings1.png create mode 100644 apps/timerclk/screenshot_settings2.png create mode 100644 apps/timerclk/screenshot_settings3.png create mode 100644 apps/timerclk/screenshot_stopwatch1.png create mode 100644 apps/timerclk/screenshot_stopwatch2.png create mode 100644 apps/timerclk/settings.js create mode 100644 apps/timerclk/stopwatch.info create mode 100644 apps/timerclk/stopwatch.js create mode 100644 apps/timerclk/timer.alert.js create mode 100644 apps/timerclk/timer.info create mode 100644 apps/timerclk/timer.js create mode 100644 apps/timerclk/wid.js diff --git a/apps/timerclk/ChangeLog b/apps/timerclk/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/timerclk/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/timerclk/README.md b/apps/timerclk/README.md new file mode 100644 index 000000000..fd6d2b16b --- /dev/null +++ b/apps/timerclk/README.md @@ -0,0 +1,72 @@ +# Timer Clock + +A clock based on the Anton Clock with stopwatches, timers and alarms based on the Stopwatch Touch style and an alarm widget based on the one from Default alarm & timer. + +## Features + +* two slots for stopwatches / timers on the clock screen +* configurable font and size (Anton font has fixed size) +* stopwatch with modifiable start value +* timer that can be paused +* alarms +* multiple stopwatches, timers and alarms +* stopwatches and timers keep running in the background + +## Images + +![](screenshot.png) + +### Stopwatch + +![](screenshot_stopwatch1.png) + +![](screenshot_stopwatch2.png) + +### Settings + +![](screenshot_settings1.png) + +![](screenshot_settings2.png) + +![](screenshot_settings3.png) + +## Controls + +### Bangle.js 1 + +#### Clock + +* Left: Stopwatch +* Right: Timer +* Button 1 / 2: Alarm + +#### Stopwatch / Timer / Alarm + +* Button 1: + * edit mode: increase + * control mode: play / pause +* Button 2: switch between edit / control mode +* Button 3: + * edit mode: decrease + * control mode: reset / remove +* Left: + * edit mode: previous index + * control mode: previous stopwatch / timer / alarm +* Right: + * edit mode: next index + * control mode: next stopwatch / timer / alarm + +### Bangle.js 2 + +#### Clock + +* Swipe left: Stopwatch +* Swipe right: Timer +* Swipe over date: Alarm + +#### Stopwatch / Timer / Alarm + +* Swipe left: previous stopwatch / timer / alarm +* Swipe right: next stopwatch / timer / alarm +* Swipe up: increase index swiped over +* Swipe down: decrease index swiped over \ No newline at end of file diff --git a/apps/timerclk/alarm.alert.js b/apps/timerclk/alarm.alert.js new file mode 100644 index 000000000..f4b61822a --- /dev/null +++ b/apps/timerclk/alarm.alert.js @@ -0,0 +1,57 @@ +if (timerclkAlarmTimeout) clearInterval(timerclkAlarmTimeout); +var timerclk = require("timerclk.lib.js"); +var settings = require('Storage').readJSON("timerclk.json", true) || {}; +settings = Object.assign({ + "vibrate":10 +}, settings.alarm||{}); + +function showAlarm(alarm) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + Bangle.setLocked(false); + E.showPrompt("Alarm!",{ + title:"ALARM!", + buttons : {/*LANG*/"Ok":true} + }).then(function(ok) { + buzzCount = 0; + if (ok) { + alarm.last = new Date().getDate(); + } + require("Storage").write("timerclk.alarm.json",JSON.stringify(alarms)); + load(); + }); + function vibrate(counter) { + VIBRATE.write(1); + setTimeout(() => VIBRATE.write(0), 100); + if (--counter) setTimeout(() => vibrate(counter), 250); + } + function buzz() { + if ((require('Storage').readJSON('setting.json',1)||{}).quiet>1) return; // total silence + vibrate(4); + if (buzzCount--) + setTimeout(buzz, 3000); + else { // auto-snooze + buzzCount = settings.vibrate; + setTimeout(buzz, 600000); + } + } + var buzzCount = settings.vibrate; + buzz(); +} + +// Check for alarms +console.log("checking for alarms..."); +var alarms = require("Storage").readJSON("timerclk.alarm.json",1)||[]; +var active = alarms.filter(e=>e.on); +if (active.length) { + // if there's an alarm, show it + active = active.sort((a,b)=>(a.time-b.time)+(a.last-b.last)*86400000); + if (active[0].last != new Date().getDate()) { + showAlarm(active[0]); + } else { + setTimeout(load, 100); + } +} else { + // otherwise just go back to default app + setTimeout(load, 100); +} diff --git a/apps/timerclk/alarm.info b/apps/timerclk/alarm.info new file mode 100644 index 000000000..1289f8cef --- /dev/null +++ b/apps/timerclk/alarm.info @@ -0,0 +1 @@ +{"id":"timerclk","name":"tclk Alarm","src":"timerclk.alarm.js","icon":"timerclk.img","version":"0.01","tags":"","files":"","sortorder":10} diff --git a/apps/timerclk/alarm.js b/apps/timerclk/alarm.js new file mode 100644 index 000000000..4acaa6cf0 --- /dev/null +++ b/apps/timerclk/alarm.js @@ -0,0 +1,116 @@ +var timerclk = require("timerclk.lib.js"); +const height = g.getHeight(), width = g.getWidth(); + +var all = require("Storage").readJSON("timerclk.alarm.json") || []; +var settings = require('Storage').readJSON("timerclk.json", true) || {}; +settings = Object.assign({ + "font":"Vector", + "fontSize":40, + "indexFont":"6x8", + "indexFontSize":3, + "buttonHeight":40, + "vibrate":4, +}, settings = settings.alarm||{}); +var defaultElement = {time:43200000, on:true, last:null}; + +var current = 0; +var editIndex = 0; +var drawInterval; +var drawIntervalTimeout; +var buttons; +var dragBorderHrsMins=0, dragBorderMinsSecs=0; + +function update() { + if (drawInterval) clearInterval(drawInterval); + if (drawIntervalTimeout) clearTimeout(drawIntervalTimeout); + if (all[current].start) { + drawIntervalTimeout = setTimeout(() => {drawInterval = setInterval(draw, 1000); draw();}, 1000 - (timerclk.getTime(all[current]) % 1000)); + } else { + drawInterval = null; + drawIntervalTimeout = null; + } + draw(); + drawButtons(); +} +function activate() { + all[current].on = !all[current].on; + all[current].last = null; + update(); + require("Storage").write("timerclk.alarm.json",JSON.stringify(all)); + timerclkCheckAlarms(); +} +function remove() { + all.splice(current, 1); + if (current == all.length) current--; + if (all.length == 0) { + all.push(defaultElement.clone()); + current++; + } + update(); + require("Storage").write("timerclk.alarm.json",JSON.stringify(all)); + timerclkCheckAlarms(); +} + +function edit(position, change) { + if (position == 1) all[current].time += change*1000; + else if (position == 2) all[current].time += change*60000; + else if (position == 3) all[current].time += change*3600000; + require("Storage").write("timerclk.alarm.json",JSON.stringify(all)); + timerclkCheckAlarms(); +} + +var buttons = { + reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: remove, img: timerclk.remove_img, col:"#f50"}, // remove + play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: activate, img: timerclk.play_img, col:"#0ff"}, // active +}; + + +function drawButtons() { + if (all[current].on) { + buttons.play.img = timerclk.pause_img; + } else { + buttons.play.img = timerclk.play_img; + } + for (var button of buttons) { + g.setColor(button.col); + g.fillRect(button.pos[0], button.pos[1], button.pos[2], button.pos[3]); + g.setColor("#000"); + // scale 24px images + let iw = settings.buttonHeight-10; + var scale = iw/24; + let ix = button.pos[0] + ((button.pos[2]-button.pos[0] - iw) /2); + let iy = button.pos[1] + ((button.pos[3]-button.pos[1] - iw) /2); + g.drawImage(button.img, ix, iy, {scale: scale}); + } +} + +function draw() { + var x = g.getWidth()/2; + var y = g.getHeight()/2; + g.reset(); + + g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2-settings.buttonHeight); + g.setFontAlign(0,0).setFont(settings.indexFont, settings.indexFontSize); + g.drawString(current+1, x, Bangle.appRect.y + (g.stringMetrics("0").height/2)); + g.setFontAlign(0,0).setFont(settings.font, settings.fontSize); + var timeStr = timerclk.formatTime(all[current].time, false, false, true); + g.drawString(timeStr,x,y); + var start = (width-g.stringMetrics(timeStr).width)/2; + timeStr = timeStr.split(":"); + var markerPosChange = g.stringMetrics("__").width/2; + if (editIndex == 3) x = start + g.stringMetrics(timeStr[0]).width - markerPosChange; + else if (editIndex == 2) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]).width - markerPosChange; + else if (editIndex == 1) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]+":"+timeStr[2]).width - markerPosChange; + else x = 0; + if (x) g.drawString("__", x, y); + dragBorderHrsMins = start+g.stringMetrics(timeStr[0]).width+g.stringMetrics(":").width/2; + dragBorderMinsSecs = start+g.stringMetrics(timeStr[0]+":"+timeStr[1]).width+g.stringMetrics(":").width/2; +} + +if (all.length == 0) { + all.push(defaultElement.clone()); +} +timerclk.registerControls(this); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +update(); diff --git a/apps/timerclk/app-icon.js b/apps/timerclk/app-icon.js new file mode 100644 index 000000000..278cf4bb6 --- /dev/null +++ b/apps/timerclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgP/AFHzvmf+f8z/8tnv/vs9/1t/v+kv94jR/H4n/wn4CBAYPwnEP8AFDg/AAoUwAoPgmABBwfQAonwAo0/4gFC4AFE4gFLmGEAoQDBxgFCwEQAIIFIj4FD/k//hNBAoZZBAoc8j6oS8/P+1NAoP63+7+wMCz/u/YEB/v/v4dI1+pAQIFBx/J/2/AoP5tFJr71eA==")) diff --git a/apps/timerclk/app-icon.png b/apps/timerclk/app-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..074db4ed7da57867d5206fc76fccea500cd7b3f9 GIT binary patch literal 9025 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 bmI+RfWKUa0v@{Eiae$GYxo*iR*RcNq2S*`S literal 0 HcmV?d00001 diff --git a/apps/timerclk/app.js b/apps/timerclk/app.js new file mode 100644 index 000000000..eeb3ac4cd --- /dev/null +++ b/apps/timerclk/app.js @@ -0,0 +1,151 @@ +Graphics.prototype.setFontAnton = function(scale) { +// Actual height 69 (68 - 0) + g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78+(scale<<8)+(1<<16)); +}; + +var timerclk = require("timerclk.lib.js"); +var settings = require('Storage').readJSON("timerclk.json", true) || {}; +settings = Object.assign({ + "timeFont":"Anton", + "timeFontSize":0, + "dateFont":"6x8", + "dateFontSize":2, + "dowFont":"6x8", + "dowFontSize":2, + "specialFont":"6x8", + "specialFontSize":2, + "shortDate":true, + "showStopwatches":true, + "showTimers":true, +}, settings.clock||{}); + +var stopwatches = [], timers = []; +if (settings.showStopwatches) { + stopwatches = require("Storage").readJSON("timerclk.stopwatch.json") || []; + stopwatches = stopwatches.filter(e=>e.start||e.time); +} +if (settings.showTimers) { + timers = require("Storage").readJSON("timerclk.timer.json") || []; + timers = timers.filter(e=>e.start||e.timeAdd); +} + +// timeout used to update every minute +var drawTimeout; +var drawSpecialTimeout; +// border between time and date/dow +var dragBorder = g.getHeight()/2; + +// schedule a draw for the next minute +function queueDraw(timeout, interval, func) { + if (timeout) clearTimeout(timeout); + timeout = setTimeout(function() { + timeout = undefined; + func(); + }, interval - (Date.now() % interval)); +} + +function drawSpecial() { + var interval = 60000; + var stopwatch = 0, timer = 0, time; + var x = g.getWidth()/4; + g.setColor(g.theme.fg); + g.setFontAlign(0,0).setFont(settings.specialFont, settings.specialFontSize); + var y = Bangle.appRect.y + g.stringMetrics("00:00").height/2; + g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y+g.stringMetrics("00:00").height); + + if (stopwatches.length) { + time = timerclk.getTime(stopwatches[stopwatch]); + g.drawString(timerclk.formatTime(time, true), x, y); + if (Math.floor(time/3600000) === 0) interval = 1000; + stopwatch++; + } else if (timers.length > 1) { + time = timers[timer].time - timerclk.getTime(timers[timer]); + g.drawString(timerclk.formatTime(time, true), x, y); + if (Math.floor(time/3600000) === 0) interval = 1000; + timer++; + } + x += g.getWidth()/2; + if (timers.length) { + time = timers[timer].time - timerclk.getTime(timers[timer]); + g.drawString(timerclk.formatTime(time, true), x, y); + if (Math.floor(time/3600000) === 0) interval = 1000; + } else if (stopwatches.length > 1) { + time = timerclk.getTime(stopwatches[stopwatch]); + g.drawString(timerclk.formatTime(time, true), x, y); + if (Math.floor(time/3600000) === 0) interval = 1000; + } + queueDraw(drawSpecialTimeout, interval, drawSpecial); +} + +function draw() { + var x = g.getWidth()/2; + var y = g.getHeight()/2; + g.reset(); + var date = new Date(); + var timeStr = require("locale").time(date,1); + var dateStr = require("locale").date(date,settings.shortDate).toUpperCase(); + var dowStr = require("locale").dow(date).toUpperCase(); + + // draw time + if (settings.timeFont == "Anton") { + g.setFontAlign(0,0).setFont("Anton"); + } else { + g.setFontAlign(0,0).setFont(settings.timeFont, settings.timeFontSize); + } + g.clearRect(Bangle.appRect.x, x-g.stringMetrics(timeStr).height/2, Bangle.appRect.x2, Bangle.appRect.y2); // clear the background + g.drawString(timeStr,x,y); + // draw date + y += g.stringMetrics(timeStr).height/2; + g.setFontAlign(0,0).setFont(settings.dateFont, settings.dateFontSize); + dragBorder = y; + y += g.stringMetrics(dateStr).height/2; + g.drawString(dateStr,x,y); + //draw day of week + y += g.stringMetrics(dateStr).height/2; + g.setFontAlign(0,0).setFont(settings.dowFont, settings.dowFontSize); + y += g.stringMetrics(dowStr).height/2; + g.drawString(dowStr,x,y); + // queue draw in one minute + queueDraw(drawTimeout, 60000, draw); +} + +if (process.env.HWVERSION==1) { + setWatch(()=>load("timerclk.stopwatch.js"), BTN4); + setWatch(()=>load("timerclk.timer.js"), BTN5); + setWatch(()=>load("timerclk.alarm.js"), BTN3); + setWatch(()=>load("timerclk.alarm.js"), BTN1); +} else { + var absY, lastX, lastY; + Bangle.on('drag', e=>{ + if (!e.b) { + if (lastX > 50) { // right + if (absY < dragBorder) { // drag over time + load("timerclk.timer.js"); + }else { // drag over date/dow + load("timerclk.alarm.js"); + } + } else if (lastX < -50) { // left + if (absY < dragBorder) { // drag over time + load("timerclk.stopwatch.js"); + }else { // drag over date/dow + load("timerclk.alarm.js"); + } + } else if (lastY > 50) { // down + } else if (lastY < -50) { // up + } + lastX = 0; + lastY = 0; + } else { + lastX = lastX + e.dx; + lastY = lastY + e.dy; + absY = e.y; + } + }); +} + +Bangle.setUI("clock"); // Show launcher when middle button pressed +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +draw(); +if (stopwatches || timers) drawSpecial(); diff --git a/apps/timerclk/boot.js b/apps/timerclk/boot.js new file mode 100644 index 000000000..9a09f68f3 --- /dev/null +++ b/apps/timerclk/boot.js @@ -0,0 +1,48 @@ +var timerclkTimerTimeout; +var timerclkAlarmTimeout; +function timerclkCheckTimers() { + if (timerclkTimerTimeout) clearTimeout(timerclkTimerTimeout); + var timers = require('Storage').readJSON('timerclk.timer.json',1)||[]; + timers = timers.filter(e=>e.start); + if (timers.length) { + timers = timers.sort((a,b)=>{ + var at = a.timeAdd; + if (a.start) at += Date.now()-a.start; + at = a.period-at; + var bt = b.timeAdd; + if (b.start) bt += Date.now()-b.start; + bt = b.period-bt; + return at-bt; + }); + if (!require('Storage').read("timerclk.timer.alert.js")) { + console.log("No timer app!"); + } else { + var time = timers[0].timeAdd; + if (timers[0].start) time += Date.now()-timers[0].start; + time = timers[0].time - time; + if (time<1000) t=1000; + if (timerclkTimerTimeout) clearTimeout(timerclkTimerTimeout); + timerclkTimerTimeout = setTimeout(() => load("timerclk.timer.alert.js"),time); + } + } +} +function timerclkCheckAlarms() { + if (timerclkAlarmTimeout) clearTimeout(timerclkAlarmTimeout); + var alarms = require('Storage').readJSON('timerclk.alarm.json',1)||[]; + var currentTime = require("timerclk.lib.js").getCurrentTime(); + alarms = alarms.filter(e=>e.on); + if (alarms.length) { + alarms = alarms.sort((a,b)=>(a.time-b.time)+(a.last-b.last)*86400000); + if (!require('Storage').read("timerclk.alarm.alert.js")) { + console.log("No alarm app!"); + } else { + var time = alarms[0].time-currentTime; + if (alarms[0].last == new Date().getDate() || time < 0) time += 86400000; + if (time<1000) t=1000; + if (timerclkAlarmTimeout) clearTimeout(timerclkAlarmTimeout); + timerclkAlarmTimeout = setTimeout(() => load("timerclk.alarm.alert.js"),time); + } + } +} +timerclkCheckTimers(); +timerclkCheckAlarms(); diff --git a/apps/timerclk/lib.js b/apps/timerclk/lib.js new file mode 100644 index 000000000..718962fe0 --- /dev/null +++ b/apps/timerclk/lib.js @@ -0,0 +1,127 @@ +exports.pause_img = atob("GBiBAf///////////+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B+D/B////////////w=="); +exports.play_img = atob("GBiBAf////////////P///D///A///Af//AH//AB//AAf/AAH/AAB/AAB/AAH/AAf/AB//AH//Af//A///D///P//////////////w=="); +exports.reset_img = atob("GBiBAf////////////AAD+AAB+f/5+f/5+f/5+cA5+cA5+cA5+cA5+cA5+cA5+cA5+cA5+f/5+f/5+f/5+AAB/AAD////////////w=="); +exports.remove_img = atob("GBiBAf///////////+P/x+H/h+D/B/B+D/g8H/wYP/4Af/8A//+B//+B//8A//4Af/wYP/g8H/B+D+D/B+H/h+P/x////////////w=="); + +exports.formatTime = function(t, short, tnthEnable, fullTime) { + var negative = ""; + if (t < 0) { + t = t*(-1); + negative = "-"; + } + let hrs = Math.floor(t/3600000); + let mins = Math.floor(t/60000)%60; + let secs = Math.floor(t/1000)%60; + var tnth = ""; + if (tnthEnable) { + tnth = Math.floor(t/100)%10; + tnth = "."+tnth; + } + var hrsStr = hrs; + if (hrs < 10 && !negative) hrsStr = "0"+hrs; + var text; + if (short) { + if (hrs === 0) text = negative + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2); + else text = negative + hrsStr + "/" + ("0"+mins).substr(-2); + } else { + if (hrs === 0 && !fullTime) text = negative + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2) + tnth; + else text = negative + hrsStr + ":" + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2); + } + return text; +}; + +exports.getTime = function(e) { + var time = e.timeAdd; + if (e.start) { + time += Date.now() - e.start; + } + return time; +}; + +exports.getCurrentTime = function() { + var date = new Date(); + return date.getHours()*3600000+date.getMinutes()*60000+date.getSeconds()*1000+date.getMilliseconds(); +}; + +exports.registerControls = function(o) { + if (process.env.HWVERSION==1) { + setWatch(()=>{ + if (o.editIndex == 0) o.buttons.play.callback(); + else o.edit(o.editIndex, 1); + o.draw(); + }, BTN1, {repeat:true}); + setWatch(()=>{ + o.editIndex = !o.editIndex; + o.draw(); + }, BTN2, {repeat:true}); + setWatch(()=>{ + if (o.editIndex == 0) o.buttons.reset.callback(); + else o.edit(o.editIndex, -1); + o.draw(); + }, BTN3, {repeat:true}); + setWatch(()=>{ + if (o.editIndex) { + o.editIndex++; + if (o.editIndex > 3) o.editIndex = 1; + } else if (o.current > 0) o.current--; + o.update(); + }, BTN4, {repeat:true}); + setWatch(()=>{ + if (o.editIndex) { + o.editIndex--; + if (o.editIndex < 1) o.editIndex = 3; + } else { + o.current++; + if (o.current == o.all.length) o.all.push(o.defaultElement.clone()); + } + o.update(); + }, BTN5, {repeat:true}); + } else { + setWatch(()=>load(), BTN1); + Bangle.on('touch',(n,e)=>{ + for (var button of o.buttons) { + if (e.x>=button.pos[0] && e.y>=button.pos[1] && + e.x{ + if (!e.b) { + if (lastX > 40) { // right + o.current++; + if (o.current == o.all.length) o.all.push(o.defaultElement.clone()); + } else if (lastX < -40) { // left + if (o.current > 0) { + o.current--; + } + } else if (lastY > 30) { // down + if (absX < o.dragBorderHrsMins) { + o.edit(3, -1); + } else if (absX > o.dragBorderHrsMins && absX < o.dragBorderMinsSecs) { + o.edit(2, -1); + } else { + o.edit(1, -1); + } + } else if (lastY < -30) { // up + if (absX < o.dragBorderHrsMins) { + o.edit(3, 1); + } else if (absX > o.dragBorderHrsMins && absX < o.dragBorderMinsSecs) { + o.edit(2, 1); + } else { + o.edit(1, 1); + } + } + lastX = 0; + lastY = 0; + o.update(); + } else { + absX = e.x; + lastX = lastX + e.dx; + lastY = lastY + e.dy; + } + }); + } +}; diff --git a/apps/timerclk/metadata.json b/apps/timerclk/metadata.json new file mode 100644 index 000000000..6b415c0fc --- /dev/null +++ b/apps/timerclk/metadata.json @@ -0,0 +1,38 @@ +{ + "id": "timerclk", + "name": "Timer Clock", + "shortName":"Timer Clock", + "version":"0.01", + "description": "A clock with stopwatches, timers and alarms build in.", + "icon": "app-icon.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS","BANGLEJS2"], + "screenshots": [ + {"url":"screenshot.png"}, + {"url":"screenshot_stopwatch1.png"}, + {"url":"screenshot_stopwatch2.png"}, + {"url":"screenshot_settings1.png"}, + {"url":"screenshot_settings2.png"}, + {"url":"screenshot_settings3.png"} + ], + "readme": "README.md", + "storage": [ + {"name":"timerclk.app.js","url":"app.js"}, + {"name":"timerclk.img","url":"app-icon.js","evaluate":true}, + {"name":"timerclk.boot.js","url":"boot.js"}, + {"name":"timerclk.lib.js","url":"lib.js"}, + {"name":"timerclk.wid.js","url":"wid.js"}, + {"name":"timerclk.settings.js","url":"settings.js"}, + {"name":"timerclk.stopwatch.js","url":"stopwatch.js"}, + {"name":"timerclk.timer.js","url":"timer.js"}, + {"name":"timerclk.timer.alert.js","url":"timer.alert.js"}, + {"name":"timerclk.alarm.js","url":"alarm.js"}, + {"name":"timerclk.alarm.alert.js","url":"alarm.alert.js"}, + {"name":"timerclk.stopwatch.info","url":"stopwatch.info"}, + {"name":"timerclk.timer.info","url":"timer.info"}, + {"name":"timerclk.alarm.info","url":"alarm.info"} + ], + "data": [{"name":"timerclk.json"},{"name":"timerclk.stopwatch.json"},{"name":"timerclk.timer.json"},{"name":"timerclk.alarm.json"}], + "sortorder": 0 +} diff --git a/apps/timerclk/pause-24.png b/apps/timerclk/pause-24.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff72e906976e641cfb698780e56411b8eb52501 GIT binary patch literal 4688 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 HlQRATsbuV8 literal 0 HcmV?d00001 diff --git a/apps/timerclk/play-24.png b/apps/timerclk/play-24.png new file mode 100644 index 0000000000000000000000000000000000000000..26fa8d99cfb7dc07295e2ac8b1c38a89397f9018 GIT binary patch literal 4761 zcmeHLdss|c8=n-zRLbqBMBC&OvgbZiGn$kdHDxlVnIpufJu`c1XfExUYKjnv)TtAP z2*+I|<&w~GD^6b_r_hCnB*cS4pOQ;w%@peS&Oe^#JO4HF?3uma^{(G~-{1RN?=x$X zgaJO51Umu_hqL7SdIy4U8^bkp2>5J_=62$6gI>jo=j#HIXh?&p<%)0=(#2>{2-Pd( zIGn!zWrpXb<|!7uj-8U!5dP4lMDa#dh+o-* zi}Eh>q{A7%)|{&jWF1(feVmx64qcji06zL=MNIpR0&c^2i_LqszOA{&{ETD;Hy*KD z*u^XVP;-1{boGj7ACj$iZ%OdEF(E^EJ|UrU`0r-*MMv_)r;qyIPAj-@Vdmx4PQ3I_ zcV4Pn6I(1x-7c*ddL=Qi8S`j*ILXp-AzE5oAZQ_6ljaO9KkM3%b7{YA{*%*df6KlH z$ExQZJxN>Q)%>sW$N3NHM?LdjfA4Ku-S&bd@XAv=b_ObzC#`hT4&S}(`h4EC!Fx${ z`zH7=fK%>Ld2?P4i$&>fgkixHbMW%F!;A4D|=Y_T~r8MUhpyLtS1z<83}edIX1 zie0Gf;uPl&9@*#6mB~LPy86Cb$2EU&p(^u~iko-Go^EwXIC;b1j}A}UZ&^J_+3#`k z{dnijQu~s`ah@bU3)2yqLBhzvo#{(NnlaYZ8!-Fyjm59B{>X1{6+q@EL-y=*uY~TL zF|#Jl$!cfYSFci>Zbxj7 zPw*RIx?`HKxohij?aYB3{s>5rni!+E|}c>Yu8H3f!G-nuzw3|*UByU6WqY=pMs zc^)=qQRYJb!smsxwUp4c*yTD)(}j0qGPtdo?@ru(wY(v??A^1XW#oq6JL>N?PBiT( zn{qiZjZ^Q5KXo(RihC7V@9^KSQNc>T%$VoXZyl=S+!egM)CG61wp(1SPv00HC0bka zVxnint}u!zC1AV9y+I}{2EO3>)X?ErNqBCGXs?A6bDJeW0&TOB>}n6m=$vHN{CVtY z+54n%-9gyYs!zY%i&nK}|J-T&Jo$DE!7+PBWBcCjw*TC3Dti^YYh~T*TV0OrBf5sh zCAiOW*qc`6Fp2TH%pntxxSZ$qu0$9 z9h^1>@4UfPmL2eeH_yJ1z{|E?x^CY1Isfj$3+y(H9_v$5*w|PpsVOO45QGo%wEk!k zp~C`o=_6bH39#f`o8IARgI3?_?vb6bT^^ZYnyK26k)noD{nk|vcGu)SnLfnKyJ>-Z8|(Fu*X@Utn)^bBRV= z4!Ad%$wbKLqFcr#&KC$FFExfj3=)Gxfq8mG6piRkfZQ;doD=9hyB7jHafx9%orXgu zM@L7KqUj_x7D}eF*=#a}MyAnV-~nr6R60ZttF(>=h#m}YR4c_48l6I|f()35L>;N) z5{Y0O`VyZ~BM^LrS801$0DO@3h=xohQOHUqx$g|Eju!<$dIS2~8Co%D=;T0DtB%B^ zC@%_C=^Xn)`0xe7uLy>eLKRAlF)2V^zr|$IuYQ_HEZpcLlakSJR0%+}AUR)?shr~wLqlN11lDV4KbSrQt|l(Hx= zgF!)HHVVL85hjC0VKW&hL(&IgE~WsgM8f+J)B?#f0bFoViqzzkH%2GO7{ zFv_A+geiA1LK*77@f7m8L>h_m%_0m(baFMOf>2F3SkUW7*UJoRjWaD{OQ zf{e1|Akv;iv`7>xGcE+?^$bbF5LGA&_IIzKzStFiS1gvqg~6uNUMf&y zVo4Y*8AC#sA#7HEbgf#hi$*ZiGZbVBvH=1zW&=$zay+%acXSwPAdmv~HiZgP*kTHm zL#1&jOlNRIp%BTv36l-G`b)-c-Yj5{)x#joWe&?dfW zV)ct1qt2BkhYpG)<`!oOciuktN3D3q7038zH>NxtL%SmGC~xA07nQuXwu&pPh^m`LjaS`~?jZ6H@>H literal 0 HcmV?d00001 diff --git a/apps/timerclk/remove-24.png b/apps/timerclk/remove-24.png new file mode 100644 index 0000000000000000000000000000000000000000..b59505bcbcb1c3d4d00c2ed30bc77013bd1ccbdb GIT binary patch literal 4753 zcmeI0X;c$g7RQ4igeWSgBj7@eCrL6 z$qx+{S&{5X1OmZI93Th--?sQcGzXs#()k?(!l0L#5mEXuB%Q3$s^y9ljI7VlU}Vgo zkP`@oyD!%Hu6gV{RM=iBT^TPX=0A$3S!XYXyXGV1Dc4wx%~a%CC?^1&L37kx&8{KEIXPVduBoDpMQR~Gxwaj z{P|VY!Yp@z+W9&0?L^11fvYc>Qd~f7a`lJrrLXd>@C_K2Q7H%4wp5&xA|;n8RvDoWZ&|lA%3w{ zLVi*8?DdDv3f8|jJ5g;nA$Lh-%3#pa0@^TR-0VFV=`H8H0a_T;%Y9Jvh?DcZKtL>z%~s3j&`9b~l+-`wW@l^6c%< zH7kM$6LS=~Oh+;y$uTgOgK{Wl4JH*esYP`j#8ocCxxYtmU$jEE{+!eFWEaJ z${uvtVt3kRiac6R&*Ht=B7&c{ZJVH!?v{v|Asex~@1hfq?Tn2&^~51`+fVk?F#0uB zQY$+vAT-9wzK&23K4ruqpG8)eYf^L2&DQTO|5T8xqX4`rn-*>2E-=|sS%~qWUx`^3J zy!;%t{9G?;o%GJaQquW)MEBq>)BC37#ofNQ4iE??OBDY8p<;jkFO?7Ky)=6@Kj3WW zsN9h7GMCX7uFJTxir{|;gyRm9gcT!_a%YX7G54c|#D2}FF`}A-4<1~V-mIyOj z5#32F?znZEpBmm+YbaXSy!qztmTBf@f``%a^_Z~>z41B?kODi1AF6}+=BBiPoXQbk6bKie@q?v z^j#rVb=`jYpr4|0%&bYfoVN@eOTU{MHf?*W=gUV9+RrveMrjLAU)Z;Z#JW)B&^dg; z)ms-sf(_z7xb+_%avdi5B#ueEG4AQ7JM-+FeA?^|H_Yh@9KZg9DO zhF|y(v=+AW8M5%SGBPxAvqjU@)(zD@-BA7hmdlkHE3aFSCHn)L2o_6EC;nJ{JG-gz zrq`i`StV~jnbc%!RbSAb3wC7HoP)k-%+rj}xE2BijcDgwdN+n_WdJGC81vlcuENhrN)>P5U-yz8T!>uld4TI+Q?8UmVzk(R0rat z_p{e4hK0t!c=L=rHnMwMV(f^Q2CBm;y+ z@Hz!#<2cBL=dZ;Oy;>WgR;TbOcw}T8X)JHDXV0btD0ILg1F!hrnh(e3^<4Gb0x1gP z6q#%+TONY;IME?#n9S%1tm~OV6A@Jc2JY|Pg8DM9_>0Yg*)WHT!g7egVS~+LqAUoZ zv89lV1q6}OnOqKw)1R(W%k}Aq7V}L2nSyLU0U5I)I~z5g+TS`o5yJ(ffqR=qhiGsF zjn1RNJT}`EKcP{my$MtCyZTGUp49)*#M5ZdrwxF0J!7D~fNn+o+OB#v!)5#%U%h+r zH+lf*0Vm(3?|@tba($Nq-(@^dT?2A`mjd5qJWyT#H@QgP9(XVn_!X269%o8zG6TV* zkhwHSBp`I-?_W=puLUEPnt*5>fiPqwewYwSO7Z`AEc9ZD(4xh}l3?jRxyi*J45`Ed z--v+oFA9B!5hfB%$9Hunv?sF0nwW&VmmgSBzqOL@93S0&c~f3om96E3*OuDA1Dk3B zPEQObUCXpCEqheC#%%aMc>>7|7V%u@lS?neC!4m0tqnqF^AgKKgduM%lV{{lnQ4>P e_E?u`+d=4jWM@n8ZQBSu6U4$`L6u*8&VK=8xcs01 literal 0 HcmV?d00001 diff --git a/apps/timerclk/reset-24.png b/apps/timerclk/reset-24.png new file mode 100644 index 0000000000000000000000000000000000000000..73fb28dec1e37e92ad8c107879295272790fe34d GIT binary patch literal 4724 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 literal 0 HcmV?d00001 diff --git a/apps/timerclk/screenshot_settings1.png b/apps/timerclk/screenshot_settings1.png new file mode 100644 index 0000000000000000000000000000000000000000..da187e49625eef735f752b8864a27fa6869ae7b8 GIT binary patch literal 3189 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 bi~@fFzTOr28Eo&E00000NkvXXu0mjfyK~@# literal 0 HcmV?d00001 diff --git a/apps/timerclk/screenshot_settings2.png b/apps/timerclk/screenshot_settings2.png new file mode 100644 index 0000000000000000000000000000000000000000..4b12848d0953df90200e3d3fb91b25cb03296616 GIT binary patch literal 3348 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 D`=nbc literal 0 HcmV?d00001 diff --git a/apps/timerclk/screenshot_stopwatch1.png b/apps/timerclk/screenshot_stopwatch1.png new file mode 100644 index 0000000000000000000000000000000000000000..f50d7a1d11c9c5030163023711e6507c71f07d92 GIT binary patch literal 14735 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 literal 0 HcmV?d00001 diff --git a/apps/timerclk/screenshot_stopwatch2.png b/apps/timerclk/screenshot_stopwatch2.png new file mode 100644 index 0000000000000000000000000000000000000000..89f91ae1bf2a5cc8b8126dc2ef7c7072020527c3 GIT binary patch literal 14382 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 literal 0 HcmV?d00001 diff --git a/apps/timerclk/settings.js b/apps/timerclk/settings.js new file mode 100644 index 000000000..556dded98 --- /dev/null +++ b/apps/timerclk/settings.js @@ -0,0 +1,292 @@ +(function(back) { + const FILE = "timerclk.json"; + const BOOL_FORMAT = v=>v?/*LANG*/"On":/*LANG*/"Off"; + // Load settings + var settings = require('Storage').readJSON(FILE, true) || {} + settings.clock = Object.assign({ + "timeFont":"Anton", + "timeFontSize":0, + "dateFont":"6x8", + "dateFontSize":2, + "dowFont":"6x8", + "dowFontSize":2, + "specialFont":"6x8", + "specialFontSize":2, + "shortDate":true, + "showStopwatches":true, + "showTimers":true, + }, settings.clock||{}); + settings.stopwatch = Object.assign({ + "font":"Vector", + "fontSize":40, + "indexFont":"6x8", + "indexFontSize":3, + "buttonHeight":40, + }, settings.stopwatch||{}); + settings.timer = Object.assign({ + "font":"Vector", + "fontSize":40, + "indexFont":"6x8", + "indexFontSize":3, + "buttonHeight":40, + "vibrate":10, + }, settings.timer||{}); + settings.alarm = Object.assign({ + "font":"Vector", + "fontSize":40, + "indexFont":"6x8", + "indexFontSize":3, + "buttonHeight":40, + "vibrate":10, + }, settings.alarm||{}); + var timeFonts = ["Anton"].concat(g.getFonts()); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + // Show the menu + var mainMenu = { + "" : { "title" : "Timer Clock" }, + "< Back" : () => back(), + "Clock": ()=>{E.showMenu(clockMenu);}, + "Stopwatch": ()=>{E.showMenu(stopwatchMenu);}, + "Timer": ()=>{E.showMenu(timerMenu);}, + "Alarm": ()=>{E.showMenu(alarmMenu);}, + }; + var clockMenu = { + "" : { "title" : "Clock" }, + "< Back" : () => E.showMenu(mainMenu), + "time font":{ + value: 0|timeFonts.indexOf(settings.clock.timeFont), + format: v => timeFonts[v], + min: 0, max: timeFonts.length-1, + onchange: v => { + settings.clock.timeFont = timeFonts[v]; + writeSettings(); + } + }, + "time size":{ + value: 0|settings.clock.timeFontSize, + min: 0, + onchange: v => { + settings.clock.timeFontSize = v; + writeSettings(); + } + }, + "date font":{ + value: 0|g.getFonts().indexOf(settings.clock.dateFont), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.clock.dateFont = g.getFonts()[v]; + writeSettings(); + } + }, + "date size":{ + value: 0|settings.clock.dateFontSize, + min: 0, + onchange: v => { + settings.clock.dateFontSize = v; + writeSettings(); + } + }, + "dow font":{ + value: 0|g.getFonts().indexOf(settings.clock.dowFont), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.clock.dowFont = g.getFonts()[v]; + writeSettings(); + } + }, + "dow size":{ + value: 0|settings.clock.dowFontSize, + min: 0, + onchange: v => { + settings.clock.dowFontSize = v; + writeSettings(); + } + }, + "short date": { + value: !!settings.clock.shortDate, + format: BOOL_FORMAT, + onchange: v => { + settings.clock.shortDate = v; + writeSettings(); + } + }, + "stopwatches": { + value: !!settings.clock.showStopwatches, + format: v=>v?/*LANG*/"Show":/*LANG*/"Hide", + onchange: v => { + settings.clock.showStopwatches = v; + writeSettings(); + } + }, + "timers": { + value: !!settings.clock.showTimers, + format: v=>v?/*LANG*/"Show":/*LANG*/"Hide", + onchange: v => { + settings.clock.showTimers = v; + writeSettings(); + } + }, + }; + + var stopwatchMenu = { + "" : { "title" : "Stopwatch" }, + "< Back" : () => E.showMenu(mainMenu), + "font":{ + value: 0|g.getFonts().indexOf(settings.stopwatch.font), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.settings.stopwatch.font = g.getFonts()[v]; + writeSettings(); + } + }, + "fontsize":{ + value: 0|settings.stopwatch.fontSize, + min: 0, + onchange: v => { + settings.stopwatch.fontSize = v; + writeSettings(); + } + }, + "index font":{ + value: 0|g.getFonts().indexOf(settings.stopwatch.indexFont), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.settings.stopwatch.indexFont = g.getFonts()[v]; + writeSettings(); + } + }, + "index size":{ + value: 0|settings.stopwatch.indexFontSize, + min: 0, + onchange: v => { + settings.stopwatch.indexFontSize = v; + writeSettings(); + } + }, + "button height":{ + value: 0|settings.stopwatch.buttonHeight, + min: 0, + onchange: v => { + settings.stopwatch.buttonHeight = v; + writeSettings(); + } + }, + }; + var timerMenu = { + "" : { "title" : "Timer" }, + "< Back" : () => E.showMenu(mainMenu), + "font":{ + value: 0|g.getFonts().indexOf(settings.timer.font), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.settings.timer.font = g.getFonts()[v]; + writeSettings(); + } + }, + "fontsize":{ + value: 0|settings.timer.fontSize, + min: 0, + onchange: v => { + settings.timer.fontSize = v; + writeSettings(); + } + }, + "index font":{ + value: 0|g.getFonts().indexOf(settings.timer.indexFont), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.settings.timer.indexFont = g.getFonts()[v]; + writeSettings(); + } + }, + "index size":{ + value: 0|settings.timer.indexFontSize, + min: 0, + onchange: v => { + settings.timer.indexFontSize = v; + writeSettings(); + } + }, + "button height":{ + value: 0|settings.timer.buttonHeight, + min: 0, + onchange: v => { + settings.timer.buttonHeight = v; + writeSettings(); + } + }, + "vibrate":{ + value: 0|settings.timer.vibrate, + min: 0, + onchange: v=>{ + settings.timer.vibrate = v; + writeSettings(); + } + } + }; + var alarmMenu = { + "" : { "title" : "Alarm" }, + "< Back" : () => E.showMenu(mainMenu), + "font":{ + value: 0|g.getFonts().indexOf(settings.alarm.font), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.settings.alarm.font = g.getFonts()[v]; + writeSettings(); + } + }, + "fontsize":{ + value: 0|settings.alarm.fontSize, + min: 0, + onchange: v => { + settings.alarm.fontSize = v; + writeSettings(); + } + }, + "index font":{ + value: 0|g.getFonts().indexOf(settings.alarm.indexFont), + format: v => g.getFonts()[v], + min: 0, max: g.getFonts().length-1, + onchange: v => { + settings.settings.alarm.indexFont = g.getFonts()[v]; + writeSettings(); + } + }, + "index size":{ + value: 0|settings.alarm.indexFontSize, + min: 0, + onchange: v => { + settings.alarm.indexFontSize = v; + writeSettings(); + } + }, + "button height":{ + value: 0|settings.alarm.buttonHeight, + min: 0, + onchange: v => { + settings.alarm.buttonHeight = v; + writeSettings(); + } + }, + "vibrate":{ + value: 0|settings.alarm.vibrate, + min: 0, + onchange: v=>{ + settings.alarm.vibrate = v; + writeSettings(); + } + } + }; + E.showMenu(mainMenu); +}); diff --git a/apps/timerclk/stopwatch.info b/apps/timerclk/stopwatch.info new file mode 100644 index 000000000..72ad418b1 --- /dev/null +++ b/apps/timerclk/stopwatch.info @@ -0,0 +1 @@ +{"id":"timerclk","name":"tclk Stopwatch","src":"timerclk.stopwatch.js","icon":"timerclk.img","version":"0.01","tags":"","files":"","sortorder":10} diff --git a/apps/timerclk/stopwatch.js b/apps/timerclk/stopwatch.js new file mode 100644 index 000000000..8ac6d30a7 --- /dev/null +++ b/apps/timerclk/stopwatch.js @@ -0,0 +1,135 @@ +var timerclk = require("timerclk.lib.js"); +const height = g.getHeight(), width = g.getWidth(); + +var all = require("Storage").readJSON("timerclk.stopwatch.json") || []; + +var settings = require('Storage').readJSON("timerclk.json", true) || {}; +settings = Object.assign({ + "font":"Vector", + "fontSize":40, + "indexFont":"6x8", + "indexFontSize":3, + "buttonHeight":40, +}, settings.stopwatch||{}); +var defaultElement = {start:null, timeAdd:0}; +var current = 0; +var editIndex = 0; +var drawInterval; +var drawIntervalTimeout; +var buttons; + +function update() { + if (drawInterval) clearInterval(drawInterval); + if (drawIntervalTimeout) clearTimeout(drawIntervalTimeout); + var interval = Math.floor(timerclk.getTime(all[current])/3600000)?1000:100; + if (all[current].start) { + drawIntervalTimeout = setTimeout(() => {drawInterval = setInterval(draw, interval); draw();}, interval - (timerclk.getTime(all[current]) % interval)); + } else { + drawInterval = null; + drawIntervalTimeout = null; + } + draw(); + drawButtons(); +} +function play() { + if (all[current].start) { // running + all[current].timeAdd += Date.now() - all[current].start; + all[current].start = null; + update(); + } else { // paused + all[current].start = Date.now(); + update(); + } + require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all)); +} +function reset() { + all[current] = defaultElement.clone(); + update(); + require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all)); +} +function remove() { + all.splice(current, 1); + if (current == all.length) current--; + if (all.length == 0) { + all.push(defaultElement.clone()); + current++; + } + update(); + require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all)); +} + +function edit(position, change) { + if (position == 1) all[current].timeAdd += change*1000; + else if (position == 2) all[current].timeAdd += change*60000; + else if (position == 3) all[current].timeAdd += change*3600000; + require("Storage").write("timerclk.stopwatch.json",JSON.stringify(all)); +} + + +var buttonsRunning = { + reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: reset, img: timerclk.reset_img, col:"#f50"}, + play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:"#0ff"}, +}; +var buttonsNormal = { + reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: remove, img: timerclk.remove_img, col:buttonsRunning.reset.col}, + play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:buttonsRunning.play.col}, +}; +buttons = buttonsNormal; + +function drawButtons() { + if (all[current].start || all[current].time) { + buttons = buttonsRunning; + if (all[current].start) { + buttons.play.img = timerclk.pause_img; + } else { + buttons.play.img = timerclk.play_img; + } + } else { + buttons = buttonsNormal; + } + for (var button of buttons) { + g.setColor(button.col); + g.fillRect(button.pos[0], button.pos[1], button.pos[2], button.pos[3]); + g.setColor("#000"); + // scale 24px images + let iw = settings.buttonHeight-10; + var scale = iw/24; + let ix = button.pos[0] + ((button.pos[2]-button.pos[0] - iw) /2); + let iy = button.pos[1] + ((button.pos[3]-button.pos[1] - iw) /2); + g.drawImage(button.img, ix, iy, {scale: scale}); + } +} + +function draw() { + var x = g.getWidth()/2; + var y = g.getHeight()/2; + g.reset(); + + var timeStr = timerclk.formatTime(timerclk.getTime(all[current]), false, true); + g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2-settings.buttonHeight); + g.setFontAlign(0,0).setFont(settings.indexFont, settings.indexFontSize); + g.drawString(current+1, x, Bangle.appRect.y + (g.stringMetrics("0").height/2)); + g.setFontAlign(0,0).setFont(settings.font, settings.fontSize); + g.drawString(timeStr,x,y); + + var start = (width-g.stringMetrics(timeStr).width)/2; + timeStr = timeStr.split(".")[0].split(":"); + if (timeStr.length < 3) timeStr = [""].concat(timeStr); + var markerPosChange = g.stringMetrics("__").width/2; + if (editIndex == 3) x = start + g.stringMetrics(timeStr[0]).width - markerPosChange; + else if (editIndex == 2) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]).width - markerPosChange; + else if (editIndex == 1) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]+":"+timeStr[2]).width - markerPosChange; + else x = 0; + if (x) g.drawString("__", x, y); + dragBorderHrsMins = start+g.stringMetrics(timeStr[0]).width+g.stringMetrics(":").width/2; + dragBorderMinsSecs = start+g.stringMetrics(timeStr[0]+":"+timeStr[1]).width+g.stringMetrics(":").width/2; +} + +if (all.length == 0) { + all.push(defaultElement.clone()); +} +timerclk.registerControls(this); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); +update(); diff --git a/apps/timerclk/timer.alert.js b/apps/timerclk/timer.alert.js new file mode 100644 index 000000000..f51ea6767 --- /dev/null +++ b/apps/timerclk/timer.alert.js @@ -0,0 +1,62 @@ +if (timerclkTimerTimeout) clearInterval(timerclkTimerTimeout); +var timerclk = require("timerclk.lib.js"); +var settings = require('Storage').readJSON("timerclk.json", true) || {}; +settings = Object.assign({ + "vibrate":10 +}, settings.timer||{}); + +function showTimer(timer) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + Bangle.setLocked(false); + E.showPrompt("Timer finished!",{ + title:"TIMER!", + buttons : {/*LANG*/"Ok":true} + }).then(function(ok) { + buzzCount = 0; + if (ok) { + timer.time += Date.now() - timer.start; + timer.start = null; + } + require("Storage").write("timerclk.timer.json",JSON.stringify(timers)); + load(); + }); + function vibrate(counter) { + VIBRATE.write(1); + setTimeout(() => VIBRATE.write(0), 100); + if (--counter) setTimeout(() => vibrate(counter), 250); + } + function buzz() { + if ((require('Storage').readJSON('setting.json',1)||{}).quiet>1) return; // total silence + vibrate(4); + if (buzzCount--) + setTimeout(buzz, 3000); + else { // auto-snooze + buzzCount = settings.vibrate; + setTimeout(buzz, 600000); + } + } + var buzzCount = settings.vibrate; + buzz(); +} + +// Check for timers +console.log("checking for timers..."); +var timers = require("Storage").readJSON("timerclk.timer.json",1)||[]; +var active = timers.filter(e=>e.start); +if (active.length) { + // if there's an timer, show it + active = active.sort((a,b)=>{ + var at = a.time; + if (a.start) at += Date.now()-a.start; + at = a.period-at; + var bt = b.time; + if (b.start) bt += Date.now()-b.start; + bt = b.period-bt; + return at-bt; + }); + showTimer(active[0]); +} else { + // otherwise just go back to default app + setTimeout(load, 100); +} diff --git a/apps/timerclk/timer.info b/apps/timerclk/timer.info new file mode 100644 index 000000000..39a338693 --- /dev/null +++ b/apps/timerclk/timer.info @@ -0,0 +1 @@ +{"id":"timerclk","name":"tclk Timer","src":"timerclk.timer.js","icon":"timerclk.img","version":"0.01","tags":"","files":"","sortorder":10} diff --git a/apps/timerclk/timer.js b/apps/timerclk/timer.js new file mode 100644 index 000000000..060c07813 --- /dev/null +++ b/apps/timerclk/timer.js @@ -0,0 +1,139 @@ +var timerclk = require("timerclk.lib.js"); +const height = g.getHeight(), width = g.getWidth(); + +var all = require("Storage").readJSON("timerclk.timer.json") || []; +var settings = require('Storage').readJSON("timerclk.json", true) || {}; +settings = Object.assign({ + "font":"Vector", + "fontSize":40, + "indexFont":"6x8", + "indexFontSize":3, + "buttonHeight":40, + "vibrate":4, +}, settings = settings.timer||{}); +var defaultElement = {time:300000, start:null, timeAdd:0}; + +var current = 0; +var editIndex = 0; +var drawInterval; +var drawIntervalTimeout; +var buttons; +var dragBorderHrsMins=0, dragBorderMinsSecs=0; + +function update() { + if (drawInterval) clearInterval(drawInterval); + if (drawIntervalTimeout) clearTimeout(drawIntervalTimeout); + if (all[current].start) { + drawIntervalTimeout = setTimeout(() => {drawInterval = setInterval(draw, 1000); draw();}, 1000 - (timerclk.getTime(all[current]) % 1000)); + } else { + drawInterval = null; + drawIntervalTimeout = null; + } + draw(); + drawButtons(); +} +function play() { + if (all[current].start) { // running + all[current].timeAdd += Date.now() - all[current].start; + all[current].start = null; + update(); + } else { // paused + all[current].start = Date.now(); + update(); + } + require("Storage").write("timerclk.timer.json",JSON.stringify(all)); + timerclkCheckTimers(); +} +function reset() { + all[current] = defaultElement.clone(); + update(); + require("Storage").write("timerclk.timer.json",JSON.stringify(all)); + timerclkCheckTimers(); +} +function remove() { + all.splice(current, 1); + if (current == all.length) current--; + if (all.length == 0) { + all.push(defaultElement.clone()); + current++; + } + update(); + require("Storage").write("timerclk.timer.json",JSON.stringify(all)); + timerclkCheckTimers(); +} + +function edit(position, change) { + if (position == 1) all[current].time += change*1000; + else if (position == 2) all[current].time += change*60000; + else if (position == 3) all[current].time += change*3600000; + require("Storage").write("timerclk.timer.json",JSON.stringify(all)); + timerclkCheckTimers(); +} + +var buttonsRunning = { + reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: reset, img: timerclk.reset_img, col:"#f50"}, + play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:"#0ff"}, +}; +var buttonsNormal = { + reset: {pos:[0, height-settings.buttonHeight, width/2, height], callback: remove, img: timerclk.remove_img, col:buttonsRunning.reset.col}, + play: {pos:[width/2, height-settings.buttonHeight, width, height], callback: play, img: timerclk.play_img, col:buttonsRunning.play.col}, +}; +buttons = buttonsNormal; + + +function drawButtons() { + if (all[current].start || all[current].timeAdd) { + buttons = buttonsRunning; + if (all[current].start) { + buttons.play.img = timerclk.pause_img; + } else { + buttons.play.img = timerclk.play_img; + } + } else { + buttons = buttonsNormal; + } + for (var button of buttons) { + g.setColor(button.col); + g.fillRect(button.pos[0], button.pos[1], button.pos[2], button.pos[3]); + g.setColor("#000"); + // scale 24px images + let iw = settings.buttonHeight-10; + var scale = iw/24; + let ix = button.pos[0] + ((button.pos[2]-button.pos[0] - iw) /2); + let iy = button.pos[1] + ((button.pos[3]-button.pos[1] - iw) /2); + g.drawImage(button.img, ix, iy, {scale: scale}); + } +} + +function draw() { + var x = g.getWidth()/2; + var y = g.getHeight()/2; + g.reset(); + + var time = all[current].time - timerclk.getTime(all[current]); + g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2-settings.buttonHeight); + g.setFontAlign(0,0).setFont(settings.indexFont, settings.indexFontSize); + g.drawString(current+1, x, Bangle.appRect.y + (g.stringMetrics("0").height/2)); + g.setFontAlign(0,0).setFont(settings.font, settings.fontSize); + var timeStr = timerclk.formatTime(time, false, false, true); + g.drawString(timeStr,x,y); + + var start = (width-g.stringMetrics(timeStr).width)/2; + timeStr = timeStr.split(":"); + var markerPosChange = g.stringMetrics("__").width/2; + if (editIndex == 3) x = start + g.stringMetrics(timeStr[0]).width - markerPosChange; + else if (editIndex == 2) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]).width - markerPosChange; + else if (editIndex == 1) x = start + g.stringMetrics(timeStr[0]+":"+timeStr[1]+":"+timeStr[2]).width - markerPosChange; + else x = 0; + if (x) g.drawString("__", x, y); + dragBorderHrsMins = start+g.stringMetrics(timeStr[0]).width+g.stringMetrics(":").width/2; + dragBorderMinsSecs = start+g.stringMetrics(timeStr[0]+":"+timeStr[1]).width+g.stringMetrics(":").width/2; +} + +if (all.length == 0) { + all.push(defaultElement.clone()); +} +timerclk.registerControls(this); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +update(); diff --git a/apps/timerclk/wid.js b/apps/timerclk/wid.js new file mode 100644 index 000000000..e3ddeb791 --- /dev/null +++ b/apps/timerclk/wid.js @@ -0,0 +1,7 @@ +WIDGETS["timerclk.alarm"]={area:"tl",width:0,draw:function() { + if (this.width) g.reset().drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y); + },reload:function() { + WIDGETS["timerclk.alarm"].width = (require('Storage').readJSON('timerclk.alarm.json',1)||[]).some(alarm=>alarm.on) ? 24 : 0; + } +}; +WIDGETS["timerclk.alarm"].reload();