David Peer 2022-05-15 21:45:59 +02:00
commit 1a7445ad60
57 changed files with 2619 additions and 68 deletions

View File

@ -1,2 +1,3 @@
0.01: New App
0.02: app keeps track of statistics now
0.03: Fix bug in valid word detection

View File

@ -110,7 +110,12 @@ class Wordle {
}
}
addGuess(w) {
if ((this.words.indexOf(w.toLowerCase())%5)!=0) {
let idx = -1;
do{
idx = this.words.indexOf(w.toLowerCase(), idx+1);
}
while(idx !== -1 && idx%5 !== 0);
if(idx%5 !== 0) {
E.showAlert(w+"\nis not a word", "Invalid word").then(function() {
layout = getKeyLayout("");
wordle.render(true);

View File

@ -2,7 +2,7 @@
"name": "Bordle",
"shortName":"Bordle",
"icon": "app.png",
"version":"0.02",
"version":"0.03",
"description": "Bangle version of a popular word search game",
"supports" : ["BANGLEJS2"],
"readme": "README.md",

View File

@ -0,0 +1,11 @@
# Banglejs - Touchscreen calibration
A simple calibration app for the touchscreen
## Usage
Once lauched touch the cross that appear on the screen to make
another spawn elsewhere.
each new touch on the screen will help to calibrate the offset
of your finger on the screen. After five or more input, press
the button to save the calibration and close the application.

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwkB/4AJ+EPBhQXg+BBDCyJaGGR5zIDBoQEL4QYOLYR3GBIouJR5AYBGBILBU5QMGFwgiFX4wwIEI4XGGBAgHd44+HD44XHNw4XWM5IIHCIoXWV5IXICQgXvLxAAKCYYXh5nMC6n8C4PPC5MAAA8PC4ZxBACAXOI653hU5zvJABASEC5PwHI4XcMBIXICIoXXJBAXHCAwXXJBAXHB5AfGC4ygJEAwXGQ5BoIQxoiDBYgXECwIuIBgb5ECIQJFGBQmCC4QHEDBwAFCxoYICx5ZELZoZJFiIXpA="))

85
apps/calibration/app.js Normal file
View File

@ -0,0 +1,85 @@
class BanglejsApp {
constructor() {
this.x = 0;
this.y = 0;
this.settings = {
xoffset: 0,
yoffset: 0,
};
}
load_settings() {
let settings = require('Storage').readJSON('calibration.json', true) || {active: false};
// do nothing if the calibration is deactivated
if (settings.active === true) {
// cancel the calibration offset
Bangle.on('touch', function(button, xy) {
xy.x += settings.xoffset;
xy.y += settings.yoffset;
});
}
if (!settings.xoffset) settings.xoffset = 0;
if (!settings.yoffset) settings.yoffset = 0;
console.log('loaded settings:');
console.log(settings);
return settings;
}
save_settings() {
this.settings.active = true;
this.settings.reload = false;
require('Storage').writeJSON('calibration.json', this.settings);
console.log('saved settings:');
console.log(this.settings);
}
explain() {
/*
* TODO:
* Present how to use the application
*
*/
}
drawTarget() {
this.x = 16 + Math.floor(Math.random() * (g.getWidth() - 32));
this.y = 40 + Math.floor(Math.random() * (g.getHeight() - 80));
g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24);
g.drawLine(this.x, this.y - 5, this.x, this.y + 5);
g.drawLine(this.x - 5, this.y, this.x + 5, this.y);
g.setFont('Vector', 10);
g.drawString('current offset: ' + this.settings.xoffset + ', ' + this.settings.yoffset, 0, 24);
}
setOffset(xy) {
this.settings.xoffset = Math.round((this.settings.xoffset + (this.x - Math.floor((this.x + xy.x)/2)))/2);
this.settings.yoffset = Math.round((this.settings.yoffset + (this.y - Math.floor((this.y + xy.y)/2)))/2);
}
}
E.srand(Date.now());
Bangle.loadWidgets();
Bangle.drawWidgets();
calibration = new BanglejsApp();
calibration.load_settings();
let modes = {
mode : 'custom',
btn : function(n) {
calibration.save_settings(this.settings);
load();
},
touch : function(btn, xy) {
calibration.setOffset(xy);
calibration.drawTarget();
},
};
Bangle.setUI(modes);
calibration.drawTarget();

14
apps/calibration/boot.js Normal file
View File

@ -0,0 +1,14 @@
let cal_settings = require('Storage').readJSON("calibration.json", true) || {active: false};
Bangle.on('touch', function(button, xy) {
// do nothing if the calibration is deactivated
if (cal_settings.active === false) return;
// reload the calibration offset at each touch event /!\ bad for the flash memory
if (cal_settings.reload === true) {
cal_settings = require('Storage').readJSON("calibration.json", true);
}
// apply the calibration offset
xy.x += cal_settings.xoffset;
xy.y += cal_settings.yoffset;
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

View File

@ -0,0 +1,17 @@
{ "id": "calibration",
"name": "Touchscreen Calibration",
"shortName":"Calibration",
"icon": "calibration.png",
"version":"1.00",
"description": "A simple calibration app for the touchscreen",
"supports": ["BANGLEJS","BANGLEJS2"],
"readme": "README.md",
"tags": "tool",
"storage": [
{"name":"calibration.app.js","url":"app.js"},
{"name":"calibration.boot.js","url":"boot.js"},
{"name":"calibration.settings.js","url":"settings.js"},
{"name":"calibration.img","url":"app-icon.js","evaluate":true}
],
"data": [{"name":"calibration.json"}]
}

View File

@ -0,0 +1,23 @@
(function(back) {
var FILE = "calibration.json";
var settings = Object.assign({
active: true,
}, require('Storage').readJSON(FILE, true) || {});
function writeSettings() {
require('Storage').writeJSON(FILE, settings);
}
E.showMenu({
"" : { "title" : "Calibration" },
"< Back" : () => back(),
'Active': {
value: !!settings.active,
format: v => v? "On":"Off",
onchange: v => {
settings.active = v;
writeSettings();
}
},
});
})

View File

@ -6,4 +6,5 @@
0.06: Fixed issue 1609 added a message popup state handler to control unwanted screen redraw
0.07: Optimized the mover algorithm for efficiency (work in progress)
0.08: Bug fix at end of the game with victorious splash and glorious orchestra
0.09: Added settings menu, removed symbol selection button (*), added highscore reset
0.09: Added settings menu, removed symbol selection button (*), added highscore reset
0.10: fixed clockmode in settings

View File

@ -1,7 +1,7 @@
{ "id": "game1024",
"name": "1024 Game",
"shortName" : "1024 Game",
"version": "0.09",
"version": "0.10",
"icon": "game1024.png",
"screenshots": [ {"url":"screenshot.png" } ],
"readme":"README.md",

View File

@ -32,10 +32,10 @@
}
},
"Exit press:": {
value: !settings.debugMode, // ! converts undefined to true
value: !settings.clockMode, // ! converts undefined to true
format: v => v?"short":"long",
onchange: v => {
settings.debugMode = v;
settings.clockMode = v;
writeSettings();
},
},
@ -67,4 +67,4 @@
}
// Show the menu
E.showMenu(settingsMenu);
})
})

