Skip to content

Commit

Permalink
Merge pull request #18 from hydralauncher/feat/adding-game-to-library…
Browse files Browse the repository at this point in the history
…-without-downloading

Feat/adding game to library without downloading
  • Loading branch information
Hydra authored Apr 16, 2024
2 parents 3246f3c + efbab40 commit 1793888
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 21 deletions.
2 changes: 2 additions & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
"hours": "hours",
"minutes": "minutes",
"accuracy": "{{accuracy}}% accuracy",
"add_to_library": "Add to library",
"remove_from_library": "Remove from library",
"delete_modal_title": "Are you sure?",
"delete_modal_description": "This will remove all game files from your system"
},
Expand Down
4 changes: 3 additions & 1 deletion src/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
"minutes": "minutos",
"accuracy": "{{accuracy}}% precisión",
"delete_modal_title": "¿Estás seguro de esto?",
"delete_modal_description": "Esto eliminará todos los archivos del juego de tu sistema"
"delete_modal_description": "Esto eliminará todos los archivos del juego de tu sistema",
"add_to_library": "Agregar a la biblioteca",
"remove_from_library": "Eliminar de la biblioteca"
},
"activation": {
"title": "Activar Hydra",
Expand Down
12 changes: 11 additions & 1 deletion src/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,13 @@
"publisher": "Édité par {{publisher}}",
"copy_link_to_clipboard": "Copier le lien",
"copied_link_to_clipboard": "Lien copié",
"hours": "heures",
"minutes": "minutes",
"accuracy": "{{accuracy}}% précision",
"add_to_library": "Ajouter à la bibliothèque",
"delete_modal_title": "Êtes-vous sûr de cela?",
"delete_modal_description": "Cela effacera tous les fichiers de jeu de votre système"
"delete_modal_description": "Cela effacera tous les fichiers de jeu de votre système",
"remove_from_library": "Supprimer de la bibliothèque"
},
"activation": {
"title": "Activer Hydra",
Expand Down Expand Up @@ -111,5 +116,10 @@
},
"game_card": {
"no_downloads": "Aucun téléchargement disponible"
},
"binary_not_found_modal": {
"description": "Les exécutables Wine ou Lutris sont introuvables sur votre système",
"instructions": "Vérifiez la bonne façon d'installer l'un d'entre eux sur votre distribution Linux afin que le jeu puisse fonctionner normalement",
"title": "Programmes non installés"
}
}
2 changes: 2 additions & 0 deletions src/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
"hours": "horas",
"minutes": "minutos",
"accuracy": "{{accuracy}}% de precisão",
"add_to_library": "Adicionar à biblioteca",
"remove_from_library": "Remover da biblioteca",
"delete_modal_title": "Tem certeza disso?",
"delete_modal_description": "Isso apagará todos os arquivos do jogo do seu sistema"
},
Expand Down
4 changes: 2 additions & 2 deletions src/main/entity/game.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class Game {
@Column("text")
shop: GameShop;

@Column("text")
@Column("text", { nullable: true })
status: string;

@Column("float", { default: 0 })
Expand All @@ -48,7 +48,7 @@ export class Game {
@Column("float", { default: 0 })
fileSize: number;

@OneToOne(() => Repack)
@OneToOne(() => Repack, { nullable: true })
@JoinColumn()
repack: Repack;

Expand Down
3 changes: 2 additions & 1 deletion src/main/events/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { app, ipcMain } from "electron";
import { defaultDownloadsPath } from "@main/constants";

import "./torrenting/start-game-download";
import "./library/add-game-to-library";
import "./catalogue/search-games";
import "./catalogue/get-game-shop-details";
import "./catalogue/get-catalogue";
Expand All @@ -10,6 +10,7 @@ import "./hardware/get-disk-free-space";
import "./torrenting/cancel-game-download";
import "./torrenting/pause-game-download";
import "./torrenting/resume-game-download";
import "./torrenting/start-game-download";
import "./misc/get-or-cache-image";
import "./user-preferences/update-user-preferences";
import "./user-preferences/get-user-preferences";
Expand Down
27 changes: 27 additions & 0 deletions src/main/events/library/add-game-to-library.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { gameRepository } from "@main/repository";

import { registerEvent } from "../register-event";

import type { GameShop } from "@types";
import { getImageBase64 } from "@main/helpers";
import { getSteamGameIconUrl } from "@main/services";

const addGameToLibrary = async (
_event: Electron.IpcMainInvokeEvent,
objectID: string,
title: string,
gameShop: GameShop,
) => {
const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID));

return gameRepository.insert({
title,
iconUrl,
objectID,
shop: gameShop,
});
};

