From b696b47febbfbd95976bc667dff723d737ec4ac4 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 10 May 2026 18:33:30 +0200 Subject: [PATCH] feat(app): SVG-Inline-Rendering via react-native-svg Co-Authored-By: Claude Opus 4.7 (1M context) --- android/package.json | 33 +++++++++++++------------- android/src/components/MessageText.tsx | 27 ++++++++++++++------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/android/package.json b/android/package.json index 39134cb..ac3d34b 100644 --- a/android/package.json +++ b/android/package.json @@ -10,31 +10,32 @@ "build:apk": "cd android && ./gradlew assembleRelease" }, "dependencies": { + "@react-native-async-storage/async-storage": "^1.21.0", + "@react-native-community/geolocation": "^3.2.1", + "@react-navigation/bottom-tabs": "^6.5.11", + "@react-navigation/native": "^6.1.9", "react": "18.2.0", "react-native": "0.73.4", - "@react-navigation/native": "^6.1.9", - "@react-navigation/bottom-tabs": "^6.5.11", - "react-native-screens": "3.27.0", - "react-native-safe-area-context": "^4.8.2", + "react-native-audio-recorder-player": "^3.6.7", + "react-native-camera-kit": "^13.0.0", "react-native-document-picker": "^9.1.1", - "react-native-sound": "^0.11.2", - "@react-native-community/geolocation": "^3.2.1", + "react-native-fs": "^2.20.0", "react-native-image-picker": "^7.1.0", "react-native-permissions": "^4.1.4", - "react-native-camera-kit": "^13.0.0", - "@react-native-async-storage/async-storage": "^1.21.0", - "react-native-fs": "^2.20.0", - "react-native-audio-recorder-player": "^3.6.7" + "react-native-safe-area-context": "^4.8.2", + "react-native-screens": "3.27.0", + "react-native-sound": "^0.11.2", + "react-native-svg": "^15.15.4" }, "devDependencies": { - "typescript": "^5.3.3", + "@react-native/eslint-config": "^0.73.2", + "@react-native/metro-config": "^0.73.5", + "@react-native/typescript-config": "^0.73.1", + "@types/jest": "^29.5.11", "@types/react": "^18.2.48", "@types/react-native": "^0.73.0", - "@react-native/eslint-config": "^0.73.2", - "@react-native/typescript-config": "^0.73.1", - "@react-native/metro-config": "^0.73.5", - "metro-react-native-babel-preset": "^0.77.0", "jest": "^29.7.0", - "@types/jest": "^29.5.11" + "metro-react-native-babel-preset": "^0.77.0", + "typescript": "^5.3.3" } } diff --git a/android/src/components/MessageText.tsx b/android/src/components/MessageText.tsx index dd4b261..11dfad2 100644 --- a/android/src/components/MessageText.tsx +++ b/android/src/components/MessageText.tsx @@ -4,25 +4,24 @@ * * - Markdown-Syntax `![alt](url)` und plain `https://...image.png` werden * erkannt — die URL bleibt im Text sichtbar (klickbar via Linkify), - * zusaetzlich wird das Bild als drunter gerendert. + * zusaetzlich wird das Bild als oder drunter gerendert. * - Wir nutzen Androids dataDetectorType="all" (System macht Phone/URL/Email * automatisch klickbar) und ein einzelnes ohne nested * mit eigenem onPress — Nested Text mit onPress fing die Long-Press- * Geste ab, damit war Markieren+Kopieren defekt. - * - SVGs werden uebersprungen (React Native Image kann SVG nicht ohne Lib). */ import React, { useEffect, useState } from 'react'; import { View, Text, Image, TextStyle, StyleProp } from 'react-native'; +import { SvgUri } from 'react-native-svg'; interface Props { text: string; style?: StyleProp; } -// Bild-URL-Pattern: http(s)://... endend auf jpg/png/gif/webp/bmp/ico (kein -// SVG — das kann RN Image ohne externe Lib nicht). -const IMG_URL_RE = /https?:\/\/[^\s)<"']+\.(?:jpe?g|png|gif|webp|bmp|ico)(?:\?[^\s)<"']*)?/gi; +// Bild-URL-Pattern: http(s)://... endend auf gaengige Bild-Endungen. +const IMG_URL_RE = /https?:\/\/[^\s)<"']+\.(?:jpe?g|png|gif|webp|bmp|ico|svg)(?:\?[^\s)<"']*)?/gi; function extractImageUrls(text: string): string[] { const urls = new Set(); @@ -31,11 +30,16 @@ function extractImageUrls(text: string): string[] { return Array.from(urls); } -/** Image mit dynamischer Aspect-Ratio aus echten Bilddimensionen. */ +const SVG_RE = /\.svg(?:\?|$)/i; + +/** Image mit dynamischer Aspect-Ratio aus echten Bilddimensionen. + * SVGs werden ueber react-native-svg gerendert (kein Image.getSize). */ const InlineImage: React.FC<{ uri: string }> = ({ uri }) => { - const [aspectRatio, setAspectRatio] = useState(16 / 9); + const isSvg = SVG_RE.test(uri); + const [aspectRatio, setAspectRatio] = useState(1); const [failed, setFailed] = useState(false); useEffect(() => { + if (isSvg) return; // Image.getSize geht fuer SVG nicht let cancelled = false; Image.getSize( uri, @@ -43,8 +47,15 @@ const InlineImage: React.FC<{ uri: string }> = ({ uri }) => { () => { if (!cancelled) setFailed(true); }, ); return () => { cancelled = true; }; - }, [uri]); + }, [uri, isSvg]); if (failed) return null; + if (isSvg) { + return ( + + setFailed(true)} /> + + ); + } return (