From 154652e51d9d7e46e4566a3b8c70b2d2e3cc8122 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 22:08:20 +0200 Subject: [PATCH 01/50] create new app 'score' --- apps.json | 13 ++ apps/score/ChangeLog | 1 + apps/score/score.app-icon.js | 1 + apps/score/score.app.js | 288 +++++++++++++++++++++++++++++++++++ apps/score/score.app.png | Bin 0 -> 897 bytes apps/score/score.settings.js | 81 ++++++++++ 6 files changed, 384 insertions(+) create mode 100644 apps/score/ChangeLog create mode 100644 apps/score/score.app-icon.js create mode 100644 apps/score/score.app.js create mode 100644 apps/score/score.app.png create mode 100644 apps/score/score.settings.js diff --git a/apps.json b/apps.json index 6b0703601..314504276 100644 --- a/apps.json +++ b/apps.json @@ -3554,5 +3554,18 @@ {"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, ...)", + "tags": "b2", + "type": "app", + "storage": [ + {"name":"score.app.js","url":"score.app.js"}, + {"name":"score.settings.js","url":"score.settings.js"}, + {"name":"score.img","url":"score.app-icon.js","evaluate":true} + ] } ] diff --git a/apps/score/ChangeLog b/apps/score/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/score/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/score/score.app-icon.js b/apps/score/score.app-icon.js new file mode 100644 index 000000000..b1d4631ba --- /dev/null +++ b/apps/score/score.app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AE2IxAKSCigv/F/4vS44ABB4IECAAoKECgM7AAIJBAgQAFBQguJF6HHEhAvKGAwvy4wPB4wuGBQwdCmgJBmguGBQwvJ0ulF5AKFEgeCwQvIBQqPJ4wuHBQ4lEFw4KHF5IAQFJAALF+vNACYv/F/4v053P64vPxPXAAOJF6vP6wbCF52zCQQAB2YvTDIgvOLoWzMJQvOL6JeCss7spgIF5nPMQgvNCAQEBr4FEd6YvVAowv/F/4v4d9WzCANlndlAgOzF82JFQWJGgWJF8xgDAAReGF8RhDLo4vRABQiHABgv/F/4v/F4owTCgIuZAH4A/AH4A/ADgA==")) diff --git a/apps/score/score.app.js b/apps/score/score.app.js new file mode 100644 index 000000000..7bfadb1ce --- /dev/null +++ b/apps/score/score.app.js @@ -0,0 +1,288 @@ +require('Font5x9Numeric7Seg').add(Graphics); +require('Font7x11Numeric7Seg').add(Graphics); +require('FontTeletext5x9Ascii').add(Graphics); +require('FontTeletext10x18Ascii').add(Graphics); + +let settingsMenu = eval(require('Storage').read('score.settings.js')); +let settings = settingsMenu(null, true); + +let scores = null; +let cSet = null; + +let firstShownSet = null; + +let settingsMenuOpened = null; +let correctionMode = false; + +let w = g.getWidth(); +let h = g.getHeight(); + +function setupInputWatchers() { + if (global.BTN4) { + setWatch(() => handleInput(2), BTN2, { repeat: true }); + setWatch(() => handleInput(3), BTN1, { repeat: true }); + setWatch(() => handleInput(4), BTN3, { repeat: true }); + } else { + setWatch(() => handleInput(2), BTN, { repeat: true }); + } + Bangle.on('touch', (b, e) => { + if (b) { + if (b === 1) { + handleInput(0); + } else { + handleInput(1); + } + } else { + if (e.x < w/2) { + handleInput(0); + } else { + handleInput(1); + } + } + }) +} + +function setupMatch() { + scores = []; + for (let s = 0; s < sets(); s++) { + scores.push([0,0,null]); + } + scores.push([0,0,null]); + + scores[0][2] = getTime(); + + cSet = 0; + firstShownSet = 0 - Math.floor(setsPerPage() / 2); +} + +function showSettingsMenu() { + settingsMenuOpened = getTime(); + settingsMenu(function (s, reset) { + E.showMenu(); + + settings = s; + + if (reset) { + setupMatch(); + } else if (getTime() - settingsMenuOpened < 0.5 || correctionMode) { + correctionMode = !correctionMode; + } + + settingsMenuOpened = null; + + draw(); + }); +} + +function setsPerPage() { + return Math.min(settings.setsPerPage, sets()); +} + +function sets() { + return settings.winSets * 2 - 1; +} + +function currentSet() { + return matchEnded() ? cSet - 1 : cSet; +} + +function formatNumber(num, length) { + return num.toString().padStart(length ? length : 2,"0"); +} + +function formatDuration(duration) { + let durS = Math.floor(duration); + 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 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 reachedMaxScore = settings.enableMaxScore && pScore >= settings.maxScore; + + return reachedMaxScore || (winScoreReached && isTwoAhead); +} + +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); +} + +function matchScore(player) { + return scores.reduce((acc, val) => acc += val[player], 0); +} + +function score(player) { + let updateCurrentSet = function (val) { + cSet += val; + firstShownSet = Math.max(0, currentSet() - settings.setsPerPage + 1); + } + + if (!matchEnded() || correctionMode) { + firstShownSet = currentSet() - Math.floor(setsPerPage() / 2); + } + + if (correctionMode) { + if ( + scores[cSet][0] === 0 && scores[cSet][1] === 0 && + cSet > 0 + ) { + updateCurrentSet(-1); + } + + if (scores[cSet][player] > 0) { + scores[cSet][player]--; + } + } else { + if (matchEnded()) return; + + scores[cSet][player]++; + + if (setEnded(cSet) && cSet < sets()) { + updateCurrentSet(1); + scores[cSet][2] = getTime(); + } + + if (matchEnded()) { + firstShownSet = 0; + } + } +} + +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(); + let lLimit = 1 - setsPerPage(); + 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('Teletext10x18Ascii',1); + g.drawString("WINNER", p === 0 ? w/4 : w/4*3, 15); + } else if (matchEnded()) { + g.setFontAlign(0,-1); + + let dur1 = formatDuration(scores[cSet][2] - scores[0][2]); + g.setFont('5x9Numeric7Seg',1); + g.drawString(dur1, p === 0 ? w/8 : w/8*5, 10); + + g.setFont('Teletext5x9Ascii',1); + g.drawString((currentSet()+1) + ' set' + (currentSet() > 1 ? 's' : ''), p === 0 ? w/8*3 : w/8*7, 12); + + } + + g.setFontAlign(p === 0 ? -1 : 1,1); + g.setFont('7x11Numeric7Seg',2); + g.drawString(setsWon(p), p === 0 ? 10 : w-8, h-5); + + g.setFontAlign(p === 0 ? 1 : -1,1); + g.setFont('7x11Numeric7Seg',2); + g.drawString(formatNumber(matchScore(p), 3), p === 0 ? w/2 - 8 : w/2 + 11, h-5); + } + g.setFontAlign(0,0); + + if (correctionMode) { + g.setFont('Teletext10x18Ascii',1); + g.drawString("R", 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, 40, y-10); + if (scores[set+1][2] != null) { + let dur2 = formatDuration(scores[set+1][2] - scores[set][2]); + g.drawString(dur2, 40, y+10); + } + + g.setFontAlign(0,0); + g.setFont('7x11Numeric7Seg',3); + for (let p = 0; p < 2; p++) { + if (!setWon(set, p === 0 ? 1 : 0) || matchEnded()) { + g.drawString( + formatNumber(scores[set][p]), + p === 0 ? (w-20)/4+20 : (w-20)/4*3+20, + y + ); + } + } + } + + // draw separator + g.drawLine(w/2,20,w/2,h-25); + + g.flip(); +} + +setupInputWatchers(); +setupMatch(); +draw(); diff --git a/apps/score/score.app.png b/apps/score/score.app.png new file mode 100644 index 0000000000000000000000000000000000000000..c1e7e22157fc295811c8b0291dd736d7d1878e5a GIT binary patch literal 897 zcmV-{1AhF8P)-q;>a)qdEv4t%nBoLyDDR~j<9&`&l zbnlXgNO%l7dGZn+>{ierq}uY3iGi7fhrmBe8YsJ!ZRKF5hsneX&? z@7wQvzu)iun+1IM@Zsag;`zG|(=XDKQ*LtI)|9FZ5{3?d@yx}|bz4*5QaZvo_5oOy zko+<=h%Gt*3K0Na?esrO?pyOcToDvOX{aMREff?CXj)klm;(SLM)Dl%$jTK2(7J#y z^yO~k;SR%E0h9SdgF=K%2d(B02Tg-mP_#jFpEUrJd6qArQo9mtxf&DA=4r8L3>7!4 zYT9w>u4LHm0lKe`mM57SG_L|kWOZVz^-?kMX^$|#^ zgzW@QxI(xVp)>ZTop4XqJs`B!xIRIGx}T#ZQ~TIgzz@J{RJ{l6KYO`()yg>E zR8B~V0^f2P0AOxi)5qJI_;Sl1z{-<@_}do^q4IMkUt;=KZ=qx?`uZT>gU_>LRIK37 zyk{j&XUF~?@GJmY;fORBMb-9>SAu5&{M}yfVbd;b3>hJ8$b27Co&~V*tDNH60KwUY zvW;Z3VQ29-UkMyNCEP$dLvf|GeAYj>7DPHj(c5O6{co2kmyTxvj4!IVaZW^gOhmF- zuw?)98pWGszQ>SfOGslt|AdUOc?D|)22}&r3JhcO3i>Bx-v1JuRY0A%?Br*Au%!Z{ zvkFFM6~`L>J>WG?TmUO>iZkH*f6~-p34j27y9tMxh%nLz=B}ndSf3kOK79D_;ST-* XivUhVT==`h00000NkvXXu0mjflmwo` literal 0 HcmV?d00001 diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js new file mode 100644 index 000000000..dde77a225 --- /dev/null +++ b/apps/score/score.settings.js @@ -0,0 +1,81 @@ +(function (back, ret) { + + const fileName = 'score.json' + let settings = require('Storage').readJSON(fileName, 1) || {}; + const offon = ['No', 'Yes']; + + let changed = false; + + function save(key, value) { + changed = true; + settings[key] = value; + if (key === 'winScore' && settings.maxScore < value) { + settings.maxScore = value; + } + require('Storage').writeJSON(fileName, settings); + } + + if (!settings.winSets) { + settings.winSets = 1; + } + if (!settings.winScore) { + settings.winScore = 21; + } + if (!settings.enableTwoAhead) { + settings.enableTwoAhead = true; + } + if (!settings.enableMaxScore) { + settings.enableMaxScore = true; + } + if (!settings.maxScore) { + settings.maxScore = 30; + } + if (!settings.setsPerPage) { + settings.setsPerPage = 5; + } + + if (ret) { + return settings; + } + + const appMenu = {}; + appMenu[''] = {'title': 'Score Settings'}, + appMenu['< Back'] = function () { back(settings, changed); }; + if (reset) { + appMenu['Reset match'] = function () { back(settings, true); }; + } + appMenu['Sets to win'] = { + value: settings.winSets, + min:1, + onchange: m => save('winSets', m) + }; + appMenu['Sets per page'] = { + value: settings.setsPerPage, + min:1, + max:5, + onchange: m => save('setsPerPage', m) + }; + appMenu['Score to win'] = { + value: settings.winScore, + min:1, + onchange: m => save('winScore', m) + }; + appMenu['2-point lead'] = { + value: settings['enableTwoAhead'], + format: m => offon[~~m], + onchange: m => save('enableTwoAhead', m) + }; + appMenu['Maximum score?'] = { + value: settings['enableMaxScore'], + format: m => offon[~~m], + onchange: m => save('enableMaxScore', m) + }; + appMenu['Maximum score'] = { + value: settings.maxScore, + min: settings.winScore, + onchange: m => save('maxScore', m) + }; + + E.showMenu(appMenu) + +}) From 2b612de6f6281651ccc611f77eef9d348880492e Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 03:45:48 +0200 Subject: [PATCH 02/50] score: refactor and fix settings --- apps/score/score.settings.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index dde77a225..4843b4a4c 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -15,22 +15,22 @@ require('Storage').writeJSON(fileName, settings); } - if (!settings.winSets) { + if (!settings.winSets == null) { settings.winSets = 1; } - if (!settings.winScore) { + if (!settings.winScore == null) { settings.winScore = 21; } - if (!settings.enableTwoAhead) { + if (!settings.enableTwoAhead == null) { settings.enableTwoAhead = true; } - if (!settings.enableMaxScore) { + if (settings.enableMaxScore == null) { settings.enableMaxScore = true; } - if (!settings.maxScore) { + if (!settings.maxScore == null) { settings.maxScore = 30; } - if (!settings.setsPerPage) { + if (!settings.setsPerPage == null) { settings.setsPerPage = 5; } @@ -61,12 +61,12 @@ onchange: m => save('winScore', m) }; appMenu['2-point lead'] = { - value: settings['enableTwoAhead'], + value: settings.enableTwoAhead, format: m => offon[~~m], onchange: m => save('enableTwoAhead', m) }; appMenu['Maximum score?'] = { - value: settings['enableMaxScore'], + value: settings.enableMaxScore, format: m => offon[~~m], onchange: m => save('enableMaxScore', m) }; From e598c4abf691bdbc052d9464e2419984a21dbe33 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 03:46:03 +0200 Subject: [PATCH 03/50] score: fix maxScore --- apps/score/score.app.js | 6 +++++- apps/score/score.settings.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 7bfadb1ce..dbe9f74ef 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -74,6 +74,10 @@ function showSettingsMenu() { }); } +function maxScore() { + return Math.max(settings.maxScore, settings.winScore); +} + function setsPerPage() { return Math.min(settings.setsPerPage, sets()); } @@ -117,7 +121,7 @@ function setWon(set, player) { let winScoreReached = pScore >= settings.winScore; let isTwoAhead = !settings.enableTwoAhead || pScore - p2Score >= 2; - let reachedMaxScore = settings.enableMaxScore && pScore >= settings.maxScore; + let reachedMaxScore = settings.enableMaxScore && pScore >= maxScore(); return reachedMaxScore || (winScoreReached && isTwoAhead); } diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 4843b4a4c..d1a4332fd 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -72,7 +72,7 @@ }; appMenu['Maximum score'] = { value: settings.maxScore, - min: settings.winScore, + min: 1, onchange: m => save('maxScore', m) }; From 7a68984626ce8eace5e55d9a5be86fa30a3b9872 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 03:40:55 +0200 Subject: [PATCH 04/50] score: fix set/sets display --- apps/score/score.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index dbe9f74ef..7e02f8dfe 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -227,7 +227,7 @@ function draw() { g.drawString(dur1, p === 0 ? w/8 : w/8*5, 10); g.setFont('Teletext5x9Ascii',1); - g.drawString((currentSet()+1) + ' set' + (currentSet() > 1 ? 's' : ''), p === 0 ? w/8*3 : w/8*7, 12); + g.drawString((currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''), p === 0 ? w/8*3 : w/8*7, 12); } From dcd15516f14696c9cff94b09bcf019b7f7a14a32 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 03:41:15 +0200 Subject: [PATCH 05/50] score: add tennis scoring --- apps.json | 2 +- apps/score/score.app.js | 66 ++++++++++++++++++++++++++++++------ apps/score/score.settings.js | 8 +++++ 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/apps.json b/apps.json index 314504276..c98686e72 100644 --- a/apps.json +++ b/apps.json @@ -3559,7 +3559,7 @@ "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, ...)", + "description": "Score Tracker for sports that use plain numbers (e.g. Badminton, Volleyball, Soccer, Table Tennis, ...). Also supports tennis scoring.", "tags": "b2", "type": "app", "storage": [ diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 7e02f8dfe..11d158440 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -6,7 +6,10 @@ require('FontTeletext10x18Ascii').add(Graphics); let settingsMenu = eval(require('Storage').read('score.settings.js')); let settings = settingsMenu(null, true); +let tennisScores = ['00','15','30','40','DC','AD'] + let scores = null; +let tScores = null; let cSet = null; let firstShownSet = null; @@ -49,6 +52,12 @@ function setupMatch() { } scores.push([0,0,null]); + if (settings.enableTennisScoring) { + tScores = [0,0]; + } else { + tScores = null; + } + scores[0][2] = getTime(); cSet = 0; @@ -170,7 +179,22 @@ function score(player) { } else { if (matchEnded()) return; - scores[cSet][player]++; + 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()) { updateCurrentSet(1); @@ -235,9 +259,11 @@ function draw() { g.setFont('7x11Numeric7Seg',2); g.drawString(setsWon(p), p === 0 ? 10 : w-8, h-5); - g.setFontAlign(p === 0 ? 1 : -1,1); - g.setFont('7x11Numeric7Seg',2); - g.drawString(formatNumber(matchScore(p), 3), p === 0 ? w/2 - 8 : w/2 + 11, h-5); + if (!settings.enableTennisScoring) { + g.setFontAlign(p === 0 ? 1 : -1,1); + g.setFont('7x11Numeric7Seg',2); + g.drawString(formatNumber(matchScore(p), 3), p === 0 ? w/2 - 8 : w/2 + 11, h-5); + } } g.setFontAlign(0,0); @@ -268,15 +294,33 @@ function draw() { g.drawString(dur2, 40, y+10); } - g.setFontAlign(0,0); - g.setFont('7x11Numeric7Seg',3); for (let p = 0; p < 2; p++) { if (!setWon(set, p === 0 ? 1 : 0) || matchEnded()) { - g.drawString( - formatNumber(scores[set][p]), - p === 0 ? (w-20)/4+20 : (w-20)/4*3+20, - y - ); + if (settings.enableTennisScoring && set === cSet) { + g.setFontAlign(0,0); + g.setFont('7x11Numeric7Seg',3); + g.drawString( + formatNumber(tennisScores[tScores[p]]), + p === 0 ? (w-20)/4+20 : (w-20)/4*3+2, + y + ); + + g.setFontAlign(p === 0 ? 1 : -1,0); + g.setFont('7x11Numeric7Seg',1); + g.drawString( + formatNumber(scores[set][p]), + p === 0 ? w/2-5 : w/2+6, + y + ); + } else { + g.setFontAlign(0,0); + g.setFont('7x11Numeric7Seg',3); + g.drawString( + formatNumber(scores[set][p]), + p === 0 ? (w-20)/4+20 : (w-20)/4*3+2, + y + ); + } } } } diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index d1a4332fd..7d058f07f 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -33,6 +33,9 @@ if (!settings.setsPerPage == null) { settings.setsPerPage = 5; } + if (!settings.enableTennisScoring == null) { + settings.enableTennisScoring = false; + } if (ret) { return settings; @@ -75,6 +78,11 @@ min: 1, onchange: m => save('maxScore', m) }; + appMenu['Tennis scoring'] = { + value: settings.enableTennisScoring, + format: m => offon[~~m], + onchange: m => save('enableTennisScoring', m) + }; E.showMenu(appMenu) From a6a5f674a090473e1396647ea19e4e2a3f2c29d2 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 03:59:24 +0200 Subject: [PATCH 06/50] score: fix commit 58c7b6c4 --- apps/score/score.settings.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 7d058f07f..ab8b8fb85 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -15,25 +15,25 @@ require('Storage').writeJSON(fileName, settings); } - if (!settings.winSets == null) { + if (settings.winSets == null) { settings.winSets = 1; } - if (!settings.winScore == null) { + if (settings.winScore == null) { settings.winScore = 21; } - if (!settings.enableTwoAhead == null) { + if (settings.enableTwoAhead == null) { settings.enableTwoAhead = true; } if (settings.enableMaxScore == null) { settings.enableMaxScore = true; } - if (!settings.maxScore == null) { + if (settings.maxScore == null) { settings.maxScore = 30; } - if (!settings.setsPerPage == null) { + if (settings.setsPerPage == null) { settings.setsPerPage = 5; } - if (!settings.enableTennisScoring == null) { + if (settings.enableTennisScoring == null) { settings.enableTennisScoring = false; } From a441d423a417538969d8fd6b39c73e0043acddfe Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 04:27:27 +0200 Subject: [PATCH 07/50] score: refactor --- apps/score/score.app.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 11d158440..2052df226 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -6,7 +6,7 @@ require('FontTeletext10x18Ascii').add(Graphics); let settingsMenu = eval(require('Storage').read('score.settings.js')); let settings = settingsMenu(null, true); -let tennisScores = ['00','15','30','40','DC','AD'] +let tennisScores = ['00','15','30','40','DC','AD']; let scores = null; let tScores = null; @@ -42,7 +42,7 @@ function setupInputWatchers() { handleInput(1); } } - }) + }); } function setupMatch() { @@ -159,17 +159,14 @@ function score(player) { let updateCurrentSet = function (val) { cSet += val; firstShownSet = Math.max(0, currentSet() - settings.setsPerPage + 1); - } + }; if (!matchEnded() || correctionMode) { firstShownSet = currentSet() - Math.floor(setsPerPage() / 2); } if (correctionMode) { - if ( - scores[cSet][0] === 0 && scores[cSet][1] === 0 && - cSet > 0 - ) { + if (scores[cSet][0] === 0 && scores[cSet][1] === 0 && cSet > 0) { updateCurrentSet(-1); } From 4c6e9a086049d1250f49cc499df99c2c807b54cd Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 04:34:30 +0200 Subject: [PATCH 08/50] score: tennis scoring: allow corrections --- apps/score/score.app.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 2052df226..636d3a97e 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -171,7 +171,12 @@ function score(player) { } if (scores[cSet][player] > 0) { - scores[cSet][player]--; + if (tScores[player] === 0 && tScores[~~!player] === 0) { + scores[cSet][player]--; + } else { + tScores[player] = 0; + tScores[~~!player] = 0; + } } } else { if (matchEnded()) return; From c45781bc8b536c91718ecb67ef25d94cbaaa90c9 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 04:42:35 +0200 Subject: [PATCH 09/50] score: add README --- apps/score/README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 apps/score/README.md diff --git a/apps/score/README.md b/apps/score/README.md new file mode 100644 index 000000000..cdb34902c --- /dev/null +++ b/apps/score/README.md @@ -0,0 +1,37 @@ +This app will allow you to keep scores for most kinds of sports. + +# Keybinds +*On Bangle.js 2 BTN is equivalent to BTN2 on Bangle.js 1* +| Keybinding | Description | +|-------------------|------------------------------| +| `BTN1` | Scroll up | +| `BTN3` | Scroll down | +| `BTN2` | Menu | +| tap on left side | increment left player score | +| tap on right side | increment right player score | + +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. + +# Settings +| Setting | Description | +|----------------|------------------------------------------------------------------------------------------------------------------------------| +| 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 | + +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. From 97166e0d1a876c8ddbea00b12afcd7cd99b2bde1 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 13:45:23 +0200 Subject: [PATCH 10/50] score: refactor settings --- apps/score/score.settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index ab8b8fb85..b7a2fefad 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -18,6 +18,9 @@ if (settings.winSets == null) { settings.winSets = 1; } + if (settings.setsPerPage == null) { + settings.setsPerPage = 5; + } if (settings.winScore == null) { settings.winScore = 21; } @@ -30,9 +33,6 @@ if (settings.maxScore == null) { settings.maxScore = 30; } - if (settings.setsPerPage == null) { - settings.setsPerPage = 5; - } if (settings.enableTennisScoring == null) { settings.enableTennisScoring = false; } From c0a18add642da63d9afd74b740e06474587f4509 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 13:47:22 +0200 Subject: [PATCH 11/50] score: implement tie-breaks instead of fixed max scores --- apps/score/score.app.js | 86 ++++++++++++++++++++++++++++++------ apps/score/score.settings.js | 39 ++++++++++++++++ 2 files changed, 111 insertions(+), 14 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 636d3a97e..2566d6922 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -48,9 +48,9 @@ function setupInputWatchers() { function setupMatch() { scores = []; for (let s = 0; s < sets(); s++) { - scores.push([0,0,null]); + scores.push([0,0,null,0,0]); } - scores.push([0,0,null]); + scores.push([0,0,null,0,0]); if (settings.enableTennisScoring) { tScores = [0,0]; @@ -87,6 +87,10 @@ 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()); } @@ -99,6 +103,11 @@ 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"); } @@ -124,15 +133,30 @@ function formatDuration(duration) { 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(); - return reachedMaxScore || (winScoreReached && isTwoAhead); + return ( + (settings.enableMaxScoreTiebreak ? tiebreakW : reachedMaxScore) || + (winScoreReached && isTwoAhead) + ); } function setEnded(set) { @@ -166,11 +190,19 @@ function score(player) { } if (correctionMode) { - if (scores[cSet][0] === 0 && scores[cSet][1] === 0 && cSet > 0) { + if ( + scores[cSet][0] === 0 && scores[cSet][1] === 0 && + scores[cSet][3] === 0 && scores[cSet][4] === 0 && + cSet > 0 + ) { updateCurrentSet(-1); } - if (scores[cSet][player] > 0) { + 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 (tScores[player] === 0 && tScores[~~!player] === 0) { scores[cSet][player]--; } else { @@ -181,7 +213,9 @@ function score(player) { } else { if (matchEnded()) return; - if (settings.enableTennisScoring) { + 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 @@ -199,6 +233,9 @@ function score(player) { } if (setEnded(cSet) && cSet < sets()) { + if (shouldTiebreak()) { + scores[cSet][player]++; + } updateCurrentSet(1); scores[cSet][2] = getTime(); } @@ -298,20 +335,23 @@ function draw() { for (let p = 0; p < 2; p++) { if (!setWon(set, p === 0 ? 1 : 0) || matchEnded()) { - if (settings.enableTennisScoring && set === cSet) { + let bigNumX = p === 0 ? (w-20)/4+18 : (w-20)/4*3+4; + let smallNumX = 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]]), - p === 0 ? (w-20)/4+20 : (w-20)/4*3+2, + bigNumX, y ); - - g.setFontAlign(p === 0 ? 1 : -1,0); - g.setFont('7x11Numeric7Seg',1); + } else if (shouldTiebreak() && set === cSet) { + g.setFontAlign(0,0); + g.setFont('7x11Numeric7Seg',3); g.drawString( - formatNumber(scores[set][p]), - p === 0 ? w/2-5 : w/2+6, + formatNumber(scores[set][3+p], 3), + bigNumX, y ); } else { @@ -319,7 +359,25 @@ function draw() { g.setFont('7x11Numeric7Seg',3); g.drawString( formatNumber(scores[set][p]), - p === 0 ? (w-20)/4+20 : (w-20)/4*3+2, + 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 ); } diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index b7a2fefad..c1a0382d2 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -37,6 +37,22 @@ 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; + } + if (ret) { return settings; } @@ -83,6 +99,29 @@ format: m => offon[~~m], onchange: m => save('enableTennisScoring', m) }; + appMenu['TB sets?'] = { + value: settings.enableMaxScoreTiebreak, + format: m => offon[~~m], + onchange: m => save('enableMaxScoreTiebreak', m) + } + appMenu['TB Score to win'] = { + value: settings.maxScoreTiebreakWinScore, + onchange: m => save('maxScoreTiebreakWinScore', m) + } + appMenu['TB 2-point lead'] = { + value: settings.maxScoreTiebreakEnableTwoAhead, + format: m => offon[~~m], + onchange: m => save('maxScoreTiebreakEnableTwoAhead', m) + } + appMenu['TB max score?'] = { + value: settings.maxScoreTiebreakEnableMaxScore, + format: m => offon[~~m], + onchange: m => save('maxScoreTiebreakEnableMaxScore', m) + } + appMenu['TB max score'] = { + value: settings.maxScoreTiebreakMaxScore, + onchange: m => save('maxScoreTiebreakMaxScore', m) + } E.showMenu(appMenu) From de2e897119b4644fd2744ca35ff4644a79e0e391 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 13:47:49 +0200 Subject: [PATCH 12/50] score: always disable correction mode on new match --- apps/score/score.app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 2566d6922..053a8df43 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -62,6 +62,8 @@ function setupMatch() { cSet = 0; firstShownSet = 0 - Math.floor(setsPerPage() / 2); + + correctionMode = false; } function showSettingsMenu() { From 64930265d7cf00a032894e239c65890a007f2948 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 13:48:12 +0200 Subject: [PATCH 13/50] score: fix automatic scrolling on score --- apps/score/score.app.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 053a8df43..9f22927af 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -182,13 +182,16 @@ function matchScore(player) { } function score(player) { + let setFirstShownSet = function () { + firstShownSet = currentSet() - Math.floor(setsPerPage() / 2); + }; let updateCurrentSet = function (val) { cSet += val; - firstShownSet = Math.max(0, currentSet() - settings.setsPerPage + 1); + setFirstShownSet(); }; if (!matchEnded() || correctionMode) { - firstShownSet = currentSet() - Math.floor(setsPerPage() / 2); + setFirstShownSet(); } if (correctionMode) { From 1983c37a819005179be5cc9b0cd410d272271973 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 13:53:24 +0200 Subject: [PATCH 14/50] score: document tiebreaks --- apps/score/README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/score/README.md b/apps/score/README.md index cdb34902c..ffd35e065 100644 --- a/apps/score/README.md +++ b/apps/score/README.md @@ -14,15 +14,17 @@ To correct a falsely awarded point simply open and close the menu within .5 seco 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. # Settings -| Setting | Description | -|----------------|------------------------------------------------------------------------------------------------------------------------------| -| 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 | +| Setting | Description | +|------------------------------------|------------------------------------------------------------------------------------------------------------------------------| +| `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. From 506918e77239cd67a7a78865670d82cc310473a3 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Mon, 27 Sep 2021 23:04:22 +0200 Subject: [PATCH 15/50] score: fix code style (indent by 2 spaces) --- apps/score/score.app.js | 554 +++++++++++++++++------------------ apps/score/score.settings.js | 232 +++++++-------- 2 files changed, 393 insertions(+), 393 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 9f22927af..7f0b04a59 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -21,93 +21,93 @@ let w = g.getWidth(); let h = g.getHeight(); function setupInputWatchers() { - if (global.BTN4) { - setWatch(() => handleInput(2), BTN2, { repeat: true }); - setWatch(() => handleInput(3), BTN1, { repeat: true }); - setWatch(() => handleInput(4), BTN3, { repeat: true }); + if (global.BTN4) { + setWatch(() => handleInput(2), BTN2, { repeat: true }); + setWatch(() => handleInput(3), BTN1, { repeat: true }); + setWatch(() => handleInput(4), BTN3, { repeat: true }); + } else { + setWatch(() => handleInput(2), BTN, { repeat: true }); + } + Bangle.on('touch', (b, e) => { + if (b) { + if (b === 1) { + handleInput(0); + } else { + handleInput(1); + } } else { - setWatch(() => handleInput(2), BTN, { repeat: true }); + if (e.x < w/2) { + handleInput(0); + } else { + handleInput(1); + } } - Bangle.on('touch', (b, e) => { - if (b) { - if (b === 1) { - handleInput(0); - } else { - handleInput(1); - } - } else { - if (e.x < 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 = []; + 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; - } + if (settings.enableTennisScoring) { + tScores = [0,0]; + } else { + tScores = null; + } - scores[0][2] = getTime(); + scores[0][2] = getTime(); - cSet = 0; - firstShownSet = 0 - Math.floor(setsPerPage() / 2); + cSet = 0; + firstShownSet = 0 - Math.floor(setsPerPage() / 2); - correctionMode = false; + correctionMode = false; } function showSettingsMenu() { - settingsMenuOpened = getTime(); - settingsMenu(function (s, reset) { - E.showMenu(); + settingsMenuOpened = getTime(); + settingsMenu(function (s, reset) { + E.showMenu(); - settings = s; + settings = s; - if (reset) { - setupMatch(); - } else if (getTime() - settingsMenuOpened < 0.5 || correctionMode) { - correctionMode = !correctionMode; - } + if (reset) { + setupMatch(); + } else if (getTime() - settingsMenuOpened < 0.5 || correctionMode) { + correctionMode = !correctionMode; + } - settingsMenuOpened = null; + settingsMenuOpened = null; - draw(); - }); + draw(); + }); } function maxScore() { - return Math.max(settings.maxScore, settings.winScore); + return Math.max(settings.maxScore, settings.winScore); } function tiebreakMaxScore() { - return Math.max(settings.maxScoreTiebreakMaxScore, settings.maxScoreTiebreakWinScore); + return Math.max(settings.maxScoreTiebreakMaxScore, settings.maxScoreTiebreakWinScore); } function setsPerPage() { - return Math.min(settings.setsPerPage, sets()); + return Math.min(settings.setsPerPage, sets()); } function sets() { - return settings.winSets * 2 - 1; + return settings.winSets * 2 - 1; } function currentSet() { - return matchEnded() ? cSet - 1 : cSet; + return matchEnded() ? cSet - 1 : cSet; } function shouldTiebreak() { - return settings.enableMaxScoreTiebreak && - scores[cSet][0] + scores[cSet][1] === (maxScore() - 1) * 2; + return settings.enableMaxScoreTiebreak && + scores[cSet][0] + scores[cSet][1] === (maxScore() - 1) * 2; } function formatNumber(num, length) { @@ -115,285 +115,285 @@ function formatNumber(num, length) { } function formatDuration(duration) { - let durS = Math.floor(duration); - let durM = Math.floor(durS / 60); - let durH = Math.floor(durM / 60); - durS = durS - durM * 60; - durM = durM - durH * 60; + let durS = Math.floor(duration); + 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); + durS = formatNumber(durS); + durM = formatNumber(durM); + durH = formatNumber(durH); - let dur = null; - if (durH > 0) { - dur = durH + ':' + durM; - } else { - dur = durM + ':' + durS; - } + let dur = null; + if (durH > 0) { + dur = durH + ':' + durM; + } else { + dur = durM + ':' + durS; + } - return dur; + return dur; } function tiebreakWon(set, player) { - let pScore = scores[set][3+player]; - let p2Score = scores[set][3+~~!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(); + let winScoreReached = pScore >= settings.maxScoreTiebreakWinScore; + let isTwoAhead = !settings.maxScoreTiebreakEnableTwoAhead || pScore - p2Score >= 2; + let reachedMaxScore = settings.maxScoreTiebreakEnableMaxScore && pScore >= tiebreakMaxScore(); - return reachedMaxScore || (winScoreReached && isTwoAhead); + return reachedMaxScore || (winScoreReached && isTwoAhead); } function setWon(set, player) { - let pScore = scores[set][player]; - let p2Score = scores[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 winScoreReached = pScore >= settings.winScore; + let isTwoAhead = !settings.enableTwoAhead || pScore - p2Score >= 2; + let tiebreakW = tiebreakWon(set, player); + let reachedMaxScore = settings.enableMaxScore && pScore >= maxScore(); - return ( - (settings.enableMaxScoreTiebreak ? tiebreakW : reachedMaxScore) || - (winScoreReached && isTwoAhead) - ); + return ( + (settings.enableMaxScoreTiebreak ? tiebreakW : reachedMaxScore) || + (winScoreReached && isTwoAhead) + ); } function setEnded(set) { - return setWon(set, 0) || setWon(set, 1); + 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); + return Array(sets()).fill(0).map((_, s) => ~~setWon(s, player)).reduce((a,v) => a+v, 0); } function matchWon(player) { - return setsWon(player) >= settings.winSets; + return setsWon(player) >= settings.winSets; } function matchEnded() { - return matchWon(0) || matchWon(1); + return matchWon(0) || matchWon(1); } function matchScore(player) { - return scores.reduce((acc, val) => acc += val[player], 0); + return scores.reduce((acc, val) => acc += val[player], 0); } function score(player) { - let setFirstShownSet = function () { - firstShownSet = currentSet() - Math.floor(setsPerPage() / 2); - }; - let updateCurrentSet = function (val) { - cSet += val; - setFirstShownSet(); - }; + let setFirstShownSet = function () { + firstShownSet = currentSet() - Math.floor(setsPerPage() / 2); + }; + let updateCurrentSet = function (val) { + cSet += val; + setFirstShownSet(); + }; - if (!matchEnded() || correctionMode) { - setFirstShownSet(); + if (!matchEnded() || correctionMode) { + 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 (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 (tScores[player] === 0 && tScores[~~!player] === 0) { + scores[cSet][player]--; + } else { + tScores[player] = 0; + tScores[~~!player] = 0; + } + } + } else { + if (matchEnded()) return; - 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 (tScores[player] === 0 && tScores[~~!player] === 0) { - scores[cSet][player]--; - } else { - tScores[player] = 0; - tScores[~~!player] = 0; - } - } + 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 { - 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); - scores[cSet][2] = getTime(); - } - - if (matchEnded()) { - firstShownSet = 0; - } + scores[cSet][player]++; } + + if (setEnded(cSet) && cSet < sets()) { + if (shouldTiebreak()) { + scores[cSet][player]++; + } + updateCurrentSet(1); + scores[cSet][2] = getTime(); + } + + if (matchEnded()) { + firstShownSet = 0; + } + } } function handleInput(button) { - if (settingsMenuOpened) { + if (settingsMenuOpened) { + return; + } + + switch (button) { + case 0: + case 1: + score(button); + break; + case 2: + showSettingsMenu(); return; - } + case 3: + case 4: + let hLimit = currentSet(); + let lLimit = 1 - setsPerPage(); + let val = (button * 2 - 7); + firstShownSet += val; + if (firstShownSet > hLimit) firstShownSet = hLimit; + if (firstShownSet < lLimit) firstShownSet = lLimit; + break; + } - switch (button) { - case 0: - case 1: - score(button); - break; - case 2: - showSettingsMenu(); - return; - case 3: - case 4: - let hLimit = currentSet(); - let lLimit = 1 - setsPerPage(); - let val = (button * 2 - 7); - firstShownSet += val; - if (firstShownSet > hLimit) firstShownSet = hLimit; - if (firstShownSet < lLimit) firstShownSet = lLimit; - break; - } - - draw(); + draw(); } function draw() { - g.setFontAlign(0,0); - g.clear(); + g.setFontAlign(0,0); + g.clear(); + + for (let p = 0; p < 2; p++) { + if (matchWon(p)) { + g.setFontAlign(0,0); + g.setFont('Teletext10x18Ascii',1); + g.drawString("WINNER", p === 0 ? w/4 : w/4*3, 15); + } else if (matchEnded()) { + g.setFontAlign(0,-1); + + let dur1 = formatDuration(scores[cSet][2] - scores[0][2]); + g.setFont('5x9Numeric7Seg',1); + g.drawString(dur1, p === 0 ? w/8 : w/8*5, 10); + + g.setFont('Teletext5x9Ascii',1); + g.drawString((currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''), p === 0 ? w/8*3 : w/8*7, 12); + + } + + g.setFontAlign(p === 0 ? -1 : 1,1); + g.setFont('7x11Numeric7Seg',2); + g.drawString(setsWon(p), p === 0 ? 10 : w-8, h-5); + + if (!settings.enableTennisScoring) { + g.setFontAlign(p === 0 ? 1 : -1,1); + g.setFont('7x11Numeric7Seg',2); + g.drawString(formatNumber(matchScore(p), 3), p === 0 ? w/2 - 8 : w/2 + 11, h-5); + } + } + g.setFontAlign(0,0); + + if (correctionMode) { + g.setFont('Teletext10x18Ascii',1); + g.drawString("R", 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, 40, y-10); + if (scores[set+1][2] != null) { + let dur2 = formatDuration(scores[set+1][2] - scores[set][2]); + g.drawString(dur2, 40, y+10); + } for (let p = 0; p < 2; p++) { - if (matchWon(p)) { - g.setFontAlign(0,0); - g.setFont('Teletext10x18Ascii',1); - g.drawString("WINNER", p === 0 ? w/4 : w/4*3, 15); - } else if (matchEnded()) { - g.setFontAlign(0,-1); - - let dur1 = formatDuration(scores[cSet][2] - scores[0][2]); - g.setFont('5x9Numeric7Seg',1); - g.drawString(dur1, p === 0 ? w/8 : w/8*5, 10); - - g.setFont('Teletext5x9Ascii',1); - g.drawString((currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''), p === 0 ? w/8*3 : w/8*7, 12); + if (!setWon(set, p === 0 ? 1 : 0) || matchEnded()) { + let bigNumX = p === 0 ? (w-20)/4+18 : (w-20)/4*3+4; + let smallNumX = 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 + ); } - g.setFontAlign(p === 0 ? -1 : 1,1); - g.setFont('7x11Numeric7Seg',2); - g.drawString(setsWon(p), p === 0 ? 10 : w-8, h-5); - - if (!settings.enableTennisScoring) { - g.setFontAlign(p === 0 ? 1 : -1,1); - g.setFont('7x11Numeric7Seg',2); - g.drawString(formatNumber(matchScore(p), 3), p === 0 ? w/2 - 8 : w/2 + 11, h-5); + 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 + ); } + } } - g.setFontAlign(0,0); + } - if (correctionMode) { - g.setFont('Teletext10x18Ascii',1); - g.drawString("R", w/2, h-10); - } + // draw separator + g.drawLine(w/2,20,w/2,h-25); - 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, 40, y-10); - if (scores[set+1][2] != null) { - let dur2 = formatDuration(scores[set+1][2] - scores[set][2]); - g.drawString(dur2, 40, y+10); - } - - for (let p = 0; p < 2; p++) { - if (!setWon(set, p === 0 ? 1 : 0) || matchEnded()) { - let bigNumX = p === 0 ? (w-20)/4+18 : (w-20)/4*3+4; - let smallNumX = 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(w/2,20,w/2,h-25); - - g.flip(); + g.flip(); } setupInputWatchers(); diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index c1a0382d2..901867d7b 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -1,128 +1,128 @@ (function (back, ret) { - const fileName = 'score.json' - let settings = require('Storage').readJSON(fileName, 1) || {}; - const offon = ['No', 'Yes']; + const fileName = 'score.json' + let settings = require('Storage').readJSON(fileName, 1) || {}; + const offon = ['No', 'Yes']; - let changed = false; + let changed = false; - function save(key, value) { - changed = true; - settings[key] = value; - if (key === 'winScore' && settings.maxScore < value) { - settings.maxScore = value; - } - require('Storage').writeJSON(fileName, settings); + function save(key, value) { + changed = true; + settings[key] = value; + if (key === 'winScore' && settings.maxScore < value) { + settings.maxScore = value; } + require('Storage').writeJSON(fileName, settings); + } - if (settings.winSets == null) { - settings.winSets = 1; - } - 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.winSets == null) { + settings.winSets = 1; + } + 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; - } + 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; + } - if (ret) { - return settings; - } + if (ret) { + return settings; + } - const appMenu = {}; - appMenu[''] = {'title': 'Score Settings'}, - appMenu['< Back'] = function () { back(settings, changed); }; - if (reset) { - appMenu['Reset match'] = function () { back(settings, true); }; - } - appMenu['Sets to win'] = { - value: settings.winSets, - min:1, - onchange: m => save('winSets', m) - }; - appMenu['Sets per page'] = { - value: settings.setsPerPage, - min:1, - max:5, - onchange: m => save('setsPerPage', m) - }; - appMenu['Score to win'] = { - value: settings.winScore, - min:1, - onchange: m => save('winScore', m) - }; - appMenu['2-point lead'] = { - value: settings.enableTwoAhead, - format: m => offon[~~m], - onchange: m => save('enableTwoAhead', m) - }; - appMenu['Maximum score?'] = { - value: settings.enableMaxScore, - format: m => offon[~~m], - onchange: m => save('enableMaxScore', m) - }; - appMenu['Maximum score'] = { - value: settings.maxScore, - min: 1, - onchange: m => save('maxScore', m) - }; - appMenu['Tennis scoring'] = { - value: settings.enableTennisScoring, - format: m => offon[~~m], - onchange: m => save('enableTennisScoring', m) - }; - appMenu['TB sets?'] = { - value: settings.enableMaxScoreTiebreak, - format: m => offon[~~m], - onchange: m => save('enableMaxScoreTiebreak', m) - } - appMenu['TB Score to win'] = { - value: settings.maxScoreTiebreakWinScore, - onchange: m => save('maxScoreTiebreakWinScore', m) - } - appMenu['TB 2-point lead'] = { - value: settings.maxScoreTiebreakEnableTwoAhead, - format: m => offon[~~m], - onchange: m => save('maxScoreTiebreakEnableTwoAhead', m) - } - appMenu['TB max score?'] = { - value: settings.maxScoreTiebreakEnableMaxScore, - format: m => offon[~~m], - onchange: m => save('maxScoreTiebreakEnableMaxScore', m) - } - appMenu['TB max score'] = { - value: settings.maxScoreTiebreakMaxScore, - onchange: m => save('maxScoreTiebreakMaxScore', m) - } + const appMenu = {}; + appMenu[''] = {'title': 'Score Settings'}, + appMenu['< Back'] = function () { back(settings, changed); }; + if (reset) { + appMenu['Reset match'] = function () { back(settings, true); }; + } + appMenu['Sets to win'] = { + value: settings.winSets, + min:1, + onchange: m => save('winSets', m) + }; + appMenu['Sets per page'] = { + value: settings.setsPerPage, + min:1, + max:5, + onchange: m => save('setsPerPage', m) + }; + appMenu['Score to win'] = { + value: settings.winScore, + min:1, + onchange: m => save('winScore', m) + }; + appMenu['2-point lead'] = { + value: settings.enableTwoAhead, + format: m => offon[~~m], + onchange: m => save('enableTwoAhead', m) + }; + appMenu['Maximum score?'] = { + value: settings.enableMaxScore, + format: m => offon[~~m], + onchange: m => save('enableMaxScore', m) + }; + appMenu['Maximum score'] = { + value: settings.maxScore, + min: 1, + onchange: m => save('maxScore', m) + }; + appMenu['Tennis scoring'] = { + value: settings.enableTennisScoring, + format: m => offon[~~m], + onchange: m => save('enableTennisScoring', m) + }; + appMenu['TB sets?'] = { + value: settings.enableMaxScoreTiebreak, + format: m => offon[~~m], + onchange: m => save('enableMaxScoreTiebreak', m) + } + appMenu['TB Score to win'] = { + value: settings.maxScoreTiebreakWinScore, + onchange: m => save('maxScoreTiebreakWinScore', m) + } + appMenu['TB 2-point lead'] = { + value: settings.maxScoreTiebreakEnableTwoAhead, + format: m => offon[~~m], + onchange: m => save('maxScoreTiebreakEnableTwoAhead', m) + } + appMenu['TB max score?'] = { + value: settings.maxScoreTiebreakEnableMaxScore, + format: m => offon[~~m], + onchange: m => save('maxScoreTiebreakEnableMaxScore', m) + } + appMenu['TB max score'] = { + value: settings.maxScoreTiebreakMaxScore, + onchange: m => save('maxScoreTiebreakMaxScore', m) + } - E.showMenu(appMenu) + E.showMenu(appMenu) }) From 9f73450b8318b930cdf6108184ebc9f757393c91 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 01:03:13 +0200 Subject: [PATCH 16/50] score: add configuration preset functionality --- apps.json | 1 + apps/score/README.md | 1 + apps/score/score.presets.json | 1 + apps/score/score.settings.js | 208 ++++++++++++++++++++-------------- 4 files changed, 127 insertions(+), 84 deletions(-) create mode 100644 apps/score/score.presets.json diff --git a/apps.json b/apps.json index c98686e72..b1e6f70fc 100644 --- a/apps.json +++ b/apps.json @@ -3565,6 +3565,7 @@ "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} ] } diff --git a/apps/score/README.md b/apps/score/README.md index ffd35e065..c3ad0e622 100644 --- a/apps/score/README.md +++ b/apps/score/README.md @@ -16,6 +16,7 @@ In this mode any score increments will be decrements. To move back a set, reduce # 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 | diff --git a/apps/score/score.presets.json b/apps/score/score.presets.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/apps/score/score.presets.json @@ -0,0 +1 @@ +{} diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 901867d7b..cbae83f0c 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -1,20 +1,4 @@ -(function (back, ret) { - - const fileName = 'score.json' - let settings = require('Storage').readJSON(fileName, 1) || {}; - const offon = ['No', 'Yes']; - - let changed = false; - - function save(key, value) { - changed = true; - settings[key] = value; - if (key === 'winScore' && settings.maxScore < value) { - settings.maxScore = value; - } - require('Storage').writeJSON(fileName, settings); - } - +function fillSettingsWithDefaults(settings) { if (settings.winSets == null) { settings.winSets = 1; } @@ -53,76 +37,132 @@ settings.maxScoreTiebreakMaxScore = 15; } + return settings; +} + +(function (back, ret) { + + 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) { + changed = true; + settings[key] = value; + if (key === 'winScore' && settings.maxScore < value) { + settings.maxScore = value; + } + save(settings); + } + + settings = fillSettingsWithDefaults(settings); + if (ret) { return settings; } - const appMenu = {}; - appMenu[''] = {'title': 'Score Settings'}, - appMenu['< Back'] = function () { back(settings, changed); }; - if (reset) { - appMenu['Reset match'] = function () { back(settings, true); }; - } - appMenu['Sets to win'] = { - value: settings.winSets, - min:1, - onchange: m => save('winSets', m) - }; - appMenu['Sets per page'] = { - value: settings.setsPerPage, - min:1, - max:5, - onchange: m => save('setsPerPage', m) - }; - appMenu['Score to win'] = { - value: settings.winScore, - min:1, - onchange: m => save('winScore', m) - }; - appMenu['2-point lead'] = { - value: settings.enableTwoAhead, - format: m => offon[~~m], - onchange: m => save('enableTwoAhead', m) - }; - appMenu['Maximum score?'] = { - value: settings.enableMaxScore, - format: m => offon[~~m], - onchange: m => save('enableMaxScore', m) - }; - appMenu['Maximum score'] = { - value: settings.maxScore, - min: 1, - onchange: m => save('maxScore', m) - }; - appMenu['Tennis scoring'] = { - value: settings.enableTennisScoring, - format: m => offon[~~m], - onchange: m => save('enableTennisScoring', m) - }; - appMenu['TB sets?'] = { - value: settings.enableMaxScoreTiebreak, - format: m => offon[~~m], - onchange: m => save('enableMaxScoreTiebreak', m) - } - appMenu['TB Score to win'] = { - value: settings.maxScoreTiebreakWinScore, - onchange: m => save('maxScoreTiebreakWinScore', m) - } - appMenu['TB 2-point lead'] = { - value: settings.maxScoreTiebreakEnableTwoAhead, - format: m => offon[~~m], - onchange: m => save('maxScoreTiebreakEnableTwoAhead', m) - } - appMenu['TB max score?'] = { - value: settings.maxScoreTiebreakEnableMaxScore, - format: m => offon[~~m], - onchange: m => save('maxScoreTiebreakEnableMaxScore', m) - } - appMenu['TB max score'] = { - value: settings.maxScoreTiebreakMaxScore, - onchange: m => save('maxScoreTiebreakMaxScore', m) - } + const presetMenu = function () { + let ret = function () { E.showMenu(appMenu()); }; + let m = { + '': {'title': 'Score Presets'}, + '< Back': ret, + }; + for (let i = 0; i < presetNames.length; i++) { + m[presetNames[i]] = (function (i) { + return function() { + changed = true; + settings = fillSettingsWithDefaults(presets[presetNames[i]]); + save(settings); + ret(); + }; + })(i); + } - E.showMenu(appMenu) + return m; + }; -}) + const appMenu = function () { + let m = {}; + + m[''] = {'title': 'Score Settings'}; + m['< Back'] = function () { back(settings, changed); }; + if (reset) { + m['Reset match'] = function () { back(settings, true); }; + } + m['Presets'] = function () { E.showMenu(presetMenu()); }; + 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, + 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, + 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; + }; + + E.showMenu(appMenu()); + +}); From a516d409919e0f4052321bc5713b4a6caa67a31c Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 01:04:13 +0200 Subject: [PATCH 17/50] score: add badminton config preset --- apps/score/score.presets.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/score/score.presets.json b/apps/score/score.presets.json index 0967ef424..12b030044 100644 --- a/apps/score/score.presets.json +++ b/apps/score/score.presets.json @@ -1 +1,8 @@ -{} +{ + "Badminton": { + "winScore": 21, + "enableTwoAhead": true, + "enableMaxScore": true, + "maxScore": 30 + } +} From 8567e3d8e156592640d4d6495199e5fcd7716b76 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 01:04:26 +0200 Subject: [PATCH 18/50] score: add tennis config preset --- apps/score/score.presets.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/score/score.presets.json b/apps/score/score.presets.json index 12b030044..fe11c9e6b 100644 --- a/apps/score/score.presets.json +++ b/apps/score/score.presets.json @@ -4,5 +4,16 @@ "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 } } From ad90c410d7a3c4fa959a5cfdca5768c633b566e7 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 01:09:13 +0200 Subject: [PATCH 19/50] score: select winSets entry after selecting preset --- apps/score/score.settings.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index cbae83f0c..8442fd80b 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -72,7 +72,7 @@ function fillSettingsWithDefaults(settings) { } const presetMenu = function () { - let ret = function () { E.showMenu(appMenu()); }; + let ret = function (changed) { E.showMenu(appMenu(changed ? 3 : null)); }; let m = { '': {'title': 'Score Presets'}, '< Back': ret, @@ -83,7 +83,7 @@ function fillSettingsWithDefaults(settings) { changed = true; settings = fillSettingsWithDefaults(presets[presetNames[i]]); save(settings); - ret(); + ret(true); }; })(i); } @@ -91,10 +91,13 @@ function fillSettingsWithDefaults(settings) { return m; }; - const appMenu = function () { + const appMenu = function (selected) { let m = {}; m[''] = {'title': 'Score Settings'}; + if (selected != null) { + m[''].selected = selected; + } m['< Back'] = function () { back(settings, changed); }; if (reset) { m['Reset match'] = function () { back(settings, true); }; From ecc4e59a01fb82edc096040a05eeaa13eee0c43a Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 14:02:15 +0200 Subject: [PATCH 20/50] score: set default winSets to 2 --- apps/score/score.settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 8442fd80b..83a98d93f 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -1,6 +1,6 @@ function fillSettingsWithDefaults(settings) { if (settings.winSets == null) { - settings.winSets = 1; + settings.winSets = 2; } if (settings.setsPerPage == null) { settings.setsPerPage = 5; From 7074340f444c25100434ee3101a30424ba626fba Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 14:03:23 +0200 Subject: [PATCH 21/50] score: add additional in-app menu, allow ending current set --- apps/score/score.app.js | 50 ++++++++++++++++++++++++------------ apps/score/score.settings.js | 33 +++++++++++++++++------- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 7f0b04a59..4b72f911c 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -4,7 +4,7 @@ require('FontTeletext5x9Ascii').add(Graphics); require('FontTeletext10x18Ascii').add(Graphics); let settingsMenu = eval(require('Storage').read('score.settings.js')); -let settings = settingsMenu(null, true); +let settings = settingsMenu(null, null, true); let tennisScores = ['00','15','30','40','DC','AD']; @@ -61,7 +61,7 @@ function setupMatch() { scores[0][2] = getTime(); cSet = 0; - firstShownSet = 0 - Math.floor(setsPerPage() / 2); + setFirstShownSet(); correctionMode = false; } @@ -82,6 +82,12 @@ function showSettingsMenu() { settingsMenuOpened = null; draw(); + }, function (msg) { + switch (msg) { + case 'end_set': + updateCurrentSet(1); + break; + } }); } @@ -154,10 +160,12 @@ function setWon(set, player) { 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) + (winScoreReached && isTwoAhead) || + manuallyEndedWon ); } @@ -181,15 +189,30 @@ function matchScore(player) { return scores.reduce((acc, val) => acc += val[player], 0); } -function score(player) { - let setFirstShownSet = function () { - firstShownSet = currentSet() - Math.floor(setsPerPage() / 2); - }; - let updateCurrentSet = function (val) { - cSet += val; - setFirstShownSet(); - }; +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 (matchEnded()) { + firstShownSet = 0; + } + + if (val > 0) { + scores[cSet][2] = getTime(); + } +} + +function score(player) { if (!matchEnded() || correctionMode) { setFirstShownSet(); } @@ -242,11 +265,6 @@ function score(player) { scores[cSet][player]++; } updateCurrentSet(1); - scores[cSet][2] = getTime(); - } - - if (matchEnded()) { - firstShownSet = 0; } } } diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 83a98d93f..4a4b5e56a 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -40,7 +40,7 @@ function fillSettingsWithDefaults(settings) { return settings; } -(function (back, ret) { +(function (back, inApp, ret) { const fileName = 'score.json'; let settings = require('Storage').readJSON(fileName, 1) || {}; @@ -71,8 +71,8 @@ function fillSettingsWithDefaults(settings) { return settings; } - const presetMenu = function () { - let ret = function (changed) { E.showMenu(appMenu(changed ? 3 : null)); }; + const presetMenu = function (appMenuBack) { + let ret = function (changed) { E.showMenu(appMenu(appMenuBack, changed ? 2 : null)); }; let m = { '': {'title': 'Score Presets'}, '< Back': ret, @@ -91,7 +91,7 @@ function fillSettingsWithDefaults(settings) { return m; }; - const appMenu = function (selected) { + const appMenu = function (back, selected) { let m = {}; m[''] = {'title': 'Score Settings'}; @@ -99,10 +99,7 @@ function fillSettingsWithDefaults(settings) { m[''].selected = selected; } m['< Back'] = function () { back(settings, changed); }; - if (reset) { - m['Reset match'] = function () { back(settings, true); }; - } - m['Presets'] = function () { E.showMenu(presetMenu()); }; + m['Presets'] = function () { E.showMenu(presetMenu(back)); }; m['Sets to win'] = { value: settings.winSets, min:1, @@ -166,6 +163,24 @@ function fillSettingsWithDefaults(settings) { return m; }; - E.showMenu(appMenu()); + 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)); + } }); From e27303a09a0d899675fea361e691de2a781df101 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 14:04:15 +0200 Subject: [PATCH 22/50] score: code style + firstShownSet limits --- apps/score/score.app.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 4b72f911c..4409b86b6 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -275,22 +275,22 @@ function handleInput(button) { } switch (button) { - case 0: - case 1: - score(button); - break; - case 2: - showSettingsMenu(); - return; - case 3: - case 4: - let hLimit = currentSet(); - let lLimit = 1 - setsPerPage(); - let val = (button * 2 - 7); - firstShownSet += val; - if (firstShownSet > hLimit) firstShownSet = hLimit; - if (firstShownSet < lLimit) firstShownSet = lLimit; - break; + 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(); From a504addd8f220ea786053bb613f3bf029d414958 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 14:29:34 +0200 Subject: [PATCH 23/50] score: remove reference to Teletext10x18Ascii font --- apps/score/score.app.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 4409b86b6..c9ed89260 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -1,7 +1,6 @@ require('Font5x9Numeric7Seg').add(Graphics); require('Font7x11Numeric7Seg').add(Graphics); require('FontTeletext5x9Ascii').add(Graphics); -require('FontTeletext10x18Ascii').add(Graphics); let settingsMenu = eval(require('Storage').read('score.settings.js')); let settings = settingsMenu(null, null, true); @@ -303,7 +302,7 @@ function draw() { for (let p = 0; p < 2; p++) { if (matchWon(p)) { g.setFontAlign(0,0); - g.setFont('Teletext10x18Ascii',1); + g.setFont('Teletext5x9Ascii',2); g.drawString("WINNER", p === 0 ? w/4 : w/4*3, 15); } else if (matchEnded()) { g.setFontAlign(0,-1); @@ -318,7 +317,7 @@ function draw() { } g.setFontAlign(p === 0 ? -1 : 1,1); - g.setFont('7x11Numeric7Seg',2); + g.setFont('5x9Numeric7Seg',2); g.drawString(setsWon(p), p === 0 ? 10 : w-8, h-5); if (!settings.enableTennisScoring) { @@ -330,7 +329,7 @@ function draw() { g.setFontAlign(0,0); if (correctionMode) { - g.setFont('Teletext10x18Ascii',1); + g.setFont('Teletext5x9Ascii',2); g.drawString("R", w/2, h-10); } From 978c181435f9afa14b6705e073fd95999109c495 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 14:30:05 +0200 Subject: [PATCH 24/50] score: fix correctionMode without tennis scoring --- apps/score/score.app.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index c9ed89260..eb373ed50 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -230,7 +230,10 @@ function score(player) { scores[cSet][3+player]--; } } else if (scores[cSet][player] > 0) { - if (tScores[player] === 0 && tScores[~~!player] === 0) { + if ( + !settings.enableTennisScoring || + (tScores[player] === 0 && tScores[~~!player] === 0) + ) { scores[cSet][player]--; } else { tScores[player] = 0; From f3398e65501ba3d0bbd52a2f703943ca3fb53ca0 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 14:32:14 +0200 Subject: [PATCH 25/50] score: add preset for soccer --- apps/score/score.presets.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/score/score.presets.json b/apps/score/score.presets.json index fe11c9e6b..3224556a6 100644 --- a/apps/score/score.presets.json +++ b/apps/score/score.presets.json @@ -15,5 +15,11 @@ "maxScoreTiebreakEnableTwoAhead": true, "maxScoreTiebreakEnableMaxScore": false, "enableTennisScoring": true + }, + "Soccer": { + "winSets": 1, + "winScore": 9999, + "enableTwoAhead": false, + "enableMaxScore": false } } From 6155893856c42248e0c3a070f9112aebd802050b Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 14:36:25 +0200 Subject: [PATCH 26/50] score: add preset for table tennis --- apps/score/score.presets.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/score/score.presets.json b/apps/score/score.presets.json index 3224556a6..b57b52157 100644 --- a/apps/score/score.presets.json +++ b/apps/score/score.presets.json @@ -21,5 +21,10 @@ "winScore": 9999, "enableTwoAhead": false, "enableMaxScore": false + }, + "Table Tennis": { + "winScore": 11, + "enableTwoAhead": true, + "enableMaxScore": false } } From f4d820bf607c4ec16c955464364a595c0f457f96 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 15:43:21 +0200 Subject: [PATCH 27/50] score: code style --- apps/score/score.app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index eb373ed50..48f503cb7 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -159,7 +159,7 @@ function setWon(set, player) { 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 + let manuallyEndedWon = cSet > set ? pScore > p2Score : false; return ( (settings.enableMaxScoreTiebreak ? tiebreakW : reachedMaxScore) || @@ -194,9 +194,9 @@ function setFirstShownSet() { function updateCurrentSet(val) { if (val > 0) { - cSet++ + cSet++; } else if (val < 0) { - cSet-- + cSet--; } else { return; } From 7a98c039e705e67db0f10e94c7623cc6769c7b78 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 15:47:19 +0200 Subject: [PATCH 28/50] score: fix settings module --- apps/score/score.settings.js | 83 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 4a4b5e56a..c4e22e45d 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -1,46 +1,45 @@ -function fillSettingsWithDefaults(settings) { - 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; -} - (function (back, inApp, ret) { + function fillSettingsWithDefaults(settings) { + 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) || {}; From ea3cfece674c5af827ca4fb077694fc1098c4daf Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 15:57:56 +0200 Subject: [PATCH 29/50] score: prevent warning in web ide for settings module --- apps/score/score.settings.js | 342 ++++++++++++++++++----------------- 1 file changed, 172 insertions(+), 170 deletions(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index c4e22e45d..da35d7a21 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -1,185 +1,187 @@ -(function (back, inApp, ret) { - function fillSettingsWithDefaults(settings) { - 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; +(function () { + return (function (back, inApp, ret) { + function fillSettingsWithDefaults(settings) { + 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; } - 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; + 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); } - 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) { - 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; - settings = fillSettingsWithDefaults(presets[presetNames[i]]); - save(settings); - ret(true); - }; - })(i); + function setAndSave(key, value) { + changed = true; + settings[key] = value; + if (key === 'winScore' && settings.maxScore < value) { + settings.maxScore = value; + } + save(settings); } - return m; - }; + settings = fillSettingsWithDefaults(settings); - const appMenu = function (back, selected) { - let m = {}; - - m[''] = {'title': 'Score Settings'}; - if (selected != null) { - m[''].selected = selected; + if (ret) { + return settings; } - m['< Back'] = function () { back(settings, changed); }; - m['Presets'] = function () { E.showMenu(presetMenu(back)); }; - 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, - 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, - 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), + + 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; + settings = fillSettingsWithDefaults(presets[presetNames[i]]); + save(settings); + ret(true); + }; + })(i); + } + + return m; }; - return m; - }; + const appMenu = function (back, selected) { + let 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()); - })); }, + m[''] = {'title': 'Score Settings'}; + if (selected != null) { + m[''].selected = selected; + } + m['< Back'] = function () { back(settings, changed); }; + m['Presets'] = function () { E.showMenu(presetMenu(back)); }; + 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, + 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, + 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; }; - 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()); + })); }, + }; - if (inApp != null) { - E.showMenu(inAppMenu()); - } else { - E.showMenu(appMenu(back)); - } + return m; + }; -}); + if (inApp != null) { + E.showMenu(inAppMenu()); + } else { + E.showMenu(appMenu(back)); + } + + }); +})(); From 656d3e65cd54b079e2fb5b47d75f2f5314238d3d Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 16:22:16 +0200 Subject: [PATCH 30/50] score: shift score display right --- apps/score/score.app.js | 46 +++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 48f503cb7..8c4a16a41 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -299,6 +299,10 @@ function handleInput(button) { } function draw() { + let getXCoord = function (func) { + let offset = 40; + return func(w-offset)+offset; + }; g.setFontAlign(0,0); g.clear(); @@ -306,34 +310,58 @@ function draw() { if (matchWon(p)) { g.setFontAlign(0,0); g.setFont('Teletext5x9Ascii',2); - g.drawString("WINNER", p === 0 ? w/4 : w/4*3, 15); + g.drawString( + "WINNER", + getXCoord(w => p === 0 ? w/4 : w/4*3), + 15 + ); } else if (matchEnded()) { g.setFontAlign(0,-1); let dur1 = formatDuration(scores[cSet][2] - scores[0][2]); g.setFont('5x9Numeric7Seg',1); - g.drawString(dur1, p === 0 ? w/8 : w/8*5, 10); + g.drawString( + dur1, + getXCoord(w => p === 0 ? w/8 : w/8*5), + 10 + ); g.setFont('Teletext5x9Ascii',1); - g.drawString((currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''), p === 0 ? w/8*3 : w/8*7, 12); + g.drawString( + (currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''), + getXCoord(w => p === 0 ? w/8*3 : w/8*7), + 12 + ); } g.setFontAlign(p === 0 ? -1 : 1,1); g.setFont('5x9Numeric7Seg',2); - g.drawString(setsWon(p), p === 0 ? 10 : w-8, h-5); + g.drawString( + setsWon(p), + getXCoord(w => p === 0 ? 10 : w-8), + h-5 + ); if (!settings.enableTennisScoring) { g.setFontAlign(p === 0 ? 1 : -1,1); g.setFont('7x11Numeric7Seg',2); - g.drawString(formatNumber(matchScore(p), 3), p === 0 ? w/2 - 8 : w/2 + 11, h-5); + g.drawString( + formatNumber(matchScore(p), 3), + getXCoord(w => p === 0 ? w/2 - 8 : w/2 + 11), + h-5 + ); } } g.setFontAlign(0,0); if (correctionMode) { g.setFont('Teletext5x9Ascii',2); - g.drawString("R", w/2, h-10); + g.drawString( + "R", + getXCoord(w => w/2), + h-10 + ); } let lastShownSet = Math.min( @@ -360,8 +388,8 @@ function draw() { for (let p = 0; p < 2; p++) { if (!setWon(set, p === 0 ? 1 : 0) || matchEnded()) { - let bigNumX = p === 0 ? (w-20)/4+18 : (w-20)/4*3+4; - let smallNumX = p === 0 ? w/2-2 : w/2+3; + let bigNumX = getXCoord(w => p === 0 ? w/4 : w/4*3+3); + let smallNumX = getXCoord(w => p === 0 ? w/2-2 : w/2+3); if (settings.enableTennisScoring && set === cSet && !shouldTiebreak()) { g.setFontAlign(0,0); @@ -411,7 +439,7 @@ function draw() { } // draw separator - g.drawLine(w/2,20,w/2,h-25); + g.drawLine(getXCoord(w => w/2), 20, getXCoord(w => w/2), h-25); g.flip(); } From df13e80b143b613a7d2d8e58edcedb054b28f965 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 16:22:31 +0200 Subject: [PATCH 31/50] score: move match sets and time tothe left --- apps/score/score.app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 8c4a16a41..73e1e8794 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -316,20 +316,20 @@ function draw() { 15 ); } else if (matchEnded()) { - g.setFontAlign(0,-1); + g.setFontAlign(1,0); let dur1 = formatDuration(scores[cSet][2] - scores[0][2]); g.setFont('5x9Numeric7Seg',1); g.drawString( dur1, - getXCoord(w => p === 0 ? w/8 : w/8*5), + 40, 10 ); g.setFont('Teletext5x9Ascii',1); g.drawString( (currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''), - getXCoord(w => p === 0 ? w/8*3 : w/8*7), + 40, 12 ); From 7f5037066925f26088bc45e87265029795a23579 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 16:42:21 +0200 Subject: [PATCH 32/50] score: change b1 control scheme --- apps/score/README.md | 25 ++++++++++++++++--------- apps/score/score.app.js | 19 ++++++++++--------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/apps/score/README.md b/apps/score/README.md index c3ad0e622..1de1ccdb5 100644 --- a/apps/score/README.md +++ b/apps/score/README.md @@ -1,18 +1,25 @@ This app will allow you to keep scores for most kinds of sports. # Keybinds -*On Bangle.js 2 BTN is equivalent to BTN2 on Bangle.js 1* -| Keybinding | Description | -|-------------------|------------------------------| -| `BTN1` | Scroll up | -| `BTN3` | Scroll down | -| `BTN2` | Menu | -| tap on left side | increment left player score | -| tap on right side | increment right player score | - 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 | |------------------------------------|------------------------------------------------------------------------------------------------------------------------------| diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 73e1e8794..072617e6b 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -19,23 +19,28 @@ let correctionMode = false; let w = g.getWidth(); let h = g.getHeight(); +function getXCoord(func) { + let offset = 40; + return func(w-offset)+offset; +}; + function setupInputWatchers() { if (global.BTN4) { setWatch(() => handleInput(2), BTN2, { repeat: true }); - setWatch(() => handleInput(3), BTN1, { repeat: true }); - setWatch(() => handleInput(4), BTN3, { repeat: true }); + setWatch(() => handleInput(0), BTN1, { repeat: true }); + setWatch(() => handleInput(1), BTN3, { repeat: true }); } else { setWatch(() => handleInput(2), BTN, { repeat: true }); } Bangle.on('touch', (b, e) => { if (b) { if (b === 1) { - handleInput(0); + handleInput(3); } else { - handleInput(1); + handleInput(4); } } else { - if (e.x < w/2) { + if (e.x < getXCoord(w => w/2)) { handleInput(0); } else { handleInput(1); @@ -299,10 +304,6 @@ function handleInput(button) { } function draw() { - let getXCoord = function (func) { - let offset = 40; - return func(w-offset)+offset; - }; g.setFontAlign(0,0); g.clear(); From f5b9c5d005e44b756fc4c5dc28e61c0bbed393eb Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 16:44:33 +0200 Subject: [PATCH 33/50] score: fix scrolling in correction mode --- apps/score/score.app.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 072617e6b..357cd965b 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -186,7 +186,7 @@ function matchWon(player) { } function matchEnded() { - return matchWon(0) || matchWon(1); + return (matchWon(0) || matchWon(1)) && cSet > (setsWon(0) + setsWon(1) - 1); } function matchScore(player) { @@ -207,17 +207,17 @@ function updateCurrentSet(val) { } setFirstShownSet(); - if (matchEnded()) { - firstShownSet = 0; - } - if (val > 0) { scores[cSet][2] = getTime(); + + if (matchEnded()) { + firstShownSet = 0; + } } } function score(player) { - if (!matchEnded() || correctionMode) { + if (!matchEnded()) { setFirstShownSet(); } From a749a382716664ebba33695e8337d6182d7c39c0 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 16:44:49 +0200 Subject: [PATCH 34/50] score: fix/reorder draw function --- apps/score/score.app.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 357cd965b..1ec15adb2 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -319,21 +319,20 @@ function draw() { } 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, - 10 + 18 ); - - g.setFont('Teletext5x9Ascii',1); - g.drawString( - (currentSet()+1) + ' set' + (currentSet() > 0 ? 's' : ''), - 40, - 12 - ); - } g.setFontAlign(p === 0 ? -1 : 1,1); From 46fc78772b7bba41314f4feba4f3bbca0d76e06d Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 16:47:23 +0200 Subject: [PATCH 35/50] score: remove unnecessary semicolon --- apps/score/score.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 1ec15adb2..2f07c7de5 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -22,7 +22,7 @@ let h = g.getHeight(); function getXCoord(func) { let offset = 40; return func(w-offset)+offset; -}; +} function setupInputWatchers() { if (global.BTN4) { From fb3f55be7cd6af03638c3869b485de7cce5f7e1c Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 21:07:00 +0200 Subject: [PATCH 36/50] score: prevent floating point numbers from getTime() --- apps/score/score.app.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 2f07c7de5..0c5d66169 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -24,6 +24,10 @@ function getXCoord(func) { return func(w-offset)+offset; } +function getSecondsTime() { + return Math.floor(getTime() * 1000); +} + function setupInputWatchers() { if (global.BTN4) { setWatch(() => handleInput(2), BTN2, { repeat: true }); @@ -62,7 +66,7 @@ function setupMatch() { tScores = null; } - scores[0][2] = getTime(); + scores[0][2] = getSecondsTime(); cSet = 0; setFirstShownSet(); @@ -71,7 +75,8 @@ function setupMatch() { } function showSettingsMenu() { - settingsMenuOpened = getTime(); + settingsMenuOpened = getSecondsTime(); + l = null; settingsMenu(function (s, reset) { E.showMenu(); @@ -79,7 +84,7 @@ function showSettingsMenu() { if (reset) { setupMatch(); - } else if (getTime() - settingsMenuOpened < 0.5 || correctionMode) { + } else if (getSecondsTime() - settingsMenuOpened < 500 || correctionMode) { correctionMode = !correctionMode; } @@ -125,7 +130,7 @@ function formatNumber(num, length) { } function formatDuration(duration) { - let durS = Math.floor(duration); + let durS = Math.floor(duration / 1000); let durM = Math.floor(durS / 60); let durH = Math.floor(durM / 60); durS = durS - durM * 60; @@ -208,7 +213,7 @@ function updateCurrentSet(val) { setFirstShownSet(); if (val > 0) { - scores[cSet][2] = getTime(); + scores[cSet][2] = getSecondsTime(); if (matchEnded()) { firstShownSet = 0; From eb384cef31027b03d009cecfa761188e52ccfe8b Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 21:56:18 +0200 Subject: [PATCH 37/50] score: fix layout for 176x176 resolution --- apps/score/score.app.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 0c5d66169..8e1535f86 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -344,7 +344,7 @@ function draw() { g.setFont('5x9Numeric7Seg',2); g.drawString( setsWon(p), - getXCoord(w => p === 0 ? 10 : w-8), + getXCoord(w => p === 0 ? 5 : w-3), h-5 ); @@ -353,7 +353,7 @@ function draw() { g.setFont('7x11Numeric7Seg',2); g.drawString( formatNumber(matchScore(p), 3), - getXCoord(w => p === 0 ? w/2 - 8 : w/2 + 11), + getXCoord(w => p === 0 ? w/2 - 3 : w/2 + 6), h-5 ); } @@ -383,17 +383,17 @@ function draw() { let y = (h-15)/(setsOnCurrentPage+1)*(set-firstShownSet+1)+5; - g.setFontAlign(1,0); + g.setFontAlign(-1,0); g.setFont('7x11Numeric7Seg',1); - g.drawString(set+1, 40, y-10); + 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, 40, y+10); + 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 : w/4*3+3); + 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()) { From dca65f0490e25747e57f10c08afc6d8dfa293751 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Tue, 28 Sep 2021 21:56:33 +0200 Subject: [PATCH 38/50] score: set score limit of 999 --- apps/score/score.settings.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index da35d7a21..d63c52a9b 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -114,6 +114,7 @@ m['Score to win'] = { value: settings.winScore, min:1, + max: 999, onchange: m => setAndSave('winScore', m), }; m['2-point lead'] = { @@ -129,6 +130,7 @@ m['Maximum score'] = { value: settings.maxScore, min: 1, + max: 999, onchange: m => setAndSave('maxScore', m), }; m['Tennis scoring'] = { From a15622f00a89e434f085e4920642dbe4243563a0 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Fri, 1 Oct 2021 22:17:51 +0200 Subject: [PATCH 39/50] score: add readme to apps.json --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index b1e6f70fc..f0690f0d3 100644 --- a/apps.json +++ b/apps.json @@ -3560,6 +3560,7 @@ "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": [ From e7d0903e82939d257b2a73b275b8a3e1fba1fa95 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Fri, 1 Oct 2021 22:18:07 +0200 Subject: [PATCH 40/50] score: add data "scores.json" to apps.json --- apps.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps.json b/apps.json index f0690f0d3..611edb53a 100644 --- a/apps.json +++ b/apps.json @@ -3568,6 +3568,9 @@ {"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"} ] } ] From fbe14a79d1aa096ba3c2bb891a918f5ffc896885 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 3 Oct 2021 15:39:07 +0200 Subject: [PATCH 41/50] score: fix scrolling on b2, change b2 detection --- apps/score/score.app.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 8e1535f86..24e49fa66 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -29,15 +29,11 @@ function getSecondsTime() { } function setupInputWatchers() { - if (global.BTN4) { - setWatch(() => handleInput(2), BTN2, { repeat: true }); - setWatch(() => handleInput(0), BTN1, { repeat: true }); - setWatch(() => handleInput(1), BTN3, { repeat: true }); - } else { - setWatch(() => handleInput(2), BTN, { repeat: true }); - } + isBangle1 = !!global.BTN4; + setWatch(() => handleInput(2), isBangle1 != null ? BTN2 : BTN, { repeat: true }); + Bangle.setUI('updown', v => v && handleInput(Math.floor((v+2)/2)+(isBangle1 ? 0 : 3))); Bangle.on('touch', (b, e) => { - if (b) { + if (isBangle1) { if (b === 1) { handleInput(3); } else { From 01d33cbbfa0864b793c2022296607aae0330d3d9 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sat, 9 Oct 2021 20:01:48 +0200 Subject: [PATCH 42/50] score: call setUI after menu --- apps/score/score.app.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 24e49fa66..b48995849 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -28,25 +28,27 @@ function getSecondsTime() { return Math.floor(getTime() * 1000); } -function setupInputWatchers() { +function setupInputWatchers(init) { isBangle1 = !!global.BTN4; - setWatch(() => handleInput(2), isBangle1 != null ? BTN2 : BTN, { repeat: true }); Bangle.setUI('updown', v => v && handleInput(Math.floor((v+2)/2)+(isBangle1 ? 0 : 3))); - Bangle.on('touch', (b, e) => { - if (isBangle1) { - if (b === 1) { - handleInput(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 { - handleInput(4); + if (e.x < getXCoord(w => w/2)) { + handleInput(0); + } else { + handleInput(1); + } } - } else { - if (e.x < getXCoord(w => w/2)) { - handleInput(0); - } else { - handleInput(1); - } - } - }); + }); + } } function setupMatch() { @@ -87,6 +89,8 @@ function showSettingsMenu() { settingsMenuOpened = null; draw(); + + setupInputWatchers(); }, function (msg) { switch (msg) { case 'end_set': @@ -445,6 +449,6 @@ function draw() { g.flip(); } -setupInputWatchers(); +setupInputWatchers(true); setupMatch(); draw(); From 88f17232bc6d99def85f20f1ed83ee1a546a4cac Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 17:16:09 +0200 Subject: [PATCH 43/50] score: update b1 detection to use process.env --- apps/score/score.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index b48995849..7da068294 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -29,7 +29,7 @@ function getSecondsTime() { } function setupInputWatchers(init) { - isBangle1 = !!global.BTN4; + isBangle1 = process.env.BOARD === 'BANGLEJS'; Bangle.setUI('updown', v => v && handleInput(Math.floor((v+2)/2)+(isBangle1 ? 0 : 3))); if (init) { setWatch(() => handleInput(2), isBangle1 != null ? BTN2 : BTN, { repeat: true }); From 23ec132b4d7a7f4574a8bcc8c0e079612d27e8ea Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 17:19:03 +0200 Subject: [PATCH 44/50] score: switch score buttons --- apps/score/score.app.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 7da068294..0c2d8c78d 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -30,7 +30,15 @@ function getSecondsTime() { function setupInputWatchers(init) { isBangle1 = process.env.BOARD === 'BANGLEJS'; - Bangle.setUI('updown', v => v && handleInput(Math.floor((v+2)/2)+(isBangle1 ? 0 : 3))); + Bangle.setUI('updown', v => { + if (v) { + if (isBangle1) { + handleInput(Math.floor(((v*-1)+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) => { From f6f1a1c352b4f43037280e6bcd198ebe86b405f7 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 17:26:35 +0200 Subject: [PATCH 45/50] score: allow user to mirror score buttons on b1 --- apps/score/score.app.js | 5 +++-- apps/score/score.settings.js | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 0c2d8c78d..4f1fd7b7b 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -33,9 +33,10 @@ function setupInputWatchers(init) { Bangle.setUI('updown', v => { if (v) { if (isBangle1) { - handleInput(Math.floor(((v*-1)+2)/2)) + let i = settings.mirrorScoreButtons ? v * -1 : v; + handleInput(Math.floor((i+2)/2)); } else { - handleInput(Math.floor((v+2)/2)+3) + handleInput(Math.floor((v+2)/2)+3); } } }); diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index d63c52a9b..3fc04839b 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -1,6 +1,13 @@ (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.winSets == null) { settings.winSets = 2; } @@ -100,6 +107,13 @@ } 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), + }; + } m['Sets to win'] = { value: settings.winSets, min:1, From f5fefc7c993946a66ca7b62cf0f982d030ff05b8 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 17:27:50 +0200 Subject: [PATCH 46/50] score: keep display powered on --- apps/score/score.app.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 4f1fd7b7b..87fdecf0c 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -19,6 +19,8 @@ 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; @@ -29,7 +31,6 @@ function getSecondsTime() { } function setupInputWatchers(init) { - isBangle1 = process.env.BOARD === 'BANGLEJS'; Bangle.setUI('updown', v => { if (v) { if (isBangle1) { @@ -458,6 +459,12 @@ function draw() { g.flip(); } +// make sure LCD on Bangle.js 1 stays on +if (isBangle1) { + Bangle.setLCDTimeout(0); + Bangle.setLCDPower(true); +} + setupInputWatchers(true); setupMatch(); draw(); From a575f323d85fd00ac637bb68e9733e2446ef10c1 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 17:41:54 +0200 Subject: [PATCH 47/50] score: don't reset match when changing button assignment --- apps/score/score.settings.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 3fc04839b..20482db65 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -63,8 +63,10 @@ require('Storage').writeJSON(fileName, settings); } - function setAndSave(key, value) { - changed = true; + function setAndSave(key, value, notChanged) { + if (!notChanged) { + changed = true; + } settings[key] = value; if (key === 'winScore' && settings.maxScore < value) { settings.maxScore = value; @@ -111,7 +113,7 @@ m['Mirror Buttons'] = { value: settings.mirrorScoreButtons, format: m => offon[~~m], - onchange: m => setAndSave('mirrorScoreButtons', m), + onchange: m => setAndSave('mirrorScoreButtons', m, true), }; } m['Sets to win'] = { From 729f5baf16350329fb4f49d2d5ec754aacb8fac7 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 17:42:21 +0200 Subject: [PATCH 48/50] score: keep specific settings when selecting new preset --- apps/score/score.settings.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 20482db65..982652b94 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -90,7 +90,11 @@ m[presetNames[i]] = (function (i) { return function() { changed = true; + let mirrorScoreButtons = settings.mirrorScoreButtons; + settings = fillSettingsWithDefaults(presets[presetNames[i]]); + + settings.mirrorScoreButtons = mirrorScoreButtons; save(settings); ret(true); }; From ed9566dbb3486e8d2d82cdbb5b18bc49d3ffa814 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 17:44:03 +0200 Subject: [PATCH 49/50] score: change default score button assignment --- apps/score/score.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index 87fdecf0c..d3bc5d1e1 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -34,7 +34,7 @@ function setupInputWatchers(init) { Bangle.setUI('updown', v => { if (v) { if (isBangle1) { - let i = settings.mirrorScoreButtons ? v * -1 : v; + let i = settings.mirrorScoreButtons ? v : v * -1; handleInput(Math.floor((i+2)/2)); } else { handleInput(Math.floor((v+2)/2)+3); From 52bdf22352b8d8752b62189b7daffda90a68d033 Mon Sep 17 00:00:00 2001 From: Mika Dede Date: Sun, 10 Oct 2021 20:39:53 +0200 Subject: [PATCH 50/50] score: allow user to choose if screen of b1 should stay on --- apps/score/score.app.js | 20 ++++++++++++++------ apps/score/score.settings.js | 10 ++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/apps/score/score.app.js b/apps/score/score.app.js index d3bc5d1e1..3a9b71505 100644 --- a/apps/score/score.app.js +++ b/apps/score/score.app.js @@ -30,6 +30,18 @@ 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) { @@ -100,6 +112,7 @@ function showSettingsMenu() { draw(); + setupDisplay(); setupInputWatchers(); }, function (msg) { switch (msg) { @@ -459,12 +472,7 @@ function draw() { g.flip(); } -// make sure LCD on Bangle.js 1 stays on -if (isBangle1) { - Bangle.setLCDTimeout(0); - Bangle.setLCDPower(true); -} - +setupDisplay(); setupInputWatchers(true); setupMatch(); draw(); diff --git a/apps/score/score.settings.js b/apps/score/score.settings.js index 982652b94..88e367821 100644 --- a/apps/score/score.settings.js +++ b/apps/score/score.settings.js @@ -7,6 +7,9 @@ if (settings.mirrorScoreButtons == null) { settings.mirrorScoreButtons = false; } + if (settings.keepDisplayOn == null) { + settings.keepDisplayOn = true; + } } if (settings.winSets == null) { settings.winSets = 2; @@ -91,10 +94,12 @@ 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); }; @@ -119,6 +124,11 @@ 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,