From be770a02dc39e7217bfc0813c9ca9df116046cce Mon Sep 17 00:00:00 2001 From: Tom Wallroth Date: Thu, 30 May 2024 15:13:42 +0200 Subject: [PATCH] Initial version done! --- apps/supaclk/ChangeLog | 1 + apps/supaclk/README.md | 25 ++++ apps/supaclk/app-icon.js | 1 + apps/{supaclockpro => supaclk}/app.js | 169 +++++++++++++------------- apps/supaclk/app.png | Bin 0 -> 3964 bytes apps/supaclk/metadata.json | 16 +++ apps/supaclk/screenshot.png | Bin 0 -> 3964 bytes apps/supaclk/screenshot2.png | Bin 0 -> 4206 bytes 8 files changed, 125 insertions(+), 87 deletions(-) create mode 100644 apps/supaclk/ChangeLog create mode 100644 apps/supaclk/README.md create mode 100644 apps/supaclk/app-icon.js rename apps/{supaclockpro => supaclk}/app.js (78%) create mode 100644 apps/supaclk/app.png create mode 100644 apps/supaclk/metadata.json create mode 100644 apps/supaclk/screenshot.png create mode 100644 apps/supaclk/screenshot2.png diff --git a/apps/supaclk/ChangeLog b/apps/supaclk/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/supaclk/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/supaclk/README.md b/apps/supaclk/README.md new file mode 100644 index 000000000..fc8f1a096 --- /dev/null +++ b/apps/supaclk/README.md @@ -0,0 +1,25 @@ +# SUPACLOCK Pro ULTRA + +A nice clock, with four ClockInfo areas at the bottom. Tap them and swipe up/down and left/right to toggle between different information. + + - Supports Light and Dark Themes. + - It has a useless splash-screen for increased ULTRAness + - Lazy Loading of Clock-Info, shows clock-face faster + - Uses locale module to display of day and month + + +Based on [LCD Clock Plus](https://banglejs.com/apps/?id=lcdclockplus) + +## Screenshots + +Light theme + +![light](screenshot.png) + +Dark theme + +![dark](screenshot2.png) + +## Credits + +Written by devsnd diff --git a/apps/supaclk/app-icon.js b/apps/supaclk/app-icon.js new file mode 100644 index 000000000..77598357b --- /dev/null +++ b/apps/supaclk/app-icon.js @@ -0,0 +1 @@ +atob("MDAB/////////////////////////////////gX2D8H//f328z3//f32+v3//AX2+v3///X2BgH///bm/v3/+A8e/v3//////////hf4/C+/+ffnM+5/+/ff1+3/+/ff1+H/+/ff1+7/+ffvt+9//BAweC+//////////4B//////AAf////+P+P////8+fH////48/H////45/H////8R/F////8x+A/////j8A/8H//j4APwD//AAYDjD//EA5HHD/+EByOHDf+EDkOGCf8OfkAAA/8P/4AAB/4P/8AAD/4f/8HAP/+///////////////55OAADx/55OTBxh/55OTD5k/55PTQDM/55PzxnAf4BAzzyOf8DAT7yff////////") diff --git a/apps/supaclockpro/app.js b/apps/supaclk/app.js similarity index 78% rename from apps/supaclockpro/app.js rename to apps/supaclk/app.js index 074425cef..c6731849f 100644 --- a/apps/supaclockpro/app.js +++ b/apps/supaclk/app.js @@ -2,6 +2,59 @@ // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global let drawTimeout; +const supaClockImg = { + width : 95, height : 13, bpp : 1, + buffer : atob("wL7B+Dhf4/C+4P//f328z0+/OZ9zPv/+/vt9fr99/X7e3f/8Bfb6/X77+vw9e///6+wMAv339fu+4DD/25v79Pv32/e4HNvAePf37BAweC+3+7f////////////P4B////////////////////////////7UEYf///////////2qrW////////////tdxh////////////iLtaA="), + palette: new Uint16Array(g.theme.dark ? [g.toColor("#fff"), 0] : [0, g.toColor("#fff")]), +} +// todo +// const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; + +const interpolatePos = function(pos1, pos2, factor, easing) { + if (easing !== undefined) { + factor = Math.pow(factor, easing); + } + return {x: (pos1.x*(1-factor) + pos2.x*factor)/2, y: (pos1.y*(1-factor) + pos2.y*factor)/2} +} + +let drawSplashScreen = function (frame, total) { + const R = Bangle.appRect; + g.reset().setColor(g.theme.fg).setBgColor(g.theme.bg); + const startPos = {x: -200, y: R.h/2}; + const endPos = {x: R.x2 - supaClockImg.width*2 + 30, y: R.h/2}; + const pos = interpolatePos(startPos, endPos, frame/total, 0.1) + g.setFontAlign(0, 1).setColor('#888').setFont("4x6:3").drawString('ULTRA', 100, frame*18); + g.setFontAlign(0, 1).setColor('#888').setFont("4x6:3").drawString('PRO', 40, R.x2 - frame*18); + g.clearRect(0, pos.y-5, R.x2, pos.y + supaClockImg.height+25); + var date = new Date(); + let minutes = date.getMinutes(); + minutes = (minutes < 10 ? '0' : '') + minutes; + let hours = date.getHours()+''; + g.drawImage(supaClockImg, pos.x, pos.y, {scale: 2}); + g.setColor(0).setFont('6x8:2').setFontAlign(0, 1).drawString(hours + ':' + minutes, R.x2/2, pos.y + supaClockImg.height + 25) +} + +// for fast startup-feeling, draw the splash screen once directly once +drawSplashScreen(0, 20); + +let splashScreen = function () { + g.clearRect(R.x,R.y, R.x2, R.y2); + return new Promise((resolve, reject) => { + let frame = 0; + function tick() { + drawSplashScreen(frame, 20); + frame += 1; + if (frame < 20) { + setTimeout(tick, 50); + } else { + resolve(); + } + } + tick(); + }) +} + + Graphics.prototype.setFontPlayfairDisplay = function() { // https://www.espruino.com/Font+Converter // @@ -27,52 +80,6 @@ Graphics.prototype.setFontPlayfairDisplaySm = function() { ); } -const supaClockImg = { - width : 95, height : 13, bpp : 1, - buffer : atob("wL7B+Dhf4/C+4P//f328z0+/OZ9zPv/+/vt9fr99/X7e3f/8Bfb6/X77+vw9e///6+wMAv339fu+4DD/25v79Pv32/e4HNvAePf37BAweC+3+7f////////////P4B////////////////////////////7UEYf///////////2qrW////////////tdxh////////////iLtaA="), - palette: new Uint16Array([0, g.toColor("#fff")]), -} -const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; - -const interpolatePos = function(pos1, pos2, factor, easing) { - if (easing !== undefined) { - factor = Math.pow(factor, easing); - } - return {x: (pos1.x*(1-factor) + pos2.x*factor)/2, y: (pos1.y*(1-factor) + pos2.y*factor)/2} -} - -let drawSplashScreen = function (t, total) { - g.reset().setColor(g.theme.fg).setBgColor(g.theme.bg); - const startPos = {x: -200, y: R.h/2}; - const endPos = {x: 100, y: R.h/2}; - const lastPos = interpolatePos(startPos, endPos, (t-1)/total) - const pos = interpolatePos(startPos, endPos, t/total) - - g.setFontAlign(0, 1).setColor('#888').setFont("4x6:3").drawString('ULTRA', 100, t*18); - g.setFontAlign(0, 1).setColor('#888').setFont("4x6:3").drawString('PRO', 40, R.x2 - t*18); - - g.clearRect(0, pos.y-5, R.x2, pos.y + supaClockImg.height+5); - g.drawImage(supaClockImg, pos.x, pos.y, {scale: 2}); - -} - -let splashScreen = function () { - g.clearRect(R.x,R.y, R.x2, R.y2); - return new Promise((resolve, reject) => { - let t = 0; - function tick() { - drawSplashScreen(t, 10); - t += 1; - if (t < 20) { - setTimeout(tick, 100); - } else { - resolve(); - } - } - tick(); - }) -} - // Actually draw the watch face let draw = function() { g.reset().setColor(g.theme.fg).setBgColor(g.theme.bg); @@ -84,22 +91,17 @@ let draw = function() { g.setColor(g.theme.fg) // Time const yt = R.y + 92 - 20 - 30 + 6 + 10; - const xt = R.w/2; + const xt = R.w/2 - 5; let hours = date.getHours()+''; - g.setFontAlign(1, 0).setFontPlayfairDisplay().drawString(hours, xt - 8, yt); g.setFontAlign(0, 0).setFontPlayfairDisplay().drawString(':', xt, yt); g.setFontAlign(-1, 0).setFontPlayfairDisplay().drawString(minutes, xt + 8, yt); - + // logo g.drawImage(supaClockImg, R.x2 - supaClockImg.width - 2, R.y + 2); - // Day of week - + // dow + date let dateStr = require("locale").dow(date).toUpperCase() + '\n' + require("locale").month(date, 2).toUpperCase() + ' ' + date.getDate(); g.setFont('6x8').setFontAlign(-1, 0).drawString(dateStr, R.x2 - supaClockImg.width - 2, R.y + 42 - 30 + 8); - g.drawLine(0, upperCI, R.x2, upperCI); - - // queue next draw if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = setTimeout(function() { drawTimeout = undefined; @@ -133,67 +135,60 @@ let clockInfoDrawR = (itm, info, options) => { g.setFontAlign(1,-1).drawString(text, options.x+options.w-24-3, options.y+6); }; + +let clockInfoItems; +let clockInfoMenu1; +let clockInfoMenu2; +let clockInfoMenu3; +let clockInfoMenu4; + // Show launcher when middle button pressed Bangle.setUI({ mode : "clock", - remove : function() { - // Called to unload all of the clock app + remove : function() { // for fastloading, clear the app memory if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - // remove info menu - clockInfoMenu.remove(); - delete clockInfoMenu; + delete Graphics.prototype.setFontPlayfairDisplay + delete Graphics.prototype.setFontPlayfairDisplaySm + delete clockInfoItems; + clockInfoMenu1.remove(); + delete clockInfoMenu1; clockInfoMenu2.remove(); delete clockInfoMenu2; clockInfoMenu3.remove(); delete clockInfoMenu3; clockInfoMenu4.remove(); delete clockInfoMenu4; - // reset theme - g.setTheme(oldTheme); }}); -// Load widgets + Bangle.loadWidgets(); -(() => { - function draw() { - g.reset(); // reset the graphics context to defaults (color/font/etc) - // add your code - g.drawString("XABCDEF", this.x, this.y); - } - - // add your widget - WIDGETS["mywidget"]={ - area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right), be aware that not all apps support widgets at the bottom of the screen - width: 28, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout - draw:draw // called to draw the widget - }; -})() - -// Work out sizes let R = Bangle.appRect; let midX = R.x+R.w/2; let upperCI = R.y2-28-28; let lowerCI = R.y2-28; -// Clear the screen once, at startup -let oldTheme = g.theme; g.clearRect(R.x, R.y, R.x2, R.y2); - splashScreen().then(() => { g.clearRect(R.x, 0, R.x2, R.y2); draw(); Bangle.drawWidgets(); // Allocate and draw clockinfos - g.drawString('Loading Clock Info Modules...', R.x + 10, upperCI); + g.setFontAlign(1, 1).setFont('6x8').drawString('Loading Clock Info Modules...', R.x + 10, upperCI); setTimeout(() => { // delay loading of clock info, so that the clock face appears quicker g.clearRect(R.x, upperCI, R.x2, upperCI+10); // clear loading text - let clockInfoItems = require("clock_info").load(); - let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:R.x+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDraw}); - let clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:midX+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDrawR}); - let clockInfoMenu3 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:R.x+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDraw}); - let clockInfoMenu4 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:midX+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDrawR}); + try { + clockInfoItems = require("clock_info").load(); + clockInfoMenu1 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:R.x+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDraw}); + clockInfoMenu2 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:midX+1, y:upperCI, w:midX-2, h:28, draw : clockInfoDrawR}); + clockInfoMenu3 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:R.x+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDraw}); + clockInfoMenu4 = require("clock_info").addInteractive(clockInfoItems, { app:"lcdclock", x:midX+1, y:lowerCI, w:midX-2, h:28, draw : clockInfoDrawR}); + } catch(err) { + if ((err + '').includes('Module "clock_info" not found' )) { + g.setFont('6x8').drawString('Please install\nclockinfo module!', R.x + 10, upperCI); + } + } }, 1); }); diff --git a/apps/supaclk/app.png b/apps/supaclk/app.png new file mode 100644 index 0000000000000000000000000000000000000000..54f2047a58f4193aebeae3d8a83842d088ccb2d9 GIT binary patch literal 3964 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 WMWWKyoVMox00000J~ literal 0 HcmV?d00001 diff --git a/apps/supaclk/metadata.json b/apps/supaclk/metadata.json new file mode 100644 index 000000000..016182545 --- /dev/null +++ b/apps/supaclk/metadata.json @@ -0,0 +1,16 @@ +{ "id": "supaclk", + "name": "SUPACLOCK Pro ULTRA", + "version": "0.01", + "description": "SUPACLOCK Pro ULTRA, with four ClockInfo areas at the bottom. Tap them and swipe up/down and left/right to toggle between different information.", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"}], + "type": "clock", + "tags": "clock,clkinfo,clockinfo", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "dependencies" : { "clock_info":"module" }, + "storage": [ + {"name":"supaclk.app.js","url":"app.js"}, + {"name":"supaclk.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/supaclk/screenshot.png b/apps/supaclk/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..54f2047a58f4193aebeae3d8a83842d088ccb2d9 GIT binary patch literal 3964 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 WMWWKyoVMox00000J~ literal 0 HcmV?d00001 diff --git a/apps/supaclk/screenshot2.png b/apps/supaclk/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..46d04a1661dc2d931a1d36801d052064a89858a2 GIT binary patch literal 4206 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 Ef>;jwKmY&$ literal 0 HcmV?d00001