1
apps/kbmorse/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New Keyboard!

25
apps/kbmorse/README.md Normal file
View File

@ -0,0 +1,25 @@
# Morse Keyboard
A library that provides the ability to input text by entering morse code.
![demo](demo.gif)
## Usage
* Press `BTN1` to input a dot, `BTN3` to input a dash, and `BTN2` to accept the
character for your current input.
* Long-press `BTN1` to toggle UPPERCASE for your next character.
* Long-press `BTN2` to finish editing.
* Tap the left side of the screen for backspace.
* Swipe left/right to move the cursor.
* Input three spaces in a row for a newline.
The top/bottom of the screen show which characters start with your current input,
so basically you just look which side includes the letter you want to type, and
press that button to narrow your selection, until it appears next to `BTN2`.
## For Developers
See the README for `kbswipe`/`kbtouch` for instructions on how to use this in your app.

BIN
apps/kbmorse/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
apps/kbmorse/demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 KiB

247
apps/kbmorse/lib.js Normal file
View File

@ -0,0 +1,247 @@
exports.input = function(options) {
options = options || {};
let text = options.text;
if ("string"!= typeof text) text = "";
let code = "",
cur = text.length, // cursor position
uc = !text.length, // uppercase
spc = 0; // consecutive spaces entered
const codes = {
// letters
"a": ".-",
"b": "-...",
"c": "-.-.",
"d": "-..",
"e": ".",
// no é
"f": "..-.",
"g": "--.",
"h": "....",
"i": "..",
"j": ".---",
"k": "-.-",
"l": ".-..",
"m": "--",
"n": "-.",
"o": "---",
"p": ".--.",
"q": "--.-",
"r": ".-.",
"s": "...",
"t": "-",
"u": "..-",
"v": "...-",
"w": ".--",
"x": "-..-",
"y": "-.--",
"z": "--..",
//digits
"1": ".----",
"2": "..---",
"3": "...--",
"4": "....-",
"5": ".....",
"6": "-....",
"7": "--...",
"8": "---..",
"9": "----.",
"0": "-----",
// punctuation
".": ".-.-.-",
",": "--..--",
":": "---...",
"?": "..--..",
"!": "-.-.--",
"'": ".----.",
"-": "-....-",
"_": "..--.-",
"/": "-..-.",
"(": "-.--.",
")": "-.--.-",
"\"": ".-..-.",
"=": "-...-",
"+": ".-.-.",
"*": "-..-",
"@": ".--.-.",
"$": "...-..-",
"&": ".-...",
}, chars = Object.keys(codes);
function choices(start) {
return chars.filter(char => codes[char].startsWith(start));
}
function char(code) {
if (code==="") return " ";
for(const char in codes) {
if (codes[char]===code) return char;
}
const c = choices(code);
if (c.length===1) return c[0]; // "-.-.-" is nothing, and only "-.-.--"(!) starts with it
return null;
}
return new Promise((resolve, reject) => {
function update() {
let dots = [], dashes = [];
layout.pick.label = (code==="" ? " " : "");
choices(code).forEach(char => {
const c = codes[char];
if (c===code) {
layout.pick.label = char;
}
const next = c.substring(code.length, code.length+1);
if (next===".") dots.push(char);
else if (next==="-") dashes.push(char);
});
if (!code && spc>1) layout.pick.label = atob("ABIYAQAAAAAAAAAABwABwABwABwABwABwOBwOBwOBxwBxwBxwB/////////xwABwABwAAOAAOAAOAA==");
g.setFont("6x8:2");
const wrap = t => g.wrapString(t, Bangle.appRect.w-60).join("\n");
layout.del.label = cur ? atob("AAwIAQ/hAiKkEiKhAg/gAA==") : " ";
layout.code.label = code;
layout.dots.label = wrap(dots.join(" "));
layout.dashes.label = wrap(dashes.join(" "));
if (uc) {
layout.pick.label = layout.pick.label.toUpperCase();
layout.dots.label = layout.dots.label.toUpperCase();
layout.dashes.label = layout.dashes.label.toUpperCase();
}
let label = text.slice(0, cur)+"|"+text.slice(cur);
layout.text.label = g.wrapString(label, Bangle.appRect.w-80).join("\n")
.replace("|", atob("AAwQAfPPPAwAwAwAwAwAwAwAwAwAwAwAwPPPPA=="));
layout.update();
layout.render();
}
function add(d) {
code += d;
const l = choices(code).length;
if (l===1) done();
else if (l<1) {
Bangle.buzz(20);
code = code.slice(0, -1);
} else update();
}
function del() {
if (code.length) code = code.slice(0, -1); // delete last dot/dash
else if (cur) { // delete char at cursor
text = text.slice(0, cur-1)+text.slice(cur);
cur--;
} else Bangle.buzz(20); // (already) at start of text
spc = 0;
uc = false;
update();
}
function done() {
let c = char(code);
if (c!==null) {
if (uc) c = c.toUpperCase();
uc = false;
text = text.slice(0, cur)+c+text.slice(cur);
cur++;
code = "";
if (c===" ") spc++;
else spc = 0;
if (spc>=3) {
text = text.slice(0, cur-3)+"\n"+text.slice(cur);
cur -= 2;
uc = true;
spc = 0;
}
update();
} else {
console.log(`No char for ${code}!`);
Bangle.buzz(20);
}
}
const Layout = require("Layout");
let layout = new Layout({
type: "h", c: [
{
type: "v", width: Bangle.appRect.w-8, bgCol: g.theme.bg, c: [
{id: "dots", type: "txt", font: "6x8:2", label: "", fillx: 1, bgCol: g.theme.bg},
{filly: 1, bgCol: g.theme.bg},
{
type: "h", fillx: 1, c: [
{id: "del", type: "txt", font: "6x8", label: "<X"},
{width: 5, bgCol: g.theme.bg},
{id: "text", type: "txt", font: "6x8:2", col: g.theme.fg2, bgCol: g.theme.bg2},
{fillx: 1, bgCol: g.theme.bg},
{id: "code", type: "txt", font: "6x8", label: "", bgCol: g.theme.bg},
{width: 5, bgCol: g.theme.bg},
{id: "pick", type: "txt", font: "6x8:3", label: "", col: g.theme.fgH, bgCol: g.theme.bgH},
],
},
{filly: 1, bgCol: g.theme.bg},
{id: "dashes", type: "txt", font: "6x8:2", label: "", fillx: 1, bgCol: g.theme.bg},
]
},
// button labels (rotated 90 degrees)
{
type: "v", pad: 1, filly: 1, c: ["<.", "^", "|"].map(l =>
({type: "txt", font: "6x8", height: Math.floor(Bangle.appRect.h/3), r: 1, label: l})
)
}
]
});
g.reset().clear();
update();
if (Bangle.btnWatches) Bangle.btnWatches.forEach(clearWatch);
Bangle.btnWatches = [];
// BTN1: press for dot, long-press to toggle uppercase
let ucTimeout;
const UC_TIME = 500;
Bangle.btnWatches.push(setWatch(e => {
if (ucTimeout) clearTimeout(ucTimeout);
ucTimeout = null;
if (e.state) {
// pressed: start UpperCase toggle timer
ucTimeout = setTimeout(() => {
ucTimeout = null;
uc = !uc;
update();
}, UC_TIME);
} else if (e.time-e.lastTime<UC_TIME/1000) add(".");
}, BTN1, {repeat: true, edge: "both"}));
// BTN2: press to pick current character, long press to enter text
let enterTimeout;
const ENTER_TIME = 1000;
Bangle.btnWatches.push(setWatch(e => {
if (enterTimeout) clearTimeout(enterTimeout);
enterTimeout = null;
if (e.state) {
// pressed: start UpperCase toggle timer
enterTimeout = setTimeout(() => {
enterTimeout = null;
resolve(text);
}, ENTER_TIME);
} else if (e.time-e.lastTime<ENTER_TIME/1000) done();
}, BTN2, {repeat: true, edge: "both"}));
// BTN3: press for dash (long-press is hardcoded to device reboot)
Bangle.btnWatches.push(setWatch(() => {
add("-");
}, BTN3, {repeat: true, edge: "falling"}));
// Left-hand side: backspace
if (Bangle.touchHandler) Bangle.removeListener("touch", Bangle.touchHandler);
Bangle.touchHandler = side => {
if (side===1) del();
};
Bangle.on("touch", Bangle.touchHandler);
// swipe: move cursor
if (Bangle.swipeHandler) Bangle.removeListener("swipe", Bangle.swipeHandler);
Bangle.swipeHandler = dir => {
cur = Math.max(0, Math.min(text.length, cur+dir));
update();
};
Bangle.on("swipe", Bangle.swipeHandler);
});
};

