From c3478f4743c10e63fb7cf0f33e36ebfb0c92eca6 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Mon, 8 Jun 2026 00:30:08 +0200 Subject: [PATCH] =?UTF-8?q?fix(native):=20Gesamt-Verteilung=20als=20Half-D?= =?UTF-8?q?onut,=202=20Circles=20+=201=20Donut=20(gleiche=20Gr=C3=B6=C3=9F?= =?UTF-8?q?e)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceSlotDonut bekommt half-Modus. Reihenfolge: Mobil-Circle, Computer-Circle, Gesamt-Half-Donut (Mobil/Computer-Anteil als zwei Bögen). Alle SIZE×SIZE. Co-Authored-By: Claude Opus 4.8 --- apps/rebreak-native/app/devices.tsx | 13 ++--- .../components/devices/DeviceSlotDonut.tsx | 49 +++++++++++-------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/apps/rebreak-native/app/devices.tsx b/apps/rebreak-native/app/devices.tsx index 99dc265..0b4d27a 100644 --- a/apps/rebreak-native/app/devices.tsx +++ b/apps/rebreak-native/app/devices.tsx @@ -577,6 +577,13 @@ export default function DevicesScreen() { label={t('devices.progress_mobile')} /> + = mobileLimit + desktopLimit} label={t('devices.progress_total')} /> - diff --git a/apps/rebreak-native/components/devices/DeviceSlotDonut.tsx b/apps/rebreak-native/components/devices/DeviceSlotDonut.tsx index 6d549b9..db0a6b0 100644 --- a/apps/rebreak-native/components/devices/DeviceSlotDonut.tsx +++ b/apps/rebreak-native/components/devices/DeviceSlotDonut.tsx @@ -7,7 +7,7 @@ const SIZE = 88; const STROKE = 11; const R = (SIZE - STROKE) / 2; -/** Geräte-Kategorie-Farben — auch im Gesamt-Ring (Verteilung) verwendet. */ +/** Geräte-Kategorie-Farben — auch im Gesamt-Half-Donut (Verteilung). */ export const MOBILE_COLOR = '#22c55e'; export const DESKTOP_COLOR = '#2563eb'; @@ -26,29 +26,35 @@ function arcPath(cx: number, cy: number, r: number, startDeg: number, endDeg: nu } /** - * Voller Progress-Ring mit Mehr-Segment-Support (react-native-svg, keine Lib). - * - Einzel-Kategorie: ein Segment (Mobil/Computer). - * - Gesamt: zwei Segmente (Mobil-/Computer-Anteil farblich getrennt). - * Animiert über sweep der Bögen. + * Slot-Anzeige (react-native-svg, keine Lib), gleiche Größe in beiden Modi: + * - `half=false` (Default): voller Progress-Ring — eine Kategorie (Mobil/Computer). + * - `half=true`: Half-Donut für die Gesamt-Verteilung (Mobil-/Computer-Anteil + * als zwei farbige Bögen). */ export function DeviceSlotDonut({ segments, total, label, atLimit, + half = false, }: { segments: SlotSegment[]; total: number; label: string; atLimit: boolean; + half?: boolean; }) { const colors = useColors(); const cx = SIZE / 2; - const cy = SIZE / 2; + // Half-Donut tiefer setzen, damit der Bogen mittig im SIZE×SIZE-Feld sitzt. + const cy = half ? SIZE / 2 + R / 2 : SIZE / 2; const r = R; const safeTotal = Math.max(1, total); const used = segments.reduce((s, x) => s + x.value, 0); + const startAngle = half ? 180 : -90; + const sweep = half ? 180 : 360; + const anim = useRef(new Animated.Value(0)).current; const [progress, setProgress] = useState(0); @@ -64,10 +70,9 @@ export function DeviceSlotDonut({ return () => anim.removeListener(l); }, [used, total, anim]); - // Konsekutive Bögen, Start oben (-90°). - let cum = -90; + let cum = startAngle; const arcs = segments.map((seg) => { - const span = 360 * (seg.value / safeTotal); + const span = sweep * (seg.value / safeTotal); const start = cum; const end = cum + span; cum = end; @@ -78,19 +83,21 @@ export function DeviceSlotDonut({ - + {half ? ( + + ) : ( + + )} {arcs.map((a, i) => { const animEnd = a.start + (a.end - a.start) * progress; if (animEnd <= a.start + 0.5) return null; - // Voll-Kreis vermeiden (start==end wäre degeneriert). - const drawEnd = Math.min(animEnd, a.start + 359.99); + const drawEnd = Math.min(animEnd, a.start + (half ? 179.99 : 359.99)); return (