1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
import { useEffect } from "react";
import { View } from "react-native";
import Animated, {
Easing,
FadeIn,
useAnimatedStyle,
useSharedValue,
withDelay,
withRepeat,
withSequence,
withTiming,
} from "react-native-reanimated";
import { Text } from "@/components/ui/Text";
import { Archive } from "lucide-react-native";
export default function LoadingAnimation() {
const scale = useSharedValue(1);
const rotation = useSharedValue(0);
const opacity = useSharedValue(0.6);
const dotOpacity1 = useSharedValue(0);
const dotOpacity2 = useSharedValue(0);
const dotOpacity3 = useSharedValue(0);
useEffect(() => {
scale.value = withRepeat(
withSequence(
withTiming(1.1, { duration: 800, easing: Easing.inOut(Easing.ease) }),
withTiming(1, { duration: 800, easing: Easing.inOut(Easing.ease) }),
),
-1,
false,
);
rotation.value = withRepeat(
withSequence(
withTiming(-5, { duration: 400, easing: Easing.inOut(Easing.ease) }),
withTiming(5, { duration: 800, easing: Easing.inOut(Easing.ease) }),
withTiming(0, { duration: 400, easing: Easing.inOut(Easing.ease) }),
),
-1,
false,
);
opacity.value = withRepeat(
withSequence(
withTiming(1, { duration: 800 }),
withTiming(0.6, { duration: 800 }),
),
-1,
false,
);
dotOpacity1.value = withRepeat(
withSequence(
withTiming(1, { duration: 300 }),
withDelay(900, withTiming(0, { duration: 0 })),
),
-1,
);
dotOpacity2.value = withDelay(
300,
withRepeat(
withSequence(
withTiming(1, { duration: 300 }),
withDelay(600, withTiming(0, { duration: 0 })),
),
-1,
),
);
dotOpacity3.value = withDelay(
600,
withRepeat(
withSequence(
withTiming(1, { duration: 300 }),
withDelay(300, withTiming(0, { duration: 0 })),
),
-1,
),
);
}, []);
const iconStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }, { rotate: `${rotation.value}deg` }],
opacity: opacity.value,
}));
const dot1Style = useAnimatedStyle(() => ({ opacity: dotOpacity1.value }));
const dot2Style = useAnimatedStyle(() => ({ opacity: dotOpacity2.value }));
const dot3Style = useAnimatedStyle(() => ({ opacity: dotOpacity3.value }));
return (
<Animated.View
entering={FadeIn.duration(300)}
className="items-center gap-6"
>
<Animated.View
style={iconStyle}
className="h-24 w-24 items-center justify-center rounded-full bg-primary/10"
>
<Archive size={48} className="text-primary" strokeWidth={1.5} />
</Animated.View>
<View className="flex-row items-baseline">
<Text variant="title1" className="font-semibold text-foreground">
Hoarding
</Text>
<View className="w-8 flex-row">
<Animated.Text style={dot1Style} className="text-xl text-foreground">
.
</Animated.Text>
<Animated.Text style={dot2Style} className="text-xl text-foreground">
.
</Animated.Text>
<Animated.Text style={dot3Style} className="text-xl text-foreground">
.
</Animated.Text>
</View>
</View>
</Animated.View>
);
}
|