Merge branch 'espruino:master' into master

pull/925/head
Ronin0000 2021-10-11 07:03:23 -07:00 committed by GitHub
commit 5db16d190b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 823 additions and 22 deletions

View File

@ -511,7 +511,7 @@
{ "id": "gpsrec",
"name": "GPS Recorder",
"icon": "app.png",
"version":"0.23",
"version":"0.24",
"interface": "interface.html",
"description": "Application that allows you to record a GPS track. Can run in background",
"tags": "tool,outdoors,gps,widget",
@ -687,7 +687,7 @@
{ "id": "widbt",
"name": "Bluetooth Widget",
"icon": "widget.png",
"version":"0.05",
"version":"0.06",
"description": "Show the current Bluetooth connection status in the top right of the clock",
"tags": "widget,bluetooth,b2",
"type":"widget",
@ -1316,7 +1316,7 @@
{ "id": "widid",
"name": "Bluetooth ID Widget",
"icon": "widget.png",
"version":"0.02",
"version":"0.03",
"description": "Display the last two tuple of your Bangle.js MAC address in the widget section. This is useful for figuring out which Bangle.js to connect to if you have more than one Bangle.js!",
"tags": "widget,address,mac",
"type":"widget",
@ -3571,5 +3571,23 @@
{"name":"floralclk.app.js","url":"app.js"},
{"name":"floralclk.img","url":"app-icon.js","evaluate":true}
]
},
{ "id": "score",
"name": "Score Tracker",
"icon": "score.app.png",
"version":"0.01",
"description": "Score Tracker for sports that use plain numbers (e.g. Badminton, Volleyball, Soccer, Table Tennis, ...). Also supports tennis scoring.",
"readme": "README.md",
"tags": "b2",
"type": "app",
"storage": [
{"name":"score.app.js","url":"score.app.js"},
{"name":"score.settings.js","url":"score.settings.js"},
{"name":"score.presets.json","url":"score.presets.json"},
{"name":"score.img","url":"score.app-icon.js","evaluate":true}
],
"data": [
{"name":"score.json"}
]
}
]

View File

@ -25,3 +25,4 @@
0.21: Fix issue where a period of 1s recorded every 2s, 5s every 6s, and so on
0.22: Ensure Bangle.setGPSPower uses 'gpsrec' as a tag
0.23: Fix issue where tracks wouldn't record when running from OpenStMap if a period hadn't been set up first
0.24: Better support for Bangle.js 2, avoid widget area for Graphs, smooth graphs more

View File

