From 501c0d9ae1e9e2a38e9d86dac4741a4056a47c59 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 29 Sep 2024 18:29:59 +0200 Subject: [PATCH 1/2] [chore] Some reworks to remove watch functions --- src/main/ipcs/bs-maps-ipcs.ts | 5 + src/main/ipcs/bs-mods-ipcs.ts | 6 +- src/main/ipcs/launcher-ipcs.ts | 2 +- .../maps/local-maps-manager.service.ts | 13 +- src/main/services/auto-updater.service.ts | 62 ++++--- .../services/mods/bs-mods-manager.service.ts | 151 ++++++++-------- .../maps/local-maps-list-panel.component.tsx | 14 +- .../download-maps-modal.component.tsx | 9 +- .../slides/mods/mod-item.component.tsx | 32 ++-- .../slides/mods/mods-grid.component.tsx | 40 +++-- .../slides/mods/mods-slide.component.tsx | 46 +++-- src/renderer/services/auto-updater.service.ts | 26 +-- .../services/bs-mods-manager.service.ts | 168 +++++++++--------- .../services/maps-downloader.service.ts | 30 ++-- src/renderer/windows/Launcher.tsx | 14 +- src/shared/models/ipc/ipc-routes.ts | 11 +- 16 files changed, 335 insertions(+), 294 deletions(-) diff --git a/src/main/ipcs/bs-maps-ipcs.ts b/src/main/ipcs/bs-maps-ipcs.ts index 0991ab1c..039a4465 100644 --- a/src/main/ipcs/bs-maps-ipcs.ts +++ b/src/main/ipcs/bs-maps-ipcs.ts @@ -27,6 +27,11 @@ ipc.on("download-map", async (args, reply) => { reply(from(maps.downloadMap(args.map, args.version))); }); +ipc.on("last-downloaded-map", (_, reply) => { + const maps = LocalMapsManagerService.getInstance(); + reply(maps.lastDownloadedMap$); +}) + ipc.on("one-click-install-map", (args, reply) => { const maps = LocalMapsManagerService.getInstance(); reply(from(maps.oneClickDownloadMap(args))) diff --git a/src/main/ipcs/bs-mods-ipcs.ts b/src/main/ipcs/bs-mods-ipcs.ts index 7d580f04..f53869a8 100644 --- a/src/main/ipcs/bs-mods-ipcs.ts +++ b/src/main/ipcs/bs-mods-ipcs.ts @@ -16,15 +16,15 @@ ipc.on("get-installed-mods", (args, reply) => { ipc.on("install-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - reply(from(modsManager.installMods(args.mods, args.version))); + reply(modsManager.installMods(args.mods, args.version)); }); ipc.on("uninstall-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - reply(from(modsManager.uninstallMods(args.mods, args.version))); + reply(modsManager.uninstallMods(args.mods, args.version)); }); ipc.on("uninstall-all-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - reply(from(modsManager.uninstallAllMods(args))); + reply(modsManager.uninstallAllMods(args)); }); diff --git a/src/main/ipcs/launcher-ipcs.ts b/src/main/ipcs/launcher-ipcs.ts index 02fa1bfb..1091cbf7 100644 --- a/src/main/ipcs/launcher-ipcs.ts +++ b/src/main/ipcs/launcher-ipcs.ts @@ -6,7 +6,7 @@ const ipc = IpcService.getInstance(); ipc.on("download-update", (_, reply) => { const updaterService = AutoUpdaterService.getInstance(); - reply(from(updaterService.downloadUpdate())); + reply(updaterService.downloadUpdate()); }); ipc.on("check-update", (_, reply) => { diff --git a/src/main/services/additional-content/maps/local-maps-manager.service.ts b/src/main/services/additional-content/maps/local-maps-manager.service.ts index c29afe15..03977a9b 100644 --- a/src/main/services/additional-content/maps/local-maps-manager.service.ts +++ b/src/main/services/additional-content/maps/local-maps-manager.service.ts @@ -14,7 +14,7 @@ import sanitize from "sanitize-filename"; import { DeepLinkService } from "../../deep-link.service"; import log from "electron-log"; import { WindowManagerService } from "../../window-manager.service"; -import { Observable, lastValueFrom } from "rxjs"; +import { Observable, Subject, lastValueFrom } from "rxjs"; import { Archive } from "../../../models/archive.class"; import { Progression, deleteFolder, ensureFolderExist, getFilesInFolder, getFoldersInFolder, pathExist } from "../../../helpers/fs.helpers"; import { readFile } from "fs/promises"; @@ -23,7 +23,6 @@ import { allSettled } from "../../../../shared/helpers/promise.helpers"; import { splitIntoChunk } from "../../../../shared/helpers/array.helpers"; import { SongDetailsCacheService } from "./song-details-cache.service"; import { SongCacheService } from "./song-cache.service"; -import { IpcService } from "../../ipc.service"; import { pathToFileURL } from "url"; import { sToMs } from "../../../../shared/helpers/time.helpers"; import { FieldRequired } from "shared/helpers/type.helpers"; @@ -57,7 +56,8 @@ export class LocalMapsManagerService { private readonly linker: FolderLinkerService; private readonly songDetailsCache: SongDetailsCacheService; private readonly songCache: SongCacheService; - private readonly ipc: IpcService; + + private readonly _lastDownloadedMap = new Subject<{ map: BsmLocalMap, version?: BSVersion }>(); private constructor() { this.localVersion = BSLocalVersionService.getInstance(); @@ -69,7 +69,6 @@ export class LocalMapsManagerService { this.linker = FolderLinkerService.getInstance(); this.songDetailsCache = SongDetailsCacheService.getInstance(); this.songCache = SongCacheService.getInstance(); - this.ipc = IpcService.getInstance(); const handleOneClick = (mapId: string, isHash = false) => { this.windows.openWindow(`oneclick-download-map.html?mapId=${mapId}&isHash=${isHash}`); @@ -344,7 +343,7 @@ export class LocalMapsManagerService { const localMap = await this.loadMapInfoFromPath(mapPath); localMap.songDetails = this.songDetailsCache.getSongDetails(localMap.hash); - this.ipc.send<{map: BsmLocalMap, version?: BSVersion}>("map-downloaded", this.windows.getWindows("index.html").at(0), { map: localMap, version }); + this._lastDownloadedMap.next({ map: localMap, version }); return localMap; } @@ -392,4 +391,8 @@ export class LocalMapsManagerService { public isDeepLinksEnabled(): boolean { return Array.from(Object.values(this.DEEP_LINKS)).every(link => this.deepLink.isDeepLinkRegistered(link)); } + + public get lastDownloadedMap$(): Observable<{ map: BsmLocalMap, version?: BSVersion }> { + return this._lastDownloadedMap.asObservable(); + } } diff --git a/src/main/services/auto-updater.service.ts b/src/main/services/auto-updater.service.ts index 667e26cf..ca2dfaab 100644 --- a/src/main/services/auto-updater.service.ts +++ b/src/main/services/auto-updater.service.ts @@ -1,13 +1,12 @@ -import { autoUpdater } from "electron-updater"; +import { autoUpdater, CancellationToken, ProgressInfo } from "electron-updater"; import log from "electron-log"; -import { UtilsService } from "./utils.service"; import { gt } from "semver"; +import { Progression } from "main/helpers/fs.helpers"; +import { Observable } from "rxjs"; export class AutoUpdaterService { private static instance: AutoUpdaterService; - private readonly utilsService: UtilsService; - public static getInstance(): AutoUpdaterService { if (!AutoUpdaterService.instance) { AutoUpdaterService.instance = new AutoUpdaterService(); @@ -18,37 +17,46 @@ export class AutoUpdaterService { constructor() { autoUpdater.logger = log; autoUpdater.autoDownload = false; - - this.utilsService = UtilsService.getInstance(); } public isUpdateAvailable(): Promise { - return new Promise(resolve => { - autoUpdater - .checkForUpdates() - .then(info => { - const needUpdate = (() => { - if (!info?.updateInfo) { - return false; - } - return gt(info.updateInfo.version, autoUpdater.currentVersion.version); - })(); - resolve(needUpdate); - }) - .catch(() => resolve(false)); - }); + return autoUpdater.checkForUpdates().then(info => { + return !!info?.updateInfo && gt(info.updateInfo.version, autoUpdater.currentVersion.version); + }).catch(() => false); } - public downloadUpdate(): Promise { - autoUpdater.removeAllListeners("download-progress"); - autoUpdater.addListener("download-progress", info => { - this.utilsService.ipcSend("update-download-progress", { success: true, data: info.percent }); - }); + public downloadUpdate(): Observable { + return new Observable(observer => { - return autoUpdater.downloadUpdate().then(res => !!res && !!res.length); + observer.next({ current: 0, total: 0 }); + + const progressListener = (progress: ProgressInfo) => { + observer.next({ current: progress.transferred, total: progress.total }); + }; + + const downloadedListener = () => { + observer.next({ current: 100, total: 100 }); + }; + + autoUpdater.addListener("download-progress", progressListener); + autoUpdater.addListener("update-downloaded", downloadedListener); + + const cancelToken = new CancellationToken(); + + autoUpdater.downloadUpdate(cancelToken) + .catch(err => observer.error(err)) + .finally(() => observer.complete()); + + return () => { + cancelToken.cancel(); + autoUpdater.removeListener("download-progress", progressListener); + autoUpdater.removeListener("update-downloaded", downloadedListener); + } + }); } public quitAndInstall() { - autoUpdater.quitAndInstall(); + log.info("Quit and install"); + return autoUpdater.quitAndInstall(); } } diff --git a/src/main/services/mods/bs-mods-manager.service.ts b/src/main/services/mods/bs-mods-manager.service.ts index be17d23f..dd574c67 100644 --- a/src/main/services/mods/bs-mods-manager.service.ts +++ b/src/main/services/mods/bs-mods-manager.service.ts @@ -1,39 +1,32 @@ import { BSVersion } from "shared/bs-version.interface"; -import { DownloadLink, InstallModsResult, Mod, ModInstallProgression, UninstallModsResult } from "shared/models/mods"; +import { DownloadLink, Mod } 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"; import md5File from "md5-file"; import { RequestService } from "../request.service"; import { spawn } from "child_process"; import { BS_EXECUTABLE } from "../../constants"; import log from "electron-log"; -import { deleteFolder, pathExist, unlinkPath } from "../../helpers/fs.helpers"; -import { lastValueFrom } from "rxjs"; +import { deleteFolder, pathExist, Progression, unlinkPath } from "../../helpers/fs.helpers"; +import { lastValueFrom, Observable } from "rxjs"; import JSZip from "jszip"; import { extractZip } from "../../helpers/zip.helpers"; import recursiveReadDir from "recursive-readdir"; import { sToMs } from "../../../shared/helpers/time.helpers"; import { ensureDir, pathExistsSync } from "fs-extra"; import { CustomError } from "shared/models/exceptions/custom-error.class"; +import { popElement } from "shared/helpers/array.helpers"; export class BsModsManagerService { private static instance: BsModsManagerService; private readonly beatModsApi: BeatModsApiService; private readonly bsLocalService: BSLocalVersionService; - private readonly utilsService: UtilsService; private readonly requestService: RequestService; private manifestMatches: Mod[]; - private nbModsToInstall = 0; - private nbInstalledMods = 0; - - private nbModsToUninstall = 0; - private nbUninstalledMods = 0; - public static getInstance(): BsModsManagerService { if (!BsModsManagerService.instance) { BsModsManagerService.instance = new BsModsManagerService(); @@ -44,7 +37,6 @@ export class BsModsManagerService { private constructor() { this.beatModsApi = BeatModsApiService.getInstance(); this.bsLocalService = BSLocalVersionService.getInstance(); - this.utilsService = UtilsService.getInstance(); this.requestService = RequestService.getInstance(); } @@ -187,7 +179,6 @@ export class BsModsManagerService { private async installMod(mod: Mod, version: BSVersion): Promise { log.info("INSTALL MOD", mod.name, "for version", `${version.BSVersion} - ${version.name}`); - this.utilsService.ipcSend("mod-installed", { success: true, data: { name: mod.name, progression: ((this.nbInstalledMods + 1) / this.nbModsToInstall) * 100 } }); const download = this.getModDownload(mod, version); @@ -246,10 +237,6 @@ export class BsModsManagerService { })) : extracted; - if(res){ - this.nbInstalledMods++; - } - return res; } @@ -275,9 +262,6 @@ export class BsModsManagerService { } private async uninstallMod(mod: Mod, version: BSVersion): Promise { - this.nbUninstalledMods++; - this.utilsService.ipcSend("mod-uninstalled", { success: true, data: { name: mod.name, progression: (this.nbUninstalledMods / this.nbModsToUninstall) * 100 } }); - if (mod.name.toLowerCase() === "bsipa") { return this.uninstallBSIPA(mod, version); } @@ -322,81 +306,92 @@ export class BsModsManagerService { return Array.from(modsDict.values()); } - public async installMods(mods: Mod[], version: BSVersion): Promise { - if (!mods?.length) { - throw CustomError.fromError(new Error("No mods to install"), "no-mods"); - } + public installMods(mods: Mod[], version: BSVersion): Observable { + const progress = { current: 0, total: mods.length }; - const bsipa = mods.find(mod => mod.name.toLowerCase() === "bsipa"); - if (bsipa) { - mods = mods.filter(mod => mod.name.toLowerCase() !== "bsipa"); - } + return new Observable(obs => { + (async () => { + if (!mods?.length) { + throw CustomError.throw(new Error("No mods to install"), "no-mods", mods); + } - this.nbModsToInstall = mods.length + (bsipa ? 1 : 0); - this.nbInstalledMods = 0; + obs.next(progress); - if (bsipa) { - const installed = await this.installMod(bsipa, version).catch(err => { - log.error("INSTALL BSIPA", err); - return false; - }); - if (!installed) { - throw CustomError.fromError(new Error("Unable to install BSIPA"), "cannot-install-bsipa"); - } - } + const bsipa = popElement(mod => mod.name.toLowerCase() === "bsipa", mods); - for (const mod of mods) { - await this.installMod(mod, version); - } + if(bsipa){ + const bsipaInstalled = await this.installMod(bsipa, version).catch(err => { + log.error("Error while installing BSIPA", err); + }); - return { - nbModsToInstall: this.nbModsToInstall, - nbInstalledMods: this.nbInstalledMods, - }; + if(!bsipaInstalled){ + throw CustomError.throw(new Error("BSIPA failed to install"), "cannot-install-bsipa"); + } + + progress.current++; + obs.next(progress); + } + + for (const mod of mods) { + await this.installMod(mod, version); + progress.current++; + obs.next(progress); + } + })() + .catch(err => obs.error(err)) + .finally(() => obs.complete()); + }); } - public async uninstallMods(mods: Mod[], version: BSVersion): Promise { - if (!mods?.length) { - throw CustomError.fromError(new Error("No mods to uninstall"), "no-mods"); - } + public uninstallMods(mods: Mod[], version: BSVersion): Observable { + const progress = { current: 0, total: mods.length }; - this.nbModsToUninstall = mods.length; - this.nbUninstalledMods = 0; + return new Observable(obs => { + (async () => { + if (!mods?.length) { + throw CustomError.throw(new Error("No mods to uninstall"), "no-mods", mods); + } - for (const mod of mods) { - await this.uninstallMod(mod, version); - } + obs.next(progress); - return { - nbModsToUninstall: this.nbModsToUninstall, - nbUninstalledMods: this.nbUninstalledMods, - }; + for (const mod of mods) { + await this.uninstallMod(mod, version); + progress.current++; + obs.next(progress); + } + })() + .catch(err => obs.error(err)) + .finally(() => obs.complete()); + }); } - public async uninstallAllMods(version: BSVersion): Promise { - const mods = await this.getInstalledMods(version); + public uninstallAllMods(version: BSVersion): Observable { + return new Observable(obs => { + (async () => { + const mods = await this.getInstalledMods(version).catch(err => { + log.error(err); + return []; + }); - if (!mods?.length) { - throw CustomError.fromError(new Error("This version has to mods to uninstall"), "no-mods"); - } + const progress = { current: 0, total: mods.length }; - this.nbModsToUninstall = mods.length; - this.nbUninstalledMods = 0; + obs.next(progress); - for (const mod of mods) { - await this.uninstallMod(mod, version); - } + for (const mod of mods) { + await this.uninstallMod(mod, version); + progress.current++; + obs.next(progress); + } - const versionPath = await this.bsLocalService.getVersionPath(version); + const versionPath = await this.bsLocalService.getVersionPath(version); - await deleteFolder(path.join(versionPath, ModsInstallFolder.PLUGINS)); - await deleteFolder(path.join(versionPath, ModsInstallFolder.LIBS)); - await deleteFolder(path.join(versionPath, ModsInstallFolder.IPA)); - - return { - nbModsToUninstall: this.nbModsToUninstall, - nbUninstalledMods: this.nbUninstalledMods, - }; + await deleteFolder(path.join(versionPath, ModsInstallFolder.PLUGINS)); + await deleteFolder(path.join(versionPath, ModsInstallFolder.LIBS)); + await deleteFolder(path.join(versionPath, ModsInstallFolder.IPA)); + })() + .catch(err => obs.error(err)) + .finally(() => obs.complete()); + }); } } diff --git a/src/renderer/components/maps-playlists-panel/maps/local-maps-list-panel.component.tsx b/src/renderer/components/maps-playlists-panel/maps/local-maps-list-panel.component.tsx index 040802da..f98e6659 100644 --- a/src/renderer/components/maps-playlists-panel/maps/local-maps-list-panel.component.tsx +++ b/src/renderer/components/maps-playlists-panel/maps/local-maps-list-panel.component.tsx @@ -87,25 +87,27 @@ export const LocalMapsListPanel = forwardRef(({ version, classNa setMaps(null); loadPercent$.next(0); subs.forEach(s => s.unsubscribe()); - mapsDownloader.removeOnMapDownloadedListener(loadMaps); }; }, [isActiveOnce, version, linked]); useEffect(() => { + + let sub: Subscription; + if(isActiveOnce){ - mapsDownloader.addOnMapDownloadedListener((map, targetVersion) => { + sub = mapsDownloader.lastDownloadedMap$.subscribe({ next: ({map, version: targetVersion}) => { if (!equal(targetVersion, version)) { return; } - setMaps((maps ? [map, ...maps] : [map])); - }); + setMaps((maps$.value ? [map, ...maps$.value] : [map])); + }}); } return () => { - mapsDownloader.removeOnMapDownloadedListener(loadMaps); + sub?.unsubscribe(); } - }, [isActiveOnce, version, maps]) + }, [isActiveOnce, version]) const loadMaps = () => { setMaps(null); diff --git a/src/renderer/components/modal/modal-types/download-maps-modal.component.tsx b/src/renderer/components/modal/modal-types/download-maps-modal.component.tsx index 43577194..a40e5d50 100644 --- a/src/renderer/components/modal/modal-types/download-maps-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/download-maps-modal.component.tsx @@ -67,22 +67,21 @@ export const DownloadMapsModal: ModalComponent { - const onMapDownloaded = (map: BsmLocalMap, targetVersion: BSVersion) => { + + const sub = mapsDownloader.lastDownloadedMap$.subscribe({ next: ({ map, version: targetVersion }) => { if (!equal(targetVersion, version)) { return; } const downloadedHash = map.hash; setOwnedMapHashs(prev => [...prev, downloadedHash]); - }; - - mapsDownloader.addOnMapDownloadedListener(onMapDownloaded); + }}); if (mapsDownloader.isDownloading) { progressBar.setStyle(mapsDownloader.progressBarStyle); } return () => { - mapsDownloader.removeOnMapDownloadedListener(onMapDownloaded); + sub.unsubscribe(); progressBar.setStyle(null); }; }, []); diff --git a/src/renderer/components/version-viewer/slides/mods/mod-item.component.tsx b/src/renderer/components/version-viewer/slides/mods/mod-item.component.tsx index 806efea7..215b019d 100644 --- a/src/renderer/components/version-viewer/slides/mods/mod-item.component.tsx +++ b/src/renderer/components/version-viewer/slides/mods/mod-item.component.tsx @@ -3,22 +3,26 @@ import { BsmCheckbox } from "renderer/components/shared/bsm-checkbox.component"; import { Mod } from "shared/models/mods/mod.interface"; import { CSSProperties, MouseEvent, useMemo, useRef } from "react"; import { useThemeColor } from "renderer/hooks/use-theme-color.hook"; -import { BsModsManagerService } from "renderer/services/bs-mods-manager.service"; -import { useObservable } from "renderer/hooks/use-observable.hook"; -import { PageStateService } from "renderer/services/page-state.service"; import useDoubleClick from "use-double-click"; import { gt } from "semver"; -import { useService } from "renderer/hooks/use-service.hook"; import { useOnUpdate } from "renderer/hooks/use-on-update.hook"; -type Props = { className?: string; mod: Mod; installedVersion: string; isDependency?: boolean; isSelected?: boolean; onChange?: (val: boolean) => void; wantInfo?: boolean; onWantInfo?: (mod: Mod) => void }; +type Props = { + className?: string; + mod: Mod; + installedVersion: string; + isDependency?: boolean; + isSelected?: boolean; + onChange?: (val: boolean) => void; + wantInfo?: boolean; + onWantInfo?: (mod: Mod) => void; + disabled?: boolean; + onUninstall?: () => void; +}; -export function ModItem({ className, mod, installedVersion, isDependency, isSelected, onChange, wantInfo, onWantInfo }: Props) { - const modsManager = useService(BsModsManagerService); - const pageState = useService(PageStateService); +export function ModItem({ className, mod, installedVersion, isDependency, isSelected, onChange, wantInfo, onWantInfo, disabled, onUninstall }: Props) { const themeColor = useThemeColor("second-color"); - const uninstalling = useObservable(() => modsManager.isUninstalling$); const clickRef = useRef(); const isChecked = useMemo(() => isDependency || isSelected || mod.required, [isDependency, isSelected, mod.required]); @@ -37,10 +41,6 @@ export function ModItem({ className, mod, installedVersion, isDependency, isSele const wantInfoStyle: CSSProperties = wantInfo ? { borderColor: themeColor } : { borderColor: "transparent" }; const isOutDated = installedVersion ? gt(mod.version, installedVersion) : false; - const uninstall = () => { - modsManager.uninstallMod(mod, pageState.getState()); - }; - const handleWantInfo = (e: MouseEvent) => { e.preventDefault(); onWantInfo(mod); @@ -53,7 +53,7 @@ export function ModItem({ className, mod, installedVersion, isDependency, isSele return (
  • - onChange(!isChecked)} disabled={mod.required || isDependency} checked={isChecked} /> + onChange(!isChecked)} disabled={mod.required || isDependency || disabled} checked={isChecked} />
    {mod.name} @@ -72,11 +72,11 @@ export function ModItem({ className, mod, installedVersion, isDependency, isSele { e.stopPropagation(); - uninstall(); + onUninstall?.(); }} /> )} diff --git a/src/renderer/components/version-viewer/slides/mods/mods-grid.component.tsx b/src/renderer/components/version-viewer/slides/mods/mods-grid.component.tsx index 3ee2f227..d9996cf3 100644 --- a/src/renderer/components/version-viewer/slides/mods/mods-grid.component.tsx +++ b/src/renderer/components/version-viewer/slides/mods/mods-grid.component.tsx @@ -3,18 +3,22 @@ import { useState } from "react"; import { BsmButton } from "renderer/components/shared/bsm-button.component"; import { BsmDropdownButton } from "renderer/components/shared/bsm-dropdown-button.component"; import { useTranslation } from "renderer/hooks/use-translation.hook"; -import { BsModsManagerService } from "renderer/services/bs-mods-manager.service"; -import { PageStateService } from "renderer/services/page-state.service"; import { Mod } from "shared/models/mods/mod.interface"; import { ModItem } from "./mod-item.component"; -import { useService } from "renderer/hooks/use-service.hook"; -type Props = { modsMap: Map; installed: Map; modsSelected: Mod[]; onModChange: (selected: boolean, mod: Mod) => void; moreInfoMod?: Mod; onWantInfos: (mod: Mod) => void }; +type Props = { + modsMap: Map; + installed: Map; + modsSelected: Mod[]; + onModChange: (selected: boolean, mod: Mod) => void; + moreInfoMod?: Mod; + onWantInfos: (mod: Mod) => void + disabled?: boolean; + uninstallMod?: (mods: Mod) => void; + uninstallAllMods?: () => void; +}; -export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreInfoMod, onWantInfos }: Props) { - - const pageState = useService(PageStateService); - const modsManager = useService(BsModsManagerService); +export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreInfoMod, onWantInfos, disabled, uninstallMod, uninstallAllMods }: Props) { const [filter, setFilter] = useState(""); const [filterEnabled, setFilterEnabled] = useState(false); @@ -50,10 +54,6 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn setFilterEnabled(b => !b); }; - const handleUninstallAll = () => { - modsManager.uninstallAllMods(pageState.getState()); - }; - return ( modsMap && (
    @@ -66,7 +66,7 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn {t("pages.version-viewer.mods.mods-grid.header-bar.latest")} {t("pages.version-viewer.mods.mods-grid.header-bar.description")} - + uninstallAllMods?.() }]} /> {Array.from(modsMap.keys()).map( @@ -74,7 +74,19 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn modsMap.get(key).some(mod => mod.name.toLowerCase().includes(filter)) && (

      {key}

      - {modsMap.get(key).map(mod => mod.name?.toLowerCase().includes(filter) && onModChange(val, mod)} onWantInfo={onWantInfos} wantInfo={mod.name === moreInfoMod?.name} />)} + {modsMap.get(key).map(mod => mod.name?.toLowerCase().includes(filter) && ( + onModChange(val, mod)} + onWantInfo={onWantInfos} + wantInfo={mod.name === moreInfoMod?.name} + disabled={disabled} + onUninstall={() => uninstallMod?.(mod)} /> + ))}
    ) )} diff --git a/src/renderer/components/version-viewer/slides/mods/mods-slide.component.tsx b/src/renderer/components/version-viewer/slides/mods/mods-slide.component.tsx index 3e94468a..50cbb46b 100644 --- a/src/renderer/components/version-viewer/slides/mods/mods-slide.component.tsx +++ b/src/renderer/components/version-viewer/slides/mods/mods-slide.component.tsx @@ -9,8 +9,7 @@ import { BsmButton } from "renderer/components/shared/bsm-button.component"; import BeatWaitingImg from "../../../../../../assets/images/apngs/beat-waiting.png"; import BeatConflictImg from "../../../../../../assets/images/apngs/beat-conflict.png"; import { useObservable } from "renderer/hooks/use-observable.hook"; -import { skip, filter } from "rxjs/operators"; -import { Subscription, lastValueFrom, noop } from "rxjs"; +import { lastValueFrom } from "rxjs"; import { useTranslation } from "renderer/hooks/use-translation.hook"; import { LinkOpenerService } from "renderer/services/link-opener.service"; import { useInView } from "framer-motion"; @@ -20,6 +19,8 @@ import { OsDiagnosticService } from "renderer/services/os-diagnostic.service"; import { lt } from "semver"; import { useService } from "renderer/hooks/use-service.hook"; import { NotificationService } from "renderer/services/notification.service"; +import { noop } from "shared/helpers/function.helpers"; +import { UninstallAllModsModal } from "renderer/components/modal/modal-types/uninstall-all-mods-modal.component"; export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion; onDisclamerDecline: () => void }) { const ACCEPTED_DISCLAIMER_KEY = "accepted-mods-disclaimer"; @@ -39,7 +40,8 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion; const [moreInfoMod, setMoreInfoMod] = useState(null as Mod); const [reinstallAllMods, setReinstallAllMods] = useState(false); const isOnline = useObservable(() => os.isOnline$); - const installing = useObservable(() => modsManager.isInstalling$); + const [installing, setInstalling] = useState(false); + const [uninstalling, setUninstalling] = useState(false); const downloadRef = useRef(null); const [downloadWith, setDownloadWidth] = useState(0); @@ -103,11 +105,34 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion; return; } - modsManager.installMods(modsToInstall, version).then(() => { + setInstalling(() => true) + lastValueFrom(modsManager.installMods(modsToInstall, version)).then(() => { loadMods(); + }).catch(noop).finally(() => setInstalling(() => false)); + }; + + const uninstallMod = (mod: Mod): void => { + setUninstalling(() => true); + lastValueFrom(modsManager.uninstallMod(mod, version)).catch(noop).finally(() => { + loadMods(); + setUninstalling(() => false); }); }; + const uninstallAllMods = async () => { + const res = await modals.openModal(UninstallAllModsModal, {data: version}); + + if (res.exitCode !== ModalExitCode.COMPLETED) { + return; + } + + setUninstalling(() => true); + lastValueFrom(modsManager.uninstallAllMods(version)).catch(noop).finally(() => { + loadMods(); + setUninstalling(() => false); + }) + }; + const loadMods = (): Promise => { if (os.isOffline) { return Promise.resolve(); @@ -128,7 +153,6 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion; }; useEffect(() => { - const subs: Subscription[] = []; if(!isVisible || !isOnline){ return noop(); @@ -153,22 +177,12 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion; } loadMods(); - - subs.push( - modsManager.isUninstalling$.pipe( - skip(1), - filter(uninstalling => !uninstalling) - ).subscribe(() => { - loadMods(); - }) - ); }); return () => { setMoreInfoMod(null); setModsAvailable(null); setModsInstalled(null); - subs.forEach(s => s.unsubscribe()); }; }, [isVisible, isOnline, version]); @@ -195,7 +209,7 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion; return ( <>
    - +
    diff --git a/src/renderer/services/auto-updater.service.ts b/src/renderer/services/auto-updater.service.ts index 2de418e9..2008b88b 100644 --- a/src/renderer/services/auto-updater.service.ts +++ b/src/renderer/services/auto-updater.service.ts @@ -1,10 +1,10 @@ -import { map } from "rxjs/operators"; import { IpcService } from "./ipc.service"; import { ProgressBarService } from "./progress-bar.service"; import { ModalService } from "renderer/services/modale.service"; import { ChangelogModal } from "renderer/components/modal/modal-types/chabgelog-modal/changelog-modal.component"; import { ConfigurationService } from "./configuration.service"; import { Observable, lastValueFrom } from "rxjs"; +import { Progression } from "main/helpers/fs.helpers"; export interface Changelog { @@ -22,8 +22,6 @@ export class AutoUpdaterService { private progressService: ProgressBarService; private ipcService: IpcService; - private downloadProgress$: Observable; - private modal: ModalService; private configurationService: ConfigurationService; @@ -42,22 +40,28 @@ export class AutoUpdaterService { this.ipcService = IpcService.getInstance(); this.modal = ModalService.getInstance(); this.configurationService = ConfigurationService.getInstance(); - - this.downloadProgress$ = this.ipcService.watch("update-download-progress").pipe(map(res => (res.success ? res.data : 0))); } public isUpdateAvailable(): Promise { return lastValueFrom(this.ipcService.sendV2("check-update")).catch(() => false); } - public downloadUpdate(): Promise { - const promise = lastValueFrom(this.ipcService.sendV2("download-update")).then(() => true).catch(() => false); - this.progressService.show(this.downloadProgress$, true); - return promise; + public downloadUpdate(): Observable { + return new Observable(obs => { + const download$ = this.ipcService.sendV2("download-update"); + this.progressService.show(download$, true); + + const sub = download$.subscribe(obs); + + return () => { + sub.unsubscribe(); + this.progressService.hide(true); + } + }); } - public quitAndInstall() { - lastValueFrom(this.ipcService.sendV2("install-update")); + public quitAndInstall(): Promise { + return lastValueFrom(this.ipcService.sendV2("install-update")); } public getLastAppVersion(): string { diff --git a/src/renderer/services/bs-mods-manager.service.ts b/src/renderer/services/bs-mods-manager.service.ts index 164a8410..97cecf77 100644 --- a/src/renderer/services/bs-mods-manager.service.ts +++ b/src/renderer/services/bs-mods-manager.service.ts @@ -1,17 +1,11 @@ -import { UninstallAllModsModal } from "renderer/components/modal/modal-types/uninstall-all-mods-modal.component"; -import { UninstallModModal } from "renderer/components/modal/modal-types/uninstall-mod-modal.component"; -import { Observable, BehaviorSubject, lastValueFrom } from "rxjs"; -import { map } from "rxjs/operators"; +import { Observable, BehaviorSubject, throwError, of } from "rxjs"; +import { catchError, tap } from "rxjs/operators"; import { BSVersion } from "shared/bs-version.interface"; -import { Mod, ModInstallProgression } from "shared/models/mods"; -import { ProgressionInterface } from "shared/models/progress-bar"; +import { Mod } from "shared/models/mods"; import { IpcService } from "./ipc.service"; -import { ModalExitCode, ModalService } from "./modale.service"; -import { NotificationType } from "../../shared/models/notification/notification.model"; -import { OsDiagnosticService } from "./os-diagnostic.service"; import { ProgressBarService } from "./progress-bar.service"; import { NotificationService } from "./notification.service"; -import { CustomError } from "shared/models/exceptions/custom-error.class"; +import { Progression } from "main/helpers/fs.helpers"; export class BsModsManagerService { private static instance: BsModsManagerService; @@ -20,11 +14,8 @@ export class BsModsManagerService { private readonly ipcService: IpcService; private readonly progressBar: ProgressBarService; - private readonly modals: ModalService; private readonly notifications: NotificationService; - private readonly os: OsDiagnosticService; - public readonly isInstalling$: BehaviorSubject = new BehaviorSubject(false); public readonly isUninstalling$: BehaviorSubject = new BehaviorSubject(false); public static getInstance(): BsModsManagerService { @@ -37,9 +28,7 @@ export class BsModsManagerService { private constructor() { this.ipcService = IpcService.getInstance(); this.progressBar = ProgressBarService.getInstance(); - this.modals = ModalService.getInstance(); this.notifications = NotificationService.getInstance(); - this.os = OsDiagnosticService.getInstance(); } public getAvailableMods(version: BSVersion): Observable { @@ -50,91 +39,98 @@ export class BsModsManagerService { return this.ipcService.sendV2("get-installed-mods", version); } - public installMods(mods: Mod[], version: BSVersion): Promise { - if (this.os.isOffline) { - this.notifications.notifyError({ - title: "notifications.shared.errors.titles.no-internet", - desc: "notifications.shared.errors.msg.no-internet", - }); - return Promise.resolve(); - } + public installMods(mods: Mod[], version: BSVersion): Observable { if (!this.progressBar.require()) { - return Promise.resolve(); + return throwError(() => new Error("Action already in progress")); } - const progress$: Observable = this.ipcService.watch("mod-installed").pipe( - map(res => { - return { progression: res.data.progression, label: res.data.name } as ProgressionInterface; - }) - ); + return new Observable(obs => { + const install$ = this.ipcService.sendV2("install-mods", { mods, version }); + this.progressBar.show(install$.pipe(catchError(() => of({ current: 0, total: 0} as Progression))), true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); - this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); + const sub = install$.pipe( + tap({ + error: err => { + if(err?.code){ + this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${err?.code}`, duration: this.NOTIFICATION_DURATION }); + } else { + this.notifications.notifyError({ title: "notifications.types.error", desc: err?.message ?? err, duration: this.NOTIFICATION_DURATION }); + } + }, + complete: () => { + this.notifications.notifySuccess({ title: "notifications.mods.install-mods.titles.success", desc: "notifications.mods.install-mods.msg.success", duration: this.NOTIFICATION_DURATION }); + }, + }) + ).subscribe(obs); - this.isInstalling$.next(true); - - return lastValueFrom(this.ipcService.sendV2("install-mods", { mods, version })).then(res => { - const isFullyInstalled = res.nbInstalledMods === res.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 }); - }).catch((e: CustomError) => { - this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${e?.code}`, duration: this.NOTIFICATION_DURATION }); - }).finally(() => { - this.isInstalling$.next(false); - this.progressBar.hide(); - }) - } - public async uninstallMod(mod: Mod, version: BSVersion): Promise { - if (!this.progressBar.require()) { - return; - } - - const modalRes = await this.modals.openModal(UninstallModModal, {data: mod}); - - if (modalRes.exitCode !== ModalExitCode.COMPLETED) { - return; - } - - const progress$ = this.ipcService.watch("mod-uninstalled").pipe(map(res => res.data.progression)); - this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); - - this.isUninstalling$.next(true); - - return lastValueFrom(this.ipcService.sendV2("uninstall-mods", { mods: [mod], version })).then(() => { - this.notifications.notifySuccess({ title: "notifications.mods.uninstall-mod.titles.success", duration: this.NOTIFICATION_DURATION }); - }).catch((e: CustomError) => { - this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${e?.code}`, duration: this.NOTIFICATION_DURATION }); - }).finally(() => { - this.isUninstalling$.next(false); - this.progressBar.hide(); - }) + return () => { + sub.unsubscribe(); + this.progressBar.hide(true); + } + }); } - public async uninstallAllMods(version: BSVersion) { + public uninstallMod(mod: Mod, version: BSVersion): Observable { if (!this.progressBar.require()) { - return; + return throwError(() => new Error("Action already in progress")); } - const modalRes = await this.modals.openModal(UninstallAllModsModal, {data: version}); + return new Observable(obs => { + const uninstall$ = this.ipcService.sendV2("uninstall-mods", { mods: [mod], version }); + this.progressBar.show(uninstall$.pipe(catchError(() => of({ current: 0, total: 0} as Progression))), true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); - if (modalRes.exitCode !== ModalExitCode.COMPLETED) { - return; + const sub = uninstall$.pipe( + tap({ + error: err => { + if(err?.code){ + this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${err?.code}`, duration: this.NOTIFICATION_DURATION }); + } else { + this.notifications.notifyError({ title: "notifications.types.error", desc: err?.message ?? err, duration: this.NOTIFICATION_DURATION }); + } + }, + complete: () => { + this.notifications.notifySuccess({ title: "notifications.mods.uninstall-mod.titles.success", duration: this.NOTIFICATION_DURATION }); + }, + }) + ).subscribe(obs); + + return () => { + sub.unsubscribe(); + this.progressBar.hide(true); + } + }); + } + + public uninstallAllMods(version: BSVersion): Observable { + if (!this.progressBar.require()) { + return throwError(() => new Error("Action already in progress")); } - const progress$ = this.ipcService.watch("mod-uninstalled").pipe(map(res => res.data.progression)); - this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); + return new Observable(obs => { + const uninstall$ = this.ipcService.sendV2("uninstall-all-mods", version); + this.progressBar.show(uninstall$.pipe(catchError(() => of({ current: 0, total: 0} as Progression))), true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); - this.isUninstalling$.next(true); - return lastValueFrom(this.ipcService.sendV2("uninstall-all-mods", version)).then(() => { - this.notifications.notifySuccess({ title: "notifications.mods.uninstall-all-mods.titles.success", desc: "notifications.mods.uninstall-all-mods.msg.success", duration: this.NOTIFICATION_DURATION }); - }).catch((e: CustomError) => { - this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${e?.code}`, duration: this.NOTIFICATION_DURATION }); - }).finally(() => { - this.isUninstalling$.next(false); - this.progressBar.hide(); - }) + const sub = uninstall$.pipe( + tap({ + error: err => { + if(err?.code){ + this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${err?.code}`, duration: this.NOTIFICATION_DURATION }); + } else { + this.notifications.notifyError({ title: "notifications.types.error", desc: err?.message ?? err, duration: this.NOTIFICATION_DURATION }); + } + }, + complete: () => { + this.notifications.notifySuccess({ title: "notifications.mods.uninstall-all-mods.titles.success", desc: "notifications.mods.uninstall-all-mods.msg.success", duration: this.NOTIFICATION_DURATION }); + }, + }) + ).subscribe(obs); + + return () => { + sub.unsubscribe(); + this.progressBar.hide(true); + } + + }); } } diff --git a/src/renderer/services/maps-downloader.service.ts b/src/renderer/services/maps-downloader.service.ts index bf2cbcf7..caa39653 100644 --- a/src/renderer/services/maps-downloader.service.ts +++ b/src/renderer/services/maps-downloader.service.ts @@ -1,5 +1,5 @@ import { DownloadMapsModal } from "renderer/components/modal/modal-types/download-maps-modal.component"; -import { map, filter } from "rxjs/operators"; +import { map, filter, share } from "rxjs/operators"; import { BehaviorSubject, timer, Observable, lastValueFrom } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; import { ModalResponse, ModalService } from "./modale.service"; @@ -30,9 +30,10 @@ export class MapsDownloaderService { private readonly mapsQueue$: BehaviorSubject = new BehaviorSubject([]); private readonly currentDownload$: BehaviorSubject = new BehaviorSubject(null); private queueMaxLenght = 0; - private downloadedListerners: ((map: BsmLocalMap, version: BSVersion) => void)[] = []; public readonly progressBarStyle: CSSProperties = { zIndex: 100000, position: "fixed", bottom: "10px", right: 0 }; + private _lastDownloadedMap$: Observable<{map: BsmLocalMap, version?: BSVersion}>; + private constructor() { this.modals = ModalService.getInstance(); this.progressBar = ProgressBarService.getInstance(); @@ -43,10 +44,6 @@ export class MapsDownloaderService { this.mapsQueue$.pipe(filter(queue => queue.length === 0)).subscribe(() => { this.queueMaxLenght = 0; }); - - this.ipc.watch<{map: BsmLocalMap, version?: BSVersion}>("map-downloaded").subscribe((data) => { - this.downloadedListerners.forEach(func => func(data.map, data.version)); - }); } private async startDownloadMaps() { @@ -119,16 +116,19 @@ export class MapsDownloaderService { return this.mapsQueue$.asObservable(); } - public addOnMapDownloadedListener(func: (map: BsmLocalMap, version: BSVersion) => void) { - this.downloadedListerners.push(func); - } + public get lastDownloadedMap$(): Observable<{map: BsmLocalMap, version?: BSVersion}> { + if(!this._lastDownloadedMap$){ + this._lastDownloadedMap$ = new Observable<{map: BsmLocalMap, version?: BSVersion}>(observer => { + const sub = this.ipc.sendV2("last-downloaded-map").subscribe(observer); - public removeOnMapDownloadedListener(func: (map: BsmLocalMap, version: BSVersion) => void) { - const funcIndex = this.downloadedListerners.indexOf(func); - if (funcIndex < 0) { - return; + return () => { + this._lastDownloadedMap$ = null; + sub.unsubscribe(); + } + }).pipe(share()); } - this.downloadedListerners.splice(funcIndex, 1); + + return this._lastDownloadedMap$; } public async oneClickInstallMap(map: BsvMapDetail): Promise { @@ -145,3 +145,5 @@ export interface MapDownload { map: BsvMapDetail; version: BSVersion; } + +export type MapsDownloadedListener = (map: BsmLocalMap, version: BSVersion) => void; diff --git a/src/renderer/windows/Launcher.tsx b/src/renderer/windows/Launcher.tsx index 155b10f8..039414c0 100644 --- a/src/renderer/windows/Launcher.tsx +++ b/src/renderer/windows/Launcher.tsx @@ -7,6 +7,8 @@ import { useTranslation } from "../hooks/use-translation.hook"; import { AutoUpdaterService } from "../services/auto-updater.service"; import { WindowManagerService } from "../services/window-manager.service"; import { useService } from "renderer/hooks/use-service.hook"; +import { lastValueFrom } from "rxjs"; +import { logRenderError } from "renderer"; export default function Launcher() { const updaterService = useService(AutoUpdaterService); @@ -24,13 +26,11 @@ export default function Launcher() { return windowService.openThenCloseAll("index.html"); } setText("auto-update.downloading"); - updaterService.downloadUpdate().then(installed => { - if (!installed) { - return windowService.openThenCloseAll("index.html"); - } - updaterService.quitAndInstall(); - }); - }); + + return lastValueFrom(updaterService.downloadUpdate()) + .then(() => updaterService.quitAndInstall()) + .catch((err) => {logRenderError("omg", err); windowService.openThenCloseAll("index.html")}); + }).catch(() => windowService.openThenCloseAll("index.html")); }, []); return ( diff --git a/src/shared/models/ipc/ipc-routes.ts b/src/shared/models/ipc/ipc-routes.ts index b145955f..01ea1575 100644 --- a/src/shared/models/ipc/ipc-routes.ts +++ b/src/shared/models/ipc/ipc-routes.ts @@ -11,7 +11,7 @@ import { DepotDownloaderEvent } from "../bs-version-download/depot-downloader.mo import { MSGetQuery, MSModel, MSModelType } from "../models/model-saber.model"; import { ModelDownload } from "renderer/services/models-management/models-downloader.service"; import { BsmLocalModel } from "../models/bsm-local-model.interface"; -import { InstallModsResult, Mod, UninstallModsResult } from "../mods"; +import { Mod, UninstallModsResult } from "../mods"; import { BPList, DownloadPlaylistProgressionData } from "../playlists/playlist.interface"; import { VersionLinkerAction } from "renderer/services/version-folder-linker.service"; import { FileFilter, OpenDialogReturnValue } from "electron"; @@ -59,6 +59,7 @@ export interface IpcChannelMapping { "delete-maps": { request: BsmLocalMap[], response: DeleteMapsProgress }; "export-maps": { request: { version: BSVersion; maps: BsmLocalMap[]; outPath: string }, response: Progression }; "download-map": { request: { map: BsvMapDetail; version: BSVersion }, response: BsmLocalMap }; + "last-downloaded-map": { request: void, response: { version?: BSVersion, map: BsmLocalMap } }; "one-click-install-map": { request: BsvMapDetail, response: void }; "register-maps-deep-link": { request: void, response: boolean }; "unregister-maps-deep-link": { request: void, response: boolean }; @@ -78,9 +79,9 @@ export interface IpcChannelMapping { /* ** bs-mods-ipcs ** */ "get-available-mods": { request: BSVersion, response: Mod[] }; "get-installed-mods": { request: BSVersion, response: Mod[] }; - "install-mods": { request: { mods: Mod[]; version: BSVersion }, response: InstallModsResult }; - "uninstall-mods": { request: { mods: Mod[]; version: BSVersion }, response: UninstallModsResult }; - "uninstall-all-mods": { request: BSVersion, response: UninstallModsResult }; + "install-mods": { request: { mods: Mod[]; version: BSVersion }, response: Progression }; + "uninstall-mods": { request: { mods: Mod[]; version: BSVersion }, response: Progression }; + "uninstall-all-mods": { request: BSVersion, response: Progression }; /* ** bs-playlist-ipcs ** */ "one-click-install-playlist": { request: string, response: Progression }; @@ -110,7 +111,7 @@ export interface IpcChannelMapping { "relink-all-versions-folders": { request: void, response: void }; /* ** launcher-ipcs ** */ - "download-update": { request: void, response: boolean }; + "download-update": { request: void, response: Progression }; "check-update": { request: void, response: boolean }; "install-update": { request: void, response: void }; From f73ab4a6a42e0f5634539ac01a83faad11bafa3a Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 29 Sep 2024 18:37:54 +0200 Subject: [PATCH 2/2] [chore-594] remove unused import --- src/shared/models/ipc/ipc-routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/models/ipc/ipc-routes.ts b/src/shared/models/ipc/ipc-routes.ts index 01ea1575..4b56d801 100644 --- a/src/shared/models/ipc/ipc-routes.ts +++ b/src/shared/models/ipc/ipc-routes.ts @@ -11,7 +11,7 @@ import { DepotDownloaderEvent } from "../bs-version-download/depot-downloader.mo import { MSGetQuery, MSModel, MSModelType } from "../models/model-saber.model"; import { ModelDownload } from "renderer/services/models-management/models-downloader.service"; import { BsmLocalModel } from "../models/bsm-local-model.interface"; -import { Mod, UninstallModsResult } from "../mods"; +import { Mod } from "../mods"; import { BPList, DownloadPlaylistProgressionData } from "../playlists/playlist.interface"; import { VersionLinkerAction } from "renderer/services/version-folder-linker.service"; import { FileFilter, OpenDialogReturnValue } from "electron";