From 0162ebd133f34849da2e7dfbba49de7f947500ab Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Wed, 22 May 2024 00:12:57 +0100 Subject: [PATCH] feat: adding toast component --- src/locales/en/translation.json | 2 +- src/locales/pt/translation.json | 2 +- .../events/torrenting/resume-game-download.ts | 18 +++++- .../events/torrenting/start-game-download.ts | 12 ++-- src/main/services/download-manager.ts | 16 +++-- src/renderer/src/app.css.ts | 4 ++ .../src/components/modal/modal.css.ts | 8 +-- .../src/components/sidebar/sidebar.css.ts | 2 +- .../src/pages/downloads/downloads.css.ts | 30 ++++++++- .../src/pages/downloads/downloads.tsx | 38 ++++++----- .../pages/game-details/game-details.css.ts | 2 +- src/renderer/src/pages/settings/settings.tsx | 63 ++++++++++++------- src/shared/index.ts | 21 ------- 13 files changed, 136 insertions(+), 82 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 7b54b889..ac695bca 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -120,7 +120,7 @@ "verifying": "Verifying…", "completed_at": "Completed in {{date}}", "completed": "Completed", - "cancelled": "Cancelled", + "removed": "Removed", "download_again": "Download again", "cancel": "Cancel", "filter": "Filter downloaded games", diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index 57ec0470..bc3190db 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -116,7 +116,7 @@ "verifying": "Verificando…", "completed_at": "Concluído em {{date}}", "completed": "Concluído", - "cancelled": "Cancelado", + "removed": "Removido", "download_again": "Baixar novamente", "cancel": "Cancelar", "filter": "Filtrar jogos baixados", diff --git a/src/main/events/torrenting/resume-game-download.ts b/src/main/events/torrenting/resume-game-download.ts index fa555199..b39ee8f3 100644 --- a/src/main/events/torrenting/resume-game-download.ts +++ b/src/main/events/torrenting/resume-game-download.ts @@ -1,7 +1,11 @@ +import { Not } from "typeorm"; + import { registerEvent } from "../register-event"; import { gameRepository } from "../../repository"; import { DownloadManager } from "@main/services"; +import { dataSource } from "@main/data-source"; +import { Game } from "@main/entity"; const resumeGameDownload = async ( _event: Electron.IpcMainInvokeEvent, @@ -18,11 +22,19 @@ const resumeGameDownload = async ( if (!game) return; if (game.status === "paused") { - await DownloadManager.pauseDownload(); + await dataSource.transaction(async (transactionalEntityManager) => { + await DownloadManager.pauseDownload(); - await gameRepository.update({ id: gameId }, { status: "active" }); + await transactionalEntityManager + .getRepository(Game) + .update({ status: "active", progress: Not(1) }, { status: "paused" }); - await DownloadManager.resumeDownload(gameId); + await DownloadManager.resumeDownload(gameId); + + await transactionalEntityManager + .getRepository(Game) + .update({ id: gameId }, { status: "active" }); + }); } }; diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index 5a987327..82b7be3b 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -44,6 +44,8 @@ const startGameDownload = async ( if (!repack || game?.status === "active") return; + await DownloadManager.pauseDownload(); + await gameRepository.update( { status: "active", progress: Not(1) }, { status: "paused" } @@ -65,9 +67,7 @@ const startGameDownload = async ( await DownloadManager.startDownload(game.id); - game.status = "active"; - - return game; + return { ...game, stauts: "active" }; } else { const steamGame = stateManager .getValue("steamGames") @@ -98,11 +98,9 @@ const startGameDownload = async ( return result; }); - DownloadManager.startDownload(createdGame.id); + await DownloadManager.startDownload(createdGame.id); - const { repack: _, ...rest } = createdGame; - - return rest; + return createdGame; } }; diff --git a/src/main/services/download-manager.ts b/src/main/services/download-manager.ts index 25f99543..225d80cb 100644 --- a/src/main/services/download-manager.ts +++ b/src/main/services/download-manager.ts @@ -30,7 +30,16 @@ export class DownloadManager { "aria2c" ); - spawn(binary, ["--enable-rpc", "--rpc-listen-all"], { stdio: "inherit" }); + spawn( + binary, + [ + "--enable-rpc", + "--rpc-listen-all", + "--file-allocation=none", + "--allow-overwrite=true", + ], + { stdio: "inherit" } + ); await this.aria2.open(); this.attachListener(); @@ -76,6 +85,7 @@ export class DownloadManager { } private static async attachListener() { + // eslint-disable-next-line no-constant-condition while (true) { try { if (!this.gid || !this.gameId) { @@ -205,8 +215,6 @@ export class DownloadManager { } static async resumeDownload(gameId: number) { - await this.aria2.call("forcePauseAll"); - if (this.downloads.has(gameId)) { const gid = this.downloads.get(gameId)!; await this.aria2.call("unpause", gid); @@ -219,8 +227,6 @@ export class DownloadManager { } static async startDownload(gameId: number) { - await this.aria2.call("forcePauseAll"); - const game = await this.getGame(gameId)!; if (game) { diff --git a/src/renderer/src/app.css.ts b/src/renderer/src/app.css.ts index 2a55f033..f87b96a3 100644 --- a/src/renderer/src/app.css.ts +++ b/src/renderer/src/app.css.ts @@ -79,6 +79,10 @@ globalStyle("img", { WebkitUserDrag: "none", } as Record); +globalStyle("progress[value]", { + WebkitAppearance: "none", +}); + export const container = style({ width: "100%", height: "100%", diff --git a/src/renderer/src/components/modal/modal.css.ts b/src/renderer/src/components/modal/modal.css.ts index 54f856b9..89e17b0e 100644 --- a/src/renderer/src/components/modal/modal.css.ts +++ b/src/renderer/src/components/modal/modal.css.ts @@ -2,14 +2,14 @@ import { keyframes, style } from "@vanilla-extract/css"; import { recipe } from "@vanilla-extract/recipes"; import { SPACING_UNIT, vars } from "../../theme.css"; -export const modalSlideIn = keyframes({ +export const fadeIn = keyframes({ "0%": { opacity: 0 }, "100%": { opacity: 1, }, }); -export const modalSlideOut = keyframes({ +export const fadeOut = keyframes({ "0%": { opacity: 1 }, "100%": { opacity: 0, @@ -18,7 +18,7 @@ export const modalSlideOut = keyframes({ export const modal = recipe({ base: { - animationName: modalSlideIn, + animationName: fadeIn, animationDuration: "0.3s", backgroundColor: vars.color.background, borderRadius: "5px", @@ -33,7 +33,7 @@ export const modal = recipe({ variants: { closing: { true: { - animationName: modalSlideOut, + animationName: fadeOut, opacity: 0, }, }, diff --git a/src/renderer/src/components/sidebar/sidebar.css.ts b/src/renderer/src/components/sidebar/sidebar.css.ts index d0bf1e3e..e91ef4a7 100644 --- a/src/renderer/src/components/sidebar/sidebar.css.ts +++ b/src/renderer/src/components/sidebar/sidebar.css.ts @@ -27,6 +27,7 @@ export const content = recipe({ display: "flex", flexDirection: "column", padding: `${SPACING_UNIT * 2}px`, + gap: `${SPACING_UNIT * 2}px`, paddingBottom: "0", width: "100%", overflow: "auto", @@ -118,7 +119,6 @@ export const sectionTitle = style({ }); export const section = style({ - padding: `${SPACING_UNIT * 2}px 0`, gap: `${SPACING_UNIT * 2}px`, display: "flex", flexDirection: "column", diff --git a/src/renderer/src/pages/downloads/downloads.css.ts b/src/renderer/src/pages/downloads/downloads.css.ts index dcccb16a..4df3dc90 100644 --- a/src/renderer/src/pages/downloads/downloads.css.ts +++ b/src/renderer/src/pages/downloads/downloads.css.ts @@ -29,7 +29,6 @@ export const downloaderName = style({ borderRadius: "4px", display: "flex", alignItems: "center", - alignSelf: "flex-start", }); export const downloads = style({ @@ -46,9 +45,34 @@ export const downloadCover = style({ width: "280px", minWidth: "280px", height: "auto", - objectFit: "cover", - objectPosition: "center", borderRight: `solid 1px ${vars.color.border}`, + position: "relative", + zIndex: "1", +}); + +export const downloadCoverContent = style({ + width: "100%", + height: "100%", + padding: `${SPACING_UNIT}px`, + display: "flex", + alignItems: "flex-end", + justifyContent: "flex-end", +}); + +export const downloadCoverBackdrop = style({ + width: "100%", + height: "100%", + background: "linear-gradient(0deg, rgba(0, 0, 0, 0.8) 5%, transparent 100%)", + display: "flex", + overflow: "hidden", + zIndex: "1", +}); + +export const downloadCoverImage = style({ + width: "100%", + height: "100%", + position: "absolute", + zIndex: "-1", }); export const download = recipe({ diff --git a/src/renderer/src/pages/downloads/downloads.tsx b/src/renderer/src/pages/downloads/downloads.tsx index e18f5bb1..b2d2b0f3 100644 --- a/src/renderer/src/pages/downloads/downloads.tsx +++ b/src/renderer/src/pages/downloads/downloads.tsx @@ -2,7 +2,11 @@ import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { Button, TextField } from "@renderer/components"; -import { formatDownloadProgress, steamUrlBuilder } from "@renderer/helpers"; +import { + buildGameDetailsPath, + formatDownloadProgress, + steamUrlBuilder, +} from "@renderer/helpers"; import { useDownload, useLibrary } from "@renderer/hooks"; import type { Game } from "@types"; @@ -86,9 +90,9 @@ export function Downloads() {

{game.downloader === Downloader.Torrent && ( -

+ {lastPacket?.numPeers} peers / {lastPacket?.numSeeds} seeds -

+ )} ); @@ -102,7 +106,6 @@ export function Downloads() { ); } - if (game?.status === "removed") return

