From afcc1fe7823edbeb2ac8f016e25384c2e429a8bf Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Tue, 25 Aug 2026 05:22:42 +0200 Subject: [PATCH] fix(downloads): stabilize remaining metric updates --- src/renderer/ui/RollingMetricValue.tsx | 6 +++++- src/renderer/views/downloads/downloads-model.ts | 7 +++++-- tests/downloads-view.test.tsx | 11 ++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/renderer/ui/RollingMetricValue.tsx b/src/renderer/ui/RollingMetricValue.tsx index 7fd9e68..ba5bcaa 100644 --- a/src/renderer/ui/RollingMetricValue.tsx +++ b/src/renderer/ui/RollingMetricValue.tsx @@ -22,6 +22,10 @@ export function getRollingMetricDirection(previous: number, next: number): Rolli return "none"; } +export function shouldAnimateRollingMetric(previousValue: string, nextValue: string): boolean { + return previousValue !== nextValue; +} + export function RollingMetricValue({ numericValue, value }: RollingMetricValueProps): ReactElement { const previousRef = useRef({ numericValue, value }); const sequenceRef = useRef(0); @@ -31,8 +35,8 @@ export function RollingMetricValue({ numericValue, value }: RollingMetricValuePr useMetricLayoutEffect(() => { const previous = previousRef.current; - if (previous.value === value && previous.numericValue === numericValue) return; previousRef.current = { numericValue, value }; + if (!shouldAnimateRollingMetric(previous.value, value)) return; const direction = getRollingMetricDirection(previous.numericValue, numericValue); if (direction === "none") { setTransition(null); diff --git a/src/renderer/views/downloads/downloads-model.ts b/src/renderer/views/downloads/downloads-model.ts index 0b23678..32421fe 100644 --- a/src/renderer/views/downloads/downloads-model.ts +++ b/src/renderer/views/downloads/downloads-model.ts @@ -117,8 +117,11 @@ export function getRemainingDownloadBytes(items: Iterable): { byte } export function formatRemainingDownloadBytes(summary: { bytes: number; unknownItems: number }): string { - if (summary.unknownItems <= 0) return humanSize(summary.bytes); - return summary.bytes > 0 ? `≥ ${humanSize(summary.bytes)}` : "Unbekannt"; + const value = summary.bytes >= 1024 ** 4 + ? `${(summary.bytes / 1024 ** 4).toFixed(4)} TB` + : humanSize(summary.bytes); + if (summary.unknownItems <= 0) return value; + return summary.bytes > 0 ? `≥ ${value}` : "Unbekannt"; } export function formatRemainingDownloadTooltip(summary: { bytes: number; unknownItems: number }): string { diff --git a/tests/downloads-view.test.tsx b/tests/downloads-view.test.tsx index d669619..48274d0 100644 --- a/tests/downloads-view.test.tsx +++ b/tests/downloads-view.test.tsx @@ -69,7 +69,7 @@ import { formatHosterLabel, normalizeDownloadServiceLabel } from "../src/renderer/download-format"; -import { getRollingMetricDirection } from "../src/renderer/ui/RollingMetricValue"; +import { getRollingMetricDirection, shouldAnimateRollingMetric } from "../src/renderer/ui/RollingMetricValue"; import { SlidingSelection } from "../src/renderer/ui/SlidingSelection"; const now = new Date(2026, 7, 10, 12, 0, 0, 0).getTime(); @@ -153,6 +153,11 @@ describe("Downloadtabellen-Spalten", () => { }); describe("rollende Downloadkennzahlen", () => { + it("does not animate raw byte changes while the visible value stays unchanged", () => { + expect(shouldAnimateRollingMetric("1.111 TB", "1.111 TB")).toBe(false); + expect(shouldAnimateRollingMetric("1.111 TB", "1.110 TB")).toBe(true); + }); + it("moves increasing values up and decreasing values down", () => { expect(getRollingMetricDirection(300, 600)).toBe("up"); expect(getRollingMetricDirection(600, 300)).toBe("down"); @@ -227,6 +232,10 @@ describe("Download-Gesamtgröße", () => { }); describe("verbleibendes Downloadvolumen", () => { + it("shows a fourth TB decimal so fast downloads stay visibly responsive", () => { + expect(formatRemainingDownloadBytes({ bytes: Math.round(1.125 * 1024 ** 4), unknownItems: 0 })).toBe("1.1250 TB"); + }); + it("summiert nur offene bekannte Restbytes und klemmt überladene Fortschritte bei null", () => { const items = [ item("partial", "remaining", "downloading", { downloadedBytes: 750_000_000, totalBytes: 2_000_000_000 }),