diff --git a/apps.json b/apps.json index 05a8600f4..fe6d58440 100644 --- a/apps.json +++ b/apps.json @@ -94,8 +94,8 @@ "name": "Notifications (default)", "shortName":"Notifications", "icon": "notify.png", - "version":"0.10", - "description": "A handler for displaying notifications that displays them in a bar at the top of the screen", + "version":"0.11", + "description": "Provides the default `notify` module used by applications to display notifications in a bar at the top of the screen. This module is installed by default by client applications such as the Gadgetbridge app. Installing `Fullscreen Notifications` replaces this module with a version that displays the notifications using the full screen", "tags": "widget", "type": "notify", "readme": "README.md", @@ -108,7 +108,7 @@ "shortName":"Notifications", "icon": "notify.png", "version":"0.11", - "description": "A handler for displaying notifications that displays them fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notifications library.", + "description": "Provides a replacement for the `Notifications (default)` `notify` module. This version is used by applications to display notifications fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notify module.", "tags": "widget,b2", "type": "notify", "storage": [ @@ -319,6 +319,20 @@ {"name":"sweepclock.img","url":"sweepclock-icon.js","evaluate":true} ] }, + { "id": "matrixclock", + "name": "Matrix Clock", + "icon": "matrixclock.png", + "version":"0.01", + "description": "inspired by The Matrix, a clock of the same style", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"matrixclock.app.js","url":"matrixclock.js"}, + {"name":"matrixclock.img","url":"matrixclock-icon.js","evaluate":true} + ] + }, { "id": "imgclock", "name": "Image background clock", "shortName":"Image Clock", @@ -3524,7 +3538,7 @@ "name": "Pastel Clock", "shortName": "Pastel", "icon": "pastel.png", - "version":"0.01", + "version":"0.02", "description": "A Configurable clock with custom fonts and background", "tags": "clock,b2", "type":"clock", diff --git a/apps/matrixclock/ChangeLog b/apps/matrixclock/ChangeLog new file mode 100644 index 000000000..d53df991b --- /dev/null +++ b/apps/matrixclock/ChangeLog @@ -0,0 +1 @@ +0.01: Initial Release diff --git a/apps/matrixclock/README.md b/apps/matrixclock/README.md new file mode 100644 index 000000000..010524b60 --- /dev/null +++ b/apps/matrixclock/README.md @@ -0,0 +1,11 @@ +# Matrix Clock + +![](app.png) + +## Requests + +Please reach out to adrian@adriankirk.com if you have feature requests or notice bugs. + +## Creator + +Made by [Adrian Kirk](mailto:adrian@adriankirk.com) diff --git a/apps/matrixclock/app.png b/apps/matrixclock/app.png new file mode 100644 index 000000000..bc135c3ee Binary files /dev/null and b/apps/matrixclock/app.png differ diff --git a/apps/matrixclock/matrixclock-icon.js b/apps/matrixclock/matrixclock-icon.js new file mode 100644 index 000000000..5d5e9cd67 --- /dev/null +++ b/apps/matrixclock/matrixclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("lEowkBBpNgEKV3Bhd2CZEGFZAgGAwUHuEGuAMIs4JFCYIBBBItmFRA7BCY4+Gs5MDCbZ3CHwQTNJgwTPB4h3LHYQTQG44Tfd4zsCCZJ3GBwQTMCwYTEgwTSbBVnCYZPDdhZSICbo7EMZbbGRZivDT54AJHIITHdYoAGBgxjCHYYnEO5QyGJpgMDbZgTLHpITJT50GOQKfTCaoMRRdITRPQQAJBgZyRC4oAFA")) diff --git a/apps/matrixclock/matrixclock.js b/apps/matrixclock/matrixclock.js new file mode 100644 index 000000000..0bf33fd68 --- /dev/null +++ b/apps/matrixclock/matrixclock.js @@ -0,0 +1,259 @@ +/** + * Adrian Kirk 2021-10 + * + * Matrix Clock + * + * A simple clock inspired by the movie. + * Text shards move down the screen as a background to the + * time and date + **/ +const Locale = require('locale'); + +const SHARD_COLOR =[0,1.0,0]; +const SHARD_FONT_SIZE = 12; +const SHARD_Y_START = 30; +/** +* The text shard object is responsible for creating the +* shards of text that move down the screen. As the +* shard moves down the screen the latest character added +* is brightest with characters being coloured darker and darker +* going back to the eldest +*/ +class TextShard { + + constructor(x,y,length){ + // The x and y coords of the first character of the shard + this.x = x; + this.y = y; + // The visible length of the shard. We don't make the + // whole chain visible just to save on cpu time + this.length = length; + // the list of characters making up this shard + this.txt = []; + } + /** + * The add method call adds another random character to + * the chain + */ + add(){ + this.txt.push(randomChar()); + } + /** + * The show method displays the latest shard image to the + * screen with the following rules: + * - latest addition is brightest, oldest is darker + * - display up to defined length of characters only + * of the shard to save cpu + */ + show(){ + g.setFontAlign(-1,-1,0); + for(var i=0; i this.length - 2){ + color_strength = 0; + } + g.setColor(color_strength*SHARD_COLOR[0], + color_strength*SHARD_COLOR[1], + color_strength*SHARD_COLOR[2]); + g.setFont("Vector",SHARD_FONT_SIZE); + g.drawString(this.txt[idx], this.x, this.y + idx*SHARD_FONT_SIZE); + } + } + /** + * Method tests to see if any part of the shard chain is still + * visible on the screen + */ + isVisible(){ + return (this.y + (this.txt.length - this.length - 2)*SHARD_FONT_SIZE < g.getHeight()); + } + /** + * resets the shard back to the top of the screen + */ + reset(){ + this.y = SHARD_Y_START; + this.txt = []; + } +} + +/** +* random character chooser to be called by the shard when adding characters +*/ +const CHAR_CODE_START = 33; +const CHAR_CODE_LAST = 126; +const CHAR_CODE_LENGTH = CHAR_CODE_LAST - CHAR_CODE_START; +function randomChar(){ + return String.fromCharCode(Math.floor(Math.random() * CHAR_CODE_LENGTH)+ CHAR_CODE_START); +} + +// Now set up the shards +// we are going to have a limited no of shards (to save cpu) +// but randomize the x value and length every reset to make it look as if there +// are more +var shards = []; +const NO_SHARDS = 3; +const channel_width = g.getWidth()/NO_SHARDS; + +function shard_x(i){ + return i*channel_width + Math.random() * channel_width; +} + +function shard_length(){ + return Math.floor(Math.random()*5) + 3; +} + +for(var i=0; i RESET_PROBABILITY){ + shards[i].reset(); + shards[i].length = shard_length(); + shards[i].x = shard_x(i); + if(shards[i].x > DATE_X_COORD - 20){ + shards[i].y = 50; + } + } + // If its still visble then add to the shard and show to screen + if(visible){ + shards[i].add(); + } + // we still have to show the shard even though it may be off the screen to keep the speed constant + shards[i].show(); + } + var now = new Date(); + // draw time. Have to draw time on every loop + g.setFont("Vector",45); + g.setFontAlign(-1,-1,0); + if(last_draw_time == null || now.getMinutes() != last_draw_time.getMinutes()){ + g.setColor(0,0,0); + g.drawString(timeStr, TIME_X_COORD, TIME_Y_COORD); + timeStr = format_time(now); + } + g.setColor(SHARD_COLOR[0], + SHARD_COLOR[1], + SHARD_COLOR[2]); + g.drawString(timeStr, TIME_X_COORD, TIME_Y_COORD); + // + // draw date when it changes + g.setFont("Vector",15); + g.setFontAlign(-1,-1,0); + if(last_draw_time == null || now.getDate() != last_draw_time.getDate()){ + g.setColor(0,0,0); + g.drawString(dateStr, DATE_X_COORD, DATE_Y_COORD); + dateStr = format_date(now); + g.setColor(SHARD_COLOR[0], + SHARD_COLOR[1], + SHARD_COLOR[2]); + g.drawString(dateStr, DATE_X_COORD, DATE_Y_COORD); + } + last_draw_time = now; +} + +function format_date(now){ + return Locale.dow(now,1) + " " + format00(now.getDate()); +} + + +function format_time(now){ + var time = new Date(now.getTime()); + var hours = time.getHours() % 12; + if(hours < 1){ + hours = 12; + } + var am_pm; + if(time.getHours() < 12){ + am_pm = "AM"; + } else { + am_pm = "PM"; + } + return format00(hours) + ":" + format00(time.getMinutes()) + " "+ am_pm; +} + +function format00(num){ + var value = (num | 0); + if(value > 99 || value < 0) + throw "must be between in range 0-99"; + if(value < 10) + return "0" + value.toString(); + else + return value.toString(); +} + +// The interval reference for updating the clock +let intervalRef = null; + +function clearTimers(){ + if(intervalRef != null) { + clearInterval(intervalRef); + intervalRef = null; + } +} + +function shouldRedraw(){ + return Bangle.isLCDOn(); +} + +function startTimers(){ + clearTimers(); + if (Bangle.isLCDOn()) { + intervalRef = setInterval(() => { + if (!shouldRedraw()) { + //console.log("draw clock callback - skipped redraw"); + } else { + draw_clock(); + } + }, 100 + ); + draw_clock(); + } else { + console.log("scheduleDrawClock - skipped not visible"); + } +} + + +Bangle.on('lcdPower', (on) => { + if (on) { + console.log("lcdPower: on"); + startTimers(); + } else { + console.log("lcdPower: off"); + clearTimers(); + } +}); + +Bangle.on('faceUp',function(up){ + //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); + if (up && !Bangle.isLCDOn()) { + //console.log("faceUp and LCD off"); + clearTimers(); + Bangle.setLCDPower(true); + } +}); + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +startTimers(); +Bangle.setUI("clock"); + + diff --git a/apps/matrixclock/matrixclock.png b/apps/matrixclock/matrixclock.png new file mode 100644 index 000000000..634253674 Binary files /dev/null and b/apps/matrixclock/matrixclock.png differ diff --git a/apps/notify/ChangeLog b/apps/notify/ChangeLog index d1826f57e..8803b82b6 100644 --- a/apps/notify/ChangeLog +++ b/apps/notify/ChangeLog @@ -7,3 +7,4 @@ 0.08: Don't turn on screen during Quiet Mode 0.09: Add onHide callback 0.10: Improvements to help notifications work with themes +0.11: Fix regression that caused no notifications and corrupted background diff --git a/apps/notify/README.md b/apps/notify/README.md index f186aaab2..7b2473015 100644 --- a/apps/notify/README.md +++ b/apps/notify/README.md @@ -1,9 +1,8 @@ # Notifications (default) -A handler for displaying notifications that displays them in a bar at the top of the screen +The default version of the `notify` module for displaying notifications in a bar at the top of the screen -This is not an app, but instead it is a library that can be used by -other applications or widgets to display messages. +This module is installed by default by client applications such as Gadgetbridge. **Note:** There are other implementations of this library available such as `notifyfs` (Fullscreen Notifications). These can be used in the exact diff --git a/apps/notify/notify.js b/apps/notify/notify.js index 4448de73b..332c301d5 100644 --- a/apps/notify/notify.js +++ b/apps/notify/notify.js @@ -94,9 +94,8 @@ exports.show = function(options) { y = 320-size, h = size, b = y+h-1, r = x+w-1; // bottom,right - g.setClipRect(x,y, r,b); // clear area - g.reset(); + g.reset().setClipRect(x,y, r,b); if (options.bgColor!==undefined) g.setColor(options.bgColor); g.clearRect(x,y, r,b); // bottom border diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog index 7b83706bf..4b99fd7c1 100644 --- a/apps/pastel/ChangeLog +++ b/apps/pastel/ChangeLog @@ -1 +1,2 @@ 0.01: First release +0.02: Display 12 hour clock as 12:xx not 00:xx when just into PM diff --git a/apps/pastel/pastel.app.js b/apps/pastel/pastel.app.js index 0c1d56118..9f9efd171 100644 --- a/apps/pastel/pastel.app.js +++ b/apps/pastel/pastel.app.js @@ -73,7 +73,8 @@ function draw() { // fix hh for 12hr clock var h2 = "0" + parseInt(hh) % 12 || 12; - hh = h2.substr(h2.length -2); + if (parseInt(hh) > 12) + hh = h2.substr(h2.length -2); var w = g.getWidth(); var h = g.getHeight();