diff --git a/package-lock.json b/package-lock.json index 09ef1ae0..f62f5de8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7207,6 +7207,11 @@ "locate-path": "^3.0.0" } }, + "fitty": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/fitty/-/fitty-2.3.6.tgz", + "integrity": "sha512-ENp/+MqqYmXBGHC0dlltCX75+5zL5m0uiIGCgYdoThao99BrJpNYzEh3xrvhiy4b7O5X82CQT7dPTiB53H6stw==" + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -11320,6 +11325,14 @@ "scheduler": "^0.23.0" } }, + "react-fitty": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-fitty/-/react-fitty-1.0.1.tgz", + "integrity": "sha512-mO+Sbon+bO8Kazv38qu3uwi52vYDdty6P8fla91TkQEc2KwfZjNLT4j31cXix3ZTlBMWmavWAu5SfG6J9SpaFQ==", + "requires": { + "fitty": "2" + } + }, "react-icons": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.4.0.tgz", diff --git a/package.json b/package.json index 6913b5ca..3b775637 100644 --- a/package.json +++ b/package.json @@ -238,6 +238,7 @@ "react": "^18.2.0", "react-colorful": "^5.5.1", "react-dom": "^18.2.0", + "react-fitty": "^1.0.1", "react-icons": "^4.4.0", "react-outside-click-handler": "^1.3.0", "react-router-dom": "^6.3.0", diff --git a/src/main/ipcs/bs-version-ipcs.ts b/src/main/ipcs/bs-version-ipcs.ts index 1073c48d..01ae180e 100644 --- a/src/main/ipcs/bs-version-ipcs.ts +++ b/src/main/ipcs/bs-version-ipcs.ts @@ -9,6 +9,7 @@ import { BS_APP_ID } from '../constants'; import { IpcRequest } from 'shared/models/ipc'; import { BSLocalVersionService } from '../services/bs-local-version.service'; import { InstallationLocationService } from '../services/installation-location.service'; +import { BsmException } from 'shared/models/bsm-exception.model'; ipcMain.on('bs-version.get-version-dict', (event, req: IpcRequest) => { BSVersionLibService.getInstance().getAvailableVersions().then(versions => { @@ -31,3 +32,23 @@ ipcMain.on("bs-version.open-folder", async (event, req: IpcRequest) = const versionFolder = req.args.steam ? await SteamService.getInstance().getGameFolder(BS_APP_ID, "Beat Saber") : path.join(locationService.versionsDirectory, req.args.BSVersion); UtilsService.getInstance().folderExist(versionFolder) && exec(`start "" "${versionFolder}"`); }); + +ipcMain.on("bs-version.rename", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => { + BSLocalVersionService.getInstance().editVersion(req.args.version, req.args.name, req.args.color).then(res => { + console.log(res); + UtilsService.getInstance().ipcSend(req.responceChannel, {success: !!res, data: res}); + }).catch((error: BsmException) => { + UtilsService.getInstance().ipcSend(req.responceChannel, {success: false, error}); + console.log(error); + }); +}); + +ipcMain.on("bs-version.clone", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => { + BSLocalVersionService.getInstance().cloneVersion(req.args.version, req.args.name, req.args.color).then(res => { + console.log(res); + UtilsService.getInstance().ipcSend(req.responceChannel, {success: !!res, data: res}); + }).catch((error: BsmException) => { + UtilsService.getInstance().ipcSend(req.responceChannel, {success: false, error}); + console.log(error); + }); +}); diff --git a/src/main/services/bs-installer.service.ts b/src/main/services/bs-installer.service.ts index 422284d9..21937029 100644 --- a/src/main/services/bs-installer.service.ts +++ b/src/main/services/bs-installer.service.ts @@ -7,6 +7,7 @@ import { ChildProcessWithoutNullStreams, spawn } from "child_process"; import log from "electron-log"; import { InstallationLocationService } from "./installation-location.service"; import { ctrlc } from "ctrlc-windows"; +import { BSLocalVersionService } from "./bs-local-version.service"; export class BSInstallerService{ @@ -15,6 +16,7 @@ export class BSInstallerService{ private readonly utils: UtilsService; private readonly bsVersionService: BSVersionLibService; private readonly installLocationService: InstallationLocationService; + private readonly localVersionService: BSLocalVersionService; private downloadProcess: ChildProcessWithoutNullStreams; @@ -22,6 +24,7 @@ export class BSInstallerService{ this.bsVersionService = BSVersionLibService.getInstance(); this.utils = UtilsService.getInstance(); this.installLocationService = InstallationLocationService.getInstance(); + this.localVersionService = BSLocalVersionService.getInstance(); } public static getInstance(){ @@ -58,7 +61,7 @@ export class BSInstallerService{ public async downloadBsVersion(downloadInfos: DownloadInfo): Promise{ if(this.downloadProcess && !this.downloadProcess?.killed){ console.log("*** AlreadyDownloading ***"); return {type: "[AlreadyDownloading]"}; } - const bsVersion = this.bsVersionService.getVersionDetails(downloadInfos.bsVersion.BSVersion); + const bsVersion = downloadInfos.bsVersion; if(!bsVersion){ return {type: "[Error]"}; } this.utils.createFolderIfNotExist(this.installLocationService.versionsDirectory); @@ -69,7 +72,7 @@ export class BSInstallerService{ `-depot ${BS_DEPOT}`, `-manifest ${bsVersion.BSManifest}`, `-username ${downloadInfos.username}`, - `-dir ${bsVersion.BSVersion}`, + `-dir \"${this.localVersionService.getVersionFolder(bsVersion)}\"`, (downloadInfos.stay || !downloadInfos.password) && "-remember-password" ], {shell: true, cwd: this.installLocationService.versionsDirectory} diff --git a/src/main/services/bs-local-version.service.ts b/src/main/services/bs-local-version.service.ts index 814ced44..5047c35e 100644 --- a/src/main/services/bs-local-version.service.ts +++ b/src/main/services/bs-local-version.service.ts @@ -7,15 +7,22 @@ import { BS_APP_ID } from "../constants"; import path from "path"; import { createInterface } from "readline"; import { createReadStream } from "fs"; +import fs from "fs-extra"; +import { ConfigurationService } from "./configuration.service"; +import { rename } from "fs/promises"; +import { BsmException } from "shared/models/bsm-exception.model"; export class BSLocalVersionService{ private static instance: BSLocalVersionService; + private readonly CUSTOM_VERSIONS_KEY = "custom-versions"; + private readonly installLocationService: InstallationLocationService; private readonly utilsService: UtilsService; private readonly steamService: SteamService; private readonly remoteVersionService: BSVersionLibService; + private readonly configService: ConfigurationService; public static getInstance(): BSLocalVersionService{ if(!BSLocalVersionService.instance){ BSLocalVersionService.instance = new BSLocalVersionService(); } @@ -27,6 +34,7 @@ export class BSLocalVersionService{ this.utilsService = UtilsService.getInstance(); this.steamService = SteamService.getInstance(); this.remoteVersionService = BSVersionLibService.getInstance(); + this.configService = ConfigurationService.getInstance(); } private async getVersionOfBSFolder(bsPath: string): Promise{ @@ -48,6 +56,40 @@ export class BSLocalVersionService{ }) } + private setCustomVersions(versions: BSVersion[]): void{ + this.configService.set(this.CUSTOM_VERSIONS_KEY, versions); + } + + private addCustomVersion(version: BSVersion): void{ + this.setCustomVersions([...this.getCustomVersions() ?? [], version]); + } + + private getCustomVersions(): BSVersion[]{ + return this.configService.get(this.CUSTOM_VERSIONS_KEY); + } + + private deleteCustomVersion(version: BSVersion): void{ + const customVersions = this.getCustomVersions() || []; + this.setCustomVersions(customVersions.filter(v => (v.name !== version.name || v.BSVersion !== version.BSVersion || v.color !== version.color))); + } + + private async getVersionPath(version: BSVersion): Promise{ + if(version.steam){ return await this.steamService.getGameFolder(BS_APP_ID, "Beat Saber") } + return path.join( + this.installLocationService.versionsDirectory, + this.getVersionFolder(version) + ); + } + + private removeSpecialChar(seq: string): string{ + return seq.replace( /[<>:"\/\\|?*]+/g, '' ); + } + + public getVersionFolder(version: BSVersion){ + console.log(version.name ? `${version.BSVersion}-${version.name}` : version.BSVersion) + return version.name ? `${version.BSVersion}-${version.name}` : version.BSVersion; + } + public async getInstalledVersions(): Promise{ const versions: BSVersion[] = []; const steamBsFolder = await this.steamService.getGameFolder(BS_APP_ID, "Beat Saber") @@ -64,15 +106,24 @@ export class BSLocalVersionService{ const folderInInstallation = this.utilsService.listDirsInDir(this.installLocationService.versionsDirectory); folderInInstallation.forEach(f => { - const version = this.remoteVersionService.getVersionDetails(f); - versions.push(version); - }) + let version = this.remoteVersionService.getVersionDetails(f); + if(version){ version = this.getCustomVersions().find(v => v.BSVersion === version.BSVersion && v.name === version.name) ?? version; } + else { version = this.getCustomVersions().find(v => { + const [version, ...rest] = f.split("-"); + if(rest.length < 1){ return false; } + const name = rest.join("-"); + return name === v.name && version === v.BSVersion; + }) + } + version && versions.push(version); + }); + this.setCustomVersions(versions.filter(v => !!v.name || !!v.color)); return versions; } public async deleteVersion(version: BSVersion): Promise{ if(version.steam){ return false; } - const versionFolder = path.join(this.installLocationService.versionsDirectory, version.BSVersion); + const versionFolder = await this.getVersionPath(version); if(!this.utilsService.folderExist(versionFolder)){ return true; } return this.utilsService.deleteFolder(versionFolder) @@ -80,8 +131,51 @@ export class BSLocalVersionService{ .catch(() => { return false; }) } - public cloneVersion(version: BSVersion, name: string): boolean{ - return true; + public async editVersion(version: BSVersion, name: string, color: string): Promise{ + if(version.steam){ throw {title: "CantEditSteam"} as BsmException; } + const oldPath = await this.getVersionPath(version); + const editedVersion: BSVersion = version.BSVersion === name + ? {...version, name: undefined, color} + : {...version, name: this.removeSpecialChar(name), color}; + const newPath = await this.getVersionPath(editedVersion); + + if(oldPath === newPath){ + this.deleteCustomVersion(version); + this.addCustomVersion(editedVersion); + return editedVersion; + } + + if(this.utilsService.pathExist(newPath)){ throw {title: "VersionAlreadExist"} as BsmException; } + + return rename(oldPath, newPath).then(() => { + this.deleteCustomVersion(version); + this.addCustomVersion(editedVersion); + return editedVersion; + }).catch((err: Error) => { + throw {title: "CantRename", error: err} as BsmException; + }); + } + + public async cloneVersion(version: BSVersion, name: string, color: string): Promise{ + const originPath = await this.getVersionPath(version); + const cloneVersion: BSVersion = version.BSVersion === name + ? {...version, name: undefined, color} + : {...version, name: this.removeSpecialChar(name), color}; + const newPath = await this.getVersionPath(cloneVersion); + + if(originPath === newPath){ + this.deleteCustomVersion(version); + this.addCustomVersion(cloneVersion); + return cloneVersion; + } + + return fs.copy(originPath, newPath).then(() => { + this.deleteCustomVersion(version); + this.addCustomVersion(cloneVersion); + return cloneVersion; + }).catch((err: Error) => { + throw {title: "CantClone", error: err} as BsmException + }) } } \ No newline at end of file diff --git a/src/main/services/configuration.service.ts b/src/main/services/configuration.service.ts index 20055090..1aa2d540 100644 --- a/src/main/services/configuration.service.ts +++ b/src/main/services/configuration.service.ts @@ -21,8 +21,8 @@ export class ConfigurationService { this.store.set(key, value); } - public get(key: string): any{ - return this.store.get(key); + public get(key: string): T{ + return this.store.get(key) as T; } public delete(key: string): void{ diff --git a/src/renderer/components/modal/modal-types/edit-version-modal.component.tsx b/src/renderer/components/modal/modal-types/edit-version-modal.component.tsx new file mode 100644 index 00000000..be746319 --- /dev/null +++ b/src/renderer/components/modal/modal-types/edit-version-modal.component.tsx @@ -0,0 +1,58 @@ +import { useState } from "react"; +import SettingColorChooser from "renderer/components/settings/setting-color-chooser.component"; +import { BsmButton } from "renderer/components/shared/bsm-button.component"; +import { BsmIcon } from "renderer/components/svgs/bsm-icon.component"; +import { DefaultConfigKey } from "renderer/config/default-configuration.config"; +import { useTranslation } from "renderer/hooks/use-translation.hook"; +import { ConfigurationService } from "renderer/services/configuration.service"; +import { ModalExitCode, ModalResponse, ModalService } from "renderer/services/modale.service"; +import { BSVersion } from "shared/bs-version.interface"; + +export function EditVersionModal({resolver, clone = false}: {resolver: (x: ModalResponse<{name: string, color: string}>) => void, clone?: boolean}) { + + const configService = ConfigurationService.getInstance(); + const modalService = ModalService.getInsance(); + + const modalData: BSVersion = modalService.getModalData(); + + const [name, setName] = useState(modalData.name || modalData.BSVersion); + const [color, setColor] = useState(modalData.color ?? configService.get("second-color" as DefaultConfigKey)); + const t = useTranslation(); + + const rename = () => { + if(!name){ return; } + resolver({exitCode: ModalExitCode.COMPLETED, data: {name, color}}) + } + + const resetColor = () => { + setColor(configService.get("second-color" as DefaultConfigKey)) + } + + return ( +
{e.preventDefault(); rename();}}> +

{t(!clone ? "Editer la version" : "Cloner_la_version")}

+ + { clone && ( +

Cloner la version te permet de séparer le contenu additionnel de BeatSaber entre deux même versions

+ )} +
+ + setName(e.target.value)} value={name} type="text" name="name" id="name" minLength={2} maxLength={15} placeholder={t("Nom de la version")}/> +
+
+ Couleur +
+ +
+ +
+
+
+
+ {resolver({exitCode: ModalExitCode.CANCELED})}} withBar={false} text="misc.cancel"/> + +
+ + ) +} + diff --git a/src/renderer/components/modal/modal.component.tsx b/src/renderer/components/modal/modal.component.tsx index cd8aa9af..ddffd326 100644 --- a/src/renderer/components/modal/modal.component.tsx +++ b/src/renderer/components/modal/modal.component.tsx @@ -7,6 +7,7 @@ import { LoginModal } from "./modal-types/login-modal.component"; import { GuardModal } from "./modal-types/guard-modal.component"; import { UninstallModal } from "./modal-types/uninstall-modal.component"; import { InstallationFolderModal } from "./modal-types/installation-folder-modal.component"; +import { EditVersionModal } from "./modal-types/edit-version-modal.component"; export function Modal() { @@ -41,6 +42,8 @@ export function Modal() { {modalType === ModalType.GUARD_CODE && } {modalType === ModalType.UNINSTALL && } {modalType === ModalType.INSTALLATION_FOLDER && } + {modalType === ModalType.EDIT_VERSION && } + {modalType === ModalType.CLONE_VERSION && } diff --git a/src/renderer/components/nav-bar/bs-version-item.component.tsx b/src/renderer/components/nav-bar/bs-version-item.component.tsx index ba13d588..1f450692 100644 --- a/src/renderer/components/nav-bar/bs-version-item.component.tsx +++ b/src/renderer/components/nav-bar/bs-version-item.component.tsx @@ -2,29 +2,32 @@ import { BSVersion } from 'shared/bs-version.interface'; import { Link, useLocation } from "react-router-dom"; import { BsDownloaderService } from "renderer/services/bs-downloader.service"; import { useEffect, useState } from "react"; -import { combineLatest } from "rxjs"; +import { combineLatest, Subscription } from "rxjs"; import { BSLauncherService, LaunchMods } from "renderer/services/bs-launcher.service"; import { ConfigurationService } from "renderer/services/configuration.service"; import { BsmButton } from "../shared/bsm-button.component"; import { BSUninstallerService } from "renderer/services/bs-uninstaller.service"; import { BSVersionManagerService } from "renderer/services/bs-version-manager.service"; import { BsmIcon } from "../svgs/bsm-icon.component"; +import { ReactFitty } from "react-fitty"; +import { DefaultConfigKey } from 'renderer/config/default-configuration.config'; export function BsVersionItem(props: {version: BSVersion}) { - const { state } = useLocation() as { state: BSVersion}; - - const [downloading, setDownloading] = useState(true); - const [downloadPercent, setDownloadPercent] = useState(0); - const downloaderService = BsDownloaderService.getInstance(); const verionManagerService = BSVersionManagerService.getInstance(); const launcherService = BSLauncherService.getInstance(); const configService = ConfigurationService.getInstance(); const bsUninstallerService = BSUninstallerService.getInstance(); + const { state } = useLocation() as { state: BSVersion}; + + const [downloading, setDownloading] = useState(false); + const [downloadPercent, setDownloadPercent] = useState(0); + const [color, setColor] = useState(""); + const isActive = (): boolean => { - return props.version?.BSVersion === state?.BSVersion && props?.version.steam === state?.steam; + return props.version?.BSVersion === state?.BSVersion && props?.version.steam === state?.steam && props?.version.name === state?.name; } const handleDoubleClick = () => { @@ -46,28 +49,39 @@ export function BsVersionItem(props: {version: BSVersion}) { }); } - useEffect(() => { - combineLatest([downloaderService.currentBsVersionDownload$, downloaderService.downloadProgress$]).subscribe(vals => { - if(vals[0]?.BSVersion === props.version.BSVersion && vals[0]?.steam === props.version.steam){ - setDownloading(true); - setDownloadPercent(vals[1]); - } + useEffect(() => { + const subs: Subscription[] = []; + const downloadSub = combineLatest([downloaderService.currentBsVersionDownload$, downloaderService.downloadProgress$]).subscribe(vals => { + if(vals[0]?.BSVersion === props.version.BSVersion && vals[0]?.steam === props.version.steam && vals[0]?.name === props.version.name){ + setDownloading(true); + setDownloadPercent(vals[1]); + } + else{ + setDownloading(false); + setDownloadPercent(0); + } + }); + subs.push(downloadSub); + if(props.version?.color){ setColor(props.version.color); } else{ - setDownloading(false); - setDownloadPercent(0); + const colorSub = configService.watch("second-color" as DefaultConfigKey).subscribe(color => setColor(color)); + subs.push(colorSub); } - }) + + return () => { subs.forEach(s => s.unsubscribe()); } }, []); return ( -
+
-
- - {props.version.steam && } - {!props.version.steam && } - {props.version.BSVersion} +
+ + {props.version.steam && } + {!props.version.steam && } +
+ {props.version.name || props.version.BSVersion} +
{downloading && }
diff --git a/src/renderer/components/nav-bar/nav-bar.component.tsx b/src/renderer/components/nav-bar/nav-bar.component.tsx index 353ccc3f..f7aa4ba8 100644 --- a/src/renderer/components/nav-bar/nav-bar.component.tsx +++ b/src/renderer/components/nav-bar/nav-bar.component.tsx @@ -24,7 +24,7 @@ export function NavBar() {
-
+
{installedVersions && installedVersions.map((version) => )}
diff --git a/src/renderer/components/settings/setting-color-chooser.component.tsx b/src/renderer/components/settings/setting-color-chooser.component.tsx index 8272eae6..9f5e7337 100644 --- a/src/renderer/components/settings/setting-color-chooser.component.tsx +++ b/src/renderer/components/settings/setting-color-chooser.component.tsx @@ -3,7 +3,7 @@ import { HexColorPicker } from "react-colorful"; import { motion, AnimatePresence } from "framer-motion" import OutsideClickHandler from "react-outside-click-handler"; -export default function SettingColorChooser({color, onChange}: {color?: string, onChange?: (color: string) => void}) { +export default function SettingColorChooser({color, onChange, pickerClassName}: {color?: string, onChange?: (color: string) => void, pickerClassName?: string}) { const [colorVisible, setColorVisible] = useState(false); @@ -13,9 +13,9 @@ export default function SettingColorChooser({color, onChange}: {color?: string, setColorVisible(!colorVisible)} style={{backgroundColor: color}}/> {colorVisible && - +
- +
}
diff --git a/src/renderer/components/shared/bsm-button.component.tsx b/src/renderer/components/shared/bsm-button.component.tsx index b0950461..09f190f7 100644 --- a/src/renderer/components/shared/bsm-button.component.tsx +++ b/src/renderer/components/shared/bsm-button.component.tsx @@ -12,7 +12,7 @@ export function BsmButton({className, style, imgClassName, icon, image, text, ty return ( onClickOutside && onClickOutside(e)}> -
onClick && onClick(e)} className={`${className} overflow-hidden cursor-pointer group ${disabled && "brightness-75 cursor-not-allowed"} ${typeColor == "error" && 'bg-red-500'}`} style={style}> +
onClick && onClick(e)} className={`${className} overflow-hidden cursor-pointer group ${disabled && "brightness-75 cursor-not-allowed"} ${typeColor === "error" && 'bg-red-500'} ${typeColor == "primary" && 'bg-blue-500'}`} style={style}> { image && } { icon && } {text && (type === "submit" ? : {t(text)})} diff --git a/src/renderer/pages/version-viewer.component.tsx b/src/renderer/pages/version-viewer.component.tsx index 94123e31..797388eb 100644 --- a/src/renderer/pages/version-viewer.component.tsx +++ b/src/renderer/pages/version-viewer.component.tsx @@ -40,9 +40,12 @@ export function VersionViewer() { setOculusMode(!!configService.get(LaunchMods.OCULUS_MOD)); setDesktopMode(!!configService.get(LaunchMods.DESKTOP_MOD)); setDebugMode(!!configService.get(LaunchMods.DEBUG_MOD)); - }, []) - + }, []); + const navigateToVersion = (version: BSVersion) => { + navigate(`/bs-version/${version.BSVersion}`, {state: version}); + } + const setMode = (mode: LaunchMods, value: boolean) => { if(mode === LaunchMods.DEBUG_MOD){ setDebugMode(value); } else if(mode === LaunchMods.OCULUS_MOD){ @@ -58,26 +61,22 @@ export function VersionViewer() { configService.set(mode, value); } - const dropDownActions = async (id: number) => { - if(id === 4){ + const openFolder = () => { + ipcService.sendLazy("bs-version.open-folder", {args: state}); + } + + const uninstall = async () => { const modalCompleted = await modalService.openModal(ModalType.UNINSTALL, state) if(modalCompleted.exitCode === ModalExitCode.COMPLETED){ bsUninstallerService.uninstall(state) .then(() => { bsVersionManagerService.askInstalledVersions(); const newVersionPage = bsVersionManagerService.getInstalledVersions()[0]; - navigate("/bs-version/"+newVersionPage.BSVersion, {state: newVersionPage}); + navigateToVersion(newVersionPage); }) .catch((e) => {console.log("*** ", e)}) } - } - else if(id === 2){ - verifyFiles(); - } - else if(id === 1){ - ipcService.sendLazy("bs-version.open-folder", {args: state}); - } - } + } const verifyFiles = () => { bsDownloaderService.download(state, true); @@ -87,12 +86,26 @@ export function VersionViewer() { bsLauncherService.launch(state, oculusMode, desktopMode, debugMode); } + const edit = () => { + bsVersionManagerService.editVersion(state).then(newVersion => { + if(!newVersion){ return; } + navigateToVersion(newVersion); + }); + } + + const clone = () => { + bsVersionManagerService.cloneVersion(state).then(newVersion => { + if(!newVersion){ return; } + navigateToVersion(newVersion); + }); + } + return ( <>
-

{state.BSVersion}

+

{state.name ? `${state.BSVersion} - ${state.name}` : state.BSVersion}

setCurrentTabIndex(i)}/>
@@ -119,11 +132,12 @@ export function VersionViewer() {
- ) diff --git a/src/renderer/services/bs-version-manager.service.ts b/src/renderer/services/bs-version-manager.service.ts index 97a15e37..7323c0ff 100644 --- a/src/renderer/services/bs-version-manager.service.ts +++ b/src/renderer/services/bs-version-manager.service.ts @@ -1,18 +1,24 @@ import { BSVersion } from 'shared/bs-version.interface'; import { BehaviorSubject } from "rxjs"; import { IpcService } from "./ipc.service"; +import { ModalExitCode, ModalService, ModalType } from './modale.service'; +import { NotificationService } from './notification.service'; export class BSVersionManagerService { private static instance: BSVersionManagerService; - public readonly ipcService: IpcService; + private readonly ipcService: IpcService; + private readonly modalService: ModalService; + private readonly notificationService: NotificationService; public readonly installedVersions$: BehaviorSubject = new BehaviorSubject([]); public readonly availableVersions$: BehaviorSubject = new BehaviorSubject([]); private constructor(){ this.ipcService = IpcService.getInstance(); + this.modalService = ModalService.getInsance(); + this.notificationService = NotificationService.getInstance(); this.askAvailableVersions(); this.askInstalledVersions(); } @@ -28,7 +34,7 @@ export class BSVersionManagerService { if(steamIndex > 0){ [sorted[0], sorted[steamIndex]] = [sorted[steamIndex], sorted[0]]; } - const cleanedSort = [...new Map(sorted.map(version => [`${version.BSVersion}-${version.steam}`, version])).values()] + const cleanedSort = [...new Map(sorted.map(version => [`${version.BSVersion}-${version.name}-${version.steam}`, version])).values()] this.installedVersions$.next(cleanedSort); } @@ -56,4 +62,32 @@ export class BSVersionManagerService { return this.availableVersions$.value.filter(v => v.year === year).sort((a, b) => +b.ReleaseDate - +a.ReleaseDate); } + public async editVersion(version: BSVersion): Promise{ + const modalRes = await this.modalService.openModal<{name: string, color: string}>(ModalType.EDIT_VERSION, version); + if(modalRes.exitCode !== ModalExitCode.COMPLETED){ return null; } + if(modalRes.data.name?.length < 2){ return null; } + return this.ipcService.send("bs-version.rename", {args: {version, name: modalRes.data.name, color: modalRes.data.color}}).then(res => { + if(!res.success){ + this.notificationService.notifyError({title: res.error.title}); + return null; + } + this.askInstalledVersions(); + return res.data; + }); + } + + public async cloneVersion(version: BSVersion): Promise{ + const modalRes = await this.modalService.openModal<{name: string, color: string}>(ModalType.CLONE_VERSION, version); + if(modalRes.exitCode !== ModalExitCode.COMPLETED){ return null; } + if(modalRes.data.name?.length < 2){ return null; } + return this.ipcService.send("bs-version.clone", {args: {version, name: modalRes.data.name, color: modalRes.data.color}}).then(res => { + if(!res.success){ + this.notificationService.notifyError({title: res.error.title}); + return null; + } + this.askInstalledVersions(); + return res.data; + }) + } + } diff --git a/src/shared/bs-version.interface.ts b/src/shared/bs-version.interface.ts index 81bcfefc..b8155fdb 100644 --- a/src/shared/bs-version.interface.ts +++ b/src/shared/bs-version.interface.ts @@ -5,5 +5,7 @@ export interface BSVersion { ReleaseImg?: string, ReleaseDate?: string, year?: string, - steam?: boolean + steam?: boolean, + name?: string, + color?: string } \ No newline at end of file