mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
Merge branch 'v1.5.0' into feature/playlists/107
This commit is contained in:
@@ -29,6 +29,10 @@ export const EditVersionModal: ModalComponent<{ name: string; color: string }, {
|
||||
setColor(configService.get("second-color" as DefaultConfigKey));
|
||||
};
|
||||
|
||||
const resetName = () => {
|
||||
setName(version.BSVersion);
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
className="static"
|
||||
@@ -44,7 +48,12 @@ export const EditVersionModal: ModalComponent<{ name: string; color: string }, {
|
||||
<label className="block font-bold cursor-pointer tracking-wide text-gray-800 dark:text-gray-200" htmlFor="name">
|
||||
{t("modals.clone-version.inputs.name.label")}
|
||||
</label>
|
||||
<input className="w-full bg-light-main-color-1 dark:bg-main-color-1 px-1 py-[2px] rounded-md outline-none" onChange={e => setName(e.target.value)} value={name} type="text" name="name" id="name" minLength={2} maxLength={15} placeholder={t("modals.clone-version.inputs.name.placeholder")} />
|
||||
<div className="relative">
|
||||
<input className="w-full bg-light-main-color-1 dark:bg-main-color-1 px-1 py-[2px] rounded-md outline-none" onChange={e => setName(e.target.value)} value={name} type="text" name="name" id="name" minLength={2} maxLength={15} placeholder={t("modals.clone-version.inputs.name.placeholder")} />
|
||||
<div className="absolute right-2 top-0 h-full flex items-center">
|
||||
<BsmButton onClick={resetName} className="px-2 font-bold italic text-sm rounded-md" text="pages.settings.appearance.reset" withBar={false} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="block font-bold tracking-wide text-gray-800 dark:text-gray-200">{t("modals.clone-version.inputs.color.label")}</span>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ConfigurationService } from "renderer/services/configuration.service";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { ModalComponent } from "renderer/services/modale.service";
|
||||
import { FolderLinkState, VersionFolderLinkerService, VersionLinkerActionType } from "renderer/services/version-folder-linker.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
|
||||
export const ShareFoldersModal: ModalComponent<void, BSVersion> = ({ options: {data} }) => {
|
||||
@@ -45,14 +46,14 @@ export const ShareFoldersModal: ModalComponent<void, BSVersion> = ({ options: {d
|
||||
}, [folders]);
|
||||
|
||||
const addFolder = async () => {
|
||||
const versionPath = await versionManager.getVersionPath(data).toPromise();
|
||||
const folder = await ipc.sendV2<{ canceled: boolean; filePaths: string[] }, string>("choose-folder", { args: versionPath }).toPromise();
|
||||
const versionPath = await lastValueFrom(versionManager.getVersionPath(data));
|
||||
const folder = await lastValueFrom(ipc.sendV2("choose-folder", versionPath));
|
||||
|
||||
if (!folder || folder.canceled || !folder.filePaths?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const relativeFolder = await ipc.sendV2<string>("full-version-path-to-relative", { args: { version: data, fullPath: folder.filePaths[0] } }).toPromise();
|
||||
const relativeFolder = await lastValueFrom(ipc.sendV2("full-version-path-to-relative", { version: data, fullPath: folder.filePaths[0] }));
|
||||
|
||||
if (folders.includes(relativeFolder)) {
|
||||
return;
|
||||
|
||||
@@ -10,11 +10,13 @@ import { BsmIconType } from "../svgs/bsm-icon.component";
|
||||
import "./title-bar.component.css";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function TitleBar({ template = "index.html" }: { template: AppWindow }) {
|
||||
|
||||
|
||||
const ipcService = useService(IpcService);
|
||||
const audio = useService(AudioPlayerService);
|
||||
const windowControls = useWindowControls();
|
||||
|
||||
const volume = useObservable(() => audio.volume$, audio.volume);
|
||||
const color = useThemeColor("first-color");
|
||||
@@ -22,7 +24,7 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin
|
||||
const [previewVersion, setPreviewVersion] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
lastValueFrom(ipcService.sendV2<string>("current-version")).then(version => {
|
||||
lastValueFrom(ipcService.sendV2("current-version")).then(version => {
|
||||
if (version.toLocaleLowerCase().includes("alpha")) {
|
||||
return setPreviewVersion("ALPHA");
|
||||
}
|
||||
@@ -35,19 +37,19 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin
|
||||
const [maximized, setMaximized] = useState(false);
|
||||
|
||||
const closeWindow = () => {
|
||||
return window.electron.window.close();
|
||||
return windowControls.close();
|
||||
};
|
||||
|
||||
const maximizeWindow = () => {
|
||||
window.electron.window.maximise();
|
||||
windowControls.maximise();
|
||||
};
|
||||
|
||||
const minimizeWindow = () => {
|
||||
window.electron.window.minimise();
|
||||
windowControls.minimise();
|
||||
};
|
||||
|
||||
const resetWindow = () => {
|
||||
window.electron.window.unmaximise();
|
||||
windowControls.unmaximise();
|
||||
};
|
||||
|
||||
const toogleMaximize = () => {
|
||||
@@ -117,7 +119,7 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<header id="titlebar" className="min-h-[22px] bg-transparent w-screen h-[22px] flex content-center items-center justify-start z-10">
|
||||
<div id="drag-region" className="grow h-full">
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useConstant } from "./use-constant.hook";
|
||||
|
||||
export function useWindowArgs<Key extends string>(...keys: Key[]): Record<Key, string|undefined> {
|
||||
|
||||
const getArgs = (...keys: Key[]) => {
|
||||
const url = new URLSearchParams(window.location.search);
|
||||
const result = {} as Record<Key, string>;
|
||||
keys.forEach(key => {
|
||||
result[key] = url.get(key) || undefined;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return useConstant(() => getArgs(...keys));
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { useService } from "./use-service.hook";
|
||||
import { useConstant } from "./use-constant.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
export function useWindowControls() {
|
||||
const ipc = useService(IpcService);
|
||||
|
||||
const { close, maximise, minimise, unmaximise } = useConstant(() => ({
|
||||
close: () => lastValueFrom(ipc.sendV2("close-window")),
|
||||
maximise: () => lastValueFrom(ipc.sendV2("maximise-window")),
|
||||
minimise: () => lastValueFrom(ipc.sendV2("minimise-window")),
|
||||
unmaximise: () => lastValueFrom(ipc.sendV2("unmaximise-window"))
|
||||
}));
|
||||
|
||||
return { close, maximise, minimise, unmaximise };
|
||||
}
|
||||
@@ -35,7 +35,6 @@ import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BsmException } from "shared/models/bsm-exception.model";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { OculusDownloaderService } from "renderer/services/bs-version-download/oculus-downloader.service";
|
||||
import { BsStore } from "shared/models/bs-store.enum";
|
||||
import { SteamIcon } from "renderer/components/svgs/icons/steam-icon.component";
|
||||
import { OculusIcon } from "renderer/components/svgs/icons/oculus-icon.component";
|
||||
@@ -52,7 +51,6 @@ export function SettingsPage() {
|
||||
const modalService = useService(ModalService);
|
||||
const bsDownloader = useService(BsDownloaderService);
|
||||
const steamDownloader = useService(SteamDownloaderService);
|
||||
const oculusDownloader = useService(OculusDownloaderService);
|
||||
const progressBarService = useService(ProgressBarService);
|
||||
const notificationService = useService(NotificationService);
|
||||
const i18nService = useService(I18nService);
|
||||
@@ -91,7 +89,7 @@ export function SettingsPage() {
|
||||
const [playlistsDeepLinkEnabled, setPlaylistsDeepLinkEnabled] = useState(false);
|
||||
const [modelsDeepLinkEnabled, setModelsDeepLinkEnabled] = useState(false);
|
||||
const [hasDownloaderSession, setHasDownloaderSession] = useState(false);
|
||||
const appVersion = useObservable(() => ipcService.sendV2<string>("current-version"));
|
||||
const appVersion = useObservable(() => ipcService.sendV2("current-version"));
|
||||
|
||||
const [isChangelogAvailable, setIsChangelogAvailable] = useState(true);
|
||||
const [changlogsLoading, setChanglogsLoading] = useState(false);
|
||||
@@ -116,16 +114,11 @@ export function SettingsPage() {
|
||||
};
|
||||
|
||||
const loadDownloadersSession = () => {
|
||||
if(steamDownloader.sessionExist()){ return setHasDownloaderSession(true); }
|
||||
|
||||
oculusDownloader.hasAuthToken().then(hasToken => {
|
||||
setHasDownloaderSession(hasToken);
|
||||
});
|
||||
setHasDownloaderSession(steamDownloader.sessionExist());
|
||||
}
|
||||
|
||||
const clearDownloadersSession = () => {
|
||||
steamDownloader.deleteSteamSession();
|
||||
oculusDownloader.clearAuthToken();
|
||||
loadDownloadersSession();
|
||||
}
|
||||
|
||||
@@ -171,7 +164,7 @@ export function SettingsPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileChooserRes = await ipcService.sendV2<{ canceled: boolean; filePaths: string[] }>("choose-folder").toPromise();
|
||||
const fileChooserRes = await lastValueFrom(ipcService.sendV2("choose-folder"));
|
||||
|
||||
if (!fileChooserRes.canceled && fileChooserRes.filePaths?.length) {
|
||||
progressBarService.showFake(0.008);
|
||||
@@ -217,7 +210,7 @@ export function SettingsPage() {
|
||||
const openDiscord = () => linkOpener.open("https://discord.gg/uSqbHVpKdV");
|
||||
const openTwitter = () => linkOpener.open("https://twitter.com/BSManager_");
|
||||
|
||||
const openLogs = () => ipcService.sendLazy("open-logs");
|
||||
const openLogs = () => lastValueFrom(ipcService.sendV2("open-logs"));
|
||||
|
||||
const showDeepLinkError = (isDeactivation: boolean) => {
|
||||
const desc = isDeactivation ? "notifications.settings.additional-content.deep-link.deactivation.error.description" : "notifications.settings.additional-content.deep-link.activation.error.description";
|
||||
@@ -231,8 +224,10 @@ export function SettingsPage() {
|
||||
};
|
||||
|
||||
const switchDeepLink = async (manager: MapsManagerService | PlaylistsManagerService | ModelsManagerService, enable: boolean, showNotification: boolean, setter: Dispatch<SetStateAction<boolean>>) => {
|
||||
const res = await (enable ? manager.enableDeepLink() : manager.disableDeepLink());
|
||||
showNotification && (res ? showDeepLinkSuccess(!enable) : showDeepLinkError(!enable));
|
||||
const res = await (enable ? manager.enableDeepLink() : manager.disableDeepLink()).then(() => true).catch(() => false);
|
||||
if(showNotification){
|
||||
res ? showDeepLinkSuccess(enable) : showDeepLinkError(enable);
|
||||
}
|
||||
const isEnable = await manager.isDeepLinksEnabled();
|
||||
setter(() => isEnable);
|
||||
return res;
|
||||
|
||||
@@ -42,7 +42,7 @@ export function VersionViewer() {
|
||||
}
|
||||
navigate(`/bs-version/${version.BSVersion}`, { state: version });
|
||||
};
|
||||
const openFolder = () => ipcService.sendLazy("bs-version.open-folder", { args: state });
|
||||
const openFolder = () => lastValueFrom(ipcService.sendV2("bs-version.open-folder", state));
|
||||
const verifyFiles = () => bsDownloader.verifyBsVersion(state);
|
||||
|
||||
const uninstall = async () => {
|
||||
|
||||
Vendored
-6
@@ -11,12 +11,6 @@ declare global {
|
||||
sep: "/"|"\\";
|
||||
join: (...args: string[]) => string;
|
||||
};
|
||||
window: {
|
||||
close: () => void;
|
||||
minimise: () => void;
|
||||
maximise: () => void;
|
||||
unmaximise: () => void;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,20 +47,17 @@ export class AutoUpdaterService {
|
||||
}
|
||||
|
||||
public isUpdateAvailable(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipcService.sendV2<boolean>("check-update")).catch(() => false);
|
||||
return lastValueFrom(this.ipcService.sendV2("check-update")).catch(() => false);
|
||||
}
|
||||
|
||||
public downloadUpdate(): Promise<boolean> {
|
||||
const promise = this.ipcService.send<boolean>("download-update").then(res => {
|
||||
return res.success;
|
||||
});
|
||||
|
||||
const promise = lastValueFrom(this.ipcService.sendV2("download-update")).then(() => true).catch(() => false);
|
||||
this.progressService.show(this.downloadProgress$, true);
|
||||
return promise;
|
||||
}
|
||||
|
||||
public quitAndInstall() {
|
||||
this.ipcService.sendLazy("install-update");
|
||||
lastValueFrom(this.ipcService.sendV2("install-update"));
|
||||
}
|
||||
|
||||
public getLastAppVersion(): string {
|
||||
@@ -103,7 +100,7 @@ export class AutoUpdaterService {
|
||||
}
|
||||
|
||||
public getAppVersion() : Observable<string> {
|
||||
return this.ipcService.sendV2<string>("current-version");
|
||||
return this.ipcService.sendV2("current-version");
|
||||
}
|
||||
|
||||
public async showChangelog(version:string): Promise<void>{
|
||||
|
||||
@@ -73,7 +73,7 @@ export class BSLauncherService {
|
||||
}
|
||||
|
||||
private async doMustStartAsAdmin(): Promise<boolean> {
|
||||
const needAdmin = await lastValueFrom(this.ipcService.sendV2<boolean, void>("bs-launch.need-start-as-admin"));
|
||||
const needAdmin = await lastValueFrom(this.ipcService.sendV2("bs-launch.need-start-as-admin"));
|
||||
if(!needAdmin){ return false; }
|
||||
if(this.config.get("dont-remind-admin")){ return true; }
|
||||
const modalRes = await this.modals.openModal(NeedLaunchAdminModal);
|
||||
@@ -83,7 +83,7 @@ export class BSLauncherService {
|
||||
}
|
||||
|
||||
public doLaunch(launchOptions: LaunchOption): Observable<BSLaunchEventData>{
|
||||
return this.ipcService.sendV2<BSLaunchEventData, LaunchOption>("bs-launch.launch", {args: launchOptions});
|
||||
return this.ipcService.sendV2("bs-launch.launch", launchOptions);
|
||||
}
|
||||
|
||||
public launch(launchOptions: LaunchOption): Observable<BSLaunchEventData> {
|
||||
@@ -114,13 +114,13 @@ export class BSLauncherService {
|
||||
|
||||
}
|
||||
|
||||
public createLaunchShortcut(launchOptions: LaunchOption): Observable<void>{
|
||||
public createLaunchShortcut(launchOptions: LaunchOption): Observable<boolean>{
|
||||
const options: LaunchOption = {...launchOptions, version: {...launchOptions.version, color: launchOptions.version.color || this.theme.getBsmColors()[1]}};
|
||||
return this.ipcService.sendV2<void, LaunchOption>("create-launch-shortcut", {args: options});
|
||||
return this.ipcService.sendV2("create-launch-shortcut", options);
|
||||
}
|
||||
|
||||
public restoreSteamVR(): Promise<void>{
|
||||
return lastValueFrom(this.ipcService.sendV2<void, void>("bs-launch.restore-steamvr"));
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-launch.restore-steamvr"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
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 } from "rxjs";
|
||||
import { Observable, BehaviorSubject, lastValueFrom } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { InstallModsResult, UninstallModsResult, Mod, ModInstallProgression } from "shared/models/mods";
|
||||
import { Mod, ModInstallProgression } from "shared/models/mods";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ModalExitCode, ModalService } from "./modale.service";
|
||||
@@ -42,11 +42,11 @@ export class BsModsManagerService {
|
||||
}
|
||||
|
||||
public getAvailableMods(version: BSVersion): Observable<Mod[]> {
|
||||
return this.ipcService.sendV2<Mod[], BSVersion>("get-available-mods", { args: version });
|
||||
return this.ipcService.sendV2("get-available-mods", version);
|
||||
}
|
||||
|
||||
public getInstalledMods(version: BSVersion): Observable<Mod[]> {
|
||||
return this.ipcService.sendV2<Mod[], BSVersion>("get-installed-mods", { args: version });
|
||||
return this.ipcService.sendV2("get-installed-mods", version);
|
||||
}
|
||||
|
||||
public installMods(mods: Mod[], version: BSVersion): Promise<void> {
|
||||
@@ -71,19 +71,20 @@ export class BsModsManagerService {
|
||||
this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" });
|
||||
|
||||
this.isInstalling$.next(true);
|
||||
return this.ipcService.send<InstallModsResult, { mods: Mod[]; version: BSVersion }>("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 });
|
||||
}
|
||||
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 => {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION });
|
||||
}).finally(() => {
|
||||
this.isInstalling$.next(false);
|
||||
this.progressBar.hide();
|
||||
});
|
||||
})
|
||||
}
|
||||
public async uninstallMod(mod: Mod, version: BSVersion): Promise<void> {
|
||||
if (!this.progressBar.require()) {
|
||||
@@ -100,16 +101,15 @@ export class BsModsManagerService {
|
||||
this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" });
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
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 => {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION });
|
||||
}).finally(() => {
|
||||
this.isUninstalling$.next(false);
|
||||
this.progressBar.hide();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
public async uninstallAllMods(version: BSVersion) {
|
||||
@@ -127,15 +127,13 @@ export class BsModsManagerService {
|
||||
this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" });
|
||||
|
||||
this.isUninstalling$.next(true);
|
||||
return this.ipcService.send<UninstallModsResult>("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 });
|
||||
}
|
||||
|
||||
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 => {
|
||||
this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION });
|
||||
}).finally(() => {
|
||||
this.isUninstalling$.next(false);
|
||||
this.progressBar.hide();
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme
|
||||
private startDownloadBsVersion(downloadInfo: DownloadInfo): Observable<Progression<BSVersion>>{
|
||||
const ignoreCode = [MetaAuthErrorCodes.META_LOGIN_WINDOW_CLOSED_BY_USER, OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED];
|
||||
return this.handleDownload(
|
||||
this.ipc.sendV2<Progression<BSVersion>>("bs-oculus-download", { args: downloadInfo }),
|
||||
this.ipc.sendV2("bs-oculus-download", downloadInfo ),
|
||||
ignoreCode
|
||||
);
|
||||
}
|
||||
@@ -115,15 +115,7 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme
|
||||
}
|
||||
|
||||
public stopDownload(): Promise<void>{
|
||||
return lastValueFrom(this.ipc.sendV2<void>("bs-oculus-stop-download"));
|
||||
return lastValueFrom(this.ipc.sendV2("bs-oculus-stop-download"));
|
||||
}
|
||||
|
||||
public hasAuthToken(): Promise<boolean>{
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("bs-oculus-has-auth-token"));
|
||||
}
|
||||
|
||||
public clearAuthToken(): Promise<void>{
|
||||
return lastValueFrom(this.ipc.sendV2<void>("bs-oculus-clear-auth-token"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
public isDotNet6Installed(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipcService.sendV2<boolean>("is-dotnet-6-installed"));
|
||||
return lastValueFrom(this.ipcService.sendV2("is-dotnet-6-installed"));
|
||||
}
|
||||
|
||||
private setSteamSession(username: string): void { localStorage.setItem(this.STEAM_SESSION_USERNAME_KEY, username); }
|
||||
@@ -67,11 +67,11 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
public async getInstallationFolder(): Promise<string> {
|
||||
return lastValueFrom(this.ipcService.sendV2<string>("bs-download.installation-folder"));
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-download.installation-folder"));
|
||||
}
|
||||
|
||||
public setInstallationFolder(path: string): Observable<string> {
|
||||
return this.ipcService.sendV2<string>("bs-download.set-installation-folder", { args: path });
|
||||
return this.ipcService.sendV2("bs-download.set-installation-folder", path);
|
||||
}
|
||||
|
||||
// ### Downloading
|
||||
@@ -177,7 +177,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
tap({
|
||||
error: (e) => {
|
||||
this.deleteSteamSession();
|
||||
!silent && this.hanndleErrorEvent(e)
|
||||
if(!silent){ this.hanndleErrorEvent(e) }
|
||||
}
|
||||
}),
|
||||
share({connector: () => new ReplaySubject(1)})
|
||||
@@ -193,20 +193,20 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
|
||||
const infos: DownloadSteamInfo = {...downloadInfo, username: this.getSteamUsername()}
|
||||
return this.wrapDownload(
|
||||
this.ipcService.sendV2<DepotDownloaderEvent>("auto-download-bs-version", { args: infos }),
|
||||
this.ipcService.sendV2("auto-download-bs-version", infos),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
private startDownload(downloadInfo: DownloadSteamInfo){
|
||||
return this.wrapDownload(
|
||||
this.ipcService.sendV2<DepotDownloaderEvent>("download-bs-version", { args: downloadInfo })
|
||||
this.ipcService.sendV2("download-bs-version", downloadInfo )
|
||||
);
|
||||
}
|
||||
|
||||
private startQrCodeDownload(downloadInfo: DownloadSteamInfo){
|
||||
return this.wrapDownload(
|
||||
this.ipcService.sendV2<DepotDownloaderEvent>("download-bs-version-qr", { args: downloadInfo })
|
||||
this.ipcService.sendV2("download-bs-version-qr", downloadInfo)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
private sendInput(input: string){
|
||||
return lastValueFrom(this.ipcService.sendV2<void>("send-input-bs-download", { args: input }));
|
||||
return lastValueFrom(this.ipcService.sendV2("send-input-bs-download", input));
|
||||
}
|
||||
|
||||
public downloadBsVersion(version: BSVersion): Promise<BSVersion> {
|
||||
@@ -272,6 +272,6 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen
|
||||
}
|
||||
|
||||
public stopDownload(): Promise<void>{
|
||||
return lastValueFrom(this.ipcService.sendV2<void>("stop-download-bs-version"));
|
||||
return lastValueFrom(this.ipcService.sendV2("stop-download-bs-version"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { EditVersionModal } from "renderer/components/modal/modal-types/edit-ver
|
||||
import { popElement } from "shared/helpers/array.helpers";
|
||||
import { ImportVersionModal } from "renderer/components/modal/modal-types/import-version-modal.component";
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { ImportVersionOptions } from "main/services/bs-local-version.service";
|
||||
|
||||
export class BSVersionManagerService {
|
||||
private static instance: BSVersionManagerService;
|
||||
@@ -48,16 +47,16 @@ export class BSVersionManagerService {
|
||||
}
|
||||
|
||||
public askAvailableVersions(): Promise<BSVersion[]> {
|
||||
return this.ipcService.send<BSVersion[]>("bs-version.get-version-dict").then(res => {
|
||||
this.availableVersions$.next(res.data);
|
||||
return res.data;
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.get-version-dict")).then(res => {
|
||||
this.availableVersions$.next(res);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
public askInstalledVersions(): Promise<BSVersion[]> {
|
||||
return this.ipcService.send<BSVersion[]>("bs-version.installed-versions").then(res => {
|
||||
this.setInstalledVersions(res.data);
|
||||
return res.data;
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.installed-versions")).then(res => {
|
||||
this.setInstalledVersions(res);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,17 +72,17 @@ export class BSVersionManagerService {
|
||||
if (modalRes.data.name?.length < 2) {
|
||||
return null;
|
||||
}
|
||||
return this.ipcService.send<BSVersion>("bs-version.edit", { args: { version, name: modalRes.data.name, color: modalRes.data.color } }).then(res => {
|
||||
if (!res.success) {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${res.error.title}`,
|
||||
...(res.error.message && { desc: `notifications.custom-version.errors.msg.${res.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.edit", { version, name: modalRes.data.name, color: modalRes.data.color })).then(res => {
|
||||
this.askInstalledVersions();
|
||||
return res.data;
|
||||
});
|
||||
return res;
|
||||
}).catch(e => {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${e.error.title}`,
|
||||
...(e.error.message && { desc: `notifications.custom-version.errors.msg.${e.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
})
|
||||
}
|
||||
|
||||
public async cloneVersion(version: BSVersion): Promise<BSVersion> {
|
||||
@@ -97,19 +96,21 @@ export class BSVersionManagerService {
|
||||
if (modalRes.data.name?.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.progressBar.showFake(0.01);
|
||||
return this.ipcService.send<BSVersion>("bs-version.clone", { args: { version, name: modalRes.data.name, color: modalRes.data.color } }).then(res => {
|
||||
this.progressBar.hide(true);
|
||||
if (!res.success) {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${res.error.title}`,
|
||||
...(res.error.message && { desc: `notifications.custom-version.errors.msg.${res.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
return lastValueFrom(this.ipcService.sendV2("bs-version.clone", { version, name: modalRes.data.name, color: modalRes.data.color })).then(res => {
|
||||
this.notification.notifySuccess({ title: "notifications.custom-version.success.titles.CloningFinished" });
|
||||
this.askInstalledVersions();
|
||||
return res.data;
|
||||
return res;
|
||||
}).catch(e => {
|
||||
this.notification.notifyError({
|
||||
title: `notifications.custom-version.errors.titles.${e.error.title}`,
|
||||
...(e.error.message && { desc: `notifications.custom-version.errors.msg.${e.error.message}` }),
|
||||
});
|
||||
return null;
|
||||
}).finally(() => {
|
||||
this.progressBar.hide(true)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,12 +132,12 @@ export class BSVersionManagerService {
|
||||
|
||||
const store = resModal.data;
|
||||
|
||||
const folderRes = await lastValueFrom(this.ipcService.sendV2<{ canceled: boolean; filePaths: string[] }>("choose-folder"));
|
||||
const folderRes = await lastValueFrom(this.ipcService.sendV2("choose-folder"));
|
||||
if(!folderRes || folderRes.canceled || !folderRes.filePaths?.length){
|
||||
return;
|
||||
}
|
||||
|
||||
const import$ = this.ipcService.sendV2<Progression<BSVersion>, ImportVersionOptions>("import-version", { args: {fromPath: folderRes.filePaths.at(0), store} });
|
||||
const import$ = this.ipcService.sendV2("import-version", {fromPath: folderRes.filePaths.at(0), store});
|
||||
|
||||
subs.push(import$.subscribe(obs));
|
||||
|
||||
@@ -167,7 +168,7 @@ export class BSVersionManagerService {
|
||||
}
|
||||
|
||||
public getVersionPath(version: BSVersion): Observable<string> {
|
||||
return this.ipcService.sendV2("get-version-full-path", { args: version });
|
||||
return this.ipcService.sendV2("get-version-full-path", version);
|
||||
}
|
||||
|
||||
public static sortVersions(versions: BSVersion[]): BSVersion[] {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Observable, ReplaySubject, identity } from "rxjs";
|
||||
import { IpcRequest, IpcResponse } from "shared/models/ipc";
|
||||
import { deserializeError } from 'serialize-error';
|
||||
import { IpcCompleteChannel, IpcErrorChannel, IpcTearDownChannel } from "shared/models/ipc/ipc-response.interface";
|
||||
import { IpcChannels, IpcRequestType, IpcResponseType } from "shared/models/ipc/ipc-routes";
|
||||
|
||||
export class IpcService {
|
||||
private static instance: IpcService;
|
||||
@@ -63,25 +64,23 @@ export class IpcService {
|
||||
|
||||
// TODO : Convert all IPCs calls to V2
|
||||
|
||||
public sendV2<T, U = unknown>(channel: string, request?: IpcRequest<U>, defaultValue?: T): Observable<T> {
|
||||
if (!request) {
|
||||
request = { args: null, responceChannel: null };
|
||||
}
|
||||
public sendV2<C extends IpcChannels>(channel: C, data?: IpcRequestType<C>, defaultValue?: IpcResponseType<C>): Observable<IpcResponseType<C>> {
|
||||
|
||||
if (!request.responceChannel) {
|
||||
request.responceChannel = `${channel}_responce_${crypto.randomUUID()}`;
|
||||
}
|
||||
const request: IpcRequest<IpcRequestType<C>> = {
|
||||
args: data,
|
||||
responceChannel: `${channel}_responce_${crypto.randomUUID()}`
|
||||
};
|
||||
|
||||
const completeChannel: IpcCompleteChannel = `${request.responceChannel}_complete`;
|
||||
const errorChannel: IpcErrorChannel = `${request.responceChannel}_error`;
|
||||
const teardownChannel: IpcTearDownChannel = `${request.responceChannel}_teardown`;
|
||||
|
||||
const obs = new Observable<T>(observer => {
|
||||
window.electron.ipcRenderer.on(request.responceChannel, (res: T) => observer.next(res));
|
||||
const obs = new Observable<IpcResponseType<C>>(observer => {
|
||||
window.electron.ipcRenderer.on(request.responceChannel, (res: IpcResponseType<C>) => observer.next(res));
|
||||
window.electron.ipcRenderer.on(errorChannel, (err) => observer.error(deserializeError(err)));
|
||||
window.electron.ipcRenderer.on(completeChannel, () => observer.complete());
|
||||
|
||||
window.electron.ipcRenderer.sendMessage(channel, request);
|
||||
window.electron.ipcRenderer.sendMessage(channel as string, request);
|
||||
|
||||
return () => {
|
||||
window.electron.ipcRenderer.removeAllListeners(request.responceChannel);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Observable, Subject } from "rxjs";
|
||||
import { Observable, Subject, lastValueFrom } from "rxjs";
|
||||
import { IpcService } from "./ipc.service";
|
||||
|
||||
export class LinkOpenerService {
|
||||
@@ -23,7 +23,7 @@ export class LinkOpenerService {
|
||||
if (internal) {
|
||||
return this._iframeLink$.next(url);
|
||||
}
|
||||
this.ipcService.sendLazy("new-window", { args: url });
|
||||
lastValueFrom(this.ipcService.sendV2("new-window", url));
|
||||
}
|
||||
|
||||
public closeIframe() {
|
||||
|
||||
@@ -75,7 +75,7 @@ export class MapsDownloaderService {
|
||||
if (this.os.isOffline) {
|
||||
return null;
|
||||
}
|
||||
return this.ipc.sendV2<BsmLocalMap, { map: BsvMapDetail; version: BSVersion }>("download-map", { args: { map, version } });
|
||||
return this.ipc.sendV2("download-map", { map, version });
|
||||
}
|
||||
|
||||
public async openDownloadMapModal(version?: BSVersion, ownedMaps: BsmLocalMap[] = []): Promise<ModalResponse<void>> {
|
||||
@@ -132,12 +132,9 @@ export class MapsDownloaderService {
|
||||
this.downloadedListerners.splice(funcIndex, 1);
|
||||
}
|
||||
|
||||
public async oneClickInstallMap(map: BsvMapDetail): Promise<boolean> {
|
||||
public async oneClickInstallMap(map: BsvMapDetail): Promise<void> {
|
||||
this.progressBar.showFake(0.04);
|
||||
|
||||
const res = await this.ipc.send<void, BsvMapDetail>("one-click-install-map", { args: map });
|
||||
|
||||
return res.success;
|
||||
return lastValueFrom(this.ipc.sendV2("one-click-install-map", map));
|
||||
}
|
||||
|
||||
public get isDownloading(): boolean {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { LinkMapsModal } from "renderer/components/modal/modal-types/link-maps-modal.component";
|
||||
import { UnlinkMapsModal } from "renderer/components/modal/modal-types/unlink-maps-modal.component";
|
||||
import { Subject, Observable, of } from "rxjs";
|
||||
import { Subject, Observable, of, lastValueFrom } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BsmLocalMapsProgress, BsmLocalMap, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface";
|
||||
import { BsmLocalMapsProgress, BsmLocalMap } from "shared/models/maps/bsm-local-map.interface";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ModalExitCode, ModalService } from "./modale.service";
|
||||
import { DeleteMapsModal } from "renderer/components/modal/modal-types/delete-maps-modal.component";
|
||||
import { ProgressBarService } from "./progress-bar.service";
|
||||
import { OpenSaveDialogOption } from "shared/models/ipc";
|
||||
import { NotificationService } from "./notification.service";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { ArchiveProgress } from "shared/models/archive.interface";
|
||||
import { map, last, catchError } from "rxjs/operators";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { FolderLinkState, VersionFolderLinkerService } from "./version-folder-linker.service";
|
||||
@@ -48,7 +46,7 @@ export class MapsManagerService {
|
||||
}
|
||||
|
||||
public getMaps(version?: BSVersion): Observable<BsmLocalMapsProgress> {
|
||||
return this.ipcService.sendV2<BsmLocalMapsProgress>("load-version-maps", { args: version }, { loaded: 0, total: 0, maps: [] });
|
||||
return this.ipcService.sendV2("load-version-maps", version, { loaded: 0, total: 0, maps: [] });
|
||||
}
|
||||
|
||||
public async versionHaveMapsLinked(version: BSVersion): Promise<boolean> {
|
||||
@@ -97,7 +95,7 @@ export class MapsManagerService {
|
||||
|
||||
const showProgressBar = this.progressBar.require();
|
||||
|
||||
const progress$ = this.ipcService.sendV2<DeleteMapsProgress>("delete-maps", { args: maps }).pipe(map(progress => (progress.deleted / progress.total) * 100));
|
||||
const progress$ = this.ipcService.sendV2("delete-maps", maps ).pipe(map(progress => (progress.deleted / progress.total) * 100));
|
||||
|
||||
if (showProgressBar) {
|
||||
this.progressBar.show(progress$, true);
|
||||
@@ -120,20 +118,15 @@ export class MapsManagerService {
|
||||
return;
|
||||
}
|
||||
|
||||
const resFile = await this.ipcService.send<string, OpenSaveDialogOption>("save-file", {
|
||||
args: {
|
||||
filename: version ? `${version.BSVersion}Maps` : "Maps",
|
||||
filters: [{ name: "zip", extensions: ["zip"] }],
|
||||
},
|
||||
});
|
||||
const resFile = await lastValueFrom(this.ipcService.sendV2("save-file", { filename: version ? `${version.BSVersion}Maps` : "Maps", filters: [{ name: "zip", extensions: ["zip"] }]})).catch(() => null as string);
|
||||
|
||||
if (!resFile.success) {
|
||||
if (!resFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const exportProgress$: Observable<ProgressionInterface> = this.ipcService.sendV2<ArchiveProgress, { version: BSVersion; maps: BsmLocalMap[]; outPath: string }>("export-maps", { args: { version, maps, outPath: resFile.data } }).pipe(
|
||||
const exportProgress$: Observable<ProgressionInterface> = this.ipcService.sendV2("export-maps", { version, maps, outPath: resFile }).pipe(
|
||||
map(p => {
|
||||
return { progression: (p.prossesedFiles / p.totalFiles) * 100, label: `${p.prossesedFiles} / ${p.totalFiles}` } as ProgressionInterface;
|
||||
return { progression: (p.current / p.total) * 100, label: `${p.current} / ${p.total}` } as ProgressionInterface;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -153,18 +146,15 @@ export class MapsManagerService {
|
||||
}
|
||||
|
||||
public async isDeepLinksEnabled(): Promise<boolean> {
|
||||
const res = await this.ipcService.send<boolean>("is-map-deep-links-enabled");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipcService.sendV2("is-map-deep-links-enabled"));
|
||||
}
|
||||
|
||||
public async enableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipcService.send<boolean>("register-maps-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipcService.sendV2("register-maps-deep-link"));
|
||||
}
|
||||
|
||||
public async disableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipcService.send<boolean>("unregister-maps-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipcService.sendV2("unregister-maps-deep-link"));
|
||||
}
|
||||
|
||||
public get versionLinked$(): Observable<BSVersion> {
|
||||
|
||||
@@ -6,7 +6,6 @@ import { ModalResponse, ModalService } from "../modale.service";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { DownloadModelsModal } from "renderer/components/modal/modal-types/models/download-models-modal.component";
|
||||
import { ProgressBarService } from "../progress-bar.service";
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import equal from "fast-deep-equal";
|
||||
|
||||
@@ -42,7 +41,7 @@ export class ModelsDownloaderService {
|
||||
}
|
||||
|
||||
private async downloadModel(download: ModelDownload) {
|
||||
const download$ = this.ipc.sendV2<Progression<BsmLocalModel>>("download-model", { args: download });
|
||||
const download$ = this.ipc.sendV2("download-model", download);
|
||||
|
||||
if (!this.progress.isVisible) {
|
||||
const progress$: Observable<ProgressionInterface> = download$.pipe(
|
||||
@@ -124,13 +123,13 @@ export class ModelsDownloaderService {
|
||||
public async oneClickInstallModel(model: MSModel): Promise<boolean> {
|
||||
this.progress.showFake(0.04);
|
||||
|
||||
const res = await this.ipc.send("one-click-install-model", { args: model });
|
||||
const res = await lastValueFrom(this.ipc.sendV2("one-click-install-model", model)).then(() => true).catch(() => false);
|
||||
|
||||
this.progress.complete();
|
||||
await timer(500).toPromise();
|
||||
await lastValueFrom(timer(500));
|
||||
this.progress.hide(true);
|
||||
|
||||
return res.success;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import { UnlinkModelsModal } from "renderer/components/modal/modal-types/models/
|
||||
import { Progression } from "main/helpers/fs.helpers";
|
||||
import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface";
|
||||
import { ProgressBarService } from "../progress-bar.service";
|
||||
import { OpenSaveDialogOption } from "shared/models/os/dialog.model";
|
||||
import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { NotificationService } from "../notification.service";
|
||||
import { ConfigurationService } from "../configuration.service";
|
||||
@@ -101,7 +100,7 @@ export class ModelsManagerService {
|
||||
}
|
||||
|
||||
public $getModels(type: MSModelType, version?: BSVersion): Observable<Progression<BsmLocalModel[]>> {
|
||||
return this.ipc.sendV2<Progression<BsmLocalModel[]>>("get-version-models", { args: { version, type } });
|
||||
return this.ipc.sendV2("get-version-models", { version, type });
|
||||
}
|
||||
|
||||
public async exportModels(models: BsmLocalModel[], version?: BSVersion) {
|
||||
@@ -109,18 +108,16 @@ export class ModelsManagerService {
|
||||
return;
|
||||
}
|
||||
|
||||
const resFile = await this.ipc.send<string, OpenSaveDialogOption>("save-file", {
|
||||
args: {
|
||||
filename: version ? `${version.name ?? version.BSVersion} Models` : "Models",
|
||||
filters: [{ name: "zip", extensions: ["zip"] }],
|
||||
},
|
||||
});
|
||||
const resFile = await lastValueFrom(this.ipc.sendV2("save-file", {
|
||||
filename: version ? `${version.name ?? version.BSVersion} Models` : "Models",
|
||||
filters: [{ name: "zip", extensions: ["zip"] }]
|
||||
})).catch(() => null as string);
|
||||
|
||||
if (!resFile.success) {
|
||||
if (!resFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const exportProgress$: Observable<ProgressionInterface> = this.ipc.sendV2<Progression, { version: BSVersion; models: BsmLocalModel[]; outPath: string }>("export-models", { args: { version, models, outPath: resFile.data } }).pipe(
|
||||
const exportProgress$ = this.ipc.sendV2("export-models", { version, models, outPath: resFile }).pipe(
|
||||
map(p => {
|
||||
return { progression: (p.current / p.total) * 100, label: `${p.current} / ${p.total}` } as ProgressionInterface;
|
||||
})
|
||||
@@ -171,7 +168,7 @@ export class ModelsManagerService {
|
||||
|
||||
const showProgressBar = this.progressBar.require();
|
||||
|
||||
const obs$ = this.ipc.sendV2<Progression<BsmLocalModel[]>>("delete-models", { args: models });
|
||||
const obs$ = this.ipc.sendV2("delete-models", models);
|
||||
|
||||
const progress$ = obs$.pipe(map(progress => (progress.current / progress.total) * 100));
|
||||
|
||||
@@ -189,16 +186,14 @@ export class ModelsManagerService {
|
||||
}
|
||||
|
||||
public isDeepLinksEnabled(): Promise<boolean> {
|
||||
return this.ipc.send<boolean>("is-models-deep-links-enabled").then(res => (res.success ? res.data : false));
|
||||
return lastValueFrom(this.ipc.sendV2("is-models-deep-links-enabled"));
|
||||
}
|
||||
|
||||
public async enableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipc.send<boolean>("register-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipc.sendV2("register-models-deep-link"));
|
||||
}
|
||||
|
||||
public async disableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipc.send<boolean>("unregister-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
return lastValueFrom(this.ipc.sendV2("unregister-models-deep-link"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
import { SystemNotificationOptions } from "shared/models/notification/system-notification.model";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { NotificationResult, NotificationType, Notification } from "../../shared/models/notification/notification.model";
|
||||
@@ -58,8 +58,8 @@ export class NotificationService {
|
||||
return this.notify(notification);
|
||||
}
|
||||
|
||||
public notifySystem(options: SystemNotificationOptions) {
|
||||
this.ipc.sendLazy<SystemNotificationOptions>("notify-system", { args: options });
|
||||
public notifySystem(options: SystemNotificationOptions): Observable<void> {
|
||||
return this.ipc.sendV2("notify-system", options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export class PlaylistDownloaderService {
|
||||
return new Observable<Progression<DownloadPlaylistProgressionData>>(subscriber => {
|
||||
(async () => {
|
||||
const playlist = await lastValueFrom(this.playlistQueue$.pipe(map(queue => queue.at(0)), filter(p => equal(bpList, p)), take(1)));
|
||||
const download$ = this.ipc.sendV2<Progression<DownloadPlaylistProgressionData>, unknown>("install-playlist", { args: { version, playlist } });
|
||||
const download$ = this.ipc.sendV2("install-playlist", { version, playlist });
|
||||
|
||||
await lastValueFrom(download$.pipe(tap(subscriber)));
|
||||
})()
|
||||
@@ -50,7 +50,7 @@ export class PlaylistDownloaderService {
|
||||
|
||||
public oneClickInstallPlaylist(bpListUrl: string): Observable<Progression<DownloadPlaylistProgressionData>> {
|
||||
|
||||
const download$ = this.ipc.sendV2<Progression<DownloadPlaylistProgressionData>, string>("one-click-install-playlist", { args: bpListUrl });
|
||||
const download$ = this.ipc.sendV2("one-click-install-playlist", bpListUrl);
|
||||
const progress$ = download$.pipe(map(data => (data.current / data.total) * 100));
|
||||
|
||||
this.progress.show(progress$, true);
|
||||
|
||||
@@ -31,11 +31,11 @@ export class PlaylistsManagerService {
|
||||
}
|
||||
|
||||
public getVersionPlaylistsDetails(version: BSVersion): Observable<Progression<LocalBPListsDetails[]>> {
|
||||
return this.ipc.sendV2("get-version-playlists-details", { args: version });
|
||||
return this.ipc.sendV2("get-version-playlists-details", version);
|
||||
}
|
||||
|
||||
public deletePlaylist(opt: {path: string, deleteMaps?: boolean}): Observable<Progression> {
|
||||
return this.ipc.sendV2<Progression, {path: string, deleteMaps?: boolean}>("delete-playlist", { args: opt });
|
||||
return this.ipc.sendV2("delete-playlist", opt);
|
||||
}
|
||||
|
||||
public async linkVersion(version: BSVersion): Promise<boolean> {
|
||||
@@ -67,15 +67,15 @@ export class PlaylistsManagerService {
|
||||
}
|
||||
|
||||
public isDeepLinksEnabled(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("is-playlists-deep-links-enabled"));
|
||||
return lastValueFrom(this.ipc.sendV2("is-playlists-deep-links-enabled"));
|
||||
}
|
||||
|
||||
public enableDeepLink(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("register-playlists-deep-link"));
|
||||
return lastValueFrom(this.ipc.sendV2("register-playlists-deep-link"));
|
||||
}
|
||||
|
||||
public disableDeepLink(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("unregister-playlists-deep-link"));
|
||||
return lastValueFrom(this.ipc.sendV2("unregister-playlists-deep-link"));
|
||||
}
|
||||
|
||||
public $playlistsFolderLinkState(version: BSVersion): Observable<FolderLinkState> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { distinctUntilChanged, map } from "rxjs/operators";
|
||||
import { BehaviorSubject, Observable, Subscription, timer, of } from "rxjs";
|
||||
import { BehaviorSubject, Observable, Subscription, timer, of, lastValueFrom } from "rxjs";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { NotificationService } from "./notification.service";
|
||||
import { CSSProperties } from "react";
|
||||
@@ -36,7 +36,7 @@ export class ProgressBarService {
|
||||
}
|
||||
|
||||
private setSystemProgression(progression: number) {
|
||||
this.ipcService.sendLazy("window.progression", { args: progression });
|
||||
lastValueFrom(this.ipcService.sendV2("window.progression", progression));
|
||||
}
|
||||
|
||||
public subscribreTo(obs: Observable<ProgressionInterface | number>) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Supporter } from "shared/models/supporters";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
export class SupportersService {
|
||||
private static instance: SupportersService;
|
||||
@@ -18,11 +19,6 @@ export class SupportersService {
|
||||
}
|
||||
|
||||
public getSupporters(): Promise<Supporter[]> {
|
||||
return this.ipcService.send<Supporter[]>("get-supporters").then(res => {
|
||||
if (!res.success) {
|
||||
return null;
|
||||
}
|
||||
return res.data;
|
||||
});
|
||||
return lastValueFrom(this.ipcService.sendV2("get-supporters"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BsvMapDetail } from "shared/models/maps";
|
||||
import { BsvPlaylist, SearchParams } from "shared/models/maps/beat-saver.model";
|
||||
import { SearchParams } from "shared/models/maps/beat-saver.model";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
export class BeatSaverService {
|
||||
private static instance: BeatSaverService;
|
||||
@@ -18,22 +19,14 @@ export class BeatSaverService {
|
||||
}
|
||||
|
||||
public async getMapDetailsFromHashs(hashs: string[]): Promise<BsvMapDetail[]> {
|
||||
const res = await this.ipc.send<BsvMapDetail[], string[]>("bsv-get-map-details-from-hashs", { args: hashs });
|
||||
return res.data ?? [];
|
||||
return lastValueFrom(this.ipc.sendV2("bsv-get-map-details-from-hashs", hashs));
|
||||
}
|
||||
|
||||
public async getMapDetailsById(id: string): Promise<BsvMapDetail> {
|
||||
const res = await this.ipc.send<BsvMapDetail, string>("bsv-get-map-details-by-id", { args: id });
|
||||
return res.data ?? null;
|
||||
return lastValueFrom(this.ipc.sendV2("bsv-get-map-details-by-id", id));
|
||||
}
|
||||
|
||||
public async searchMaps(search: SearchParams): Promise<BsvMapDetail[]> {
|
||||
const res = await this.ipc.send<BsvMapDetail[], SearchParams>("bsv-search-map", { args: search });
|
||||
return res.data ?? [];
|
||||
}
|
||||
|
||||
public async getPlaylistDetailsById(id: string): Promise<BsvPlaylist> {
|
||||
const res = await this.ipc.send<BsvPlaylist>("bsv-get-playlist-details-by-id", { args: id });
|
||||
return res.data ?? null;
|
||||
return lastValueFrom(this.ipc.sendV2("bsv-search-map", search));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MSGetQuery, MSGetQueryFilter, MSGetQueryFilterType, MSModel } from "shared/models/models/model-saber.model";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { Observable } from "rxjs";
|
||||
import { Observable, lastValueFrom } from "rxjs";
|
||||
import { MS_QUERY_FILTER_TYPES } from "shared/models/models/constants";
|
||||
|
||||
export class ModelSaberService {
|
||||
@@ -19,16 +19,12 @@ export class ModelSaberService {
|
||||
this.ipc = IpcService.getInstance();
|
||||
}
|
||||
|
||||
public async getModelById(id: number | string): Promise<MSModel> {
|
||||
const res = await this.ipc.send<MSModel>("ms-get-model-by-id", { args: id });
|
||||
if (!res.success) {
|
||||
return null;
|
||||
}
|
||||
return res.data;
|
||||
public getModelById(id: number | string): Promise<MSModel> {
|
||||
return lastValueFrom(this.ipc.sendV2("ms-get-model-by-id", id));
|
||||
}
|
||||
|
||||
public searchModels(query: MSGetQuery): Observable<MSModel[]> {
|
||||
return this.ipc.sendV2("search-models", { args: query });
|
||||
return this.ipc.sendV2("search-models", query);
|
||||
}
|
||||
|
||||
public parseFilter(stringFilters: string): MSGetQueryFilter[] {
|
||||
|
||||
@@ -59,7 +59,7 @@ export class VersionFolderLinkerService {
|
||||
}
|
||||
|
||||
private doAction(action: VersionLinkerAction): Observable<boolean> {
|
||||
return this.ipcService.sendV2<boolean, VersionLinkerAction>("link-version-folder-action", { args: action });
|
||||
return this.ipcService.sendV2("link-version-folder-action", action);
|
||||
}
|
||||
|
||||
private get currentAction$(): Observable<VersionLinkerAction> {
|
||||
@@ -126,7 +126,7 @@ export class VersionFolderLinkerService {
|
||||
}
|
||||
|
||||
public isVersionFolderLinked(version: BSVersion, relativeFolder: string): Observable<boolean> {
|
||||
return this.ipcService.sendV2("is-version-folder-linked", { args: { version, relativeFolder } });
|
||||
return this.ipcService.sendV2("is-version-folder-linked", { version, relativeFolder });
|
||||
}
|
||||
|
||||
public $folderLinkedState(version: BSVersion, relativeFolder: string): Observable<FolderLinkState> {
|
||||
@@ -159,7 +159,7 @@ export class VersionFolderLinkerService {
|
||||
}
|
||||
|
||||
public getLinkedFolders(version: BSVersion, options?: { relative?: boolean }): Observable<string[]> {
|
||||
return this.ipcService.sendV2("get-linked-folders", { args: { version, options } });
|
||||
return this.ipcService.sendV2("get-linked-folders", { version, options });
|
||||
}
|
||||
|
||||
public relinkAllVersionsFolders(): Observable<void> {
|
||||
|
||||
@@ -19,11 +19,11 @@ export class WindowManagerService {
|
||||
}
|
||||
|
||||
public openThenCloseAll(window: AppWindow): Promise<void> {
|
||||
return lastValueFrom(this.ipcService.sendV2<void>("open-window-then-close-all", { args: window }));
|
||||
return lastValueFrom(this.ipcService.sendV2("open-window-then-close-all", window));
|
||||
}
|
||||
|
||||
public openWindowOrFocus(window: AppWindow): Promise<void> {
|
||||
return lastValueFrom(this.ipcService.sendV2<void, AppWindow>("open-window-or-focus", { args: window }));
|
||||
return lastValueFrom(this.ipcService.sendV2("open-window-or-focus", window));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,25 +3,27 @@ import { BsmProgressBar } from "renderer/components/progress-bar/bsm-progress-ba
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component";
|
||||
import TitleBar from "renderer/components/title-bar/title-bar.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { MapsDownloaderService } from "renderer/services/maps-downloader.service";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { ProgressBarService } from "renderer/services/progress-bar.service";
|
||||
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { BsvMapDetail } from "shared/models/maps";
|
||||
import defaultImage from "../../../../assets/images/default-version-img.jpg";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { useWindowArgs } from "renderer/hooks/use-window-args.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function OneClickDownloadMap() {
|
||||
|
||||
const ipc = useService(IpcService);
|
||||
|
||||
const bsv = useService(BeatSaverService);
|
||||
const mapsDownloader = useService(MapsDownloaderService);
|
||||
const progressBar = useService(ProgressBarService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const { mapId, isHash } = useWindowArgs("mapId", "isHash");
|
||||
const [mapInfo, setMapInfo] = useState<BsvMapDetail>(null);
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
const cover = mapInfo ? mapInfo.versions.at(0).coverURL : null;
|
||||
@@ -31,14 +33,16 @@ export default function OneClickDownloadMap() {
|
||||
|
||||
progressBar.open();
|
||||
|
||||
const promise = (async () => {
|
||||
const ipcRes = await lastValueFrom(ipc.sendV2<{ id: string; isHash: boolean }>("one-click-map-info"));
|
||||
console.log("AAAA", mapId, isHash);
|
||||
|
||||
const mapDetails = ipcRes.isHash ? (await bsv.getMapDetailsFromHashs([ipcRes.id])).at(0) : await bsv.getMapDetailsById(ipcRes.id);
|
||||
const promise = (async () => {
|
||||
|
||||
const mapDetails = isHash === "true" ? (await bsv.getMapDetailsFromHashs([mapId])).at(0) : await bsv.getMapDetailsById(mapId);
|
||||
console.log(mapDetails);
|
||||
|
||||
setMapInfo(() => mapDetails);
|
||||
|
||||
const res = await mapsDownloader.oneClickInstallMap(mapDetails);
|
||||
|
||||
const res = await mapsDownloader.oneClickInstallMap(mapDetails).then(() => true).catch(() => false);
|
||||
|
||||
progressBar.complete();
|
||||
|
||||
@@ -57,9 +61,9 @@ export default function OneClickDownloadMap() {
|
||||
});
|
||||
|
||||
promise.finally(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,6 @@ import { BsmProgressBar } from "renderer/components/progress-bar/bsm-progress-ba
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component";
|
||||
import TitleBar from "renderer/components/title-bar/title-bar.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { ProgressBarService } from "renderer/services/progress-bar.service";
|
||||
import { ModelSaberService } from "renderer/services/thrird-partys/model-saber.service";
|
||||
@@ -11,16 +10,18 @@ import { MSModel } from "shared/models/models/model-saber.model";
|
||||
import defaultImage from "../../../../assets/images/default-version-img.jpg";
|
||||
import { ModelsDownloaderService } from "renderer/services/models-management/models-downloader.service";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { useWindowArgs } from "renderer/hooks/use-window-args.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function OneClickDownloadModel() {
|
||||
|
||||
const ipc = useService(IpcService);
|
||||
const modelSaber = useService(ModelSaberService);
|
||||
const progress = useService(ProgressBarService);
|
||||
const modelDownloader = useService(ModelsDownloaderService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const { modelId } = useWindowArgs("modelId");
|
||||
const [model, setModel] = useState<MSModel>(null);
|
||||
const t = useTranslation();
|
||||
|
||||
@@ -30,9 +31,8 @@ export default function OneClickDownloadModel() {
|
||||
useEffect(() => {
|
||||
|
||||
const promise = (async () => {
|
||||
const infos = await lastValueFrom(ipc.sendV2<{ id: string; type: string }>("one-click-model-info"));
|
||||
|
||||
const model = await modelSaber.getModelById(infos.id);
|
||||
const model = await modelSaber.getModelById(modelId);
|
||||
|
||||
if (!model) {
|
||||
throw new Error("Failed to get model from ModelSaber");
|
||||
@@ -58,7 +58,7 @@ export default function OneClickDownloadModel() {
|
||||
});
|
||||
|
||||
promise.finally(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
@@ -13,16 +13,19 @@ import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { useConstant } from "renderer/hooks/use-constant.hook";
|
||||
import { BPList } from "shared/models/playlists/playlist.interface";
|
||||
import { useOnUpdate } from "renderer/hooks/use-on-update.hook";
|
||||
import { useWindowArgs } from "renderer/hooks/use-window-args.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function OneClickDownloadPlaylist() {
|
||||
|
||||
|
||||
|
||||
const t = useTranslation();
|
||||
const playlistDownloader = useService(PlaylistDownloaderService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const mapsContainer = useRef<HTMLDivElement>(null);
|
||||
const playlistUrl = useConstant(() => new URLSearchParams(window.location.search).get("playlistUrl"));
|
||||
const { playlistUrl } = useWindowArgs("playlistUrl");
|
||||
const download$ = useConstant(() => playlistDownloader.oneClickInstallPlaylist(playlistUrl));
|
||||
const playlistInfos = useObservable<BPList>(() => download$.pipe(filter(progress => !!progress.data?.playlistInfos), map(progress => progress.data.playlistInfos), take(1)));
|
||||
const downloadedMaps = useObservable(() => download$.pipe(filter(progress => !!progress.data?.downloadedMaps), map(progress => progress.data.downloadedMaps)));
|
||||
@@ -34,7 +37,7 @@ export default function OneClickDownloadPlaylist() {
|
||||
}).catch(() => {
|
||||
notification.notifySystem({ title: t("notifications.types.error"), body: t("notifications.playlists.one-click-install.error") });
|
||||
}).finally(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
}, []);
|
||||
@@ -61,7 +64,7 @@ export default function OneClickDownloadPlaylist() {
|
||||
<BsmImage className="mt-2 aspect-square w-1/2 object-cover rounded-md shadow-black shadow-lg" placeholder={defaultImage} image={playlistImage()} errorImage={defaultImage} />
|
||||
<h1 className="mt-4 overflow-hidden font-bold italic text-xl text-gray-200 tracking-wide w-full text-center whitespace-nowrap text-ellipsis px-2">{playlistInfos?.playlistTitle}</h1>
|
||||
<div className="w-full py-3 flex items-center justify-center max-w-full overflow-x-scroll overflow-y-hidden scrollbar scrollbar-thin scrollbar-track-transparent scrollbar-thumb-neutral-900" ref={mapsContainer}>
|
||||
<div className="flex justify-start items-start gap-2.5">{downloadedMaps?.map(map => map?.coverUrl &&
|
||||
<div className="flex justify-start items-start gap-2.5">{downloadedMaps?.map(map => map?.coverUrl &&
|
||||
<motion.img layout="position" key={map.hash} className="block aspect-square w-14 object-cover rounded-md shadow-black shadow-md" src={map?.coverUrl} initial={{ scale: 0 }} animate={{ scale: 1 }} whileHover={{ rotate: 5 }} />
|
||||
)}</div>
|
||||
</div>
|
||||
|
||||
@@ -13,20 +13,22 @@ import { BsNoteFill } from "renderer/components/svgs/icons/bs-note-fill.componen
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { motion } from "framer-motion"
|
||||
import { BSLaunchError, BSLaunchEventType, LaunchOption } from "shared/models/bs-launch";
|
||||
import { BSLaunchError, BSLaunchEventType } from "shared/models/bs-launch";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { useWindowControls } from "renderer/hooks/use-window-controls.hook";
|
||||
|
||||
export default function ShortcutLaunch() {
|
||||
|
||||
|
||||
const windows = useService(WindowManagerService);
|
||||
const ipc = useService(IpcService);
|
||||
const bsLauncher = useService(BSLauncherService);
|
||||
const notification = useService(NotificationService);
|
||||
|
||||
const { close: closeWindow } = useWindowControls();
|
||||
const t = useTranslation();
|
||||
const color = useThemeColor("second-color");
|
||||
const launchOptions = useObservable(() => ipc.sendV2<LaunchOption>("shortcut-launch-options").pipe(take(1)), null)
|
||||
const launchOptions = useObservable(() => ipc.sendV2("shortcut-launch-options").pipe(take(1)), null)
|
||||
const [rotation, setRotation] = useState(0);
|
||||
const [status, setStatus] = useState<BSLaunchEventType>();
|
||||
|
||||
@@ -57,7 +59,7 @@ export default function ShortcutLaunch() {
|
||||
});
|
||||
|
||||
sub.add(() => {
|
||||
window.electron.window.close();
|
||||
closeWindow();
|
||||
});
|
||||
|
||||
return () => sub.unsubscribe();
|
||||
|
||||
Reference in New Issue
Block a user