Merge branch 'master' of github.com:espruino/BangleApps

pull/1669/head
Gordon Williams 2022-04-07 17:02:38 +01:00
commit 0dcc0ec789
20 changed files with 88 additions and 65 deletions

View File

@ -1,2 +1,3 @@
0.01: New app!
0.02: Fix bug with regenerating index, fix bug in word lookups
0.03: Improve word search performance

View File

@ -27,10 +27,7 @@ least once and yields an additional 7 points. Each game contains at least one pa
The game uses an internal dictionary consisting of a newline separated list of English words ('bee.words', using the '2of12inf' word list).
The dictionary is fairly large (~700kB of flash space) and thus requires appropriate space on the watch and will make installing the app somewhat
slow. Because of its size it cannot be compressed (heatshrink needs to hold the compressed/uncompressed data in memory).
In order to make checking the validity of a guessed word faster an index file ('bee_lindex.json') is installed with
the app that facilitates faster word lookups. This index file is specific to the dictionary file used. If one were to
replace the dictionary file with a different version (e.g. a different language) the index file has to be regenerated. The easiest
way to do so is to delete (via the Web IDE or the fileman app on the watch) the file 'bee_lindex.json' - it will be regenerated (and saved,
i.e. it only happens once) on app startup automatically, a process that takes roughly 30 seconds.
This file can be replaced with a custom dictionary, an ASCII file containing a newline-separated (single "\n", not DOS-style "\r\n") alphabetically
sorted (sorting is important for the word lookup algorithm) list of words.
![Screenshot](./bee_screenshot.png)

View File

