diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index d58cf507..fd171178 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -81,6 +81,11 @@ "warning": "⚠️ Warning", "success": "🎉 Success" }, + "common":{ + "msg":{ + "error-occurred": "An error has occurred" + } + }, "shared":{ "errors":{ "titles":{ @@ -196,7 +201,44 @@ "CloningFinished": "Cloning complete 🎉" } } - } + }, + "mods":{ + "install-mods":{ + "titles":{ + "success": "Mods installed 🎉", + "warning": "Mods installed 🤔" + }, + "msg":{ + "success": "All mods have been installed.", + "warning": "One or more mods could not be installed.", + "errors":{ + "no-mods": "No mods to install.", + "cannot-install-bsipa": "BSIPA installation failed 😨" + } + } + }, + "uninstall-mod":{ + "titles":{ + "success": "Mod uninstalled 🎉" + }, + "msg":{ + "errors":{ + "no-mods": "This mod isn't installed 😑" + } + } + }, + "uninstall-all-mods":{ + "titles":{ + "success": "Mods uninstalled 🎉" + }, + "msg":{ + "success": "All mods have been uninstalled.", + "errors": { + "no-mods": "No mod is installed in this version 😑" + } + } + } + } }, "modals":{ "guard":{ diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index b8dff17f..3a7613a6 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -81,6 +81,11 @@ "warning": "⚠️ Advertencia", "success": "🎉 Éxito" }, + "common":{ + "msg":{ + "error-occurred": "Se ha producido un error" + } + }, "shared":{ "errors":{ "titles":{ @@ -196,7 +201,44 @@ "CloningFinished": "Clonación completa 🎉" } } - } + }, + "mods":{ + "install-mods":{ + "titles":{ + "success": "Mods instalados 🎉", + "warning": "Mods instalados 🤔" + }, + "msg":{ + "success": "Todos los mods han sido instalados.", + "warning": "No se han podido instalar uno o más mods.", + "errors":{ + "no-mods": "No hay que instalar mods.", + "cannot-install-bsipa": "La instalación de BSIPA falló 😨" + } + } + }, + "uninstall-mod":{ + "titles":{ + "success": "Mod desinstalado 🎉" + }, + "msg":{ + "errors":{ + "no-mods": "Este mod no está instalado 😑" + } + } + }, + "uninstall-all-mods":{ + "titles":{ + "success": "Mods desinstalados 🎉" + }, + "msg":{ + "success": "Todos los mods han sido desinstalados.", + "errors": { + "no-mods": "No se instala ningún mod en esta versión 😑" + } + } + } + } }, "modals":{ "guard":{ diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index cac929ae..2db2db14 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -81,6 +81,11 @@ "warning": "⚠️ Attention", "success": "🎉 Succès" }, + "common":{ + "msg":{ + "error-occurred": "Une erreur c'est produite" + } + }, "shared":{ "errors":{ "titles":{ @@ -196,7 +201,44 @@ "CloningFinished": "Clonage terminer 🎉" } } - } + }, + "mods":{ + "install-mods":{ + "titles":{ + "success": "Mods installés 🎉", + "warning": "Mods installés 🤔" + }, + "msg":{ + "success": "Tous les mods on été installés.", + "warning": "Un ou plusieurs mods n'ont pas pu être installés.", + "errors":{ + "no-mods": "Aucun mods à installer.", + "cannot-install-bsipa": "L'installation de BSIPA à échoué 😨" + } + } + }, + "uninstall-mod":{ + "titles":{ + "success": "Mod désintallé 🎉" + }, + "msg":{ + "errors":{ + "no-mods": "Ce mod n'est pas installé 😑" + } + } + }, + "uninstall-all-mods":{ + "titles":{ + "success": "Mods désintallés 🎉" + }, + "msg":{ + "success": "Tous les mods on été désintallés.", + "errors": { + "no-mods": "Aucun mod n'est installé dans dans cette version 😑" + } + } + } + } }, "modals":{ "guard":{ diff --git a/src/main/ipcs/bs-mods-ipcs.ts b/src/main/ipcs/bs-mods-ipcs.ts index 515c6219..6c69cd8b 100644 --- a/src/main/ipcs/bs-mods-ipcs.ts +++ b/src/main/ipcs/bs-mods-ipcs.ts @@ -4,6 +4,7 @@ import { UtilsService } from "../services/utils.service"; import { BSVersion } from "shared/bs-version.interface"; import { IpcRequest } from "shared/models/ipc"; import { Mod } from "shared/models/mods/mod.interface"; +import { InstallModsResult } from "shared/models/mods"; ipcMain.on("get-available-mods", (event, request: IpcRequest) => { const utils = UtilsService.getInstance(); @@ -28,7 +29,7 @@ ipcMain.on("install-mods", (event, request: IpcRequest<{mods: Mod[], version: BS const modsManager = BsModsManagerService.getInstance(); modsManager.installMods(request.args.mods, request.args.version).then(nbInstalled => { - utils.ipcSend(request.responceChannel, {success: true, data: nbInstalled}) + utils.ipcSend(request.responceChannel, {success: true, data: nbInstalled}) }).catch(err => { utils.ipcSend(request.responceChannel, {success: false, error: err}); }) diff --git a/src/main/services/mods/bs-mods-manager.service.ts b/src/main/services/mods/bs-mods-manager.service.ts index c516d4c7..b85767f6 100644 --- a/src/main/services/mods/bs-mods-manager.service.ts +++ b/src/main/services/mods/bs-mods-manager.service.ts @@ -1,5 +1,6 @@ import { BSVersion } from "shared/bs-version.interface"; -import { DownloadLink, Mod, ModInstallProgression } from "shared/models/mods/mod.interface";import { BeatModsApiService } from "./beat-mods-api.service"; +import { DownloadLink, InstallModsResult, Mod, ModInstallProgression, UninstallModsResult } from "shared/models/mods"; +import { BeatModsApiService } from "./beat-mods-api.service"; import { BSLocalVersionService } from "../bs-local-version.service" import path from "path"; import { UtilsService } from "../utils.service"; @@ -127,8 +128,7 @@ export class BsModsManagerService { private async installMod(mod: Mod, version: BSVersion): Promise{ - this.nbInstalledMods++; - this.utilsService.ipcSend("mod-installed", {success: true, data: {name: mod.name, progression: (this.nbInstalledMods / this.nbModsToInstall) * 100}}) + this.utilsService.ipcSend("mod-installed", {success: true, data: {name: mod.name, progression: ((this.nbInstalledMods + 1) / this.nbModsToInstall) * 100}}) const download = this.getModDownload(mod, version); @@ -154,9 +154,11 @@ export class BsModsManagerService { const isBSIPA = mod.name.toLowerCase() === "bsipa"; const destDir = isBSIPA ? verionPath : path.join(verionPath, ModsInstallFolder.PENDING); - await zip.extract(null, destDir).catch(err => console.log(err)); + const extracted = await zip.extract(null, destDir).then(() => true).catch(err => {return false}); - const res = isBSIPA ? await this.executeBSIPA(version, ["-n"]) : true; + const res = isBSIPA ? (await this.executeBSIPA(version, ["-n"]) && extracted) : extracted; + + res && this.nbInstalledMods++; return res; } @@ -239,8 +241,8 @@ export class BsModsManagerService { }); } - public async installMods(mods: Mod[], version: BSVersion): Promise{ - if(!mods){ throw "no-mod"; } + public async installMods(mods: Mod[], version: BSVersion): Promise{ + if(!mods || !mods.length){ throw "no-mods"; } const deps = await this.resolveDependencies(mods, version); mods.push(...deps); @@ -256,17 +258,18 @@ export class BsModsManagerService { if(!installed){ throw "cannot-install-bsipa"; } } - let nbInstalledMods = bsipa ? 1 : 0; - for(const mod of mods){ - await this.installMod(mod, version).then(installed => installed && nbInstalledMods++) + await this.installMod(mod, version); } - return nbInstalledMods; + return { + nbModsToInstall: this.nbModsToInstall, + nbInstalledMods: this.nbInstalledMods + }; } - public async uninstallMods(mods: Mod[], version: BSVersion): Promise{ - if(!mods){ throw "no-mod"; } + public async uninstallMods(mods: Mod[], version: BSVersion): Promise{ + if(!mods || !mods.length){ throw "no-mods"; } this.nbModsToUninstall = mods.length; this.nbUninstalledMods = 0; @@ -275,12 +278,17 @@ export class BsModsManagerService { await this.uninstallMod(mod, version); } - return this.nbUninstalledMods; + return { + nbModsToUninstall: this.nbModsToUninstall, + nbUninstalledMods: this.nbUninstalledMods + }; } - public async uninstallAllMods(version: BSVersion): Promise{ + public async uninstallAllMods(version: BSVersion): Promise{ const mods = await this.getInstalledMods(version); + if(!mods || !mods.length){ throw "no-mods"; } + this.nbModsToUninstall = mods.length; this.nbUninstalledMods = 0; @@ -294,7 +302,12 @@ export class BsModsManagerService { this.utilsService.rmDirIfExist(path.join(versionPath, ModsInstallFolder.LIBS)); this.utilsService.rmDirIfExist(path.join(versionPath, ModsInstallFolder.IPA)); - return this.nbUninstalledMods; + path.resolve + + return { + nbModsToUninstall: this.nbModsToUninstall, + nbUninstalledMods: this.nbUninstalledMods + }; } } diff --git a/src/renderer/services/bs-mods-manager.service.ts b/src/renderer/services/bs-mods-manager.service.ts index 9253b416..7f7ef89b 100644 --- a/src/renderer/services/bs-mods-manager.service.ts +++ b/src/renderer/services/bs-mods-manager.service.ts @@ -1,16 +1,19 @@ import { BehaviorSubject } from "rxjs"; import { map } from "rxjs/operators"; import { BSVersion } from "shared/bs-version.interface"; -import { Mod, ModInstallProgression } from "shared/models/mods/mod.interface"; +import { InstallModsResult, UninstallModsResult } from "shared/models/mods"; +import { Mod, ModInstallProgression } from "shared/models/mods"; import { IpcService } from "./ipc.service"; import { ModalExitCode, ModalService, ModalType } from "./modale.service"; -import { NotificationService } from "./notification.service"; +import { NotificationService, NotificationType } from "./notification.service"; import { ProgressBarService } from "./progress-bar.service"; export class BsModsManagerService { private static instance: BsModsManagerService; + private readonly NOTIFICATION_DURATION = 3000; + private readonly ipcService: IpcService; private readonly progressBar: ProgressBarService; private readonly modals: ModalService; @@ -46,8 +49,18 @@ export class BsModsManagerService { this.progressBar.show(progress$, true, {paddingLeft: "190px", paddingRight: "190px", bottom: "20px"}); this.isInstalling$.next(true); - return this.ipcService.send("install-mods", {args: {mods, version}}).then(res => { + return this.ipcService.send("install-mods", {args: {mods, version}}).then(res => { + if(res.success && res.data){ + const isFullyInstalled = res.data.nbInstalledMods === res.data.nbModsToInstall; + const title = `notifications.mods.install-mods.titles.${isFullyInstalled ? "success" : "warning"}`; + const desc = `notifications.mods.install-mods.msg.${isFullyInstalled ? "success" : "warning"}`; + + this.notifications.notify({type: isFullyInstalled ? NotificationType.SUCCESS : NotificationType.WARNING, title, desc, duration: this.NOTIFICATION_DURATION}); + } + else{ + this.notifications.notifyError({title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION}) + } this.isInstalling$.next(false); this.progressBar.hide(); }); @@ -65,6 +78,14 @@ export class BsModsManagerService { this.isUninstalling$.next(true); return this.ipcService.send("uninstall-mods", {args: {mods: [mod], version}}).then(res => { + + if(res.success){ + this.notifications.notifySuccess({title: "notifications.mods.uninstall-mod.titles.success", duration: this.NOTIFICATION_DURATION}) + } + else{ + this.notifications.notifyError({title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION}) + } + this.isUninstalling$.next(false); this.progressBar.hide(); }); @@ -82,7 +103,15 @@ export class BsModsManagerService { this.progressBar.show(progress$, true, {paddingLeft: "190px", paddingRight: "190px", bottom: "20px"}); this.isUninstalling$.next(true); - return this.ipcService.send("uninstall-all-mods", {args: version}).then(res => { + return this.ipcService.send("uninstall-all-mods", {args: version}).then(res => { + + if(res.success){ + this.notifications.notifySuccess({title: "notifications.mods.uninstall-all-mods.titles.success", desc: "notifications.mods.uninstall-all-mods.msg.success", duration: this.NOTIFICATION_DURATION}) + } + else{ + this.notifications.notifyError({title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION}) + } + this.isUninstalling$.next(false); this.progressBar.hide(); }); diff --git a/src/shared/models/mods/index.ts b/src/shared/models/mods/index.ts new file mode 100644 index 00000000..f8b92ee4 --- /dev/null +++ b/src/shared/models/mods/index.ts @@ -0,0 +1,2 @@ +export { ModInstallProgression, InstallModsResult, UninstallModsResult } from "./mod-ipc.model" +export { Mod, DownloadLink, DownloadLinkType, FileHashes, ModAuthor } from "./mod.interface" \ No newline at end of file diff --git a/src/shared/models/mods/mod-ipc.model.ts b/src/shared/models/mods/mod-ipc.model.ts new file mode 100644 index 00000000..a9a38ff1 --- /dev/null +++ b/src/shared/models/mods/mod-ipc.model.ts @@ -0,0 +1,14 @@ +export interface ModInstallProgression{ + name: string, + progression: number +} + +export interface InstallModsResult { + nbModsToInstall: number, + nbInstalledMods: number +} + +export interface UninstallModsResult { + nbModsToUninstall: number, + nbUninstalledMods: number +} \ No newline at end of file diff --git a/src/shared/models/mods/mod.interface.ts b/src/shared/models/mods/mod.interface.ts index b89d2f5a..8f325812 100644 --- a/src/shared/models/mods/mod.interface.ts +++ b/src/shared/models/mods/mod.interface.ts @@ -34,9 +34,4 @@ export type DownloadLinkType = "universal"|"steam"|"oculus"; export interface FileHashes { hash: string, file: string -} - -export interface ModInstallProgression{ - name: string, - progression: number } \ No newline at end of file