mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[chore] fix some sonarcloud code smells
This commit is contained in:
+4
-5
@@ -1,22 +1,21 @@
|
||||
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
|
||||
import { IpcChannel } from 'shared/models/ipc/ipc-response.interface';
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
ipcRenderer: {
|
||||
sendMessage(channel: IpcChannel, args: unknown[]) {
|
||||
sendMessage(channel: string, args: unknown[]) {
|
||||
ipcRenderer.send(channel, args);
|
||||
},
|
||||
on(channel: IpcChannel, func: (...args: unknown[]) => void) {
|
||||
on(channel: string, func: (...args: unknown[]) => void) {
|
||||
const subscription = (_event: IpcRendererEvent, ...args: unknown[]) =>
|
||||
func(...args);
|
||||
ipcRenderer.on(channel, subscription);
|
||||
|
||||
return () => ipcRenderer.removeListener(channel, subscription);
|
||||
},
|
||||
once(channel: IpcChannel, func: (...args: unknown[]) => void) {
|
||||
once(channel: string, func: (...args: unknown[]) => void) {
|
||||
ipcRenderer.once(channel, (_event, ...args) => func(...args));
|
||||
},
|
||||
removeAllListeners(channel: IpcChannel) {
|
||||
removeAllListeners(channel: string) {
|
||||
ipcRenderer.removeAllListeners(channel);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable prefer-promise-reject-errors */
|
||||
import { BS_APP_ID, BS_DEPOT } from "../constants";
|
||||
import path from "path";
|
||||
import { BSVersion, PartialBSVersion } from 'shared/bs-version.interface';
|
||||
@@ -10,57 +9,52 @@ import { ctrlc } from "ctrlc-windows";
|
||||
import { BSLocalVersionService } from "./bs-local-version.service";
|
||||
import isOnline from 'is-online';
|
||||
import { WindowManagerService } from "./window-manager.service";
|
||||
import { copy, copySync } from "fs-extra";
|
||||
import { clean, satisfies } from "semver";
|
||||
import { copy } from "fs-extra";
|
||||
import { ensureFolderExist, pathExist } from "../helpers/fs.helpers";
|
||||
|
||||
export class BSInstallerService{
|
||||
|
||||
private static instance: BSInstallerService;
|
||||
private static instance: BSInstallerService;
|
||||
|
||||
private readonly utils: UtilsService;
|
||||
private readonly installLocationService: InstallationLocationService;
|
||||
private readonly localVersionService: BSLocalVersionService;
|
||||
private readonly windows: WindowManagerService;
|
||||
private readonly utils: UtilsService;
|
||||
private readonly installLocationService: InstallationLocationService;
|
||||
private readonly localVersionService: BSLocalVersionService;
|
||||
private readonly windows: WindowManagerService;
|
||||
|
||||
private downloadProcess: ChildProcessWithoutNullStreams;
|
||||
private downloadProcess: ChildProcessWithoutNullStreams;
|
||||
|
||||
private constructor(){
|
||||
this.utils = UtilsService.getInstance();
|
||||
this.installLocationService = InstallationLocationService.getInstance();
|
||||
this.localVersionService = BSLocalVersionService.getInstance();
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
private constructor(){
|
||||
this.utils = UtilsService.getInstance();
|
||||
this.installLocationService = InstallationLocationService.getInstance();
|
||||
this.localVersionService = BSLocalVersionService.getInstance();
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
|
||||
this.windows.getWindow("index.html")?.on("close", () => {
|
||||
this.killDownloadProcess();
|
||||
});
|
||||
}
|
||||
this.windows.getWindow("index.html")?.on("close", () => {
|
||||
this.killDownloadProcess();
|
||||
});
|
||||
}
|
||||
|
||||
public static getInstance(){
|
||||
if(!BSInstallerService.instance){ BSInstallerService.instance = new BSInstallerService(); }
|
||||
return BSInstallerService.instance;
|
||||
}
|
||||
|
||||
private escapeSpaces(path: string): string{
|
||||
return `\"${path}\"`
|
||||
public static getInstance(){
|
||||
if(!BSInstallerService.instance){ BSInstallerService.instance = new BSInstallerService(); }
|
||||
return BSInstallerService.instance;
|
||||
}
|
||||
|
||||
private getDepotDownloaderExePath(): string{
|
||||
return this.escapeSpaces(path.join(this.utils.getAssetsScriptsPath(), 'depot-downloader', 'DepotDownloader.exe'));
|
||||
return path.join(this.utils.getAssetsScriptsPath(), 'depot-downloader', 'DepotDownloader.exe');
|
||||
}
|
||||
|
||||
private removeSpecialSchar(txt: string): string{ return txt.replaceAll(/\[|\]/g, ""); }
|
||||
private removeSpecialSchar(txt: string): string{ return txt.replaceAll(/[\[\]]/g, ""); }
|
||||
|
||||
private sendDownloadEvent(event: DownloadEventType, data?: string|number, success = true): void{
|
||||
if(typeof data === "string"){ data = this.removeSpecialSchar(data); }
|
||||
this.utils.ipcSend(`bs-download.${event}`, { success, data });
|
||||
}
|
||||
|
||||
public sendInputProcess(input: string){
|
||||
if(this.downloadProcess.stdin.writable){
|
||||
this.downloadProcess.stdin.write(`${input}\n`);
|
||||
public sendInputProcess(input: string){
|
||||
if(this.downloadProcess.stdin.writable){
|
||||
this.downloadProcess.stdin.write(`${input}\n`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public killDownloadProcess(): Promise<boolean>{
|
||||
return new Promise(resolve => {
|
||||
@@ -78,7 +72,7 @@ export class BSInstallerService{
|
||||
|
||||
public async isDotNet6Installed(): Promise<boolean>{
|
||||
try{
|
||||
const process = spawnSync(this.getDepotDownloaderExePath(), {shell: true});
|
||||
const process = spawnSync(`"${this.getDepotDownloaderExePath()}"`, {shell: true});
|
||||
if(process.stderr.toString()){
|
||||
log.error("no dotnet", process.stderr.toString());
|
||||
return false;
|
||||
@@ -93,9 +87,9 @@ export class BSInstallerService{
|
||||
|
||||
public async downloadBsVersion(downloadInfos: DownloadInfo): Promise<DownloadEvent>{
|
||||
|
||||
// TODO : Can be a lot improved by using ipcV2 and Observable
|
||||
// TODO : Can be a lot improved by using ipcV2 and Observable -- This will be reworked for qrCode login
|
||||
|
||||
if(this.downloadProcess && this.downloadProcess.connected){ throw "AlreadyDownloading"; }
|
||||
if(this.downloadProcess?.connected){ throw "AlreadyDownloading"; }
|
||||
const {bsVersion} = downloadInfos;
|
||||
if(!bsVersion){ return {type: "[Error]"}; }
|
||||
if(!(await isOnline({timeout: 1500}))){ throw "no-internet"; }
|
||||
@@ -109,13 +103,13 @@ export class BSInstallerService{
|
||||
const downloadVersion: BSVersion = {...downloadInfos.bsVersion, ...(path.basename(dest) !== downloadInfos.bsVersion.BSVersion && {name: path.basename(dest)})}
|
||||
|
||||
this.downloadProcess = spawn(
|
||||
this.getDepotDownloaderExePath(),
|
||||
`"${this.getDepotDownloaderExePath()}"`,
|
||||
[
|
||||
`-app ${BS_APP_ID}`,
|
||||
`-depot ${BS_DEPOT}`,
|
||||
`-manifest ${bsVersion.BSManifest}`,
|
||||
`-username \"${downloadInfos.username}\"`,
|
||||
`-dir \"${this.localVersionService.getVersionFolder(downloadVersion)}\"`
|
||||
`-username "${downloadInfos.username}"`,
|
||||
`-dir "${this.localVersionService.getVersionFolder(downloadVersion)}"`
|
||||
],
|
||||
{shell: true, cwd: this.installLocationService.versionsDirectory}
|
||||
);
|
||||
|
||||
@@ -106,10 +106,10 @@ export class BSLauncherService{
|
||||
}
|
||||
|
||||
if(launchOptions.debug){
|
||||
this.bsProcess = spawn(`\"${exePath}\"`, launchArgs, {shell: true, cwd, env: {...process.env, "SteamAppId": BS_APP_ID}, detached: true, windowsVerbatimArguments: true });
|
||||
this.bsProcess = spawn(`"${exePath}"`, launchArgs, {shell: true, cwd, env: {...process.env, "SteamAppId": BS_APP_ID}, detached: true, windowsVerbatimArguments: true });
|
||||
}
|
||||
else{
|
||||
this.bsProcess = spawn(`\"${exePath}\"`, launchArgs, {shell: true, cwd, env: {...process.env, "SteamAppId": BS_APP_ID} });
|
||||
this.bsProcess = spawn(`"${exePath}"`, launchArgs, {shell: true, cwd, env: {...process.env, "SteamAppId": BS_APP_ID} });
|
||||
}
|
||||
|
||||
this.bsProcess.on('error', err => log.error(err));
|
||||
|
||||
@@ -52,16 +52,16 @@ export class BSVersionLibService{
|
||||
], {keepStructure: true});
|
||||
|
||||
let resVersions = localVersions;
|
||||
if(remoteVersions && remoteVersions.length){ resVersions = remoteVersions; this.updateLocalVersions(resVersions); }
|
||||
if(remoteVersions?.length){ resVersions = remoteVersions; this.updateLocalVersions(resVersions); }
|
||||
this.bsVersions = resVersions;
|
||||
return this.bsVersions;
|
||||
}
|
||||
|
||||
public async getAvailableVersions(): Promise<BSVersion[]>{
|
||||
const bsVersions = await this.loadBsVersions();
|
||||
if(!bsVersions || !bsVersions.length){ return []; }
|
||||
return bsVersions;
|
||||
}
|
||||
public async getAvailableVersions(): Promise<BSVersion[]>{
|
||||
const bsVersions = await this.loadBsVersions();
|
||||
if(!bsVersions?.length){ return []; }
|
||||
return bsVersions;
|
||||
}
|
||||
|
||||
public async getVersionDetails(version: string): Promise<BSVersion>{
|
||||
const versions = await this.getAvailableVersions();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { ipcMain } from "electron";
|
||||
import { Observable } from "rxjs";
|
||||
import { IpcChannel, IpcCompleteChannel, IpcErrorChannel } from "shared/models/ipc/ipc-response.interface";
|
||||
import { IpcCompleteChannel, IpcErrorChannel } from "shared/models/ipc/ipc-response.interface";
|
||||
import { AppWindow } from "shared/models/window-manager/app-window.model";
|
||||
import { WindowManagerService } from "./window-manager.service";
|
||||
import { IpcReplier } from "shared/models/ipc/ipc-request.interface";
|
||||
@@ -22,15 +22,15 @@ export class IpcService {
|
||||
this.windows = WindowManagerService.getInstance();
|
||||
}
|
||||
|
||||
private getErrorChannel(channel: IpcChannel): IpcErrorChannel {
|
||||
private getErrorChannel(channel: string): IpcErrorChannel {
|
||||
return `${channel}_error`;
|
||||
}
|
||||
|
||||
private getCompleteChannel(channel: IpcChannel): IpcCompleteChannel {
|
||||
private getCompleteChannel(channel: string): IpcCompleteChannel {
|
||||
return `${channel}_complete`;
|
||||
}
|
||||
|
||||
private buildProxyListener<T>(listener: (req: IpcRequest<T>, replier: IpcReplier) => void) {
|
||||
private buildProxyListener<T>(listener: IpcListener<T>) {
|
||||
|
||||
return (event: Electron.IpcMainEvent, req: IpcRequest<T>) => {
|
||||
const window = this.windows.getAppWindowFromWebContents(event.sender);
|
||||
@@ -40,11 +40,11 @@ export class IpcService {
|
||||
|
||||
}
|
||||
|
||||
public send<T>(channel: IpcChannel, window: AppWindow, response?: T|Error): void{
|
||||
public send<T>(channel: string, window: AppWindow, response?: T|Error): void{
|
||||
this.windows.getWindow(window)?.webContents?.send(channel, response);
|
||||
}
|
||||
|
||||
private connectStream(channel: IpcChannel, window: AppWindow, observable: Observable<unknown>): void{
|
||||
private connectStream(channel: string, window: AppWindow, observable: Observable<unknown>): void{
|
||||
observable.subscribe(data => {
|
||||
this.send(channel, window, data);
|
||||
}, error => {
|
||||
@@ -55,12 +55,14 @@ export class IpcService {
|
||||
});
|
||||
}
|
||||
|
||||
public on<T>(channel: IpcChannel, listener: (req: IpcRequest<T>, replier: IpcReplier) => void): void{
|
||||
public on<T>(channel: string, listener: IpcListener<T>): void{
|
||||
ipcMain.on(channel, this.buildProxyListener(listener));
|
||||
}
|
||||
|
||||
public once<T>(channel: IpcChannel, listener: (req: IpcRequest<T>, replier: IpcReplier) => void): void{
|
||||
public once<T>(channel: string, listener: IpcListener<T>): void{
|
||||
ipcMain.once(channel, this.buildProxyListener(listener));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
type IpcListener<T = unknown> = (req: IpcRequest<T>, replier: IpcReplier) => void|Promise<void>;
|
||||
|
||||
@@ -269,7 +269,7 @@ export class BsModsManagerService {
|
||||
}
|
||||
|
||||
public async installMods(mods: Mod[], version: BSVersion): Promise<InstallModsResult>{
|
||||
if(!mods || !mods.length){ throw "no-mods"; }
|
||||
if(!mods?.length){ throw "no-mods"; }
|
||||
|
||||
const deps = await this.resolveDependencies(mods, version);
|
||||
mods.push(...deps);
|
||||
@@ -296,7 +296,7 @@ export class BsModsManagerService {
|
||||
}
|
||||
|
||||
public async uninstallMods(mods: Mod[], version: BSVersion): Promise<UninstallModsResult>{
|
||||
if(!mods || !mods.length){ throw "no-mods"; }
|
||||
if(!mods?.length){ throw "no-mods"; }
|
||||
|
||||
this.nbModsToUninstall = mods.length;
|
||||
this.nbUninstalledMods = 0;
|
||||
@@ -314,7 +314,7 @@ export class BsModsManagerService {
|
||||
public async uninstallAllMods(version: BSVersion): Promise<UninstallModsResult>{
|
||||
const mods = await this.getInstalledMods(version);
|
||||
|
||||
if(!mods || !mods.length){ throw "no-mods"; }
|
||||
if(!mods?.length){ throw "no-mods"; }
|
||||
|
||||
this.nbModsToUninstall = mods.length;
|
||||
this.nbUninstalledMods = 0;
|
||||
@@ -329,8 +329,6 @@ export class BsModsManagerService {
|
||||
await deleteFolder(path.join(versionPath, ModsInstallFolder.LIBS));
|
||||
await deleteFolder(path.join(versionPath, ModsInstallFolder.IPA));
|
||||
|
||||
path.resolve
|
||||
|
||||
return {
|
||||
nbModsToUninstall: this.nbModsToUninstall,
|
||||
nbUninstalledMods: this.nbUninstalledMods
|
||||
|
||||
@@ -92,9 +92,9 @@ export class ModelSaberService {
|
||||
const res = await this.modelSaberApi.searchModel(query);
|
||||
if(res.status !== 200){ observer.error(res.status); }
|
||||
observer.next(Object.values(res.data).map(model => {
|
||||
if(!model || !model.name){ return model; }
|
||||
(model as MSModel).name = striptags(model.name);
|
||||
(model as MSModel).author = striptags(model.author);
|
||||
if(!model?.name){ return null; }
|
||||
model.name = striptags(model.name);
|
||||
model.author = striptags(model.author);
|
||||
return model;
|
||||
}));
|
||||
})().catch(e => observer.error(e)).then(() => observer.complete());
|
||||
|
||||
@@ -67,7 +67,7 @@ export const MapsRow = memo(({maps, style, selectedMaps$, onMapSelect, onMapDele
|
||||
|
||||
return (
|
||||
<ul className="h-fit w-full flex flex-nowrap basis-0 gap-x-[8px] py-1 px-3" style={style}>
|
||||
{maps && maps.map(renderMapItem)}
|
||||
{maps?.map(renderMapItem)}
|
||||
</ul>
|
||||
)
|
||||
}, equal);
|
||||
|
||||
@@ -17,7 +17,7 @@ export const WhyCredentialsModal: ModalComponent<void> = () => {
|
||||
|
||||
<p>{t("modals.steam-credentials.p-1")}</p>
|
||||
{ /* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
||||
<a onClick={e => {e.preventDefault; openTutorial()}} className="underline text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-600 mb-2 block cursor-pointer">
|
||||
<a onClick={e => {e.preventDefault(); openTutorial()}} className="underline text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-600 mb-2 block cursor-pointer">
|
||||
https://steamcommunity.com/sharedfiles/filedetails/?id=1805934840
|
||||
</a>
|
||||
<p>{t("modals.steam-credentials.p-2")}</p>
|
||||
|
||||
@@ -138,7 +138,7 @@ function ModelItemElement<T = unknown>(props: Props<T>) {
|
||||
<span className="mt-0.5 cursor-copy block w-full max-w-fit overflow-hidden whitespace-nowrap text-ellipsis bg-main-color-1 rounded-md p-1 uppercase text-xs" onClick={() => copyContent(`${props.hash}`, 'hash')}>{props.hash}</span>
|
||||
</Tippy>
|
||||
<div className="flex gap-1">
|
||||
{props.id && (
|
||||
{!!props.id && (
|
||||
<Tippy placement="top" content={idContentCopied === "id" ? t("misc.copied") : t("misc.copy")} followCursor="horizontal" plugins={[followCursor]} hideOnClick={false}>
|
||||
<span className="cursor-copy w-fit shrink-0 max-w-full overflow-hidden whitespace-nowrap text-ellipsis bg-main-color-1 rounded-md p-1 uppercase text-xs" onClick={() => copyContent(`${props.id}`, 'id')}>{props.id}</span>
|
||||
</Tippy>
|
||||
|
||||
@@ -68,7 +68,7 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active,
|
||||
|
||||
useOnUpdate(() => {
|
||||
if(!active){ return; }
|
||||
if(models && models.length){ return; }
|
||||
if(models?.length){ return; }
|
||||
loadModels();
|
||||
}, [active]);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ export function NavBar() {
|
||||
<ol id='versions' className='w-fit max-w-[120px] relative left-[2px] grow overflow-y-hidden scrollbar-track-transparent scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900 hover:overflow-y-scroll'>
|
||||
<SharedNavBarItem/>
|
||||
<NavBarSpliter/>
|
||||
{installedVersions && installedVersions.map((version) => <BsVersionItem key={JSON.stringify(version)} version={version}/>)}
|
||||
{installedVersions?.map((version) => <BsVersionItem key={JSON.stringify(version)} version={version}/>)}
|
||||
</ol>
|
||||
<NavBarSpliter/>
|
||||
<div className='w-full pb-2 flex flex-col items-center content-center justify-start gap-1'>
|
||||
|
||||
@@ -15,7 +15,7 @@ export function BsmCheckbox({className, checked, onChange, disabled} : Props) {
|
||||
|
||||
const handleClick = () => {
|
||||
if(disabled){ return; }
|
||||
onChange && onChange(!checked);
|
||||
onChange?.(!checked);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -56,7 +56,7 @@ export function BsmRange({colorType = "first-color", values, onChange, onFinalCh
|
||||
color: labelTextColor,
|
||||
}}
|
||||
>
|
||||
{renderLabel && renderLabel(values[index])}
|
||||
{renderLabel?.(values[index])}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -19,7 +19,7 @@ export function BsmSelect<T = unknown>(props: Props<T>) {
|
||||
|
||||
return (
|
||||
<select {...props} onChange={handleChange} defaultValue={props.options?.findIndex(opt => equal(opt.value, props.selected))}>
|
||||
{props.options && props.options.map((option, index) => (
|
||||
{props.options?.map((option, index) => (
|
||||
<option key={JSON.stringify(option)} value={index}>{t(option.text)}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
@@ -20,7 +20,7 @@ export function ModsGrid({modsMap, installed, modsSelected, onModChange, moreInf
|
||||
const t = useTranslation();
|
||||
|
||||
const installedModVersion = (key: string, mod: Mod): string => {
|
||||
if(!installed || !installed.get(key)){ return undefined; }
|
||||
if(!installed?.get(key)){ return undefined; }
|
||||
const installedMod = installed.get(key).find(m => m.name === mod.name);
|
||||
if(!installedMod){ return undefined }
|
||||
return installedMod.version
|
||||
|
||||
@@ -62,7 +62,7 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
}
|
||||
|
||||
const handleOpenMoreInfo = () => {
|
||||
if(!moreInfoMod || !moreInfoMod.link){ return; }
|
||||
if(!moreInfoMod?.link){ return; }
|
||||
linkOpener.open(moreInfoMod.link);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+4
-6
@@ -1,16 +1,14 @@
|
||||
import { IpcChannel } from "shared/models/ipc/ipc-response.interface";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electron: {
|
||||
ipcRenderer: {
|
||||
sendMessage(channel: IpcChannel, args: any): void;
|
||||
sendMessage(channel: string, args: any): void;
|
||||
on(
|
||||
channel: IpcChannel,
|
||||
channel: string,
|
||||
func: (...args: any) => void
|
||||
): (() => void) | undefined;
|
||||
once(channel: IpcChannel, func: (...args: any) => void): void;
|
||||
removeAllListeners(channel: IpcChannel): void;
|
||||
once(channel: string, func: (...args: any) => void): void;
|
||||
removeAllListeners(channel: string): void;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export class BSVersionManagerService {
|
||||
}
|
||||
|
||||
public setInstalledVersions(versions: BSVersion[]){
|
||||
const sorted: BSVersion[] = versions.sort((a, b) => +b.ReleaseDate - +a.ReleaseDate)
|
||||
const sorted: BSVersion[] = [...versions].sort((a, b) => +b.ReleaseDate - +a.ReleaseDate)
|
||||
const steamIndex = sorted.findIndex(v => v.steam);
|
||||
const oculusIndex = sorted.findIndex(v => v.oculus);
|
||||
if(steamIndex > 0){
|
||||
|
||||
@@ -51,15 +51,15 @@ export class I18nService {
|
||||
this.configService.set("language" as DefaultConfigKey, this.getSupportedLanguages().includes(lang) ? lang : this.LANG_FALLBACK);
|
||||
}
|
||||
|
||||
public translate(translationKey: string, args?: Record<string, string>): string{
|
||||
let translated = this.cache.get(translationKey);
|
||||
if(!translated){
|
||||
translated = getProperty(this.dictionary, translationKey);
|
||||
translated ? this.cache.set(translated, translationKey) : translated = translationKey;
|
||||
}
|
||||
args && Object.keys(args).forEach(key => {translated = translated.replaceAll(`{${key}}`, args[key])});
|
||||
return translated;
|
||||
}
|
||||
public translate(translationKey: string, args?: Record<string, string>): string{
|
||||
let translated = this.cache.get(translationKey);
|
||||
if(!translated){
|
||||
translated = getProperty(this.dictionary, translationKey) ?? translationKey;
|
||||
this.cache.set(translationKey, translated);
|
||||
}
|
||||
args && Object.keys(args).forEach(key => {translated = translated.replaceAll(`{${key}}`, args[key])});
|
||||
return translated;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export class ProgressBarService{
|
||||
|
||||
public unsubscribe(){
|
||||
this._progression$.next({progression: 0});
|
||||
this.subscription && this.subscription.unsubscribe();
|
||||
this.subscription?.unsubscribe();
|
||||
this.subscription = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,5 @@ export interface IpcResponse<T>{
|
||||
success: boolean,
|
||||
}
|
||||
|
||||
export type IpcChannel = string;
|
||||
export type IpcErrorChannel = IpcChannel & `${string}_error`;
|
||||
export type IpcCompleteChannel = IpcChannel & `${string}_complete`;
|
||||
export type IpcErrorChannel = string & `${string}_error`;
|
||||
export type IpcCompleteChannel = string & `${string}_complete`;
|
||||
@@ -12,13 +12,11 @@ export interface MSModel {
|
||||
discord?: string,
|
||||
variationid?: number,
|
||||
platform: MSModelPlatform,
|
||||
download: ModelDownloadURL,
|
||||
download: string,
|
||||
install_link: string,
|
||||
date: string
|
||||
}
|
||||
|
||||
export type ModelDownloadURL = string;
|
||||
|
||||
export enum MSModelType {
|
||||
Avatar = "avatar",
|
||||
Saber = "saber",
|
||||
|
||||
Reference in New Issue
Block a user