diff --git a/apps/pongclock/ChangeLog b/apps/pongclock/ChangeLog new file mode 100644 index 000000000..7b83706bf --- /dev/null +++ b/apps/pongclock/ChangeLog @@ -0,0 +1 @@ +0.01: First release diff --git a/apps/pongclock/README.md b/apps/pongclock/README.md new file mode 100644 index 000000000..894070b73 --- /dev/null +++ b/apps/pongclock/README.md @@ -0,0 +1,15 @@ +# Pong Clock + +A clock which is playing Pong while showing the current time as score +* Settings + * Show or hide widgets (auto detecting the used widgets areas) + * Use inverted or standard theme colors for the play area + * Optionally pause while locked (saving battery) +* Loosely based on [https://codepen.io/Rabrennie/pen/WxNEoe](https://codepen.io/Rabrennie/pen/WxNEoe) + +![](screenshot.png) +![](screenshot_settings.png) +![](screenshot_invers_full.png) + +## Creator +[@pidajo](https://github.com/pidajo) diff --git a/apps/pongclock/app.js b/apps/pongclock/app.js new file mode 100644 index 000000000..2a10bf6ed --- /dev/null +++ b/apps/pongclock/app.js @@ -0,0 +1,310 @@ +class Ball { + constructor(collision) { + this.collision = collision; + this.w = 4; + this.h = this.w; + this.y = height / 2 - this.h / 2; + this.x = width / 2 - this.w / 2; + this.oldX = this.x; + this.oldY = this.y; + this.velX = 6; + this.velY = 3.5 + Math.random(); + } + + reset() { + this.y = height / 2 - this.h / 2; + this.x = width / 2 - this.w / 2; + this.velX = 6; + this.velY = 3.5 + Math.random(); + } + + checkCollision(that, isLeft) { + let test = false; + if (isLeft) { + test = this.x <= that.w + this.w && this.y > that.y && this.y < that.y + that.h; + } else { + test = this.x >= that.x + this.w && this.y > that.y && this.y < that.y + that.h; + } + if (test) { + this.velX = -this.velX; + this.velY = (3.5 + 2 * Math.random()) * this.velY / Math.abs(this.velY); + + if (isLeft) { + right.follow = this; + left.follow = null; + } else { + left.follow = this; + right.follow = null; + } + } + } + + move() { + if (this.velX > 0) { + this.checkCollision(right, false); + } else { + this.checkCollision(left, true); + } + + this.x += this.velX; + this.y += this.velY; + + if (this.y <= this.h) { + this.y = this.h; + this.velY = -this.velY; + } + + if (this.y >= height - this.h) { + this.y = height - this.h; + this.velY = -this.velY; + } + + if (this.x >= width) { + left.scored(); + restart(); + } else if (this.x < 0) { + right.scored(); + restart(); + } + + } +} + +class Paddle { + constructor(side) { + this.side = side; + this.w = 4; //15; + this.h = 30; //80; + this.y = height / 2 - this.h / 2; + this.follow = null; + this.target = height / 2 - this.h / 2; + this.score = 99; + this.hasLost = false; + } + + reset() { + this.follow = null; + this.hasLost = false; + this.target = height / 2 - this.h / 2; + this.y = height / 2 - this.h / 2; + this.move(); + } + + scored() { + let d = new Date(); + let value = 0; + if (this.side == "left") { + value = d.getHours(); + } else { + value = d.getMinutes(); + } + if (this.score < value) { + this.score++; + } else { + this.score = value; + } + } + + move() { + + if (this.follow && !this.hasLost) { + var dy = this.follow.y - this.y - this.h / 2; + this.y += dy / 2; + } else { + this.y += (this.target - this.y) / 10; + } + if (this.y < 0) { + this.y = 0; + } + if (this.y > height - this.h) { + this.y = height - this.h; + } + } +} + +var updateTimeout = null; + +function update() { + var d = new Date(); + var lastStep = Date.now(); + left.move(); + right.move(); + if (d.getHours() != left.score) { + right.follow = null; + right.hasLost = true; + } + if (d.getMinutes() != right.score) { + left.follow = null; + left.hasLost = true; + } + + ball.move(); + redraw(); + var nextStep = 40 - (Date.now() - lastStep); + //console.log(nextStep); + updateTimeout = setTimeout(update, nextStep > 0 ? nextStep : 0); + return lastStep; +} + +function redraw() { + let fontHeight = width / 3.6; + let fontTop = top + height / 11; + let topHeight = top + height; + g.reset(); + + if (settings.isInvers) { + g.setColor(g.theme.bg); + g.setBgColor(g.theme.fg); + } + + g.clearRect(0, top + left.oldY, left.w, top + left.oldY + left.h); + g.clearRect(width - right.w, top + right.oldY, width, top + right.oldY + right.h); + //g.clearRect(width / 2 - fontHeight * 1.4, fontTop, width / 2 + fontHeight * 1.4, fontTop + fontHeight); + g.clearRect(ball.oldX - ball.w, top + ball.oldY - ball.h, ball.oldX + ball.w, top + ball.oldY + ball.h); + + g.setFontVector(fontHeight); + /**/ + g.setFontAlign(1, -1); + g.drawString(("0" + left.score).substr(-2), 5 * width / 11, fontTop, true); + g.setFontAlign(-1, -1); + g.drawString(("0" + right.score).substr(-2), 6 * width / 11, fontTop, true); + /**/ + + g.drawLine(width / 2, top, width / 2, topHeight); + g.fillRect(0, top + left.y, left.w, top + left.y + left.h); + left.oldY = left.y; + g.fillRect(width - right.w, top + right.y, width, top + right.y + right.h); + right.oldY = right.y; + g.fillCircle(ball.x, top + ball.y, ball.w); + ball.oldX = ball.x; + ball.oldY = ball.y; +} + +function restart() { + g.reset(); + if (settings.isInvers) { + g.setColor(g.theme.bg); + g.setBgColor(g.theme.fg); + } + g.clearRect(0, top, width, top + height); + ball.reset(); + left.reset(); + right.reset(); + right.follow = ball; + left.move(); + right.move(); + if (settings.withWidgets) { + Bangle.drawWidgets(); + } +} + +function stop() { + if (updateTimeout) { + clearTimeout(updateTimeout); + } + updateTimeout = null; + if (pauseTimeout) { + clearTimeout(pauseTimeout); + } + pauseTimeout = null; +} + +var pauseTimeout = null; + +function pause() { + stop(); + left.scored(); + right.scored(); + redraw(); + pauseTimeout = setTimeout(pause, Date.now() % 60000); +} + +//load settings +const SETTINGS_FILE = "pongclock.json"; +var settings = Object.assign({ + // default values + withWidgets: true, + isInvers: false, + playLocked: true, +}, require('Storage').readJSON(SETTINGS_FILE, true) || {}); +require('Storage').writeJSON(SETTINGS_FILE, settings); + +//make clock +Bangle.setUI("clock"); + +//setup play area +var height = g.getHeight(), + width = g.getWidth(); +var top = 0; + +g.reset(); +g.clearRect(0, top, width, height); + +if (settings.withWidgets) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + //console.log(WIDGETS); + if (global.WIDGETS) { + let bottom = 0; + for (var i in WIDGETS) { + var w = WIDGETS[i]; + if (w.area) { + if (w.area.indexOf("t") >= 0) { + top = Bangle.appRect.y; + } + if (w.area.indexOf("b") >= 0) { + bottom = height - Bangle.appRect.y2; + } + } + } + height -= top + bottom; + } +} + +if (settings.isInvers) { + g.setColor(g.theme.bg); + g.setBgColor(g.theme.fg); +} +g.clearRect(0, top, width, top + height); + +//setup game +var left = new Paddle("left"); +var right = new Paddle("right"); +var ball = new Ball(true); + +left.x = 20; +right.x = width - 20; + +left.scored(); +right.scored(); + +Bangle.on("lock", (on) => { + //console.log(on); + if (!settings.playLocked) { + if (on) { + pause(); + } else { + stop(); + update(); + } + } +}); + +//start clock +restart(); +if (!settings.playLocked && Bangle.isLocked()) { + pause(); +} else { + update(); +} + +/* +//local testing +require("Storage").write("pongclock.info",{ + "id":"pongclock", + "name":"Pong Clock", + "type":"clock", + "src":"pongclock.app.js", + "icon":"pongclock.img" +}); +*/ diff --git a/apps/pongclock/metadata.json b/apps/pongclock/metadata.json new file mode 100644 index 000000000..dbd044517 --- /dev/null +++ b/apps/pongclock/metadata.json @@ -0,0 +1,20 @@ +{ "id": "pongclock", + "name": "Pong Clock", + "shortName":"Pong Clock", + "icon": "pongclock.png", + "version":"0.01", + "description": "A Pong playing clock", + "tags": "", + "allow_emulator":true, + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme":"README.md", + "screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot_settings.png" }, { "url":"screenshot_invers_full.png" } ], + "storage": [ + {"name":"pongclock.app.js","url":"app.js"}, + {"name":"pongclock.img","url":"pongclock-icon.js","evaluate":true}, + {"name":"pongclock.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"pongclock.json"} + ] +} diff --git a/apps/pongclock/pongclock-icon.js b/apps/pongclock/pongclock-icon.js new file mode 100644 index 000000000..22e472af4 --- /dev/null +++ b/apps/pongclock/pongclock-icon.js @@ -0,0 +1 @@ +atob("MDCEBAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAIiAAAAAAAAAAEAAAAAAAABP/EAE//yAAAAAAAD8wAAAT//IAAAAAAv//EA////IAAAAAAP8gAAH///8gAAAAAvP/EB/xA/MAIiAAAf8QAAL/ED8wAAAAAxD/EC8wAf8ALyAAAv8AAAPyAC/wAAAAAAD/ED/wAf8ALyAAD/MAAA/zAC8wAAAAAAD/EAAAAv8ALyAAH/EAAAAAAD8wAAAAAAD/EAAAA/IALyAAL/AAAAAAAP8gAAAAAAD/EAAAH/EALyAAPzD/IAAAAv8AAAAAAAD/EAAAPzAALyAA/yD/IAAAD/IAAAAAAAD/EAAB/xAALyAB/xD/IAAAL/AAAAAAAAD/EAAP8wAALyAC/wD/IAAB/yAAAAAAAAD/EAAv8QAAIiAP8wD/IAAD/wAAAAAAAAD/EAD/MAAAAAAf/zP/MwAf8gAAAA//AAD/EAL/AAAAAAAf////8wA/8AAAAA//AAD/EB/zAAAAIiACIiL/MgL/IAAAAA//AAD/EC////8ALyAAAAD/IAP////wAA//AAD/EC////8ALyAAAAD/IAP////wAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAALyAAAAAAAAAAAAAAAA//AAAAAAAAAAAAIiAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAD/8A//AAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAIiAAAAAAAAAAAAD/8AAAAAAAASEAAAAALyAAAAAAAAAAAAD/8AAAAAAAP/8wAAAALyAAAAAAAAAAAAD/8AAAAAAB///xAAAALyAAAAAAAAAAAAD/8AAAAAAC///yAAAALyAAAAAAAAAAAAD/8AAAAAAB///xAAAALyAAAAAAAAAAAAD/8AAAAAAAP/8wAAAALyAAAAAAAAAAAAD/8AAAAAAAASEAAAAALyAAAAAAAAAAAAD/8AAAAAAAAAAAAAAALyAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAIiAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyAAAAAAAAAAAAAAAA==") diff --git a/apps/pongclock/pongclock.png b/apps/pongclock/pongclock.png new file mode 100644 index 000000000..78934d7c6 Binary files /dev/null and b/apps/pongclock/pongclock.png differ diff --git a/apps/pongclock/screenshot.png b/apps/pongclock/screenshot.png new file mode 100644 index 000000000..0750105f0 Binary files /dev/null and b/apps/pongclock/screenshot.png differ diff --git a/apps/pongclock/screenshot_invers_full.png b/apps/pongclock/screenshot_invers_full.png new file mode 100644 index 000000000..434e24872 Binary files /dev/null and b/apps/pongclock/screenshot_invers_full.png differ diff --git a/apps/pongclock/screenshot_settings.png b/apps/pongclock/screenshot_settings.png new file mode 100644 index 000000000..0b27286ea Binary files /dev/null and b/apps/pongclock/screenshot_settings.png differ diff --git a/apps/pongclock/settings.js b/apps/pongclock/settings.js new file mode 100644 index 000000000..0d61d013d --- /dev/null +++ b/apps/pongclock/settings.js @@ -0,0 +1,44 @@ +(function(back) { + var FILE = "pongclock.json"; + // Load settings + var settings = Object.assign({ + // default values + withWidgets: true, + isInvers: false, + playLocked: true, + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + // Show the menu + E.showMenu({ + "" : { "title" : "Pong Clock" }, + "< Back" : () => back(), + 'Widgets?': { + value: !!settings.withWidgets, // !! converts undefined to false + format: v => v?"Show":"Hide", + onchange: v => { + settings.withWidgets = v; + writeSettings(); + } + }, + 'Inverted?': { + value: !!settings.isInvers, // !! converts undefined to false + format: v => v?"Yes":"No", + onchange: v => { + settings.isInvers = v; + writeSettings(); + } + }, + 'On Lock?': { + value: !!settings.playLocked, // !! converts undefined to false + format: v => v?"Play":"Pause", + onchange: v => { + settings.playLocked = v; + writeSettings(); + } + } + }); +})/*(load)/**/ diff --git a/apps/widday/ChangeLog b/apps/widday/ChangeLog new file mode 100644 index 000000000..7b83706bf --- /dev/null +++ b/apps/widday/ChangeLog @@ -0,0 +1 @@ +0.01: First release diff --git a/apps/widday/README.md b/apps/widday/README.md new file mode 100644 index 000000000..61f48aa4c --- /dev/null +++ b/apps/widday/README.md @@ -0,0 +1,9 @@ +# Day Widget + +Just shows the day of the current date, to save space in the widget area. The month and year should be known because they don't change that often. Just the number in maximum size for readability. + +![](screenshot.png) + +## Creator +[@pidajo](https://github.com/pidajo) + diff --git a/apps/widday/app-icon.js b/apps/widday/app-icon.js new file mode 100644 index 000000000..aa17aedc5 --- /dev/null +++ b/apps/widday/app-icon.js @@ -0,0 +1 @@ +atob("MDCEAiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIBEREREREREREREREREREREREREREQIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////zMz////8zMzMzMzP////xIiIf///////czM////PMzMzMzMzP///xIiIf/////zzMzM////PMzMzMzMzP///xIiIf////PczMzM////PMzMzMzMzP///xIiIf////3MzMzM////8zMzMz3MzP///xIiIf////3MM8zM//////////zMw////xIiIf////0/88zM/////////zzMz////xIiIf//////88zM/////////8zM3////xIiIf//////88zM////////88zM/////xIiIf//////88zM/////////MzN/////xIiIf//////88zM////////PMzD/////xIiIf//////88zM////////3Mzf/////xIiIf//////88zM////////zMw//////xIiIf//////88zM///////9zMz//////xIiIf//////88zM///////8zMP//////xIiIf//////88zM//////88zM///////xIiIf//////88zM///////MzN///////xIiIf////8zM8zM//////PMzD///////xIiIf////3MzMzMzM3///3Mzf///////xIiIf////3MzMzMzM3//zzMw////////xIiIf////PMzMzMzM3//9zMz////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIf///////////////////////////xIiIBEREREREREREREREREREREREREREQIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIg==") diff --git a/apps/widday/metadata.json b/apps/widday/metadata.json new file mode 100644 index 000000000..82de23035 --- /dev/null +++ b/apps/widday/metadata.json @@ -0,0 +1,15 @@ +{ "id": "widday", + "name": "Day Widget", + "shortName":"My Timer", + "icon": "widget.png", + "type": "widget", + "version":"0.01", + "description": "Just the day of the current date as widget", + "readme": "README.md", + "tags": "widget,say,date", + "supports": ["BANGLEJS", "BANGLEJS2"], + "screenshots" : [ { "url":"screenshot.png" } ], + "storage": [ + {"name":"widday.wid.js","url":"widget.js"} + ] +} diff --git a/apps/widday/screenshot.png b/apps/widday/screenshot.png new file mode 100644 index 000000000..9a7a9f8cf Binary files /dev/null and b/apps/widday/screenshot.png differ diff --git a/apps/widday/widget.js b/apps/widday/widget.js new file mode 100644 index 000000000..cdea76a29 --- /dev/null +++ b/apps/widday/widget.js @@ -0,0 +1,27 @@ +(() => { + var width = 32; // width of the widget + + function draw() { + var date = new Date(); + g.reset(); // reset the graphics context to defaults (color/font/etc) + g.setFontAlign(0,1); // center fonts + //g.drawRect(this.x, this.y, this.x+width-1, this.y+23); // check the bounds! + + var text = date.getDate(); + g.setFont("Vector", 24); + g.drawString(text, this.x+width/2+1, this.y + 28); + //g.setColor(0, 0, 1); + //g.drawRect(this.x, this.y, this.x+width-2, this.y+1); + } + + setInterval(function() { + WIDGETS["widday"].draw(WIDGETS["widdateday"]); + }, 10*60000); // update every 10 minutes + + // add your widget + WIDGETS["widday"]={ + area:"bl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: width, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout + draw:draw // called to draw the widget + }; +})() diff --git a/apps/widday/widget.png b/apps/widday/widget.png new file mode 100644 index 000000000..462097871 Binary files /dev/null and b/apps/widday/widget.png differ