{t("cancelled")}

; if (game?.status === "paused") { return ( @@ -113,7 +116,7 @@ export function Downloads() { ); } - return null; + return

{t(game?.status)}

; }; const openDeleteModal = (gameId: number) => { @@ -173,7 +176,7 @@ export function Downloads() { return ( <> - - {downloaderName[game?.downloader]} - {getGameInfo(game)} diff --git a/src/renderer/src/pages/game-details/game-details.css.ts b/src/renderer/src/pages/game-details/game-details.css.ts index dadfb641..fd55d69d 100644 --- a/src/renderer/src/pages/game-details/game-details.css.ts +++ b/src/renderer/src/pages/game-details/game-details.css.ts @@ -2,7 +2,7 @@ import { globalStyle, keyframes, style } from "@vanilla-extract/css"; import { SPACING_UNIT, vars } from "../../theme.css"; export const slideIn = keyframes({ - "0%": { transform: `translateY(${40 + 16}px)` }, + "0%": { transform: `translateY(${40 + SPACING_UNIT * 2}px)` }, "100%": { transform: "translateY(0)" }, }); diff --git a/src/renderer/src/pages/settings/settings.tsx b/src/renderer/src/pages/settings/settings.tsx index b305f38c..b5a03ff3 100644 --- a/src/renderer/src/pages/settings/settings.tsx +++ b/src/renderer/src/pages/settings/settings.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { Button } from "@renderer/components"; import * as styles from "./settings.css"; @@ -7,6 +7,7 @@ import { UserPreferences } from "@types"; import { SettingsRealDebrid } from "./settings-real-debrid"; import { SettingsGeneral } from "./settings-general"; import { SettingsBehavior } from "./settings-behavior"; +import { Toast } from "@renderer/components/toast/toast"; const categories = ["general", "behavior", "real_debrid"]; @@ -14,6 +15,7 @@ export function Settings() { const [currentCategory, setCurrentCategory] = useState(categories.at(0)!); const [userPreferences, setUserPreferences] = useState(null); + const [isToastVisible, setIsToastVisible] = useState(false); const { t } = useTranslation("settings"); @@ -23,8 +25,14 @@ export function Settings() { }); }, []); - const handleUpdateUserPreferences = (values: Partial) => { - window.electron.updateUserPreferences(values); + const handleUpdateUserPreferences = async ( + values: Partial + ) => { + await window.electron.updateUserPreferences(values); + window.electron.getUserPreferences().then((userPreferences) => { + setUserPreferences(userPreferences); + setIsToastVisible(true); + }); }; const renderCategory = () => { @@ -54,24 +62,37 @@ export function Settings() { ); }; - return ( -
-
-
- {categories.map((category) => ( - - ))} -
+ const handleToastClose = useCallback(() => { + setIsToastVisible(false); + }, []); -

{t(currentCategory)}

- {renderCategory()} -
-
+ return ( + <> +
+
+
+ {categories.map((category) => ( + + ))} +
+ +

{t(currentCategory)}

+ {renderCategory()} +
+
+ + + ); } diff --git a/src/shared/index.ts b/src/shared/index.ts index e55fc60f..c925d5b5 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -1,14 +1,3 @@ -export enum GameStatus { - Seeding = "seeding", - Downloading = "downloading", - Paused = "paused", - CheckingFiles = "checking_files", - DownloadingMetadata = "downloading_metadata", - Cancelled = "cancelled", - Decompressing = "decompressing", - Finished = "finished", -} - export enum Downloader { RealDebrid, Torrent, @@ -29,13 +18,3 @@ export const formatBytes = (bytes: number): string => { return `${Math.trunc(formatedByte * 10) / 10} ${FORMAT[base]}`; }; - -export class GameStatusHelper { - public static isDownloading(status: string | null) { - return status === "active"; - } - - public static isReady(status: string | null) { - return status === "complete"; - } -}