From 09dbb9df8385caff751f2e05b2ce0580779045ef Mon Sep 17 00:00:00 2001 From: Maciej Lodygowski Date: Wed, 6 May 2026 14:42:56 +0200 Subject: [PATCH] feat: add SVG support to image preloading --- .changeset/orange-ways-invite.md | 7 + .../android/AndroidImagePreloadingScreen.tsx | 167 ++++++++++++- .../testing-grounds/ImagePreloadingScreen.tsx | 146 +++++++++++- packages/android/src/types.ts | 15 +- packages/ios/src/types.ts | 15 +- packages/voltra/.prettierignore | 5 + packages/voltra/android/build.gradle | 4 + .../src/main/java/voltra/VoltraModule.kt | 22 +- .../java/voltra/images/VoltraImageManager.kt | 223 +++++++++++++----- .../voltra/images/VoltraImageManagerTest.kt | 47 ++++ .../src/test/resources/robolectric.properties | 1 + packages/voltra/ios/Voltra.podspec | 1 + .../voltra/ios/app/VoltraImagePreload.swift | 205 +++++++++++++++- .../shared/VoltraWidgetServerFetcher.swift | 4 +- packages/voltra/src/android/preload.ts | 11 +- packages/voltra/src/preload.ts | 14 +- website/docs/android/components/visual.md | 2 +- .../android/development/image-preloading.md | 18 +- .../docs/ios/development/image-preloading.md | 16 +- website/docs/ios/development/images.md | 4 +- 20 files changed, 833 insertions(+), 94 deletions(-) create mode 100644 .changeset/orange-ways-invite.md create mode 100644 packages/voltra/.prettierignore create mode 100644 packages/voltra/android/src/test/java/voltra/images/VoltraImageManagerTest.kt create mode 100644 packages/voltra/android/src/test/resources/robolectric.properties diff --git a/.changeset/orange-ways-invite.md b/.changeset/orange-ways-invite.md new file mode 100644 index 00000000..f8d62383 --- /dev/null +++ b/.changeset/orange-ways-invite.md @@ -0,0 +1,7 @@ +--- +'@use-voltra/android': minor +'voltra': minor +'@use-voltra/ios': minor +--- + +Add SVG support to image preloading on iOS and Android. diff --git a/example/screens/android/AndroidImagePreloadingScreen.tsx b/example/screens/android/AndroidImagePreloadingScreen.tsx index ec7152fc..96d76a10 100644 --- a/example/screens/android/AndroidImagePreloadingScreen.tsx +++ b/example/screens/android/AndroidImagePreloadingScreen.tsx @@ -2,7 +2,13 @@ import { useRouter } from 'expo-router' import React, { useState } from 'react' import { Alert, ScrollView, StyleSheet, Text, View } from 'react-native' import { VoltraAndroid } from 'voltra' -import { clearPreloadedImages, preloadImages, reloadWidgets, updateAndroidWidget } from 'voltra/android/client' +import { + clearPreloadedImages, + preloadImages, + reloadWidgets, + updateAndroidWidget, + VoltraWidgetPreview, +} from 'voltra/android/client' import { Button } from '~/components/Button' import { TextInput } from '~/components/TextInput' @@ -11,12 +17,70 @@ function generateRandomUrl(): string { return `https://picsum.photos/id/${Math.floor(Math.random() * 200)}/300/200` } +const ANDROID_SVG_OPTIONS = { + green: { + key: 'android-widget-svg-test-green', + color: '#34C759', + title: 'Show Green SVG in Widget', + }, + purple: { + key: 'android-widget-svg-test-purple', + color: '#7C3AED', + title: 'Show Purple SVG in Widget', + }, +} as const + +type AndroidSvgOption = (typeof ANDROID_SVG_OPTIONS)[keyof typeof ANDROID_SVG_OPTIONS] + +function createAndroidTestSvg(color: string): string { + return ` + + + + +` +} + +function AndroidSvgWidgetContent({ assetKey, color }: { assetKey: string; color: string }) { + return ( + + + + + + + + SVG preload + + + {color} + + + + + + Preloaded SVG asset + + + + ) +} + export default function AndroidImagePreloadingScreen() { const router = useRouter() const [url, setUrl] = useState(generateRandomUrl()) const [isProcessing, setIsProcessing] = useState(false) const [assetKey] = useState('android-preload-test') const [updateCount, setUpdateCount] = useState(0) + const [isSvgProcessing, setIsSvgProcessing] = useState(false) + const [selectedSvgOption, setSelectedSvgOption] = useState(null) const handleUpdateAndPreload = async () => { if (!url.trim()) { @@ -128,6 +192,40 @@ export default function AndroidImagePreloadingScreen() { } } + const handleShowSvgWidget = async (option: AndroidSvgOption) => { + setIsSvgProcessing(true) + + try { + const result = await preloadImages([ + { + key: option.key, + svg: createAndroidTestSvg(option.color), + width: 48, + height: 48, + }, + ]) + + if (result.failed.length > 0) { + throw new Error(result.failed[0].error) + } + + await updateAndroidWidget('image_preloading', [ + { + size: { width: 300, height: 200 }, + content: , + }, + ]) + await reloadWidgets(['image_preloading']) + + setSelectedSvgOption(option) + Alert.alert('Success', 'SVG preloaded and widget updated!') + } catch (error) { + Alert.alert('Error', `Failed to update SVG widget: ${error}`) + } finally { + setIsSvgProcessing(false) + } + } + return ( @@ -165,6 +263,41 @@ export default function AndroidImagePreloadingScreen() {