From 67ea9e78a2d5ba50bd588312be9af2d340971b41 Mon Sep 17 00:00:00 2001 From: Moyasee Date: Sat, 13 Dec 2025 18:14:52 +0200 Subject: [PATCH] feat: enhance download tracking by adding speed history management in download slice --- src/renderer/src/features/download-slice.ts | 17 ++++- .../src/pages/downloads/download-group.tsx | 74 +++---------------- 2 files changed, 28 insertions(+), 63 deletions(-) diff --git a/src/renderer/src/features/download-slice.ts b/src/renderer/src/features/download-slice.ts index 80d78b0d..f70421c0 100644 --- a/src/renderer/src/features/download-slice.ts +++ b/src/renderer/src/features/download-slice.ts @@ -13,6 +13,7 @@ export interface DownloadState { gamesWithDeletionInProgress: string[]; extraction: ExtractionInfo | null; peakSpeeds: Record; + speedHistory: Record; } const initialState: DownloadState = { @@ -21,6 +22,7 @@ const initialState: DownloadState = { gamesWithDeletionInProgress: [], extraction: null, peakSpeeds: {}, + speedHistory: {}, }; export const downloadSlice = createSlice({ @@ -31,13 +33,25 @@ export const downloadSlice = createSlice({ state.lastPacket = action.payload; if (!state.gameId && action.payload) state.gameId = action.payload.gameId; - // Track peak speed atomically when packet arrives + // Track peak speed and speed history atomically when packet arrives if (action.payload?.gameId && action.payload.downloadSpeed != null) { const { gameId, downloadSpeed } = action.payload; + + // Update peak speed if this is higher const currentPeak = state.peakSpeeds[gameId] || 0; if (downloadSpeed > currentPeak) { state.peakSpeeds[gameId] = downloadSpeed; } + + // Update speed history for chart + if (!state.speedHistory[gameId]) { + state.speedHistory[gameId] = []; + } + state.speedHistory[gameId].push(downloadSpeed); + // Keep only last 120 entries + if (state.speedHistory[gameId].length > 120) { + state.speedHistory[gameId].shift(); + } } }, clearDownload: (state) => { @@ -85,6 +99,7 @@ export const downloadSlice = createSlice({ }, clearPeakSpeed: (state, action: PayloadAction) => { state.peakSpeeds[action.payload] = 0; + state.speedHistory[action.payload] = []; }, }, }); diff --git a/src/renderer/src/pages/downloads/download-group.tsx b/src/renderer/src/pages/downloads/download-group.tsx index 7c3f0f77..bf6584f2 100644 --- a/src/renderer/src/pages/downloads/download-group.tsx +++ b/src/renderer/src/pages/downloads/download-group.tsx @@ -11,12 +11,10 @@ import { addMilliseconds } from "date-fns"; import { DOWNLOADER_NAME } from "@renderer/constants"; import { useAppSelector, - useAppDispatch, useDownload, useLibrary, useDate, } from "@renderer/hooks"; -import { clearPeakSpeed } from "@renderer/features"; import "./download-group.scss"; import { useTranslation } from "react-i18next"; @@ -514,9 +512,9 @@ export function DownloadGroup({ const { formatDistance } = useDate(); - const dispatch = useAppDispatch(); + // Get speed history and peak speeds from Redux (centralized state) + const speedHistory = useAppSelector((state) => state.download.speedHistory); const peakSpeeds = useAppSelector((state) => state.download.peakSpeeds); - const speedHistoryRef = useRef>({}); const [dominantColors, setDominantColors] = useState>( {} ); @@ -579,62 +577,8 @@ export function DownloadGroup({ }); }, [library, lastPacket?.gameId]); - useEffect(() => { - if (!lastPacket?.gameId || lastPacket.downloadSpeed === undefined) return; - - const gameId = lastPacket.gameId; - const downloadSpeed = lastPacket.downloadSpeed; - - if (!speedHistoryRef.current[gameId]) { - speedHistoryRef.current[gameId] = []; - } - - speedHistoryRef.current[gameId].push(downloadSpeed); - - if (speedHistoryRef.current[gameId].length > 120) { - speedHistoryRef.current[gameId].shift(); - } - }, [lastPacket]); - - useEffect(() => { - for (const game of library) { - if ( - game.download && - game.download.progress < 0.01 && - game.download.status !== "paused" - ) { - // Fresh download - clear any old data - if (speedHistoryRef.current[game.id]?.length > 0) { - speedHistoryRef.current[game.id] = []; - dispatch(clearPeakSpeed(game.id)); - } - } - } - }, [library, dispatch]); - - useEffect(() => { - const timeouts: NodeJS.Timeout[] = []; - - for (const game of library) { - if ( - game.download?.progress === 1 && - speedHistoryRef.current[game.id]?.length > 0 - ) { - const gameId = game.id; - const timeout = setTimeout(() => { - speedHistoryRef.current[gameId] = []; - dispatch(clearPeakSpeed(gameId)); - }, 10_000); - timeouts.push(timeout); - } - } - - return () => { - for (const timeout of timeouts) { - clearTimeout(timeout); - } - }; - }, [library, dispatch]); + // Speed history and peak speeds are now tracked in Redux (in setLastPacket reducer) + // No local effect needed - data is updated atomically when packets arrive useEffect(() => { if (library.length > 0 && title === t("download_in_progress")) { @@ -839,7 +783,13 @@ export function DownloadGroup({ ? (lastPacket?.downloadSpeed ?? 0) : 0; const finalDownloadSize = getFinalDownloadSize(game); - const peakSpeed = peakSpeeds[game.id] || 0; + // Use lastPacket.gameId for lookup since that's the key used to store the data + // Fall back to game.id if lastPacket is not available + const dataKey = lastPacket?.gameId ?? game.id; + const gameSpeedHistory = speedHistory[dataKey] ?? []; + const storedPeak = peakSpeeds[dataKey]; + // Use stored peak if available and > 0, otherwise use current speed as initial value + const peakSpeed = storedPeak !== undefined && storedPeak > 0 ? storedPeak : downloadSpeed; let currentProgress = game.download?.progress || 0; if (isGameExtracting) { @@ -861,7 +811,7 @@ export function DownloadGroup({ currentProgress={currentProgress} dominantColor={dominantColor} lastPacket={lastPacket} - speedHistory={speedHistoryRef.current[game.id] || []} + speedHistory={gameSpeedHistory} formatSpeed={formatSpeed} calculateETA={calculateETA} pauseDownload={pauseDownload}