forked from FOSS/BangleApps
Merge branch 'master' of github.com:espruino/BangleApps
# Conflicts: # apps.jsonmaster
commit
48bb819be7
20
apps.json
20
apps.json
|
@ -95,7 +95,7 @@
|
|||
"shortName":"Notifications",
|
||||
"icon": "notify.png",
|
||||
"version":"0.11",
|
||||
"description": "A handler for displaying notifications that displays them in a bar at the top of the screen",
|
||||
"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",
|
||||
|
@ -3507,7 +3521,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",
|
||||
|
|
|
@ -1 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwge27dtAX4C+/dt+wFB/wCECIu3/dvBYNv34RC7/tCIu//99EYN9C4IpB74jG3379ovDFIIRBEYxHD/47D2wjHCIX+AQJHBCIIXBNZt/+5QBEZIgBAQX///9EZRWBBARHDEwhlC/9/EAJoBDQIOBNwyPCEYYCDJQ4CJSQ4CB0O2lojL2lwBIXFiwsK0f/KgUbuwRJo6cBPAO34cUmJHH7U/97tBgEGBIODEY/RXoOw7cAgHbtlxoojGx7hCjAjD20ANA1378MEIIAB4d0u5HGNAPYCAYAB2n2SQSPDjv3CIsF2lxEYto//+CoOGCIUt0O3EYtHvqMBvlw4UAgJQBqIjERgQDBsO+7FAhaMH64DB+4qB+3AgARG9uhIgQJD4dghd+7dLBQZoBaISwC4cArf27dpCIf/23f9uHCIQABhoNClsl20ttuwgYKBEAIAChOmCIOH/vx9ttwB2BDgMBAoIRBmnbpkbtk2ltsgAMCJQOwAgMBk+eq3AhiSBsE2GAX//4WCAAOBAoVbtt8mCJBgHHfYMHdgoRBott+zmDsEAn/tEwkC7UAVoYACgPbv4REAASTBEYY0BPIPwCJAjEu3Dvq8BCAnbsEwGgm2jbAC8EAjFvEAQREjuwDQXbvvx7cd2K/EgEb9oRCAoLOBjEAgk/A="))
|
||||
require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA=="))
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: Initial Release
|
|
@ -0,0 +1,11 @@
|
|||
# Matrix Clock
|
||||
|
||||

