mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature-136] Models panel + models linkage + models linkage modals + some cleaning
This commit is contained in:
@@ -4,7 +4,7 @@ import { ipcMain } from "electron";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { UtilsService } from "../utils.service";
|
||||
import { WindowManagerService } from "../window-manager.service";
|
||||
import { MSModel, MSModelType } from "shared/models/model-saber/model-saber.model";
|
||||
import { MSModel, MSModelType } from "../../../shared/models/model-saber/model-saber.model";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BSLocalVersionService } from "../bs-local-version.service";
|
||||
import path from "path";
|
||||
@@ -12,6 +12,7 @@ import { RequestService } from "../request.service";
|
||||
import { copyFileSync } from "fs-extra";
|
||||
import sanitize from "sanitize-filename";
|
||||
import { ensureFolderExist } from "../../helpers/fs.helpers";
|
||||
import { MODEL_TYPE_FOLDERS } from "../../../shared/models/model-saber/models-constants";
|
||||
|
||||
export class LocalModelsManagerService {
|
||||
|
||||
@@ -26,13 +27,6 @@ export class LocalModelsManagerService {
|
||||
ModelSaber: "modelsaber",
|
||||
};
|
||||
|
||||
private readonly MODEL_TYPE_FOLDER: Record<Exclude<MSModelType, "misc">, string> = {
|
||||
avatar: "CustomAvatars",
|
||||
bloq: "CustomNotes",
|
||||
platform: "CustomPlatforms",
|
||||
saber: "CustomSabers"
|
||||
}
|
||||
|
||||
private readonly deepLink: DeepLinkService;
|
||||
private readonly utils: UtilsService;
|
||||
private readonly windows: WindowManagerService;
|
||||
@@ -70,10 +64,9 @@ export class LocalModelsManagerService {
|
||||
private async getModelFolderPath(type: MSModelType, version?: BSVersion): Promise<string>{
|
||||
|
||||
if(!version){ throw "will be implemented whith models management" }
|
||||
if(type === "misc"){ throw "model type not supported"; }
|
||||
|
||||
const versionPath = await this.localVersion.getVersionPath(version);
|
||||
const modelFolderPath = path.join(versionPath, this.MODEL_TYPE_FOLDER[type]);
|
||||
const modelFolderPath = path.join(versionPath, MODEL_TYPE_FOLDERS[type]);
|
||||
|
||||
await ensureFolderExist(modelFolderPath);
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { useState } from "react"
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component"
|
||||
import { BsmCheckbox } from "renderer/components/shared/bsm-checkbox.component"
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component"
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook"
|
||||
import { ModalComponent, ModalExitCode } from "renderer/services/modale.service"
|
||||
import { MSModelType } from "shared/models/model-saber/model-saber.model"
|
||||
import BeatRunning from '../../../../../../assets/images/apngs/beat-running.png'
|
||||
|
||||
export const LinkModelsModal: ModalComponent<boolean, MSModelType> = ({resolver, data}) => {
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
const [keepMaps, setKeepMaps] = useState(true)
|
||||
|
||||
return (
|
||||
<form className="text-gray-800 dark:text-gray-200">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t(`modals.models.link-models.${data}.title`)}</h1>
|
||||
<BsmImage className="mx-auto h-24" image={BeatRunning} />
|
||||
<p className="max-w-sm w-full">{t(`modals.models.link-models.${data}.desc`)}</p>
|
||||
<p className="max-w-sm w-full text-sm italic mt-2">{t(`modals.models.link-models.${data}.info`)}</p>
|
||||
<div className="relative h-5 flex my-3 items-center">
|
||||
<BsmCheckbox className="h-full aspect-square relative bg-inherit mr-1.5 z-[1]" checked={keepMaps} onChange={setKeepMaps}/>
|
||||
<span className="text-sm mb-0.5 cursor-help" title={t(`modals.models.link-models.${data}.keep-models.title`)}>{t(`modals.models.link-models.${data}.keep-models.label`)}</span>
|
||||
</div>
|
||||
<div className="grid grid-flow-col grid-cols-2 gap-4 mt-4">
|
||||
<BsmButton typeColor="cancel" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="misc.cancel"/>
|
||||
<BsmButton typeColor="primary" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`modals.models.link-models.${data}.valid-btn`}/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { useState } from "react";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { BsmCheckbox } from "renderer/components/shared/bsm-checkbox.component";
|
||||
import { BsmImage } from "renderer/components/shared/bsm-image.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { ModalComponent, ModalExitCode } from "renderer/services/modale.service";
|
||||
import BeatConflict from '../../../../../../assets/images/apngs/beat-conflict.png'
|
||||
import { MSModelType } from "shared/models/model-saber/model-saber.model";
|
||||
|
||||
export const UnlinkModelsModal: ModalComponent<boolean, MSModelType> = ({resolver, data}) => {
|
||||
|
||||
const t = useTranslation();
|
||||
const [keepMaps, setKeepMaps] = useState(true);
|
||||
|
||||
return (
|
||||
<form className="text-gray-800 dark:text-gray-200">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t(`modals.models.unlink-models.${data}.title`)}</h1>
|
||||
<BsmImage className="mx-auto h-24" image={BeatConflict} />
|
||||
<p className="max-w-sm w-full">{t(`modals.models.unlink-models.${data}.desc`)}</p>
|
||||
<div className="relative h-5 flex my-3 items-center">
|
||||
<BsmCheckbox className="h-full aspect-square relative bg-inherit mr-1.5 z-[1]" checked={keepMaps} onChange={setKeepMaps}/>
|
||||
<span className="text-sm mb-0.5 cursor-help" title={t(`modals.models.unlink-models.${data}.keep-models.title`)}>{t(`modals.models.unlink-models.${data}.keep-models.label`)}</span>
|
||||
</div>
|
||||
<div className="grid grid-flow-col grid-cols-2 gap-4 mt-4">
|
||||
<BsmButton typeColor="cancel" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="misc.cancel"/>
|
||||
<BsmButton typeColor="error" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`modals.models.unlink-models.${data}.valid-btn`}/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { Variants } from "framer-motion";
|
||||
import { version } from "os";
|
||||
import { useEffect, useState } from "react";
|
||||
import { LinkButton } from "renderer/components/maps-mangement-components/link-button.component";
|
||||
import { BsmBasicSpinner } from "renderer/components/shared/bsm-basic-spinner/bsm-basic-spinner.component";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { BsmIcon } from "renderer/components/svgs/bsm-icon.component";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { useState } from "react";
|
||||
import { ModelsTabsNavbar } from "./models-tabs-navbar.component";
|
||||
|
||||
export function ModelsPanel({version}: {version?: BSVersion}) {
|
||||
|
||||
const [modelTypeTab, setModelTypeTab] = useState<ModelTabType>(ModelTabType.Avatars);
|
||||
|
||||
return (
|
||||
<div className="w-full h-full flex flex-col items-center justify-center">
|
||||
<div>
|
||||
|
||||
</div>
|
||||
<div className="w-full h-full flex flex-col bg-light-main-color-3 dark:bg-main-color-2 rounded-md shadow-black shadow-md overflow-hidden">
|
||||
<ModelsTabsNavbar version={version} tabIndex={modelTypeTab} onTabChange={setModelTypeTab}/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
enum ModelTabType {
|
||||
Avatars = 0,
|
||||
Sabers = 1,
|
||||
Platforms = 2,
|
||||
Bloqs = 3,
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import { BSVersion } from "shared/bs-version.interface"
|
||||
import { TabNavBar } from "../shared/tab-nav-bar.component"
|
||||
import { MSModelType } from "shared/models/model-saber/model-saber.model"
|
||||
import { LinkButton } from "../maps-mangement-components/link-button.component"
|
||||
import { Variants } from "framer-motion"
|
||||
import { DetailedHTMLProps, useEffect, useState } from "react"
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook"
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook"
|
||||
import { useOnUpdate } from "renderer/hooks/use-on-update.hook"
|
||||
import { useConstant } from "renderer/hooks/use-constant.hook"
|
||||
import { ModelsManagerService } from "renderer/services/models-management/models-manager.service"
|
||||
|
||||
type Props = {
|
||||
version?: BSVersion
|
||||
tabIndex: number,
|
||||
onTabChange: (index: number) => void
|
||||
}
|
||||
|
||||
export function ModelsTabsNavbar({version, tabIndex, onTabChange}: Props) {
|
||||
|
||||
const renderTab = (props: DetailedHTMLProps<React.HTMLAttributes<any>, any>, text: string, index?: number) => {
|
||||
return <ModelTab version={version} index={index} modelType={Object.values(MSModelType).at(index)} onClick={props.onClick}/>
|
||||
}
|
||||
|
||||
return (
|
||||
<TabNavBar className="!rounded-none shadow-sm" tabsText={
|
||||
["Avatars", "Sabers", "Platforms", "Bloqs"]
|
||||
} tabIndex={tabIndex} onTabChange={onTabChange} renderTab={renderTab}/>
|
||||
)
|
||||
}
|
||||
|
||||
type TabProps = {
|
||||
version?: BSVersion,
|
||||
modelType: MSModelType,
|
||||
index: number,
|
||||
onLink?: (type: MSModelType) => void,
|
||||
onUnlink?: (type: MSModelType) => void,
|
||||
} & DetailedHTMLProps<React.HTMLAttributes<HTMLLIElement>, HTMLLIElement>;
|
||||
|
||||
function ModelTab({version, modelType, onClick, onLink, onUnlink}: TabProps){
|
||||
|
||||
const modelsManager = useConstant(() => ModelsManagerService.getInstance());
|
||||
|
||||
const [modelsAreLinked, setModelsAreLinked] = useState(false);
|
||||
const [linkBtnDisabled, setLinkBtnDisabled] = useState(false);
|
||||
|
||||
useOnUpdate(() => {
|
||||
if(!version){ return; }
|
||||
|
||||
const sub = modelsManager.$modelsLinkingPending(version, modelType).subscribe(async (pending) => {
|
||||
if(pending){ return setLinkBtnDisabled(() => pending); }
|
||||
const modelsLinked = await modelsManager.isModelsLinked(version, modelType);
|
||||
setModelsAreLinked(() => modelsLinked);
|
||||
setLinkBtnDisabled(() => pending);
|
||||
});
|
||||
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
}
|
||||
}, [version]);
|
||||
|
||||
const linkModels = () => modelsManager.linkModels(modelType, version).then(() => onLink?.(modelType));
|
||||
const unlinkModels = () => modelsManager.unlinkModels(modelType, version).then(() => onUnlink?.(modelType));
|
||||
|
||||
const onClickLink = () => {
|
||||
if(!version){ return Promise.resolve(); }
|
||||
if(modelsAreLinked){ return unlinkModels(); }
|
||||
return linkModels();
|
||||
}
|
||||
|
||||
return (
|
||||
<li className="relative text-center text-lg font-bold hover:backdrop-brightness-75 flex justify-center items-center content-center" onClick={onClick}>
|
||||
<span className="text-main-color-1 dark:text-gray-200">{modelType}</span>
|
||||
<div className="h-full flex absolute right-0 top-0 gap-1.5 items-center pr-2">
|
||||
{!!version && (
|
||||
<LinkButton
|
||||
variants={{ hover: {rotate: 22.5}, tap: {rotate: 45} }}
|
||||
disabled={linkBtnDisabled}
|
||||
whileHover="hover"
|
||||
whileTap="tap"
|
||||
initial={{rotate: 0}}
|
||||
className="block p-0.5 h-[calc(100%-5px)] aspect-square blur-0 hover:brightness-75"
|
||||
linked={modelsAreLinked}
|
||||
title={"aaa"}
|
||||
onClick={onClickLink}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { useRef } from "react"
|
||||
|
||||
type ResultBox<T> = { v: T }
|
||||
|
||||
export function useConstant<T>(fn: () => T): T {
|
||||
const ref = useRef<ResultBox<T>>()
|
||||
|
||||
if (!ref.current) {
|
||||
ref.current = { v: fn() }
|
||||
}
|
||||
|
||||
return ref.current.v
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { useEffect, EffectCallback, DependencyList } from "react";
|
||||
|
||||
export function useOnUpdate(func: EffectCallback, deps: DependencyList = []) {
|
||||
useEffect(() => {
|
||||
func();
|
||||
}, deps);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import beatleaderIcon from "../../../assets/images/third-party-icons/beat-leader
|
||||
import Tippy from '@tippyjs/react';
|
||||
import { MapsManagerService } from "renderer/services/maps-manager.service";
|
||||
import { PlaylistsManagerService } from "renderer/services/playlists-manager.service";
|
||||
import { ModelsManagerService } from "renderer/services/models-manager.service";
|
||||
import { ModelsManagerService } from "renderer/services/models-management/models-manager.service";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { VersionFolderLinkerService } from "renderer/services/version-folder-linker.service";
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ModsSlide } from 'renderer/components/version-viewer/slides/mods/mods-s
|
||||
import { UninstallModal } from 'renderer/components/modal/modal-types/uninstall-modal.component';
|
||||
import { MapsPlaylistsPanel } from 'renderer/components/maps-mangement-components/maps-playlists-panel.component';
|
||||
import { ShareFoldersModal } from 'renderer/components/modal/modal-types/share-folders-modal.component';
|
||||
import { ModelsPanel } from 'renderer/components/models-management/models-panel.component';
|
||||
|
||||
export function VersionViewer() {
|
||||
|
||||
@@ -78,12 +79,15 @@ export function VersionViewer() {
|
||||
<div className="relative flex items-center flex-col w-full h-full text-gray-200 backdrop-blur-lg">
|
||||
<BsmImage className='relative object-cover h-28' image={BSLogo}/>
|
||||
<h1 className='relative text-4xl font-bold italic -top-3'>{state.name ? `${state.BSVersion} - ${state.name}` : state.BSVersion}</h1>
|
||||
<TabNavBar className='my-3' tabIndex={currentTabIndex} tabsText={["misc.launch", "misc.maps", "misc.mods"]} onTabChange={(i : number) => setCurrentTabIndex(i)}/>
|
||||
<TabNavBar className='my-3' tabIndex={currentTabIndex} tabsText={["misc.launch", "misc.maps", "Models", "misc.mods"]} onTabChange={(i : number) => setCurrentTabIndex(i)}/>
|
||||
<div className='mt-2 w-full min-h-0 grow flex transition-transform duration-300' style={{transform: `translate(${-(currentTabIndex * 100)}%, 0)`}}>
|
||||
<LaunchSlide version={state}/>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<MapsPlaylistsPanel version={state}/>
|
||||
</div>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<ModelsPanel version={state}/>
|
||||
</div>
|
||||
<ModsSlide version={state} onDisclamerDecline={handleModsDisclaimerDecline}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -159,9 +159,7 @@ export class MapsManagerService {
|
||||
}
|
||||
|
||||
public $mapsLinkingPending(version: BSVersion): Observable<boolean>{
|
||||
return this.linker.queue$.pipe(mergeMap(async queue => {
|
||||
return queue.some(q => q.relativeFolder.includes(MapsManagerService.RELATIVE_MAPS_FOLDER) && equal(q.version, version));
|
||||
}), distinctUntilChanged());
|
||||
return this.linker.$isVersionFolderPending(version, MapsManagerService.RELATIVE_MAPS_FOLDER);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { MSModelType } from "shared/models/model-saber/model-saber.model";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { VersionFolderLinkerService, VersionLinkerActionType } from "../version-folder-linker.service";
|
||||
import { MODEL_TYPE_FOLDERS } from "shared/models/model-saber/models-constants";
|
||||
import { Observable, distinctUntilChanged, lastValueFrom, mergeMap, share } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { ModalExitCode, ModalService } from "../modale.service";
|
||||
import { LinkModelsModal } from "renderer/components/modal/modal-types/models/link-models-modal.component";
|
||||
import { UnlinkModelsModal } from "renderer/components/modal/modal-types/models/unlink-models-modal.component";
|
||||
|
||||
export class ModelsManagerService {
|
||||
|
||||
private static instance: ModelsManagerService;
|
||||
|
||||
public static getInstance(): ModelsManagerService{
|
||||
if(!ModelsManagerService.instance){ ModelsManagerService.instance = new ModelsManagerService(); }
|
||||
return ModelsManagerService.instance;
|
||||
}
|
||||
|
||||
private readonly ipc: IpcService;
|
||||
private readonly versionFolderLinked: VersionFolderLinkerService;
|
||||
private readonly modalService: ModalService;
|
||||
|
||||
private constructor(){
|
||||
this.ipc = IpcService.getInstance();
|
||||
this.versionFolderLinked = VersionFolderLinkerService.getInstance();
|
||||
this.modalService = ModalService.getInsance();
|
||||
}
|
||||
|
||||
public isModelsLinked(version: BSVersion, type: MSModelType): Promise<boolean>{
|
||||
return lastValueFrom(this.versionFolderLinked.isVersionFolderLinked(version, MODEL_TYPE_FOLDERS[type]));
|
||||
}
|
||||
|
||||
public $modelsLinkingPending(version: BSVersion, type: MSModelType): Observable<boolean>{
|
||||
return this.versionFolderLinked.$isVersionFolderPending(version, MODEL_TYPE_FOLDERS[type]);
|
||||
}
|
||||
|
||||
public async linkModels(type: MSModelType, version?: BSVersion): Promise<boolean>{
|
||||
|
||||
const res = await this.modalService.openModal(LinkModelsModal, type);
|
||||
|
||||
if(res.exitCode !== ModalExitCode.COMPLETED){ return null; }
|
||||
|
||||
return this.versionFolderLinked.linkVersionFolder({
|
||||
version,
|
||||
relativeFolder: MODEL_TYPE_FOLDERS[type],
|
||||
type: VersionLinkerActionType.Link,
|
||||
options: { keepContents: res.data !== false }
|
||||
});
|
||||
}
|
||||
|
||||
public async unlinkModels(type: MSModelType, version?: BSVersion): Promise<boolean>{
|
||||
|
||||
const res = await this.modalService.openModal(UnlinkModelsModal, type);
|
||||
|
||||
if(res.exitCode !== ModalExitCode.COMPLETED){ return null; }
|
||||
|
||||
return this.versionFolderLinked.unlinkVersionFolder({
|
||||
version,
|
||||
relativeFolder: MODEL_TYPE_FOLDERS[type],
|
||||
type: VersionLinkerActionType.Unlink,
|
||||
options: { keepContents: res.data !== false }
|
||||
});
|
||||
}
|
||||
|
||||
public isDeepLinksEnabled(): Promise<boolean>{
|
||||
return this.ipc.send<boolean>("is-models-deep-links-enabled").then(res => (
|
||||
res.success ? res.data : false
|
||||
));
|
||||
}
|
||||
|
||||
public async enableDeepLink(): Promise<boolean>{
|
||||
const res = await this.ipc.send<boolean>("register-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
}
|
||||
|
||||
public async disableDeepLink(): Promise<boolean>{
|
||||
const res = await this.ipc.send<boolean>("unregister-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import { IpcService } from "./ipc.service";
|
||||
|
||||
export class ModelsManagerService {
|
||||
|
||||
private static instance: ModelsManagerService;
|
||||
|
||||
public static getInstance(): ModelsManagerService{
|
||||
if(!ModelsManagerService.instance){ ModelsManagerService.instance = new ModelsManagerService(); }
|
||||
return ModelsManagerService.instance;
|
||||
}
|
||||
|
||||
private readonly ipc: IpcService;
|
||||
|
||||
private constructor(){
|
||||
this.ipc = IpcService.getInstance();
|
||||
}
|
||||
|
||||
public isDeepLinksEnabled(): Promise<boolean>{
|
||||
return this.ipc.send<boolean>("is-models-deep-links-enabled").then(res => (
|
||||
res.success ? res.data : false
|
||||
));
|
||||
}
|
||||
|
||||
public async enableDeepLink(): Promise<boolean>{
|
||||
const res = await this.ipc.send<boolean>("register-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
}
|
||||
|
||||
public async disableDeepLink(): Promise<boolean>{
|
||||
const res = await this.ipc.send<boolean>("unregister-models-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import { LinkOptions, UnlinkOptions } from "main/services/folder-linker.service";
|
||||
import { map, distinctUntilChanged, filter } from "rxjs/operators";
|
||||
import { map, distinctUntilChanged, filter, mergeMap, share } from "rxjs/operators";
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ProgressBarService } from "./progress-bar.service";
|
||||
import equal from "fast-deep-equal";
|
||||
|
||||
export class VersionFolderLinkerService{
|
||||
|
||||
@@ -137,6 +138,12 @@ export class VersionFolderLinkerService{
|
||||
return this.ipcService.sendV2("relink-all-versions-folders");
|
||||
}
|
||||
|
||||
public $isVersionFolderPending(version: BSVersion, relativeFolder: string): Observable<boolean>{
|
||||
return this.queue$.pipe(mergeMap(async queue => {
|
||||
return queue.some(q => q.relativeFolder.includes(relativeFolder) && equal(q.version, version));
|
||||
}), distinctUntilChanged(), share());
|
||||
}
|
||||
|
||||
public get currentAction$(): Observable<VersionLinkerAction>{
|
||||
return this._queue$.pipe(map(actions => actions.at(0)), distinctUntilChanged());
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import 'tippy.js/dist/tippy.css';
|
||||
import 'tippy.js/animations/shift-away-subtle.css';
|
||||
import { MapsManagerService } from "renderer/services/maps-manager.service";
|
||||
import { PlaylistsManagerService } from "renderer/services/playlists-manager.service";
|
||||
import { ModelsManagerService } from "renderer/services/models-manager.service";
|
||||
import { ModelsManagerService } from "renderer/services/models-management/models-manager.service";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { timer } from "rxjs";
|
||||
import { ConfigurationService } from "renderer/services/configuration.service";
|
||||
|
||||
@@ -17,8 +17,18 @@ export interface MSModel {
|
||||
date: string
|
||||
}
|
||||
|
||||
export type MSModelType = "saber"|"platform"|"bloq"|"misc"|"avatar";
|
||||
export type MSModelPlatform = "pc"|"quest"|"all";
|
||||
export enum MSModelType {
|
||||
Avatar = "avatar",
|
||||
Saber = "saber",
|
||||
Platfrom = "platform",
|
||||
Bloq = "bloq"
|
||||
};
|
||||
|
||||
export enum MSModelPlatform {
|
||||
PC = "pc",
|
||||
QUEST = "quest",
|
||||
ALL = "all"
|
||||
};
|
||||
|
||||
export interface MSGetQuery {
|
||||
type?: MSModelType;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { MSModelType } from "./model-saber.model";
|
||||
|
||||
export const MODEL_TYPE_FOLDERS = {
|
||||
[MSModelType.Avatar]: "CustomAvatars",
|
||||
[MSModelType.Bloq]: "CustomNotes",
|
||||
[MSModelType.Platfrom]: "CustomPlatforms",
|
||||
[MSModelType.Saber]: "CustomSabers"
|
||||
}
|
||||
Reference in New Issue
Block a user