1import { BlurTint, BlurView, BlurViewProps } from 'expo-blur';
2import React, { useCallback, useRef, memo, useEffect } from 'react';
3import { View, StyleSheet, Text, Image } from 'react-native';
4import Animated, {
5  useAnimatedProps,
6  useSharedValue,
7  withRepeat,
8  withSequence,
9  withTiming,
10} from 'react-native-reanimated';
11
12import useResettingState from '../../utilities/useResettingState';
13import Slider from './Slider';
14
15const AnimatedBlurView = Animated.createAnimatedComponent(BlurView);
16
17export default memo((props: { tint: BlurTint }) => {
18  const blurViewRef = useRef<View>(null);
19  const animatedIntensity = useSharedValue(0);
20  const manualIntensity = useSharedValue(0);
21  const [manualIntensityIsActive, setManualIntensityIsActive] = useResettingState(false, 3000);
22
23  const handleSliderChange = useCallback((value: number) => {
24    setManualIntensityIsActive(true);
25    manualIntensity.value = value;
26  }, []);
27
28  useEffect(() => {
29    // Use two with timing animations to make sure the animation always runs from 0 to 100
30    animatedIntensity.value = withRepeat(
31      withSequence(withTiming(100, { duration: 2000 }), withTiming(0, { duration: 2000 })),
32      -1,
33      true
34    );
35  }, []);
36
37  const animatedProps = useAnimatedProps(() => {
38    return {
39      proxiedProperties: {
40        intensity: manualIntensityIsActive ? manualIntensity.value : animatedIntensity.value,
41        tint: props.tint,
42      },
43    } as BlurViewProps;
44  });
45
46  return (
47    <View style={styles.container}>
48      <View style={styles.innerContainer}>
49        <Image style={styles.image} source={{ uri: 'https://source.unsplash.com/300x300' }} />
50        <Text style={styles.blurredText}>This text is blurred</Text>
51        <AnimatedBlurView ref={blurViewRef} style={styles.blurView} animatedProps={animatedProps}>
52          <Text style={styles.nonBlurredText}>{props.tint}</Text>
53          <Slider
54            title="Manual intensity:"
55            onChange={handleSliderChange}
56            active={!!manualIntensityIsActive}
57            value={manualIntensity.value}
58            style={styles.slider}
59          />
60        </AnimatedBlurView>
61      </View>
62    </View>
63  );
64});
65
66const styles = StyleSheet.create({
67  container: {
68    alignItems: 'center',
69    justifyContent: 'center',
70    padding: 6,
71  },
72  innerContainer: {
73    alignItems: 'center',
74    justifyContent: 'center',
75  },
76  image: {
77    width: 250,
78    height: 250,
79  },
80  blurredText: {
81    position: 'absolute',
82    padding: 10,
83    backgroundColor: 'rgb(120,20,20)',
84    color: 'white',
85    fontWeight: 'bold',
86    fontSize: 20,
87    borderRadius: 5,
88  },
89  blurView: {
90    ...StyleSheet.absoluteFillObject,
91    alignItems: 'center',
92    paddingTop: 20,
93  },
94  nonBlurredText: {
95    paddingHorizontal: 10,
96    paddingVertical: 4,
97    backgroundColor: 'rgb(120,20,20)',
98    color: 'white',
99    fontWeight: 'bold',
100    fontSize: 18,
101  },
102  slider: {
103    position: 'absolute',
104    bottom: 10,
105  },
106});
107