@ -1,7 +1,7 @@
const S = require("Storage");
const words = S.read("bee.words");
var letters = [];
var letterIdx = [];
var centers = [];
@ -12,29 +12,17 @@ var score = 0;
var intervalID = -1;
function prepareLetterIdx () {
function biSearch(w, ws, start, end, count) {
"compile"
var li = [0];
if (S.read("bee_lindex.json")!==undefined) li = S.readJSON("bee_lindex.json"); // check for cached index
else {
for (var i=1; i<26; ++i) {
var prefix = String.fromCharCode(97+i%26);
console.log(prefix);
li.push(S.read('bee.words').indexOf("\n"+prefix, li[i-1])+1);
}
li.push(S.read('bee.words').length);
S.writeJSON("bee_lindex.json", li);
}
for (var i=0; i<26; ++i) letterIdx[i] = S.read("bee.words", li[i], li[i+1]-li[i]);
}
function findWord (w) {
"compile"
var ci = w.charCodeAt(0)-97;
var f = letterIdx[ci].indexOf("\n"+w+"\n");
if (f>=0) return true;
if (letterIdx[ci].substr(0, w.length)==w) return true;
return false;
if (start>end-w.legnth || count--<=0) return ws.substr(start, end-start).indexOf("\n"+w+"\n");
var mid = (end+start)>>1;
if (ws[mid-1]==="\n") --mid;
else while (mid<end && ws[mid]!=="\n") mid++;
var i = 0;
while (i<w.length && ws[mid+i+1]==w[i]) ++i;
if (i==w.length && ws[mid+i+1]==="\n") return mid+1;
if (i==w.length || w[i]<ws[mid+i+1]) return biSearch(w, ws, start, mid+1, count);
if (w[i]>ws[mid+i+1]) return biSearch(w, ws, mid+1, end, count);
}
function isPangram(w) {
@ -46,7 +34,7 @@ function isPangram(w) {
function checkWord (w) {
if (w.indexOf(String.fromCharCode(97+letters[0]))==-1) return false; // does it contain central letter?
if (foundWords.indexOf(w)>=0) return false; // already found
if (findWord(w)) {
if (biSearch(w, words, 0, words.length, 20)>-1) {
foundWords.push(w);
foundWords.sort();
if (w.length==4) score++;
@ -93,13 +81,12 @@ function pickLetters() {
var ltrs = "";
while (ltrs.length!==7) {
ltrs = [];
var j = Math.floor(26*Math.random());
var i = Math.floor((letterIdx[j].length-10)*Math.random());
while (letterIdx[j][i]!="\n" && i<letterIdx[j].length) ++i;
if (i<letterIdx[j].length-1) {
var i = Math.floor((words.length-10)*Math.random());
while (words[i]!="\n" && i<words.length) ++i;
if (i<words.length-1) {
++i;
while (letterIdx[j][i]!=="\n") {
var c = letterIdx[j][i];
while (words[i]!=="\n") {
var c = words[i];
if (ltrs.indexOf(c)===-1) ltrs += c;
++i;
}
@ -187,7 +174,6 @@ function showWordList() {
});
}
prepareLetterIdx();
pickLetters();
drawHive();
drawScore();

View File

@ -1 +0,0 @@
[0,41048,80445,152390,198606,228714,257919,279071,303726,337982,343582,348026,367246,404452,419780,438696,496250,499697,544600,624304,659085,680996,691270,708186,708341,709916,710883]

View File

@ -2,7 +2,7 @@
"name": "Bee",
"shortName":"Bee",
"icon": "app.png",
"version":"0.02",
"version":"0.03",
"description": "Spelling bee",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
@ -10,7 +10,6 @@
"storage": [
{"name":"bee.app.js","url":"bee.app.js"},
{"name":"bee.words","url":"bee_words_2of12"},
{"name":"bee_lindex.json","url":"bee_lindex.json"},
{"name":"bee.img","url":"app-icon.js","evaluate":true}
]
}

View File

@ -1,3 +1,4 @@
0.01: New App!
0.02: Add the option to enable touching the widget only on clock and settings.
0.03: Settings page now uses built-in min/max/wrap (fix #1607)
0.04: Add masking widget input to other apps (using espruino/Espruino#2151), add a oversize option to increase the touch area.

View File

@ -1,8 +1,11 @@
# Light Switch Widget
Whis this widget I wanted to create a solution to quickly en-/disable the LCD backlight and even change the brightness.
With this widget I wanted to create a solution to quickly en-/disable the LCD backlight and even change the brightness.
In addition it shows the lock status with the option to personalize the lock icon with a tiny image.
All touch and drag inputs related to this widget are cached/masked to prevent actions in the active app.
(See [espruino/Espruino#2151](https://github.com/espruino/Espruino/issues/2151) for more information.)
---
### Control
---
@ -39,6 +42,9 @@ In addition it shows the lock status with the option to personalize the lock ico
* _clk+launch_ -> on all apps of the types _clock_ and _launch_
* _except apps_ -> on all apps of the types _clock_ and _launch_ and in the settings
* _always on_ -> always enabled when the widget is displayed
* __Oversize__
_0px_ / _1px_ / _..._ / __20px__ / _..._ / _50px_
To make it easier to hit the widget, this value extends the touch area of the widget in all directions.
* __Drag Delay__
_off_ / _50ms_ / _100ms_ / _..._ / __500ms__ / _..._ / _1000ms_
Change the maximum delay between first touch and re-touch/drag to change the brightness or disable changing the brightness completely.
@ -85,8 +91,6 @@ This images are stored in a seperate file _(lightswitch.images.json)_.
### Worth Mentioning
---
#### To do list
* Catch the touch and draw input related to this widget to prevent actions in the active app.
_(For now I have no idea how to achieve this, help is appreciated)_
* Manage images for the lock icon through a _Customize and Upload App_ page.
#### Requests, Bugs and Feedback

View File

@ -2,7 +2,7 @@
"id": "lightswitch",
"name": "Light Switch Widget",
"shortName": "Light Switch",
"version": "0.03",
"version": "0.04",
"description": "A fast way to switch LCD backlight on/off, change the brightness and show the lock status. All in one widget.",
"icon": "images/app.png",
"screenshots": [

View File

@ -6,7 +6,8 @@
var settings = Object.assign({
colors: "011",
image: "default",
touchOn: "clock,launch",
touchOn: "always",
oversize: 20,
dragDelay: 500,
minValue: 0.1,
unlockSide: "",
@ -45,7 +46,7 @@
return {
value: entry.value.indexOf(settings[key]),
min : 0,
max : entry.value.length-1,
max : entry.value.length - 1,
wrap : true,
format: v => entry.title ? entry.title[v] : entry.value[v],
onchange: function(v) {
@ -57,11 +58,11 @@
// return entry for numerical value
return {
value: settings[key] * entry.factor,
step: entry.step,
format: v => v > 0 ? v + entry.unit : "off",
min : entry.min,
max : entry.max,
step: entry.step,
wrap : true,
format: v => v > 0 ? v + entry.unit : "off",
onchange: function(v) {
writeSetting(key, v / entry.factor, entry.drawWidgets);
},
@ -96,6 +97,14 @@
value: ["", "clock", "clock,setting.app.js", "clock,launch", "clock,setting.app.js,launch", "always"],
drawWidgets: true
},
oversize: {
factor: 1,
unit: "px",
min: 0,
max: 50,
step: 1,
drawWidgets: true
},
dragDelay: {
factor: 1,
unit: "ms",
@ -142,6 +151,7 @@
"Image": getEntry("image"),
"-- Control": 0,
"Touch": getEntry("touchOn"),
"Oversize": getEntry("oversize"),
"Drag Delay": getEntry("dragDelay"),
"Min Value": getEntry("minValue"),
"-- Unlock": 0,

View File

@ -10,8 +10,8 @@
"101" -> magenta
* image: string //
"default" ->
"random" ->
"default" -> image nearest to the default lock
"random" -> a random image from all available
* touchOn: string // select when widget touch is active
"" -> only on default clock
@ -19,6 +19,9 @@
"clock,launch" -> on all clocks and lanchers (default)
"always" -> always
* oversize: int // extends the touch area of the widget in px in all directions
0 to 50, 20 as default
* dragDelay: int // drag listener reset time in ms
// time until a drag is needed to activate backlight changing mode
0 -> disabled
@ -59,6 +62,7 @@
"colors": "011",
"image": "default",
"touchOn": "clock,launch",
"oversize": 20,
"dragDelay": 500,
"minValue": 0.1,
"unlockSide": "",

View File

@ -3,7 +3,8 @@
var settings = Object.assign({
colors: "011",
image: "default",
touchOn: "clock,launch",
touchOn: "always",
oversize: 20,
dragDelay: 500,
minValue: 0.1,
unlockSide: "",
@ -162,6 +163,11 @@
// change brigthness value, skip write to storage while still touching
w.changeValue(value, event.b);
// masks this drag event by messing up the event handler
// see https://github.com/espruino/Espruino/issues/2151
Bangle.removeListener("drag", w.dragListener);
Bangle["#ondrag"] = [w.dragListener].concat(Bangle["#ondrag"]);
// on touch release remove drag listener and reset drag status to indicate stopped drag action
if (!event.b) {
Bangle.removeListener("drag", w.dragListener);
@ -184,14 +190,14 @@
if (w.dragStatus === "off") {
// check if inside widget area
if (!(!w || cursor.x < w.x || cursor.x > w.x + w.width ||
cursor.y < w.y || cursor.y > w.y + 23)) {
if (!(!w || cursor.x < w.x - w.oversize || cursor.x > w.x + w.width + w.oversize ||
cursor.y < w.y - w.oversize || cursor.y > w.y + 23 + w.oversize)) {
// first touch feedback
Bangle.buzz(25);
// check if drag is disabled
if (w.dragDelay) {
// add drag listener
Bangle.on("drag", w.dragListener);
// add drag listener at first position
Bangle["#ondrag"] = [w.dragListener].concat(Bangle["#ondrag"]);
// set drag timeout
w.dragStatus = setTimeout((w) => {
// remove drag listener
@ -204,6 +210,10 @@
}
// switch backlight
w.changeValue();
// masks this touch event by messing up the event handler
// see https://github.com/espruino/Espruino/issues/2151
Bangle.removeListener("touch", w.touchListener);
Bangle["#ontouch"] = [w.touchListener].concat(Bangle["#ontouch"]);
}
}
@ -236,11 +246,11 @@
// add lock listener
Bangle.on("lock", w.draw);
// add touch listener to control the light depending on settings
// add touch listener to control the light depending on settings at first position
if (w.touchOn === "always" || !global.__FILE__ ||
w.touchOn.includes(__FILE__) ||
w.touchOn.includes(require("Storage").readJSON(__FILE__.replace("app.js", "info")).type))
Bangle.on("touch", w.touchListener);
Bangle["#ontouch"] = [w.touchListener].concat(Bangle["#ontouch"]);
// add tap listener to unlock and/or flash backlight
if (w.unlockSide || w.tapSide) Bangle.on("tap", require("lightswitch.js").tapListener);

View File

@ -688,8 +688,8 @@ var locales = {
datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20
abmonth: "Jan,Feb,Mar,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Des",
month: "Januar,Februar,Mars,April,Mai,Juni,Juli,August,September,Oktober,November,Desember",
abday: "Ma,Ti,On,To,Fr,Lø,Sø",
day: "Mandag,Tirsdag,Onsdag,Torsdag,Fredag,Lørdag,Søndag",
abday: "Sø,Ma,Ti,On,To,Fr,Lø",
day: "Søndag,Mandag,Tirsdag,Onsdag,Torsdag,Fredag,Lørdag",
trans: { yes: "ja", Yes: "Ja", no: "nei", No: "Nei", ok: "ok", on: "på", off: "av", "< Back": "< Tilbake", "Delete": "Slett", "Mark Unread": "Merk som ulest" }
},
/*,

View File

@ -43,3 +43,4 @@
0.28: Option to auto-unlock the watch when a new message arrives
0.29: Fix message list overwrites on Bangle.js 1 (fix #1642)
0.30: Add new Icons (Youtube, Twitch, MS TODO, Teams, Snapchat, Signal, Post & DHL, Nina, Lieferando, Kalender, Discord, Corona Warn, Bibel)
0.31: Option to disable icon flashing

View File

@ -21,6 +21,7 @@ is chosen if there isn't much message text, but this specifies the smallest the
it starts getting clipped.
* `Auto-Open Music` - Should the app automatically open when the phone starts playing music?
* `Unlock Watch` - Should the app unlock the watch when a new message arrives, so you can touch the buttons at the bottom of the app?
* `Flash Icon` - Toggle flashing of the widget icon.
## New Messages

View File

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

View File

@ -7,6 +7,7 @@
settings.unlockWatch=!!settings.unlockWatch;
settings.openMusic=!!settings.openMusic;
settings.maxUnreadTimeout=240;
if (settings.flash===undefined) settings.flash=true;
return settings;
}
function updateSetting(setting, value) {
@ -47,6 +48,11 @@
format: v => v?/*LANG*/'Yes':/*LANG*/'No',
onchange: v => updateSetting("unlockWatch", v)
},
/*LANG*/'Flash Icon': {
value: !!settings().flash,
format: v => v?/*LANG*/'Yes':/*LANG*/'No',
onchange: v => updateSetting("flash", v)
},
};
E.showMenu(mainmenu);
})

View File

@ -1,5 +1,5 @@
WIDGETS["messages"]={area:"tl", width:0, iconwidth:24,
draw:function() {
draw:function(recall) {
// If we had a setTimeout queued from the last time we were called, remove it
if (WIDGETS["messages"].i) {
clearTimeout(WIDGETS["messages"].i);
@ -8,15 +8,18 @@ draw:function() {
Bangle.removeListener('touch', this.touch);
if (!this.width) return;
var c = (Date.now()-this.t)/1000;
g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+this.iconwidth);
g.drawImage((c&1) ? atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+DAADDAADDAADDwAPD8A/DOBzDDn/DA//DAHvDAPvjAPvjAPvjAPvh///gf/vAAD+AAB8AAAAA==") : atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+D///D///A//8CP/xDj/HD48DD+B8D/D+D/3vD/vvj/vvj/vvj/vvh/v/gfnvAAD+AAB8AAAAA=="), this.x, this.y);
let settings = require('Storage').readJSON("messages.settings.json", true) || {};
if (settings.flash===undefined) settings.flash = true;
if (recall !== true || settings.flash) {
g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+23);
g.drawImage(settings.flash && (c&1) ? atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+DAADDAADDAADDwAPD8A/DOBzDDn/DA//DAHvDAPvjAPvjAPvjAPvh///gf/vAAD+AAB8AAAAA==") : atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+D///D///A//8CP/xDj/HD48DD+B8D/D+D/3vD/vvj/vvj/vvj/vvh/v/gfnvAAD+AAB8AAAAA=="), this.x, this.y-1);
}
if (settings.repeat===undefined) settings.repeat = 4;
if (c<120 && (Date.now()-this.l)>settings.repeat*1000) {
this.l = Date.now();
WIDGETS["messages"].buzz(); // buzz every 4 seconds
}
WIDGETS["messages"].i=setTimeout(()=>WIDGETS["messages"].draw(), 1000);
WIDGETS["messages"].i=setTimeout(()=>WIDGETS["messages"].draw(true), 1000);
if (process.env.HWVERSION>1) Bangle.on('touch', this.touch);
},show:function(quiet) {
WIDGETS["messages"].t=Date.now(); // first time

View File

@ -1,3 +1,4 @@
0.01: First release
0.02: Enhanced icon, make it bolder
0.03: Fixed issue with defaulting back to London
0.04: Fixed issue selecting Frankfurt not saved

View File

@ -4,7 +4,7 @@
"icon": "mylocation.png",
"type": "app",
"screenshots": [{"url":"screenshot_1.png"}],
"version":"0.03",
"version":"0.04",
"description": "Sets and stores the lat and long of your preferred City or it can be set from the GPS. mylocation.json can be used by other apps that need your main location lat and lon. See README",
"readme": "README.md",
"tags": "tool,utility",

View File

@ -61,7 +61,7 @@ function showMainMenu() {
min: 0, max: locations.length - 1,
format: v => locations[v],
onchange: v => {
if (v != 6) {
if (locations[v] !== "???") {
s.location = locations[v];
s.lat = lats[v];
s.lon = lons[v];