diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3fa2f6f..f099f2a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -32,6 +32,7 @@ A preview of major changes can be found in the Wiki ([Latest Changes](https://gi
- New "Explore" tab on player statistics, to explore darts thrown
- Support for `ANY` and `MASTER` outs for `x01` legs
- Simplified input for `x01` legs
+- Ability to configure: "Announcement Volume", "Auto Busting" and "Auto Leg Finish" from frontend
#### Changed
- Updated to use `Node.js v18`
diff --git a/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.component.js b/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.component.js
index e77273e..e564418 100644
--- a/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.component.js
+++ b/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.component.js
@@ -4,7 +4,11 @@ module.exports = {
onCreate(input) {
this.state = {
layouts: [ {id: "wide", name: "Wide"}, {id: "compact", name: "Compact"}, {id: "compact-large", name: "Compact (Large)"} ],
- buttonLayout: "wide"
+ buttonLayout: "wide",
+ volume: 100,
+ confirmBusts: true,
+ autoFinishLegs: false,
+ autoFinishTime: 10
}
},
onMount() {
@@ -12,9 +16,45 @@ module.exports = {
if (buttonLayout) {
this.state.buttonLayout = buttonLayout
}
+
+ const volume = localStorage.get("volume");
+ if (volume) {
+ this.state.volume = Math.min(Math.max(parseInt(volume * 100), 0), 100);
+ }
+
+ const confirmBusts = localStorage.get("confirm-busts");
+ if (confirmBusts !== null) {
+ this.state.confirmBusts = confirmBusts === 'true';
+ }
+
+ const autoFinishLegs = localStorage.get("auto-finish-legs");
+ if (autoFinishLegs !== null) {
+ this.state.autoFinishLegs = autoFinishLegs === 'true';
+ }
+
+ const autoFinishTime = localStorage.get("auto-finish-time");
+ if (autoFinishTime !== null) {
+ this.state.autoFinishTime = parseInt(autoFinishTime, 10) || 10;
+ }
+ },
+ updateVolume(event, selected) {
+ this.state.volume = selected.value;
+ },
+ toggleConfirmBusts(event) {
+ this.state.confirmBusts = event.target.checked;
+ },
+ toggleAutoFinishLegs(event) {
+ this.state.autoFinishLegs = event.target.checked;
+ },
+ updateAutoFinishTime(event) {
+ this.state.autoFinishTime = parseInt(event.target.value, 10);
},
onSave() {
this.state.buttonLayout = document.getElementById("buttonLayout").value;
localStorage.set('button-layout', this.state.buttonLayout);
+ localStorage.set('confirm-busts', this.state.confirmBusts);
+ localStorage.set('auto-finish-legs', this.state.autoFinishLegs);
+ localStorage.set('auto-finish-time', this.state.autoFinishTime);
+ localStorage.set('volume', this.state.volume / 100);
},
}
diff --git a/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.marko b/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.marko
index a94fb3b..068c107 100644
--- a/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.marko
+++ b/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.marko
@@ -11,11 +11,51 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.style.less b/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.style.less
new file mode 100644
index 0000000..9f3aec2
--- /dev/null
+++ b/src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.style.less
@@ -0,0 +1,52 @@
+.block-container-header > span {
+ font-weight: 700;
+}
+
+.form-check-input {
+ display: none;
+}
+
+.toggle-button {
+ width: 50px;
+ height: 24px;
+ background-color: #ccc;
+ border-radius: 12px;
+ position: relative;
+ cursor: pointer;
+ transition: background-color 0.3s;
+ margin-bottom: -5px;
+}
+
+.toggle-button .toggle-slider {
+ position: absolute;
+ top: 2px;
+ left: 2px;
+ width: 20px;
+ height: 20px;
+ background-color: white;
+ border-radius: 50%;
+ transition: transform 0.3s;
+}
+
+.form-check-input:checked + .toggle-button {
+ background-color: #4caf50;
+}
+
+.form-check-input:checked + .toggle-button .toggle-slider {
+ transform: translateX(26px);
+}
+
+.block-container-with-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+
+.form-group {
+ margin-bottom: 0;
+}
+
+.toggle-button {
+ display: inline-block;
+}
\ No newline at end of file
diff --git a/src/components/scorecard-header/scorecard-header.marko b/src/components/scorecard-header/scorecard-header.marko
index 45a2073..09e480d 100644
--- a/src/components/scorecard-header/scorecard-header.marko
+++ b/src/components/scorecard-header/scorecard-header.marko
@@ -1,7 +1,7 @@
$ const types = require("../scorecard/components/match_types");
-
+
diff --git a/src/components/scorecard-header/scorecard-header.style.less b/src/components/scorecard-header/scorecard-header.style.less
index d5bcc48..17907cc 100644
--- a/src/components/scorecard-header/scorecard-header.style.less
+++ b/src/components/scorecard-header/scorecard-header.style.less
@@ -1,3 +1,20 @@
+/*@media (max-width: 1340px) {
+ .scorecard-header {
+ overflow: hidden;
+ transform: scaleY(0.75);
+ transform-origin: top left;
+ margin-bottom: -40px !important;
+ }
+
+ .label-player-name {
+ font-size: 14pt;
+ }
+
+ .label-player-score {
+ font-size: 24pt;
+ }
+}*/
+
table {
width: 100%;
table-layout: fixed;
@@ -35,7 +52,7 @@ table {
}
.label-player-name {
- font-size: 10pt;
+ font-size: 18pt;
padding: 0px;
margin: 0px;
color: #ffffff;
@@ -50,7 +67,7 @@ table {
.label-player-score {
font-weight: 700;
padding: 10px 0px 0px 0px;
- font-size: 40pt;
+ font-size: 32pt;
}
.player-legs {
diff --git a/src/components/scorecard/components/x01.js b/src/components/scorecard/components/x01.js
index c1f4833..99d9b4f 100644
--- a/src/components/scorecard/components/x01.js
+++ b/src/components/scorecard/components/x01.js
@@ -1,4 +1,5 @@
const alertify = require("../../../util/alertify");
+const localStorage = require("../../../util/localstorage");
const types = require("./match_types");
exports.removeLast = function(dart, external) {
@@ -66,26 +67,27 @@ exports.confirmThrow = function (external) {
const isBust = module.exports.isBust(this.state.player, dart, this.state.totalScore, this.state.leg);
if (isCheckout) {
submitting = true;
- alertify.confirm('Leg will be finished.',
- () => {
- this.emit('leg-finished', true);
- }, () => {
- this.removeLast();
- this.emit('leg-finished', false);
- });
- } else if (isBust) {
+ }
+ else if (isBust) {
submitting = true;
this.state.isBusted = true;
- alertify.confirm('Player busted',
- () => {
- alertify.success('Player busted');
- this.emit('player-busted', true);
- },
- () => {
- this.removeLast();
- this.state.isBusted = false;
- this.emit('player-busted', false);
- });
+ const isConfirmBust = localStorage.getBool('confirm-busts');
+
+ if (isConfirmBust) {
+ alertify.confirm('Player busted',
+ () => {
+ alertify.success('Player busted');
+ this.emit('player-busted', true);
+ },
+ () => {
+ this.removeLast();
+ this.state.isBusted = false;
+ this.emit('player-busted', false);
+ });
+ } else {
+ alertify.success('Player busted');
+ this.emit('player-busted', true);
+ }
}
if (!this.state.player.player.options || this.state.player.player.options.subtract_per_dart) {
this.state.player.current_score -= scored;
@@ -96,3 +98,4 @@ exports.confirmThrow = function (external) {
}
return submitting;
}
+
diff --git a/src/components/scorecard/scorecard.component.js b/src/components/scorecard/scorecard.component.js
index f981733..dc8a46a 100644
--- a/src/components/scorecard/scorecard.component.js
+++ b/src/components/scorecard/scorecard.component.js
@@ -1,4 +1,5 @@
const alertify = require("../../util/alertify");
+const localStorage = require("../../util/localstorage");
const x01 = require("./components/x01");
const shootout = require("./components/shootout");
@@ -260,12 +261,39 @@ module.exports = {
},
confirmLegFinish() {
- alertify.confirm('Leg will be finished.',
+ let countdown = localStorage.get('auto-finish-time') || 10;
+ let confirmed = false;
+
+ const okFunction = () => {
+ confirmed = true;
+ this.emit('leg-finished', true);
+ };
+
+ const confirmDialog = alertify.confirm(`Leg will be finished`,
+ okFunction,
() => {
- this.emit('leg-finished', true);
- }, () => {
this.removeLast();
this.emit('leg-finished', false);
+ }
+ );
+
+ const isAutoFinish = localStorage.getBool('auto-finish-legs');
+ if (isAutoFinish) {
+ confirmDialog.setContent(`Leg will be finished (${countdown}s)`);
+ const countdownInterval = setInterval(() => {
+ countdown--;
+ confirmDialog.setContent(`Leg will be finished (${countdown}s)`);
+
+ if (countdown <= 0) {
+ clearInterval(countdownInterval);
+ if (!confirmed) {
+ okFunction();
+ }
+ }
+ }, 1000);
+ confirmDialog.set('onclose', function() {
+ clearInterval(countdownInterval);
});
+ }
}
};
diff --git a/src/util/alertify.js b/src/util/alertify.js
index 547aa40..6f3bf85 100644
--- a/src/util/alertify.js
+++ b/src/util/alertify.js
@@ -37,7 +37,7 @@ exports.alert = (text, okFnc) => {
.show();
}
exports.confirm = (text, okFnc, cancelFnc) => {
- bootstrap().confirm(text, okFnc, cancelFnc)
+ return bootstrap().confirm(text, okFnc, cancelFnc)
.setting({
title: TITLE,
defaultFocus: 'ok',
diff --git a/src/util/localstorage.js b/src/util/localstorage.js
index cf57980..679f5ea 100644
--- a/src/util/localstorage.js
+++ b/src/util/localstorage.js
@@ -4,6 +4,13 @@ function getKey(key) {
exports.get = key => localStorage.getItem(getKey(key));
exports.getInt = key => parseInt(localStorage.getItem(getKey(key)));
+exports.getBool = key => {
+ const item = localStorage.getItem(getKey(key));
+ if (!item) {
+ return false;
+ }
+ return item === 'true';
+}
exports.set = (key, value) =>
localStorage.setItem(getKey(key), value);
exports.getKey = getKey;
diff --git a/src/util/socket.io-helper.js b/src/util/socket.io-helper.js
index 93a2dfc..c0556ac 100644
--- a/src/util/socket.io-helper.js
+++ b/src/util/socket.io-helper.js
@@ -3,6 +3,7 @@ const io = require('socket.io-client');
const alertify = require('./alertify');
const speaker = require('./speaker');
const types = require('../components/scorecard/components/match_types');
+const localStorage = require('./localstorage');
exports.connect = (url) => {
const socket = io(url);
@@ -89,13 +90,17 @@ exports.say = (data, thiz) => {
if (thiz.state.venueConfig) {
voice = thiz.state.venueConfig.tts_voice;
}
+ let volume = localStorage.get("volume");
+ volume = volume ? Math.min(Math.max(parseFloat(volume), 0.0), 1.0) : 1.0;
const oldPlayer = thiz.state.audioAnnouncer;
const isAudioAnnouncement = (oldPlayer.duration > 0 && !oldPlayer.paused) || (!isNaN(oldPlayer.duration) && !oldPlayer.ended && oldPlayer.paused);
if (data.audios) {
const audioPlayers = [ ];
for (const file of data.audios) {
- audioPlayers.push(file.file ? new Audio(file.file) : speaker.getUtteranceWithVoice(file, voice));
+ const audioPlayer = file.file ? new Audio(file.file) : speaker.getUtteranceWithVoice(file, voice);
+ audioPlayer.volume = volume;
+ audioPlayers.push(audioPlayer);
}
for (let i = 0; i < audioPlayers.length; i++) {
|