From cc38be4383c5ba15046cbda060693cbfce290b13 Mon Sep 17 00:00:00 2001 From: ctrlcat0x Date: Sat, 15 Nov 2025 11:31:39 +0530 Subject: [PATCH] Fixed linter and sonarcloud errors, refactored some functions and fixed UI padding issues with certain themes. --- .../src/pages/downloads/download-group.scss | 27 +- .../src/pages/downloads/download-group.tsx | 527 ++++++++++-------- 2 files changed, 323 insertions(+), 231 deletions(-) diff --git a/src/renderer/src/pages/downloads/download-group.scss b/src/renderer/src/pages/downloads/download-group.scss index 0891e682..4f2a6316 100644 --- a/src/renderer/src/pages/downloads/download-group.scss +++ b/src/renderer/src/pages/downloads/download-group.scss @@ -5,7 +5,15 @@ flex-direction: column; gap: calc(globals.$spacing-unit * 2); margin-inline: calc(globals.$spacing-unit * 3); - margin-bottom: calc(globals.$spacing-unit * 4); + padding-block: calc(globals.$spacing-unit * 3); + + &--queued { + padding-bottom: 0; + } + + &--completed { + padding-top: 0; + } &__header { display: flex; @@ -29,7 +37,7 @@ overflow: hidden; margin: 0; padding: 0; - margin-bottom: calc(globals.$spacing-unit * 3); + padding-bottom: calc(globals.$spacing-unit * 3); } &__hero-background { @@ -57,8 +65,8 @@ background: linear-gradient( to bottom, rgba(0, 0, 0, 0.3) 0%, - rgba(0, 0, 0, 1) 70%, - rgb(27, 27, 27) 100% + rgb(5, 5, 5) 70%, + rgb(26, 26, 26) 100% ); } @@ -85,7 +93,6 @@ max-width: 600px; max-height: 200px; object-fit: contain; - filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.8)); } h1 { @@ -113,7 +120,11 @@ &__hero-menu-btn { background-color: rgba(0, 0, 0, 0.4); - padding: calc(globals.$spacing-unit); + padding: calc(globals.$spacing-unit * 1); + min-height: unset; + } + &__hero-menu-btn:hover { + background-color: rgba(0, 0, 0, 0.8); } &__hero-progress { @@ -320,6 +331,10 @@ &__simple-actions { flex-shrink: 0; + display: flex; + justify-content: center; + align-items: center; + gap: calc(globals.$spacing-unit); } &__simple-menu-btn { diff --git a/src/renderer/src/pages/downloads/download-group.tsx b/src/renderer/src/pages/downloads/download-group.tsx index b70fbc5b..3f9c50ea 100644 --- a/src/renderer/src/pages/downloads/download-group.tsx +++ b/src/renderer/src/pages/downloads/download-group.tsx @@ -37,9 +37,9 @@ const getProgressGradient = ( if (!hex.startsWith("#")) return undefined; try { - const r = parseInt(hex.slice(1, 3), 16); - const g = parseInt(hex.slice(3, 5), 16); - const b = parseInt(hex.slice(5, 7), 16); + const r = Number.parseInt(hex.slice(1, 3), 16); + const g = Number.parseInt(hex.slice(3, 5), 16); + const b = Number.parseInt(hex.slice(5, 7), 16); return `linear-gradient(90deg, rgba(${r},${g},${b},0.95) 0%, rgba(${r},${g},${b},0.65) 100%)`; } catch { return undefined; @@ -56,7 +56,7 @@ function SpeedChart({ speeds, peakSpeed, color = "rgba(255, 255, 255, 1)", -}: SpeedChartProps) { +}: Readonly) { const canvasRef = useRef(null); useEffect(() => { @@ -91,28 +91,28 @@ function SpeedChart({ b = 255; if (color.startsWith("#")) { const hex = color.replace("#", ""); - r = parseInt(hex.substring(0, 2), 16); - g = parseInt(hex.substring(2, 4), 16); - b = parseInt(hex.substring(4, 6), 16); + r = Number.parseInt(hex.substring(0, 2), 16); + g = Number.parseInt(hex.substring(2, 4), 16); + b = Number.parseInt(hex.substring(4, 6), 16); } else if (color.startsWith("rgb")) { const matches = color.match(/\d+/g); if (matches && matches.length >= 3) { - r = parseInt(matches[0]); - g = parseInt(matches[1]); - b = parseInt(matches[2]); + r = Number.parseInt(matches[0]); + g = Number.parseInt(matches[1]); + b = Number.parseInt(matches[2]); } } + const displaySpeeds = speeds.slice(-totalBars); for (let i = 0; i < totalBars; i++) { const x = i * barSpacing; - ctx.fillStyle = "rgba(255, 255, 255, 0.08)"; ctx.beginPath(); ctx.roundRect(x, 0, barWidth, height, 3); ctx.fill(); - if (i < speeds.length) { - const speed = speeds[i] || 0; + if (i < displaySpeeds.length) { + const speed = displaySpeeds[i] || 0; const filledHeight = (speed / maxHeight) * height; if (filledHeight > 0) { @@ -133,14 +133,13 @@ function SpeedChart({ } } } + animationFrameId = requestAnimationFrame(draw); }; animationFrameId = requestAnimationFrame(draw); return () => { - if (animationFrameId) { - cancelAnimationFrame(animationFrameId); - } + cancelAnimationFrame(animationFrameId); }; }, [speeds, peakSpeed, color]); @@ -149,6 +148,201 @@ function SpeedChart({ ); } +interface HeroDownloadViewProps { + game: LibraryGame; + isGameDownloading: boolean; + downloadSpeed: number; + finalDownloadSize: string; + peakSpeed: number; + currentProgress: number; + dominantColor: string; + lastPacket: ReturnType["lastPacket"]; + speedHistory: number[]; + getGameActions: (game: LibraryGame) => DropdownMenuItem[]; + getStatusText: (game: LibraryGame) => string; + formatSpeed: (speed: number) => string; + calculateETA: () => string; + pauseDownload: (shop: GameShop, objectId: string) => void; + resumeDownload: (shop: GameShop, objectId: string) => void; + t: (key: string) => string; +} + +function HeroDownloadView({ + game, + isGameDownloading, + downloadSpeed, + finalDownloadSize, + peakSpeed, + currentProgress, + dominantColor, + lastPacket, + speedHistory, + getGameActions, + getStatusText, + formatSpeed, + calculateETA, + pauseDownload, + resumeDownload, + t, +}: Readonly) { + return ( +
+
+ {game.title} +
+
+ +
+
+
+ + + +
+
+ +
+
+ {game.logoImageUrl ? ( + {game.title} + ) : ( +

{game.title}

+ )} +
+ + {isGameDownloading ? ( + + ) : ( + + )} +
+ +
+
+ + {getStatusText(game)} + + + {formatDownloadProgress(currentProgress)} + +
+
+
+
+
+ + {isGameDownloading && lastPacket + ? `${formatBytes(lastPacket.download.bytesDownloaded)} / ${finalDownloadSize}` + : `0 B / ${finalDownloadSize}`} + + + {isGameDownloading && + lastPacket?.timeRemaining && + lastPacket.timeRemaining > 0 + ? calculateETA() + : ""} + +
+
+ +
+
+
+ + + +
+ + {t("network")}: + + + {isGameDownloading ? formatSpeed(downloadSpeed) : "0 B/s"} + +
+
+ +
+ + + +
+ {t("peak")}: + + {peakSpeed > 0 ? formatSpeed(peakSpeed) : "0 B/s"} + +
+
+ + {game.download?.downloader === Downloader.Torrent && + isGameDownloading && + lastPacket && + (lastPacket.numSeeds > 0 || lastPacket.numPeers > 0) && ( +
+
+ + Seeds:{" "} + + {lastPacket.numSeeds} + + , Peers:{" "} + + {lastPacket.numPeers} + + +
+
+ )} +
+ +
+ +
+
+
+
+ ); +} + export interface DownloadGroupProps { library: LibraryGame[]; title: string; @@ -219,14 +413,14 @@ export function DownloadGroup({ speedHistoryRef.current[gameId].push(lastPacket.downloadSpeed); - if (speedHistoryRef.current[gameId].length > 60) { + if (speedHistoryRef.current[gameId].length > 120) { speedHistoryRef.current[gameId].shift(); } } }, [lastPacket?.gameId, lastPacket?.downloadSpeed]); useEffect(() => { - library.forEach((game) => { + for (const game of library) { if ( game.download && game.download.progress < 0.01 && @@ -238,13 +432,13 @@ export function DownloadGroup({ peakSpeedsRef.current[game.id] = 0; } } - }); + } }, [library]); useEffect(() => { const timeouts: NodeJS.Timeout[] = []; - library.forEach((game) => { + for (const game of library) { if ( game.download?.progress === 1 && speedHistoryRef.current[game.id]?.length > 0 @@ -255,10 +449,12 @@ export function DownloadGroup({ }, 10_000); timeouts.push(timeout); } - }); + } return () => { - timeouts.forEach((timeout) => clearTimeout(timeout)); + for (const timeout of timeouts) { + clearTimeout(timeout); + } }; }, [library]); @@ -275,15 +471,15 @@ export function DownloadGroup({ const isGameSeeding = (game: LibraryGame) => { const entry = seedingStatus.find((s) => s.gameId === game.id); - if (entry && entry.status) return entry.status === "seeding"; + if (entry?.status) return entry.status === "seeding"; return game.download?.status === "seeding"; }; const isGameDownloadingMap = useMemo(() => { const map: Record = {}; - library.forEach((game) => { + for (const game of library) { map[game.id] = lastPacket?.gameId === game.id; - }); + } return map; }, [library, lastPacket?.gameId]); @@ -306,17 +502,29 @@ export function DownloadGroup({ }; const calculateETA = () => { - if (!lastPacket || lastPacket.timeRemaining < 0) return ""; - - try { - return formatDistance( - addMilliseconds(new Date(), lastPacket.timeRemaining), - new Date(), - { addSuffix: true } - ); - } catch (err) { + if ( + !lastPacket || + lastPacket.timeRemaining < 0 || + !Number.isFinite(lastPacket.timeRemaining) + ) { return ""; } + + return formatDistance( + addMilliseconds(new Date(), lastPacket.timeRemaining), + new Date(), + { addSuffix: true } + ); + }; + + const getCompletedStatusText = (game: LibraryGame) => { + const isTorrent = game.download?.downloader === Downloader.Torrent; + if (isTorrent) { + return isGameSeeding(game) + ? `${t("completed")} (${t("seeding")})` + : `${t("completed")} (${t("paused")})`; + } + return t("completed"); }; const getStatusText = (game: LibraryGame) => { @@ -332,14 +540,7 @@ export function DownloadGroup({ } if (game.download?.progress === 1) { - const isTorrent = game.download?.downloader === Downloader.Torrent; - if (isTorrent) { - if (isGameSeeding(game)) { - return `${t("completed")} (${t("seeding")})`; - } - return `${t("completed")} (${t("paused")})`; - } - return t("completed"); + return getCompletedStatusText(game); } if (isGameDownloading && lastPacket) { @@ -352,17 +553,15 @@ export function DownloadGroup({ return t("download_in_progress"); } - if (status === "paused") { - return t("paused"); + switch (status) { + case "paused": + case "error": + return t("paused"); + case "waiting": + return t("calculating_eta"); + default: + return t("paused"); } - if (status === "waiting") { - return t("calculating_eta"); - } - if (status === "error") { - return t("paused"); - } - - return t("paused"); }; const extractGameDownload = useCallback( @@ -475,10 +674,22 @@ export function DownloadGroup({ ]; }; + const downloadInfo = useMemo( + () => + library.map((game) => ({ + game, + size: getFinalDownloadSize(game), + progress: game.download?.progress || 0, + isSeeding: isGameSeeding(game), + })), + [library, lastPacket?.gameId] + ); + if (!library.length) return null; const isDownloadingGroup = title === t("download_in_progress"); const isQueuedGroup = title === t("queued_downloads"); + const isCompletedGroup = title === t("downloads_completed"); if (isDownloadingGroup && library.length > 0) { const game = library[0]; @@ -496,183 +707,31 @@ export function DownloadGroup({ const dominantColor = dominantColors[game.id] || "#fff"; return ( - <> -
-
- {game.title} -
-
- -
-
-
- - - -
-
- -
-
- {game.logoImageUrl ? ( - {game.title} - ) : ( -

{game.title}

- )} -
- - {isGameDownloading ? ( - - ) : ( - - )} -
- -
-
- - {getStatusText(game)} - - - {formatDownloadProgress(currentProgress)} - -
-
-
-
-
- - {isGameDownloading && lastPacket - ? `${formatBytes(lastPacket.download.bytesDownloaded)} / ${finalDownloadSize}` - : `0 B / ${finalDownloadSize}`} - - - {isGameDownloading && - lastPacket?.timeRemaining && - lastPacket.timeRemaining > 0 - ? calculateETA() - : ""} - -
-
- -
-
-
- - - -
- - {t("network")}: - - - {isGameDownloading ? formatSpeed(downloadSpeed) : "0 B/s"} - -
-
- -
- - - -
- - {t("peak")}: - - - {peakSpeed > 0 ? formatSpeed(peakSpeed) : "0 B/s"} - -
-
- - {game.download?.downloader === Downloader.Torrent && - isGameDownloading && - lastPacket && - (lastPacket.numSeeds > 0 || lastPacket.numPeers > 0) && ( -
-
- - Seeds:{" "} - - {lastPacket.numSeeds} - - , Peers:{" "} - - {lastPacket.numPeers} - - -
-
- )} -
- -
- -
-
-
-
- + ); } - const downloadInfo = useMemo( - () => - library.map((game) => ({ - game, - size: getFinalDownloadSize(game), - progress: game.download?.progress || 0, - isSeeding: isGameSeeding(game), - })), - [library, lastPacket?.gameId] - ); - return ( -
+

{title}

@@ -718,6 +777,24 @@ export function DownloadGroup({ )}
+ {game.download?.progress === 1 ? ( + + ) : isQueuedGroup ? ( + + ) : null}