diff --git a/assets/jsons/translations/de.json b/assets/jsons/translations/de.json index a776735d9..066256e49 100644 --- a/assets/jsons/translations/de.json +++ b/assets/jsons/translations/de.json @@ -362,7 +362,7 @@ "steam":{ "steam-launching":{ "title": "Steam startet!", - "description": "Abhängig von deiner Konfiguration kann es einige Zeit dauern, bis Steam gestartet wird." + "description": "Beat Saber wird automatisch nach Steam gestartet." } }, "custom-version": { diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index 4d0cfbb61..87ead7b0c 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -362,7 +362,7 @@ "steam":{ "steam-launching":{ "title": "Steam is launching!", - "description": "Steam may take some time to launch depending on your configuration." + "description": "Beat Saber will automatically launch after Steam." } }, "custom-version": { diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index 68a983292..55a6dadf6 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -361,7 +361,7 @@ "steam":{ "steam-launching":{ "title": "¡Steam se está iniciando!", - "description": "Steam puede tardar un poco en iniciarse dependiendo de tu configuración." + "description": "Beat Saber se lanzará automáticamente después de Steam." } }, "custom-version": { diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index 3221fd195..8e7d43056 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -361,7 +361,7 @@ "steam":{ "steam-launching":{ "title": "Steam se lance !", - "description": "Steam peut mettre quelque temps à se lancer selon votre configuration." + "description": "Beat Saber se lancera automatiquement après Steam." } }, "custom-version": { diff --git a/src/main/main.ts b/src/main/main.ts index d194a6fda..07bd83285 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -21,7 +21,6 @@ import { LocalModelsManagerService } from './services/additional-content/local-m import { APP_NAME } from './constants'; import { BSLauncherService } from './services/bs-launcher.service'; import { IpcRequest } from 'shared/models/ipc'; -import { MSModelType } from '../shared/models/models/model-saber.model'; const isDebug = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; diff --git a/src/main/services/bs-launcher.service.ts b/src/main/services/bs-launcher.service.ts index dda6d49e4..02eae74d7 100644 --- a/src/main/services/bs-launcher.service.ts +++ b/src/main/services/bs-launcher.service.ts @@ -10,6 +10,8 @@ import { pathExist } from "../helpers/fs.helpers"; import { rename } from "fs/promises"; import log from "electron-log"; import { timer } from "rxjs"; +import { NotificationService } from "./notification.service"; +import { NotificationType } from "../../shared/models/notification/notification.model"; export class BSLauncherService{ @@ -19,6 +21,7 @@ export class BSLauncherService{ private readonly steamService: SteamService; private readonly oculusService: OculusService; private readonly localVersionService: BSLocalVersionService; + private readonly notification: NotificationService; private bsProcess: ChildProcessWithoutNullStreams; @@ -32,6 +35,7 @@ export class BSLauncherService{ this.steamService = SteamService.getInstance(); this.oculusService = OculusService.getInstance(); this.localVersionService = BSLocalVersionService.getInstance(); + this.notification = NotificationService.getInstance(); } private getSteamVRPath(): Promise{ @@ -55,10 +59,22 @@ export class BSLauncherService{ return this.bsProcess?.connected || this.utilsService.taskRunning(BS_EXECUTABLE) === true; } + // TODO : Rework with shortcuts implementation public async launch(launchOptions: LauchOption): Promise{ - if(launchOptions.version.oculus && this.oculusService.oculusRunning() === false){ return "OCULUS_NOT_RUNNING" } - if(!launchOptions.version.oculus && this.steamService.steamRunning() === false){ return "STEAM_NOT_RUNNING" } if(this.isBsRunning() === true){ return "BS_ALREADY_RUNNING" } + if(launchOptions.version.oculus && this.oculusService.oculusRunning() === false){ return "OCULUS_NOT_RUNNING" } + + const steamRunning = await this.steamService.steamRunning().catch(() => true); // True if error (error not not means that steam is not running) + if(!launchOptions.version.oculus && !steamRunning){ + + this.notification.notifyRenderer({ + title: "notifications.steam.steam-launching.title", + desc: "notifications.steam.steam-launching.description", + type: NotificationType.SUCCESS, + }); + + await this.steamService.openSteam().catch(log.error); + } const cwd = await this.localVersionService.getVersionPath(launchOptions.version); const exePath = path.join(cwd, BS_EXECUTABLE); diff --git a/src/main/services/ipc.service.ts b/src/main/services/ipc.service.ts index 36ee016bf..4f239c5d4 100644 --- a/src/main/services/ipc.service.ts +++ b/src/main/services/ipc.service.ts @@ -44,7 +44,7 @@ export class IpcService { this.windows.getWindow(window)?.webContents?.send(channel, response); } - public connectStream(channel: IpcChannel, window: AppWindow, observable: Observable): void{ + private connectStream(channel: IpcChannel, window: AppWindow, observable: Observable): void{ observable.subscribe(data => { this.send(channel, window, data); }, error => { diff --git a/src/main/services/notification.service.ts b/src/main/services/notification.service.ts index 74277badd..0d200132d 100644 --- a/src/main/services/notification.service.ts +++ b/src/main/services/notification.service.ts @@ -1,6 +1,8 @@ -import { Notification } from "electron"; import { SystemNotificationOptions } from "shared/models/notification/system-notification.model"; import { UtilsService } from "./utils.service"; +import { Notification } from "electron"; +import { Notification as NotificationRenderer } from "../../shared/models/notification/notification.model"; +import { IpcService } from "./ipc.service"; export class NotificationService { @@ -14,9 +16,11 @@ export class NotificationService { private readonly APP_ICON: string; private readonly utils: UtilsService; + private readonly ipc: IpcService; private constructor(){ this.utils = UtilsService.getInstance(); + this.ipc = IpcService.getInstance(); this.APP_ICON = this.utils.getAssetsPath("favicon.ico"); } @@ -24,4 +28,15 @@ export class NotificationService { new Notification({...options, icon: this.APP_ICON}).show(); } + // TODO : Make actions work + public notifyRenderer(notification: Omit){ + try{ + this.ipc.send("show-notification", "index.html", notification); + } + catch(e){ + console.error(e); + } + + } + } \ No newline at end of file diff --git a/src/main/services/steam.service.ts b/src/main/services/steam.service.ts index b4e570a7c..c7e4ce382 100644 --- a/src/main/services/steam.service.ts +++ b/src/main/services/steam.service.ts @@ -25,9 +25,20 @@ export class SteamService{ return SteamService.instance; } - public steamRunning(): boolean | null{ - return this.utils.taskRunning('steam.exe'); - } + public async getActiveUser(): Promise{ + const res = await regedit.promisified.list(["HKCU\\Software\\Valve\\Steam\\ActiveProcess"]); + const keys = res?.["HKCU\\Software\\Valve\\Steam\\ActiveProcess"]; + + if(!keys?.exists){ throw "Key \"HKCU\\Software\\Valve\\Steam\\ActiveProcess\" not exist"; } + + return (keys.values?.ActiveUser.value || undefined) as number; + } + + public steamRunning(): Promise{ + return this.getActiveUser() + .then(userId => !!userId) + .catch(e => {log.error(e); throw e}) + } public async getSteamPath(): Promise{ @@ -71,12 +82,25 @@ export class SteamService{ } } - public openSteam(): Promise{ + public openSteam(): Promise{ const process = spawn("start", ["steam://open/games"], {shell: true}); - return new Promise(resolve => { - process.on("exit", () => resolve(true)); - process.on("error", () => resolve(false)); + process.on("error", log.error); + + return new Promise(async (resolve, reject) => { + // Every 3 seconds check if steam is running + const interval = setInterval(async () => { + const steamRunning = await this.steamRunning().catch(() => false); + if(!steamRunning){ return; } + clearInterval(interval); + resolve(); + }, 3000); + + // If steam is not running after 60 seconds, reject + setTimeout(() => { + clearInterval(interval); + reject("Unable to open steam"); + }, 60_000); }); } diff --git a/src/renderer/components/notification/notification-item.component.tsx b/src/renderer/components/notification/notification-item.component.tsx index 3b9013311..43ce904c7 100644 --- a/src/renderer/components/notification/notification-item.component.tsx +++ b/src/renderer/components/notification/notification-item.component.tsx @@ -1,4 +1,4 @@ -import { NotificationResult, NotificationType, Notification } from "renderer/services/notification.service" +import { NotificationResult, NotificationType, Notification } from "../../../shared/models/notification/notification.model" import { motion, PanInfo } from "framer-motion" import { BsmImage } from "../shared/bsm-image.component"; import BeatRunningImg from "../../../../assets/images/apngs/beat-running.png"; diff --git a/src/renderer/services/bs-launcher.service.ts b/src/renderer/services/bs-launcher.service.ts index 9e5131227..78523108c 100644 --- a/src/renderer/services/bs-launcher.service.ts +++ b/src/renderer/services/bs-launcher.service.ts @@ -1,9 +1,10 @@ import { LauchOption, LaunchResult } from "shared/models/bs-launch"; import { BSVersion } from 'shared/bs-version.interface'; import { IpcService } from "./ipc.service"; -import { NotificationResult, NotificationService } from "./notification.service"; +import { NotificationService } from "./notification.service"; import { BsDownloaderService } from "./bs-downloader.service"; import { BehaviorSubject } from "rxjs"; +import { NotificationResult } from "shared/models/notification/notification.model"; export class BSLauncherService{ @@ -39,7 +40,7 @@ export class BSLauncherService{ } - + // TODO : Rework with shortcuts implementation public launch(version: BSVersion, oculus: boolean, desktop: boolean, debug: boolean, additionalArgs?: string[]): Promise{ const lauchOption: LauchOption = {debug, oculus, desktop, version, additionalArgs}; if(this.launchState$.value){ return this.notificationService.notifyError({title: "notifications.bs-launch.errors.titles.BS_ALREADY_RUNNING"}); } @@ -59,18 +60,6 @@ export class BSLauncherService{ }); } if(res.data){ - // TODO : too much nesting here, need refactor - if(res.data === "STEAM_NOT_RUNNING"){ - return new Promise(async resolve => { - const notif = await this.notificationService.notifyError({title: `notifications.bs-launch.errors.titles.${res.data}`, actions: [{id: "0", title: `notifications.bs-launch.errors.actions.${res.data}`}]}); - if(notif === "0"){ - await this.ipcService.send("open-steam"); - const lastNotif = await this.notificationService.notifySuccess({title: "notifications.steam.steam-launching.title", desc: "notifications.steam.steam-launching.description"}); - resolve(lastNotif); - } - resolve(notif) - }) - } return this.notificationService.notifyError({title: `notifications.bs-launch.errors.titles.${res.data}`}); } return this.notificationService.notifyError({title: res.data || res.error.title}); diff --git a/src/renderer/services/bs-mods-manager.service.ts b/src/renderer/services/bs-mods-manager.service.ts index a7568b94a..844c15885 100644 --- a/src/renderer/services/bs-mods-manager.service.ts +++ b/src/renderer/services/bs-mods-manager.service.ts @@ -9,9 +9,10 @@ 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"; -import { NotificationService, NotificationType } from "./notification.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"; export class BsModsManagerService { diff --git a/src/renderer/services/ipc.service.ts b/src/renderer/services/ipc.service.ts index a06f43d1b..3c5b44a7b 100644 --- a/src/renderer/services/ipc.service.ts +++ b/src/renderer/services/ipc.service.ts @@ -35,6 +35,7 @@ export class IpcService{ window.electron.ipcRenderer.sendMessage(channel, request); } + // Also need a rework public watch(channel: string): Observable>{ if(this.channelObservables.has(channel)){ return this.channelObservables.get(channel) as Observable>; } diff --git a/src/renderer/services/notification.service.ts b/src/renderer/services/notification.service.ts index 942a365af..0d59b0746 100644 --- a/src/renderer/services/notification.service.ts +++ b/src/renderer/services/notification.service.ts @@ -1,6 +1,7 @@ import { BehaviorSubject } 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"; export class NotificationService{ @@ -20,6 +21,11 @@ export class NotificationService{ private constructor(){ this.ipc = IpcService.getInstance(); this.notifications$ = new BehaviorSubject([]); + + // TODO : Make actions work and adapt with "watch" remork + this.ipc.watch("show-notification").subscribe(notification => { + this.notify(notification as any as Notification); + }); } public notify(notification: Notification): Promise{ @@ -64,32 +70,6 @@ export class NotificationService{ } -export interface Notification { - title: string, - type?: NotificationType - desc?: string, - actions?: NotificationAction[], - duration?: number, -} - -export enum NotificationType { - SUCCESS = 0, - WARNING = 1, - ERROR = 2, - INFO = 3, -} - -export interface NotificationAction { - id: string, - title: string, - cancel?: boolean -} - -export enum NotificationResult { - NO_CHOICE = "no_choice", - CLOSE = "close", -} - interface ResolvableNotification{ id: string, resolver: (value: NotificationResult|string) => void, diff --git a/src/shared/models/notification/notification.model.ts b/src/shared/models/notification/notification.model.ts new file mode 100644 index 000000000..17ec5dfb8 --- /dev/null +++ b/src/shared/models/notification/notification.model.ts @@ -0,0 +1,25 @@ +export interface Notification { + title: string, + type?: NotificationType + desc?: string, + actions?: NotificationAction[], + duration?: number, +} + +export enum NotificationType { + SUCCESS = 0, + WARNING = 1, + ERROR = 2, + INFO = 3, +} + +export interface NotificationAction { + id: string, + title: string, + cancel?: boolean +} + +export enum NotificationResult { + NO_CHOICE = "no_choice", + CLOSE = "close", +} \ No newline at end of file