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:
@@ -597,6 +597,88 @@
|
||||
"unlink-folder": "Ordner Verknüpfung Aufheben",
|
||||
"link-all": "Alle verlinken"
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"link-models": {
|
||||
"avatar": {
|
||||
"title": "Avatare verbinden",
|
||||
"desc": "Das Verbinden von Avataren ermöglicht das Teilen von Avataren zwischen allen Versionen. Sobald verbunden, wird diese Version von den geteilten Avataren profitieren",
|
||||
"info": "Das Hinzufügen und Entfernen von Avataren wird ebenfalls geteilt",
|
||||
"keep-models": {
|
||||
"label": "Avatare behalten",
|
||||
"title": "Das Behalten der Avatare wird die Avatare der aktuellen Version in den Ordner der geteilten Avatare verschieben. Andernfalls gehen sie verloren"
|
||||
},
|
||||
"valid-btn": "Avatare verbinden"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Säbel verbinden",
|
||||
"desc": "Das Verbinden von Säbeln ermöglicht das Teilen von Säbeln zwischen allen Versionen. Sobald verbunden, wird diese Version von den geteilten Säbeln profitieren",
|
||||
"info": "Das Hinzufügen und Entfernen von Säbeln wird ebenfalls geteilt",
|
||||
"keep-models": {
|
||||
"label": "Säbel behalten",
|
||||
"title": "Das Behalten der Säbel wird die Säbel der aktuellen Version in den Ordner der geteilten Säbel verschieben. Andernfalls gehen sie verloren"
|
||||
},
|
||||
"valid-btn": "Säbel verbinden"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Plattformen verbinden",
|
||||
"desc": "Das Verbinden von Plattformen ermöglicht das Teilen von Plattformen zwischen allen Versionen. Sobald verbunden, wird diese Version von den geteilten Plattformen profitieren",
|
||||
"info": "Das Hinzufügen und Entfernen von Plattformen wird ebenfalls geteilt",
|
||||
"keep-models": {
|
||||
"label": "Plattformen behalten",
|
||||
"title": "Das Behalten der Plattformen wird die Plattformen der aktuellen Version in den Ordner der geteilten Plattformen verschieben. Andernfalls gehen sie verloren"
|
||||
},
|
||||
"valid-btn": "Plattformen verbinden"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Bloqs verbinden",
|
||||
"desc": "Das Verbinden von Bloqs ermöglicht das Teilen von Bloqs zwischen allen Versionen. Sobald verbunden, wird diese Version von den geteilten Bloqs profitieren",
|
||||
"info": "Das Hinzufügen und Entfernen von Bloqs wird ebenfalls geteilt",
|
||||
"keep-models": {
|
||||
"label": "Bloqs behalten",
|
||||
"title": "Das Behalten der Bloqs wird die Bloqs der aktuellen Version in den Ordner der geteilten Bloqs verschieben. Andernfalls gehen sie verloren"
|
||||
},
|
||||
"valid-btn": "Bloqs verbinden"
|
||||
}
|
||||
},
|
||||
"unlink-models": {
|
||||
"avatar": {
|
||||
"title": "Avatare trennen",
|
||||
"desc": "Achtung, das Trennen der Avatare wird die Nutzung der geteilten Avatare für diese Version nicht mehr ermöglichen.",
|
||||
"keep-models": {
|
||||
"label": "Avatare behalten",
|
||||
"title": "Das Behalten der Avatare wird eine Kopie der geteilten Avatare für die aktuelle Version erstellen. Andernfalls wird kein Avatar für diese Version aufbewahrt."
|
||||
},
|
||||
"valid-btn": "Avatare trennen"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Säbel trennen",
|
||||
"desc": "Achtung, das Trennen der Säbel wird die Nutzung der geteilten Säbel für diese Version nicht mehr ermöglichen.",
|
||||
"keep-models": {
|
||||
"label": "Säbel behalten",
|
||||
"title": "Das Behalten der Säbel wird eine Kopie der geteilten Säbel für die aktuelle Version erstellen. Andernfalls wird kein Säbel für diese Version aufbewahrt."
|
||||
},
|
||||
"valid-btn": "Säbel trennen"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Plattformen trennen",
|
||||
"desc": "Achtung, das Trennen der Plattformen wird die Nutzung der geteilten Plattformen für diese Version nicht mehr ermöglichen.",
|
||||
"keep-models": {
|
||||
"label": "Plattformen behalten",
|
||||
"title": "Das Behalten der Plattformen wird eine Kopie der geteilten Plattformen für die aktuelle Version erstellen. Andernfalls wird keine Plattform für diese Version aufbewahrt."
|
||||
},
|
||||
"valid-btn": "Plattformen trennen"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Bloqs trennen",
|
||||
"desc": "Achtung, das Trennen der Bloqs wird die Nutzung der geteilten Bloqs für diese Version nicht mehr ermöglichen.",
|
||||
"keep-models": {
|
||||
"label": "Bloqs behalten",
|
||||
"title": "Das Behalten der Bloqs wird eine Kopie der geteilten Bloqs für die aktuelle Version erstellen. Andernfalls wird kein Bloq für diese Version aufbewahrt."
|
||||
},
|
||||
"valid-btn": "Bloqs trennen"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"maps": {
|
||||
|
||||
@@ -597,6 +597,88 @@
|
||||
"unlink-folder": "Unlink Folder",
|
||||
"link-all": "Link all"
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"link-models": {
|
||||
"avatar": {
|
||||
"title": "Link Avatars",
|
||||
"desc": "Linking avatars allows sharing avatars between all versions. Once linked, this version will benefit from the shared avatars",
|
||||
"info": "Adding and deleting avatars will also be shared",
|
||||
"keep-models": {
|
||||
"label": "Keep Avatars",
|
||||
"title": "Keeping the avatars will move the avatars from the current version to the shared avatars folder. Otherwise, they will be lost"
|
||||
},
|
||||
"valid-btn": "Link Avatars"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Link Sabers",
|
||||
"desc": "Linking sabers allows sharing sabers between all versions. Once linked, this version will benefit from the shared sabers",
|
||||
"info": "Adding and deleting sabers will also be shared",
|
||||
"keep-models": {
|
||||
"label": "Keep Sabers",
|
||||
"title": "Keeping the sabers will move the sabers from the current version to the shared sabers folder. Otherwise, they will be lost"
|
||||
},
|
||||
"valid-btn": "Link Sabers"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Link Platforms",
|
||||
"desc": "Linking platforms allows sharing platforms between all versions. Once linked, this version will benefit from the shared platforms",
|
||||
"info": "Adding and deleting platforms will also be shared",
|
||||
"keep-models": {
|
||||
"label": "Keep Platforms",
|
||||
"title": "Keeping the platforms will move the platforms from the current version to the shared platforms folder. Otherwise, they will be lost"
|
||||
},
|
||||
"valid-btn": "Link Platforms"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Link Bloqs",
|
||||
"desc": "Linking bloqs allows sharing bloqs between all versions. Once linked, this version will benefit from the shared bloqs",
|
||||
"info": "Adding and deleting bloqs will also be shared",
|
||||
"keep-models": {
|
||||
"label": "Keep Bloqs",
|
||||
"title": "Keeping the bloqs will move the bloqs from the current version to the shared bloqs folder. Otherwise, they will be lost"
|
||||
},
|
||||
"valid-btn": "Link Bloqs"
|
||||
}
|
||||
},
|
||||
"unlink-models": {
|
||||
"avatar": {
|
||||
"title": "Unlink Avatars",
|
||||
"desc": "Be careful, unlinking avatars will no longer allow the use of shared avatars for this version.",
|
||||
"keep-models": {
|
||||
"label": "Keep Avatars",
|
||||
"title": "Keeping the avatars will create a copy of the shared avatars for the current version. Otherwise, no avatars will be kept for this version."
|
||||
},
|
||||
"valid-btn": "Unlink Avatars"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Unlink Sabers",
|
||||
"desc": "Be careful, unlinking sabers will no longer allow the use of shared sabers for this version.",
|
||||
"keep-models": {
|
||||
"label": "Keep Sabers",
|
||||
"title": "Keeping the sabers will create a copy of the shared sabers for the current version. Otherwise, no sabers will be kept for this version."
|
||||
},
|
||||
"valid-btn": "Unlink Sabers"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Unlink Platforms",
|
||||
"desc": "Be careful, unlinking platforms will no longer allow the use of shared platforms for this version.",
|
||||
"keep-models": {
|
||||
"label": "Keep Platforms",
|
||||
"title": "Keeping the platforms will create a copy of the shared platforms for the current version. Otherwise, no platforms will be kept for this version."
|
||||
},
|
||||
"valid-btn": "Unlink Platforms"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Unlink Bloqs",
|
||||
"desc": "Be careful, unlinking bloqs will no longer allow the use of shared bloqs for this version.",
|
||||
"keep-models": {
|
||||
"label": "Keep Bloqs",
|
||||
"title": "Keeping the bloqs will create a copy of the shared bloqs for the current version. Otherwise, no bloqs will be kept for this version."
|
||||
},
|
||||
"valid-btn": "Unlink Bloqs"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"maps": {
|
||||
|
||||
@@ -596,6 +596,88 @@
|
||||
"unlink-folder": "Desenlazar Carpeta",
|
||||
"link-all": "Enlazar todo"
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"link-models": {
|
||||
"avatar": {
|
||||
"title": "Vincular avatares",
|
||||
"desc": "La vinculación de avatares permite compartir avatares entre todas las versiones. Una vez vinculada, esta versión se beneficiará de los avatares compartidos",
|
||||
"info": "La adición y eliminación de avatares también se compartirá",
|
||||
"keep-models": {
|
||||
"label": "Conservar los avatares",
|
||||
"title": "Conservar los avatares moverá los avatares de la versión actual a la carpeta de avatares compartidos. De lo contrario, se perderán"
|
||||
},
|
||||
"valid-btn": "Vincular avatares"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Vincular sables",
|
||||
"desc": "La vinculación de sables permite compartir sables entre todas las versiones. Una vez vinculada, esta versión se beneficiará de los sables compartidos",
|
||||
"info": "La adición y eliminación de sables también se compartirá",
|
||||
"keep-models": {
|
||||
"label": "Conservar los sables",
|
||||
"title": "Conservar los sables moverá los sables de la versión actual a la carpeta de sables compartidos. De lo contrario, se perderán"
|
||||
},
|
||||
"valid-btn": "Vincular sables"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Vincular plataformas",
|
||||
"desc": "La vinculación de plataformas permite compartir plataformas entre todas las versiones. Una vez vinculada, esta versión se beneficiará de las plataformas compartidas",
|
||||
"info": "La adición y eliminación de plataformas también se compartirá",
|
||||
"keep-models": {
|
||||
"label": "Conservar las plataformas",
|
||||
"title": "Conservar las plataformas moverá las plataformas de la versión actual a la carpeta de plataformas compartidas. De lo contrario, se perderán"
|
||||
},
|
||||
"valid-btn": "Vincular plataformas"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Vincular bloqs",
|
||||
"desc": "La vinculación de bloqs permite compartir bloqs entre todas las versiones. Una vez vinculada, esta versión se beneficiará de los bloqs compartidos",
|
||||
"info": "La adición y eliminación de bloqs también se compartirá",
|
||||
"keep-models": {
|
||||
"label": "Conservar los bloqs",
|
||||
"title": "Conservar los bloqs moverá los bloqs de la versión actual a la carpeta de bloqs compartidos. De lo contrario, se perderán"
|
||||
},
|
||||
"valid-btn": "Vincular bloqs"
|
||||
}
|
||||
},
|
||||
"unlink-models": {
|
||||
"avatar": {
|
||||
"title": "Desvincular avatares",
|
||||
"desc": "Atención, desvincular los avatares ya no permitirá el uso de avatares compartidos para esta versión.",
|
||||
"keep-models": {
|
||||
"label": "Conservar los avatares",
|
||||
"title": "Conservar los avatares creará una copia de los avatares compartidos para la versión actual. En caso contrario, ningún avatar se conservará para esta versión."
|
||||
},
|
||||
"valid-btn": "Desvincular avatares"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Desvincular sables",
|
||||
"desc": "Atención, desvincular los sables ya no permitirá el uso de sables compartidos para esta versión.",
|
||||
"keep-models": {
|
||||
"label": "Conservar los sables",
|
||||
"title": "Conservar los sables creará una copia de los sables compartidos para la versión actual. En caso contrario, ningún sable se conservará para esta versión."
|
||||
},
|
||||
"valid-btn": "Desvincular sables"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Desvincular plataformas",
|
||||
"desc": "Atención, desvincular las plataformas ya no permitirá el uso de plataformas compartidas para esta versión.",
|
||||
"keep-models": {
|
||||
"label": "Conservar las plataformas",
|
||||
"title": "Conservar las plataformas creará una copia de las plataformas compartidas para la versión actual. En caso contrario, ninguna plataforma se conservará para esta versión."
|
||||
},
|
||||
"valid-btn": "Desvincular plataformas"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Desvincular bloqs",
|
||||
"desc": "Atención, desvincular los bloqs ya no permitirá el uso de bloqs compartidos para esta versión.",
|
||||
"keep-models": {
|
||||
"label": "Conservar los bloqs",
|
||||
"title": "Conservar los bloqs creará una copia de los bloqs compartidos para la versión actual. En caso contrario, ningún bloq se conservará para esta versión."
|
||||
},
|
||||
"valid-btn": "Desvincular bloqs"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"maps": {
|
||||
|
||||
@@ -596,6 +596,88 @@
|
||||
"unlink-folder": "Délier le dossier",
|
||||
"link-all": "Tout lier"
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"link-models":{
|
||||
"avatar": {
|
||||
"title": "Lier les avatars",
|
||||
"desc": "La liaison des avatars permet de partager les avatars entre toute les version. Une fois liée, cette version profitera des avatars partagés",
|
||||
"info": "L'ajout et la suppression d'avatars sera également partagé",
|
||||
"keep-models": {
|
||||
"label": "Conserver les avatars",
|
||||
"title": "Conserver les avatars déplacera les avatars de la version actuelle dans le dossier des avatars partagés. Dans le cas contraire ils seront perdus"
|
||||
},
|
||||
"valid-btn": "Lier les avatars"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Lier les sabres",
|
||||
"desc": "La liaison des sabres permet de partager les sabres entre toute les version. Une fois liée, cette version profitera des sabres partagés",
|
||||
"info": "L'ajout et la suppression de sabres sera également partagé",
|
||||
"keep-models": {
|
||||
"label": "Conserver les sabres",
|
||||
"title": "Conserver les sabres déplacera les sabres de la version actuelle dans le dossier des sabres partagés. Dans le cas contraire ils seront perdus"
|
||||
},
|
||||
"valid-btn": "Lier les sabres"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Lier les plateformes",
|
||||
"desc": "La liaison des plateformes permet de partager les plateformes entre toute les version. Une fois liée, cette version profitera des plateformes partagées",
|
||||
"info": "L'ajout et la suppression de plateformes sera également partagé",
|
||||
"keep-models": {
|
||||
"label": "Conserver les plateformes",
|
||||
"title": "Conserver les plateformes déplacera les plateformes de la version actuelle dans le dossier des plateformes partagées. Dans le cas contraire ils seront perdus"
|
||||
},
|
||||
"valid-btn": "Lier les plateformes"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Lier les bloqs",
|
||||
"desc": "La liaison des bloqs permet de partager les bloqs entre toute les version. Une fois liée, cette version profitera des bloqs partagés",
|
||||
"info": "L'ajout et la suppression de bloqs sera également partagé",
|
||||
"keep-models": {
|
||||
"label": "Conserver les bloqs",
|
||||
"title": "Conserver les bloqs déplacera les bloqs de la version actuelle dans le dossier des bloqs partagés. Dans le cas contraire ils seront perdus"
|
||||
},
|
||||
"valid-btn": "Lier les bloqs"
|
||||
}
|
||||
},
|
||||
"unlink-models":{
|
||||
"avatar": {
|
||||
"title": "Délier les avatars",
|
||||
"desc": "Attention, délier les avatars ne permettra plus l'utilisation des avatars paratagés pour cette version.",
|
||||
"keep-models": {
|
||||
"label": "Conserver les avatars",
|
||||
"title": "Conserver les avatars créera une copie des avatars partagés pour la version actuelle. Dans le cas contraire, aucun avatar ne sera conservé pour cette version."
|
||||
},
|
||||
"valid-btn": "Délier les avatars"
|
||||
},
|
||||
"saber": {
|
||||
"title": "Délier les sabres",
|
||||
"desc": "Attention, délier les sabres ne permettra plus l'utilisation des sabres paratagés pour cette version.",
|
||||
"keep-models": {
|
||||
"label": "Conserver les sabres",
|
||||
"title": "Conserver les sabres créera une copie des sabres partagés pour la version actuelle. Dans le cas contraire, aucun sabre ne sera conservé pour cette version."
|
||||
},
|
||||
"valid-btn": "Délier les sabres"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Délier les plateformes",
|
||||
"desc": "Attention, délier les plateformes ne permettra plus l'utilisation des plateformes paratagées pour cette version.",
|
||||
"keep-models": {
|
||||
"label": "Conserver les plateformes",
|
||||
"title": "Conserver les plateformes créera une copie des plateformes partagées pour la version actuelle. Dans le cas contraire, aucune plateforme ne sera conservée pour cette version."
|
||||
},
|
||||
"valid-btn": "Délier les plateformes"
|
||||
},
|
||||
"bloq": {
|
||||
"title": "Délier les bloqs",
|
||||
"desc": "Attention, délier les bloqs ne permettra plus l'utilisation des bloqs paratagés pour cette version.",
|
||||
"keep-models": {
|
||||
"label": "Conserver les bloqs",
|
||||
"title": "Conserver les bloqs créera une copie des bloqs partagés pour la version actuelle. Dans le cas contraire, aucun bloq ne sera conservé pour cette version."
|
||||
},
|
||||
"valid-btn": "Délier les bloqs"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"maps": {
|
||||
|
||||
@@ -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