mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 09acc3ccaa | |||
| 7c3f4f6a64 | |||
| 8dc48b20cb | |||
| 165b17e034 | |||
| 4255e2ad85 | |||
| 16b7c1ed76 | |||
| d179bde348 | |||
| e2234b19ea | |||
| 45259f304b | |||
| 220c7940a8 | |||
| 9665dbcb4e | |||
| 8d88b59e3d | |||
| ae9d1dfc9b | |||
| 6930df940f | |||
| fd523f4017 | |||
| 4c8f903256 | |||
| d2ba6aadc1 | |||
| 0023066e32 | |||
| 39bcf63e3c | |||
| 656f32e755 | |||
| f66279980b | |||
| 1f65841e62 |
@@ -17,8 +17,11 @@
|
||||
"version-viewer": {
|
||||
"launch-mods": {
|
||||
"oculus": "Oculus Mod",
|
||||
"oculus-description": "If you are running Beat Saber through Steam, this allows you to play the game on an Oculus headset.",
|
||||
"desktop": "Desktop Mod",
|
||||
"debug": "Debug Mod"
|
||||
"desktop-description": "This allows you to use WASD and the mouse to navigate around the menu in game. This makes testing much easier, because you don't have to put on your headset!",
|
||||
"debug": "Debug Mod",
|
||||
"debug-description": "Enables the output log window for IPA. This will show the debug console that mods use."
|
||||
},
|
||||
"maps": {
|
||||
"search-bar": {
|
||||
@@ -51,6 +54,7 @@
|
||||
},
|
||||
"mods": {
|
||||
"loading-mods": "Loading mods...",
|
||||
"no-internet": "No internet",
|
||||
"buttons": {
|
||||
"more-infos": "More info",
|
||||
"install-or-update": "Install or update"
|
||||
@@ -164,10 +168,12 @@
|
||||
"shared": {
|
||||
"errors": {
|
||||
"titles": {
|
||||
"operation-running": "Operation running"
|
||||
"operation-running": "Operation running",
|
||||
"no-internet": "No internet"
|
||||
},
|
||||
"msg": {
|
||||
"operation-running": "Wait for the end of the current operation then start again."
|
||||
"operation-running": "Wait for the end of the current operation then start again.",
|
||||
"no-internet": "Check your connection and try again."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -505,7 +511,9 @@
|
||||
},
|
||||
"download-maps": {
|
||||
"search-btn": "Search",
|
||||
"loading-maps": "Loading maps..."
|
||||
"loading-maps": "Loading maps...",
|
||||
"no-maps-found": "No maps found",
|
||||
"no-internet": "No internet"
|
||||
},
|
||||
"mods-disclaimer":{
|
||||
"title": "disclaimer",
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
"version-viewer": {
|
||||
"launch-mods": {
|
||||
"oculus": "Oculus Mod",
|
||||
"oculus-description": "Si estás ejecutando Beat Saber a través de Steam, esto te permite jugar en un auricular Oculus.",
|
||||
"desktop": "Desktop Mod",
|
||||
"debug": "Debug Mod"
|
||||
"desktop-description": "Esto te permite usar WASD y el mouse para navegar por el menú en juego. Esto hace que las pruebas sean mucho más fáciles, ¡porque no tienes que ponerte el auricular!",
|
||||
"debug": "Debug Mod",
|
||||
"debug-description": "Habilita la ventana de registro de salida para IPA. Esto mostrará la consola de depuración que usan los mods."
|
||||
},
|
||||
"maps": {
|
||||
"search-bar": {
|
||||
@@ -51,6 +54,7 @@
|
||||
},
|
||||
"mods": {
|
||||
"loading-mods": "Cargando mods...",
|
||||
"no-internet": "Sin internet",
|
||||
"buttons": {
|
||||
"more-infos": "Más información",
|
||||
"install-or-update": "Instalar o actualizar"
|
||||
@@ -164,10 +168,12 @@
|
||||
"shared": {
|
||||
"errors": {
|
||||
"titles": {
|
||||
"operation-running": "Operación en curso"
|
||||
"operation-running": "Operación en curso",
|
||||
"no-internet": "Sin internet"
|
||||
},
|
||||
"msg": {
|
||||
"operation-running": "Espere a que termine la operación actual y vuelva a empezar."
|
||||
"operation-running": "Espere a que termine la operación actual y vuelva a empezar.",
|
||||
"no-internet": "Comprueba tu conexión a Internet e inténtalo de nuevo."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -505,7 +511,9 @@
|
||||
},
|
||||
"download-maps": {
|
||||
"search-btn": "buscar",
|
||||
"loading-maps": "Cargando mapas..."
|
||||
"loading-maps": "Cargando mapas...",
|
||||
"no-maps-found": "No se encontraron mapas",
|
||||
"no-internet": "Sin internet"
|
||||
},
|
||||
"mods-disclaimer":{
|
||||
"title": "descargo de responsabilidad",
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
"version-viewer": {
|
||||
"launch-mods": {
|
||||
"oculus": "Mode Oculus",
|
||||
"oculus-description": "Si vous exécutez Beat Saber via Steam, cela vous permet de jouer au jeu sur un casque Oculus.",
|
||||
"desktop": "Mode Bureau",
|
||||
"debug": "Mode Debug"
|
||||
"desktop-description": "Cela vous permet d'utiliser WASD et la souris pour naviguer dans le menu en jeu. Cela rend les tests beaucoup plus faciles, car vous n'avez pas à mettre votre casque!",
|
||||
"debug": "Mode Debug",
|
||||
"debug-description": "Active la fenêtre de log pour IPA. Cela affichera la console de débogage utilisée par les mods."
|
||||
},
|
||||
"maps": {
|
||||
"search-bar": {
|
||||
@@ -51,6 +54,7 @@
|
||||
},
|
||||
"mods": {
|
||||
"loading-mods": "Chargement des mods...",
|
||||
"no-internet": "Pas d'internet",
|
||||
"buttons": {
|
||||
"more-infos": "Plus d'infos",
|
||||
"install-or-update": "Installer ou mettre à jour"
|
||||
@@ -164,10 +168,12 @@
|
||||
"shared": {
|
||||
"errors": {
|
||||
"titles": {
|
||||
"operation-running": "Opération en cours"
|
||||
"operation-running": "Opération en cours",
|
||||
"no-internet": "Pas d'internet"
|
||||
},
|
||||
"msg": {
|
||||
"operation-running": "Attend la fin de l'opération en cours puis recommences."
|
||||
"operation-running": "Attend la fin de l'opération en cours puis recommences.",
|
||||
"no-internet": "Verifie t'a connexion internet et recommence."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -505,7 +511,9 @@
|
||||
},
|
||||
"download-maps": {
|
||||
"search-btn": "Rechercher",
|
||||
"loading-maps": "Chargement des maps..."
|
||||
"loading-maps": "Chargement des maps...",
|
||||
"no-maps-found": "Aucune map trouvée",
|
||||
"no-internet": "Pas d'internet"
|
||||
},
|
||||
"mods-disclaimer":{
|
||||
"title": "avis de non-responsabilité",
|
||||
|
||||
Generated
+18877
-154
File diff suppressed because it is too large
Load Diff
@@ -246,6 +246,7 @@
|
||||
"react-range": "^1.8.14",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"regedit": "^5.1.1",
|
||||
"rfdc": "^1.3.0",
|
||||
"rxjs": "^7.5.6",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"semver": "^7.3.8",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bs-manager",
|
||||
"version": "1.0.0-alpha.3",
|
||||
"version": "1.0.0-alpha.5",
|
||||
"description": "A foundation for scalable desktop apps",
|
||||
"main": "./dist/main/main.js",
|
||||
"author": {
|
||||
|
||||
@@ -50,6 +50,9 @@ export class OculusService {
|
||||
public async getGameFolder(gameFolder: string): Promise<string>{
|
||||
|
||||
const libsFolders = await this.getOculusLibsPath();
|
||||
|
||||
if(!libsFolders){ return null; }
|
||||
|
||||
const rootLibDir = "Software"
|
||||
|
||||
for(const lib of libsFolders){
|
||||
|
||||
@@ -12,6 +12,8 @@ import { MAP_SPECIFICITIES } from "renderer/partials/maps/map-general/map-specif
|
||||
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 equal from "fast-deep-equal/es6";
|
||||
import clone from "rfdc";
|
||||
|
||||
export type Props = {
|
||||
className?: string,
|
||||
@@ -28,6 +30,7 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
|
||||
const t = useTranslation();
|
||||
|
||||
const [haveChanged, setHaveChanged] = useState(false);
|
||||
const [firstFilter,] = useState(clone()(filter));
|
||||
const firstRun = useRef(true);
|
||||
|
||||
const MIN_NPS = 0;
|
||||
@@ -47,7 +50,8 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
|
||||
firstRun.current = false;
|
||||
return;
|
||||
}
|
||||
setHaveChanged(() => true);
|
||||
console.log(filter, firstFilter);
|
||||
setHaveChanged(() => !equal(filter, firstFilter));
|
||||
}, [filter])
|
||||
|
||||
|
||||
@@ -89,6 +93,9 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
|
||||
if(max === MAX_NPS){
|
||||
delete newFilter["maxNps"];
|
||||
}
|
||||
if(min === MIN_NPS){
|
||||
delete newFilter["minNps"];
|
||||
}
|
||||
onChange(newFilter);
|
||||
}
|
||||
|
||||
@@ -97,6 +104,9 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
|
||||
if(max === MAX_DURATION){
|
||||
delete newFilter["maxDuration"];
|
||||
}
|
||||
if(min === MIN_DURATION){
|
||||
delete newFilter["minDuration"];
|
||||
}
|
||||
onChange(newFilter);
|
||||
}
|
||||
|
||||
@@ -116,11 +126,17 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
|
||||
enabledTags.add(tag);
|
||||
}
|
||||
|
||||
onChange({
|
||||
...filter,
|
||||
enabledTags,
|
||||
excludedTags
|
||||
});
|
||||
const newFilter = {...filter, enabledTags, excludedTags};
|
||||
|
||||
if(newFilter.enabledTags.size === 0){
|
||||
delete newFilter["enabledTags"];
|
||||
}
|
||||
|
||||
if(newFilter.excludedTags.size === 0){
|
||||
delete newFilter["excludedTags"];
|
||||
}
|
||||
|
||||
onChange(newFilter);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,11 @@ import { ModalComponent } from "renderer/services/modale.service";
|
||||
import { BSVersion } from "shared/bs-version.interface";
|
||||
import { BsvMapCharacteristic, BsvMapDetail, MapFilter, SearchOrder, SearchParams } from "shared/models/maps/beat-saver.model";
|
||||
import BeatWaitingImg from "../../../../../assets/images/apngs/beat-waiting.png";
|
||||
import BeatConflictImg from "../../../../../assets/images/apngs/beat-conflict.png";
|
||||
import equal from "fast-deep-equal/es6";
|
||||
import { ProgressBarService } from "renderer/services/progress-bar.service";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { OsDiagnosticService } from "renderer/services/os-diagnostic.service";
|
||||
|
||||
export const DownloadMapsModal: ModalComponent<void, BSVersion> = ({data}) => {
|
||||
|
||||
@@ -24,6 +26,7 @@ export const DownloadMapsModal: ModalComponent<void, BSVersion> = ({data}) => {
|
||||
const mapsManager = MapsManagerService.getInstance();
|
||||
const mapsDownloader = MapsDownloaderService.getInstance();
|
||||
const progressBar = ProgressBarService.getInstance();
|
||||
const os = OsDiagnosticService.getInstance();
|
||||
|
||||
const currentDownload = useObservable(mapsDownloader.currentMapDownload$);
|
||||
const mapsInQueue = useObservable(mapsDownloader.mapsInQueue$);
|
||||
@@ -34,6 +37,8 @@ export const DownloadMapsModal: ModalComponent<void, BSVersion> = ({data}) => {
|
||||
const [maps, setMaps] = useState<BsvMapDetail[]>([]);
|
||||
const [sortOrder, setSortOrder] = useState<SearchOrder>(BSV_SORT_ORDER.at(0));
|
||||
const [ownedMapHashs, setOwnedMapHashs] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const isOnline = useObservable(os.isOnline$);
|
||||
const [searchParams, setSearchParams] = useState<SearchParams>({
|
||||
sortOrder,
|
||||
filter,
|
||||
@@ -73,7 +78,8 @@ export const DownloadMapsModal: ModalComponent<void, BSVersion> = ({data}) => {
|
||||
}, [])
|
||||
|
||||
const loadMaps = (params: SearchParams) => {
|
||||
beatSaver.searchMaps(params).then((maps => setMaps(prev => [...prev, ...maps])));
|
||||
setLoading(() => true);
|
||||
beatSaver.searchMaps(params).then((maps => setMaps(prev => [...prev, ...maps]))).finally(() => setLoading(() => false));
|
||||
}
|
||||
|
||||
const extractMapDiffs = (map: BsvMapDetail): Map<BsvMapCharacteristic, ParsedMapDiff[]> => {
|
||||
@@ -167,8 +173,8 @@ export const DownloadMapsModal: ModalComponent<void, BSVersion> = ({data}) => {
|
||||
<ul className="w-full grow flex content-start flex-wrap gap-2 px-2 overflow-y-scroll overflow-x-hidden scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900 z-0" >
|
||||
{maps.length === 0 ? (
|
||||
<div className="w-full h-full flex flex-col items-center justify-center">
|
||||
<img className="w-32 h-32 spin-loading" src={BeatWaitingImg} alt=" "/>
|
||||
<span className="text-lg">{t("modals.download-maps.loading-maps")}</span>
|
||||
<img className={`w-32 h-32 ${loading && "spin-loading"}`} src={loading ? BeatWaitingImg : BeatConflictImg} alt=" "/>
|
||||
<span className="text-lg">{t(loading ? "modals.download-maps.loading-maps" : isOnline ? "modals.download-maps.no-maps-found" : "modals.download-maps.no-internet")}</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -34,7 +34,7 @@ export const BsManagerIcon = memo(({className}: {className?: string}) => {
|
||||
<path d="M626.75,485.91l20.82,351.94a35.21,35.21,0,0,1-15.49,31.36L487.37,965.35l-.06,0A35.56,35.56,0,0,1,476,970.12a34.85,34.85,0,0,1-23.51-2.87L136.58,809.9a115.45,115.45,0,0,1-63.75-96.49L52,361.46a35.26,35.26,0,0,1,15.23-31.21l145.05-96.36a35.72,35.72,0,0,1,11.27-4.7,34.87,34.87,0,0,1,23.51,2.87L563,389.42a115.41,115.41,0,0,1,63.75,96.49Z"/>
|
||||
<path filter="brightness(30%)" d="M613.78,486.67l20.82,352a22.34,22.34,0,0,1-32.26,21.31L286.4,702.57A102.43,102.43,0,0,1,229.83,617L209,265a22.35,22.35,0,0,1,32.26-21.32L557.2,401.05A102.42,102.42,0,0,1,613.78,486.67Z"/>
|
||||
</g>
|
||||
<g fill="#fff">
|
||||
<g className="text-black dark:text-white" fill="currentColor">
|
||||
<path d="M718.29,776.48,700,804.18c-40.63,39.5-87.06,67.25-133.81,90.75-87.32,43.9-203.67,77.19-249,90.34a48,48,0,0,1-26.17.16c-64-17.72-188.62-72-236.28-125.49a4.23,4.23,0,0,1,5.3-6.45c35.64,20.87,111.22,57.64,156.37,74.22,49.18,18.06,81.29,8.74,92.28-3.26a4.77,4.77,0,0,1,7.24.21c19.51,24,107.26,4.6,166.64-13C546.91,892.66,668.42,835.1,718.29,776.48Z"/>
|
||||
<path d="M522.09,933.81,374.64,989.49a3.92,3.92,0,0,0,1.44,7.58l54.62-.77a35.63,35.63,0,0,0,19-5.79l76-49.55A4,4,0,0,0,522.09,933.81Z"/>
|
||||
<path d="M218.92,195.56c-21.14.07-33.55,35.86-33.16,89.08.2,28,2.58,92.74,4.79,147.73.23,5.71-8.18,6.48-9,.81L143.13,162.47a4.38,4.38,0,0,1,7.12-4,63.63,63.63,0,0,0,21.93,11.85,4.61,4.61,0,0,0,5.9-3.72c4.2-27.7,16.63-58.74,37.35-88.74a4.36,4.36,0,0,1,7.56.69c10.86,23.87,49,103.8,93.34,152.79a4.65,4.65,0,0,1-5.62,7.22C274.14,219.18,227.7,195.54,218.92,195.56Z"/>
|
||||
|
||||
@@ -18,7 +18,7 @@ export function SupportersBlock({className, title, supporters}: Props) {
|
||||
<div className={`mb-10 flex flex-col items-center ${className}`}>
|
||||
<h2 className="uppercase text-3xl font-bold">{t(title)}</h2>
|
||||
<div className="flex justify-center flex-wrap py-5 px-20">
|
||||
{supporters.map(s => <SupporterItem supporter={s} delay={someDelay()}/>)}
|
||||
{supporters.map(s => <SupporterItem key={crypto.randomUUID()} supporter={s} delay={someDelay()}/>)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ export function BsmIframeView() {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{iframeUrl && (
|
||||
<div className="top-0 absolute w-screen h-screen flex content-center items-center justify-center z-50">
|
||||
<div className="top-0 absolute w-screen h-screen flex content-center items-center justify-center z-[150]">
|
||||
<motion.span className="absolute w-full h-full bg-black top-0 right-0" initial={{opacity: 0}} animate={{opacity: .60}} exit={{opacity: 0}} transition={{duration: .2}}/>
|
||||
<motion.div ref={ref} className="z-[1] w-[calc(100vw-250px)] h-[calc(100vh-250px)] shadow-black shadow-md rounded-md overflow-hidden bg-black" initial={{y: "100vh"}} animate={{y: 0}} exit={{y: "100vh"}}>
|
||||
<iframe className="w-full h-full" src={iframeUrl}/>
|
||||
@@ -46,9 +46,10 @@ import { FilterIcon } from "./icons/filter-icon.component";
|
||||
import DiscordIcon from "./icons/discord-icon.component";
|
||||
import { TwitterIcon } from "./icons/twitter-icon.component";
|
||||
import { Mee6Icon } from "./icons/mee6-icon.component";
|
||||
import { InfoIcon } from "./icons/info-icon.component";
|
||||
|
||||
export type BsmIconType = BsvMapCharacteristic | (
|
||||
"settings"|"trash"|"favorite"|"folder"|"bsNote"|"check"|"three-dots"|"twitch"|"eye"|"play"|"checkCircleIcon"|"discord"|
|
||||
"settings"|"trash"|"favorite"|"folder"|"bsNote"|"check"|"three-dots"|"twitch"|"eye"|"play"|"checkCircleIcon"|"discord"|"info"|
|
||||
"terminal"|"desktop"|"oculus"|"add"|"cross"|"task"|"github"|"close"|"thumbUpFill"|"timerFill"|"pause"|"twitter"|
|
||||
"copy"|"steam"|"edit"|"export"|"patreon"|"search"|"bsMapDifficulty"|"link"|"unlink"|"download"|"filter"|"mee6"|
|
||||
"fr-FR-flag"|"es-ES-flag"|"en-US-flag"|"en-EN-flag"
|
||||
@@ -103,6 +104,7 @@ export const BsmIcon = memo(({className, icon, style}: {className?: string, icon
|
||||
if(icon === "discord"){ return <DiscordIcon className={className} style={style}/> }
|
||||
if(icon === "twitter"){ return <TwitterIcon className={className} style={style}/> }
|
||||
if(icon === "mee6"){ return <Mee6Icon className={className} style={style}/> }
|
||||
if(icon === "info"){ return <InfoIcon className={className} style={style}/> }
|
||||
return <TrashIcon className={className} style={style}/>
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { CSSProperties } from "react";
|
||||
|
||||
export function InfoIcon(props: {className?: string, style?: CSSProperties}) {
|
||||
return (
|
||||
<svg className={props.className} style={props.style} viewBox="0 0 400 400">
|
||||
<path stroke="none" fill="currentColor" fillRule="evenodd" d="M225 1.3c-34.8 9.2-48.5 49.6-25.4 75 30.8 34 89 14.6 88.8-29.8 0-31-31.9-53.7-63.4-45.3m-45 134.4c-13.6 2.1-31.1 7.3-52.3 15.5l-10.9 4.2L114 167c-1.5 6.4-2.7 11.7-2.6 11.9.1.1 4-1 8.7-2.5 23.6-7.6 42.2-5.7 47.6 5 6.3 12.3 4.2 25.2-14.4 91.4-6 21.2-11.7 42.8-12.7 48-10 51.7 11.2 78.7 62.1 78.9 23 0 26-.7 61-14.1L278 380l2.8-11.7c3.3-13.6 3.5-12.5-1.8-10.5-24.3 9.3-48.5 6.9-53.6-5.3-5.2-12.4-3-25.6 14.5-87.8 13.3-47 12.5-44.1 13.8-52.7 6.5-42.6-6-66.5-38.8-74.6-6.5-1.6-28.5-2.8-34.7-1.9"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
+19
-5
@@ -1,18 +1,32 @@
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { BsmIcon, BsmIconType } from "renderer/components/svgs/bsm-icon.component"
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
|
||||
type props = {onClick: (active: boolean) => void, active: boolean, text: string, icon: BsmIconType}
|
||||
type props = {
|
||||
onClick: (active: boolean) => void,
|
||||
active: boolean,
|
||||
text: string,
|
||||
icon: BsmIconType,
|
||||
infoText?: string,
|
||||
}
|
||||
|
||||
export function LaunchModToogle({onClick, active, text, icon}: props) {
|
||||
export function LaunchModToogle({onClick, active, text, icon, infoText}: props) {
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
return (
|
||||
<div className={`relative rounded-full cursor-pointer group active:scale-95 transition-transform ${!active && "shadow-md shadow-black"}`} onClick={() => onClick(!active)}>
|
||||
<div className={`absolute glow-on-hover !rounded-full ${active && "!opacity-100 blur-[2px]"}`}/>
|
||||
<div className='w-full h-full px-6 flex justify-center items-center bg-light-main-color-2 dark:bg-main-color-2 p-3 rounded-full text-gray-800 dark:text-white group-hover:bg-light-main-color-1 dark:group-hover:bg-main-color-1'>
|
||||
<BsmIcon icon={icon} className='mr-1 h-7 text-gray-800 dark:text-white'/>
|
||||
<span className='w-fit min-w-fit h-full text-lg font-bold uppercase tracking-wide italic'>{t(text)}</span>
|
||||
<div className='w-full h-full px-6 flex gap-1.5 justify-center items-center bg-light-main-color-2 dark:bg-main-color-2 p-3 rounded-full text-gray-800 dark:text-white group-hover:bg-light-main-color-1 dark:group-hover:bg-main-color-1'>
|
||||
<BsmIcon icon={icon} className='h-7 text-gray-800 dark:text-white'/>
|
||||
<span className='w-fit min-w-fit text-lg font-bold uppercase tracking-wide italic '>{t(text)}</span>
|
||||
{infoText && (
|
||||
<Tippy content={t(infoText)} placement="bottom" delay={[400, 0]}>
|
||||
<div className="h-[25px] w-[25px] p-1.5 rounded-full cursor-help bg-light-main-color-1 dark:bg-main-color-3 hover:brightness-110">
|
||||
<BsmIcon className="w-full h-full" icon="info"/>
|
||||
</div>
|
||||
</Tippy>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -39,9 +39,9 @@ export function LaunchSlide({version}: Props) {
|
||||
return (
|
||||
<div className="w-full shrink-0 items-center relative flex flex-col justify-start">
|
||||
<div className='grid grid-flow-col gap-6'>
|
||||
{!version.oculus && <LaunchModToogle icon='oculus' onClick={() => setMode(LaunchMods.OCULUS_MOD, !oculusMode)} active={oculusMode} text="pages.version-viewer.launch-mods.oculus"/>}
|
||||
<LaunchModToogle icon='desktop' onClick={() => setMode(LaunchMods.DESKTOP_MOD, !desktopMode)} active={desktopMode} text="pages.version-viewer.launch-mods.desktop"/>
|
||||
<LaunchModToogle icon='terminal' onClick={() => setMode(LaunchMods.DEBUG_MOD, !debugMode)} active={debugMode} text="pages.version-viewer.launch-mods.debug"/>
|
||||
{!version.oculus && <LaunchModToogle infoText="pages.version-viewer.launch-mods.oculus-description" icon='oculus' onClick={() => setMode(LaunchMods.OCULUS_MOD, !oculusMode)} active={oculusMode} text="pages.version-viewer.launch-mods.oculus"/>}
|
||||
<LaunchModToogle infoText="pages.version-viewer.launch-mods.desktop-description" icon='desktop' onClick={() => setMode(LaunchMods.DESKTOP_MOD, !desktopMode)} active={desktopMode} text="pages.version-viewer.launch-mods.desktop"/>
|
||||
<LaunchModToogle infoText="pages.version-viewer.launch-mods.debug-description" icon='terminal' onClick={() => setMode(LaunchMods.DEBUG_MOD, !debugMode)} active={debugMode} text="pages.version-viewer.launch-mods.debug"/>
|
||||
</div>
|
||||
<div className='grow flex justify-center items-center'>
|
||||
<BsmButton onClick={launch} active={JSON.stringify(version) === JSON.stringify(launchState)} className='relative text-5xl text-gray-800 dark:text-gray-200 font-bold tracking-wide pt-1 pb-3 px-7 rounded-lg shadow-md italic shadow-black active:scale-90 transition-transform' text="misc.launch"/>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ConfigurationService } from "renderer/services/configuration.service";
|
||||
import { DefaultConfigKey } from "renderer/config/default-configuration.config";
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import BeatWaitingImg from "../../../../../../assets/images/apngs/beat-waiting.png"
|
||||
import BeatConflictImg from "../../../../../../assets/images/apngs/beat-conflict.png"
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { skip, filter } from "rxjs/operators";
|
||||
import { Subscription } from "rxjs";
|
||||
@@ -15,6 +16,7 @@ import { LinkOpenerService } from "renderer/services/link-opener.service";
|
||||
import { useInView } from "framer-motion";
|
||||
import { ModalExitCode, ModalService } from "renderer/services/modale.service";
|
||||
import { ModsDisclaimerModal } from "renderer/components/modal/modal-types/mods-disclaimer-modal.component";
|
||||
import { OsDiagnosticService } from "renderer/services/os-diagnostic.service";
|
||||
|
||||
export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, onDisclamerDecline: () => void}) {
|
||||
|
||||
@@ -24,6 +26,7 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
const configService = ConfigurationService.getInstance();
|
||||
const linkOpener = LinkOpenerService.getInstance();
|
||||
const modals = ModalService.getInsance();
|
||||
const os = OsDiagnosticService.getInstance();
|
||||
|
||||
const ref = useRef(null);
|
||||
const isVisible = useInView(ref, {amount: .5});
|
||||
@@ -31,11 +34,13 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
const [modsInstalled, setModsInstalled] = useState(null as Map<string, Mod[]>);
|
||||
const [modsSelected, setModsSelected] = useState([] as Mod[]);
|
||||
const [moreInfoMod, setMoreInfoMod] = useState(null as Mod);
|
||||
const isOnline = useObservable(os.isOnline$);
|
||||
const installing = useObservable(modsManager.isInstalling$);
|
||||
const t = useTranslation();
|
||||
|
||||
const downloadRef = useRef(null);
|
||||
const [downloadWith, setDownloadWidth] = useState(0);
|
||||
|
||||
|
||||
const modsToCategoryMap = (mods: Mod[]): Map<string, Mod[]> => {
|
||||
if(!mods){ return new Map<string, Mod[]>(); }
|
||||
@@ -69,6 +74,8 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
}
|
||||
|
||||
const loadMods = () => {
|
||||
if(os.isOffline){ return; }
|
||||
|
||||
Promise.all([
|
||||
modsManager.getAvailableMods(version),
|
||||
modsManager.getInstalledMods(version)
|
||||
@@ -84,7 +91,7 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
|
||||
const subs: Subscription[] = [];
|
||||
|
||||
if(isVisible){
|
||||
if(isVisible && isOnline){
|
||||
|
||||
const promise = new Promise<boolean>(async resolve => {
|
||||
|
||||
@@ -115,7 +122,7 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
subs.forEach(s => s.unsubscribe());
|
||||
}
|
||||
|
||||
}, [isVisible, version]);
|
||||
}, [isVisible, isOnline, version]);
|
||||
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@@ -128,7 +135,7 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
return (
|
||||
<div ref={ref} className='shrink-0 w-full h-full px-8 pb-7 flex justify-center'>
|
||||
<div className='relative flex flex-col grow-0 bg-light-main-color-2 dark:bg-main-color-2 h-full w-full rounded-md shadow-black shadow-center overflow-hidden'>
|
||||
{modsAvailable ? (
|
||||
{isOnline && modsAvailable ? (
|
||||
<>
|
||||
<div className="overflow-scroll w-full min-h-0 scrollbar-thin scrollbar-thumb-neutral-900 scrollbar-thumb-rounded-full">
|
||||
<ModsGrid modsMap={modsAvailable} installed={modsInstalled} modsSelected={modsSelected} onModChange={handleModChange} moreInfoMod={moreInfoMod} onWantInfos={handleMoreInfo}/>
|
||||
@@ -142,8 +149,8 @@ export function ModsSlide({version, onDisclamerDecline}: {version: BSVersion, on
|
||||
</>
|
||||
) : (
|
||||
<div className="w-full h-full flex flex-col items-center justify-center">
|
||||
<img className="w-32 h-32 spin-loading" src={BeatWaitingImg} alt=" "/>
|
||||
<span className="text-xl mt-3 h-0 italic">{t("pages.version-viewer.mods.loading-mods")}</span>
|
||||
<img className={`w-32 h-32 ${isOnline && "spin-loading"}`} src={isOnline ? BeatWaitingImg : BeatConflictImg} alt=" "/>
|
||||
<span className="text-xl mt-3 h-0 italic">{t(isOnline ? "pages.version-viewer.mods.loading-mods" : "pages.version-viewer.mods.no-internet")}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,6 @@ import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { BSVersionManagerService } from "renderer/services/bs-version-manager.service";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
|
||||
export function AvailableVersionsList() {
|
||||
|
||||
@@ -15,12 +14,15 @@ export function AvailableVersionsList() {
|
||||
const versionManagerService: BSVersionManagerService = BSVersionManagerService.getInstance();
|
||||
|
||||
const [versionSelected, setVersionSelected] = useState(null as BSVersion);
|
||||
const currentVersionDownloading = useObservable(bsDownloaderService.currentBsVersionDownload$);
|
||||
const [downloading, setDownloading] = useState(false);
|
||||
const t = useTranslation();
|
||||
|
||||
const startDownload = () => {
|
||||
bsDownloaderService.download(versionSelected, versionManagerService.isVersionInstalled(versionSelected));
|
||||
}
|
||||
const startDownload = () => {
|
||||
setDownloading(() => true)
|
||||
bsDownloaderService.download(versionSelected, versionManagerService.isVersionInstalled(versionSelected)).finally(() => {
|
||||
setDownloading(() => false);
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const versionSelectedSub = bsDownloaderService.selectedBsVersion$.subscribe(version => {
|
||||
@@ -40,7 +42,7 @@ export function AvailableVersionsList() {
|
||||
<AvailableVersionsSlider/>
|
||||
|
||||
<AnimatePresence>
|
||||
{ versionSelected && !currentVersionDownloading && (
|
||||
{ versionSelected && !downloading && (
|
||||
<motion.div initial={{y:"150%"}} animate={{y:"0%"}} exit={{y:"150%"}} className="absolute bottom-5" onClick={startDownload}>
|
||||
<BsmButton text={versionManagerService.isVersionInstalled(versionSelected) ? "misc.verify" : "misc.download"} className="relative text-gray-800 dark:text-gray-100 rounded-md text-3xl font-bold italic tracking-wide px-3 pb-2 pt-1 shadow-md shadow-black"/>
|
||||
</motion.div>
|
||||
|
||||
@@ -294,7 +294,7 @@ export function SettingsPage() {
|
||||
<SettingContainer title="pages.settings.patreon.title" description="pages.settings.patreon.description">
|
||||
<div className="flex gap-2">
|
||||
<BsmButton className="flex w-fit rounded-md h-8 px-2 font-bold py-1 whitespace-nowrap !bg-red-500 !text-white" text="pages.settings.patreon.buttons.support" withBar={false} onClick={openSupportPage}/>
|
||||
<BsmButton className="flex w-fit rounded-md h-8 px-2 font-bold py-1 !text-white" withBar={false} text="pages.settings.patreon.buttons.supporters" color="#6c5ce7" onClick={() => toogleShowSupporters}/>
|
||||
<BsmButton className="flex w-fit rounded-md h-8 px-2 font-bold py-1 !text-white" withBar={false} text="pages.settings.patreon.buttons.supporters" color="#6c5ce7" onClick={toogleShowSupporters}/>
|
||||
</div>
|
||||
<SettingContainer className="mt-3" description="pages.settings.discord.description">
|
||||
<div className="flex gap-2">
|
||||
|
||||
@@ -28,7 +28,13 @@ export function VersionViewer() {
|
||||
const navigate = useNavigate();
|
||||
const [currentTabIndex, setCurrentTabIndex] = useState(0);
|
||||
|
||||
const navigateToVersion = (version: BSVersion) => navigate(`/bs-version/${version.BSVersion}`, {state: version});
|
||||
const navigateToVersion = (version?: BSVersion) => {
|
||||
console.log(version);
|
||||
if(!version){
|
||||
return navigate("/available-versions");
|
||||
}
|
||||
navigate(`/bs-version/${version.BSVersion}`, {state: version});
|
||||
}
|
||||
const openFolder = () => ipcService.sendLazy("bs-version.open-folder", {args: state});
|
||||
const verifyFiles = () => bsDownloaderService.download(state, true);
|
||||
|
||||
@@ -36,9 +42,9 @@ export function VersionViewer() {
|
||||
const modalCompleted = await modalService.openModal(UninstallModal, state);
|
||||
if(modalCompleted.exitCode === ModalExitCode.COMPLETED){
|
||||
bsUninstallerService.uninstall(state).then(() => {
|
||||
bsVersionManagerService.askInstalledVersions();
|
||||
const newVersionPage = bsVersionManagerService.getInstalledVersions()[0];
|
||||
navigateToVersion(newVersionPage);
|
||||
bsVersionManagerService.askInstalledVersions().then(versions => {
|
||||
navigateToVersion(versions?.at(0));
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ProgressionInterface } from "shared/models/progress-bar";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ModalExitCode, ModalService } from "./modale.service";
|
||||
import { NotificationService, NotificationType } from "./notification.service";
|
||||
import { OsDiagnosticService } from "./os-diagnostic.service";
|
||||
import { ProgressBarService } from "./progress-bar.service";
|
||||
|
||||
export class BsModsManagerService {
|
||||
@@ -22,6 +23,7 @@ export class BsModsManagerService {
|
||||
private readonly progressBar: ProgressBarService;
|
||||
private readonly modals: ModalService;
|
||||
private readonly notifications: NotificationService;
|
||||
private readonly os: OsDiagnosticService;
|
||||
|
||||
public readonly isInstalling$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
public readonly isUninstalling$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
@@ -36,17 +38,27 @@ export class BsModsManagerService {
|
||||
this.progressBar = ProgressBarService.getInstance();
|
||||
this.modals = ModalService.getInsance();
|
||||
this.notifications = NotificationService.getInstance();
|
||||
this.os = OsDiagnosticService.getInstance();
|
||||
}
|
||||
|
||||
public getAvailableMods(version: BSVersion): Promise<Mod[]>{
|
||||
public async getAvailableMods(version: BSVersion): Promise<Mod[]>{
|
||||
return this.ipcService.send<Mod[], BSVersion>("get-available-mods", {args: version}).then(res => res.data);
|
||||
}
|
||||
|
||||
public getInstalledMods(version: BSVersion): Promise<Mod[]>{
|
||||
public async getInstalledMods(version: BSVersion): Promise<Mod[]>{
|
||||
return this.ipcService.send<Mod[], BSVersion>("get-installed-mods", {args: version}).then(res => res.data);
|
||||
}
|
||||
|
||||
public installMods(mods: Mod[], version: BSVersion): Promise<void>{
|
||||
|
||||
if(this.os.isOffline){
|
||||
this.notifications.notifyError({
|
||||
title: "notifications.shared.errors.titles.no-internet",
|
||||
desc: "notifications.shared.errors.msg.no-internet"
|
||||
});
|
||||
return new Promise(res => res());
|
||||
}
|
||||
|
||||
if(!this.progressBar.require()){ return new Promise(res => res()); }
|
||||
|
||||
const progress$: Observable<ProgressionInterface> = this.ipcService.watch<ModInstallProgression>("mod-installed").pipe(map(res => {
|
||||
|
||||
@@ -9,7 +9,7 @@ export class OsDiagnosticService {
|
||||
return OsDiagnosticService.instance;
|
||||
}
|
||||
|
||||
private _isOnline$ = new BehaviorSubject(true);
|
||||
private _isOnline$ = new BehaviorSubject(navigator.onLine);
|
||||
|
||||
private constructor(){
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { NotificationOverlay } from "../components/notification/notification-ove
|
||||
import { PageStateService } from "../services/page-state.service";
|
||||
import { MapsPage } from "../pages/maps-page.component";
|
||||
import "tailwindcss/tailwind.css";
|
||||
import { BsmIframeView } from "../components/shared/bsm-map-preview.component";
|
||||
import { BsmIframeView } from "../components/shared/iframe-view.component";
|
||||
import 'tippy.js/dist/tippy.css';
|
||||
import { MapsManagerService } from "renderer/services/maps-manager.service";
|
||||
import { PlaylistsManagerService } from "renderer/services/playlists-manager.service";
|
||||
@@ -20,6 +20,7 @@ import { ModelsManagerService } from "renderer/services/models-manager.service";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
import { timer } from "rxjs";
|
||||
import { ConfigurationService } from "renderer/services/configuration.service";
|
||||
import { OsDiagnosticService } from "renderer/services/os-diagnostic.service";
|
||||
|
||||
export default function App() {
|
||||
|
||||
@@ -30,6 +31,7 @@ export default function App() {
|
||||
const models = ModelsManagerService.getInstance();
|
||||
const notification = NotificationService.getInstance();
|
||||
const config = ConfigurationService.getInstance();
|
||||
const os = OsDiagnosticService.getInstance();
|
||||
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
Reference in New Issue
Block a user