diff --git a/android/src/main/java/com/turboimage/TurboImageView.kt b/android/src/main/java/com/turboimage/TurboImageView.kt index ba2d753..7ecc19c 100644 --- a/android/src/main/java/com/turboimage/TurboImageView.kt +++ b/android/src/main/java/com/turboimage/TurboImageView.kt @@ -51,6 +51,8 @@ class TurboImageView(private val reactContext: ThemedReactContext) : } } + var memoryCacheKey: String? = null + val circleProgressDrawable: CircularProgressDrawable? get() { indicator.let { diff --git a/android/src/main/java/com/turboimage/TurboImageViewManager.kt b/android/src/main/java/com/turboimage/TurboImageViewManager.kt index 799ab1f..c2c6a58 100644 --- a/android/src/main/java/com/turboimage/TurboImageViewManager.kt +++ b/android/src/main/java/com/turboimage/TurboImageViewManager.kt @@ -94,6 +94,9 @@ class TurboImageViewManager : SimpleViewManager() { placeholder( view.thumbhashDrawable ?: view.blurhashDrawable ?: view.circleProgressDrawable ) + view.memoryCacheKey?.let { + placeholderMemoryCacheKey(it) + } transformations(view.transformations) crossfade(view.crossfade ?: defaultCrossfade) view.showPlaceholderOnFailure?.let { @@ -119,6 +122,7 @@ class TurboImageViewManager : SimpleViewManager() { fun setPlaceholder(view: TurboImageView, placeholder: ReadableMap?) { view.blurhash = placeholder?.getString("blurhash") view.thumbhash = placeholder?.getString("thumbhash") + view.memoryCacheKey = placeholder?.getString("memoryCacheKey") } @ReactProp(name = "showPlaceholderOnFailure") diff --git a/example/src/App.tsx b/example/src/App.tsx index 4d7effb..ef21653 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -15,6 +15,7 @@ import PrefetchScreen from './screens/PrefetchScreen'; import PlaceholderScreen from './screens/PlaceholderScreen'; import LiveTextScreen from './screens/LiveTextScreen'; import APNGScreen from './screens/APNGScreen'; +import DetailScreen from './screens/DetailScreen'; const Stack = createNativeStackNavigator(); @@ -43,6 +44,7 @@ function App() { + { + const { + params: { memoryCacheKey }, + } = useRoute>(); + + const handlePress = () => { + Linking.openURL( + 'https://coil-kt.github.io/coil/recipes/#using-a-memory-cache-key-as-a-placeholder' + ); + }; + return ( + + + + use the image which is cached in memory as placholder + + + reference + + + ); +}; + +export default DetailScreen; + +const styles = StyleSheet.create({ + container: { + justifyContent: 'center', + alignItems: 'center', + }, + image: { + width: 400, + height: 400, + }, + text: { + fontSize: 18, + }, + link: { + fontSize: 18, + color: 'blue', + }, +}); diff --git a/example/src/screens/SuccessScreen.tsx b/example/src/screens/SuccessScreen.tsx index 4adc0fa..8d20f78 100644 --- a/example/src/screens/SuccessScreen.tsx +++ b/example/src/screens/SuccessScreen.tsx @@ -1,7 +1,15 @@ -import { Text, View, type NativeSyntheticEvent } from 'react-native'; +import { + Pressable, + StyleSheet, + Text, + View, + type NativeSyntheticEvent, +} from 'react-native'; import React, { useState } from 'react'; import Card from '../components/Card'; import type { Success, TaskState } from 'react-native-turbo-image'; +import { useNavigation } from '@react-navigation/native'; +import { RouteName, type HomeStackNavigationProps } from './routes.type'; type Information = { width: number; @@ -16,6 +24,7 @@ const SuccessScreen = () => { const handleSuccess = ({ nativeEvent }: NativeSyntheticEvent) => { setInformation(nativeEvent); }; + const navigation = useNavigation(); const handleStart = ({ nativeEvent }: NativeSyntheticEvent) => { setStart(nativeEvent.state === 'running'); @@ -26,18 +35,22 @@ const SuccessScreen = () => { }: NativeSyntheticEvent) => { setCompletion(nativeEvent.state === 'completed'); }; - + const navigateToDetailScreen = () => { + navigation.navigate(RouteName.Detail, { + memoryCacheKey: 'https://placedog.net/100/100?id=121', + }); + }; return ( - + console.log(nativeEvent.error)} placeholder={{ blurhash: 'UBIr4u9}00Rj?yEzxu%LIQ%1%6xt-ks,tAIU', }} @@ -48,8 +61,33 @@ const SuccessScreen = () => { {information?.height && height: {information?.height}} {information?.source && source: {information?.source}} {completion && Complete at {Date()}} + + Go to detail + ); }; export default SuccessScreen; + +const styles = StyleSheet.create({ + container: { + height: '100%', + width: '100%', + alignItems: 'center', + }, + button: { + marginHorizontal: 10, + padding: 10, + backgroundColor: 'black', + borderRadius: 50, + color: 'white', + position: 'absolute', + bottom: 50, + }, + text: { + fontSize: 20, + textAlign: 'center', + color: 'white', + }, +}); diff --git a/example/src/screens/routes.type.ts b/example/src/screens/routes.type.ts index 58e39e4..a6af2d2 100644 --- a/example/src/screens/routes.type.ts +++ b/example/src/screens/routes.type.ts @@ -18,6 +18,7 @@ export type HomeStackParamList = { SVG: undefined; Gif: undefined; APNG: undefined; + Detail: { memoryCacheKey: string }; }; export type HomeStackProps = NativeStackScreenProps; @@ -44,4 +45,5 @@ export enum RouteName { SVG = 'SVG', Gif = 'Gif', APNG = 'APNG', + Detail = 'Detail', } diff --git a/ios/TurboImageView.swift b/ios/TurboImageView.swift index ea8ef4e..b40f78c 100644 --- a/ios/TurboImageView.swift +++ b/ios/TurboImageView.swift @@ -99,6 +99,12 @@ final class TurboImageView : UIView { } } } + + if let memoryCacheKey = placeholder.value(forKey: "memoryCacheKey") as? String { + let request = ImageRequest(url: URL(string: memoryCacheKey)) + let memoryCachedImage = ImagePipeline.shared.cache.cachedImage(for: request, caches: .memory)?.image + lazyImageView.placeholderImage = memoryCachedImage + } } } diff --git a/src/TurboImage.tsx b/src/TurboImage.tsx index 0f98959..6d2843b 100644 --- a/src/TurboImage.tsx +++ b/src/TurboImage.tsx @@ -52,7 +52,7 @@ const TurboImageView = forwardRef( ...restProps } = props; if (placeholder && Object.keys(placeholder).length > 1) { - throw new Error('Choose one hash string, either thumbhash or blurhash'); + throw new Error('Choose only one placeholder'); } const processedIndicator = diff --git a/src/types.ts b/src/types.ts index e822a9b..74c3a54 100644 --- a/src/types.ts +++ b/src/types.ts @@ -28,6 +28,7 @@ type State = 'running' | 'cancelled' | 'completed'; export type Placeholder = { blurhash: string; thumbhash: string; + memoryCacheKey: string; }; export type TaskState = {