mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature-136] refresh models on link/unlink
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useInView } from "framer-motion";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { useRef, forwardRef, useImperativeHandle } from "react";
|
||||
import { useRef, forwardRef, useImperativeHandle, useState } from "react";
|
||||
import { MSModelType } from "shared/models/models/model-saber.model";
|
||||
import { useOnUpdate } from "renderer/hooks/use-on-update.hook";
|
||||
import { useConstant } from "renderer/hooks/use-constant.hook";
|
||||
@@ -10,6 +10,15 @@ import { Progression } from "main/helpers/fs.helpers";
|
||||
import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface";
|
||||
import { ModelItem } from "./model-item.component";
|
||||
import { useBehaviorSubject } from "renderer/hooks/use-behavior-subject.hook";
|
||||
import { BsmImage } from "../shared/bsm-image.component";
|
||||
import BeatWaitingImg from "../../../../assets/images/apngs/beat-waiting.png"
|
||||
import BeatConflict from "../../../../assets/images/apngs/beat-conflict.png"
|
||||
import TextProgressBar from "../progress-bar/text-progress-bar.component";
|
||||
import { BehaviorSubject, distinctUntilChanged, map, startWith, tap } from "rxjs";
|
||||
import { BsmButton } from "../shared/bsm-button.component";
|
||||
import equal from "fast-deep-equal";
|
||||
import { VersionLinkerAction, VersionLinkerActionListener } from "renderer/services/version-folder-linker.service";
|
||||
import { MODEL_TYPE_FOLDERS } from "shared/models/models/constants";
|
||||
|
||||
type Props = {
|
||||
className?: string,
|
||||
@@ -26,27 +35,28 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active}
|
||||
const ref = useRef();
|
||||
const isVisible = useInView(ref, {once: true, amount: .1});
|
||||
|
||||
const [models, setModelsLoadObservable,, setModels] = useSwitchableObservable<Progression<BsmLocalModel[]>>();
|
||||
const [models, setModelsLoadObservable,, setModels] = useSwitchableObservable<BsmLocalModel[]>();
|
||||
const [progress$, setProgress$] = useState(new BehaviorSubject(0).asObservable());
|
||||
const [modelsSelected, modelsSelected$] = useBehaviorSubject<BsmLocalModel[]>([]);
|
||||
const isLoading = !models || !models?.extra;
|
||||
const hasModels = !isLoading && models?.extra.length;
|
||||
|
||||
const isLoading = !models;
|
||||
const hasModels = !!models?.length;
|
||||
|
||||
useImperativeHandle(forwardRef, () => ({
|
||||
getModels: () => {
|
||||
console.log(type, models?.extra);
|
||||
return models?.extra ?? [];
|
||||
return models ?? [];
|
||||
},
|
||||
getSelectedModels: () => {
|
||||
return modelsSelected;
|
||||
},
|
||||
reloadModels: () => {
|
||||
setModelsLoadObservable(() => modelsManager.$getModels(type, version));
|
||||
loadModels();
|
||||
},
|
||||
deleteSelectedModels: () => {
|
||||
modelsManager.deleteModels(modelsSelected, version).then(deleted => {
|
||||
if(!deleted){ return; }
|
||||
models.extra = models.extra.filter(m => !modelsSelected.some(d => d.hash === m.hash));
|
||||
setModels(() => models);
|
||||
const newModels = models.filter(m => !modelsSelected.some(d => d.hash === m.hash));
|
||||
setModels(() => newModels);
|
||||
modelsSelected$.next([]);
|
||||
});
|
||||
|
||||
@@ -55,9 +65,29 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active}
|
||||
|
||||
useOnUpdate(() => {
|
||||
if(!isVisible){ return; }
|
||||
setModelsLoadObservable(() => modelsManager.$getModels(type, version));
|
||||
loadModels();
|
||||
|
||||
const onLinkStateChangeCb = (action: VersionLinkerAction) => {
|
||||
if(!equal(version, action.version) || !action.relativeFolder.includes(MODEL_TYPE_FOLDERS[type])){ return; }
|
||||
loadModels();
|
||||
}
|
||||
|
||||
modelsManager.onModelsFolderLinked(onLinkStateChangeCb);
|
||||
modelsManager.onModelsFolderUnlinked(onLinkStateChangeCb);
|
||||
|
||||
return () => {
|
||||
modelsManager.removeModelsFolderLinkedListener(onLinkStateChangeCb);
|
||||
modelsManager.removeModelsFolderUnlinkedListener(onLinkStateChangeCb);
|
||||
}
|
||||
|
||||
}, [version, isVisible, type]);
|
||||
|
||||
const loadModels = () => {
|
||||
const modelsObs$ = modelsManager.$getModels(type, version);
|
||||
setModelsLoadObservable(() => modelsObs$.pipe(map(models => models?.extra), distinctUntilChanged()));
|
||||
setProgress$(modelsObs$.pipe(map(models => Math.floor((models.current / models.total) * 100)), startWith(0), distinctUntilChanged()))
|
||||
}
|
||||
|
||||
const handleModelClick = (model: BsmLocalModel) => {
|
||||
const prunedArray = Array.from(new Set(modelsSelected));
|
||||
if(prunedArray.some(m => m.hash === model.hash)){
|
||||
@@ -70,11 +100,11 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active}
|
||||
}
|
||||
|
||||
const filtredModels = () => {
|
||||
if(!active){ return models?.extra; }
|
||||
if(!active){ return models; }
|
||||
|
||||
const lowerSearch = search?.toLowerCase();
|
||||
|
||||
return models?.extra?.filter(model => {
|
||||
return models?.filter(model => {
|
||||
const findedInRawValues = Object.values(model).some(value => {
|
||||
if(typeof value !== "string" && typeof value !== "number"){ return false; }
|
||||
return value.toString().toLowerCase().includes(lowerSearch);
|
||||
@@ -96,12 +126,29 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref} className={`w-full h-full flex-shrink-0 ${className ?? ""}`}>
|
||||
{isLoading && <>loading</> /** TODO that **/}
|
||||
{!hasModels && <>no models</> /** TODO that **/}
|
||||
{hasModels && !isLoading && (
|
||||
<ul className="flex flex-wrap shrink-0 justify-start content-start w-full h-full overflow-y-scroll overflow-x-hidden p-4 gap-4 scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900">
|
||||
const renderContent = () => {
|
||||
if(isLoading){
|
||||
return (
|
||||
<div className="h-full flex flex-col items-center justify-center flex-wrap gap-1 text-gray-800 dark:text-gray-200">
|
||||
<BsmImage className="w-32 h-32 spin-loading" image={BeatWaitingImg}/>
|
||||
<span className="font-bold">Chargement des models...</span> {/** TODO TRANSLATE **/}
|
||||
<TextProgressBar value$={progress$}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if(!hasModels){
|
||||
return (
|
||||
<div className="h-full flex flex-col items-center justify-center flex-wrap gap-1 text-gray-800 dark:text-gray-200">
|
||||
<BsmImage className="h-32" image={BeatConflict}/>
|
||||
<span className="font-bold">Aucun modelès</span> {/** TODO TRANSLATE **/}
|
||||
<BsmButton className="font-bold rounded-md p-2" text="Télécharger des modèles" typeColor="primary" withBar={false} onClick={e => {e.preventDefault();}}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="flex flex-wrap shrink-0 justify-start content-start w-full h-full overflow-y-scroll overflow-x-hidden p-4 gap-4 scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900">
|
||||
{filtredModels().map(localModel => (
|
||||
<ModelItem
|
||||
key={localModel.model?.hash ?? localModel.hash}
|
||||
@@ -120,7 +167,12 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref} className={`w-full h-full flex-shrink-0 ${className ?? ""}`}>
|
||||
{renderContent()}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defaultIfEmpty, share } from "rxjs/operators";
|
||||
import { defaultIfEmpty, share, shareReplay } from "rxjs/operators";
|
||||
import { Observable } from "rxjs";
|
||||
import { IpcRequest, IpcResponse } from "shared/models/ipc";
|
||||
import { identity } from "rxjs";
|
||||
@@ -62,7 +62,7 @@ export class IpcService {
|
||||
window.electron.ipcRenderer.on(request.responceChannel, (res: T) => observer.next(res));
|
||||
window.electron.ipcRenderer.on(errorChannel, (err: Error) => observer.error(err));
|
||||
window.electron.ipcRenderer.on(completeChannel, () => observer.complete());
|
||||
}).pipe(defaultValue ? defaultIfEmpty(defaultValue) : identity, share());
|
||||
}).pipe(defaultValue ? defaultIfEmpty(defaultValue) : identity, shareReplay(1));
|
||||
|
||||
window.electron.ipcRenderer.once(completeChannel, () => {
|
||||
window.electron.ipcRenderer.removeAllListeners(request.responceChannel);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MSModelType } from "shared/models/models/model-saber.model";
|
||||
import { IpcService } from "../ipc.service";
|
||||
import { VersionFolderLinkerService, VersionLinkerActionType } from "../version-folder-linker.service";
|
||||
import { VersionFolderLinkerService, VersionLinkerActionListener, VersionLinkerActionType } from "../version-folder-linker.service";
|
||||
import { MODEL_TYPE_FOLDERS } from "shared/models/models/constants";
|
||||
import { Observable, distinctUntilChanged, lastValueFrom, map, mergeMap, share } from "rxjs";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
@@ -52,6 +52,22 @@ export class ModelsManagerService {
|
||||
return this.versionFolderLinked.$isVersionFolderPending(version, MODEL_TYPE_FOLDERS[type]);
|
||||
}
|
||||
|
||||
public onModelsFolderLinked(callback: VersionLinkerActionListener): void{
|
||||
return this.versionFolderLinked.onVersionFolderLinked(callback);
|
||||
}
|
||||
|
||||
public onModelsFolderUnlinked(callback: VersionLinkerActionListener): void{
|
||||
return this.versionFolderLinked.onVersionFolderUnlinked(callback);
|
||||
}
|
||||
|
||||
public removeModelsFolderLinkedListener(callback: VersionLinkerActionListener): void{
|
||||
return this.versionFolderLinked.removeVersionFolderLinkedListener(callback);
|
||||
}
|
||||
|
||||
public removeModelsFolderUnlinkedListener(callback: VersionLinkerActionListener): void{
|
||||
return this.versionFolderLinked.removeVersionFolderUnlinkedListener(callback);
|
||||
}
|
||||
|
||||
public async linkModels(type: MSModelType, version?: BSVersion): Promise<boolean>{
|
||||
|
||||
const res = await this.modalService.openModal(LinkModelsModal, type);
|
||||
|
||||
Reference in New Issue
Block a user