You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tobspr_shapez.io/src/js/profile/setting_types.js

389 lines
11 KiB

/* typehints:start */
import { Application } from "../application";
/* typehints:end */
import { createLogger } from "../core/logging";
import { WEB_STEAM_SSO_AUTHENTICATED } from "../core/steam_sso";
import { T } from "../translations";
const logger = createLogger("setting_types");
/*
* ***************************************************
*
* LEGACY CODE WARNING
*
* This is old code from yorg3.io and needs to be refactored
* @TODO
*
* ***************************************************
*/
export class BaseSetting {
/**
*
* @param {string} id
* @param {string} categoryId
* @param {function(Application, any):void} changeCb
* @param {function(Application) : boolean=} enabledCb
*/
constructor(id, categoryId, changeCb, enabledCb = null) {
this.id = id;
this.categoryId = categoryId;
this.changeCb = changeCb;
this.enabledCb = enabledCb;
/** @type {Application} */
this.app = null;
this.element = null;
this.dialogs = null;
}
/**
* @param {Application} app
* @param {any} value
*/
apply(app, value) {
if (this.changeCb) {
this.changeCb(app, value);
}
}
/**
* Binds all parameters
* @param {Application} app
* @param {HTMLElement} element
* @param {any} dialogs
*/
bind(app, element, dialogs) {
this.app = app;
this.element = element;
this.dialogs = dialogs;
}
/**
* Returns the HTML for this setting
* @param {Application} app
* @abstract
*/
getHtml(app) {
abstract;
return "";
}
/**
* Returns whether this setting is enabled and available
* @param {Application} app
*/
getIsAvailable(app) {
return this.enabledCb ? this.enabledCb(app) : true;
}
syncValueToElement() {
abstract;
}
/**
* Attempts to modify the setting
* @abstract
*/
modify() {
abstract;
}
/**
* Shows the dialog that a restart is required
*/
showRestartRequiredDialog() {
const { restart } = this.dialogs.showInfo(
T.dialogs.restartRequired.title,
T.dialogs.restartRequired.text,
this.app.platformWrapper.getSupportsRestart() ? ["later:grey", "restart:misc"] : ["ok:good"]
);
if (restart) {
restart.add(() => this.app.platformWrapper.performRestart());
}
}
/**
* Validates the set value
* @param {any} value
* @returns {boolean}
* @abstract
*/
validate(value) {
abstract;
return false;
}
}
export class EnumSetting extends BaseSetting {
constructor(
id,
{
options,
valueGetter,
textGetter,
descGetter = null,
category,
restartRequired = true,
iconPrefix = null,
changeCb = null,
magicValue = null,
enabledCb = null,
}
) {
super(id, category, changeCb, enabledCb);
this.options = options;
this.valueGetter = valueGetter;
this.textGetter = textGetter;
this.descGetter = descGetter || (() => null);
this.restartRequired = restartRequired;
this.iconPrefix = iconPrefix;
this.magicValue = magicValue;
}
/**
* @param {Application} app
*/
getHtml(app) {
const available = this.getIsAvailable(app);
return `
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
${
available
? ""
: `<span class="standaloneOnlyHint">${
WEB_STEAM_SSO_AUTHENTICATED ? "" : T.demo.settingNotAvailable
}</span>`
}
<div class="row">
<label>${T.settings.labels[this.id].title}</label>
<div class="value enum" data-setting="${this.id}"></div>
</div>
<div class="desc">
${T.settings.labels[this.id].description}
</div>
</div>`;
}
validate(value) {
if (value === this.magicValue) {
return true;
}
const availableValues = this.options.map(option => this.valueGetter(option));
if (availableValues.indexOf(value) < 0) {
logger.error(
"Value '" + value + "' is not contained in available values:",
availableValues,
"of",
this.id
);
return false;
}
return true;
}
syncValueToElement() {
const value = this.app.settings.getSetting(this.id);
let displayText = "???";
const matchedInstance = this.options.find(data => this.valueGetter(data) === value);
if (matchedInstance) {
displayText = this.textGetter(matchedInstance);
} else {
logger.warn("Setting value", value, "not found for", this.id, "!");
}
this.element.innerText = displayText;
}
modify() {
const { optionSelected } = this.dialogs.showOptionChooser(T.settings.labels[this.id].title, {
active: this.app.settings.getSetting(this.id),
options: this.options.map(option => ({
value: this.valueGetter(option),
text: this.textGetter(option),
desc: this.descGetter(option),
iconPrefix: this.iconPrefix,
})),
});
optionSelected.add(value => {
this.app.settings.updateSetting(this.id, value);
this.syncValueToElement();
if (this.restartRequired) {
this.showRestartRequiredDialog();
}
if (this.changeCb) {
this.changeCb(this.app, value);
}
}, this);
}
}
export class BoolSetting extends BaseSetting {
constructor(id, category, changeCb = null, enabledCb = null) {
super(id, category, changeCb, enabledCb);
}
/**
* @param {Application} app
*/
getHtml(app) {
const available = this.getIsAvailable(app);
return `
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
${
available
? ""
: `<span class="standaloneOnlyHint">${
WEB_STEAM_SSO_AUTHENTICATED ? "" : T.demo.settingNotAvailable
}</span>`
}
<div class="row">
<label>${T.settings.labels[this.id].title}</label>
<div class="value checkbox checked" data-setting="${this.id}">
<span class="knob"></span>
</div>
</div>
<div class="desc">
${T.settings.labels[this.id].description}
</div>
</div>`;
}
syncValueToElement() {
const value = this.app.settings.getSetting(this.id);
this.element.classList.toggle("checked", value);
}
modify() {
const newValue = !this.app.settings.getSetting(this.id);
this.app.settings.updateSetting(this.id, newValue);
this.syncValueToElement();
if (this.changeCb) {
this.changeCb(this.app, newValue);
}
}
validate(value) {
return typeof value === "boolean";
}
}
export class RangeSetting extends BaseSetting {
constructor(
id,
category,
changeCb = null,
defaultValue = 1.0,
minValue = 0,
maxValue = 1.0,
stepSize = 0.0001,
enabledCb = null
) {
super(id, category, changeCb, enabledCb);
this.defaultValue = defaultValue;
this.minValue = minValue;
this.maxValue = maxValue;
this.stepSize = stepSize;
}
/**
* @param {Application} app
*/
getHtml(app) {
const available = this.getIsAvailable(app);
return `
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
${
available
? ""
: `<span class="standaloneOnlyHint">${
WEB_STEAM_SSO_AUTHENTICATED ? "" : T.demo.settingNotAvailable
}</span>`
}
<div class="row">
<label>${T.settings.labels[this.id].title}</label>
<div class="value rangeInputContainer noPressEffect" data-setting="${this.id}">
<label>${this.defaultValue}</label>
<input class="rangeInput" type="range" value="${this.defaultValue}" min="${
this.minValue
}" max="${this.maxValue}" step="${this.stepSize}">
</div>
</div>
<div class="desc">
${T.settings.labels[this.id].description}
</div>
</div>`;
}
bind(app, element, dialogs) {
this.app = app;
this.element = element;
this.dialogs = dialogs;
this.getRangeInputElement().addEventListener("input", () => {
this.updateLabels();
});
this.getRangeInputElement().addEventListener("change", () => {
this.modify();
});
}
syncValueToElement() {
const value = this.app.settings.getSetting(this.id);
this.setElementValue(value);
}
/**
* Sets the elements value to the given value
* @param {number} value
*/
setElementValue(value) {
const rangeInput = this.getRangeInputElement();
const rangeLabel = this.element.querySelector("label");
rangeInput.value = String(value);
rangeLabel.innerHTML = T.settings.rangeSliderPercentage.replace(
"<amount>",
String(Math.round(value * 100.0))
);
}
updateLabels() {
const value = Number(this.getRangeInputElement().value);
this.setElementValue(value);
}
/**
* @returns {HTMLInputElement}
*/
getRangeInputElement() {
return this.element.querySelector("input.rangeInput");
}
modify() {
const rangeInput = this.getRangeInputElement();
const newValue = Math.round(Number(rangeInput.value) * 100.0) / 100.0;
this.app.settings.updateSetting(this.id, newValue);
this.syncValueToElement();
console.log("SET", newValue);
if (this.changeCb) {
this.changeCb(this.app, newValue);
}
}
validate(value) {
return typeof value === "number" && value >= this.minValue && value <= this.maxValue;
}
}