Compare commits

...

2 Commits

Author SHA1 Message Date
MathieuG-P b59f3f6ad5 Merge branch 'master' into feature/see-available-mods-for-a-version 2024-07-13 15:26:53 +02:00
MathieuG-P cfde548150 [feature] we can open a modal to see available mods for a version 2024-06-06 21:57:09 +02:00
15 changed files with 206 additions and 73 deletions
+9 -3
View File
@@ -1,12 +1,13 @@
import { BsModsManagerService } from "../services/mods/bs-mods-manager.service";
import { IpcService } from "../services/ipc.service";
import { from } from "rxjs";
import { BeatModsApiService } from "main/services/mods/beat-mods-api.service";
const ipc = IpcService.getInstance();
ipc.on("get-available-mods", (args, reply) => {
const modsManager = BsModsManagerService.getInstance();
reply(from(modsManager.getAvailableMods(args)));
ipc.on("get-version-mods", (args, reply) => {
const beatMods = BeatModsApiService.getInstance();
reply(from(beatMods.getVersionMods(args)));
});
ipc.on("get-installed-mods", (args, reply) => {
@@ -14,6 +15,11 @@ ipc.on("get-installed-mods", (args, reply) => {
reply(from(modsManager.getInstalledMods(args)));
});
ipc.on("get-version-aliases", (_, reply) => {
const beatmods = BeatModsApiService.getInstance();
reply(from(beatmods.getVersionAliases()));
});
ipc.on("install-mods", (args, reply) => {
const modsManager = BsModsManagerService.getInstance();
reply(from(modsManager.installMods(args.mods, args.version)));
+17 -25
View File
@@ -1,4 +1,4 @@
import { BSVersion } from "shared/bs-version.interface";
import { BSVersion, BSVersionString } from "shared/bs-version.interface";
import { Mod } from "shared/models/mods/mod.interface";
import { RequestService } from "../request.service";
@@ -12,8 +12,8 @@ export class BeatModsApiService {
private readonly BEAT_MODS_API_URL = "https://beatmods.com/api/v1/";
public readonly BEAT_MODS_URL = "https://beatmods.com";
private readonly aliasesCache = new Map<string, BSVersion[]>();
private readonly versionModsCache = new Map<string, Mod[]>();
private aliasesCache: Record<BSVersionString, BSVersionString[]> = {};
private readonly versionModsCache = new Map<BSVersionString, Mod[]>();
private allModsCache: Mod[];
@@ -36,29 +36,21 @@ export class BeatModsApiService {
return `${this.BEAT_MODS_API_URL}mod`;
}
private async getVersionAlias(): Promise<Map<string, BSVersion[]>> {
if (this.aliasesCache.size) {
public async getVersionAliases(): Promise<Record<BSVersionString, BSVersionString[]>> {
if (Object.keys(this.aliasesCache).length > 0) {
return this.aliasesCache;
}
return this.requestService.getJSON<Record<string, string[]>>(this.BEAT_MODS_ALIAS).then(rawAliases => {
Object.entries(rawAliases).forEach(([key, value]) => {
this.aliasesCache.set(
key,
value.map(s => ({ BSVersion: s } as BSVersion))
);
});
return this.requestService.getJSON<Record<BSVersionString, BSVersionString[]>>(this.BEAT_MODS_ALIAS).then(rawAliases => {
this.aliasesCache = rawAliases;
return this.aliasesCache;
});
}
private async getAliasOfVersion(version: BSVersion): Promise<BSVersion> {
return this.getVersionAlias().then(aliases => {
if (Array.from(aliases.keys()).some(k => k === version.BSVersion)) {
return version;
}
const alias = Array.from(aliases.entries()).find(([, value]) => value.find(v => v.BSVersion === version.BSVersion))?.[0];
return { BSVersion: alias } as BSVersion;
});
private async getAliasOfVersion(version: BSVersionString): Promise<BSVersionString> {
return this.getVersionAliases().then(aliases => (
aliases[version] ? version : Object.keys(aliases).find(k => aliases[k as BSVersionString].some(v => v === version)) as BSVersionString
));
}
private asignDependencies(mod: Mod, mods: Mod[]): Mod {
@@ -66,16 +58,16 @@ export class BeatModsApiService {
return mod;
}
public async getVersionMods(version: BSVersion): Promise<Mod[]> {
if (this.versionModsCache.has(version.BSVersion)) {
return this.versionModsCache.get(version.BSVersion);
public async getVersionMods(version: BSVersionString): Promise<Mod[]> {
if (this.versionModsCache.has(version)) {
return this.versionModsCache.get(version);
}
const alias = await this.getAliasOfVersion(version);
return this.requestService.getJSON<Mod[]>(this.getVersionModsUrl(alias)).then(mods => {
return this.requestService.getJSON<Mod[]>(this.getVersionModsUrl({ BSVersion: alias })).then(mods => {
mods = mods.map(mod => this.asignDependencies(mod, mods));
this.versionModsCache.set(version.BSVersion, mods);
this.versionModsCache.set(version, mods);
return mods;
});
}
@@ -264,7 +264,7 @@ export class BsModsManagerService {
}
private async resolveDependencies(mods: Mod[], version: BSVersion): Promise<Mod[]> {
const availableMods = await this.beatModsApi.getVersionMods(version);
const availableMods = await this.beatModsApi.getVersionMods(version.BSVersion);
return Array.from(
new Map<string, Mod>(
availableMods.reduce((res, mod) => {
@@ -316,10 +316,6 @@ export class BsModsManagerService {
await Promise.all(promises);
}
public getAvailableMods(version: BSVersion): Promise<Mod[]> {
return this.beatModsApi.getVersionMods(version);
}
public async getInstalledMods(version: BSVersion): Promise<Mod[]> {
this.manifestMatches = [];
await this.beatModsApi.getAllMods();
@@ -1,4 +1,4 @@
import { BSVersion } from "shared/bs-version.interface";
import { BSVersion, BSVersionString } from "shared/bs-version.interface";
import { useState, memo, ComponentProps } from "react";
import defaultImage from "../../../../assets/images/default-version-img.jpg";
import dateFormat from "dateformat";
@@ -9,19 +9,33 @@ import { GlowEffect } from "../shared/glow-effect.component";
import equal from "fast-deep-equal";
import { SteamIcon } from "../svgs/icons/steam-icon.component";
import { useConstant } from "renderer/hooks/use-constant.hook";
import { CpuIcon } from "../svgs/icons/cpu-icon.component";
import Tippy from "@tippyjs/react";
import { useService } from "renderer/hooks/use-service.hook";
import { ModalService } from "renderer/services/modale.service";
import { AvailableModsModal } from "../modal/modal-types/available-mods-modal.component";
type Props = {
version: BSVersion;
selected: boolean;
beatModsVersionAlias?: BSVersionString;
onClick: ComponentProps<"li">["onClick"];
}
export const AvailableVersionItem = memo(function AvailableVersionItem({version, selected, onClick}: Props) {
export const AvailableVersionItem = memo(function AvailableVersionItem({version, selected, beatModsVersionAlias, onClick}: Props) {
const t = useTranslation();
const modal = useService(ModalService);
const [hovered, setHovered] = useState(false);
const formatedDate = useConstant(() => dateFormat(+version.ReleaseDate * 1000, "ddd. d mmm yyyy"));
const openAvailableMods = () => {
if(!beatModsVersionAlias) { return; }
modal.openModal(AvailableModsModal, beatModsVersionAlias);
};
return (
<motion.li className="group relative w-72 h-60 active:scale-[.98]" onClick={onClick} onHoverStart={() => setHovered(true)} onHoverEnd={() => setHovered(false)}>
<GlowEffect visible={hovered || selected} className="absolute" />
@@ -36,12 +50,22 @@ export const AvailableVersionItem = memo(function AvailableVersionItem({version,
<h2 className="block text-xl font-bold text-white tracking-wider">{version.BSVersion}</h2>
<span className="text-sm text-gray-700 dark:text-gray-400">{formatedDate}</span>
</div>
{version.ReleaseURL && (
<a href={version.ReleaseURL} target="_blank" className="flex flex-row justify-between items-center rounded-full bg-black bg-opacity-30 text-white pb-px overflow-hidden hover:bg-opacity-50" tabIndex={-1}>
<SteamIcon className="w-[25px] h-[25px] transition-transform group-hover:rotate-[-360deg] duration-300" />
<span className="relative -left-px text-sm w-fit max-w-0 text-center overflow-hidden h-full whitespace-nowrap pb-[3px] transition-all group-hover:max-w-[200px] group-hover:px-1 duration-300">{t("pages.available-versions.steam-release")}</span>
</a>
)}
<div className="flex items-end gap-2">
{version.ReleaseURL && (
<a href={version.ReleaseURL} target="_blank" className="flex flex-row justify-between items-center rounded-full bg-black bg-opacity-30 text-white pb-px overflow-hidden hover:bg-opacity-50" tabIndex={-1}>
<SteamIcon className="size-[25px] transition-transform group-hover:rotate-[-360deg] duration-300" />
<span className="relative -left-px text-sm w-fit max-w-0 text-center overflow-hidden h-full whitespace-nowrap pb-[3px] transition-all group-hover:max-w-[200px] group-hover:px-1 duration-300">{t("pages.available-versions.steam-release")}</span>
</a>
)}
{beatModsVersionAlias && (
<Tippy content="Voir les mods disponnible" placement="top" theme="default">
<button className="size-[25px] rounded-full bg-black bg-opacity-30 p-[3px] hover:bg-opacity-50" type="button" onClickCapture={openAvailableMods}>
<CpuIcon className="text-gray-200"/>
</button>
</Tippy>
)}
</div>
</div>
</div>
</motion.li>
@@ -1,14 +1,15 @@
import { useContext } from "react";
import { AvailableVersionItem } from "./available-version-item.component";
import { BSVersion } from "shared/bs-version.interface";
import { BSVersion, BSVersionString } from "shared/bs-version.interface";
import { AvailableVersionsContext } from "renderer/pages/available-versions-list.components";
import equal from "fast-deep-equal";
type Props = {
versions: BSVersion[]
versions: BSVersion[],
versionModAliases?: Record<BSVersionString, BSVersionString[]>
}
export function AvailableVersionsSlide({ versions }: Props) {
export function AvailableVersionsSlide({ versions, versionModAliases }: Props) {
const context = useContext(AvailableVersionsContext);
@@ -28,10 +29,16 @@ export function AvailableVersionsSlide({ versions }: Props) {
return copy;
}
const getVersionModAlias = (version: BSVersion): BSVersionString => {
if(!versionModAliases) { return; }
if(versionModAliases[version.BSVersion]) { return version.BSVersion; }
return Object.keys(versionModAliases).find(k => versionModAliases[k as BSVersionString].some(v => v === version.BSVersion)) as BSVersionString;
}
return (
<ol className="w-full flex items-start justify-center gap-6 shrink-0 content-start flex-wrap px-3.5 py-4 overflow-x-hidden overflow-y-scroll scrollbar-default">
{getVersions().map(version => (
<AvailableVersionItem key={version.BSManifest} version={version} selected={equal(version, context.selectedVersion)} onClick={() => setSelectedVersion(version)}/>
<AvailableVersionItem key={version.BSManifest} version={version} selected={equal(version, context.selectedVersion)} onClick={() => setSelectedVersion(version)} beatModsVersionAlias={getVersionModAlias(version)}/>
))}
</ol>
);
@@ -4,10 +4,13 @@ import { AvailableVersionsSlide } from "./available-versions-slide.component";
import { TabNavBar } from "../shared/tab-nav-bar.component";
import { useService } from "renderer/hooks/use-service.hook";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { BeatModsService } from "renderer/services/thrird-partys/beat-mods.service";
export function AvailableVersionsSlider() {
const versionManagerService = useService(BSVersionManagerService);
const beatMods = useService(BeatModsService);
const versionModAliases = useObservable(() => beatMods.getVersionAliases(), undefined);
const availableVersions = useObservable(() => versionManagerService.availableVersions$);
const [yearIndex, setYearIndex] = useState(0);
@@ -29,7 +32,7 @@ export function AvailableVersionsSlider() {
<TabNavBar tabIndex={yearIndex} tabsText={availableYears} onTabChange={setSelectedYear} />
<ol className="w-full min-h-0 flex transition-transform duration-300" style={{ transform: `translate(${-(yearIndex * 100)}%, 0)` }}>
{availableYears.map(year => (
<AvailableVersionsSlide key={year} versions={getVersionOfYear(year)} />
<AvailableVersionsSlide key={year} versions={getVersionOfYear(year)} versionModAliases={versionModAliases} />
))}
</ol>
</div>
@@ -0,0 +1,19 @@
import { ModsGrid, modsArrayToCategoryMap } from "renderer/components/version-viewer/slides/mods/mods-grid.component";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { useService } from "renderer/hooks/use-service.hook"
import { ModalComponent } from "renderer/services/modale.service"
import { BeatModsService } from "renderer/services/thrird-partys/beat-mods.service";
import { BSVersionString } from "shared/bs-version.interface"
export const AvailableModsModal: ModalComponent<void, BSVersionString> = ({ data }) => {
const beatMods = useService(BeatModsService);
const availableMods = useObservable(() => beatMods.getVersionMods(data), undefined);
return (
<div className="h-[85vh] overflow-y-scroll">
{availableMods && <ModsGrid modsMap={modsArrayToCategoryMap(availableMods)} />}
</div>
)
}
@@ -0,0 +1,9 @@
import { createSvgIcon } from "../svg-icon.type"
export const CpuIcon = createSvgIcon((props, ref) => {
return (
<svg ref={ref} {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor">
<path d="M360-405.5v-149q0-19.15 13.17-32.33Q386.35-600 405.5-600h149q19.15 0 32.33 13.17Q600-573.65 600-554.5v149q0 19.15-13.17 32.33Q573.65-360 554.5-360h-149q-19.15 0-32.33-13.17Q360-386.35 360-405.5Zm80-34.5h80v-80h-80v80Zm-85.5 289.8v-41.67h-71.63q-37.78 0-64.39-26.61t-26.61-64.39v-71.63h-41.85q-17.78 0-29.76-12.05t-11.98-29.86q0-17.71 12.05-29.7 12.05-11.98 29.87-11.98h41.67v-83.82h-41.79q-17.77 0-29.78-12.05-12.02-12.05-12.02-29.87 0-17.71 12.05-29.69t29.87-11.98h41.67v-71.63q0-37.78 26.61-64.39t64.39-26.61h71.63v-41.85q0-17.78 12.05-29.76t29.86-11.98q17.71 0 29.7 12.02 11.98 12.01 11.98 29.78v41.79h83.82v-41.79q0-17.77 12.05-29.78 12.05-12.02 29.87-12.02 17.71 0 29.69 12.02 11.98 12.01 11.98 29.78v41.79h71.63q37.78 0 64.39 26.61t26.61 64.39v71.63h41.85q17.78 0 29.76 11.98t11.98 29.69q0 17.82-12.02 29.87-12.01 12.05-29.78 12.05h-41.79v83.82h41.79q17.77 0 29.78 11.99 12.02 11.98 12.02 29.69T839.7-366.6q-12.01 12.1-29.78 12.1h-41.79v71.63q0 37.78-26.61 64.39t-64.39 26.61H605.5v41.85q0 17.78-11.98 29.76t-29.7 11.98q-17.71 0-29.81-12.05-12.1-12.05-12.1-29.87v-41.67h-83.82v41.79q0 17.77-11.99 29.78-11.98 12.02-29.69 12.02t-29.81-12.05q-12.1-12.05-12.1-29.87Zm322.63-132.67v-394.26H282.87v394.26h394.26ZM480-480Z"/>
</svg>
)
});
@@ -10,9 +10,29 @@ import useDoubleClick from "use-double-click";
import { gt } from "semver";
import { useService } from "renderer/hooks/use-service.hook";
type Props = { className?: string; mod: Mod; installedVersion: string; isDependency?: boolean; isSelected?: boolean; onChange?: (val: boolean) => void; wantInfo?: boolean; onWantInfo?: (mod: Mod) => void };
type Props = {
className?: string;
mod: Mod;
installedVersion: string;
isDependency?: boolean;
isSelected?: boolean;
showInstalled?: boolean;
onChange?: (val: boolean) => void;
wantInfo?: boolean;
onWantInfo?: (mod: Mod) => void
};
export function ModItem({ className, mod, installedVersion, isDependency, isSelected, onChange, wantInfo, onWantInfo }: Props) {
export function ModItem({
className,
mod,
installedVersion,
isDependency,
isSelected,
showInstalled,
onChange,
wantInfo,
onWantInfo
}: Props) {
const modsManager = useService(BsModsManagerService);
const pageState = useService(PageStateService);
@@ -48,14 +68,14 @@ export function ModItem({ className, mod, installedVersion, isDependency, isSele
return (
<li ref={clickRef} className={`${className} group`}>
<div className="h-full aspect-square flex items-center justify-center p-[7px] rounded-l-md bg-inherit ml-3 border-2 border-r-0 z-[1] group-hover:brightness-90" style={wantInfoStyle}>
<BsmCheckbox className="h-full aspect-square z-[1] relative bg-inherit" onChange={onChange} disabled={mod.required || isDependency} checked={isChecked} />
{onChange && <BsmCheckbox className="h-full aspect-square z-[1] relative bg-inherit" onChange={onChange} disabled={mod.required || isDependency} checked={isChecked} />}
</div>
<span className="bg-inherit py-2 pl-3 font-bold text-sm whitespace-nowrap border-t-2 border-b-2 blur-none group-hover:brightness-90" style={wantInfoStyle}>
{mod.name}
</span>
<span className={`min-w-0 text-center bg-inherit py-2 px-1 text-sm border-t-2 border-b-2 group-hover:brightness-90 ${installedVersion && isOutDated && "text-red-400 line-through"} ${installedVersion && !isOutDated && "text-green-400"}`} style={wantInfoStyle}>
{showInstalled !== false && <span className={`min-w-0 text-center bg-inherit py-2 px-1 text-sm border-t-2 border-b-2 group-hover:brightness-90 ${installedVersion && isOutDated && "text-red-400 line-through"} ${installedVersion && !isOutDated && "text-green-400"}`} style={wantInfoStyle}>
{installedVersion || "-"}
</span>
</span>}
<span className="min-w-0 text-center bg-inherit py-2 px-1 text-sm border-t-2 border-b-2 group-hover:brightness-90" style={wantInfoStyle}>
{mod.version}
</span>
@@ -9,10 +9,25 @@ import { Mod } from "shared/models/mods/mod.interface";
import { ModItem } from "./mod-item.component";
import { useService } from "renderer/hooks/use-service.hook";
type Props = { modsMap: Map<string, Mod[]>; installed: Map<string, Mod[]>; modsSelected: Mod[]; onModChange: (selected: boolean, mod: Mod) => void; moreInfoMod?: Mod; onWantInfos: (mod: Mod) => void };
type Props = {
modsMap: Map<string, Mod[]>;
installed?: Map<string, Mod[]>;
showInstalled?: boolean;
modsSelected?: Mod[];
onModChange?: (selected: boolean, mod: Mod) => void;
moreInfoMod?: Mod;
onWantInfos?: (mod: Mod) => void };
export function ModsGrid({
modsMap,
installed,
modsSelected,
showInstalled,
onModChange,
moreInfoMod,
onWantInfos
}: Props) {
export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreInfoMod, onWantInfos }: Props) {
const pageState = useService(PageStateService);
const modsManager = useService(BsModsManagerService);
@@ -32,7 +47,7 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn
};
const isDependency = (mod: Mod): boolean => {
return modsSelected.some(m => {
return !!modsSelected?.some(m => {
const deps = m.dependencies.map(dep =>
Array.from(modsMap.values())
.flat()
@@ -45,7 +60,7 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn
});
};
const isSelected = (mod: Mod): boolean => modsSelected.some(m => m.name === mod.name);
const isSelected = (mod: Mod): boolean => !!modsSelected?.some(m => m.name === mod.name);
const handleInput = (val: string) => setFilter(val.toLowerCase());
@@ -66,7 +81,7 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn
<BsmButton className="rounded-full h-6 w-6 p-[2px]" withBar={false} icon="search" onClick={handleToogleFilter} />
</span>
<span className="z-10 sticky top-0 flex items-center bg-inherit border-main-color-1 border-b-2 h-8 px-1 whitespace-nowrap">{filterEnabled ? <motion.input autoFocus className="bg-main-color-1 rounded-md h-6 px-2" initial={{ width: 0 }} animate={{ width: "250px" }} transition={{ ease: "easeInOut", duration: 0.15 }} onChange={e => handleInput(e.target.value)} /> : <span className="w-full text-center">{t("pages.version-viewer.mods.mods-grid.header-bar.name")}</span>}</span>
<span className="z-10 sticky flex items-center justify-center top-0 bg-inherit border-b-2 border-main-color-1 h-8 px-2 whitespace-nowrap">{t("pages.version-viewer.mods.mods-grid.header-bar.installed")}</span>
{showInstalled !== false && <span className="z-10 sticky flex items-center justify-center top-0 bg-inherit border-b-2 border-main-color-1 h-8 px-2 whitespace-nowrap">{t("pages.version-viewer.mods.mods-grid.header-bar.installed")}</span>}
<span className="z-10 sticky flex items-center justify-center top-0 bg-inherit border-b-2 border-main-color-1 h-8 px-2 whitespace-nowrap">{t("pages.version-viewer.mods.mods-grid.header-bar.latest")}</span>
<span className="z-10 sticky flex items-center justify-center top-0 bg-inherit border-b-2 border-main-color-1 h-8 whitespace-nowrap">{t("pages.version-viewer.mods.mods-grid.header-bar.description")}</span>
<span className="z-10 sticky top-0 bg-inherit border-b-2 border-main-color-1 h-8 flex justify-start items-center py-1 pl-[3px] min-w-[50px]">
@@ -86,3 +101,12 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn
)
);
}
export function modsArrayToCategoryMap(mods: Mod[]): Map<string, Mod[]> {
if (!mods) {
return new Map<string, Mod[]>();
}
const map = new Map<string, Mod[]>();
mods.forEach(mod => map.set(mod.category, [...(map.get(mod.category) ?? []), mod]));
return map;
};
@@ -2,7 +2,7 @@ import { ReactNode, useEffect, useLayoutEffect, useRef, useState } from "react";
import { BsModsManagerService } from "renderer/services/bs-mods-manager.service";
import { BSVersion } from "shared/bs-version.interface";
import { Mod } from "shared/models/mods/mod.interface";
import { ModsGrid } from "./mods-grid.component";
import { ModsGrid, modsArrayToCategoryMap } from "./mods-grid.component";
import { ConfigurationService } from "renderer/services/configuration.service";
import { DefaultConfigKey } from "renderer/config/default-configuration.config";
import { BsmButton } from "renderer/components/shared/bsm-button.component";
@@ -41,15 +41,6 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion;
const downloadRef = useRef(null);
const [downloadWith, setDownloadWidth] = useState(0);
const modsToCategoryMap = (mods: Mod[]): Map<string, Mod[]> => {
if (!mods) {
return new Map<string, Mod[]>();
}
const map = new Map<string, Mod[]>();
mods.forEach(mod => map.set(mod.category, [...(map.get(mod.category) ?? []), mod]));
return map;
};
const handleModChange = (selected: boolean, mod: Mod) => {
if (selected) {
return setModsSelected([...modsSelected, mod]);
@@ -110,9 +101,9 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion;
modsManager.getInstalledMods(version)
]).pipe(map(([available, installed]) => {
const defaultMods = configService.get<string[]>("default_mods" as DefaultConfigKey);
setModsAvailable(() => modsToCategoryMap(available));
setModsAvailable(() => modsArrayToCategoryMap(available));
setModsSelected(() => available.filter(m => m.required || defaultMods.some(d => m.name.toLowerCase() === d.toLowerCase()) || installed.some(i => m.name === i.name)));
setModsInstalled(() => modsToCategoryMap(installed));
setModsInstalled(() => modsArrayToCategoryMap(installed));
}));
};
@@ -11,6 +11,7 @@ import { NotificationType } from "../../shared/models/notification/notification.
import { OsDiagnosticService } from "./os-diagnostic.service";
import { ProgressBarService } from "./progress-bar.service";
import { NotificationService } from "./notification.service";
import { BeatModsService } from "./thrird-partys/beat-mods.service";
export class BsModsManagerService {
private static instance: BsModsManagerService;
@@ -22,6 +23,7 @@ export class BsModsManagerService {
private readonly modals: ModalService;
private readonly notifications: NotificationService;
private readonly os: OsDiagnosticService;
private readonly beatMods: BeatModsService;
public readonly isInstalling$: BehaviorSubject<boolean> = new BehaviorSubject(false);
public readonly isUninstalling$: BehaviorSubject<boolean> = new BehaviorSubject(false);
@@ -39,10 +41,11 @@ export class BsModsManagerService {
this.modals = ModalService.getInstance();
this.notifications = NotificationService.getInstance();
this.os = OsDiagnosticService.getInstance();
this.beatMods = BeatModsService.getInstance();
}
public getAvailableMods(version: BSVersion): Observable<Mod[]> {
return this.ipcService.sendV2("get-available-mods", version);
return this.beatMods.getVersionMods(version.BSVersion);
}
public getInstalledMods(version: BSVersion): Observable<Mod[]> {
@@ -136,4 +139,8 @@ export class BsModsManagerService {
this.progressBar.hide();
})
}
public getVersionAliases(): Observable<Record<string, string[]>> {
return this.ipcService.sendV2("get-version-aliases");
}
}
@@ -0,0 +1,32 @@
import { Observable } from "rxjs";
import { IpcService } from "../ipc.service";
import { BSVersionString } from "shared/bs-version.interface";
import { Mod } from "shared/models/mods";
export class BeatModsService {
private static instance: BeatModsService;
public static getInstance(): BeatModsService {
if (!BeatModsService.instance) {
BeatModsService.instance = new BeatModsService();
}
return BeatModsService.instance;
}
private readonly ipcService: IpcService;
private constructor() {
this.ipcService = IpcService.getInstance();
}
public getVersionAliases(): Observable<Record<BSVersionString, BSVersionString[]>> {
return this.ipcService.sendV2("get-version-aliases");
}
public getVersionMods(version: BSVersionString): Observable<Mod[]> {
return this.ipcService.sendV2("get-version-mods", version);
}
}
+3 -1
View File
@@ -1,7 +1,9 @@
import { BsStore } from "./models/bs-store.enum";
export type BSVersionString = `${number}.${number}.${string}`; // 1.1.0p1
export interface PartialBSVersion {
BSVersion: string,
BSVersion: BSVersionString,
name?: string
ino?: number,
}
+3 -2
View File
@@ -1,6 +1,6 @@
import { Progression } from "main/helpers/fs.helpers";
import { Observable } from "rxjs";
import { BSVersion } from "shared/bs-version.interface";
import { BSVersion, BSVersionString } from "shared/bs-version.interface";
import { BSLaunchEventData, LaunchOption } from "shared/models/bs-launch";
import { BsvMapDetail, SongDetails } from "shared/models/maps";
import { BsmLocalMap, BsmLocalMapsProgress, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface";
@@ -71,8 +71,9 @@ export interface IpcChannelMapping {
"delete-models": { request: BsmLocalModel[], response: Progression<BsmLocalModel[]> };
/* ** bs-mods-ipcs ** */
"get-available-mods": { request: BSVersion, response: Mod[] };
"get-version-mods": { request: BSVersionString, response: Mod[] };
"get-installed-mods": { request: BSVersion, response: Mod[] };
"get-version-aliases": { request: void, response: Record<BSVersionString, BSVersionString[]> }
"install-mods": { request: { mods: Mod[]; version: BSVersion }, response: InstallModsResult };
"uninstall-mods": { request: { mods: Mod[]; version: BSVersion }, response: UninstallModsResult };
"uninstall-all-mods": { request: BSVersion, response: UninstallModsResult };