diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 4cd7e796398..3e3a6ce8f8b 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -730,16 +730,15 @@ export class GameData { * Saves a setting to localStorage * @param setting string ideally of SettingKeys * @param valueIndex index of the setting's option - * @param fromSettings whether the function was called from the settings menu * @returns true */ - public saveSetting(setting: string, valueIndex: integer, fromSettings?: boolean): boolean { + public saveSetting(setting: string, valueIndex: integer): boolean { let settings: object = {}; if (localStorage.hasOwnProperty("settings")) { settings = JSON.parse(localStorage.getItem("settings")!); // TODO: is this bang correct? } - setSetting(this.scene, setting, valueIndex, fromSettings); + setSetting(this.scene, setting, valueIndex); settings[setting] = valueIndex; settings["gameVersion"] = this.scene.game.config.gameVersion; diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 018901ba33d..64ddfdae5cf 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -1,16 +1,15 @@ import { Mode } from "#app/ui/ui"; import i18next from "i18next"; -import BattleScene from "../../battle-scene"; -import { hasTouchscreen } from "../../touch-controls"; -import { updateWindowType } from "../../ui/ui-theme"; -import { CandyUpgradeNotificationChangedEvent } from "../../events/battle-scene"; +import BattleScene from "#app/battle-scene"; +import { hasTouchscreen } from "#app/touch-controls"; +import { updateWindowType } from "#app/ui/ui-theme"; +import { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene"; import SettingsUiHandler from "#app/ui/settings/settings-ui-handler"; import { EaseType } from "#enums/ease-type"; import { MoneyFormat } from "#enums/money-format"; import { PlayerGender } from "#enums/player-gender"; import { getIsInitialized, initI18n } from "#app/plugins/i18n"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; -import { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler"; function getTranslation(key: string): string { if (!getIsInitialized()) { @@ -45,6 +44,7 @@ const OFF_ON: SettingOption[] = [ label: i18next.t("settings:on") } ]; + const AUTO_DISABLED: SettingOption[] = [ { value: "Auto", @@ -56,6 +56,19 @@ const AUTO_DISABLED: SettingOption[] = [ } ]; +const TOUCH_CONTROLS_OPTIONS: SettingOption[] = [ + { + value: "Auto", + label: i18next.t("settings:auto") + }, + { + value: "Disabled", + label: i18next.t("settings:disabled"), + needConfirmation: true, + confirmationMessage: i18next.t("settings:confirmDisableTouch") + } +]; + const SHOP_CURSOR_TARGET_OPTIONS: SettingOption[] = [ { value: "Rewards", @@ -101,7 +114,9 @@ export enum SettingType { type SettingOption = { value: string, - label: string + label: string, + needConfirmation?: boolean, + confirmationMessage?: string }; export interface Setting { @@ -355,7 +370,7 @@ export const Setting: Array = [ { key: SettingKeys.Touch_Controls, label: i18next.t("settings:touchControls"), - options: AUTO_DISABLED, + options: TOUCH_CONTROLS_OPTIONS, default: 0, type: SettingType.GENERAL, isHidden: () => !hasTouchscreen() @@ -698,11 +713,9 @@ export function resetSettings(scene: BattleScene) { * @param scene current BattleScene * @param setting string ideally from SettingKeys * @param value value to update setting with - * @param fromSettings whether the function was called from the settings menu, meaning it is possible - * to access the handler and add extra interactions for the player * @returns true if successful, false if not */ -export function setSetting(scene: BattleScene, setting: string, value: integer, fromSettings?: boolean): boolean { +export function setSetting(scene: BattleScene, setting: string, value: integer): boolean { const index: number = settingIndex(setting); if (index === -1) { return false; @@ -836,43 +849,10 @@ export function setSetting(scene: BattleScene, setting: string, value: integer, } break; case SettingKeys.Touch_Controls: - const setTouchControlsVisibility = (scene: BattleScene) => { - const touchControls = document.getElementById("touchControls"); - if (touchControls) { - touchControls.classList.toggle("visible", scene.enableTouchControls); - } - }; - - if (fromSettings && Setting[index].options[value].value === "Disabled") { - const optionsConfig: OptionSelectConfig = { - yOffset: 24, - delay: 1000, - options: [ - { - label: i18next.t("settings:disableTouchControls"), - handler: () => { - scene.ui.revertMode(); - scene.enableTouchControls = false; - setTouchControlsVisibility(scene); - return true; - } - }, - { - label: i18next.t("settings:cancel"), - handler: () => { - scene.ui.revertMode(); - // Put the option cursor back to "Auto" and save that - (scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true); - return true; - } - } - ] - }; - // Player moved to the "Disabled" option, show a confirmation window, with a 1s delay before being able to confirm - scene.ui.setOverlayMode(Mode.OPTION_SELECT, optionsConfig); - } else { - scene.enableTouchControls = Setting[index].options[value].value !== "Disabled" && hasTouchscreen(); - setTouchControlsVisibility(scene); + scene.enableTouchControls = Setting[index].options[value].value !== "Disabled" && hasTouchscreen(); + const touchControls = document.getElementById("touchControls"); + if (touchControls) { + touchControls.classList.toggle("visible", scene.enableTouchControls); } break; case SettingKeys.Vibration: @@ -883,7 +863,7 @@ export function setSetting(scene: BattleScene, setting: string, value: integer, break; case SettingKeys.Language: if (value) { - if (fromSettings) { + if (scene.ui) { const cancelHandler = () => { scene.ui.revertMode(); (scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true); diff --git a/src/ui/settings/abstract-settings-ui-handler.ts b/src/ui/settings/abstract-settings-ui-handler.ts index e731a63862d..1c87f4a702e 100644 --- a/src/ui/settings/abstract-settings-ui-handler.ts +++ b/src/ui/settings/abstract-settings-ui-handler.ts @@ -1,7 +1,7 @@ import BattleScene from "#app/battle-scene"; import { TextStyle, addTextObject } from "#app/ui/text"; import { Mode } from "#app/ui/ui"; -import UiHandler from "#app/ui/ui-handler"; +import MessageUiHandler from "#app/ui/message-ui-handler"; import { addWindow } from "#app/ui/ui-theme"; import { ScrollBar } from "#app/ui/scroll-bar"; import { Button } from "#enums/buttons"; @@ -14,9 +14,10 @@ import i18next from "i18next"; /** * Abstract class for handling UI elements related to settings. */ -export default class AbstractSettingsUiHandler extends UiHandler { +export default class AbstractSettingsUiHandler extends MessageUiHandler { private settingsContainer: Phaser.GameObjects.Container; private optionsContainer: Phaser.GameObjects.Container; + private messageBoxContainer: Phaser.GameObjects.Container; private navigationContainer: NavigationMenu; private scrollCursor: number; @@ -134,6 +135,22 @@ export default class AbstractSettingsUiHandler extends UiHandler { this.scrollBar = new ScrollBar(this.scene, this.optionsBg.width - 9, this.optionsBg.y + 5, 4, this.optionsBg.height - 11, this.rowsToDisplay); this.scrollBar.setTotalRows(this.settings.length); + // Single-line message box + this.messageBoxContainer = this.scene.add.container(0, this.scene.scaledCanvas.height); + this.messageBoxContainer.setName("settings-message-box"); + this.messageBoxContainer.setVisible(false); + + const settingsMessageBox = addWindow(this.scene, 0, -1, this.scene.scaledCanvas.width - 2, 28); + settingsMessageBox.setOrigin(0, 1); + this.messageBoxContainer.add(settingsMessageBox); + + const messageText = addTextObject(this.scene, 8, -8, "", TextStyle.WINDOW); + messageText.setOrigin(0, 1); + messageText.setName("settings-message"); + + this.messageBoxContainer.add(messageText); + this.message = messageText; + this.settingsContainer.add(this.optionsBg); this.settingsContainer.add(this.scrollBar); this.settingsContainer.add(this.navigationContainer); @@ -143,6 +160,7 @@ export default class AbstractSettingsUiHandler extends UiHandler { this.settingsContainer.add(iconCancel); this.settingsContainer.add(actionText); this.settingsContainer.add(cancelText); + this.settingsContainer.add(this.messageBoxContainer); ui.add(this.settingsContainer); @@ -350,9 +368,34 @@ export default class AbstractSettingsUiHandler extends UiHandler { newValueLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true)); if (save) { - this.scene.gameData.saveSetting(setting.key, cursor, true); - if (this.reloadSettings.includes(setting)) { - this.reloadRequired = true; + const saveSetting = () => { + this.scene.gameData.saveSetting(setting.key, cursor); + if (setting.requireReload) { + this.reloadRequired = true; + } + }; + + // For settings that ask for confirmation + if (setting.options[cursor].needConfirmation) { + const confirmUpdateSetting = () => { + this.scene.ui.revertMode(); + this.showText(""); + saveSetting(); + }; + const cancelUpdateSetting = () => { + this.scene.ui.revertMode(); + this.showText(""); + // Put the cursor back to its previous position without saving or asking for confirmation again + this.setOptionCursor(settingIndex, lastCursor, false); + }; + + const confirmationMessage = setting.options[cursor].confirmationMessage ?? i18next.t("settings:defaultConfirmMessage"); + this.scene.ui.showText(confirmationMessage, null, () => { + const yOffset = 48 - this.messageBoxContainer.getAt(0).height; + this.scene.ui.setOverlayMode(Mode.CONFIRM, confirmUpdateSetting, cancelUpdateSetting, null, null, yOffset, 1000); + }); + } else { + saveSetting(); } } @@ -419,4 +462,10 @@ export default class AbstractSettingsUiHandler extends UiHandler { } this.cursorObj = null; } + + showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + console.log("HELLO"); + this.messageBoxContainer.setVisible(!!text?.length); + super.showText(text, delay, callback, callbackDelay, prompt, promptDelay); + } }