@ -102,7 +102,8 @@ function getTrackInfo(fn) {
var lfactor = Math.cos(minLat*Math.PI/180);
var ylen = (maxLat-minLat);
var xlen = (maxLong-minLong)* lfactor;
var scale = xlen>ylen ? 200/xlen : 200/ylen;
var screenSize = g.getHeight()-48; // 24 for widgets, plus a border
var scale = xlen>ylen ? screenSize/xlen : screenSize/ylen;
return {
fn : fn,
filename : filename,
@ -110,6 +111,7 @@ function getTrackInfo(fn) {
records : nl,
minLat : minLat, maxLat : maxLat,
minLong : minLong, maxLong : maxLong,
lat : (minLat+maxLat)/2, lon : (minLong+maxLong)/2,
lfactor : lfactor,
scale : scale,
duration : Math.round(duration/1000)
@ -180,16 +182,18 @@ function plotTrack(info) {
getMapXY = osm.latLonToXY.bind(osm);
} else {
getMapXY = function(lat, lon) { "ram"
var ix = 30 + Math.round((long - info.minLong)*info.lfactor*info.scale);
var iy = 210 - Math.round((lat - info.minLat)*info.scale);
return {x:ix, y:iy};
return {x:cx + Math.round((long - info.lon)*info.lfactor*info.scale),
y:cy + Math.round((info.lat - lat)*info.scale)};
}
}
E.showMenu(); // remove menu
E.showMessage("Drawing...","GPS Track "+info.fn);
g.flip(); // on buffered screens, draw a not saying we're busy
g.clear(1);
var s = require("Storage");
var cx = g.getWidth()/2;
var cy = g.getHeight()/2;
var cy = 24 + (g.getHeight()-24)/2;
g.setColor(1,0.5,0.5);
g.setFont("Vector",16);
g.drawString("Track"+info.fn.toString()+" - Loading",10,220);
@ -203,8 +207,8 @@ function plotTrack(info) {
g.drawString("N",2,40);
g.setColor(1,1,1);
} else {
osm.lat = (info.minLat+info.maxLat)/2;
osm.lon = (info.minLong+info.maxLong)/2;
osm.lat = info.lat;
osm.lon = info.lon;
osm.draw();
g.setColor(0, 0, 0);
}
@ -251,7 +255,8 @@ function plotTrack(info) {
g.drawString("Back",230,200);
setWatch(function() {
viewTrack(info.fn, info);
}, BTN3);
}, global.BTN3||BTN1);
Bangle.drawWidgets();
g.flip();
}
@ -260,8 +265,8 @@ function plotGraph(info, style) {
E.showMenu(); // remove menu
E.showMessage("Calculating...","GPS Track "+info.fn);
var filename = getFN(info.fn);
var infn = new Float32Array(200);
var infc = new Uint16Array(200);
var infn = new Float32Array(80);
var infc = new Uint16Array(80);
var title;
var lt = 0; // last time
var tn = 0; // count for each time period
@ -278,7 +283,7 @@ function plotGraph(info, style) {
title = "Altitude (m)";
while(l!==undefined) {
++nl;c=l.split(",");
i = Math.round(200*(c[0]/1000 - strt)/dur);
i = Math.round(80*(c[0]/1000 - strt)/dur);
infn[i]+=+c[3];
infc[i]++;
l = f.readLine(f);
@ -289,7 +294,7 @@ function plotGraph(info, style) {
var t,dx,dy,d,lt = c[0]/1000;
while(l!==undefined) {
++nl;c=l.split(",");
i = Math.round(200*(c[0]/1000 - strt)/dur);
i = Math.round(80*(c[0]/1000 - strt)/dur);
t = c[0]/1000;
p = Bangle.project({lat:c[1],lon:c[2]});
dx = p.x-lp.x;
@ -320,9 +325,9 @@ function plotGraph(info, style) {
// draw
g.clear(1).setFont("6x8",1);
var r = require("graph").drawLine(g, infn, {
x:4,y:0,
x:4,y:24,
width: g.getWidth()-24,
height: g.getHeight()-8,
height: g.getHeight()-(24+8),
axes : true,
gridy : grid,
gridx : 50,
@ -334,7 +339,7 @@ function plotGraph(info, style) {
g.drawString("Back",230,200);
setWatch(function() {
viewTrack(info.fn, info);
}, BTN3);
}, global.BTN3||BTN1);
g.flip();
}

1
apps/score/ChangeLog Normal file
View File

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

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

@ -0,0 +1,47 @@
This app will allow you to keep scores for most kinds of sports.
# Keybinds
To correct a falsely awarded point simply open and close the menu within .5 seconds. This will put the app into correction mode (indicated by the `R`).
In this mode any score increments will be decrements. To move back a set, reduce both players scores to 0, then decrement one of the scores once again.
## Bangle.js 1
| Keybinding | Description |
|---------------------|------------------------------|
| `BTN1` | Increment left player score |
| `BTN3` | Increment right player score |
| `BTN2` | Menu |
| touch on left side | Scroll up |
| touch on right side | Scroll down |
## Bangle.js 2
| Keybinding | Description |
|-------------------------------------|------------------------------|
| `BTN1` | Menu |
| touch on left side of divider line | Increment left player score |
| touch on right side of divider line | Increment right player score |
# Settings
| Setting | Description |
|------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| `Presets` | Enable a preset for one of the configured sports |
| `Sets to win` | How many sets a player has to win before the match is won (Maximum sets: this*2-1) |
| `Sets per page` | How many sets should be shown in the app. Further sets will be available by scrolling (ignored if higher than `Sets to win`) |
| `Score to win` | What score ends a given set |
| `2-point lead` | Does winning a set require a two-point lead |
| `Maximum score?` | Should there be a maximum score, at which point the two-point lead rule falls away |
| `Maximum score` | At which score should the two-point lead rule fall away (ignored if lower than Sets to win) |
| `Tennis scoring` | If enabled, each point in a set will require a full tennis game |
| `TB sets?` | Should sets that have reached `(maxScore-1):(maxScore-1)` be decided with a tiebreak |
| All other options starting with TB | Equivalent to option with same name but applied to tiebreaks |
The settings can be changed both from within the app by simply pressing `BTN2` (`BTN1` on Bangle.js 2) or in the `App Settings` in the `Settings` app.
If changes are made to the settings from within the app, a new match will automatically be initialized upon exiting the settings.
By default the settings will reflect Badminton rules.
## Tennis Scoring
While tennis scoring is available, correcting in this mode will reset to the beginning of the current game.
Resetting at the beginning of the current game will reset to the beginning of the previous game, leaving the user to fast-forward to the correct score once again.
This might get changed at some point.

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AE2IxAKSCigv/F/4vS44ABB4IECAAoKECgM7AAIJBAgQAFBQguJF6HHEhAvKGAwvy4wPB4wuGBQwdCmgJBmguGBQwvJ0ulF5AKFEgeCwQvIBQqPJ4wuHBQ4lEFw4KHF5IAQFJAALF+vNACYv/F/4v053P64vPxPXAAOJF6vP6wbCF52zCQQAB2YvTDIgvOLoWzMJQvOL6JeCss7spgIF5nPMQgvNCAQEBr4FEd6YvVAowv/F/4v4d9WzCANlndlAgOzF82JFQWJGgWJF8xgDAAReGF8RhDLo4vRABQiHABgv/F/4v/F4owTCgIuZAH4A/AH4A/ADgA=="))

478
apps/score/score.app.js Normal file
View File

@ -0,0 +1,478 @@
require('Font5x9Numeric7Seg').add(Graphics);
require('Font7x11Numeric7Seg').add(Graphics);
require('FontTeletext5x9Ascii').add(Graphics);
let settingsMenu = eval(require('Storage').read('score.settings.js'));
let settings = settingsMenu(null, null, true);
let tennisScores = ['00','15','30','40','DC','AD'];
let scores = null;
let tScores = null;
let cSet = null;
let firstShownSet = null;
let settingsMenuOpened = null;
let correctionMode = false;
let w = g.getWidth();
let h = g.getHeight();
let isBangle1 = process.env.BOARD === 'BANGLEJS';
function getXCoord(func) {
let offset = 40;
return func(w-offset)+offset;
}
function getSecondsTime() {
return Math.floor(getTime() * 1000);
}
function setupDisplay() {
// make sure LCD on Bangle.js 1 stays on
if (isBangle1) {
if (settings.keepDisplayOn) {
Bangle.setLCDTimeout(0);
Bangle.setLCDPower(true);
} else {
Bangle.setLCDTimeout(10);
}
}
}
function setupInputWatchers(init) {
Bangle.setUI('updown', v => {
if (v) {
if (isBangle1) {
let i = settings.mirrorScoreButtons ? v : v * -1;
handleInput(Math.floor((i+2)/2));
} else {
handleInput(Math.floor((v+2)/2)+3);
}
}
});
if (init) {
setWatch(() => handleInput(2), isBangle1 ? BTN2 : BTN, { repeat: true });
Bangle.on('touch', (b, e) => {
if (isBangle1) {
if (b === 1) {
handleInput(3);
} else {
handleInput(4);
}
} else {
if (e.x < getXCoord(w => w/2)) {
handleInput(0);
} else {
handleInput(1);
}
}
});
}
}
function setupMatch() {
scores = [];
for (let s = 0; s < sets(); s++) {
scores.push([0,0,null,0,0]);
}
scores.push([0,0,null,0,0]);
if (settings.enableTennisScoring) {
tScores = [0,0];
} else {
tScores = null;
}
scores[0][2] = getSecondsTime();
cSet = 0;
setFirstShownSet();
correctionMode = false;
}
function showSettingsMenu() {
settingsMenuOpened = getSecondsTime();
l = null;
settingsMenu(function (s, reset) {
E.showMenu();
settings = s;
if (reset) {
setupMatch();
} else if (getSecondsTime() - settingsMenuOpened < 500 || correctionMode) {
correctionMode = !correctionMode;
}
settingsMenuOpened = null;
draw();
setupDisplay();
setupInputWatchers();
}, function (msg) {
switch (msg) {
case 'end_set':
updateCurrentSet(1);
break;
}
});
}
function maxScore() {
return Math.max(settings.maxScore, settings.winScore);
}
function tiebreakMaxScore() {
return Math.max(settings.maxScoreTiebreakMaxScore, settings.maxScoreTiebreakWinScore);
}
function setsPerPage() {
return Math.min(settings.setsPerPage, sets());
}
function sets() {
return settings.winSets * 2 - 1;
}
function currentSet() {
return matchEnded() ? cSet - 1 : cSet;
}
function shouldTiebreak() {
return settings.enableMaxScoreTiebreak &&
scores[cSet][0] + scores[cSet][1] === (maxScore() - 1) * 2;
}
function formatNumber(num, length) {
return num.toString().padStart(length ? length : 2,"0");
}
function formatDuration(duration) {
let durS = Math.floor(duration / 1000);
let durM = Math.floor(durS / 60);
let durH = Math.floor(durM / 60);
durS = durS - durM * 60;
durM = durM - durH * 60;
durS = formatNumber(durS);
durM = formatNumber(durM);
durH = formatNumber(durH);
let dur = null;
if (durH > 0) {
dur = durH + ':' + durM;
} else {
dur = durM + ':' + durS;
}
return dur;
}
function tiebreakWon(set, player) {
let pScore = scores[set][3+player];
let p2Score = scores[set][3+~~!player];
let winScoreReached = pScore >= settings.maxScoreTiebreakWinScore;
let isTwoAhead = !settings.maxScoreTiebreakEnableTwoAhead || pScore - p2Score >= 2;
let reachedMaxScore = settings.maxScoreTiebreakEnableMaxScore && pScore >= tiebreakMaxScore();
return reachedMaxScore || (winScoreReached && isTwoAhead);
}
function setWon(set, player) {
let pScore = scores[set][player];
let p2Score = scores[set][~~!player];
let winScoreReached = pScore >= settings.winScore;
let isTwoAhead = !settings.enableTwoAhead || pScore - p2Score >= 2;
let tiebreakW = tiebreakWon(set, player);
let reachedMaxScore = settings.enableMaxScore && pScore >= maxScore();
let manuallyEndedWon = cSet > set ? pScore > p2Score : false;
return (
(settings.enableMaxScoreTiebreak ? tiebreakW : reachedMaxScore) ||
(winScoreReached && isTwoAhead) ||
manuallyEndedWon
);
}
function setEnded(set) {
return setWon(set, 0) || setWon(set, 1);
}
function setsWon(player) {
return Array(sets()).fill(0).map((_, s) => ~~setWon(s, player)).reduce((a,v) => a+v, 0);
}
function matchWon(player) {
return setsWon(player) >= settings.winSets;
}
function matchEnded() {
return (matchWon(0) || matchWon(1)) && cSet > (setsWon(0) + setsWon(1) - 1);
}
function matchScore(player) {
return scores.reduce((acc, val) => acc += val[player], 0);
}
function setFirstShownSet() {
firstShownSet = Math.max(0, currentSet() - setsPerPage() + 1);
}
function updateCurrentSet(val) {
if (val > 0) {
cSet++;
} else if (val < 0) {
cSet--;
} else {
return;
}
setFirstShownSet();
if (val > 0) {
scores[cSet][2] = getSecondsTime();
if (matchEnded()) {
firstShownSet = 0;
}
}
}
function score(player) {
if (!matchEnded()) {
setFirstShownSet();
}
if (correctionMode) {
if (
scores[cSet][0] === 0 && scores[cSet][1] === 0 &&
scores[cSet][3] === 0 && scores[cSet][4] === 0 &&
cSet > 0
) {
updateCurrentSet(-1);
}
if (scores[cSet][3] > 0 || scores[cSet][4] > 0) {
if (scores[cSet][3+player] > 0) {
scores[cSet][3+player]--;
}
} else if (scores[cSet][player] > 0) {
if (
!settings.enableTennisScoring ||
(tScores[player] === 0 && tScores[~~!player] === 0)
) {
scores[cSet][player]--;
} else {
tScores[player] = 0;
tScores[~~!player] = 0;
}
}
} else {
if (matchEnded()) return;
if (shouldTiebreak()) {
scores[cSet][3+player]++;
} else if (settings.enableTennisScoring) {
if (tScores[player] === 4 && tScores[~~!player] === 5) { // DC : AD
tScores[~~!player]--;
} else if (tScores[player] === 2 && tScores[~~!player] === 3) { // 30 : 40
tScores[0] = 4;
tScores[1] = 4;
} else if (tScores[player] === 3 || tScores[player] === 5) { // 40 / AD
tScores[0] = 0;
tScores[1] = 0;
scores[cSet][player]++;
} else {
tScores[player]++;
}
} else {
scores[cSet][player]++;
}
if (setEnded(cSet) && cSet < sets()) {
if (shouldTiebreak()) {
scores[cSet][player]++;
}
updateCurrentSet(1);
}
}
}
function handleInput(button) {
if (settingsMenuOpened) {
return;
}
switch (button) {
case 0:
case 1:
score(button);
break;
case 2:
showSettingsMenu();
return;
case 3:
case 4:
let hLimit = currentSet() - setsPerPage() + 1;
let lLimit = 0;
let val = (button * 2 - 7);
firstShownSet += val;
if (firstShownSet > hLimit) firstShownSet = hLimit;
if (firstShownSet < lLimit) firstShownSet = lLimit;
break;
}
draw();
}
function draw() {
g.setFontAlign(0,0);
g.clear();
for (let p = 0; p < 2; p++) {
if (matchWon(p)) {
g.setFontAlign(0,0);
g.setFont('Teletext5x9Ascii',2);
g.drawString(
"WINNER",
getXCoord(w => p === 0 ? w/4 : w/4*3),
15
);
} else if (matchEnded()) {
g.setFontAlign(1,0);
g.setFont('Teletext5x9Ascii',1);
g.drawString(
(currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''),
40,
8
);
let dur1 = formatDuration(scores[cSet][2] - scores[0][2]);
g.setFont('5x9Numeric7Seg',1);
g.drawString(
dur1,
40,
18
);
}
g.setFontAlign(p === 0 ? -1 : 1,1);
g.setFont('5x9Numeric7Seg',2);
g.drawString(
setsWon(p),
getXCoord(w => p === 0 ? 5 : w-3),
h-5
);
if (!settings.enableTennisScoring) {
g.setFontAlign(p === 0 ? 1 : -1,1);
g.setFont('7x11Numeric7Seg',2);
g.drawString(
formatNumber(matchScore(p), 3),
getXCoord(w => p === 0 ? w/2 - 3 : w/2 + 6),
h-5
);
}
}
g.setFontAlign(0,0);
if (correctionMode) {
g.setFont('Teletext5x9Ascii',2);
g.drawString(
"R",
getXCoord(w => w/2),
h-10
);
}
let lastShownSet = Math.min(
sets(),
currentSet() + 1,
firstShownSet+setsPerPage()
);
let setsOnCurrentPage = Math.min(
sets(),
setsPerPage()
);
for (let set = firstShownSet; set < lastShownSet; set++) {
if (set < 0) continue;
let y = (h-15)/(setsOnCurrentPage+1)*(set-firstShownSet+1)+5;
g.setFontAlign(-1,0);
g.setFont('7x11Numeric7Seg',1);
g.drawString(set+1, 5, y-10);
if (scores[set+1][2] != null) {
let dur2 = formatDuration(scores[set+1][2] - scores[set][2]);
g.drawString(dur2, 5, y+10);
}
for (let p = 0; p < 2; p++) {
if (!setWon(set, p === 0 ? 1 : 0) || matchEnded()) {
let bigNumX = getXCoord(w => p === 0 ? w/4-12 : w/4*3+15);
let smallNumX = getXCoord(w => p === 0 ? w/2-2 : w/2+3);
if (settings.enableTennisScoring && set === cSet && !shouldTiebreak()) {
g.setFontAlign(0,0);
g.setFont('7x11Numeric7Seg',3);
g.drawString(
formatNumber(tennisScores[tScores[p]]),
bigNumX,
y
);
} else if (shouldTiebreak() && set === cSet) {
g.setFontAlign(0,0);
g.setFont('7x11Numeric7Seg',3);
g.drawString(
formatNumber(scores[set][3+p], 3),
bigNumX,
y
);
} else {
g.setFontAlign(0,0);
g.setFont('7x11Numeric7Seg',3);
g.drawString(
formatNumber(scores[set][p]),
bigNumX,
y
);
}
if ((shouldTiebreak() || settings.enableTennisScoring) && set === cSet) {
g.setFontAlign(p === 0 ? 1 : -1,0);
g.setFont('7x11Numeric7Seg',1);
g.drawString(
formatNumber(scores[set][p]),
smallNumX,
y
);
} else if ((scores[set][3] !== 0 || scores[set][4] !== 0) && set !== cSet) {
g.setFontAlign(p === 0 ? 1 : -1,0);
g.setFont('7x11Numeric7Seg',1);
g.drawString(
formatNumber(scores[set][3+p], 3),
smallNumX,
y
);
}
}
}
}
// draw separator
g.drawLine(getXCoord(w => w/2), 20, getXCoord(w => w/2), h-25);
g.flip();
}
setupDisplay();
setupInputWatchers(true);
setupMatch();
draw();

BIN
apps/score/score.app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

View File

@ -0,0 +1,30 @@
{
"Badminton": {
"winScore": 21,
"enableTwoAhead": true,
"enableMaxScore": true,
"maxScore": 30
},
"Tennis": {
"winScore": 6,
"enableTwoAhead": true,
"enableMaxScore": true,
"maxScore": 7,
"enableMaxScoreTiebreak": true,
"maxScoreTiebreakWinScore": 7,
"maxScoreTiebreakEnableTwoAhead": true,
"maxScoreTiebreakEnableMaxScore": false,
"enableTennisScoring": true
},
"Soccer": {
"winSets": 1,
"winScore": 9999,
"enableTwoAhead": false,
"enableMaxScore": false
},
"Table Tennis": {
"winScore": 11,
"enableTwoAhead": true,
"enableMaxScore": false
}
}

View File

@ -0,0 +1,219 @@
(function () {
return (function (back, inApp, ret) {
const isBangle1 = process.env.BOARD === 'BANGLEJS'
function fillSettingsWithDefaults(settings) {
if (isBangle1) {
if (settings.mirrorScoreButtons == null) {
settings.mirrorScoreButtons = false;
}
if (settings.keepDisplayOn == null) {
settings.keepDisplayOn = true;
}
}
if (settings.winSets == null) {
settings.winSets = 2;
}
if (settings.setsPerPage == null) {
settings.setsPerPage = 5;
}
if (settings.winScore == null) {
settings.winScore = 21;
}
if (settings.enableTwoAhead == null) {
settings.enableTwoAhead = true;
}
if (settings.enableMaxScore == null) {
settings.enableMaxScore = true;
}
if (settings.maxScore == null) {
settings.maxScore = 30;
}
if (settings.enableTennisScoring == null) {
settings.enableTennisScoring = false;
}
if (settings.enableMaxScoreTiebreak == null) {
settings.enableMaxScoreTiebreak = false;
}
if (settings.maxScoreTiebreakWinScore == null) {
settings.maxScoreTiebreakWinScore = 6;
}
if (settings.maxScoreTiebreakEnableTwoAhead == null) {
settings.maxScoreTiebreakEnableTwoAhead = true;
}
if (settings.maxScoreTiebreakEnableMaxScore == null) {
settings.maxScoreTiebreakEnableMaxScore = false;
}
if (settings.maxScoreTiebreakMaxScore == null) {
settings.maxScoreTiebreakMaxScore = 15;
}
return settings;
}
const fileName = 'score.json';
let settings = require('Storage').readJSON(fileName, 1) || {};
const offon = ['No', 'Yes'];
let presetsFileName = 'score.presets.json';
let presets = require('Storage').readJSON(presetsFileName);
let presetNames = Object.keys(presets);
let changed = false;
function save(settings) {
require('Storage').writeJSON(fileName, settings);
}
function setAndSave(key, value, notChanged) {
if (!notChanged) {
changed = true;
}
settings[key] = value;
if (key === 'winScore' && settings.maxScore < value) {
settings.maxScore = value;
}
save(settings);
}
settings = fillSettingsWithDefaults(settings);
if (ret) {
return settings;
}
const presetMenu = function (appMenuBack) {
let ret = function (changed) { E.showMenu(appMenu(appMenuBack, changed ? 2 : null)); };
let m = {
'': {'title': 'Score Presets'},
'< Back': ret,
};
for (let i = 0; i < presetNames.length; i++) {
m[presetNames[i]] = (function (i) {
return function() {
changed = true;
let mirrorScoreButtons = settings.mirrorScoreButtons;
let keepDisplayOn = settings.keepDisplayOn;
settings = fillSettingsWithDefaults(presets[presetNames[i]]);
settings.mirrorScoreButtons = mirrorScoreButtons;
settings.keepDisplayOn = keepDisplayOn;
save(settings);
ret(true);
};
})(i);
}
return m;
};
const appMenu = function (back, selected) {
let m = {};
m[''] = {'title': 'Score Settings'};
if (selected != null) {
m[''].selected = selected;
}
m['< Back'] = function () { back(settings, changed); };
m['Presets'] = function () { E.showMenu(presetMenu(back)); };
if (isBangle1) {
m['Mirror Buttons'] = {
value: settings.mirrorScoreButtons,
format: m => offon[~~m],
onchange: m => setAndSave('mirrorScoreButtons', m, true),
};
m['Keep display on'] = {
value: settings.keepDisplayOn,
format: m => offon[~~m],
onchange: m => setAndSave('keepDisplayOn', m, true),
}
}
m['Sets to win'] = {
value: settings.winSets,
min:1,
onchange: m => setAndSave('winSets', m),
};
m['Sets per page'] = {
value: settings.setsPerPage,
min:1,
max:5,
onchange: m => setAndSave('setsPerPage', m),
};
m['Score to win'] = {
value: settings.winScore,
min:1,
max: 999,
onchange: m => setAndSave('winScore', m),
};
m['2-point lead'] = {
value: settings.enableTwoAhead,
format: m => offon[~~m],
onchange: m => setAndSave('enableTwoAhead', m),
};
m['Maximum score?'] = {
value: settings.enableMaxScore,
format: m => offon[~~m],
onchange: m => setAndSave('enableMaxScore', m),
};
m['Maximum score'] = {
value: settings.maxScore,
min: 1,
max: 999,
onchange: m => setAndSave('maxScore', m),
};
m['Tennis scoring'] = {
value: settings.enableTennisScoring,
format: m => offon[~~m],
onchange: m => setAndSave('enableTennisScoring', m),
};
m['TB sets?'] = {
value: settings.enableMaxScoreTiebreak,
format: m => offon[~~m],
onchange: m => setAndSave('enableMaxScoreTiebreak', m),
};
m['TB Score to win'] = {
value: settings.maxScoreTiebreakWinScore,
onchange: m => setAndSave('maxScoreTiebreakWinScore', m),
};
m['TB 2-point lead'] = {
value: settings.maxScoreTiebreakEnableTwoAhead,
format: m => offon[~~m],
onchange: m => setAndSave('maxScoreTiebreakEnableTwoAhead', m),
};
m['TB max score?'] = {
value: settings.maxScoreTiebreakEnableMaxScore,
format: m => offon[~~m],
onchange: m => setAndSave('maxScoreTiebreakEnableMaxScore', m),
};
m['TB max score'] = {
value: settings.maxScoreTiebreakMaxScore,
onchange: m => setAndSave('maxScoreTiebreakMaxScore', m),
};
return m;
};
const inAppMenu = function () {
let m = {
'': {'title': 'Score Menu'},
'< Back': function () { back(settings, changed); },
'Reset match': function () { back(settings, true); },
'End current set': function () { inApp('end_set'); back(settings, changed); },
'Configuration': function () { E.showMenu(appMenu(function () {
E.showMenu(inAppMenu());
})); },
};
return m;
};
if (inApp != null) {
E.showMenu(inAppMenu());
} else {
E.showMenu(appMenu(back));
}
});
})();

View File

@ -2,3 +2,4 @@
0.03: Ensure redrawing works with variable size widget system
0.04: Fix automatic update of Bluetooth connection status
0.05: Make Bluetooth widget thinner, and when on a bright theme use light grey for disabled color
0.06: Tweaking colors for dark/light themes and low bpp screens

View File

@ -2,9 +2,9 @@
function draw() {
g.reset();
if (NRF.getSecurityStatus().connected)
g.setColor("#07f");
g.setColor((g.getBPP()>8) ? "#07f" : (g.theme.dark ? "#0ff" : "#00f"));
else
g.setColor(g.theme.bg ? "#AAA" : "#555");
g.setColor(g.theme.dark ? "#666" : "#999");
g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),2+this.x,2+this.y);
}
function changed() {

View File

@ -1,2 +1,3 @@
0.01: New Widget!
0.02: Tweaks for variable size widget system
0.03: Tweaking colors for dark/light themes

View File

@ -1,8 +1,7 @@
/* jshint esversion: 6 */
(() => {
function draw() {
var id = NRF.getAddress().substr().substr(12).split(":");
g.reset().setColor(0, 0.49, 1).setFont("6x8", 1);
g.reset().setColor(g.theme.dark ? "#0ff" : "#00f").setFont("6x8", 1);
g.drawString(id[0], this.x+2, this.y+4, true);
g.drawString(id[1], this.x+2, this.y+14, true);
}