Index: binaries/data/mods/public/gui/lobby/AccountSettingsPage/AccountSettingsPage.js =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/lobby/AccountSettingsPage/AccountSettingsPage.js @@ -0,0 +1,199 @@ +/** + * The account settings page allows the player to change some of their account settings. + */ +class AccountSettingsPage +{ + constructor(xmppMessages) + { + this.openPageHandlers = new Set(); + this.closePageHandlers = new Set(); + + this.pageElement = Engine.GetGUIObjectByName("accountSettingsPage"); + this.overlayElement = Engine.GetGUIObjectByName("as_Overlay"); + this.requestResultElement = Engine.GetGUIObjectByName("as_RequestResult"); + this.passwordInputElement = Engine.GetGUIObjectByName("as_PasswordInput"); + this.passwordInputConfirmElement = Engine.GetGUIObjectByName("as_PasswordInputConfirm"); + + this.pageElement.onTick = () => this.onTick(); + + this.currentRequest = undefined; + + xmppMessages.registerXmppMessageHandler("system", "registered", x => this.onSystemMessage(x)); + xmppMessages.registerXmppMessageHandler("system", "error", x => this.onSystemMessage(x)); + + Engine.GetGUIObjectByName("as_ChangePasswordBtn").onPress = () => this.onPressChangePassword(); + Engine.GetGUIObjectByName("as_Close").onPress = () => this.onPressClose(); + } + + registerOpenPageHandler(handler) + { + this.openPageHandlers.add(handler); + } + + registerClosePageHandler(handler) + { + this.closePageHandlers.add(handler); + } + + onTick() + { + if (this.currentRequest) + updateTimers(); + } + + openPage() + { + this.currentRequest = undefined; + this.requestResultElement.caption = ""; + this.pageElement.hidden = false; + Engine.SetGlobalHotkey("cancel", "Press", () => this.onPressClose()); + } + + onSystemMessage(message) + { + if (!this.currentRequest) + return; + + if (this.currentRequest.type === "changePassword" && message.level === 'registered') + this.currentRequest.succeed(message); + else if (message.level === 'error') + this.currentRequest.fail(message.text); + } + + handleRequestSuccess() + { + this.overlayElement.hidden = true; + + if (!this.currentRequest?.resolved) + { + error("handleRequestSuccess called on unresolved request"); + return; + } + + if (this.currentRequest.type === "changePassword") + { + this.requestResultElement.caption = translate("Password changed successfully."); + if (Engine.ConfigDB_GetValue("user", "lobby.rememberpassword") == "true") + Engine.ConfigDB_CreateValue("user", "lobby.password", this.currentRequest.newPassword); + else + Engine.ConfigDB_RemoveValue("user", "lobby.password"); + Engine.ConfigDB_SaveChanges("user"); + } + } + + handleRequestFailure() + { + this.overlayElement.hidden = true; + + if (!this.currentRequest?.resolved) + { + error("handleRequestFailure called on unresolved request"); + return; + } + this.requestResultElement.caption = this.currentRequest.message; + + if (this.currentRequest.type === "changePassword") + { + this.passwordInputElement.caption = ""; + this.passwordInputConfirmElement.caption = ""; + } + } + + onPressChangePassword() + { + if (this.currentRequest && !this.currentRequest.resolved) + return; + + this.currentRequest = new PasswordChangeRequest(() => this.handleRequestSuccess(), () => this.handleRequestFailure()); + + let newPass = this.passwordInputElement.caption; + if (newPass.length < minimumPasswordLength) + return this.currentRequest.fail(translate("Error: Please choose a longer password")) + + let confirm = this.passwordInputConfirmElement.caption; + if (newPass !== confirm) + return this.currentRequest.fail(translate("Error: Passwords do not match")); + + let usn = Engine.LobbyGetJID(); + let atIndex = usn.indexOf("@"); + if (atIndex == -1) + { + // Probably can't happen too easily, so error out. + error("Invalid JID"); + return this.currentRequest.fail(translate("Error: Invalid JID, cannot change password.")); + } + + newPass = Engine.EncryptPassword(newPass, usn.substring(0, atIndex).toLowerCase()); + this.overlayElement.hidden = false; + Engine.LobbyChangePassword(newPass); + this.currentRequest.newPassword = newPass; + this.currentRequest.startTimeout(translate("Error: Request timed out.")); + } + + onPressClose() + { + this.pageElement.hidden = true; + + for (let handler of this.closePageHandlers) + handler(); + } +} + +/** + * TODO: convert this to a proper promise ? + */ +class AccountSettingsRequest +{ + message = ""; + status = "pending"; + timeout = undefined; + + constructor(success, failure) + { + this.onSuccess = success; + this.onFailure = failure; + } + + _resolveCommon(message) + { + this.message = message; + if (!this.timeout) + return; + clearTimeout(this.timeout); + this.timeout = undefined; + } + + succeed(message) + { + this._resolveCommon(message); + this.status = "success"; + this.onSuccess(); + } + + fail(message) + { + this._resolveCommon(message); + this.status = "failed"; + this.onFailure(); + } + + startTimeout(message, timeout = 30000) + { + this.timeout = setTimeout(() => this.fail(message), timeout); + } + + get resolved() + { + return this.status !== "pending"; + } +} + +class PasswordChangeRequest extends AccountSettingsRequest +{ + newPassword = ""; + constructor(success, failure) + { + super(success, failure); + this.type = "changePassword"; + } +} Index: binaries/data/mods/public/gui/lobby/AccountSettingsPage/AccountSettingsPage.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/lobby/AccountSettingsPage/AccountSettingsPage.xml @@ -0,0 +1,46 @@ + +