mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-09-23 15:03:24 +02:00
allow up to 7 usernames in panel before P02
This commit is contained in:
parent
207808f37d
commit
9937cca8f8
@ -20,6 +20,18 @@ interface BuildInteractableImageOpts {
|
||||
origin?: { x: number; y: number };
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum number of saves that are allowed to show up in the username panel pefore
|
||||
* the `P02: Too many saves` popup is displayed.
|
||||
*
|
||||
* @privateRemarks
|
||||
* This limitation is in place to allow for the password reset helpers to get
|
||||
* enough information in one screenshot. If the user has too many saves, this
|
||||
* complicates the interaction as it would require scrolling, which will
|
||||
* make tickets take longer to resolve.
|
||||
*/
|
||||
const MAX_SAVES_FOR_USERNAME_PANEL = 7;
|
||||
|
||||
export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
private readonly ERR_USERNAME: string = "invalid username";
|
||||
private readonly ERR_PASSWORD: string = "invalid password";
|
||||
@ -54,21 +66,16 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
new Phaser.Geom.Rectangle(0, 0, globalScene.scaledCanvas.width / 2, globalScene.scaledCanvas.height / 2),
|
||||
Phaser.Geom.Rectangle.Contains,
|
||||
);
|
||||
this.externalPartyTitle = addTextObject(0, 4, "", TextStyle.SETTINGS_LABEL);
|
||||
this.externalPartyTitle.setOrigin(0.5, 0);
|
||||
this.externalPartyTitle = addTextObject(0, 4, "", TextStyle.SETTINGS_LABEL).setOrigin(0.5, 0);
|
||||
this.externalPartyBg = addWindow(0, 0, 0, 0);
|
||||
this.externalPartyContainer.add(this.externalPartyBg);
|
||||
this.externalPartyContainer.add(this.externalPartyTitle);
|
||||
|
||||
this.googleImage = this.buildInteractableImage("google", "google-icon");
|
||||
this.discordImage = this.buildInteractableImage("discord", "discord-icon");
|
||||
|
||||
this.externalPartyContainer.add(this.googleImage);
|
||||
this.externalPartyContainer.add(this.discordImage);
|
||||
this.externalPartyContainer
|
||||
.add([this.externalPartyBg, this.externalPartyTitle, this.googleImage, this.discordImage])
|
||||
.setVisible(false);
|
||||
this.getUi().add(this.externalPartyContainer);
|
||||
this.externalPartyContainer.add(this.googleImage);
|
||||
this.externalPartyContainer.add(this.discordImage);
|
||||
this.externalPartyContainer.setVisible(false);
|
||||
}
|
||||
|
||||
private buildInfoContainer() {
|
||||
@ -89,12 +96,11 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
scale: 0.5,
|
||||
});
|
||||
|
||||
this.infoContainer.add(this.usernameInfoImage);
|
||||
this.infoContainer.add(this.saveDownloadImage);
|
||||
this.infoContainer.add(this.changeLanguageImage);
|
||||
this.infoContainer
|
||||
.add([this.usernameInfoImage, this.saveDownloadImage, this.changeLanguageImage])
|
||||
.setVisible(false)
|
||||
.disableInteractive();
|
||||
this.getUi().add(this.infoContainer);
|
||||
this.infoContainer.setVisible(false);
|
||||
this.infoContainer.disableInteractive();
|
||||
}
|
||||
|
||||
override getModalTitle(_config?: ModalConfig): string {
|
||||
@ -142,16 +148,20 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
|
||||
override getInputFieldConfigs(): InputFieldConfig[] {
|
||||
const inputFieldConfigs: InputFieldConfig[] = [];
|
||||
inputFieldConfigs.push({ label: i18next.t("menu:username") });
|
||||
inputFieldConfigs.push({
|
||||
inputFieldConfigs.push(
|
||||
{ label: i18next.t("menu:username") },
|
||||
{
|
||||
label: i18next.t("menu:password"),
|
||||
isPassword: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
return inputFieldConfigs;
|
||||
}
|
||||
|
||||
override show(args: any[]): boolean {
|
||||
if (super.show(args)) {
|
||||
if (!super.show(args)) {
|
||||
return false;
|
||||
}
|
||||
const config = args[0] as ModalConfig;
|
||||
this.processExternalProvider(config);
|
||||
const originalLoginAction = this.submitAction;
|
||||
@ -189,13 +199,10 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
override clear() {
|
||||
super.clear();
|
||||
this.externalPartyContainer.setVisible(false);
|
||||
this.infoContainer.setVisible(false);
|
||||
this.externalPartyContainer.setVisible(false).setActive(false);
|
||||
this.infoContainer.setVisible(false).setActive(false);
|
||||
this.setMouseCursorStyle("default"); //reset cursor
|
||||
|
||||
[
|
||||
@ -204,62 +211,47 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
this.usernameInfoImage,
|
||||
this.saveDownloadImage,
|
||||
this.changeLanguageImage,
|
||||
].forEach(img => img.off("pointerdown"));
|
||||
].forEach(img => {
|
||||
img.off("pointerdown");
|
||||
});
|
||||
}
|
||||
|
||||
private processExternalProvider(config: ModalConfig): void {
|
||||
this.externalPartyTitle.setText(i18next.t("menu:orUse") ?? "");
|
||||
this.externalPartyTitle.setX(20 + this.externalPartyTitle.text.length);
|
||||
this.externalPartyTitle.setVisible(true);
|
||||
this.externalPartyContainer.setPositionRelative(this.modalContainer, 175, 0);
|
||||
this.externalPartyContainer.setVisible(true);
|
||||
this.externalPartyBg.setSize(this.externalPartyTitle.text.length + 50, this.modalBg.height);
|
||||
this.getUi().moveTo(this.externalPartyContainer, this.getUi().length - 1);
|
||||
this.googleImage.setPosition(this.externalPartyBg.width / 3.1, this.externalPartyBg.height - 60);
|
||||
this.discordImage.setPosition(this.externalPartyBg.width / 3.1, this.externalPartyBg.height - 40);
|
||||
override destroy() {
|
||||
super.destroy();
|
||||
this.externalPartyContainer.destroy();
|
||||
this.infoContainer.destroy();
|
||||
}
|
||||
|
||||
this.infoContainer.setPosition(5, -76);
|
||||
this.infoContainer.setVisible(true);
|
||||
this.getUi().moveTo(this.infoContainer, this.getUi().length - 1);
|
||||
this.usernameInfoImage.setPositionRelative(this.infoContainer, 0, 0);
|
||||
this.saveDownloadImage.setPositionRelative(this.infoContainer, 20, 0);
|
||||
this.changeLanguageImage.setPositionRelative(this.infoContainer, 40, 0);
|
||||
|
||||
this.discordImage.on("pointerdown", () => {
|
||||
const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`);
|
||||
const discordId = import.meta.env.VITE_DISCORD_CLIENT_ID;
|
||||
const discordUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordId}&redirect_uri=${redirectUri}&response_type=code&scope=identify&prompt=none`;
|
||||
window.open(discordUrl, "_self");
|
||||
});
|
||||
|
||||
this.googleImage.on("pointerdown", () => {
|
||||
const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/google/callback`);
|
||||
const googleId = import.meta.env.VITE_GOOGLE_CLIENT_ID;
|
||||
const googleUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${googleId}&redirect_uri=${redirectUri}&response_type=code&scope=openid`;
|
||||
window.open(googleUrl, "_self");
|
||||
});
|
||||
|
||||
const onFail = error => {
|
||||
globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] });
|
||||
globalScene.ui.setModeForceTransition(UiMode.LOGIN_FORM, Object.assign(config, { errorMessage: error?.trim() }));
|
||||
globalScene.ui.playError();
|
||||
};
|
||||
|
||||
this.usernameInfoImage.on("pointerdown", () => {
|
||||
/**
|
||||
* Show a panel with all usernames found in localStorage
|
||||
*
|
||||
* @remarks
|
||||
* Up to {@linkcode MAX_SAVES_FOR_USERNAME_PANEL} usernames are shown, otherwise P02 is triggered
|
||||
* @param onFail - Callback function for failure
|
||||
*/
|
||||
private showUsernames(config: ModalConfig) {
|
||||
if (globalScene.tweens.getTweensOf(this.infoContainer).length === 0) {
|
||||
const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage
|
||||
const keyToFind = "data_";
|
||||
const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0);
|
||||
if (dataKeys.length > 0 && dataKeys.length <= 2) {
|
||||
if (dataKeys.length === 0) {
|
||||
this.onFail(this.ERR_NO_SAVES, config);
|
||||
return;
|
||||
}
|
||||
if (dataKeys.length > MAX_SAVES_FOR_USERNAME_PANEL) {
|
||||
this.onFail(this.ERR_TOO_MANY_SAVES, config);
|
||||
return;
|
||||
}
|
||||
const options: OptionSelectItem[] = [];
|
||||
for (const key of dataKeys) {
|
||||
options.push({
|
||||
label: key.replace(keyToFind, ""),
|
||||
handler: () => {
|
||||
const handler = () => {
|
||||
globalScene.ui.revertMode();
|
||||
this.infoContainer.disableInteractive();
|
||||
return true;
|
||||
},
|
||||
};
|
||||
for (const key of dataKeys) {
|
||||
options.push({
|
||||
label: key.replace(keyToFind, ""),
|
||||
handler,
|
||||
});
|
||||
}
|
||||
globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
|
||||
@ -270,24 +262,39 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
new Phaser.Geom.Rectangle(0, 0, globalScene.game.canvas.width, globalScene.game.canvas.height),
|
||||
Phaser.Geom.Rectangle.Contains,
|
||||
);
|
||||
} else {
|
||||
if (dataKeys.length > 2) {
|
||||
return onFail(this.ERR_TOO_MANY_SAVES);
|
||||
}
|
||||
return onFail(this.ERR_NO_SAVES);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.saveDownloadImage.on("pointerdown", async () => {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private onFail(error: string, config: ModalConfig) {
|
||||
const ui = globalScene.ui;
|
||||
ui.setMode(UiMode.LOADING, { buttonActions: [] });
|
||||
ui.setModeForceTransition(UiMode.LOGIN_FORM, Object.assign(config, { errorMessage: error?.trim() }));
|
||||
ui.playError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the user's save files from localStorage and download them as a zip file
|
||||
*
|
||||
* @remarks
|
||||
* Used as the `pointerDown` callback for the save download image
|
||||
* @param config - The modal configuration
|
||||
*/
|
||||
private async downloadSaves(config: ModalConfig): Promise<void> {
|
||||
// find all data_ and sessionData keys, put them in a .txt file and download everything in a single zip
|
||||
const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage
|
||||
const keyToFind = "data_";
|
||||
const sessionKeyToFind = "sessionData";
|
||||
const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0);
|
||||
const sessionKeys = localStorageKeys.filter(ls => ls.indexOf(sessionKeyToFind) >= 0);
|
||||
if (dataKeys.length > 0 || sessionKeys.length > 0) {
|
||||
if (dataKeys.length <= 0 && sessionKeys.length <= 0) {
|
||||
this.onFail(this.ERR_NO_SAVES, config);
|
||||
return;
|
||||
}
|
||||
const zip = new JSZip();
|
||||
// Bang is safe here because of the filter above
|
||||
for (const dataKey of dataKeys) {
|
||||
zip.file(dataKey + ".prsv", localStorage.getItem(dataKey)!);
|
||||
}
|
||||
@ -301,12 +308,53 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
a.download = "pokerogue_saves.zip";
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
} else {
|
||||
return onFail(this.ERR_NO_SAVES);
|
||||
}
|
||||
|
||||
private processExternalProvider(config: ModalConfig): void {
|
||||
this.externalPartyTitle
|
||||
.setText(i18next.t("menu:orUse") ?? "")
|
||||
.setX(20 + this.externalPartyTitle.text.length)
|
||||
.setVisible(true);
|
||||
|
||||
const externalPartyContainer = this.externalPartyContainer
|
||||
.setPositionRelative(this.modalContainer, 175, 0)
|
||||
.setVisible(true);
|
||||
|
||||
const externalPartyBg = this.externalPartyBg.setSize(this.externalPartyTitle.text.length + 50, this.modalBg.height);
|
||||
this.getUi().moveTo(externalPartyContainer, this.getUi().length - 1);
|
||||
|
||||
const externalPartyIconWidth = externalPartyBg.width / 3.1;
|
||||
this.discordImage;
|
||||
const infoContainer = this.infoContainer.setPosition(5, -76).setVisible(true);
|
||||
this.getUi().moveTo(infoContainer, this.getUi().length - 1);
|
||||
|
||||
this.discordImage // formatting
|
||||
.setPosition(externalPartyIconWidth, externalPartyBg.height - 40)
|
||||
.on("pointerdown", () => {
|
||||
const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`);
|
||||
const discordId = import.meta.env.VITE_DISCORD_CLIENT_ID;
|
||||
const discordUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordId}&redirect_uri=${redirectUri}&response_type=code&scope=identify&prompt=none`;
|
||||
window.open(discordUrl, "_self");
|
||||
});
|
||||
|
||||
this.changeLanguageImage.on("pointerdown", () => {
|
||||
this.googleImage // formatting
|
||||
.setPosition(externalPartyIconWidth, externalPartyBg.height - 60)
|
||||
.on("pointerdown", () => {
|
||||
const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/google/callback`);
|
||||
const googleId = import.meta.env.VITE_GOOGLE_CLIENT_ID;
|
||||
const googleUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${googleId}&redirect_uri=${redirectUri}&response_type=code&scope=openid`;
|
||||
window.open(googleUrl, "_self");
|
||||
});
|
||||
|
||||
this.usernameInfoImage // formatting
|
||||
.setPositionRelative(infoContainer, 0, 0)
|
||||
.on("pointerdown", () => this.showUsernames(config));
|
||||
|
||||
this.saveDownloadImage // formatting
|
||||
.setPositionRelative(infoContainer, 20, 0)
|
||||
.on("pointerdown", () => this.downloadSaves(config));
|
||||
|
||||
this.changeLanguageImage.setPositionRelative(infoContainer, 40, 0).on("pointerdown", () => {
|
||||
globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, {
|
||||
options: languageOptions,
|
||||
maxOptions: 7,
|
||||
@ -335,11 +383,12 @@ export class LoginFormUiHandler extends FormModalUiHandler {
|
||||
|
||||
private buildInteractableImage(texture: string, name: string, opts: BuildInteractableImageOpts = {}) {
|
||||
const { scale = 0.07, x = 0, y = 0, origin = { x: 0, y: 0 } } = opts;
|
||||
const img = globalScene.add.image(x, y, texture);
|
||||
img.setName(name);
|
||||
img.setOrigin(origin.x, origin.y);
|
||||
img.setScale(scale);
|
||||
img.setInteractive();
|
||||
const img = globalScene.add
|
||||
.image(x, y, texture)
|
||||
.setName(name)
|
||||
.setOrigin(origin.x, origin.y)
|
||||
.setScale(scale)
|
||||
.setInteractive();
|
||||
this.addInteractionHoverEffect(img);
|
||||
|
||||
return img;
|
||||
|
Loading…
Reference in New Issue
Block a user