|
||||
|
||||
## 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)
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("lEowkBBpNgEKV3Bhd2CZEGFZAgGAwUHuEGuAMIs4JFCYIBBBItmFRA7BCY4+Gs5MDCbZ3CHwQTNJgwTPB4h3LHYQTQG44Tfd4zsCCZJ3GBwQTMCwYTEgwTSbBVnCYZPDdhZSICbo7EMZbbGRZivDT54AJHIITHdYoAGBgxjCHYYnEO5QyGJpgMDbZgTLHpITJT50GOQKfTCaoMRRdITRPQQAJBgZyRC4oAFA"))
|
|
@ -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<Math.min(this.txt.length, this.length + 1) ; i++){
|
||||
idx = this.txt.length - i - 1;
|
||||
var color_strength=1 - i/this.length;
|
||||
if(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<NO_SHARDS; i++){
|
||||
shards.push(new TextShard(shard_x(i),50 + Math.random()*100,shard_length()) );
|
||||
}
|
||||
|
||||
var timeStr = "";
|
||||
var dateStr = "";
|
||||
var last_draw_time = null;
|
||||
|
||||
const TIME_X_COORD = 20;
|
||||
const TIME_Y_COORD = 100;
|
||||
const DATE_X_COORD = 170;
|
||||
const DATE_Y_COORD = 30;
|
||||
const RESET_PROBABILITY = 0.5;
|
||||
/**
|
||||
* main loop to draw the clock face
|
||||
*/
|
||||
function draw_clock(){
|
||||
// first move all the shards down the screen
|
||||
for(var i=0; i<this.shards.length; i++){
|
||||
var visible = shards[i].isVisible();
|
||||
// once the shard is no longer visible we wait
|
||||
// a random no of loops before reseting
|
||||
if(!visible && Math.random() > 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");
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
|
@ -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
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.01: First release
|
||||
0.02: Display 12 hour clock as 12:xx not 00:xx when just into PM
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA=="))
|
||||
require("heatshrink").decompress(atob("mEwge27dtAX4C+/dt+wFB/wCECIu3/dvBYNv34RC7/tCIu//99EYN9C4IpB74jG3379ovDFIIRBEYxHD/47D2wjHCIX+AQJHBCIIXBNZt/+5QBEZIgBAQX///9EZRWBBARHDEwhlC/9/EAJoBDQIOBNwyPCEYYCDJQ4CJSQ4CB0O2lojL2lwBIXFiwsK0f/KgUbuwRJo6cBPAO34cUmJHH7U/97tBgEGBIODEY/RXoOw7cAgHbtlxoojGx7hCjAjD20ANA1378MEIIAB4d0u5HGNAPYCAYAB2n2SQSPDjv3CIsF2lxEYto//+CoOGCIUt0O3EYtHvqMBvlw4UAgJQBqIjERgQDBsO+7FAhaMH64DB+4qB+3AgARG9uhIgQJD4dghd+7dLBQZoBaISwC4cArf27dpCIf/23f9uHCIQABhoNClsl20ttuwgYKBEAIAChOmCIOH/vx9ttwB2BDgMBAoIRBmnbpkbtk2ltsgAMCJQOwAgMBk+eq3AhiSBsE2GAX//4WCAAOBAoVbtt8mCJBgHHfYMHdgoRBott+zmDsEAn/tEwkC7UAVoYACgPbv4REAASTBEYY0BPIPwCJAjEu3Dvq8BCAnbsEwGgm2jbAC8EAjFvEAQREjuwDQXbvvx7cd2K/EgEb9oRCAoLOBjEAgk/A="))
|
||||
|
|
|
@ -154,16 +154,20 @@ function touchHandler(l,e) {
|
|||
if (l.c) l.c.forEach(n => touchHandler(n,e));
|
||||
}
|
||||
|
||||
function prepareLazyRender(l, rectsToClear, drawList, rects, bgCol) {
|
||||
if ((l.bgCol != null && l.bgCol != bgCol) || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") {
|
||||
function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
||||
var bgCol = l.bgCol == null ? parentBg : g.toColor(l.bgCol);
|
||||
if (bgCol != parentBg || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") {
|
||||
// Hash the layoutObject without including its children
|
||||
let c = l.c;
|
||||
var c = l.c;
|
||||
delete l.c;
|
||||
let hash = "H"+E.CRC32(E.toJS(l)); // String keys maintain insertion order
|
||||
var hash = "H"+E.CRC32(E.toJS(l)); // String keys maintain insertion order
|
||||
if (c) l.c = c;
|
||||
|
||||
if (!delete rectsToClear[hash]) {
|
||||
rects[hash] = {bg: bgCol, r: [l.x,l.y,l.x+l.w-1,l.y+l.h-1]};
|
||||
rects[hash] = {
|
||||
bg: parentBg == null ? g.theme.bg : parentBg,
|
||||
r: [l.x,l.y,l.x+l.w-1,l.y+l.h-1]
|
||||
};
|
||||
if (drawList) {
|
||||
drawList.push(l);
|
||||
drawList = null; // Prevent children from being redundantly added to the drawList
|
||||
|
@ -171,7 +175,7 @@ function prepareLazyRender(l, rectsToClear, drawList, rects, bgCol) {
|
|||
}
|
||||
}
|
||||
|
||||
if (l.c) for (let ch of l.c) prepareLazyRender(ch, rectsToClear, drawList, rects, l.bgCol == null ? bgCol : l.bgCol);
|
||||
if (l.c) for (var ch of l.c) prepareLazyRender(ch, rectsToClear, drawList, rects, bgCol);
|
||||
}
|
||||
|
||||
Layout.prototype.render = function (l) {
|
||||
|
@ -220,7 +224,7 @@ Layout.prototype.render = function (l) {
|
|||
if (!this.rects) this.rects = {};
|
||||
var rectsToClear = this.rects.clone();
|
||||
var drawList = [];
|
||||
prepareLazyRender(l, rectsToClear, drawList, this.rects, g.getBgColor());
|
||||
prepareLazyRender(l, rectsToClear, drawList, this.rects, null);
|
||||
for (var h in rectsToClear) delete this.rects[h];
|
||||
var clearList = Object.keys(rectsToClear).map(k=>rectsToClear[k]).reverse(); // Rects are cleared in reverse order so that the original bg color is restored
|
||||
for (var r of clearList) g.setBgColor(r.bg).clearRect.apply(g, r.r);
|
||||
|
|
Loading…
Reference in New Issue