[Feature] Add save download functionality with JSZip integration (#4945)

This commit is contained in:
Frederico Santos 2024-11-28 01:01:48 +00:00 committed by GitHub
parent 4c8a18690e
commit 8f053ea16f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 126 additions and 1 deletions

87
package-lock.json generated
View File

@ -16,6 +16,7 @@
"i18next-http-backend": "^2.6.1", "i18next-http-backend": "^2.6.1",
"i18next-korean-postposition-processor": "^1.0.0", "i18next-korean-postposition-processor": "^1.0.0",
"json-stable-stringify": "^1.1.0", "json-stable-stringify": "^1.1.0",
"jszip": "^3.10.1",
"phaser": "^3.70.0", "phaser": "^3.70.0",
"phaser3-rex-plugins": "^1.1.84" "phaser3-rex-plugins": "^1.1.84"
}, },
@ -2723,6 +2724,11 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/cross-fetch": { "node_modules/cross-fetch": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
@ -4045,6 +4051,11 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -4072,6 +4083,11 @@
"node": ">=0.8.19" "node": ">=0.8.19"
} }
}, },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/ini": { "node_modules/ini": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz",
@ -4481,6 +4497,17 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@ -4648,6 +4675,14 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/linkify-it": { "node_modules/linkify-it": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
@ -5237,6 +5272,11 @@
"dev": true, "dev": true,
"license": "BlueOak-1.0.0" "license": "BlueOak-1.0.0"
}, },
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"node_modules/papaparse": { "node_modules/papaparse": {
"version": "5.4.1", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz",
@ -5485,6 +5525,11 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/prompts": { "node_modules/prompts": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@ -5551,6 +5596,25 @@
} }
] ]
}, },
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/readable-stream/node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"node_modules/rechoir": { "node_modules/rechoir": {
"version": "0.8.0", "version": "0.8.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
@ -5741,6 +5805,11 @@
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }
}, },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/safe-regex": { "node_modules/safe-regex": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz",
@ -5800,6 +5869,11 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -5917,6 +5991,14 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/string-width": { "node_modules/string-width": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
@ -6473,6 +6555,11 @@
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
} }
}, },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.8", "version": "5.4.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",

View File

@ -55,6 +55,7 @@
"i18next-http-backend": "^2.6.1", "i18next-http-backend": "^2.6.1",
"i18next-korean-postposition-processor": "^1.0.0", "i18next-korean-postposition-processor": "^1.0.0",
"json-stable-stringify": "^1.1.0", "json-stable-stringify": "^1.1.0",
"jszip": "^3.10.1",
"phaser": "^3.70.0", "phaser": "^3.70.0",
"phaser3-rex-plugins": "^1.1.84" "phaser3-rex-plugins": "^1.1.84"
}, },

View File

@ -8,6 +8,7 @@ import { addTextObject, TextStyle } from "./text";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import JSZip from "jszip";
interface BuildInteractableImageOpts { interface BuildInteractableImageOpts {
scale?: number; scale?: number;
@ -27,6 +28,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
private googleImage: Phaser.GameObjects.Image; private googleImage: Phaser.GameObjects.Image;
private discordImage: Phaser.GameObjects.Image; private discordImage: Phaser.GameObjects.Image;
private usernameInfoImage: Phaser.GameObjects.Image; private usernameInfoImage: Phaser.GameObjects.Image;
private saveDownloadImage: Phaser.GameObjects.Image;
private externalPartyContainer: Phaser.GameObjects.Container; private externalPartyContainer: Phaser.GameObjects.Container;
private infoContainer: Phaser.GameObjects.Container; private infoContainer: Phaser.GameObjects.Container;
private externalPartyBg: Phaser.GameObjects.NineSlice; private externalPartyBg: Phaser.GameObjects.NineSlice;
@ -46,7 +48,13 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
scale: 0.5 scale: 0.5
}); });
this.saveDownloadImage = this.buildInteractableImage("saving_icon", "save-download-icon", {
x: 0,
scale: 0.75
});
this.infoContainer.add(this.usernameInfoImage); this.infoContainer.add(this.usernameInfoImage);
this.infoContainer.add(this.saveDownloadImage);
this.getUi().add(this.infoContainer); this.getUi().add(this.infoContainer);
this.infoContainer.setVisible(false); this.infoContainer.setVisible(false);
this.infoContainer.disableInteractive(); this.infoContainer.disableInteractive();
@ -160,7 +168,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
this.infoContainer.setVisible(false); this.infoContainer.setVisible(false);
this.setMouseCursorStyle("default"); //reset cursor this.setMouseCursorStyle("default"); //reset cursor
[ this.discordImage, this.googleImage, this.usernameInfoImage ].forEach((img) => img.off("pointerdown")); [ this.discordImage, this.googleImage, this.usernameInfoImage, this.saveDownloadImage ].forEach((img) => img.off("pointerdown"));
} }
private processExternalProvider(config: ModalConfig): void { private processExternalProvider(config: ModalConfig): void {
@ -178,6 +186,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
this.infoContainer.setVisible(true); this.infoContainer.setVisible(true);
this.getUi().moveTo(this.infoContainer, this.getUi().length - 1); this.getUi().moveTo(this.infoContainer, this.getUi().length - 1);
this.usernameInfoImage.setPositionRelative(this.infoContainer, 0, 0); this.usernameInfoImage.setPositionRelative(this.infoContainer, 0, 0);
this.saveDownloadImage.setPositionRelative(this.infoContainer, 20, 0);
this.discordImage.on("pointerdown", () => { this.discordImage.on("pointerdown", () => {
const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`); const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`);
@ -229,6 +238,34 @@ export default class LoginFormUiHandler extends FormModalUiHandler {
} }
}); });
this.saveDownloadImage.on("pointerdown", () => {
// 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) {
const zip = new JSZip();
for (let i = 0; i < dataKeys.length; i++) {
zip.file(dataKeys[i], localStorage.getItem(dataKeys[i])!);
}
for (let i = 0; i < sessionKeys.length; i++) {
zip.file(sessionKeys[i], localStorage.getItem(sessionKeys[i])!);
}
zip.generateAsync({ type: "blob" }).then(content => {
const url = URL.createObjectURL(content);
const a = document.createElement("a");
a.href = url;
a.download = "pokerogue_saves.zip";
a.click();
URL.revokeObjectURL(url);
});
} else {
return onFail(this.ERR_NO_SAVES);
}
});
this.externalPartyContainer.setAlpha(0); this.externalPartyContainer.setAlpha(0);
this.scene.tweens.add({ this.scene.tweens.add({
targets: this.externalPartyContainer, targets: this.externalPartyContainer,