From 55aeab896c48794c30dc04690b821fe6252e3296 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 1 Sep 2024 18:08:03 +0200 Subject: [PATCH] [feature] disable hardware acceleration and use symlinks work, just still need to translate --- src/main/helpers/fs.helpers.ts | 2 +- src/main/ipcs/index.ts | 1 + src/main/ipcs/os-controls-ipcs.ts | 12 ++- src/main/ipcs/static-configuration.ipcs.ts | 14 ++++ src/main/main.ts | 11 ++- .../maps/song-details-cache.service.ts | 10 +-- src/main/services/folder-linker.service.ts | 23 +++++- .../services/installation-location.service.ts | 14 ++-- .../services/static-configuration.service.ts | 73 +++++++++++++++++ .../modal/basic-modal.component.tsx | 42 ++++++++++ .../shared/toogle-switch.component.tsx | 26 +++--- .../pages/settings-page.component.tsx | 81 +++++++++++++++++-- .../services/static-configuration.service.ts | 30 +++++++ src/shared/models/ipc/ipc-routes.ts | 6 ++ 14 files changed, 310 insertions(+), 35 deletions(-) create mode 100644 src/main/ipcs/static-configuration.ipcs.ts create mode 100644 src/main/services/static-configuration.service.ts create mode 100644 src/renderer/components/modal/basic-modal.component.tsx create mode 100644 src/renderer/services/static-configuration.service.ts diff --git a/src/main/helpers/fs.helpers.ts b/src/main/helpers/fs.helpers.ts index 8e663954..a24284f3 100644 --- a/src/main/helpers/fs.helpers.ts +++ b/src/main/helpers/fs.helpers.ts @@ -153,7 +153,7 @@ export async function copyDirectoryWithJunctions(src: string, dest: string, opti const symlinkTarget = await readlink(sourcePath); const relativePath = path.relative(src, symlinkTarget); const newTarget = path.join(dest, relativePath); - await symlink(newTarget, destinationPath, "junction"); + await symlink(newTarget, destinationPath, "junction"); // Only junction to avoid right issues while copying content of BSManager folder } } } diff --git a/src/main/ipcs/index.ts b/src/main/ipcs/index.ts index 2da80a78..38384c27 100644 --- a/src/main/ipcs/index.ts +++ b/src/main/ipcs/index.ts @@ -12,3 +12,4 @@ import "./bs-playlist-ipcs"; import "./model-saber.ipcs"; import "./bs-model-ipcs"; import "./bs-version-download/bs-download-ipcs"; +import "./static-configuration.ipcs"; diff --git a/src/main/ipcs/os-controls-ipcs.ts b/src/main/ipcs/os-controls-ipcs.ts index 110c3de7..4f39e4a0 100644 --- a/src/main/ipcs/os-controls-ipcs.ts +++ b/src/main/ipcs/os-controls-ipcs.ts @@ -3,6 +3,7 @@ import { NotificationService } from "../services/notification.service"; import { IpcService } from "../services/ipc.service"; import { from, of } from "rxjs"; import { readFileSync } from "fs-extra"; +import log from "electron-log"; // TODO IMPROVE WINDOW CONTROL BY USING WINDOW SERVICE @@ -16,7 +17,7 @@ ipc.on("choose-folder", (args, reply) => { reply(from(dialog.showOpenDialog({ properties: ["openDirectory"], defaultPath: args ?? "" }))); }); -ipc.on("choose-file", async (args, reply) => { +ipc.on("choose-file", async (args, reply) => { reply(from(dialog.showOpenDialog({ properties: ["openFile"], defaultPath: args ?? "" }))); }); @@ -62,3 +63,12 @@ ipc.on("choose-image", (args, reply) => { return res.filePaths; }))); }); + +ipc.on("restart-app", (_, reply) => { + log.info("App was requested to restart"); + + reply(of()); // Reply before restarting to avoid any issue + + app.relaunch(); + app.quit(); +}); diff --git a/src/main/ipcs/static-configuration.ipcs.ts b/src/main/ipcs/static-configuration.ipcs.ts new file mode 100644 index 00000000..586b04e5 --- /dev/null +++ b/src/main/ipcs/static-configuration.ipcs.ts @@ -0,0 +1,14 @@ +import { of } from "rxjs"; +import { IpcService } from "../services/ipc.service"; +import { StaticConfigurationService } from "../services/static-configuration.service"; + +const ipc = IpcService.getInstance(); +const staticConfig = StaticConfigurationService.getInstance(); + +ipc.on("static-configuration.get", (args, reply) => { + reply(of(staticConfig.get(args))); +}); + +ipc.on("static-configuration.set", (args, reply) => { + reply(of(staticConfig.set(args.key, args.value))); +}); diff --git a/src/main/main.ts b/src/main/main.ts index 8ff6f65b..42d73836 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -24,8 +24,10 @@ import { SteamLauncherService } from "./services/bs-launcher/steam-launcher.serv import { FileAssociationService } from "./services/file-association.service"; import { SongDetailsCacheService } from "./services/additional-content/maps/song-details-cache.service"; import { readdirSync, statSync, unlinkSync } from "fs-extra"; +import { StaticConfigurationService } from "./services/static-configuration.service"; const isDebug = process.env.NODE_ENV === "development" || process.env.DEBUG_PROD === "true"; +const staticConfig = StaticConfigurationService.getInstance(); export const filterStrings = new Set(); export const filterPatterns = new Set(); @@ -37,6 +39,13 @@ initLogger(); deleteOlestLogs(); deleteOldLogs(); +staticConfig.take("disable-hadware-acceleration", disabled => { + if(disabled === true){ // strictly check for true + log.info("Disabling hardware acceleration"); + app.disableHardwareAcceleration(); + } +}); + if (process.env.NODE_ENV === "production") { const sourceMapSupport = require("source-map-support"); @@ -108,7 +117,7 @@ if (!gotTheLock) { app.whenReady().then(() => { - // C:\\Users\\Mathieu\\Desktop\\BSManager\\BSInstances\\My Version\\UserData\\SongDetailsCache.proto + app.setAppUserModelId(APP_NAME); diff --git a/src/main/services/additional-content/maps/song-details-cache.service.ts b/src/main/services/additional-content/maps/song-details-cache.service.ts index b374fd42..b8f777cf 100644 --- a/src/main/services/additional-content/maps/song-details-cache.service.ts +++ b/src/main/services/additional-content/maps/song-details-cache.service.ts @@ -1,7 +1,6 @@ import path from "path"; import { ensureDirSync, existsSync, readFile, writeFile } from "fs-extra"; import { BehaviorSubject, Observable, catchError, filter, lastValueFrom, of, take, timeout } from "rxjs"; -import { ConfigurationService } from "../../configuration.service"; import { RequestService } from "../../request.service"; import { tryit } from "shared/helpers/error.helpers"; import { CACHE_PATH, HTTP_STATUS_CODES } from "main/constants"; @@ -12,6 +11,7 @@ import { SongDetails } from "shared/models/maps/song-details-cache/song-details- import { inflate } from "pako"; import { RawSongDetailsCache } from "shared/models/maps/song-details-cache/raw-song-details-cache.model"; import { RawSongDetailsDeserializer } from "shared/models/maps/song-details-cache/raw-song-details-deserializer.class"; +import { StaticConfigurationService } from "main/services/static-configuration.service"; export class SongDetailsCacheService { @@ -32,7 +32,7 @@ export class SongDetailsCacheService { private readonly PROTO_CACHE_PATH = path.join(CACHE_PATH, "song-details-cache"); private readonly etagKey = "song-details-cache-etag"; - private readonly config: ConfigurationService; + private readonly staticConfig: StaticConfigurationService; private readonly request: RequestService; private readonly utils: UtilsService; @@ -41,7 +41,7 @@ export class SongDetailsCacheService { private readonly _loaded$ = new BehaviorSubject(null); private constructor(){ - this.config = ConfigurationService.getInstance(); + this.staticConfig = StaticConfigurationService.getInstance(); this.request = RequestService.getInstance(); this.utils = UtilsService.getInstance(); this.loadCache() @@ -49,10 +49,10 @@ export class SongDetailsCacheService { private async loadCache(): Promise { const protoCacheExists = existsSync(this.PROTO_CACHE_PATH); - const etag = protoCacheExists ? this.config.get(this.etagKey) : null; + const etag = protoCacheExists ? this.staticConfig.get(this.etagKey) : null; await this.downloadCacheFile(etag).then(etag => { - this.config.set(this.etagKey, etag); + this.staticConfig.set(this.etagKey, etag); log.info("SongDetailsCache downloaded"); this.songDetailsIdIndex = this.createIdIndex(this.songDetailsCache); log.info("SongDetailsIdIndex created"); diff --git a/src/main/services/folder-linker.service.ts b/src/main/services/folder-linker.service.ts index 42f7686c..134be320 100644 --- a/src/main/services/folder-linker.service.ts +++ b/src/main/services/folder-linker.service.ts @@ -6,6 +6,7 @@ import path from "path"; import { copy, readlink } from "fs-extra"; import { lastValueFrom } from "rxjs"; import { noop } from "shared/helpers/function.helpers"; +import { StaticConfigurationService } from "./static-configuration.service"; export class FolderLinkerService { private static instance: FolderLinkerService; @@ -18,9 +19,20 @@ export class FolderLinkerService { } private readonly installLocationService = InstallationLocationService.getInstance(); + private readonly staticConfig: StaticConfigurationService; + + private linkingType: "junction" | "symlink" = "junction"; private constructor() { this.installLocationService = InstallationLocationService.getInstance(); + this.staticConfig = StaticConfigurationService.getInstance(); + + this.linkingType = this.staticConfig.get("use-symlinks") === true ? "symlink" : "junction"; + + this.staticConfig.$watch("use-symlinks").subscribe(({ newValue: useSymlink }) => { + this.linkingType = useSymlink === true ? "symlink" : "junction"; + log.info(`Linking type set to ${this.linkingType}`); + }); } private async sharedFolder(): Promise { @@ -51,6 +63,10 @@ export class FolderLinkerService { }); } + private getLinkingType(): "junction" | undefined { + return this.linkingType === "junction" ? "junction" : undefined; + } + public async linkFolder(folderPath: string, options?: LinkOptions): Promise { const sharedPath = await this.getSharedFolder(folderPath, options?.intermediateFolder); @@ -62,7 +78,9 @@ export class FolderLinkerService { return; } await unlinkPath(folderPath); - return symlink(sharedPath, folderPath, "junction"); + + log.info(`Linking ${folderPath} to ${sharedPath}; type: ${this.linkingType}`); + return symlink(sharedPath, folderPath, this.getLinkingType()); } await ensureFolderExist(sharedPath); @@ -79,7 +97,8 @@ export class FolderLinkerService { await deleteFolder(folderPath); - return symlink(sharedPath, folderPath, "junction"); + log.info(`Linking ${folderPath} to ${sharedPath}; type: ${this.linkingType}`); + return symlink(sharedPath, folderPath, this.getLinkingType()); } public async unlinkFolder(folderPath: string, options?: UnlinkOptions): Promise { diff --git a/src/main/services/installation-location.service.ts b/src/main/services/installation-location.service.ts index d8afcef3..58ef547e 100644 --- a/src/main/services/installation-location.service.ts +++ b/src/main/services/installation-location.service.ts @@ -1,9 +1,9 @@ import path from "path"; import { app } from "electron"; -import ElectronStore from "electron-store"; import { copyDirectoryWithJunctions, deleteFolder, ensureFolderExist } from "../helpers/fs.helpers"; import { tryit } from "../../shared/helpers/error.helpers"; import { pathExistsSync } from "fs-extra"; +import { StaticConfigurationService } from "./static-configuration.service"; export class InstallationLocationService { private static instance: InstallationLocationService; @@ -23,15 +23,15 @@ export class InstallationLocationService { private readonly STORE_INSTALLATION_PATH_KEY = "installation-folder"; - private readonly installPathConfig: ElectronStore; + private readonly staticConfig: StaticConfigurationService; private readonly updateListeners: Set = new Set(); private _installationDirectory: string; private constructor() { - this.installPathConfig = new ElectronStore({ watch: true }); + this.staticConfig = StaticConfigurationService.getInstance(); - this.installPathConfig.onDidChange(this.STORE_INSTALLATION_PATH_KEY, () => { + this.staticConfig.$watch(this.STORE_INSTALLATION_PATH_KEY).subscribe(() => { this.triggerListeners(); }); } @@ -48,7 +48,7 @@ export class InstallationLocationService { await copyDirectoryWithJunctions(oldDir, path.join(newDir, this.INSTALLATION_FOLDER), { overwrite: true }); this._installationDirectory = newDir; - this.installPathConfig.set(this.STORE_INSTALLATION_PATH_KEY, newDir); + this.staticConfig.set(this.STORE_INSTALLATION_PATH_KEY, newDir); deleteFolder(oldDir); @@ -66,8 +66,8 @@ export class InstallationLocationService { return this._installationDirectory; } - if(this.installPathConfig.has(this.STORE_INSTALLATION_PATH_KEY)) { - return this.installPathConfig.get(this.STORE_INSTALLATION_PATH_KEY) as string; + if(this.staticConfig.has(this.STORE_INSTALLATION_PATH_KEY)) { + return this.staticConfig.get(this.STORE_INSTALLATION_PATH_KEY) as string; } const { result: oldPath } = tryit(() => path.join(app.getPath("documents"), this.INSTALLATION_FOLDER)); diff --git a/src/main/services/static-configuration.service.ts b/src/main/services/static-configuration.service.ts new file mode 100644 index 00000000..e36ea64b --- /dev/null +++ b/src/main/services/static-configuration.service.ts @@ -0,0 +1,73 @@ +import ElectronStore from "electron-store"; +import { Observable } from "rxjs"; + +export class StaticConfigurationService { + private static instance: StaticConfigurationService; + + public static getInstance(): StaticConfigurationService { + if (!StaticConfigurationService.instance) { + StaticConfigurationService.instance = new StaticConfigurationService(); + } + return StaticConfigurationService.instance; + } + + private readonly store: ElectronStore; + + private constructor() { + this.store = new ElectronStore({ watch: true }); + } + + public has(key: K): boolean { + return this.store.has(key); + } + + public get(key: K): StaticConfigKeyValues[K] { + return this.store.get(key) as StaticConfigKeyValues[K]; + } + + public take(key: K, cb: (val: StaticConfigKeyValues[K]) => void): void { + cb(this.get(key)); + } + + public set(key: K, value: StaticConfigKeyValues[K]): void { + this.store.set(key, value); + } + + public delete(key: K): void { + this.store.delete(key); + } + + public getStore(): ElectronStore { + return this.store; + } + + public $watch(key: K): Observable<{ newValue: StaticConfigKeyValues[K], oldValue: StaticConfigKeyValues[K] }> { + return new Observable(obs => { + const unsub = this.store.onDidChange(key, (newValue, oldValue) => { + obs.next({ newValue, oldValue } as { newValue: StaticConfigKeyValues[K], oldValue: StaticConfigKeyValues[K] }); + }); + + return () => unsub(); + }) + } +} + +export interface StaticConfigKeyValues { + "installation-folder": string; + "song-details-cache-etag": string; + "disable-hadware-acceleration": boolean; + "use-symlinks": boolean; +} + +export type StaticConfigKeys = keyof StaticConfigKeyValues; + +export type StaticConfigGetIpcRequestResponse = { + request: K; + response: StaticConfigKeyValues[K]; +}; + +export type StaticConfigSetIpcRequest = { + request: { key: K, value: StaticConfigKeyValues[K] }; + response: void; +} + diff --git a/src/renderer/components/modal/basic-modal.component.tsx b/src/renderer/components/modal/basic-modal.component.tsx new file mode 100644 index 00000000..9e8c3e3e --- /dev/null +++ b/src/renderer/components/modal/basic-modal.component.tsx @@ -0,0 +1,42 @@ +import { BsmButton, BsmButtonType } from "renderer/components/shared/bsm-button.component"; +import { BsmImage } from "renderer/components/shared/bsm-image.component"; +import { cn } from "renderer/helpers/css-class.helpers"; +import { useTranslation } from "renderer/hooks/use-translation.hook"; +import { ModalComponent, ModalExitCode } from "renderer/services/modale.service"; + +type BasicModalOptions = { + title: string; + image: string; + body?: string; + buttons?: { + id: string; + text: string; + type: BsmButtonType, + isCancel?: boolean; + }[]; + buttonsLayout?: "row" | "column"; +}; + +export const BasicModal: ModalComponent = ({ resolver, options: { + data: { title, image, body, buttons, buttonsLayout = "column" } +} }) => { + + const t = useTranslation(); + + const handleClick = (button: BasicModalOptions["buttons"][0]) => { + resolver({ exitCode: button.isCancel ? ModalExitCode.CANCELED : ModalExitCode.COMPLETED, data: button.id }); + } + + return ( +
+

{t(title)}

+ + { body &&

{t(body)}

} +
+ {buttons.map(button => ( + handleClick(button)} withBar={false} text={button.text} /> + ))} +
+ + ); +}; diff --git a/src/renderer/components/shared/toogle-switch.component.tsx b/src/renderer/components/shared/toogle-switch.component.tsx index 4a564357..9bd50456 100644 --- a/src/renderer/components/shared/toogle-switch.component.tsx +++ b/src/renderer/components/shared/toogle-switch.component.tsx @@ -34,36 +34,36 @@ export function ToogleSwitch({ checked, className, classNames, bgColor, onChange }, [dotColor]); useEffect(() => { - if (checked !== undefined) { - setIsChecked(checked); - } + setIsChecked(checked); }, [checked]); - useEffect(() => { - if (onChange) { - onChange(isChecked); - } - }, [isChecked]); - const handleCheckboxChange = () => { if (middleWare) { setIsChecked(prev => { const newState = !prev; - console.log('newState', newState); const result = middleWare(newState); if (isPromise(result)) { result.then(shouldChange => { if (shouldChange) { - setIsChecked(newState); + setIsChecked(() => { + onChange?.(newState); + return newState; + }); } }).catch(noop); } else if (result) { - setIsChecked(newState); + setIsChecked(() => { + onChange?.(newState); + return newState; + }); } return prev; }); } else { - setIsChecked(prev => !prev); + setIsChecked(prev => { + onChange?.(!prev); + return !prev; + }); } } diff --git a/src/renderer/pages/settings-page.component.tsx b/src/renderer/pages/settings-page.component.tsx index baa45363..6fac67de 100644 --- a/src/renderer/pages/settings-page.component.tsx +++ b/src/renderer/pages/settings-page.component.tsx @@ -41,9 +41,13 @@ import { OculusIcon } from "renderer/components/svgs/icons/oculus-icon.component import { BsDownloaderService } from "renderer/services/bs-version-download/bs-downloader.service"; import { AutoUpdaterService } from "renderer/services/auto-updater.service"; import BeatWaitingImg from "../../../assets/images/apngs/beat-waiting.png"; +import BeatConflict from "../../../assets/images/apngs/beat-conflict.png"; import { logRenderError } from "renderer"; import { BSLauncherService } from "renderer/services/bs-launcher.service"; import { SettingToogleSwitchGrid } from "renderer/components/settings/setting-toogle-switch-grid.component"; +import { BasicModal } from "renderer/components/modal/basic-modal.component"; +import { StaticConfigurationService } from "renderer/services/static-configuration.service"; +import { tryit } from "shared/helpers/error.helpers"; export function SettingsPage() { @@ -63,6 +67,7 @@ export function SettingsPage() { const modelsManager = useService(ModelsManagerService); const versionLinker = useService(VersionFolderLinkerService); const autoUpdater = useService(AutoUpdaterService); + const staticConfig = useService(StaticConfigurationService); const { firstColor, secondColor } = useThemeColor(); @@ -93,7 +98,7 @@ export function SettingsPage() { const [playlistsDeepLinkEnabled, setPlaylistsDeepLinkEnabled] = useState(false); const [modelsDeepLinkEnabled, setModelsDeepLinkEnabled] = useState(false); const [hasDownloaderSession, setHasDownloaderSession] = useState(false); - const [hardwareAcceleration, setHardwareAcceleration] = useState(true); + const [hardwareAccelerationEnabled, setHardwareAccelerationEnabled] = useState(true); const [useSymlink, setUseSymlink] = useState(false); const appVersion = useObservable(() => ipcService.sendV2("current-version")); @@ -106,6 +111,9 @@ export function SettingsPage() { mapsManager.isDeepLinksEnabled().then(enabled => setMapDeepLinksEnabled(() => enabled)); playlistsManager.isDeepLinksEnabled().then(enabled => setPlaylistsDeepLinkEnabled(() => enabled)); modelsManager.isDeepLinksEnabled().then(enabled => setModelsDeepLinkEnabled(() => enabled)); + + staticConfig.get("disable-hadware-acceleration").then(disabled =>setHardwareAccelerationEnabled(() => disabled === false)); + staticConfig.get("use-symlinks").then(useSymlinks => setUseSymlink(() => useSymlinks)); }, []); const allDeepLinkEnabled = mapDeepLinksEnabled && playlistsDeepLinkEnabled && modelsDeepLinkEnabled; @@ -222,14 +230,77 @@ export function SettingsPage() { }); }; - const onChangeHardwareAcceleration = async (enabled: boolean): Promise => { - if(enabled === hardwareAcceleration){ return false; } + const onAboutToChangeHardwareAcceleration = async (enabled: boolean): Promise => { + if(enabled === hardwareAccelerationEnabled){ return false; } + const res = await modalService.openModal(BasicModal, { data: { + title: "Restart Needed", + body: "Changing hardware acceleration setting will quit and re-launch BSManager. Are you sure you want to do this?", + image: BeatConflict, + buttons: [ + { id: "cancel", text: "Cancel", type: "cancel", isCancel: true }, + { id: "confirm", text: "Yes I'm sure", type: "error" } + ] + }}); + + if(res.exitCode !== ModalExitCode.COMPLETED || res.data !== "confirm"){ + return false; + } return true; }; + const onChangeHardwareAcceleration = async (enabled: boolean) => { + + const { error } = await tryit(() => staticConfig.set("disable-hadware-acceleration", !enabled)); + + if(error){ + notificationService.notifyError({ title: "notifications.types.error", desc: "An error occur, unable to disable hardware acceleration" }); + return; + } + + setHardwareAccelerationEnabled(() => enabled); + + if(!progressBarService.require()){ + return; + } + + await lastValueFrom(ipcService.sendV2("restart-app")); + }; + + const onAboutToChangeUseSymlinks = async (newUseSymlink: boolean): Promise => { + if(newUseSymlink === useSymlink){ return false; } + if(!newUseSymlink){ return true; } // If we are disabling symlinks, no need to inform about admin rights + + const res = await modalService.openModal(BasicModal, { data: { + title: "Permission Needed", + body: "In order to create symlinks, BSManager will need to run as administrator or your system will need to have developer mode enabled. Are you sure you want to do this?", + image: BeatConflict, + buttons: [ + { id: "cancel", text: "Cancel", type: "cancel", isCancel: true }, + { id: "confirm", text: "Yes I'm sure", type: "error" } + ] + }}); + + if(res.exitCode !== ModalExitCode.COMPLETED || res.data !== "confirm"){ + return false; + } + + return true; + } + + const onChangeUseSymlinks = async (useSymlink: boolean) => { + const { error } = await tryit(() => staticConfig.set("use-symlinks", useSymlink)); + + if(error){ + notificationService.notifyError({ title: "notifications.types.error", desc: "An error occur, unable to change symlinks settings" }); + return; + } + + setUseSymlink(() => useSymlink); + } + const toogleShowSupporters = () => { setShowSupporters(show => !show); }; @@ -514,8 +585,8 @@ export function SettingsPage() { {} }, + { checked: hardwareAccelerationEnabled, text: "Hadware Acceleration", desc: "Enable Hardware Acceleration to use your GPU and improve BSManager's performance. Turn this off if you're experiencing frame drops.", middleWare: onAboutToChangeHardwareAcceleration, onChange: onChangeHardwareAcceleration }, + { checked: useSymlink, text: "Use Symlinks", desc: "Use Symlinks instead of Junctions to link folders. Turn this on only if you really need it.", middleWare: onAboutToChangeUseSymlinks, onChange: onChangeUseSymlinks }, ]}/> diff --git a/src/renderer/services/static-configuration.service.ts b/src/renderer/services/static-configuration.service.ts new file mode 100644 index 00000000..69d177a9 --- /dev/null +++ b/src/renderer/services/static-configuration.service.ts @@ -0,0 +1,30 @@ +import { StaticConfigKeys, StaticConfigKeyValues } from "main/services/static-configuration.service"; +import { IpcService } from "./ipc.service"; +import { lastValueFrom } from "rxjs"; + +export class StaticConfigurationService { + + private static instance: StaticConfigurationService; + + public static getInstance(): StaticConfigurationService { + if (!StaticConfigurationService.instance) { + StaticConfigurationService.instance = new StaticConfigurationService(); + } + return StaticConfigurationService.instance; + } + + private readonly ipc: IpcService; + + private constructor(){ + this.ipc = IpcService.getInstance(); + } + + public get(key: K): Promise { + return lastValueFrom(this.ipc.sendV2("static-configuration.get", key)) as Promise; + } + + public set(key: K, value: StaticConfigKeyValues[K]): Promise { + return lastValueFrom(this.ipc.sendV2("static-configuration.set", { key, value })); + } + +} diff --git a/src/shared/models/ipc/ipc-routes.ts b/src/shared/models/ipc/ipc-routes.ts index d32ff3cc..2589a7c0 100644 --- a/src/shared/models/ipc/ipc-routes.ts +++ b/src/shared/models/ipc/ipc-routes.ts @@ -19,6 +19,7 @@ import { SystemNotificationOptions } from "../notification/system-notification.m import { Supporter } from "../supporters"; import { AppWindow } from "../window-manager/app-window.model"; import { LocalBPList, LocalBPListsDetails } from "../playlists/local-playlist.models"; +import { StaticConfigGetIpcRequestResponse, StaticConfigKeys, StaticConfigSetIpcRequest } from "main/services/static-configuration.service"; export type IpcReplier = (data: Observable) => void; @@ -124,6 +125,7 @@ export interface IpcChannelMapping { "open-logs": { request: void, response: string }; "notify-system": { request: SystemNotificationOptions, response: void }; "view-path-in-explorer": { request: string, response: void }; + "restart-app": { request: void, response: void }; /* ** supporters-ipcs ** */ "get-supporters": { request: void, response: Supporter[] }; @@ -136,6 +138,10 @@ export interface IpcChannelMapping { "open-window-then-close-all": { request: AppWindow, response: void }; "open-window-or-focus": { request: AppWindow, response: void }; + /* ** static-configuration.ipcs ** */ + "static-configuration.get": StaticConfigGetIpcRequestResponse; + "static-configuration.set": StaticConfigSetIpcRequest; + /* ** OTHERS (if your IPC channel is not in a "-ipcs" file, put it here) ** */ "shortcut-launch-options": { request: void, response: LaunchOption }; }