From 3b606659dd2f6d5e1c6a4fae958974b25eee37f7 Mon Sep 17 00:00:00 2001 From: duguyihou Date: Mon, 26 Aug 2024 07:45:13 +1000 Subject: [PATCH 1/2] feat(placeholder): add memoryCacheKey for Android --- .../java/com/turboimage/TurboImageView.kt | 2 + .../com/turboimage/TurboImageViewManager.kt | 4 ++ example/src/App.tsx | 2 + example/src/screens/DetailScreen.tsx | 40 +++++++++++++++++++ example/src/screens/SuccessScreen.tsx | 36 ++++++++++++++--- example/src/screens/routes.type.ts | 2 + src/TurboImage.tsx | 2 +- src/types.ts | 1 + 8 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 example/src/screens/DetailScreen.tsx 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>(); + return ( + + + + reference to + https://coil-kt.github.io/coil/recipes/#using-a-memory-cache-key-as-a-placeholder + + + ); +}; + +export default DetailScreen; + +const styles = StyleSheet.create({ + container: { + justifyContent: 'center', + alignItems: 'center', + }, + image: { + width: 400, + height: 400, + }, + text: { + fontSize: 18, + }, +}); diff --git a/example/src/screens/SuccessScreen.tsx b/example/src/screens/SuccessScreen.tsx index 4adc0fa..4a7b4f1 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,21 @@ 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({ + button: { + padding: 20, + fontSize: 20, + backgroundColor: 'black', + color: 'white', + textAlign: 'center', + }, +}); 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/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 = { From 3ae2782e194a06b397af392374735862bbc89b27 Mon Sep 17 00:00:00 2001 From: duguyihou Date: Mon, 26 Aug 2024 20:04:28 +1000 Subject: [PATCH 2/2] feat(placeholder): add memoryCacheKey for iOS --- example/src/screens/DetailScreen.tsx | 18 +++++++++++++++--- example/src/screens/SuccessScreen.tsx | 22 +++++++++++++++++----- ios/TurboImageView.swift | 6 ++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/example/src/screens/DetailScreen.tsx b/example/src/screens/DetailScreen.tsx index 5a2af6e..4e06e3b 100644 --- a/example/src/screens/DetailScreen.tsx +++ b/example/src/screens/DetailScreen.tsx @@ -1,4 +1,4 @@ -import { StyleSheet, Text, View } from 'react-native'; +import { Linking, Pressable, StyleSheet, Text, View } from 'react-native'; import React from 'react'; import TurboImage from 'react-native-turbo-image'; import { useRoute } from '@react-navigation/native'; @@ -8,6 +8,12 @@ const DetailScreen = () => { const { params: { memoryCacheKey }, } = useRoute>(); + + const handlePress = () => { + Linking.openURL( + 'https://coil-kt.github.io/coil/recipes/#using-a-memory-cache-key-as-a-placeholder' + ); + }; return ( { style={styles.image} /> - reference to - https://coil-kt.github.io/coil/recipes/#using-a-memory-cache-key-as-a-placeholder + use the image which is cached in memory as placholder + + reference + ); }; @@ -37,4 +45,8 @@ const styles = StyleSheet.create({ text: { fontSize: 18, }, + link: { + fontSize: 18, + color: 'blue', + }, }); diff --git a/example/src/screens/SuccessScreen.tsx b/example/src/screens/SuccessScreen.tsx index 4a7b4f1..8d20f78 100644 --- a/example/src/screens/SuccessScreen.tsx +++ b/example/src/screens/SuccessScreen.tsx @@ -41,7 +41,7 @@ const SuccessScreen = () => { }); }; return ( - + { {information?.height && height: {information?.height}} {information?.source && source: {information?.source}} {completion && Complete at {Date()}} - - Go to detail + + Go to detail ); @@ -71,11 +71,23 @@ const SuccessScreen = () => { export default SuccessScreen; const styles = StyleSheet.create({ + container: { + height: '100%', + width: '100%', + alignItems: 'center', + }, button: { - padding: 20, - fontSize: 20, + marginHorizontal: 10, + padding: 10, backgroundColor: 'black', + borderRadius: 50, color: 'white', + position: 'absolute', + bottom: 50, + }, + text: { + fontSize: 20, textAlign: 'center', + color: 'white', }, }); 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 + } } }