View File

@ -0,0 +1,15 @@
{
"id": "kbmorse",
"name": "Morse keyboard",
"version": "0.01",
"description": "A library for text input as morse code",
"icon": "app.png",
"type": "textinput",
"tags": "keyboard",
"supports" : ["BANGLEJS"],
"screenshots": [{"url":"screenshot.png"}],
"readme": "README.md",
"storage": [
{"name":"textinput","url":"lib.js"}
]
}

BIN
apps/kbmorse/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

1
apps/kbmulti/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New keyboard

16
apps/kbmulti/README.md Normal file
View File

@ -0,0 +1,16 @@
# Multitap Keyboard
A library that provides the ability to input text in a style familiar to anyone who had a mobile phone before they went all touchscreen.
Swipe right for Space, left for Backspace, and up/down for Caps lock. Tap the '?' button in the app if you need a reminder!
At time of writing, only the [Noteify app](http://microco.sm/out/Ffe9i) uses a keyboard.
Uses the multitap keypad logic originally from here: http://www.espruino.com/Morse+Code+Texting
![](screenshot_1.png)
![](screenshot_2.png)
Written by: [Sir Indy](https://github.com/sir-indy) and [Thyttan](https://github.com/thyttan)
For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/)

BIN
apps/kbmulti/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

145
apps/kbmulti/lib.js Normal file
View File

@ -0,0 +1,145 @@
//Multitap logic originally from here: http://www.espruino.com/Morse+Code+Texting
exports.input = function(options) {
options = options||{};
var text = options.text;
if ("string"!=typeof text) text="";
var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {};
if (settings.firstLaunch===undefined) { settings.firstLaunch = true; }
if (settings.charTimeout===undefined) { settings.charTimeout = 500; }
var fontSize = "6x15";
var Layout = require("Layout");
var letters = {
"1":".,!?1","2":"ABC2","3":"DEF3",
"4":"GHI4","5":"JKL5","6":"MNO6",
"7":"PQRS7","8":"TUV80","9":"WXYZ9",
};
var helpMessage = 'swipe:\nRight: Space\nLeft:Backspace\nUp/Down: Caps lock\n';
var charTimeout; // timeout after a key is pressed
var charCurrent; // current character (index in letters)
var charIndex; // index in letters[charCurrent]
var caps = true;
var layout;
function displayText() {
layout.clear(layout.text);
layout.text.label = text.slice(-12);
layout.render(layout.text);
}
function backspace() {
// remove the timeout if we had one
if (charTimeout!==undefined) {
clearTimeout(charTimeout);
charTimeout = undefined;
}
text = text.slice(0, -1);
newCharacter();
}
function setCaps() {
caps = !caps;
for (var key in letters) {
layout[key].label = caps ? letters[key].toUpperCase() : letters[key].toLowerCase();
}
layout.render();
}
function newCharacter(ch) {
displayText();
charCurrent = ch;
charIndex = 0;
}
function onKeyPad(key) {
// remove the timeout if we had one
if (charTimeout!==undefined) {
clearTimeout(charTimeout);
charTimeout = undefined;
}
// work out which char was pressed
if (key==charCurrent) {
charIndex = (charIndex+1) % letters[charCurrent].length;
text = text.slice(0, -1);
} else {
newCharacter(key);
}
var newLetter = letters[charCurrent][charIndex];
text += (caps ? newLetter.toUpperCase() : newLetter.toLowerCase());
displayText();
// set a timeout
charTimeout = setTimeout(function() {
charTimeout = undefined;
newCharacter();
}, settings.charTimeout);
}
function onSwipe(dirLeftRight, dirUpDown) {
if (dirUpDown) {
setCaps();
} else if (dirLeftRight == 1) {
text += ' ';
newCharacter();
} else if (dirLeftRight == -1) {
backspace();
}
}
function onHelp(resolve,reject) {
Bangle.removeListener("swipe", onSwipe);
E.showPrompt(
helpMessage, {title: "Help", buttons : {"Ok":true}}
).then(function(v) {
Bangle.on('swipe', onSwipe);
generateLayout(resolve,reject);
layout.render();
});
}
function generateLayout(resolve,reject) {
layout = new Layout( {
type:"v", c: [
{type:"h", c: [
{type:"txt", font:"12x20", label:text.slice(-12), id:"text", fillx:1},
{type:"btn", font:'6x8', label:'?', cb: l=>onHelp(resolve,reject), filly:1 },
]},
{type:"h", c: [
{type:"btn", font:fontSize, label:letters[1], cb: l=>onKeyPad(1), id:'1', fillx:1, filly:1 },
{type:"btn", font:fontSize, label:letters[2], cb: l=>onKeyPad(2), id:'2', fillx:1, filly:1 },
{type:"btn", font:fontSize, label:letters[3], cb: l=>onKeyPad(3), id:'3', fillx:1, filly:1 },
]},
{type:"h", filly:1, c: [
{type:"btn", font:fontSize, label:letters[4], cb: l=>onKeyPad(4), id:'4', fillx:1, filly:1 },
{type:"btn", font:fontSize, label:letters[5], cb: l=>onKeyPad(5), id:'5', fillx:1, filly:1 },
{type:"btn", font:fontSize, label:letters[6], cb: l=>onKeyPad(6), id:'6', fillx:1, filly:1 },
]},
{type:"h", filly:1, c: [
{type:"btn", font:fontSize, label:letters[7], cb: l=>onKeyPad(7), id:'7', fillx:1, filly:1 },
{type:"btn", font:fontSize, label:letters[8], cb: l=>onKeyPad(8), id:'8', fillx:1, filly:1 },
{type:"btn", font:fontSize, label:letters[9], cb: l=>onKeyPad(9), id:'9', fillx:1, filly:1 },
]},
]
},{back: ()=>{
Bangle.setUI();
Bangle.removeListener("swipe", onSwipe);
g.clearRect(Bangle.appRect);
resolve(text);
}});
}
return new Promise((resolve,reject) => {
g.clearRect(Bangle.appRect);
if (settings.firstLaunch) {
onHelp(resolve,reject);
settings.firstLaunch = false;
require('Storage').writeJSON("kbmulti.settings.json", settings);
} else {
generateLayout(resolve,reject);
Bangle.on('swipe', onSwipe);
layout.render();
}
});
};

View File

@ -0,0 +1,18 @@
{ "id": "kbmulti",
"name": "Multitap keyboard",
"version":"0.01",
"description": "A library for text input via multitap/T9 style keypad",
"icon": "app.png",
"type":"textinput",
"tags": "keyboard",
"supports" : ["BANGLEJS2"],
"screenshots": [{"url":"screenshot_1.png"},{"url":"screenshot_2.png"}],
"readme": "README.md",
"storage": [
{"name":"textinput","url":"lib.js"},
{"name":"kbmulti.settings.js","url":"settings.js"}
],
"data": [
{"name":"kbmulti.settings.json"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

31
apps/kbmulti/settings.js Normal file
View File

@ -0,0 +1,31 @@
(function(back) {
function settings() {
var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {};
if (settings.firstLaunch===undefined) { settings.firstLaunch = true; }
if (settings.charTimeout===undefined) { settings.charTimeout = 500; }
return settings;
}
function updateSetting(setting, value) {
var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {};
settings[setting] = value;
require('Storage').writeJSON("kbmulti.settings.json", settings);
}
var mainmenu = {
"" : { "title" : /*LANG*/"Multitap keyboard" },
"< Back" : back,
/*LANG*/'Character selection timeout [ms]': {
value: settings().charTimeout,
min: 200, max: 1500, step : 50,
format: v => v,
onchange: v => updateSetting("charTimeout", v),
},
/*LANG*/'Show help on first launch': {
value: !!settings().firstLaunch,
format: v => v?"Yes":"No",
onchange: v => updateSetting("firstLaunch", v)
}
};
E.showMenu(mainmenu);
})

View File

@ -564,7 +564,7 @@ var locales = {
month: "Janeiro,Fevereiro,Março,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro",
abday: "Dom,Seg,Ter,Qua,Qui,Sex,Sab",
day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado",
trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "certo", on: "ligado", off: "desligado" }
trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "confirmar", on: "ativado", off: "desativado" }
},
"cs_CZ": { // THIS NEVER WORKED PROPERLY - many chars are not in the ISO8859-1 codepage and we use CODEPAGE_CONVERSIONS
lang: "cs_CZ",

View File

@ -49,3 +49,5 @@
0.34: Don't buzz for 'map' update messages
0.35: Reset graphics colors before rendering a message (possibly fix #1752)
0.36: Ensure a new message plus an almost immediate deletion of that message doesn't load the messages app (fix #1362)
0.37: Now use the setUI 'back' icon in the top left rather than specific buttons/menu items

View File

@ -13,11 +13,11 @@
/* For example for maps:
// a message
{"t":"add","id":1575479849,"src":"Hangouts","title":"A Name","body":"message contents"}
require("messages").pushMessage({"t":"add","id":1575479849,"src":"Hangouts","title":"A Name","body":"message contents"})
// maps
{"t":"add","id":1,"src":"Maps","title":"0 yd - High St","body":"Campton - 11:48 ETA","img":"GhqBAAAMAAAHgAAD8AAB/gAA/8AAf/gAP/8AH//gD/98B//Pg/4B8f8Afv+PP//n3/f5//j+f/wfn/4D5/8Aef+AD//AAf/gAD/wAAf4AAD8AAAeAAADAAA="}
require("messages").pushMessage({"t":"add","id":1,"src":"Maps","title":"0 yd - High St","body":"Campton - 11:48 ETA","img":"GhqBAAAMAAAHgAAD8AAB/gAA/8AAf/gAP/8AH//gD/98B//Pg/4B8f8Afv+PP//n3/f5//j+f/wfn/4D5/8Aef+AD//AAf/gAD/wAAf4AAD8AAAeAAADAAA="});
// call
{"t":"add","id":"call","src":"Phone","name":"Bob","number":"12421312",positive:true,negative:true}
require("messages").pushMessage({"t":"add","id":"call","src":"Phone","title":"Bob","body":"12421312",positive:true,negative:true})
*/
var Layout = require("Layout");
@ -67,9 +67,6 @@ function saveMessages() {
require("Storage").writeJSON("messages.json",MESSAGES)
}
function getBackImage() {
return atob("FhYBAAAAEAAAwAAHAAA//wH//wf//g///BwB+DAB4EAHwAAPAAA8AADwAAPAAB4AAHgAB+AH/wA/+AD/wAH8AA==");
}
function getNotificationImage() {
return atob("HBKBAD///8H///iP//8cf//j4//8f5//j/x/8//j/H//H4//4PB//EYj/44HH/Hw+P4//8fH//44///xH///g////A==");
}
@ -123,7 +120,6 @@ function getMessageImage(msg) {
if (s=="wordfeud") return atob("GBgCWqqqqqqlf//////9v//////+v/////++v/////++v8///Lu+v8///L++v8///P/+v8v//P/+v9v//P/+v+fx/P/+v+Pk+P/+v/PN+f/+v/POuv/+v/Ofdv/+v/NvM//+v/I/Y//+v/k/k//+v/i/w//+v/7/6//+v//////+v//////+f//////9Wqqqqqql");
if (s=="youtube") return atob("GBgBAAAAAAAAAAAAAAAAAf8AH//4P//4P//8P//8P5/8P4/8f4P8f4P8P4/8P5/8P//8P//8P//4H//4Af8AAAAAAAAAAAAAAAAA");
if (msg.id=="music") return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A=");
if (msg.id=="back") return getBackImage();
return getNotificationImage();
}
function getMessageImageCol(msg,def) {
@ -195,13 +191,13 @@ function showMapMessage(msg) {
]});
g.reset().clearRect(Bangle.appRect);
layout.render();
Bangle.setUI("updown",function() {
// any input to mark as not new and return to menu
function back() { // mark as not new and return to menu
msg.new = false;
saveMessages();
layout = undefined;
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:0});
});
}
Bangle.setUI({mode:"updown", back: back}, back); // any input takes us back
}
var updateLabelsInterval;
@ -224,8 +220,6 @@ function showMusicMessage(msg) {
var sliceLength = offset + maxLen > text.length ? text.length - offset : maxLen;
return text.substr(offset, sliceLength).padEnd(maxLen, " ");
}
function back() {
clearInterval(updateLabelsInterval);
updateLabelsInterval = undefined;
@ -254,7 +248,6 @@ function showMusicMessage(msg) {
layout = new Layout({ type:"v", c: [
{type:"h", fillx:1, bgCol:g.theme.bg2, col: g.theme.fg2, c: [
{ type:"btn", src:getBackImage, cb:back },
{ type:"v", fillx:1, c: [
{ type:"txt", font:fontMedium, bgCol:g.theme.bg2, label:artistName, pad:2, id:"artist" },
{ type:"txt", font:fontMedium, bgCol:g.theme.bg2, label:albumName, pad:2, id:"album" }
@ -267,7 +260,7 @@ function showMusicMessage(msg) {
{type:"btn", pad:8, label:"\0"+atob("EhKBAMAB+AB/gB/wB/8B/+B//B//x//5//5//x//B/+B/8B/wB/gB+AB8ABw"), cb:()=>Bangle.musicControl("next")}, // next
]}:{},
{type:"txt", font:"6x8:2", label:msg.dur?fmtTime(msg.dur):"--:--" }
]});
]}, { back : back });
g.reset().clearRect(Bangle.appRect);
layout.render();
@ -302,12 +295,9 @@ function showMessageScroller(msg) {
}, select : function(idx) {
if (idx>=lines.length-2)
showMessage(msg.id);
}
},
back : () => showMessage(msg.id)
});
// ensure button-press on Bangle.js 2 takes us back
if (process.env.HWVERSION>1) Bangle.btnWatches = [
setWatch(() => showMessage(msg.id), BTN1, {repeat:1,edge:"falling"})
];
}
function showMessageSettings(msg) {
@ -395,10 +385,8 @@ function showMessage(msgid) {
checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0,openMusic:openMusic});
}
var buttons = [
{type:"btn", src:getBackImage(), cb:goBack} // back
];
if (msg.positive) {
buttons.push({fillx:1});
buttons.push({type:"btn", src:getPosImage(), cb:()=>{
msg.new = false; saveMessages();
cancelReloadTimeout(); // don't auto-reload to clock now
@ -407,7 +395,7 @@ function showMessage(msgid) {
}});
}
if (msg.negative) {
buttons.push({fillx:1});
if (buttons.length) buttons.push({width:32}); // nasty hack...
buttons.push({type:"btn", src:getNegImage(), cb:()=>{
msg.new = false; saveMessages();
cancelReloadTimeout(); // don't auto-reload to clock now
@ -419,27 +407,23 @@ function showMessage(msgid) {
layout = new Layout({ type:"v", c: [
{type:"h", fillx:1, bgCol:g.theme.bg2, col: g.theme.fg2, c: [
{ type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{
cancelReloadTimeout(); // don't auto-reload to clock now
showMessageSettings(msg);
}},
{ type:"v", fillx:1, c: [
{type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2, halign:1 },
title?{type:"txt", font:titleFont, label:title, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 }:{},
]},
{ type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{
cancelReloadTimeout(); // don't auto-reload to clock now
showMessageSettings(msg);
}},
]},
{type:"txt", font:bodyFont, label:body, fillx:1, filly:1, pad:2, cb:()=>{
// allow tapping to show a larger version
showMessageScroller(msg);
} },
{type:"h",fillx:1, c: buttons}
]});
]},{back:goBack});
g.reset().clearRect(Bangle.appRect);
layout.render();
// ensure button-press on Bangle.js 2 takes us back
if (process.env.HWVERSION>1) Bangle.btnWatches = [
setWatch(goBack, BTN1, {repeat:1,edge:"falling"})
];
}
@ -475,13 +459,12 @@ function checkMessages(options) {
// Otherwise show a menu
E.showScroller({
h : 48,
c : Math.max(MESSAGES.length+1,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
c : Math.max(MESSAGES.length,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
draw : function(idx, r) {"ram"
var msg = MESSAGES[idx-1];
var msg = MESSAGES[idx];
if (msg && msg.new) g.setBgColor(g.theme.bgH).setColor(g.theme.fgH);
else g.setColor(g.theme.fg);
g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
if (idx==0) msg = {id:"back", title:"< Back"};
if (!msg) return;
var x = r.x+2, title = msg.title, body = msg.body;
var img = getMessageImage(msg);
@ -510,13 +493,12 @@ function checkMessages(options) {
if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2);
g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items
},
select : idx => {
if (idx==0) load();
else showMessage(MESSAGES[idx-1].id);
}
select : idx => showMessage(MESSAGES[idx].id),
back : () => load()
});
}
function cancelReloadTimeout() {
if (!unreadTimeout) return;
clearTimeout(unreadTimeout);

View File

@ -1,7 +1,7 @@
{
"id": "messages",
"name": "Messages",
"version": "0.36",
"version": "0.37",
"description": "App to display notifications from iOS and Gadgetbridge/Android",
"icon": "app.png",
"type": "app",

View File

@ -18,3 +18,6 @@ This app uses the [Scheduler library](https://banglejs.com/apps/?id=sched) and r
![](note.png)
![](timer-alert.png)
## Web interface
You can also add, edit or delete notes in the web interface, accessible with the download button.

View File

@ -0,0 +1,93 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<div id="notes" class="container">
<div class="columns">
<div class="column col-9">
<textarea class="form-input" id="note-new" placeholder="New note" rows="3"></textarea>
</div>
<div class="column col-3">
<button class="btn btn-default" id="btnAdd">Add</button>
</div>
</div>
</div>
<script src="../../core/lib/interface.js"></script>
<script>
var notesElement = document.getElementById("notes");
var notes = {};
function getData() {
// show loading window
Util.showModal("Loading...");
Util.readStorage(`noteify.json`,data=>{
notes = JSON.parse(data || "[]");
// remove window
Util.hideModal();
notes.forEach((note, i) => {
const divColumn = document.createElement("div");
divColumn.classList.add('columns');
const divColumn1 = document.createElement("div");
divColumn1.classList.add('column');
divColumn1.classList.add('col-9');
const textarea = document.createElement("textarea");
textarea.id = "note" + i;
textarea.classList.add('form-input');
textarea.rows = 3;
textarea.value = note.note;
divColumn1.appendChild(textarea);
divColumn.appendChild(divColumn1);
const divColumn2 = document.createElement("div");
divColumn2.classList.add('column');
divColumn2.classList.add('col-3');
const buttonSave = document.createElement("button");
buttonSave.textContent = "Save";
buttonSave.classList.add('btn');
buttonSave.classList.add('btn-default');
buttonSave.onclick = function() {
notes[i].note = textarea.value;
Util.writeStorage("noteify.json", JSON.stringify(notes));
location.reload();
}
divColumn2.appendChild(buttonSave);
const buttonDelete = document.createElement("button");
buttonDelete.classList.add('btn');
buttonDelete.textContent = "Delete";
buttonDelete.onclick = function() {
notes[i].note = textarea.value;
notes.splice(i, 1);
Util.writeStorage("noteify.json", JSON.stringify(notes));
location.reload(); // reload so we see current data
}
divColumn2.appendChild(buttonDelete);
divColumn.appendChild(divColumn2);
notesElement.prepend(document.createElement("hr"));
notesElement.prepend(divColumn);
});
document.getElementById("btnAdd").addEventListener("click", function() {
const note = document.getElementById("note-new").value;
notes.push({"note": note});
Util.writeStorage("noteify.json", JSON.stringify(notes));
location.reload(); // reload so we see current data
});
});
}
// Called when app starts
function onInit() {
getData();
}
</script>
</body>
</html>

View File

@ -14,6 +14,7 @@
],
"data": [{"name":"noteify.json"}],
"dependencies": {"scheduler":"type","textinput":"type"},
"interface": "interface.html",
"screenshots": [
{"url": "menu.png"},
{"url": "note.png"},

View File

@ -11,7 +11,7 @@ function scrollX(){
gfx.clearRect(0,gfx.getHeight()*(1/4),gfx.getWidth(),0);
gfx.scroll(0,gfx.getHeight()/4);
score++;
if(typeof(m) != undefined && score>0){
if(typeof m !== 'undefined' && score>0){
clearInterval(m);
m = setInterval(scrollY,Math.abs(100/score+15-0.1*score));}
gfx.setColor(1,1,1);

View File

@ -368,8 +368,8 @@ class TextBox {
// x and y are the center points
this.x = x;
this.y = y;
this.text = (typeof text !== undefined) ? text : "Default";
this.col = (typeof col !== undefined) ? col : red;
this.text = text || "Default";
this.col = col || red;
// console.log(`Constr TextBox ${this.text} -> Center: (${this.x}, ${this.y}) | Col ${this.col}`);
}

1
apps/tabanchi/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.0.1: Initial implementation

47
apps/tabanchi/README.md Normal file
View File

@ -0,0 +1,47 @@
たばんち (tabanchi)
===================
A Tamagotchi clone watch app for the BangleJS2 smartwatch.
Author
------
Written by pancake in 2022, powered by insomnia
Source repository: https://github.com/trufae/tabanchi
Features
--------
* [x] 12/24 clock with HH:mm:ss
* [x] Battery level indicator
* [x] Eating meals and snacks
* [x] Refusing to do things
* [x] Getting sick
* [x] Take a shower
* [x] Switch on/off the light
* [x] Status for happy/hunger/discipline
* [ ] Evolutions
* [ ] Hatching eggs
* [x] Playing a game
* [ ] Education
* [x] Medicine
* [ ] Death
Resources
---------
* Original pixmaps taken from:
- https://www.spriters-resource.com/resources/sheets/141/144400.png
* Espruino Image converter:
- https://www.espruino.com/Image+Converter
* Tamagotchi Essentials
- https://tamagotchi.fandom.com/wiki/Tamagotchi_(1996_Pet)
* Tamagotchi Emulator Source (Java)
- https://gist.github.com/aerospark/80c60e801398fd961e3f
Screenshots
-----------
![tama on bangle](screenshot.jpg)

View File

@ -0,0 +1 @@
atob("MDDBAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gAAAAD//gAAAAD//gAAAAf//8AAAAf//8AAAAf//8AAAD/////gAD/////gAD/////gAf/////8Af/////8Af/////8D//////8D//////8D//////8D//////8D//////8D//////8D//////8D//////8D//////8D//////8D//////8D//////8f//////gf//////gf//////gD/////gAD/////gAD/////gAAf///8AAAf///8AAAf///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")

1603
apps/tabanchi/app.js Normal file

File diff suppressed because it is too large Load Diff

BIN
apps/tabanchi/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

View File

@ -0,0 +1,31 @@
{
"id": "tabanchi",
"name": "Tabanchi",
"shortName": "Tabanchi",
"version": "0.0.1",
"type": "app",
"description": "Tamagotchi WatchApp",
"icon": "app.png",
"allow_emulator": true,
"tags": "watch, pet",
"supports": [
"BANGLEJS2"
],
"readme": "README.md",
"storage": [
{
"name": "tabanchi.app.js",
"url": "app.js"
},
{
"name": "tabanchi.img",
"url": "app-icon.js",
"evaluate": true
}
],
"screenshots": [
{
"url": "screenshot.jpg"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 KiB

View File

@ -2,3 +2,4 @@
0.02: Rename "Activity" in "Motion" and display the true values for it
0.03: Add Banglejs 1 compatibility
0.04: Fix settings bug
0.05: Add altitude display (only Bangle.js 2)

View File

@ -4,6 +4,7 @@ A clock displayed as a terminal cli.
It can display :
- time
- date
- altitude
- hrm
- motion
- steps

View File

@ -1,6 +1,7 @@
var locale = require("locale");
var fontColor = g.theme.dark ? "#0f0" : "#000";
var heartRate = 0;
var altitude = -9001;
// handling the differents versions of the Banglejs smartwatch
if (process.env.HWVERSION == 1){
@ -26,13 +27,13 @@ function setFontSize(pos){
}
function clearField(pos){
var yStartPos = Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos-1) +
var yStartPos = Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos-1) +
font6x8At2Size * Math.max(0, pos-2);
var yEndPos = Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos) +
var yEndPos = Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos) +
font6x8At2Size * Math.max(0, pos-1);
g.clearRect(Bangle.appRect.x, yStartPos, Bangle.appRect.x2, yEndPos);
}
@ -44,9 +45,9 @@ function clearWatchIfNeeded(now){
function drawLine(line, pos){
setFontSize(pos);
var yPos = Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos-1) +
var yPos = Bangle.appRect.y +
paddingY * (pos - 1) +
font6x8At4Size * Math.min(1, pos-1) +
font6x8At2Size * Math.max(0, pos-2);
g.drawString(line, 5, yPos, true);
}
@ -84,6 +85,14 @@ function drawHRM(pos){
drawLine(">HR: unknown", pos);
}
function drawAltitude(pos){
clearField(pos);
if(altitude > 0)
drawLine(">Alt: " + altitude.toFixed(1) + "m", pos);
else
drawLine(">Alt: unknown", pos);
}
function drawActivity(pos){
clearField(pos);
var health = Bangle.getHealthStatus('last');
@ -104,6 +113,10 @@ function draw(){
drawDate(now, curPos);
curPos++;
}
if(settings.showAltitude){
drawAltitude(curPos);
curPos++;
}
if(settings.showHRM){
drawHRM(curPos);
curPos++;
@ -124,6 +137,18 @@ Bangle.on('HRM',function(hrmInfo) {
heartRate = hrmInfo.bpm;
});
var MEDIANLENGTH = 20;
var avr = [], median;
Bangle.on('pressure', function(e) {
while (avr.length>MEDIANLENGTH) avr.pop();
avr.unshift(e.altitude);
median = avr.slice().sort();
if (median.length>10) {
var mid = median.length>>1;
altitude = E.sum(median.slice(mid-4,mid+5)) / 9;
}
});
// Clear the screen once, at startup
g.clear();
@ -135,7 +160,13 @@ var settings = Object.assign({
showHRM: true,
showActivity: true,
showStepCount: true,
showAltitude: process.env.HWVERSION != 1 ? true : false,
}, require('Storage').readJSON("terminalclock.json", true) || {});
if(settings.showAltitude && process.env.HWVERSION != 1){
Bangle.setBarometerPower(true, "app");
}
// Show launcher when middle button pressed
Bangle.setUI("clock");
// Load widgets

View File

@ -3,7 +3,7 @@
"name": "Terminal Clock",
"shortName":"Terminal Clock",
"description": "A terminal cli like clock displaying multiple sensor data",
"version":"0.04",
"version":"0.05",
"icon": "app.png",
"type": "clock",
"tags": "clock",

View File

@ -4,6 +4,7 @@
var settings = Object.assign({
HRMinConfidence: 50,
showDate: true,
showAltitude: process.env.HWVERSION != 1 ? true : false,
showHRM: true,
showActivity: true,
showStepCount: true,
@ -14,7 +15,7 @@
}
// Show the menu
E.showMenu({
var menu = {
"" : { "title" : "Terminal Clock" },
"< Back" : () => back(),
'HR confidence': {
@ -33,6 +34,14 @@
writeSettings();
}
},
'Show Altitude': {
value: settings.showAltitude,
format: v => v?"Yes":"No",
onchange: v => {
settings.showAltitude = v;
writeSettings();
}
},
'Show HRM': {
value: settings.showHRM,
format: v => v?"Yes":"No",
@ -57,5 +66,9 @@
writeSettings();
}
}
});
}
if (process.env.HWVERSION == 1) {
delete menu['Show Altitude']
}
E.showMenu(menu);
})

View File

@ -3,3 +3,4 @@
0.03: Fix positioning
0.04: Show GPS fix status
0.05: Don't poll for GPS status, override setGPSPower handler (fix #1456)
0.06: Periodically update so the always on display does show current GPS fix

View File

@ -1,7 +1,7 @@
{
"id": "widgps",
"name": "GPS Widget",
"version": "0.05",
"version": "0.06",
"description": "Tiny widget to show the power and fix status of the GPS",
"icon": "widget.png",
"type": "widget",

View File

@ -1,4 +1,6 @@
(function(){
var interval;
// override setGPSPower so we know if GPS is on or off
var oldSetGPSPower = Bangle.setGPSPower;
Bangle.setGPSPower = function(on,id) {
@ -19,6 +21,16 @@
} else {
g.setColor("#888"); // off = grey
}
// check if we need to update the widget periodically
if (Bangle.isGPSOn() && interval === undefined) {
interval = setInterval(function() {
WIDGETS.gps.draw(WIDGETS.gps);
}, 10*1000); // update every 10 seconds to show gps fix/no fix
} else if (!Bangle.isGPSOn() && interval !== undefined) {
clearInterval(interval);
interval = undefined;
}
g.drawImage(atob("GBiBAAAAAAAAAAAAAA//8B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+A//8AAAAAAAAAAAAA=="), this.x, 2+this.y);
}};
})();

View File

@ -0,0 +1,13 @@
{ "id": "widslimbat",
"name": "Slim battery widget with cells",
"shortName":"Slim battery with cells",
"version":"0.01",
"description": "A small (13px wide) battery widget with cells",
"icon": "widget.png",
"type": "widget",
"tags": "widget",
"supports" : ["BANGLEJS2"],
"storage": [
{"name":"widslimbat.wid.js","url":"widget.js"}
]
}

55
apps/widslimbat/widget.js Normal file
View File

@ -0,0 +1,55 @@
(() => {
const intervalLow = 60000; // update time when not charging
const intervalHigh = 2000; // update time when charging
const outline = atob("CRSBAD4AP/AYDAYDAYDAYDAYDAYDAYDAYD/w");
let COLORS = {
'black': g.theme.dark ? "#fff" : "#000",
'charging': "#0f0",
'low': "#f00",
};
function draw() {
var i;
var oCol = COLORS.low;
var cCol = COLORS.low;
var nCells = 0;
const bat = E.getBattery();
if (bat>5) {
oCol = COLORS.black;
nCells = 1 + Math.floor((bat-6)/19);
}
if (nCells>1)
cCol = COLORS.black;
if (Bangle.isCharging())
oCol = COLORS.charging;
g.reset();
g.setColor(oCol).drawImage(outline,this.x+2,this.y+2);
for (i=0;i<nCells;i++) {
var x = this.x+2+2;
var y = this.y+16+2-i*3;
g.setColor(cCol).drawRect(x,y,x+4,y+1);
}
if (Bangle.isCharging()) {
changeInterval(id,intervalHigh);
} else {
changeInterval(id,intervalLow);
}
}
Bangle.on("charging",function(charging) {
if (charging) Bangle.buzz();
WIDGETS["widslimbat"].draw();
});
Bangle.on('lcdPower',function(on) {
WIDGETS["widslimbat"].draw();
});
var id = setInterval(()=>WIDGETS["widslimbat"].draw(),intervalLow);
WIDGETS["widslimbat"]={
area:"tr",
width:13,
draw:draw
};
})();

BIN
apps/widslimbat/widget.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -51,7 +51,8 @@ options is an object containing:
* `label` - the text on the button
* `cb` - a callback function
* `cbl` - a callback function for long presses
* `back` - a callback function, passed as `back` into Bangle.setUI
* `back` - a callback function, passed as `back` into Bangle.setUI (which usually adds an icon in the top left)
If automatic lazy rendering is enabled, calls to `layout.render()` will attempt to automatically
determine what objects have changed or moved, clear their previous locations, and re-render just those objects.
Once `layout.update()` is called, the following fields are added

View File

@ -3,8 +3,13 @@
"description": "Bangle.js App Loader (and Apps)",
"author": "Gordon Williams <gw@pur3.co.uk> (http://espruino.com)",
"version": "0.0.1",
"license": "MIT",
"repository": "https://github.com/espruino/BangleApps",
"devDependencies": {
"eslint": "7.1.0"
"eslint": "^8.14.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.26.0",
"npm-watch": "^0.11.0"
},
"scripts": {
"lint-apps": "eslint ./apps --ext .js",
@ -18,8 +23,5 @@
},
"dependencies": {
"acorn": "^7.2.0"
},
"devDpendencies": {
"npm-watch": "^0.11.0"
}
}