mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature-107] moving files around and create Playlist panel component
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { LocalPlaylistsManagerService } from "../services/additional-content/local-playlists-manager.service";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
import { IpcService } from "../services/ipc.service";
|
||||
import { of, throwError } from "rxjs";
|
||||
|
||||
const ipc = IpcService.getInstance();
|
||||
|
||||
@@ -11,38 +9,32 @@ ipc.on<string>("one-click-install-playlist", (req, reply) => {
|
||||
reply(mapsManager.oneClickInstallPlaylist(req.args));
|
||||
});
|
||||
|
||||
ipcMain.on("register-playlists-deep-link", async (event, request: IpcRequest<void>) => {
|
||||
ipc.on("register-playlists-deep-link", (_, reply) => {
|
||||
const maps = LocalPlaylistsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
|
||||
try {
|
||||
const res = maps.enableDeepLinks();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
reply(of(maps.enableDeepLinks()));
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
reply(throwError(() => e));
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on("unregister-playlists-deep-link", async (event, request: IpcRequest<void>) => {
|
||||
ipc.on("unregister-playlists-deep-link", (_, reply) => {
|
||||
const maps = LocalPlaylistsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
|
||||
try {
|
||||
const res = maps.disableDeepLinks();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
reply(of(maps.disableDeepLinks()));
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
reply(throwError(() => e));
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on("is-playlists-deep-links-enabled", async (event, request: IpcRequest<void>) => {
|
||||
ipc.on("is-playlists-deep-links-enabled", (_, reply) => {
|
||||
const maps = LocalPlaylistsManagerService.getInstance();
|
||||
const utils = UtilsService.getInstance();
|
||||
|
||||
try {
|
||||
const res = maps.isDeepLinksEnabled();
|
||||
utils.ipcSend(request.responceChannel, { success: true, data: res });
|
||||
reply(of(maps.isDeepLinksEnabled()));
|
||||
} catch (e) {
|
||||
utils.ipcSend(request.responceChannel, { success: false });
|
||||
reply(throwError(() => e));
|
||||
}
|
||||
});
|
||||
|
||||
+30
-44
@@ -1,15 +1,13 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { LocalMapsListPanel } from "./local-maps-list-panel.component";
|
||||
import { LocalMapsListPanel } from "./maps/local-maps-list-panel.component";
|
||||
import { BsmDropdownButton, DropDownItem } from "../shared/bsm-dropdown-button.component";
|
||||
import { FilterPanel } from "./filter-panel.component";
|
||||
import { FilterPanel } from "./maps/filter-panel.component";
|
||||
import { MapFilter } from "shared/models/maps/beat-saver.model";
|
||||
import { MapsManagerService } from "renderer/services/maps-manager.service";
|
||||
import { MapsDownloaderService } from "renderer/services/maps-downloader.service";
|
||||
import { BsmImage } from "../shared/bsm-image.component";
|
||||
import wipGif from "../../../../assets/images/gifs/wip.gif";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { FolderLinkState, VersionFolderLinkerService, VersionLinkerActionListener } from "renderer/services/version-folder-linker.service";
|
||||
import { FolderLinkState } from "renderer/services/version-folder-linker.service";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { BsContentTabPanel } from "../shared/bs-content-tab-panel/bs-content-tab-panel.component";
|
||||
import { BsmButton } from "../shared/bsm-button.component";
|
||||
@@ -17,6 +15,8 @@ import { MapIcon } from "../svgs/icons/map-icon.component";
|
||||
import { PlaylistIcon } from "../svgs/icons/playlist-icon.component";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { of } from "rxjs";
|
||||
import { LocalPlaylistsListPanel } from "./playlists/local-playlists-list-panel.component";
|
||||
import { PlaylistsManagerService } from "renderer/services/playlists-manager.service";
|
||||
|
||||
type Props = {
|
||||
version?: BSVersion;
|
||||
@@ -24,46 +24,28 @@ type Props = {
|
||||
};
|
||||
|
||||
export function MapsPlaylistsPanel({ version, isActive }: Props) {
|
||||
|
||||
|
||||
const mapsService = useService(MapsManagerService);
|
||||
const mapsDownloader = useService(MapsDownloaderService);
|
||||
const linker = useService(VersionFolderLinkerService);
|
||||
const playlistsService = useService(PlaylistsManagerService);
|
||||
|
||||
const t = useTranslation();
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
|
||||
const mapsRef = useRef<any>();
|
||||
const [mapFilter, setMapFilter] = useState<MapFilter>({});
|
||||
const [mapSearch, setMapSearch] = useState("");
|
||||
const mapsLinkedState = useObservable(() => {
|
||||
if(!version) return of(FolderLinkState.Unlinked);
|
||||
return mapsService.$mapsFolderLinkState(version);
|
||||
}, FolderLinkState.Unlinked, [version]);
|
||||
|
||||
const [playlistSearch, setPlaylistSearch] = useState("");
|
||||
const [mapsLinked, setMapsLinked] = useState(false);
|
||||
const mapsLinkedState = useObservable(() => version ? mapsService.$mapsFolderLinkState(version) : of(null), FolderLinkState.Unlinked, [version]);
|
||||
const t = useTranslation();
|
||||
const mapsRef = useRef<any>();
|
||||
const playlistLinkedState = useObservable(() => {
|
||||
if(!version) return of(FolderLinkState.Unlinked);
|
||||
return playlistsService.$playlistsFolderLinkState(version);
|
||||
}, FolderLinkState.Unlinked, [version]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!version) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadMapIsLinked();
|
||||
|
||||
const onMapsLinked: VersionLinkerActionListener = action => {
|
||||
if (!action.relativeFolder.includes(MapsManagerService.RELATIVE_MAPS_FOLDER)) {
|
||||
return;
|
||||
}
|
||||
loadMapIsLinked();
|
||||
};
|
||||
|
||||
linker.onVersionFolderLinked(onMapsLinked);
|
||||
linker.onVersionFolderUnlinked(onMapsLinked);
|
||||
|
||||
return () => {
|
||||
linker.removeVersionFolderLinkedListener(onMapsLinked);
|
||||
linker.removeVersionFolderUnlinkedListener(onMapsLinked);
|
||||
};
|
||||
}, [version, isActive]);
|
||||
|
||||
const loadMapIsLinked = () => {
|
||||
mapsService.versionHaveMapsLinked(version).then(setMapsLinked);
|
||||
};
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
if (tabIndex === 0) {
|
||||
@@ -77,9 +59,12 @@ export function MapsPlaylistsPanel({ version, isActive }: Props) {
|
||||
};
|
||||
|
||||
const handleMapsLinkClick = () => {
|
||||
if (!mapsLinked) {
|
||||
if(mapsLinkedState === FolderLinkState.Pending || mapsLinkedState === FolderLinkState.Processing){ return Promise.resolve(false); }
|
||||
|
||||
if (mapsLinkedState === FolderLinkState.Unlinked) {
|
||||
return mapsService.linkVersion(version);
|
||||
}
|
||||
|
||||
return mapsService.unlinkVersion(version);
|
||||
};
|
||||
|
||||
@@ -130,15 +115,16 @@ export function MapsPlaylistsPanel({ version, isActive }: Props) {
|
||||
text: "misc.playlists",
|
||||
icon: PlaylistIcon,
|
||||
onClick: () => setTabIndex(1),
|
||||
linkProps: version ? {
|
||||
state: playlistLinkedState,
|
||||
onClick: () => Promise.resolve(false),
|
||||
} : null,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<>
|
||||
<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>
|
||||
</div>
|
||||
<LocalMapsListPanel isActive={isActive && tabIndex === 0} ref={mapsRef} className="w-full h-full shrink-0" version={version} filter={mapFilter} search={mapSearch} linkedState={mapsLinkedState} />
|
||||
<LocalPlaylistsListPanel isActive={isActive && tabIndex === 1} version={version} linkedState={playlistLinkedState}/>
|
||||
</>
|
||||
</BsContentTabPanel>
|
||||
</div>
|
||||
+5
-5
@@ -3,18 +3,18 @@ import { motion } from "framer-motion";
|
||||
import { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import { MAP_TYPES } from "renderer/partials/maps/map-tags/map-types";
|
||||
import { MAP_STYLES } from "renderer/partials/maps/map-tags/map-styles";
|
||||
import { BsmCheckbox } from "../shared/bsm-checkbox.component";
|
||||
import { minToS } from "../../../shared/helpers/time.helpers";
|
||||
import { BsmCheckbox } from "../../shared/bsm-checkbox.component";
|
||||
import { minToS } from "../../../../shared/helpers/time.helpers";
|
||||
import dateFormat from "dateformat";
|
||||
import { BsmRange } from "../shared/bsm-range.component";
|
||||
import { BsmRange } from "../../shared/bsm-range.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { MAP_SPECIFICITIES } from "renderer/partials/maps/map-general/map-specificity";
|
||||
import { MAP_REQUIREMENTS } from "renderer/partials/maps/map-requirements/map-requirements";
|
||||
import { MAP_DIFFICULTIES_COLORS } from "renderer/partials/maps/map-difficulties/map-difficulties-colors";
|
||||
import { BsmButton } from "../shared/bsm-button.component";
|
||||
import { BsmButton } from "../../shared/bsm-button.component";
|
||||
import equal from "fast-deep-equal/es6";
|
||||
import clone from "rfdc";
|
||||
import { GlowEffect } from "../shared/glow-effect.component";
|
||||
import { GlowEffect } from "../../shared/glow-effect.component";
|
||||
|
||||
export type Props = {
|
||||
className?: string;
|
||||
+17
-9
@@ -11,24 +11,26 @@ import { debounceTime, last, mergeMap, tap } from "rxjs/operators";
|
||||
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service";
|
||||
import { OsDiagnosticService } from "renderer/services/os-diagnostic.service";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import BeatWaitingImg from "../../../../assets/images/apngs/beat-waiting.png";
|
||||
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";
|
||||
import BeatWaitingImg from "../../../../../assets/images/apngs/beat-waiting.png";
|
||||
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 { useChangeUntilEqual } from "renderer/hooks/use-change-until-equal.hook";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import { FolderLinkState } from "renderer/services/version-folder-linker.service";
|
||||
import { useOnUpdate } from "renderer/hooks/use-on-update.hook";
|
||||
|
||||
type Props = {
|
||||
version: BSVersion;
|
||||
className?: string;
|
||||
filter?: MapFilter;
|
||||
search?: string;
|
||||
linked?: boolean;
|
||||
linkedState?: FolderLinkState;
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
export const LocalMapsListPanel = forwardRef(({ version, className, filter, search, linked, isActive }: Props, forwardRef) => {
|
||||
export const LocalMapsListPanel = forwardRef(({ version, className, filter, search, linkedState, isActive }: Props, forwardRef) => {
|
||||
const mapsManager = useService(MapsManagerService);
|
||||
const mapsDownloader = useService(MapsDownloaderService);
|
||||
const bsaver = useService(BeatSaverService);
|
||||
@@ -41,7 +43,8 @@ export const LocalMapsListPanel = forwardRef(({ version, className, filter, sear
|
||||
const [selectedMaps$] = useState(new BehaviorSubject<BsmLocalMap[]>([]));
|
||||
const [itemPerRow, setItemPerRow] = useState(2);
|
||||
const [listHeight, setListHeight] = useState(0);
|
||||
const isActiveOnce = useChangeOnce(isActive, true);
|
||||
const isActiveOnce = useChangeUntilEqual(isActive, { untilEqual: true, emitOnEqual: true });
|
||||
const [linked, setLinked] = useState(false);
|
||||
|
||||
const [loadPercent$] = useState(new BehaviorSubject(0));
|
||||
|
||||
@@ -68,6 +71,11 @@ export const LocalMapsListPanel = forwardRef(({ version, className, filter, sear
|
||||
[selectedMaps$.value, maps, version]
|
||||
);
|
||||
|
||||
useOnUpdate(() => {
|
||||
if(linkedState === FolderLinkState.Pending || linkedState === FolderLinkState.Processing) return () => {};
|
||||
setLinked(linkedState === FolderLinkState.Linked);
|
||||
}, [linkedState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isActiveOnce) {
|
||||
loadMaps();
|
||||
+7
-7
@@ -1,9 +1,9 @@
|
||||
import { BsmImage } from "../shared/bsm-image.component";
|
||||
import { BsmImage } from "../../shared/bsm-image.component";
|
||||
import { BsvMapCharacteristic, BsvMapDifficultyType } from "shared/models/maps/beat-saver.model";
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { BsmLink } from "../shared/bsm-link.component";
|
||||
import { BsmIcon } from "../svgs/bsm-icon.component";
|
||||
import { BsmButton } from "../shared/bsm-button.component";
|
||||
import { BsmLink } from "../../shared/bsm-link.component";
|
||||
import { BsmIcon } from "../../svgs/bsm-icon.component";
|
||||
import { BsmButton } from "../../shared/bsm-button.component";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useState, Fragment, memo, useRef } from "react";
|
||||
import { LinkOpenerService } from "renderer/services/link-opener.service";
|
||||
@@ -12,13 +12,13 @@ import { AudioPlayerService } from "renderer/services/audio-player.service";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { map } from "rxjs/operators";
|
||||
import equal from "fast-deep-equal/es6";
|
||||
import { BsmBasicSpinner } from "../shared/bsm-basic-spinner/bsm-basic-spinner.component";
|
||||
import defaultImage from "../../../../assets/images/default-version-img.jpg";
|
||||
import { BsmBasicSpinner } from "../../shared/bsm-basic-spinner/bsm-basic-spinner.component";
|
||||
import defaultImage from "../../../../../assets/images/default-version-img.jpg";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { MAP_DIFFICULTIES } from "renderer/partials/maps/map-difficulties/map-difficulties";
|
||||
import { MAP_DIFFICULTIES_COLORS } from "renderer/partials/maps/map-difficulties/map-difficulties-colors";
|
||||
import useDoubleClick from "use-double-click";
|
||||
import { GlowEffect } from "../shared/glow-effect.component";
|
||||
import { GlowEffect } from "../../shared/glow-effect.component";
|
||||
import { useDelayedState } from "renderer/hooks/use-delayed-state.hook";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
import Tippy from "@tippyjs/react";
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { FolderLinkState } from "renderer/services/version-folder-linker.service";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
|
||||
type Props = {
|
||||
version: BSVersion;
|
||||
className?: string;
|
||||
linkedState?: FolderLinkState;
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
export function LocalPlaylistsListPanel({ version, className, isActive, linkedState }: Props) {
|
||||
return (
|
||||
<div>local-playlists-list-panel.component</div>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { FilterPanel } from "renderer/components/maps-mangement-components/filter-panel.component";
|
||||
import { MapItem, ParsedMapDiff } from "renderer/components/maps-mangement-components/map-item.component";
|
||||
import { FilterPanel } from "renderer/components/maps-playlists-panel/maps/filter-panel.component";
|
||||
import { MapItem, ParsedMapDiff } from "renderer/components/maps-playlists-panel/maps/map-item.component";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { BsmDropdownButton } from "renderer/components/shared/bsm-dropdown-button.component";
|
||||
import { BsmSelect, BsmSelectOption } from "renderer/components/shared/bsm-select.component";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { LinkButton } from "renderer/components/maps-mangement-components/link-button.component";
|
||||
import { LinkButton } from "renderer/components/shared/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 { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
@@ -137,7 +137,7 @@ const FolderItem = ({ version, relativeFolder, onDelete }: FolderProps) => {
|
||||
</span>
|
||||
<div className="flex flex-row gap-1.5">
|
||||
<Tippy placement="left" content={t(`modals.shared-folders.buttons.${state === FolderLinkState.Linked ? "unlink-folder" : "link-folder"}`)} arrow={false}>
|
||||
<LinkButton
|
||||
<LinkButton
|
||||
className="p-0.5 h-7 shrink-0 aspect-square blur-0 cursor-pointer hover:brightness-75"
|
||||
state={state}
|
||||
onClick={onClickLink}
|
||||
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
import { LinkBtnProps, LinkButton } from "renderer/components/maps-mangement-components/link-button.component";
|
||||
import { LinkBtnProps, LinkButton } from "renderer/components/shared/link-button.component";
|
||||
import { SvgIcon } from "renderer/components/svgs/svg-icon.type";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
|
||||
@@ -32,13 +32,13 @@ export const BsContentTabItem: BsContentTabItemComponent = ({ text, icon: Icon,
|
||||
{linkProps && (
|
||||
<div className="flex items-center absolute top-1.5 left-1.5">
|
||||
<LinkButton
|
||||
state={linkProps.state}
|
||||
className={linkProps.className ?? "block w-6 h-6 aspect-square blur-0 cursor-pointer hover:brightness-75"}
|
||||
title={linkProps.title}
|
||||
onClick={linkProps.onClick}
|
||||
state={linkProps.state}
|
||||
className={linkProps.className ?? "block w-6 h-6 aspect-square blur-0 cursor-pointer hover:brightness-75"}
|
||||
title={linkProps.title}
|
||||
onClick={linkProps.onClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -3,6 +3,7 @@ import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { BsmIcon } from "../svgs/bsm-icon.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { FolderLinkState } from "renderer/services/version-folder-linker.service";
|
||||
import React from "react";
|
||||
|
||||
export type LinkBtnProps = {
|
||||
className?: string;
|
||||
@@ -11,9 +12,9 @@ export type LinkBtnProps = {
|
||||
onClick?: () => unknown;
|
||||
};
|
||||
|
||||
export const LinkButton = ({className, title, state, onClick}: LinkBtnProps) => {
|
||||
export function LinkButton({className, title, state, onClick}: LinkBtnProps) {
|
||||
const t = useTranslation();
|
||||
|
||||
|
||||
const color = useThemeColor("first-color");
|
||||
const disabled = state === FolderLinkState.Processing || state === FolderLinkState.Pending;
|
||||
|
||||
@@ -34,14 +35,15 @@ export const LinkButton = ({className, title, state, onClick}: LinkBtnProps) =>
|
||||
const handleClick = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
!disabled && onClick?.();
|
||||
if(disabled){ return; }
|
||||
onClick?.();
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
variants={{ hover: { rotate: 22.5 }, tap: { rotate: 45 } }}
|
||||
whileHover="hover"
|
||||
whileTap="tap"
|
||||
whileHover="hover"
|
||||
whileTap="tap"
|
||||
initial={{ rotate: 0 }}
|
||||
className={className}
|
||||
title={title ? t(title) : null}
|
||||
@@ -1,18 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import equal from "fast-deep-equal";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
type Options<T = unknown> = {
|
||||
untilEqual: T;
|
||||
emitOnEqual?: boolean;
|
||||
}
|
||||
|
||||
export function useChangeUntilEqual<T = unknown>(variableValue: T, { untilEqual, emitOnEqual }: Options<T>): T {
|
||||
const [value, setValue] = useState(variableValue);
|
||||
|
||||
const untilEqualRef = useRef(untilEqual);
|
||||
const emitOnEqualRef = useRef(emitOnEqual);
|
||||
const hasBeenEqual = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if(hasBeenEqual.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isEqual = equal(variableValue, untilEqualRef.current);
|
||||
|
||||
if(!isEqual){
|
||||
return setValue(variableValue);
|
||||
}
|
||||
|
||||
hasBeenEqual.current = true;
|
||||
|
||||
if(emitOnEqualRef.current) {
|
||||
setValue(variableValue);
|
||||
}
|
||||
}, [variableValue]);
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState } from "react";
|
||||
import { MapsPlaylistsPanel } from "renderer/components/maps-mangement-components/maps-playlists-panel.component";
|
||||
import { MapsPlaylistsPanel } from "renderer/components/maps-playlists-panel/maps-playlists-panel.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";
|
||||
|
||||
@@ -12,7 +12,7 @@ import { IpcService } from "renderer/services/ipc.service";
|
||||
import { LaunchSlide } from "renderer/components/version-viewer/slides/launch/launch-slide.component";
|
||||
import { ModsSlide } from "renderer/components/version-viewer/slides/mods/mods-slide.component";
|
||||
import { UninstallModal } from "renderer/components/modal/modal-types/uninstall-modal.component";
|
||||
import { MapsPlaylistsPanel } from "renderer/components/maps-mangement-components/maps-playlists-panel.component";
|
||||
import { MapsPlaylistsPanel } from "renderer/components/maps-playlists-panel/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";
|
||||
import { useService } from "renderer/hooks/use-service.hook";
|
||||
|
||||
@@ -101,7 +101,9 @@ export class MapsManagerService {
|
||||
|
||||
const progress$ = this.ipcService.sendV2<DeleteMapsProgress>("delete-maps", { args: maps }).pipe(map(progress => (progress.deleted / progress.total) * 100));
|
||||
|
||||
showProgressBar && this.progressBar.show(progress$, true);
|
||||
if (showProgressBar) {
|
||||
this.progressBar.show(progress$, true);
|
||||
}
|
||||
|
||||
progress$.toPromise().finally(() => this.progressBar.hide(true));
|
||||
|
||||
@@ -175,10 +177,6 @@ export class MapsManagerService {
|
||||
return this.lastUnlinkedVersion$.asObservable();
|
||||
}
|
||||
|
||||
public $mapsLinkingPending(version: BSVersion): Observable<boolean> {
|
||||
return this.linker.$isPending(version, MapsManagerService.RELATIVE_MAPS_FOLDER);
|
||||
}
|
||||
|
||||
public $mapsFolderLinkState(version: BSVersion): Observable<FolderLinkState> {
|
||||
return this.linker.$folderLinkedState(version, MapsManagerService.RELATIVE_MAPS_FOLDER);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { Observable, lastValueFrom } from "rxjs";
|
||||
import { FolderLinkState, VersionFolderLinkerService } from "./version-folder-linker.service";
|
||||
|
||||
export class PlaylistsManagerService {
|
||||
private static instance: PlaylistsManagerService;
|
||||
@@ -10,23 +13,29 @@ export class PlaylistsManagerService {
|
||||
return PlaylistsManagerService.instance;
|
||||
}
|
||||
|
||||
public static readonly RELATIVE_PLAYLISTS_FOLDER = "Playlists";
|
||||
|
||||
private readonly ipc: IpcService;
|
||||
private readonly linker: VersionFolderLinkerService;
|
||||
|
||||
private constructor() {
|
||||
this.ipc = IpcService.getInstance();
|
||||
this.linker = VersionFolderLinkerService.getInstance();
|
||||
}
|
||||
|
||||
public isDeepLinksEnabled(): Promise<boolean> {
|
||||
return this.ipc.send<boolean>("is-playlists-deep-links-enabled").then(res => (res.success ? res.data : false));
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("is-playlists-deep-links-enabled"));
|
||||
}
|
||||
|
||||
public async enableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipc.send<boolean>("register-playlists-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
public enableDeepLink(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("register-playlists-deep-link"));
|
||||
}
|
||||
|
||||
public async disableDeepLink(): Promise<boolean> {
|
||||
const res = await this.ipc.send<boolean>("unregister-playlists-deep-link");
|
||||
return res.success ? res.data : false;
|
||||
public disableDeepLink(): Promise<boolean> {
|
||||
return lastValueFrom(this.ipc.sendV2<boolean>("unregister-playlists-deep-link"));
|
||||
}
|
||||
|
||||
public $playlistsFolderLinkState(version: BSVersion): Observable<FolderLinkState> {
|
||||
return this.linker.$folderLinkedState(version, PlaylistsManagerService.RELATIVE_PLAYLISTS_FOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user