From 7b5f6e10c55a78f53fc0cc0a99cf069b7684da2f Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 5 Jan 2023 19:39:02 +0100 Subject: [PATCH 1/6] Use clock_info.addInteractive instead of a custom implementation --- apps/bwclk/ChangeLog | 2 +- apps/bwclk/app.js | 268 ++++++++++----------------------------- apps/bwclk/metadata.json | 2 +- 3 files changed, 69 insertions(+), 203 deletions(-) diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index cd52c7665..4bd8664c1 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -24,4 +24,4 @@ 0.24: Update clock_info to avoid a redraw 0.25: Use Bangle.setUI({remove:...}) to allow loading the launcher without a full reset on fw2v16. ClockInfo Fix: Use .get instead of .show as .show is not implemented for weather etc. - +0.26: Use clkinfo.addInteractive instead of a custom implementation diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index db531a22f..b0b727fd2 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -31,6 +31,19 @@ for (const key in saved_settings) { settings[key] = saved_settings[key]; } +let isFullscreen = function() { + var s = settings.screen.toLowerCase(); + if(s == "dynamic"){ + return Bangle.isLocked(); + } else { + return s == "full"; + } +}; + +let getLineY = function(){ + return H/5*2 + (isFullscreen() ? 0 : 8); +} + /************************************************ * Assets */ @@ -86,70 +99,47 @@ let imgLock = function() { /************************************************ * Menu */ -// Custom bwItems menu - therefore, its added here and not in a clkinfo.js file. -let bwItems = { - name: null, - img: null, - items: [ - { name: "WeekOfYear", - get: () => ({ text: "Week " + weekOfYear(), img: null}), - show: function() {}, - hide: function () {} - }, - ] -}; +let clockInfoItems = clock_info.load(); +let clockInfoMenu = clock_info.addInteractive(clockInfoItems, { + x : 0, + y: 135, + w: W, + h: H-135, + draw : (itm, info, options) => { + g.setColor(g.theme.fg); + g.fillRect(options.x, options.y, options.x+options.w, options.y+options.h); -let weekOfYear = function() { - var date = new Date(); - date.setHours(0, 0, 0, 0); - // Thursday in current week decides the year. - date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); - // January 4 is always in week 1. - var week1 = new Date(date.getFullYear(), 0, 4); - // Adjust to Thursday in week 1 and count number of weeks from date to week1. - return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - - 3 + (week1.getDay() + 6) % 7) / 7); -}; + g.setFontAlign(0,0); + g.setColor(g.theme.bg); - -// Load menu -let menu = clock_info.load(); -menu = menu.concat(bwItems); - - -// Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it. -if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){ - settings.menuPosX = 0; - settings.menuPosY = 0; -} - -let canRunMenuItem = function() { - if(settings.menuPosY == 0){ - return false; - } - - var menuEntry = menu[settings.menuPosX]; - var item = menuEntry.items[settings.menuPosY-1]; - return item.run !== undefined; -}; - - -let runMenuItem = function() { - if(settings.menuPosY == 0){ - return; - } - - var menuEntry = menu[settings.menuPosX]; - var item = menuEntry.items[settings.menuPosY-1]; - try{ - var ret = item.run(); - if(ret){ - Bangle.buzz(300, 0.6); + if (options.focus){ + g.drawRect(options.x, options.y, options.x+options.w-2, options.y+options.h-1); // show if focused + g.drawRect(options.x+1, options.y+1, options.x+options.w-3, options.y+options.h-2); // show if focused } - } catch (ex) { - // Simply ignore it... + + // Set text and font + var image = info.img; + var text = String(info.text); + if(text.split('\n').length > 1){ + g.setMiniFont(); + } else { + g.setSmallFont(); + } + + // Compute sizes + var strWidth = g.stringWidth(text); + var imgWidth = image == null ? 0 : 24; + var midx = options.x+options.w/2; + + // Draw + + if (image) { + var scale = imgWidth / image.width; + g.drawImage(image, midx-16-parseInt(strWidth/2), options.y+8, {scale: scale}); + } + g.drawString(text, midx+imgWidth-6, options.y+20); } -}; +}); /************************************************ @@ -161,7 +151,7 @@ let draw = function() { // Draw clock drawDate(); - drawMenuAndTime(); + drawTime(); drawLock(); drawWidgets(); }; @@ -169,7 +159,7 @@ let draw = function() { let drawDate = function() { // Draw background - var y = H/5*2 + (isFullscreen() ? 0 : 8); + var y = getLineY() g.reset().clearRect(0,0,W,y); // Draw date @@ -197,14 +187,12 @@ let drawDate = function() { }; -let drawTime = function(y, smallText) { +let drawTime = function() { // Draw background + var y1 = getLineY(); + var y = y1; var date = new Date(); - // Draw time - g.setColor(g.theme.bg); - g.setFontAlign(0,0); - var hours = String(date.getHours()); var minutes = date.getMinutes(); minutes = minutes < 10 ? String("0") + minutes : minutes; @@ -212,67 +200,18 @@ let drawTime = function(y, smallText) { var timeStr = hours + colon + minutes; // Set y coordinates correctly - y += parseInt((H - y)/2) + 5; + y += parseInt((H - y)/2)-10; - // Show large or small time depending on info entry - if(smallText){ - y -= 15; - g.setMediumFont(); - } else { - g.setLargeFont(); - } + // Clear region + g.setColor(g.theme.fg); + g.fillRect(0,y1,W,y+20); + + g.setMediumFont(); + g.setColor(g.theme.bg); + g.setFontAlign(0,0); g.drawString(timeStr, W/2, y); }; -let drawMenuItem = function(text, image) { - // First clear the time region - var y = H/5*2 + (isFullscreen() ? 0 : 8); - - g.setColor(g.theme.fg); - g.fillRect(0,y,W,H); - - // Draw menu text - var hasText = (text != null && text != ""); - if(hasText){ - g.setFontAlign(0,0); - - // For multiline text we show an even smaller font... - text = String(text); - if(text.split('\n').length > 1){ - g.setMiniFont(); - } else { - g.setSmallFont(); - } - - var imgWidth = image == null ? 0 : 24; - var strWidth = g.stringWidth(text); - g.setColor(g.theme.fg).fillRect(0, 149-14, W, H); - g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 149+3); - - if(image != null){ - var scale = imgWidth / image.width; - g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 149 - parseInt(imgWidth/2), {scale: scale}); - } - } - - // Draw time - drawTime(y, hasText); -}; - - -let drawMenuAndTime = function() { - var menuEntry = menu[settings.menuPosX]; - - // The first entry is the overview... - if(settings.menuPosY == 0){ - drawMenuItem(menuEntry.name, menuEntry.img); - return; - } - - // Draw item if needed - var item = menuEntry.items[settings.menuPosY-1].get(); - drawMenuItem(item.text, item.img); -}; let drawLock = function() { if(settings.showLock && Bangle.isLocked()){ @@ -291,17 +230,6 @@ let drawWidgets = function() { }; -let isFullscreen = function() { - var s = settings.screen.toLowerCase(); - if(s == "dynamic"){ - return Bangle.isLocked(); - } else { - return s == "full"; - } -}; - - - /************************************************ * Listener */ @@ -343,74 +271,12 @@ let lockListenerBw = function(isLocked) { }; Bangle.on('lock', lockListenerBw); -let chargingListenerBw = function(charging) { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; - // Jump to battery - settings.menuPosX = 0; - settings.menuPosY = 1; - draw(); +let kill = function(){ + clockInfoMenu.remove(); + delete clockInfoMenu; }; -Bangle.on('charging', chargingListenerBw); - -let touchListenerBw = function(btn, e) { - var widget_size = isFullscreen() ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better... - var left = parseInt(g.getWidth() * 0.22); - var right = g.getWidth() - left; - var upper = parseInt(g.getHeight() * 0.22) + widget_size; - var lower = g.getHeight() - upper; - - var is_upper = e.y < upper; - var is_lower = e.y > lower; - var is_left = e.x < left && !is_upper && !is_lower; - var is_right = e.x > right && !is_upper && !is_lower; - var is_center = !is_upper && !is_lower && !is_left && !is_right; - - if(is_lower){ - Bangle.buzz(40, 0.6); - settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1); - - drawMenuAndTime(); - } - - if(is_upper){ - if(e.y < widget_size){ - return; - } - - Bangle.buzz(40, 0.6); - settings.menuPosY = settings.menuPosY-1; - settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY; - - drawMenuAndTime(); - } - - if(is_right){ - Bangle.buzz(40, 0.6); - settings.menuPosX = (settings.menuPosX+1) % menu.length; - settings.menuPosY = 0; - drawMenuAndTime(); - } - - if(is_left){ - Bangle.buzz(40, 0.6); - settings.menuPosY = 0; - settings.menuPosX = settings.menuPosX-1; - settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX; - drawMenuAndTime(); - } - - if(is_center){ - if(canRunMenuItem()){ - runMenuItem(); - } - } -}; -Bangle.on('touch', touchListenerBw); - -let save = () => storage.write(SETTINGS_FILE, settings); -E.on("kill", save); +E.on("kill", kill); /************************************************ * Startup Clock diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index 376124a96..c464e51aa 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -1,7 +1,7 @@ { "id": "bwclk", "name": "BW Clock", - "version": "0.25", + "version": "0.26", "description": "A very minimalistic clock to mainly show date and time.", "readme": "README.md", "icon": "app.png", From 85f7d3e739313865c9148a024e9ec821563fcac3 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 5 Jan 2023 19:50:35 +0100 Subject: [PATCH 2/6] Updated readme --- apps/bwclk/README.md | 37 ++++++++----------------------------- apps/bwclk/metadata.json | 2 +- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md index d869fa2cf..b19e52787 100644 --- a/apps/bwclk/README.md +++ b/apps/bwclk/README.md @@ -3,18 +3,16 @@ A very minimalistic clock. ![](screenshot.png) +## ToDos and known issues +- [ ] The clkinfo is always shown and its, therefore, not possible to only show the time as shown in the screenshot. +- [ ] The weeknumber is currently not an option in clkinfo. +- [ ] Its not possible to run clkinfo items (e.g. trigger home assistant). + ## Features The BW clock implements features that are exposed by other apps through the `clkinfo` module. -For example, if you install the HomeAssistant app, this menu item will be shown if you click right -and additionally allows you to send triggers directly from the clock (select triggers via up/down and -send via click center). Here are examples of other apps that are integrated: - -- Bangle data such as steps, heart rate, battery or charging state. -- Show agenda entries. A timer for an agenda entry can also be set by simply clicking in the middle of the screen. This can be used to not forget a meeting etc. Note that only one agenda-timer can be set at a time. *Requirement: Gadgetbridge calendar sync enabled* -- Weather temperature as well as the wind speed can be shown. *Requirement: Weather app* -- HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant app* - -Note: If some apps are not installed (e.gt. weather app), then this menu item is hidden. +For example, if you install the HomeAssistant app, this menu item will be shown if you first +touch the bottom of the screen and then swipe left/right to the home assistant menu. To select +sub-items simply swipe up/down. ## Settings - Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden). @@ -22,25 +20,6 @@ Note: If some apps are not installed (e.gt. weather app), then this menu item is - The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further. - Your bangle uses the sys color settings so you can change the color too. -## Menu structure -2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to trigger HomeAssistant. - -Simply click left / right to go through the menu entries such as Bangle, Weather etc. -and click up/down to move into this sub-menu. You can then click in the middle of the screen -to e.g. send a trigger via HomeAssistant once you selected it. The actions really depend -on the app that provide this sub-menu through the `clkinfo` module. - -``` - Bangle -- Agenda -- Weather -- HomeAssistant - | | | | - Battery Entry 1 Temperature Trigger1 - | | | | - Steps ... ... ... - | - ... -``` - - ## Thanks to - Thanks to Gordon Williams not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located. - Icons created by Flaticon diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index c464e51aa..f2e7ef428 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -2,7 +2,7 @@ "id": "bwclk", "name": "BW Clock", "version": "0.26", - "description": "A very minimalistic clock to mainly show date and time.", + "description": "A very minimalistic clock.", "readme": "README.md", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}], From 239038d58da1c1f81f3c0f0e1168e2be79ac4255 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 5 Jan 2023 19:55:12 +0100 Subject: [PATCH 3/6] Removed one old Screenshot --- apps/bwclk/metadata.json | 2 +- apps/bwclk/screenshot_4.png | Bin 3283 -> 0 bytes 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 apps/bwclk/screenshot_4.png diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index f2e7ef428..e26307410 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -5,7 +5,7 @@ "description": "A very minimalistic clock.", "readme": "README.md", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}], + "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}], "type": "clock", "tags": "clock,clkinfo", "supports": ["BANGLEJS2"], diff --git a/apps/bwclk/screenshot_4.png b/apps/bwclk/screenshot_4.png deleted file mode 100644 index 83de5c2ce095c7fc8ea6c37ec86a29024048dea0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3283 zcmV;^3@r1BP)Px>jY&j7RCr$Po!ge=s18J@{{N$UR@St8Tr{B21tIJ>PqR9O5TT7Ma8{nLU%!6+ z`iK9c0*5N_MSu^@9K-%rfB+MO6a~J%{+kAU-hW*KZqfCc1p=IsK2CDy5rr60jQ}Gm z(Z;R72jCC5QYG$H-gfePB__b`)I85Y=jr_ezWa*NYI*_u-M3EKi4VZDdxiFM0{lGw z!dG;!o+z+w5O;uQ5EJ0=^u60*uX0|Bj9~6nSOWZRj<&46g-)uf_s?61*+Ohd;d>|T z!P~2%vzFoxvE~rR9{9c7g{^#4eYMwNqXXe6Q1-xKDWsz)1vJnT;3(DUCrkkX93~|l zWh=lIB3p6J_x+;5dfz*`iQplQV5KQA0~l=wyw_->FZ1wCTp9-FPSig3uWF25qeZ;P zAi(GHvpsSRsA#LfH*wq3`knx00HZC$?5!R0Wgb@G_wW|J(hQ|p_C%EurcHzQYpV80xYboy z(?Uc5i~@4mA=SV2so5~vcrJSatWZw7i4?BCO*OX-+TOVJuZ@iW|5j{w1-8yV1Hj{R z_Slvx*!4LIm*fwDTH`}wi_G0^Q&wK1S%Z@Lsr%>JYaS15l`61hLq!0k@u9J`va+m& zum+^teal zK;p7MT^?XhCH0IQ-466bj!q8xnD2pv#)3esspJxTXk3z?_VdyJOCn36NaK-yIKqcI zDT>|^d7Ntx#)vMxKKDM)CpVgnsMYAt{8g{fByc2nC4r?!r8Iw=ENcQd&Zj`h3M|2c z!mEYYDy23a>pUFyw*sXAmcZ3K+WzX5CbtM)FjfJa@d);=efRh>0I!61btNXi`!Fs6 za0a{{h{9pFrO?{Zk?&3F?xig8tyml3ILu@ztoL_6gqz&q9N&%F)c z)8PHcR|Q~AYk_>HVONV3u^qMmd?LJ01{eXUY73JN@Tu^=9bnHDCbB`SHmLwV5#E)F z9XKdo^>J>*aII5CTizdt92{^HY&Fo-uBwAoezbI71)^IRaLJ- z1@3x_V0U_jHR~Kccr}^D2PbswRnZ|9nN_+NYGJO_0X+ z)~fM;UporAM$ahQWdKJ7xXKUO;;aC71jlTx$XhZ=D*`Mj#Lv|VARB44iIB0grwCeE zQ9JeG0|vad0taXp>cVnQE%o-&pSGi5qIRKzfX)aoC=|_VDnNj1=7mv#3J_pWD4Nw& zfB@Ib3!?%RAi$tdG^?oq0j`-BMg=NBfI*>XR#Snm&oA!R42@Ay0a*b8ENeuI!U_=J z!pUK1vH}EH)`%8`6(GQclf%$t1qiUL5iJTUK!6J;hoQ*|5MWs&S`=1*02fXULz5LC zz_LcPD69YhE}R^OCM!UIWsPW2SOEfDI5`YWR-g>P$e*uk{|Z-LJ}o{9Alh4%TAj14 z09%EN5(WKHXKV5-kfhI%*d!m_L{I*& zc2~{$Sb!r1(}IT1t@Uexsy7CWPdgtguvW2w{fY!3uxaN-dc*Ov7+aSfU@KT@r&4`RN%-3YJEwSLHZmKG18`5JjmL#IYE4)Hm?L2`L)Ge z74Jy^XK1(;VCw=kNxs|m=F|8>tAfX_7mrmZPaNpjoz?dfd1>h|G zUIFl|npCR5m103E@b2oHR)G;QG&Yfmj`XEj!xL^GDrlEdfxU@s$43fR$ya17(VAD? za0K{Q|EJ+BJ)9RnWW02*ZHe0gdxiGl$QB}6I0PCr!CqeyoM;^1iJg4=Oyg%{>s@O^ z3>QJQ9B; zy-FYAq+~=LQmQ4S_f*hq(v=l*rEg^Obf1)2-v`zNm<4aO7DA(u<&fpw^c6RIxkFqg zyaX8EG8L0Q&&e+>T%~>8-X_;N9>NU>TUo)pu(Jt^jW|z!807>%&^*B4U~8qP?3TBMu96k#Sk_BaKM~SOV7~u(Uww^T-5wd__H~qx_sueN$VA zitu`?X1h5&07n6n0dVFMQYt_x6&Qh63KaR=BCHp>dt6>$l1?jrJ8q0SJTUs*$d{bMhES|*N$L_Ac5$jl?)f03XY0C;6Sb-w|j;_Ly@LDQ)lqLjt zpn$h;U6~+nHMYPTeXw1rPueYnHxZ}^mV{LX*jkM(Iz%2u(R@YNrL+(cfxg`bQUtu< zo~SVaJ~3;I`Hunwm@piz00BNaeGHxelYyfZAizhbkHHgQGH|p41o-ImF?a$@298#M z03V$`24523`&%dU?UH2-(|^7K1o-?Mx>j)d#wWn8^q)OA>Mx*osz88us=smWQ~u&Y zl869H3O(@iQQOdi8a;#TlIe8-TPx2sZuZmuZL+OESYt#W>cRW@w@>WWc#(Nm*}Mv1 z&v$B(v7aQ3K)5H+^Vh}K92Ou(Jud;as5u#9IT=f1Pyk1OXvQOQ^dQ#Ep?$O?e|dt~ zAZyFCc|`?APTP`=_VeCGnE8F(!019|k7%hnUt?!>k`ELv zUy3aXN{t@^+^8j0tl1$7flC5dlRWf5cg=Y}U|#<{0=NgfHnt4=@&Kc|-UHsK z3XdMAD=V-z>4-jefZMh9s&QMvkvX(+N7)nLVikA=EWHC7+GnFxJ_<;!9|HVRfJb0z zVb=l|ZBKx2ik@(YvjBizk?|hbqHbplau{ldd9J{Er}o)v;piS%bK3W6)9N;RHGbKy zXlsH{`RDN!xP=3KbnXP$8si8Gqyi&0QP4&Dc?G~dh-V^7uX$Hg;D{IraOBo-`0_p` z5x_>_A!AqC%qrmtk90@cO+#N(fqQ-Ks2}VpiEOGBHkues1ROr7B*2Gj%J35vAi#-Y zbE Date: Thu, 5 Jan 2023 20:56:05 +0100 Subject: [PATCH 4/6] Minor changes --- apps/bwclk/app.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index b0b727fd2..a8c9f1b80 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -132,10 +132,9 @@ let clockInfoMenu = clock_info.addInteractive(clockInfoItems, { var midx = options.x+options.w/2; // Draw - if (image) { var scale = imgWidth / image.width; - g.drawImage(image, midx-16-parseInt(strWidth/2), options.y+8, {scale: scale}); + g.drawImage(image, midx-14-parseInt(strWidth/2), options.y+6, {scale: scale}); } g.drawString(text, midx+imgWidth-6, options.y+20); } From bdefe4217cae08524359c29c58ac95c358e3ae92 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 5 Jan 2023 21:02:55 +0100 Subject: [PATCH 5/6] Minor changes --- apps/bwclk/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index a8c9f1b80..b5e485822 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -134,9 +134,9 @@ let clockInfoMenu = clock_info.addInteractive(clockInfoItems, { // Draw if (image) { var scale = imgWidth / image.width; - g.drawImage(image, midx-14-parseInt(strWidth/2), options.y+6, {scale: scale}); + g.drawImage(image, midx-parseInt(imgWidth*1.3/2)-parseInt(strWidth/2), options.y+6, {scale: scale}); } - g.drawString(text, midx+imgWidth-6, options.y+20); + g.drawString(text, midx+parseInt(imgWidth*1.3/2), options.y+20); } }); From 3c1465ae46c00f6e1af3ab02e2f89abb6dee8ecb Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 5 Jan 2023 22:05:52 +0100 Subject: [PATCH 6/6] AI Clock - Use clock_info.addInteractive instead of a custom implementation --- apps/aiclock/ChangeLog | 3 +- apps/aiclock/README.md | 3 +- apps/aiclock/aiclock.app.js | 331 ++++++++++-------------------------- apps/aiclock/metadata.json | 2 +- apps/bwclk/app.js | 2 +- 5 files changed, 96 insertions(+), 245 deletions(-) diff --git a/apps/aiclock/ChangeLog b/apps/aiclock/ChangeLog index 15a7d0a14..6d6eeb55e 100644 --- a/apps/aiclock/ChangeLog +++ b/apps/aiclock/ChangeLog @@ -3,4 +3,5 @@ 0.03: Indicate battery level through line occurrence. 0.04: Use widget_utils module. 0.05: Support for clkinfo. -0.06: ClockInfo Fix: Use .get instead of .show as .show is not implemented for weather etc. \ No newline at end of file +0.06: ClockInfo Fix: Use .get instead of .show as .show is not implemented for weather etc. +0.07: Use clock_info.addInteractive instead of a custom implementation \ No newline at end of file diff --git a/apps/aiclock/README.md b/apps/aiclock/README.md index 31dd5aa29..521bd2c5e 100644 --- a/apps/aiclock/README.md +++ b/apps/aiclock/README.md @@ -11,8 +11,7 @@ The original output of stable diffusion is shown here: My implementation is shown below. Note that horizontal lines occur randomly, but the probability is correlated with the battery level. So if your screen contains only a few lines its time to charge your bangle again ;) Also note that the upper text -implementes the clkinfo module and can be configured via touch left/right/up/down. -Touch at the center to trigger the selected action. +implements the clkinfo module and can be configured via touch and swipe left/right and up/down. ![](impl.png) diff --git a/apps/aiclock/aiclock.app.js b/apps/aiclock/aiclock.app.js index 66fa2ca6a..350832367 100644 --- a/apps/aiclock/aiclock.app.js +++ b/apps/aiclock/aiclock.app.js @@ -1,7 +1,6 @@ /************************************************ * AI Clock */ - const storage = require('Storage'); const clock_info = require("clock_info"); @@ -21,124 +20,14 @@ Graphics.prototype.setFontGochiHand = function(scale) { return this; } -/************************************************ - * Set some important constants such as width, height and center - */ -var W = g.getWidth(),R=W/2; -var H = g.getHeight(); -var cx = W/2; -var cy = H/2; -var drawTimeout; - -/************************************************ - * SETTINGS - */ -const SETTINGS_FILE = "aiclock.setting.json"; -let settings = { - menuPosX: 0, - menuPosY: 0, -}; -let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings; -for (const key in saved_settings) { - settings[key] = saved_settings[key] -} - - -/************************************************ - * Menu - */ -function getDate(){ - var date = new Date(); - return ("0"+date.getDate()).substr(-2) + "/" + ("0"+(date.getMonth()+1)).substr(-2) -} - - -// Custom clockItems menu - therefore, its added here and not in a clkinfo.js file. -var clockItems = { - name: getDate(), - img: null, - items: [ - { name: "Week", - get: () => ({ text: "Week " + weekOfYear(), img: null}), - show: function() { clockItems.items[0].emit("redraw"); }, - hide: function () {} - }, - ] - }; - -function weekOfYear() { - var date = new Date(); - date.setHours(0, 0, 0, 0); - // Thursday in current week decides the year. - date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); - // January 4 is always in week 1. - var week1 = new Date(date.getFullYear(), 0, 4); - // Adjust to Thursday in week 1 and count number of weeks from date to week1. - return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - - 3 + (week1.getDay() + 6) % 7) / 7); -} - - - -// Load menu -var menu = clock_info.load(); -menu = menu.concat(clockItems); - - - // Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it. - if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){ - settings.menuPosX = 0; - settings.menuPosY = 0; - } - - function canRunMenuItem(){ - if(settings.menuPosY == 0){ - return false; - } - - var menuEntry = menu[settings.menuPosX]; - var item = menuEntry.items[settings.menuPosY-1]; - return item.run !== undefined; - } - - - function runMenuItem(){ - if(settings.menuPosY == 0){ - return; - } - - var menuEntry = menu[settings.menuPosX]; - var item = menuEntry.items[settings.menuPosY-1]; - try{ - var ret = item.run(); - if(ret){ - Bangle.buzz(300, 0.6); - } - } catch (ex) { - // Simply ignore it... - } - } - - -/* - * Based on the great multi clock from https://github.com/jeffmer/BangleApps/ - */ -Graphics.prototype.drawRotRect = function(w, r1, r2, angle) { - angle = angle % 360; - var w2=w/2, h=r2-r1, theta=angle*Math.PI/180; - return this.fillPoly(this.transformVertices([-w2,0,-w2,-h,w2,-h,w2,0], - {x:cx+r1*Math.sin(theta),y:cy-r1*Math.cos(theta),rotate:theta})); -}; - - -function drawBackground() { +function drawBackground(start, end) { g.setFontAlign(0,0); - g.setColor(g.theme.fg); + g.setColor("#000"); var bat = E.getBattery() / 100.0; - var y = 0; - while(y < H){ + var y = start; + while(y < end){ // Show less lines in case of small battery level. if(Math.random() > bat){ y += 5; @@ -154,6 +43,30 @@ function drawBackground() { } +/************************************************ + * Set some important constants such as width, height and center + */ +var W = g.getWidth(),R=W/2; +var H = g.getHeight(); +var cx = W/2; +var cy = H/2; +var drawTimeout; + +var clkInfoY = 60; + + +/* + * Based on the great multi clock from https://github.com/jeffmer/BangleApps/ + */ +Graphics.prototype.drawRotRect = function(w, r1, r2, angle) { + angle = angle % 360; + var w2=w/2, h=r2-r1, theta=angle*Math.PI/180; + return this.fillPoly(this.transformVertices([-w2,0,-w2,-h,w2,-h,w2,0], + {x:cx+r1*Math.sin(theta),y:cy-r1*Math.cos(theta),rotate:theta})); +}; + + + function drawCircle(isLocked){ g.setColor(g.theme.fg); g.fillCircle(cx, cy, 12); @@ -163,54 +76,6 @@ function drawCircle(isLocked){ g.fillCircle(cx, cy, 6); } -function toAngle(a){ - if (a < 0){ - return 360 + a; - } - - if(a > 360) { - return 360 - a; - } - - return a -} - - -function drawMenuItem(text, image){ - if(text == null){ - drawTime(); - return - } - text = String(text); - - g.reset().setBgColor("#fff").setColor("#000"); - g.setFontAlign(0,0); - g.setFont("Vector", 20); - - var imgWidth = image == null ? 0 : 24; - var strWidth = g.stringWidth(text); - var strHeight = text.split('\n').length > 1 ? 40 : Math.max(24, imgWidth+2); - var w = imgWidth + strWidth; - - g.clearRect(cx-w/2-8, 40-strHeight/2-1, cx+w/2+4, 40+strHeight/2) - - // Draw right line as designed by stable diffusion - g.drawLine(cx+w/2+5, 40-strHeight/2-1, cx+w/2+5, 40+strHeight/2); - g.drawLine(cx+w/2+6, 40-strHeight/2-1, cx+w/2+6, 40+strHeight/2); - g.drawLine(cx+w/2+7, 40-strHeight/2-1, cx+w/2+7, 40+strHeight/2); - - // And finally the text - g.drawString(text, cx+imgWidth/2, 42); - g.drawString(text, cx+1+imgWidth/2, 41); - - if(image != null) { - var scale = image.width ? imgWidth / image.width : 1; - g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 41-12, {scale: scale}); - } - - drawTime(); -} - function drawTime(){ // Draw digital time first @@ -267,34 +132,23 @@ function drawDigits(){ } -function drawMenu(){ - var menuEntry = menu[settings.menuPosX]; - - // The first entry is the overview... - if(settings.menuPosY == 0){ - drawMenuItem(menuEntry.name, menuEntry.img); - return; - } - - // Draw item if needed - var item = menuEntry.items[settings.menuPosY-1].get(); - drawMenuItem(item.text, item.img); +function draw(){ + // Note that we force a redraw also of the clock info as + // we want to ensure (for design purpose) that the hands + // are above the clkinfo section. + clockInfoMenu.redraw(); } - - - -function draw(){ +function drawMainClock(){ // Queue draw in one minute queueDraw(); - g.reset(); - g.clearRect(0, 0, g.getWidth(), g.getHeight()); - g.setColor(1,1,1); + g.setColor("#fff"); + g.reset().clearRect(0, clkInfoY, g.getWidth(), g.getHeight()); - drawBackground(); - drawMenu(); + drawBackground(clkInfoY, H); + drawTime(); drawCircle(Bangle.isLocked()); } @@ -304,7 +158,7 @@ function draw(){ */ Bangle.on('lcdPower',on=>{ if (on) { - draw(true); + draw(); } else { // stop draw timer if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; @@ -315,62 +169,10 @@ Bangle.on('lock', function(isLocked) { drawCircle(isLocked); }); -Bangle.on('touch', function(btn, e){ - var left = parseInt(g.getWidth() * 0.22); - var right = g.getWidth() - left; - var upper = parseInt(g.getHeight() * 0.22); - var lower = g.getHeight() - upper; - - var is_upper = e.y < upper; - var is_lower = e.y > lower; - var is_left = e.x < left && !is_upper && !is_lower; - var is_right = e.x > right && !is_upper && !is_lower; - var is_center = !is_upper && !is_lower && !is_left && !is_right; - - if(is_lower){ - Bangle.buzz(40, 0.6); - settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1); - - draw(); - } - - if(is_upper){ - Bangle.buzz(40, 0.6); - settings.menuPosY = settings.menuPosY-1; - settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY; - - draw(); - } - - if(is_right){ - Bangle.buzz(40, 0.6); - settings.menuPosX = (settings.menuPosX+1) % menu.length; - settings.menuPosY = 0; - draw(); - } - - if(is_left){ - Bangle.buzz(40, 0.6); - settings.menuPosY = 0; - settings.menuPosX = settings.menuPosX-1; - settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX; - draw(); - } - - if(is_center){ - if(canRunMenuItem()){ - runMenuItem(); - } - } -}); - E.on("kill", function(){ - try{ - storage.write(SETTINGS_FILE, settings); - } catch(ex){ - // If this fails, we still kill the app... - } + clockInfoMenu.remove(); + delete clockInfoMenu; }); @@ -386,6 +188,55 @@ function queueDraw() { } +/************************************************ + * Clock Info + */ +let clockInfoItems = clock_info.load(); +let clockInfoMenu = clock_info.addInteractive(clockInfoItems, { + x : 0, + y: 0, + w: W, + h: clkInfoY, + draw : (itm, info, options) => { + g.setFontAlign(0,0); + g.setFont("Vector", 20); + + g.setColor("#fff"); + g.fillRect(options.x, options.y, options.x+options.w, options.y+options.h); + drawBackground(0, clkInfoY+2); + + // Set text and font + var image = info.img; + var text = String(info.text); + + var imgWidth = image == null ? 0 : 24; + var strWidth = g.stringWidth(text); + var strHeight = text.split('\n').length > 1 ? 40 : Math.max(24, imgWidth+2); + var w = imgWidth + strWidth; + + // Draw right line as designed by stable diffusion + g.setColor(options.focus ? "#0f0" : "#fff"); + g.fillRect(cx-w/2-8, 40-strHeight/2-1, cx+w/2+4, 40+strHeight/2) + + g.setColor("#000"); + g.drawLine(cx+w/2+5, 40-strHeight/2-1, cx+w/2+5, 40+strHeight/2); + g.drawLine(cx+w/2+6, 40-strHeight/2-1, cx+w/2+6, 40+strHeight/2); + g.drawLine(cx+w/2+7, 40-strHeight/2-1, cx+w/2+7, 40+strHeight/2); + + // Draw text and image + g.drawString(text, cx+imgWidth/2, 42); + g.drawString(text, cx+1+imgWidth/2, 41); + + if(image != null) { + var scale = image.width ? imgWidth / image.width : 1; + g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 41-12, {scale: scale}); + } + + drawMainClock(); + } +}); + + /* * Lets start widgets, listen for btn etc. */ @@ -400,7 +251,7 @@ Bangle.loadWidgets(); require('widget_utils').hide(); // Clear the screen once, at startup and draw clock -g.setTheme({bg:"#fff",fg:"#000",dark:false}).clear(); +g.setTheme({bg:"#fff",fg:"#000",dark:false}); draw(); // After drawing the watch face, we can draw the widgets diff --git a/apps/aiclock/metadata.json b/apps/aiclock/metadata.json index 4ff40ca65..4c01ecaa9 100644 --- a/apps/aiclock/metadata.json +++ b/apps/aiclock/metadata.json @@ -3,7 +3,7 @@ "name": "AI Clock", "shortName":"AI Clock", "icon": "aiclock.png", - "version":"0.06", + "version":"0.07", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "A watch face that was designed by an AI (stable diffusion) and implemented by a human.", diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index b5e485822..05db62779 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -97,7 +97,7 @@ let imgLock = function() { /************************************************ - * Menu + * Clock Info */ let clockInfoItems = clock_info.load(); let clockInfoMenu = clock_info.addInteractive(clockInfoItems, {