registerEvent(addGameToLibrary, {
name: "addGameToLibrary",
});
6 changes: 4 additions & 2 deletions src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contextBridge.exposeInMainWorld("electron", {
repackId: number,
objectID: string,
title: string,
shop: GameShop
shop: GameShop,
) => ipcRenderer.invoke("startGameDownload", repackId, objectID, title, shop),
cancelGameDownload: (gameId: number) =>
ipcRenderer.invoke("cancelGameDownload", gameId),
Expand All @@ -26,7 +26,7 @@ contextBridge.exposeInMainWorld("electron", {
onDownloadProgress: (callback: (value: TorrentProgress) => void) => {
const listener = (
_event: Electron.IpcRendererEvent,
value: TorrentProgress
value: TorrentProgress,
) => callback(value);
ipcRenderer.on("on-download-progress", listener);
return () => ipcRenderer.removeListener("on-download-progress", listener);
Expand All @@ -48,6 +48,8 @@ contextBridge.exposeInMainWorld("electron", {
ipcRenderer.invoke("updateUserPreferences", preferences),

/* Library */
addGameToLibrary: (objectID: string, title: string, shop: GameShop) =>
ipcRenderer.invoke("addGameToLibrary", objectID, title, shop),
getLibrary: () => ipcRenderer.invoke("getLibrary"),
getRepackersFriendlyNames: () =>
ipcRenderer.invoke("getRepackersFriendlyNames"),
Expand Down
1 change: 1 addition & 0 deletions src/renderer/components/game-card/game-card.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export const specificsItem = style({
display: "flex",
color: "#c0c1c7",
fontSize: "12px",
alignItems: "flex-end",
});

export const titleContainer = style({
Expand Down
17 changes: 11 additions & 6 deletions src/renderer/declaration.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ declare global {
repackId: number,
objectID: string,
title: string,
shop: GameShop
shop: GameShop,
) => Promise<Game>;
cancelGameDownload: (gameId: number) => Promise<void>;
pauseGameDownload: (gameId: number) => Promise<void>;
resumeGameDownload: (gameId: number) => Promise<void>;
onDownloadProgress: (
cb: (value: TorrentProgress) => void
cb: (value: TorrentProgress) => void,
) => () => Electron.IpcRenderer;

/* Catalogue */
Expand All @@ -37,16 +37,21 @@ declare global {
getGameShopDetails: (
objectID: string,
shop: GameShop,
language: string
language: string,
) => Promise<ShopDetails | null>;
getRandomGame: () => Promise<string>;
getHowLongToBeat: (
objectID: string,
shop: GameShop,
title: string
title: string,
) => Promise<HowLongToBeatCategory[] | null>;

/* Library */
addGameToLibrary: (
objectID: string,
title: string,
shop: GameShop,
) => Promise<void>;
getLibrary: () => Promise<Game[]>;
getRepackersFriendlyNames: () => Promise<Record<string, string>>;
openGame: (gameId: number) => Promise<boolean>;
Expand All @@ -57,7 +62,7 @@ declare global {
/* User preferences */
getUserPreferences: () => Promise<UserPreferences | null>;
updateUserPreferences: (
preferences: Partial<UserPreferences>
preferences: Partial<UserPreferences>,
) => Promise<void>;

/* Hardware */
Expand All @@ -69,7 +74,7 @@ declare global {
ping: () => string;
getDefaultDownloadsPath: () => Promise<string>;
showOpenDialog: (
options: Electron.OpenDialogOptions
options: Electron.OpenDialogOptions,
) => Promise<Electron.OpenDialogReturnValue>;
platform: NodeJS.Platform;
}
Expand Down
57 changes: 49 additions & 8 deletions src/renderer/pages/game-details/hero-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useDownload, useLibrary } from "@renderer/hooks";
import type { Game, ShopDetails } from "@types";

import { formatDownloadProgress } from "@renderer/helpers";
import { NoEntryIcon, PlusCircleIcon } from "@primer/octicons-react";
import { BinaryNotFoundModal } from "../shared-modals/binary-not-found-modal";
import { DeleteModal } from "./delete-modal";
import * as styles from "./hero-panel.css";
Expand Down Expand Up @@ -45,7 +46,14 @@ export function HeroPanel({
removeGame,
isGameDeleting,
} = useDownload();
const { updateLibrary } = useLibrary();
const { updateLibrary, library } = useLibrary();

const [toggleLibraryGameDisabled, setToggleLibraryGameDisabled] =
useState(false);

const gameOnLibrary = library.find(
({ objectID }) => objectID === gameDetails?.objectID
);

const [showDeleteModal, setShowDeleteModal] = useState(false);

Expand All @@ -67,6 +75,26 @@ export function HeroPanel({
return game.repack?.fileSize ?? "N/A";
}, [game, isGameDownloading, gameDownloading]);

const toggleLibraryGame = async () => {
setToggleLibraryGameDisabled(true);

try {
if (gameOnLibrary) {
await window.electron.removeGame(gameOnLibrary.id);
} else {
await window.electron.addGameToLibrary(
gameDetails.objectID,
gameDetails.name,
"steam"
);
}

await updateLibrary();
} finally {
setToggleLibraryGameDisabled(false);
}
};

const getInfo = () => {
if (!gameDetails) return null;

Expand Down Expand Up @@ -209,20 +237,33 @@ export function HeroPanel({
}

return (
<Button onClick={openRepacksModal} theme="outline">
{t("open_download_options")}
</Button>
<>
<Button
theme="outline"
disabled={!gameDetails || toggleLibraryGameDisabled}
onClick={toggleLibraryGame}
>
{gameOnLibrary ? <NoEntryIcon /> : <PlusCircleIcon />}
{gameOnLibrary ? t("remove_from_library") : t("add_to_library")}
</Button>

<Button onClick={openRepacksModal} theme="outline">
{t("open_download_options")}
</Button>
</>
);
};

return (
<div style={{ backgroundColor: color }} className={styles.panel}>
<>
<BinaryNotFoundModal
visible={showBinaryNotFoundModal}
onClose={() => setShowBinaryNotFoundModal(false)}
/>
<div className={styles.content}>{getInfo()}</div>
<div className={styles.actions}>{getActions()}</div>
</div>
<div style={{ backgroundColor: color }} className={styles.panel}>
<div className={styles.content}>{getInfo()}</div>
<div className={styles.actions}>{getActions()}</div>
</div>
</>
);
}

0 comments on commit 1793888

Please sign in to comment.