Merge pull request #828 from Xervon/feature/score/create-app
Score Tracker - Create new app 'score'master
commit
66bfee0ff0
18
apps.json
18
apps.json
|
|
@ -3554,5 +3554,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"}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -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.
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AE2IxAKSCigv/F/4vS44ABB4IECAAoKECgM7AAIJBAgQAFBQguJF6HHEhAvKGAwvy4wPB4wuGBQwdCmgJBmguGBQwvJ0ulF5AKFEgeCwQvIBQqPJ4wuHBQ4lEFw4KHF5IAQFJAALF+vNACYv/F/4v053P64vPxPXAAOJF6vP6wbCF52zCQQAB2YvTDIgvOLoWzMJQvOL6JeCss7spgIF5nPMQgvNCAQEBr4FEd6YvVAowv/F/4v4d9WzCANlndlAgOzF82JFQWJGgWJF8xgDAAReGF8RhDLo4vRABQiHABgv/F/4v/F4owTCgIuZAH4A/AH4A/ADgA=="))
|
||||
|
|
@ -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 != null ? 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();
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 897 B |
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
});
|
||||
})();
|
||||
Loading…
Reference in New Issue