mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
Merge branch 'master' into fix/running-processes
This commit is contained in:
Generated
+555
-543
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -179,7 +179,7 @@
|
||||
"css-minimizer-webpack-plugin": "^4.1.0",
|
||||
"detect-port": "^1.3.0",
|
||||
"electron": "^24.3.1",
|
||||
"electron-builder": "^23.6.0",
|
||||
"electron-builder": "^24.4.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-notarize": "^1.2.1",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
@@ -238,7 +238,7 @@
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-log": "^4.4.8",
|
||||
"electron-store": "^8.1.0",
|
||||
"electron-updater": "^6.0.3",
|
||||
"electron-updater": "^6.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"framer-motion": "^10.12.16",
|
||||
"fs-extra": "^11.1.1",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ipcMain } from 'electron';
|
||||
import { ipcMain, shell } from 'electron';
|
||||
import { UtilsService } from '../services/utils.service';
|
||||
import { BSVersionLibService } from '../services/bs-version-lib.service'
|
||||
import { BSVersion } from 'shared/bs-version.interface';
|
||||
@@ -38,7 +38,9 @@ ipcMain.on('bs-version.installed-versions', async (event, req: IpcRequest<void>)
|
||||
ipcMain.on("bs-version.open-folder", async (event, req: IpcRequest<BSVersion>) => {
|
||||
const localVersionService = BSLocalVersionService.getInstance();
|
||||
const versionFolder = await localVersionService.getVersionPath(req.args);
|
||||
(await pathExist(versionFolder)) && exec(`start "" "${versionFolder}"`);
|
||||
if (!(await pathExist(versionFolder)))
|
||||
return;
|
||||
shell.openPath(versionFolder);
|
||||
});
|
||||
|
||||
ipcMain.on("bs-version.edit", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => {
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ const installExtensions = async () => {
|
||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
||||
const extensions = ['REACT_DEVELOPER_TOOLS'];
|
||||
|
||||
return installer.default(extensions.map((name) => installer[name]), forceDownload).catch(console.log);
|
||||
return installer.default(extensions.map((name) => installer[name]), forceDownload).catch(console.error);
|
||||
};
|
||||
|
||||
const createWindow = async (window: AppWindow = "launcher.html") => {
|
||||
|
||||
@@ -66,9 +66,12 @@ export class BSInstallerService{
|
||||
return new Promise(resolve => {
|
||||
if(this.downloadProcess?.killed && !this.downloadProcess?.pid){ return resolve(false); }
|
||||
|
||||
this.downloadProcess.once('exit', () => resolve(true));
|
||||
|
||||
ctrlc(this.downloadProcess.pid);
|
||||
this.downloadProcess?.once('exit', () => resolve(true));
|
||||
if (process.platform === 'win32') {
|
||||
ctrlc(this.downloadProcess.pid);
|
||||
} else {
|
||||
this.downloadProcess.kill();
|
||||
}
|
||||
setTimeout(() => resolve(false), 3000);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { UtilsService } from "./utils.service";
|
||||
import regedit from 'regedit'
|
||||
import path from "path";
|
||||
import { path, join } from "path";
|
||||
import { parse } from "@node-steam/vdf";
|
||||
import { readFile } from "fs/promises";
|
||||
import { spawn } from "child_process";
|
||||
import { pathExist } from "../helpers/fs.helpers";
|
||||
import log from "electron-log";
|
||||
import psList from 'ps-list';
|
||||
import { app } from "electron";
|
||||
|
||||
export class SteamService{
|
||||
|
||||
@@ -44,20 +45,28 @@ export class SteamService{
|
||||
|
||||
public async getSteamPath(): Promise<string>{
|
||||
|
||||
if(!!this.steamPath){ return this.steamPath; }
|
||||
if(this.steamPath){ return this.steamPath; }
|
||||
|
||||
const [win32Res, win64Res] = await Promise.all([
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\Valve\\Steam']),
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\WOW6432Node\\Valve\\Steam'])
|
||||
]);
|
||||
switch (process.platform) {
|
||||
case "linux":
|
||||
this.steamPath = path.join(app.getPath('home'), '.steam', "steam");
|
||||
return this.steamPath;
|
||||
case "win32":
|
||||
const [win32Res, win64Res] = await Promise.all([
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\Valve\\Steam']),
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\WOW6432Node\\Valve\\Steam'])
|
||||
]);
|
||||
|
||||
const [win32, win64] = [win32Res["HKLM\\SOFTWARE\\Valve\\Steam"], win64Res["HKLM\\SOFTWARE\\WOW6432Node\\Valve\\Steam"]];
|
||||
|
||||
let res = '';
|
||||
if(win64.exists && win64?.values?.InstallPath?.value){ res = win64.values.InstallPath.value as string; }
|
||||
else if(win32.exists && win32?.values?.InstallPath?.value){ res = win32.values.InstallPath.value as string; }
|
||||
this.steamPath = res;
|
||||
return this.steamPath;
|
||||
const [win32, win64] = [win32Res["HKLM\\SOFTWARE\\Valve\\Steam"], win64Res["HKLM\\SOFTWARE\\WOW6432Node\\Valve\\Steam"]];
|
||||
|
||||
let res = '';
|
||||
if(win64.exists && win64?.values?.InstallPath?.value){ res = win64.values.InstallPath.value as string; }
|
||||
else if(win32.exists && win32?.values?.InstallPath?.value){ res = win32.values.InstallPath.value as string; }
|
||||
this.steamPath = res;
|
||||
return res;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async getGameFolder(gameId: string, gameFolder?: string): Promise<string>{
|
||||
@@ -88,7 +97,7 @@ export class SteamService{
|
||||
const process = spawn("start", ["steam://open/games"], {shell: true});
|
||||
|
||||
process.on("error", log.error);
|
||||
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
// Every 3 seconds check if steam is running
|
||||
const interval = setInterval(async () => {
|
||||
|
||||
+18
-10
@@ -4,7 +4,6 @@ import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useSta
|
||||
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"
|
||||
import { Subscription } from "rxjs"
|
||||
import { MapFilter } from "shared/models/maps/beat-saver.model"
|
||||
import { useInView } from "framer-motion"
|
||||
import { MapsDownloaderService } from "renderer/services/maps-downloader.service"
|
||||
import { VariableSizeList } from "react-window"
|
||||
import { MapsRow } from "./maps-row.component"
|
||||
@@ -18,16 +17,18 @@ import BeatConflict from "../../../../assets/images/apngs/beat-conflict.png"
|
||||
import { BsmImage } from "../shared/bsm-image.component"
|
||||
import { BsmButton } from "../shared/bsm-button.component"
|
||||
import TextProgressBar from "../progress-bar/text-progress-bar.component"
|
||||
import { useChangeOnce } from "renderer/hooks/use-change-once.hook"
|
||||
|
||||
type Props = {
|
||||
version: BSVersion,
|
||||
className?: string,
|
||||
filter?: MapFilter
|
||||
search?: string,
|
||||
linked?: boolean
|
||||
linked?: boolean,
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
export const LocalMapsListPanel = forwardRef(({version, className, filter, search, linked} : Props, forwardRef) => {
|
||||
export const LocalMapsListPanel = forwardRef(({version, className, filter, search, linked, isActive} : Props, forwardRef) => {
|
||||
|
||||
const mapsManager = MapsManagerService.getInstance();
|
||||
const mapsDownloader = MapsDownloaderService.getInstance();
|
||||
@@ -35,13 +36,13 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
const os = OsDiagnosticService.getInstance();
|
||||
|
||||
const t = useTranslation();
|
||||
const ref = useRef(null)
|
||||
const isVisible = useInView(ref, {once: true, amount: .5});
|
||||
const ref = useRef(null);
|
||||
const [maps, setMaps] = useState<BsmLocalMap[]>(null);
|
||||
const [subs] = useState<Subscription[]>([]);
|
||||
const [selectedMaps$] = useState(new BehaviorSubject<BsmLocalMap[]>([]));
|
||||
const [itemPerRow, setItemPerRow] = useState(2);
|
||||
const [listHeight, setListHeight] = useState(0);
|
||||
const isActiveOnce = useChangeOnce(isActive, true);
|
||||
|
||||
const [loadPercent$] = useState(new BehaviorSubject(0));
|
||||
|
||||
@@ -64,7 +65,7 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if(isVisible){
|
||||
if(isActiveOnce){
|
||||
loadMaps();
|
||||
mapsDownloader.addOnMapDownloadedListener((map, targerVersion) => {
|
||||
if(targerVersion !== version){ return; }
|
||||
@@ -78,11 +79,11 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
subs.forEach(s => s.unsubscribe());
|
||||
mapsDownloader.removeOnMapDownloadedListener(loadMaps);
|
||||
}
|
||||
}, [isVisible, version, linked]);
|
||||
}, [isActiveOnce, version, linked]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if(!isVisible){ return () => {}; }
|
||||
if(!isActiveOnce){ return; }
|
||||
|
||||
const updateItemPerRow = (listWidth: number) => {
|
||||
const newPerRow = Math.min(Math.floor(listWidth / 400), 3);
|
||||
@@ -106,7 +107,7 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
sub.unsubscribe();
|
||||
}
|
||||
|
||||
}, [isVisible, itemPerRow])
|
||||
}, [isActiveOnce, itemPerRow])
|
||||
|
||||
const loadMaps = () => {
|
||||
|
||||
@@ -136,10 +137,17 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
const removeMapsFromList = (mapsToRemove: BsmLocalMap[]) => {
|
||||
const filtredMaps = maps.filter(map => !mapsToRemove.some(toDeleteMaps => map.hash === toDeleteMaps.hash));
|
||||
setMaps(() => filtredMaps);
|
||||
|
||||
const filtredSelectedMaps = selectedMaps$.value.filter(map => !mapsToRemove.some(toDeleteMaps => map.hash === toDeleteMaps.hash));
|
||||
selectedMaps$.next(filtredSelectedMaps);
|
||||
};
|
||||
|
||||
const handleDelete = useCallback((map: BsmLocalMap) => {
|
||||
mapsManager.deleteMaps([map], version).then(res => res && removeMapsFromList([map]));
|
||||
mapsManager.deleteMaps([map], version).then(res => {
|
||||
if(!res){ return; }
|
||||
removeMapsFromList([map]);
|
||||
|
||||
});
|
||||
}, [version, maps]);
|
||||
|
||||
const onMapSelected = useCallback((map: BsmLocalMap) => {
|
||||
|
||||
+5
-4
@@ -21,10 +21,11 @@ import { VersionFolderLinkerService, VersionLinkerActionListener } from "rendere
|
||||
|
||||
|
||||
type Props = {
|
||||
version?: BSVersion
|
||||
version?: BSVersion,
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
export function MapsPlaylistsPanel({version}: Props) {
|
||||
export function MapsPlaylistsPanel({version, isActive}: Props) {
|
||||
|
||||
const mapsService = MapsManagerService.getInstance();
|
||||
const mapsDownloader = MapsDownloaderService.getInstance();
|
||||
@@ -63,7 +64,7 @@ export function MapsPlaylistsPanel({version}: Props) {
|
||||
linker.removeVersionFolderUnlinkedListener(onMapsLinked);
|
||||
}
|
||||
|
||||
}, [version]);
|
||||
}, [version, isActive]);
|
||||
|
||||
const loadMapIsLinked = () => {
|
||||
mapsService.versionHaveMapsLinked(version).then(setMapsLinked);
|
||||
@@ -160,7 +161,7 @@ export function MapsPlaylistsPanel({version}: Props) {
|
||||
<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">
|
||||
<TabNavBar className="!rounded-none shadow-sm" tabIndex={tabIndex} tabsText={["misc.maps", "misc.playlists"]} onTabChange={setTabIndex} renderTab={renderTab}/>
|
||||
<div className="w-full grow min-h-0 flex flex-row items-center transition-transform duration-300" style={{transform: `translate(${-(tabIndex * 100)}%, 0)`}}>
|
||||
<LocalMapsListPanel ref={mapsRef} className="w-full h-full shrink-0 flex flex-col" version={version} filter={mapFilter} search={mapSearch} linked={mapsLinked}/>
|
||||
<LocalMapsListPanel isActive={isActive && tabIndex === 0} ref={mapsRef} className="w-full h-full shrink-0 flex flex-col" version={version} filter={mapFilter} search={mapSearch} linked={mapsLinked}/>
|
||||
<div className="w-full h-full shrink-0 flex flex-col justify-center items-center content-center gap-2 overflow-hidden text-gray-800 dark:text-gray-200">
|
||||
<BsmImage className="rounded-md" image={wipGif}/>
|
||||
<span>Coming soon</span>
|
||||
|
||||
@@ -41,7 +41,6 @@ export function BsmButton({className, style, imgClassName, iconClassName, icon,
|
||||
|
||||
const textColor = (() => {
|
||||
if(primaryColor){
|
||||
console.log(getCorrectTextColor(primaryColor), text);
|
||||
return getCorrectTextColor(primaryColor);
|
||||
}
|
||||
return typeColor ? "white" : undefined;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import equal from "fast-deep-equal";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export function useChangeOnce<T = unknown>(initialValue: T, onlyFirstIfTruthy?: boolean): T {
|
||||
const [trackedValue, setTrackedValue] = useState<T>(initialValue);
|
||||
const didChangeOnceRef = useRef<boolean>(onlyFirstIfTruthy ? !!initialValue : false);
|
||||
|
||||
useEffect(() => {
|
||||
if(didChangeOnceRef.current || equal(initialValue, trackedValue)){ return; }
|
||||
|
||||
setTrackedValue(() => initialValue);
|
||||
didChangeOnceRef.current = true;
|
||||
|
||||
}, [initialValue]);
|
||||
|
||||
return trackedValue;
|
||||
}
|
||||
@@ -3,12 +3,9 @@ import { MapsPlaylistsPanel } from "renderer/components/maps-mangement-component
|
||||
import { ModelsPanel } from "renderer/components/models-management/models-panel.component";
|
||||
import { TabNavBar } from "renderer/components/shared/tab-nav-bar.component";
|
||||
import { Slideshow } from "renderer/components/slideshow/slideshow.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
|
||||
export function SharedContentsPage() {
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
|
||||
return (
|
||||
@@ -17,7 +14,7 @@ export function SharedContentsPage() {
|
||||
<TabNavBar className='my-4' tabIndex={tabIndex} tabsText={["misc.maps", "misc.models"]} onTabChange={setTabIndex}/>
|
||||
<div className='w-full min-h-0 grow flex transition-transform duration-300' style={{transform: `translate(${-(tabIndex * 100)}%, 0)`}}>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<MapsPlaylistsPanel/>
|
||||
<MapsPlaylistsPanel isActive={tabIndex === 0}/>
|
||||
</div>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<ModelsPanel isActive={tabIndex === 1}/>
|
||||
|
||||
@@ -80,7 +80,7 @@ export function VersionViewer() {
|
||||
<div className='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}/>
|
||||
<MapsPlaylistsPanel version={state} isActive={currentTabIndex === 1}/>
|
||||
</div>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<ModelsPanel version={state} isActive={currentTabIndex === 2} goToMods={() => setCurrentTabIndex(() => 3)}/>
|
||||
|
||||
@@ -86,7 +86,7 @@ export class MapsManagerService {
|
||||
|
||||
public async deleteMaps(maps: BsmLocalMap[], version?: BSVersion): Promise<boolean>{
|
||||
|
||||
const versionLinked = await this.versionHaveMapsLinked(version);
|
||||
const versionLinked = !version || await this.versionHaveMapsLinked(version);
|
||||
|
||||
const askModal = maps.length > 1 || !this.config.get<boolean>(MapsManagerService.REMEMBER_CHOICE_DELETE_MAP_KEY);
|
||||
|
||||
|
||||
+8
-1
@@ -1,5 +1,12 @@
|
||||
const colors = require('tailwindcss/colors');
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
|
||||
// Suppress deprecation warnings during build
|
||||
delete colors.lightBlue;
|
||||
delete colors.warmGray;
|
||||
delete colors.trueGray;
|
||||
delete colors.coolGray;
|
||||
delete colors.blueGray;
|
||||
|
||||
module.exports = {
|
||||
darkMode: 'class',
|
||||
content: ['./src/renderer/**/*.{js,jsx,ts,tsx,ejs}'],
|
||||
|
||||
Reference in New Issue
Block a user