From 48b6d1c941af6c1a088e98c45b84819af27f372e Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:33:21 -0300 Subject: [PATCH] feat: create game options modal fix error when getSteamAppDetails fails dont set game as removed when deleting instalation folder fix game not deleting installation folder organize code feat: add open game executable path and installer path --- src/main/events/index.ts | 3 + .../library/open-game-executable-path.ts | 22 +++ .../library/open-game-installer-path.ts | 27 +++ .../events/library/update-executable-path.ts | 20 +++ src/preload/index.ts | 6 + src/renderer/src/declaration.d.ts | 3 + .../game-details/hero/hero-panel-actions.tsx | 23 ++- .../modals/game-options-modal.css.ts | 13 ++ .../modals/game-options-modal.tsx | 167 ++++++++++++++++++ 9 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 src/main/events/library/open-game-executable-path.ts create mode 100644 src/main/events/library/open-game-installer-path.ts create mode 100644 src/main/events/library/update-executable-path.ts create mode 100644 src/renderer/src/pages/game-details/modals/game-options-modal.css.ts create mode 100644 src/renderer/src/pages/game-details/modals/game-options-modal.tsx diff --git a/src/main/events/index.ts b/src/main/events/index.ts index 83b90595..23271eba 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -15,7 +15,10 @@ import "./library/delete-game-folder"; import "./library/get-game-by-object-id"; import "./library/get-library"; import "./library/open-game"; +import "./library/open-game-executable-path"; import "./library/open-game-installer"; +import "./library/open-game-installer-path"; +import "./library/update-executable-path"; import "./library/remove-game"; import "./library/remove-game-from-library"; import "./misc/open-external"; diff --git a/src/main/events/library/open-game-executable-path.ts b/src/main/events/library/open-game-executable-path.ts new file mode 100644 index 00000000..47aa0b47 --- /dev/null +++ b/src/main/events/library/open-game-executable-path.ts @@ -0,0 +1,22 @@ +import { shell } from "electron"; +import path from "node:path"; +import { gameRepository } from "@main/repository"; +import { registerEvent } from "../register-event"; + +const openGameExecutablePath = async ( + _event: Electron.IpcMainInvokeEvent, + gameId: number +) => { + const game = await gameRepository.findOne({ + where: { id: gameId, isDeleted: false }, + }); + + if (!game || !game.executablePath) return true; + + const gamePath = path.join(game.executablePath, "../"); + + shell.openPath(gamePath); + return true; +}; + +registerEvent("openGameExecutablePath", openGameExecutablePath); diff --git a/src/main/events/library/open-game-installer-path.ts b/src/main/events/library/open-game-installer-path.ts new file mode 100644 index 00000000..bb5d0c6f --- /dev/null +++ b/src/main/events/library/open-game-installer-path.ts @@ -0,0 +1,27 @@ +import { shell } from "electron"; +import path from "node:path"; +import { gameRepository } from "@main/repository"; +import { getDownloadsPath } from "../helpers/get-downloads-path"; +import { registerEvent } from "../register-event"; + +const openGameInstallerPath = async ( + _event: Electron.IpcMainInvokeEvent, + gameId: number +) => { + const game = await gameRepository.findOne({ + where: { id: gameId, isDeleted: false }, + }); + + if (!game || !game.folderName) return true; + + const gamePath = path.join( + game.downloadPath ?? (await getDownloadsPath()), + game.folderName! + ); + + shell.openPath(gamePath); + + return true; +}; + +registerEvent("openGameInstallerPath", openGameInstallerPath); diff --git a/src/main/events/library/update-executable-path.ts b/src/main/events/library/update-executable-path.ts new file mode 100644 index 00000000..6546e8b9 --- /dev/null +++ b/src/main/events/library/update-executable-path.ts @@ -0,0 +1,20 @@ +import { gameRepository } from "@main/repository"; + +import { registerEvent } from "../register-event"; + +const updateExecutablePath = async ( + _event: Electron.IpcMainInvokeEvent, + id: number, + executablePath: string +) => { + return gameRepository.update( + { + id, + }, + { + executablePath, + } + ); +}; + +registerEvent("updateExecutablePath", updateExecutablePath); diff --git a/src/preload/index.ts b/src/preload/index.ts index 4d1f0eea..8f0ca282 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -73,9 +73,15 @@ contextBridge.exposeInMainWorld("electron", { shop, executablePath ), + updateExecutablePath: (id: number, executablePath: string) => + ipcRenderer.invoke("updateExecutablePath", id, executablePath), getLibrary: () => ipcRenderer.invoke("getLibrary"), openGameInstaller: (gameId: number) => ipcRenderer.invoke("openGameInstaller", gameId), + openGameInstallerPath: (gameId: number) => + ipcRenderer.invoke("openGameInstallerPath", gameId), + openGameExecutablePath: (gameId: number) => + ipcRenderer.invoke("openGameExecutablePath", gameId), openGame: (gameId: number, executablePath: string) => ipcRenderer.invoke("openGame", gameId, executablePath), closeGame: (gameId: number) => ipcRenderer.invoke("closeGame", gameId), diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 5d5bf0ec..f9bf8a7e 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -59,8 +59,11 @@ declare global { shop: GameShop, executablePath: string | null ) => Promise; + updateExecutablePath: (id: number, executablePath: string) => Promise; getLibrary: () => Promise; openGameInstaller: (gameId: number) => Promise; + openGameInstallerPath: (gameId: number) => Promise; + openGameExecutablePath: (gameId: number) => Promise; openGame: (gameId: number, executablePath: string) => Promise; closeGame: (gameId: number) => Promise; removeGameFromLibrary: (gameId: number) => Promise; diff --git a/src/renderer/src/pages/game-details/hero/hero-panel-actions.tsx b/src/renderer/src/pages/game-details/hero/hero-panel-actions.tsx index 06406d22..64730b6c 100644 --- a/src/renderer/src/pages/game-details/hero/hero-panel-actions.tsx +++ b/src/renderer/src/pages/game-details/hero/hero-panel-actions.tsx @@ -1,4 +1,4 @@ -import { NoEntryIcon, PlusCircleIcon } from "@primer/octicons-react"; +import { GearIcon, NoEntryIcon, PlusCircleIcon } from "@primer/octicons-react"; import { BinaryNotFoundModal } from "../../shared-modals/binary-not-found-modal"; @@ -10,11 +10,13 @@ import { useTranslation } from "react-i18next"; import * as styles from "./hero-panel-actions.css"; import { gameDetailsContext } from "../game-details.context"; import { Downloader } from "@shared"; +import { GameOptionsModal } from "../modals/game-options-modal"; export function HeroPanelActions() { const [toggleLibraryGameDisabled, setToggleLibraryGameDisabled] = useState(false); const [showBinaryNotFoundModal, setShowBinaryNotFoundModal] = useState(false); + const [showGameOptionsModal, setShowGameOptionsModal] = useState(false); const { resumeDownload, @@ -224,6 +226,25 @@ export function HeroPanelActions() { if (game) { return ( <> + { + setShowGameOptionsModal(false); + }} + selectGameExecutable={selectGameExecutable} + /> + + {game?.progress === 1 && game?.folderName && ( <> void; + selectGameExecutable: () => Promise; +} + +export function GameOptionsModal({ + visible, + game, + onClose, + selectGameExecutable, +}: GameOptionsModalProps) { + const [currentCategoryIndex, setCurrentCategoryIndex] = useState(0); + + const { updateGame, openRepacksModal } = useContext(gameDetailsContext); + + const [showDeleteModal, setShowDeleteModal] = useState(false); + + const { removeGameInstaller, isGameDeleting } = useDownload(); + + const deleting = game ? isGameDeleting(game?.id) : false; + + const { t } = useTranslation("game_details"); + + const handleChangeExecutableLocation = async () => { + const location = await selectGameExecutable(); + + if (location) { + await window.electron.updateExecutablePath(game.id, location); + updateGame(); + } + }; + + const handleDeleteGame = async () => { + await removeGameInstaller(game.id); + }; + + const handleOpenGameInstallerPath = async () => { + await window.electron.openGameInstallerPath(game.id); + }; + + const handleOpenGameExecutablePath = async () => { + await window.electron.openGameExecutablePath(game.id); + }; + + return ( + <> + + setShowDeleteModal(false)} + deleteGame={handleDeleteGame} + /> + +
+
+ +
+ +
+ + + + + +
+ +
+ +
+ +
+ + + +
+
+
+ + ); +}