From 685313a13306160ac22bdb3f9473a22180439771 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 29 Oct 2023 13:04:22 +0100 Subject: [PATCH] [feature-274] Add setting to select the default platfrom to download BS --- .../choose-store-modal.component.tsx | 15 ++++-- .../setting-radio-array.component.tsx | 32 +++++++++---- .../svgs/icons/oculus-icon.component.tsx | 6 +-- .../available-versions-list.components.tsx | 9 +--- .../pages/settings-page.component.tsx | 47 ++++++++++++------- .../bs-downloader.service.ts | 21 +++++++-- .../services/configuration.service.ts | 16 +++++-- 7 files changed, 99 insertions(+), 47 deletions(-) diff --git a/src/renderer/components/modal/modal-types/bs-downgrade/choose-store-modal.component.tsx b/src/renderer/components/modal/modal-types/bs-downgrade/choose-store-modal.component.tsx index b7fee7e9..a58fe169 100644 --- a/src/renderer/components/modal/modal-types/bs-downgrade/choose-store-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/bs-downgrade/choose-store-modal.component.tsx @@ -6,11 +6,14 @@ import { BsStore } from "shared/models/bs-store.enum"; import { useState } from "react"; import tailwindConfig from "../../../../../../tailwind.config"; import Color from "color"; +import { useNavigate } from "react-router-dom"; export const ChooseStore: ModalComponent = ({ resolver }) => { const t = useTranslation(); + const navigate = useNavigate(); + const [oculusHover, setOculusHover] = useState(false); const [steamHover, setSteamHover] = useState(false); @@ -18,6 +21,11 @@ export const ChooseStore: ModalComponent = ({ resolver }) => { resolver({ exitCode: ModalExitCode.COMPLETED, data: store }); } + const goToSettings = () => { + resolver({ exitCode: ModalExitCode.CANCELED }); + navigate("/settings#choose-default-store"); + } + const isDarkMode = document.documentElement.classList.contains("dark"); const bg = (() => { @@ -37,10 +45,10 @@ export const ChooseStore: ModalComponent = ({ resolver }) => { // TODO : Translate return ( -
+

{t("which platform ?")}

-

Select the platfrom where you own Beat Saber or from which you want to download it.

-
+

Select the platfrom where you own Beat Saber or from which you want to download it.

+
setOculusHover(true)} onMouseLeave={() => setOculusHover(false)} onClick={() => chooseStore(BsStore.OCULUS)} style={{backgroundColor: oculusHover ? bg.dim : bg.bright}}>

Oculus Store (PC)

@@ -50,6 +58,7 @@ export const ChooseStore: ModalComponent = ({ resolver }) => {

Steam

+

Définir la platforme par défaut dans les paramètres

); }; diff --git a/src/renderer/components/settings/setting-radio-array.component.tsx b/src/renderer/components/settings/setting-radio-array.component.tsx index ee0ab1f4..60eb44a1 100644 --- a/src/renderer/components/settings/setting-radio-array.component.tsx +++ b/src/renderer/components/settings/setting-radio-array.component.tsx @@ -1,24 +1,37 @@ import { motion } from "framer-motion"; import { useTranslation } from "renderer/hooks/use-translation.hook"; -import { BsmIcon, BsmIconType } from "../svgs/bsm-icon.component"; +import { CSSProperties } from "react" -export function SettingRadioArray({ items, selectedItem = items[0].id, onItemSelected }: { items: RadioItem[]; selectedItem?: number; onItemSelected?: (id: number) => void }) { +type Props = { + id?: HTMLDivElement["id"]; + items: RadioItem[]; + selectedItemId?: number; + selectedItemValue?: T; + direction?: CSSProperties["flexDirection"], + onItemSelected?: (item: RadioItem) => void +}; + +export function SettingRadioArray({ id, items, selectedItemId, selectedItemValue, onItemSelected, direction = "column" }: Props) { const t = useTranslation(); + const isSelected = (item: RadioItem) => { + return item.id === selectedItemId || item.value === selectedItemValue; + } + return ( -
+
{items.map(i => ( -
onItemSelected(i.id)} key={i.id} className={`py-3 my-[6px] w-full flex cursor-pointer justify-between items-center rounded-md px-2 transition-colors duration-200 ${i.id === selectedItem ? "bg-light-main-color-3 dark:bg-main-color-3" : "bg-light-main-color-1 dark:bg-main-color-1"}`}> +
onItemSelected(i)} key={i.id} className={`py-3 w-full flex cursor-pointer justify-between items-center rounded-md px-2 transition-colors duration-200 ${isSelected(i) ? "bg-light-main-color-3 dark:bg-main-color-3" : "bg-light-main-color-1 dark:bg-main-color-1"} ${i.className}`}>
- +

{t(i.text)}

{i.icon && (
{i.textIcon && {t(i.textIcon)}} - + {i.icon}
)}
@@ -27,10 +40,11 @@ export function SettingRadioArray({ items, selectedItem = items[0].id, onItemSel ); } -export interface RadioItem { +export interface RadioItem { id: number; text: string; - icon?: BsmIconType; + icon?: JSX.Element; textIcon?: string; - value?: any; + className?: string; + value?: T; } diff --git a/src/renderer/components/svgs/icons/oculus-icon.component.tsx b/src/renderer/components/svgs/icons/oculus-icon.component.tsx index 77f54b82..ec44e16d 100644 --- a/src/renderer/components/svgs/icons/oculus-icon.component.tsx +++ b/src/renderer/components/svgs/icons/oculus-icon.component.tsx @@ -1,12 +1,12 @@ import { forwardRef, HTMLProps } from "react"; -export const OculusIcon = forwardRef>((props, ref) => { +export function OculusIcon(props: HTMLProps) { return ( - + ); -}) +} diff --git a/src/renderer/pages/available-versions-list.components.tsx b/src/renderer/pages/available-versions-list.components.tsx index da2833e5..ae158336 100644 --- a/src/renderer/pages/available-versions-list.components.tsx +++ b/src/renderer/pages/available-versions-list.components.tsx @@ -28,14 +28,7 @@ export function AvailableVersionsList() { const startDownload = async () => { - const store = await (async () => { - if(!selectedVersion.OculusBinaryId) { return BsStore.STEAM; } - return bsDownloader.getLastStoreDownloadedFrom() ?? await bsDownloader.chooseStoreToDownloadFrom().catch(() => null); - })(); - - if(!store){ return; } - - return bsDownloader.downloadVersion(selectedVersion, store) + return bsDownloader.downloadVersion(selectedVersion) .catch(console.log) .finally(() => setSelectedVersion(null)); }; diff --git a/src/renderer/pages/settings-page.component.tsx b/src/renderer/pages/settings-page.component.tsx index 7809c7bd..469bbf4f 100644 --- a/src/renderer/pages/settings-page.component.tsx +++ b/src/renderer/pages/settings-page.component.tsx @@ -3,7 +3,7 @@ import SettingColorChooser from "renderer/components/settings/setting-color-choo import { SettingContainer } from "renderer/components/settings/setting-container.component"; import { RadioItem, SettingRadioArray } from "renderer/components/settings/setting-radio-array.component"; import { BsmButton } from "renderer/components/shared/bsm-button.component"; -import { BsmIconType } from "renderer/components/svgs/bsm-icon.component"; +import { BsmIcon, BsmIconType } from "renderer/components/svgs/bsm-icon.component"; import { DefaultConfigKey, ThemeConfig } from "renderer/config/default-configuration.config"; import { useThemeColor } from "renderer/hooks/use-theme-color.hook"; import { SteamDownloaderService } from "renderer/services/bs-version-download/steam-downloader.service"; @@ -36,6 +36,10 @@ import { lastValueFrom } from "rxjs"; import { BsmException } from "shared/models/bsm-exception.model"; import { useObservable } from "renderer/hooks/use-observable.hook"; import { OculusDownloaderService } from "renderer/services/bs-version-download/oculus-downloader.service"; +import { BsStore } from "shared/models/bs-store.enum"; +import { SteamIcon } from "renderer/components/svgs/icons/steam-icon.component"; +import { OculusIcon } from "renderer/components/svgs/icons/oculus-icon.component"; +import { BsDownloaderService } from "renderer/services/bs-version-download/bs-downloader.service"; export function SettingsPage() { @@ -43,6 +47,7 @@ export function SettingsPage() { const themeService = useService(ThemeService); const ipcService = useService(IpcService); const modalService = useService(ModalService); + const bsDownloader = useService(BsDownloaderService); const steamDownloader = useService(SteamDownloaderService); const oculusDownloader = useService(OculusDownloaderService); const progressBarService = useService(ProgressBarService); @@ -56,24 +61,25 @@ export function SettingsPage() { const { firstColor, secondColor } = useThemeColor(); - const themeItem: RadioItem[] = [ + const themeItem: RadioItem[] = [ { id: 0, text: "pages.settings.appearance.themes.dark", value: "dark" as ThemeConfig }, { id: 1, text: "pages.settings.appearance.themes.light", value: "light" as ThemeConfig }, { id: 3, text: "pages.settings.appearance.themes.os", value: "os" as ThemeConfig }, ]; - const languagesItems: RadioItem[] = i18nService + const languagesItems: RadioItem[] = i18nService .getSupportedLanguages() .map((l, index) => { - return { id: index, text: `pages.settings.language.languages.${l}`, value: l, textIcon: `pages.settings.language.languages.translated.${l}`, icon: `${l}-flag` as BsmIconType }; + return { id: index, text: `pages.settings.language.languages.${l}`, value: l, textIcon: `pages.settings.language.languages.translated.${l}`, icon: }; }) .sort((a, b) => a.text.localeCompare(b.text)); const nav = useNavigate(); const t = useTranslation(); - const [themeIdSelected, setThemeIdSelected] = useState(themeItem.find(e => e.value === themeService.getTheme()).id); - const [languageSelected, setLanguageSelected] = useState(languagesItems.find(e => e.value === i18nService.currentLanguage).id); + const themeSelected = useObservable(themeService.theme$, "os"); + const languageSelected = useObservable(i18nService.currentLanguage$, i18nService.getFallbackLanguage()); + const downloadStore = useObservable(bsDownloader.defaultStore$); const [installationFolder, setInstallationFolder] = useState(null); const [showSupporters, setShowSupporters] = useState(false); const [mapDeepLinksEnabled, setMapDeepLinksEnabled] = useState(false); @@ -118,15 +124,16 @@ export function SettingsPage() { const setFirstColorSetting = (hex: string) => configService.set("first-color", hex); const setSecondColorSetting = (hex: string) => configService.set("second-color", hex); - const handleChangeTheme = (id: number) => { - setThemeIdSelected(id); - themeService.setTheme(themeItem.find(e => e.id === id).value); + const handleChangeBsStore = (item: RadioItem) => { + bsDownloader.setDefaultStore(item.value); + } + + const handleChangeTheme = (item: RadioItem) => { + themeService.setTheme(item.value); }; - const handleChangeLanguage = (id: number) => { - const selectedLanguage = languagesItems.find(l => l.id === id).value; - i18nService.setLanguage(selectedLanguage); - setLanguageSelected(languagesItems.find(l => l.value === i18nService.currentLanguage).id); + const handleChangeLanguage = (item: RadioItem) => { + i18nService.setLanguage(item.value); }; const setDefaultInstallationFolder = () => { @@ -224,7 +231,15 @@ export function SettingsPage() { - + + {/* TODO: Translate */} + }, + { id: 2, text: "Oculus", value: BsStore.OCULUS, icon: }, + { id: 0, text: "Toujours demander", value: undefined }, + ]} selectedItemValue={downloadStore} onItemSelected={handleChangeBsStore} direction="row"/> + +
@@ -235,7 +250,7 @@ export function SettingsPage() {
- + @@ -398,7 +413,7 @@ export function SettingsPage() { - + diff --git a/src/renderer/services/bs-version-download/bs-downloader.service.ts b/src/renderer/services/bs-version-download/bs-downloader.service.ts index f7c47b32..ebc8d6c4 100644 --- a/src/renderer/services/bs-version-download/bs-downloader.service.ts +++ b/src/renderer/services/bs-version-download/bs-downloader.service.ts @@ -8,6 +8,7 @@ import { OculusDownloaderService } from "./oculus-downloader.service"; import { DownloaderServiceInterface } from "./bs-store-downloader.interface"; import { AbstractBsDownloaderService } from "./abstract-bs-downloader.service"; import { BSVersionManagerService } from "../bs-version-manager.service"; +import { Observable } from "rxjs"; export class BsDownloaderService extends AbstractBsDownloaderService { @@ -27,6 +28,8 @@ export class BsDownloaderService extends AbstractBsDownloaderService { private readonly oculusDownloader: OculusDownloaderService; private readonly versionManager: BSVersionManagerService; + private readonly SELECTED_STORE_TO_DOWNLOAD_KET = "selectedStoreToDownload"; + private constructor(){ super(); this.config = ConfigurationService.getInstance(); @@ -52,8 +55,11 @@ export class BsDownloaderService extends AbstractBsDownloaderService { this._isVerifying$.next(false); } - public getLastStoreDownloadedFrom(): BsStore | undefined { - return this.config.get("lastStoreDownloadedFrom"); + public get defaultStore(): BsStore | undefined { return this.config.get(this.SELECTED_STORE_TO_DOWNLOAD_KET); } + public get defaultStore$(): Observable { return this.config.watch(this.SELECTED_STORE_TO_DOWNLOAD_KET); } + + public setDefaultStore(store: BsStore|undefined): void { + this.config.set(this.SELECTED_STORE_TO_DOWNLOAD_KET, store); } public async chooseStoreToDownloadFrom(): Promise { @@ -66,8 +72,15 @@ export class BsDownloaderService extends AbstractBsDownloaderService { return res.data; } - public downloadVersion(version: BSVersion, from: BsStore): Promise { - return this.getStoreDownloader(from).downloadBsVersion(version).finally(() => { + public async downloadVersion(version: BSVersion, from?: BsStore): Promise { + + if(!from){ + from = this.defaultStore ?? await this.chooseStoreToDownloadFrom(); + } + + return this.getStoreDownloader(from).downloadBsVersion(version).then(() => { + return this.downloadingVersion; + }).finally(() => { this.resetDownloadState(); this.versionManager.askInstalledVersions(); }); diff --git a/src/renderer/services/configuration.service.ts b/src/renderer/services/configuration.service.ts index d39dee0c..81dc31a6 100644 --- a/src/renderer/services/configuration.service.ts +++ b/src/renderer/services/configuration.service.ts @@ -1,5 +1,6 @@ import { BehaviorSubject, Observable } from "rxjs"; import { DefaultConfigKey, defaultConfiguration } from "renderer/config/default-configuration.config"; +import { tryit } from "shared/helpers/error.helpers"; export class ConfigurationService { private static instance: ConfigurationService; @@ -27,15 +28,22 @@ export class ConfigurationService { } public get(key: string | DefaultConfigKey): Type { - const t = JSON.parse(window.sessionStorage.getItem(key) || window.localStorage.getItem(key)); - if (!t) { + const rawValue = (window.sessionStorage.getItem(key) ?? window.localStorage.getItem(key)); + const tryParse = tryit(() => JSON.parse(rawValue)); + if (!tryParse.result) { return defaultConfiguration[key as DefaultConfigKey]; } - return t; + return (tryParse.result ?? rawValue) as Type; } public set(key: string, value: unknown, persistant = true) { - this.getPropperStorage(persistant).setItem(key, JSON.stringify(value)); + + if(value != null){ + this.getPropperStorage(persistant).setItem(key, JSON.stringify(value)); + } else { + this.getPropperStorage(persistant).removeItem(key); + } + this.emitChange(key); }