Fix chart label clipping, persist speed history across tabs, fix pause button
- Dynamic left padding based on measured label width (no more cut-off numbers) - Speed history ref lifted to App so chart data survives tab switches - Pause button uses optimistic UI update for instant visual feedback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ba673b9e53
commit
e6c17393fb
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.5.0",
|
"version": "1.5.1",
|
||||||
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
||||||
"main": "build/main/main/main.js",
|
"main": "build/main/main/main.js",
|
||||||
"author": "Sucukdeluxe",
|
"author": "Sucukdeluxe",
|
||||||
|
|||||||
@ -136,12 +136,12 @@ interface BandwidthChartProps {
|
|||||||
items: Record<string, DownloadItem>;
|
items: Record<string, DownloadItem>;
|
||||||
running: boolean;
|
running: boolean;
|
||||||
paused: boolean;
|
paused: boolean;
|
||||||
|
speedHistoryRef: React.MutableRefObject<{ time: number; speed: number }[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BandwidthChart = memo(function BandwidthChart({ items, running, paused }: BandwidthChartProps): ReactElement {
|
const BandwidthChart = memo(function BandwidthChart({ items, running, paused, speedHistoryRef }: BandwidthChartProps): ReactElement {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const speedHistoryRef = useRef<{ time: number; speed: number }[]>([]);
|
|
||||||
const lastUpdateRef = useRef<number>(0);
|
const lastUpdateRef = useRef<number>(0);
|
||||||
const [, forceUpdate] = useState(0);
|
const [, forceUpdate] = useState(0);
|
||||||
const animationFrameRef = useRef<number>(0);
|
const animationFrameRef = useRef<number>(0);
|
||||||
@ -162,9 +162,6 @@ const BandwidthChart = memo(function BandwidthChart({ items, running, paused }:
|
|||||||
canvas.width = width * dpr;
|
canvas.width = width * dpr;
|
||||||
canvas.height = height * dpr;
|
canvas.height = height * dpr;
|
||||||
ctx.scale(dpr, dpr);
|
ctx.scale(dpr, dpr);
|
||||||
const padding = { top: 20, right: 20, bottom: 30, left: 60 };
|
|
||||||
const chartWidth = width - padding.left - padding.right;
|
|
||||||
const chartHeight = height - padding.top - padding.bottom;
|
|
||||||
|
|
||||||
ctx.clearRect(0, 0, width, height);
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
@ -174,16 +171,6 @@ const BandwidthChart = memo(function BandwidthChart({ items, running, paused }:
|
|||||||
const accentColor = isDark ? "#38bdf8" : "#1168d9";
|
const accentColor = isDark ? "#38bdf8" : "#1168d9";
|
||||||
const fillColor = isDark ? "rgba(56, 189, 248, 0.15)" : "rgba(17, 104, 217, 0.15)";
|
const fillColor = isDark ? "rgba(56, 189, 248, 0.15)" : "rgba(17, 104, 217, 0.15)";
|
||||||
|
|
||||||
ctx.strokeStyle = gridColor;
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
for (let i = 0; i <= 5; i += 1) {
|
|
||||||
const y = padding.top + (chartHeight / 5) * i;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(padding.left, y);
|
|
||||||
ctx.lineTo(width - padding.right, y);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
const history = speedHistoryRef.current;
|
const history = speedHistoryRef.current;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const maxTime = now;
|
const maxTime = now;
|
||||||
@ -196,6 +183,28 @@ const BandwidthChart = memo(function BandwidthChart({ items, running, paused }:
|
|||||||
maxSpeed = Math.max(maxSpeed, 1024 * 1024);
|
maxSpeed = Math.max(maxSpeed, 1024 * 1024);
|
||||||
const niceMax = Math.pow(2, Math.ceil(Math.log2(maxSpeed)));
|
const niceMax = Math.pow(2, Math.ceil(Math.log2(maxSpeed)));
|
||||||
|
|
||||||
|
// Measure widest label to set dynamic left padding
|
||||||
|
ctx.font = "11px 'Manrope', sans-serif";
|
||||||
|
let maxLabelWidth = 0;
|
||||||
|
for (let i = 0; i <= 5; i += 1) {
|
||||||
|
const speedVal = niceMax * (1 - i / 5);
|
||||||
|
const w = ctx.measureText(formatSpeedMbps(speedVal)).width;
|
||||||
|
if (w > maxLabelWidth) maxLabelWidth = w;
|
||||||
|
}
|
||||||
|
const padding = { top: 20, right: 20, bottom: 30, left: Math.ceil(maxLabelWidth) + 16 };
|
||||||
|
const chartWidth = width - padding.left - padding.right;
|
||||||
|
const chartHeight = height - padding.top - padding.bottom;
|
||||||
|
|
||||||
|
ctx.strokeStyle = gridColor;
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
for (let i = 0; i <= 5; i += 1) {
|
||||||
|
const y = padding.top + (chartHeight / 5) * i;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(padding.left, y);
|
||||||
|
ctx.lineTo(width - padding.right, y);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
ctx.font = "11px 'Manrope', sans-serif";
|
ctx.font = "11px 'Manrope', sans-serif";
|
||||||
ctx.textAlign = "right";
|
ctx.textAlign = "right";
|
||||||
@ -1415,6 +1424,7 @@ export function App(): ReactElement {
|
|||||||
setContextMenu({ x, y, packageId, itemId });
|
setContextMenu({ x, y, packageId, itemId });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const speedHistoryRef = useRef<{ time: number; speed: number }[]>([]);
|
||||||
const dragSelectRef = useRef(false);
|
const dragSelectRef = useRef(false);
|
||||||
const dragAnchorRef = useRef<string | null>(null);
|
const dragAnchorRef = useRef<string | null>(null);
|
||||||
const dragDidMoveRef = useRef(false);
|
const dragDidMoveRef = useRef(false);
|
||||||
@ -1903,7 +1913,10 @@ export function App(): ReactElement {
|
|||||||
className={`ctrl-icon-btn ctrl-pause${snapshot.session.running && !snapshot.session.paused ? " active" : ""}${snapshot.session.paused ? " paused" : ""}`}
|
className={`ctrl-icon-btn ctrl-pause${snapshot.session.running && !snapshot.session.paused ? " active" : ""}${snapshot.session.paused ? " paused" : ""}`}
|
||||||
title={snapshot.session.paused ? "Fortsetzen" : "Pause"}
|
title={snapshot.session.paused ? "Fortsetzen" : "Pause"}
|
||||||
disabled={!snapshot.canPause}
|
disabled={!snapshot.canPause}
|
||||||
onClick={() => { void window.rd.togglePause(); }}
|
onClick={() => {
|
||||||
|
setSnapshot((prev) => ({ ...prev, session: { ...prev.session, paused: !prev.session.paused } }));
|
||||||
|
void window.rd.togglePause();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<svg viewBox="0 0 24 24" width="18" height="18"><rect x="5" y="3" width="4.5" height="18" rx="1" fill="currentColor" /><rect x="14.5" y="3" width="4.5" height="18" rx="1" fill="currentColor" /></svg>
|
<svg viewBox="0 0 24 24" width="18" height="18"><rect x="5" y="3" width="4.5" height="18" rx="1" fill="currentColor" /><rect x="14.5" y="3" width="4.5" height="18" rx="1" fill="currentColor" /></svg>
|
||||||
</button>
|
</button>
|
||||||
@ -2157,7 +2170,7 @@ export function App(): ReactElement {
|
|||||||
|
|
||||||
<article className="card stats-chart-card">
|
<article className="card stats-chart-card">
|
||||||
<h3>Bandbreitenverlauf</h3>
|
<h3>Bandbreitenverlauf</h3>
|
||||||
<BandwidthChart items={snapshot.session.items} running={snapshot.session.running} paused={snapshot.session.paused} />
|
<BandwidthChart items={snapshot.session.items} running={snapshot.session.running} paused={snapshot.session.paused} speedHistoryRef={speedHistoryRef} />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article className="card stats-provider-card">
|
<article className="card stats-provider-card">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user