Skip to content

Commit

Permalink
feat(placeholder): add memoryCacheKey (#325)
Browse files Browse the repository at this point in the history
* feat(placeholder): add memoryCacheKey for Android

* feat(placeholder): add memoryCacheKey for iOS
  • Loading branch information
duguyihou committed Aug 26, 2024
1 parent 7331355 commit 856e128
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 7 deletions.
2 changes: 2 additions & 0 deletions android/src/main/java/com/turboimage/TurboImageView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class TurboImageView(private val reactContext: ThemedReactContext) :
}
}

var memoryCacheKey: String? = null

val circleProgressDrawable: CircularProgressDrawable?
get() {
indicator.let {
Expand Down
4 changes: 4 additions & 0 deletions android/src/main/java/com/turboimage/TurboImageViewManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class TurboImageViewManager : SimpleViewManager<TurboImageView>() {
placeholder(
view.thumbhashDrawable ?: view.blurhashDrawable ?: view.circleProgressDrawable
)
view.memoryCacheKey?.let {
placeholderMemoryCacheKey(it)
}
transformations(view.transformations)
crossfade(view.crossfade ?: defaultCrossfade)
view.showPlaceholderOnFailure?.let {
Expand All @@ -119,6 +122,7 @@ class TurboImageViewManager : SimpleViewManager<TurboImageView>() {
fun setPlaceholder(view: TurboImageView, placeholder: ReadableMap?) {
view.blurhash = placeholder?.getString("blurhash")
view.thumbhash = placeholder?.getString("thumbhash")
view.memoryCacheKey = placeholder?.getString("memoryCacheKey")
}

@ReactProp(name = "showPlaceholderOnFailure")
Expand Down
2 changes: 2 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HomeStackParamList>();

Expand Down Expand Up @@ -43,6 +44,7 @@ function App() {
<Stack.Group>
<Stack.Screen name={RouteName.Success} component={SuccessScreen} />
<Stack.Screen name={RouteName.Failure} component={FailureScreen} />
<Stack.Screen name={RouteName.Detail} component={DetailScreen} />
</Stack.Group>
<Stack.Screen
name={RouteName.ImageProcessing}
Expand Down
52 changes: 52 additions & 0 deletions example/src/screens/DetailScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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';
import type { HomeRouteType, RouteName } from './routes.type';

const DetailScreen = () => {
const {
params: { memoryCacheKey },
} = useRoute<HomeRouteType<RouteName.Detail>>();

const handlePress = () => {
Linking.openURL(
'https://coil-kt.github.io/coil/recipes/#using-a-memory-cache-key-as-a-placeholder'
);
};
return (
<View style={styles.container}>
<TurboImage
source={{ uri: 'https://placedog.net/400/400?id=121' }}
placeholder={{ memoryCacheKey }}
style={styles.image}
/>
<Text style={styles.text}>
use the image which is cached in memory as placholder
</Text>
<Pressable onPress={handlePress}>
<Text style={styles.link}>reference</Text>
</Pressable>
</View>
);
};

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',
},
});
50 changes: 44 additions & 6 deletions example/src/screens/SuccessScreen.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -16,6 +24,7 @@ const SuccessScreen = () => {
const handleSuccess = ({ nativeEvent }: NativeSyntheticEvent<Success>) => {
setInformation(nativeEvent);
};
const navigation = useNavigation<HomeStackNavigationProps>();

const handleStart = ({ nativeEvent }: NativeSyntheticEvent<TaskState>) => {
setStart(nativeEvent.state === 'running');
Expand All @@ -26,18 +35,22 @@ const SuccessScreen = () => {
}: NativeSyntheticEvent<TaskState>) => {
setCompletion(nativeEvent.state === 'completed');
};

const navigateToDetailScreen = () => {
navigation.navigate(RouteName.Detail, {
memoryCacheKey: 'https://placedog.net/100/100?id=121',
});
};
return (
<View>
<View style={styles.container}>
<Card
source={{
uri: 'https://placedog.net/300/300?id=121',
uri: 'https://placedog.net/100/100?id=121',
}}
style={{ width: 200, height: 200 }}
resize={200}
style={{ width: 100, height: 100 }}

Check warning on line 49 in example/src/screens/SuccessScreen.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { width: 100, height: 100 }
onStart={handleStart}
onSuccess={handleSuccess}
onCompletion={handleCompletion}
onFailure={({ nativeEvent }) => console.log(nativeEvent.error)}
placeholder={{
blurhash: 'UBIr4u9}00Rj?yEzxu%LIQ%1%6xt-ks,tAIU',
}}
Expand All @@ -48,8 +61,33 @@ const SuccessScreen = () => {
{information?.height && <Text>height: {information?.height}</Text>}
{information?.source && <Text>source: {information?.source}</Text>}
{completion && <Text>Complete at {Date()}</Text>}
<Pressable style={styles.button} onPress={navigateToDetailScreen}>
<Text style={styles.text}>Go to detail</Text>
</Pressable>
</View>
);
};

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',
},
});
2 changes: 2 additions & 0 deletions example/src/screens/routes.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type HomeStackParamList = {
SVG: undefined;
Gif: undefined;
APNG: undefined;
Detail: { memoryCacheKey: string };
};

export type HomeStackProps = NativeStackScreenProps<HomeStackParamList>;
Expand All @@ -44,4 +45,5 @@ export enum RouteName {
SVG = 'SVG',
Gif = 'Gif',
APNG = 'APNG',
Detail = 'Detail',
}
6 changes: 6 additions & 0 deletions ios/TurboImageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/TurboImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type State = 'running' | 'cancelled' | 'completed';
export type Placeholder = {
blurhash: string;
thumbhash: string;
memoryCacheKey: string;
};

export type TaskState = {
Expand Down

0 comments on commit 856e128

Please sign in to comment.