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 000000000..54f2047a5 Binary files /dev/null and b/apps/supaclk/app.png differ 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 000000000..54f2047a5 Binary files /dev/null and b/apps/supaclk/screenshot.png differ diff --git a/apps/supaclk/screenshot2.png b/apps/supaclk/screenshot2.png new file mode 100644 index 000000000..46d04a166 Binary files /dev/null and b/apps/supaclk/screenshot2.png differ