mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
add linked unlinked maps indication
This commit is contained in:
@@ -15,4 +15,13 @@ ipcMain.on('get-version-maps', (event, request: IpcRequest<BSVersion>) => {
|
||||
utilsService.ipcSend(request.responceChannel, {success: false});
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
ipcMain.on("verion-have-maps-linked", async (event, request: IpcRequest<BSVersion>) => {
|
||||
const utils = UtilsService.getInstance();
|
||||
const maps = LocalMapsManagerService.getInstance();
|
||||
|
||||
console.log(request.args);
|
||||
utils.ipcSend<boolean>(request.responceChannel, {success: true, data: await maps.versionIsLinked(request.args)});
|
||||
|
||||
});
|
||||
@@ -6,6 +6,7 @@ import { BSLocalVersionService } from "../bs-local-version.service";
|
||||
import { InstallationLocationService } from "../installation-location.service";
|
||||
import { UtilsService } from "../utils.service";
|
||||
import crypto from "crypto";
|
||||
import { lstat, lstatSync, symlinkSync } from "fs";
|
||||
|
||||
export class LocalMapsManagerService {
|
||||
|
||||
@@ -29,15 +30,14 @@ export class LocalMapsManagerService {
|
||||
this.utils = UtilsService.getInstance();
|
||||
}
|
||||
|
||||
private async getMapsPath(version?: BSVersion): Promise<string>{
|
||||
if(version){ return path.join(await this.localVersion.getVersionPath(version), this.LEVELS_ROOT_FOLDER); }
|
||||
return this.installLocation.sharedMapsPath;
|
||||
private async getMapsFolderPath(version?: BSVersion): Promise<string>{
|
||||
if(version){ return path.join(await this.localVersion.getVersionPath(version), this.LEVELS_ROOT_FOLDER, this.CUSTOM_LEVELS_FOLDER); }
|
||||
return path.join(this.installLocation.sharedMapsPath, this.CUSTOM_LEVELS_FOLDER);
|
||||
}
|
||||
|
||||
private async computeMapHash(mapPath: string, rawInfoString: string): Promise<string>{
|
||||
const mapRawInfo = JSON.parse(rawInfoString);
|
||||
let content = rawInfoString;
|
||||
console.log("oui");
|
||||
for(const set of mapRawInfo._difficultyBeatmapSets){
|
||||
for(const diff of set._difficultyBeatmaps){
|
||||
const diffFilePath = path.join(mapPath, diff._beatmapFilename);
|
||||
@@ -69,13 +69,10 @@ export class LocalMapsManagerService {
|
||||
}
|
||||
|
||||
public async getMaps(version?: BSVersion): Promise<BsmLocalMap[]>{
|
||||
const levelsRoot = await this.getMapsPath(version);
|
||||
const levelsFolder = path.join(levelsRoot, this.CUSTOM_LEVELS_FOLDER);
|
||||
const levelsFolder = await this.getMapsFolderPath(version)
|
||||
|
||||
const levelsPath = (await this.utils.pathExist(levelsFolder)) ? this.utils.listDirsInDir(levelsFolder, true) : [];
|
||||
|
||||
|
||||
|
||||
const mapsInfo = await Promise.all(levelsPath.map(levelPath => this.loadMapInfoFromPath(levelPath)))
|
||||
|
||||
console.log(mapsInfo);
|
||||
@@ -87,4 +84,28 @@ export class LocalMapsManagerService {
|
||||
|
||||
}
|
||||
|
||||
public async versionIsLinked(version: BSVersion): Promise<boolean>{
|
||||
|
||||
const levelsPath = await this.getMapsFolderPath(version);
|
||||
|
||||
console.log(levelsPath, version);
|
||||
|
||||
const isPathExist = await this.utils.pathExist(levelsPath);
|
||||
|
||||
if(!isPathExist){ return false; }
|
||||
|
||||
return lstatSync(levelsPath).isSymbolicLink()
|
||||
}
|
||||
|
||||
public async linkVersionMaps(verion: BSVersion, includeVersionMaps: boolean): Promise<void>{
|
||||
//TODO
|
||||
//Can use fs.symlink to create symlink
|
||||
}
|
||||
|
||||
public async unlinkVersionMaps(version: BSVersion, keepLinkedMaps: boolean): Promise<void>{
|
||||
//TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+34
-6
@@ -1,10 +1,14 @@
|
||||
import { useState } from "react"
|
||||
import { DetailedHTMLProps, useEffect, useState } from "react"
|
||||
import { BSVersion } from "shared/bs-version.interface"
|
||||
import { TabNavBar } from "../shared/tab-nav-bar.component"
|
||||
import { LocalMapsListPanel } from "./local-maps-list-panel.component"
|
||||
import { BsmDropdownButton } from "../shared/bsm-dropdown-button.component"
|
||||
import { FilterPanel } from "./filter-panel.component"
|
||||
import { MapFilter, MapTag } from "shared/models/maps/beat-saver.model"
|
||||
import { BsmButton } from "../shared/bsm-button.component"
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook"
|
||||
import { MapsManagerService } from "renderer/services/maps-manager.service"
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
type Props = {
|
||||
oneBlock?: boolean,
|
||||
@@ -12,6 +16,8 @@ type Props = {
|
||||
}
|
||||
|
||||
export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {
|
||||
|
||||
const mapsService = MapsManagerService.getInstance();
|
||||
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
const [mapFilter, setMapFilter] = useState<MapFilter>({
|
||||
@@ -20,6 +26,14 @@ export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {
|
||||
});
|
||||
const [mapSearch, setMapSearch] = useState("");
|
||||
const [playlistSearch, setPlaylistSearch] = useState("");
|
||||
const [mapsLinked, setMapsLinked] = useState(false);
|
||||
const color = useThemeColor("first-color")
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
mapsService.versionHaveMapsLinked(version).then(setMapsLinked);
|
||||
}, [version])
|
||||
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
if(tabIndex === 0){
|
||||
@@ -28,6 +42,21 @@ export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {
|
||||
return setPlaylistSearch(() => value);
|
||||
}
|
||||
|
||||
const renderTab = (props: DetailedHTMLProps<React.HTMLAttributes<any>, any>, text: string): JSX.Element => {
|
||||
|
||||
const mainColor = mapsLinked ? color : "red";
|
||||
|
||||
return (
|
||||
<li className="relative text-center text-lg font-bold hover:backdrop-brightness-75 flex justify-center items-center content-center" onClick={props.onClick}>
|
||||
<span>{text}</span>
|
||||
<motion.div whileHover={{rotate: [0, 20, 0]}} transition={{duration: .35}} className="absolute block p-1 right-3 h-[calc(100%-5px)] aspect-square blur-0 hover:brightness-75">
|
||||
<span className="absolute top-0 left-0 h-full w-full rounded-full opacity-20" style={{backgroundColor: mainColor}}/>
|
||||
<BsmButton className="p-1 absolute top-0 left-0 h-full w-full !bg-transparent -rotate-45" iconClassName="" icon={mapsLinked ? "link" : "unlink"} withBar={false} style={{color: mainColor}}/>
|
||||
</motion.div>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!oneBlock && <TabNavBar className="mb-8 w-72" tabsText={["misc.maps", "Playlists"]} onTabChange={setTabIndex}/>}
|
||||
@@ -44,13 +73,12 @@ export function MapsPlaylistsPanel({version, oneBlock = false}: Props) {
|
||||
</BsmDropdownButton>
|
||||
</nav>
|
||||
<div className="w-full h-full flex flex-col bg-main-color-2 rounded-md shadow-black shadow-md overflow-hidden">
|
||||
{oneBlock && <TabNavBar className="!rounded-none shadow-sm" tabsText={["misc.maps", "Playlists"]} onTabChange={setTabIndex}/>}
|
||||
{oneBlock && <TabNavBar className="!rounded-none shadow-sm" tabsText={["misc.maps", "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 className="w-full h-full shrink-0 flex flex-col" version={version} filter={mapFilter} search={mapSearch}/>
|
||||
<div className="w-full h-full grow shrink-0">b</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>b</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
|
||||
@@ -45,7 +45,7 @@ export function BsmButton({className, style, imgClassName, iconClassName, icon,
|
||||
|
||||
const renderTypeColor = (() => {
|
||||
if(typeColor === "primary"){ return ""; }
|
||||
if(!typeColor){ return `bg-light-main-color-2 dark:bg-main-color-2 ${!withBar && "hover:bg-light-main-color-3 dark:hover:bg-main-color-3"}`; }
|
||||
if(!typeColor){ return `bg-light-main-color-2 dark:bg-main-color-2 ${!withBar && "hover:brightness-125"}`; }
|
||||
if(typeColor === "cancel"){ return "bg-gray-500"; }
|
||||
if(typeColor === "error"){ return "bg-red-500"; }
|
||||
if(typeColor === "success"){ return "bg-green-500"; }
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
import { useState } from "react";
|
||||
import { DetailedHTMLProps, Fragment, useState } from "react";
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
|
||||
export function TabNavBar(props: {tabsText: string[], onTabChange: (index: number) => void, className?: string}) {
|
||||
type Props = {
|
||||
tabsText: string[],
|
||||
onTabChange: (index: number) => void,
|
||||
className?: string,
|
||||
renderTab?: (props: DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, text: string) => JSX.Element
|
||||
}
|
||||
|
||||
export function TabNavBar(props: Props) {
|
||||
|
||||
const [currentTabIndex, setCurrentTabIndex] = useState(0);
|
||||
const t = useTranslation();
|
||||
const secondColor = useThemeColor("second-color");
|
||||
|
||||
const selectYear = (tab: string) => {
|
||||
const newIndex = props.tabsText.indexOf(tab);
|
||||
setCurrentTabIndex(newIndex);
|
||||
props.onTabChange(newIndex);
|
||||
const selectTab = (index: number) => {
|
||||
setCurrentTabIndex(index);
|
||||
props.onTabChange(index);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -21,9 +27,16 @@ export function TabNavBar(props: {tabsText: string[], onTabChange: (index: numbe
|
||||
<span className="absolute h-full block bg-current transition-transform duration-300 shadow-center shadow-current" style={{transform: `translate(${currentTabIndex * 100}%, 0)`, width: `calc(100% / ${props.tabsText.length})`}}/>
|
||||
</div>
|
||||
<ul className="grid" style={{gridTemplateColumns: `repeat(${props.tabsText.length}, minmax(0, 1fr))`}}>
|
||||
{ props.tabsText.map((y, index) =>
|
||||
<li className="px-4 h-full text-center text-gray-800 dark:text-gray-200 text-lg font-bold hover:backdrop-brightness-75" key={index} onClick={() => selectYear(y)}>{t(y)}</li>
|
||||
)}
|
||||
{props.tabsText.map((text, index) => (
|
||||
props.renderTab ? (
|
||||
<Fragment key={text}>
|
||||
{props.renderTab({onClick: () => selectTab(index)}, t(text))}
|
||||
</Fragment>
|
||||
) : (
|
||||
<li className="px-4 h-full text-center text-gray-800 dark:text-gray-200 text-lg font-bold hover:backdrop-brightness-75" key={text} onClick={() => selectTab(index)}>{t(text)}</li>
|
||||
)
|
||||
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
|
||||
@@ -39,11 +39,13 @@ import { NoArrowIcon } from "./icons/no-arrow-icon.component";
|
||||
import { OneSaberIcon } from "./icons/one-saber-icon.component";
|
||||
import { NinetyDregreeIcon } from "./icons/ninety-dregree-icon.component";
|
||||
import { ThreeSixtyDegreeIcon } from "./icons/three-sixty-degree-icon.component";
|
||||
import { LinkIcon } from "./icons/link-icon.component";
|
||||
import { UnlinkIcon } from "./icons/unlink-icon.component";
|
||||
|
||||
export type BsmIconType = BsvMapCharacteristic | (
|
||||
"settings"|"trash"|"favorite"|"folder"|"bsNote"|"check"|"three-dots"|"twitch"|"eye"|"play"|"checkCircleIcon"|
|
||||
"terminal"|"desktop"|"oculus"|"add"|"cross"|"task"|"github"|"close"|"thumbUpFill"|"timerFill"|"pause"|
|
||||
"copy"|"steam"|"edit"|"export"|"patreon"|"search"|"bsMapDifficulty"|
|
||||
"copy"|"steam"|"edit"|"export"|"patreon"|"search"|"bsMapDifficulty"|"link"|"unlink"|
|
||||
"fr-FR-flag"|"es-ES-flag"|"en-US-flag"|"en-EN-flag"
|
||||
);
|
||||
|
||||
@@ -89,6 +91,8 @@ export const BsmIcon = memo(({className, icon, style}: {className?: string, icon
|
||||
if(icon === "Lightshow"){ return <LightshowIcon className={className} style={style}/> }
|
||||
if(icon === "90Degree"){ return <NinetyDregreeIcon className={className} style={style}/> }
|
||||
if(icon === "360Degree"){ return <ThreeSixtyDegreeIcon className={className} style={style}/> }
|
||||
if(icon === "link"){ return <LinkIcon className={className} style={style}/> }
|
||||
if(icon === "unlink"){ return <UnlinkIcon className={className} style={style}/> }
|
||||
return <TrashIcon className={className} style={style}/>
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { CSSProperties } from "react";
|
||||
|
||||
export function LinkIcon(props: {className?: string, style?: CSSProperties}) {
|
||||
return (
|
||||
<svg className={props.className} style={props.style} stroke="currentColor" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" strokeWidth="48" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M200.66,352H144a96,96,0,0,1,0-192h55.41"/>
|
||||
<path d="M312.59,160H368a96,96,0,0,1,0,192H311.34"/>
|
||||
<line x1="169.07" x2="344.93" y1="256" y2="256"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { CSSProperties } from "react";
|
||||
|
||||
export function UnlinkIcon(props: {className?: string, style?: CSSProperties}) {
|
||||
return (
|
||||
<svg className={props.className} style={props.style} viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="48">
|
||||
<path d="M200.66,352H144a96,96,0,0,1,0-192h55.41"/>
|
||||
<path d="M312.59,160H368a96,96,0,0,1,0,192H311.34"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -22,7 +22,6 @@ export class MapsManagerService {
|
||||
}
|
||||
|
||||
public getMaps(version?: BSVersion): Observable<BsmLocalMap[]>{
|
||||
console.log("get maps")
|
||||
return new Observable(obs => {
|
||||
this.ipcService.send<BsmLocalMap[], BSVersion>("get-version-maps", {args: version}).then(res => {
|
||||
if(!res.success){ return obs.next(null);}
|
||||
@@ -38,6 +37,13 @@ export class MapsManagerService {
|
||||
});
|
||||
}
|
||||
|
||||
public versionHaveMapsLinked(version: BSVersion): Promise<boolean>{
|
||||
return this.ipcService.send<boolean, BSVersion>("verion-have-maps-linked", {args: version}).then(res => {
|
||||
if(!res.success){ throw "error"; }
|
||||
return res.data;
|
||||
})
|
||||
}
|
||||
|
||||
public downloadMap(map: any, version?: BSVersion){
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user