Compare commits

...

22 Commits

Author SHA1 Message Date
MathieuG-P 09acc3ccaa bump version 2023-01-13 03:20:37 +01:00
MathieuG-P 7c3f4f6a64 Merge pull request #106 from Zagrios/hotfix/bsm-icon-black-spark-on-light-theme
hotfix/bsm-icon-black-spark-on-light-theme
2023-01-13 03:03:22 +01:00
MathieuG-P 8dc48b20cb black spark bsm icon on light theme 2023-01-13 03:02:16 +01:00
MathieuG-P 165b17e034 Merge pull request #105 from Zagrios/hotfix/redirect-on-available-versions-on-delete-uninstall-version
hotfix/redirect-on-available-versions-on-delete-uninstall-version
2023-01-13 02:54:29 +01:00
MathieuG-P 4255e2ad85 redirect on available versions page on uninstall last version 2023-01-13 02:54:03 +01:00
MathieuG-P 16b7c1ed76 Merge pull request #104 from Zagrios/bugfix/pending-and-download-button-overlap/99
bugfix/pending-and-download-button-overlap/99
2023-01-13 02:41:09 +01:00
MathieuG-P d179bde348 fix overlapping download button and pending spinner 2023-01-13 02:40:24 +01:00
MathieuG-P e2234b19ea Merge pull request #102 from Zagrios/bugfix/cant-manage-versions/101
fix error libsFolders not iterable
2023-01-13 01:01:12 +01:00
MathieuG-P 45259f304b fix error libsFolders not iterable 2023-01-13 00:59:11 +01:00
MathieuG-P 220c7940a8 Merge pull request #98 from Zagrios/feature/add-info-launch-mod/11
feature/add-info-launch-mod/11
2023-01-11 23:53:19 +01:00
MathieuG-P 9665dbcb4e add info to launch mod 2023-01-11 23:51:40 +01:00
MathieuG-P 8d88b59e3d bump version 2023-01-10 22:19:24 +01:00
MathieuG-P ae9d1dfc9b Merge pull request #97 from Zagrios/bugfix/unglow-apply-when-no-filter-change/90
bugfix/unglow-apply-when-no-filter-change/90
2023-01-10 22:06:27 +01:00
MathieuG-P 6930df940f compare first and new filter to know if changes 2023-01-10 22:05:25 +01:00
MathieuG-P fd523f4017 Merge pull request #95 from Zagrios/bugfix/error-when-no-internet/87
bugfix/error-when-no-internet/87
2023-01-10 21:38:02 +01:00
MathieuG-P 4c8f903256 handle no internet for mods and maps 2023-01-10 21:37:26 +01:00
MathieuG-P d2ba6aadc1 Merge pull request #94 from Zagrios/bugfix/infinite-map-loading/91
bugfix/infinite-map-loading/91
2023-01-10 20:21:34 +01:00
MathieuG-P 0023066e32 add text when no maps found 2023-01-10 20:21:00 +01:00
MathieuG-P 39bcf63e3c Merge pull request #93 from Zagrios/bugfix/supporter-button-not-work/89
bugfix/supporter-button-not-work/89
2023-01-10 20:05:41 +01:00
MathieuG-P 656f32e755 fix supporters not open + add missing key 2023-01-10 20:05:07 +01:00
MathieuG-P f66279980b Merge pull request #92 from Zagrios/bugfix/map-preview-behind-maps-download/88
bugfix/map-preview-behind-maps-download/88
2023-01-10 19:58:15 +01:00
MathieuG-P 1f65841e62 fix iframe view z index + rename iframe view file 2023-01-10 19:57:39 +01:00
23 changed files with 19035 additions and 208 deletions
+12 -4
View File
@@ -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",
+12 -4
View File
@@ -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",
+12 -4
View File
@@ -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é",
+18877 -154
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -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 -1
View File
@@ -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": {
+3
View File
@@ -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>
)
@@ -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>
)
}
@@ -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(){
+3 -1
View File
@@ -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();