forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {View} from 'react-native'
2import Animated, {
3 Keyframe,
4 LayoutAnimationConfig,
5 useReducedMotion,
6} from 'react-native-reanimated'
7
8import {s} from '#/lib/styles'
9import {useTheme} from '#/alf'
10import {
11 Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
12 Heart2_Stroke2_Corner0_Rounded as HeartIconOutline,
13} from '#/components/icons/Heart2'
14
15const keyframe = new Keyframe({
16 0: {
17 transform: [{scale: 1}],
18 },
19 10: {
20 transform: [{scale: 0.7}],
21 },
22 40: {
23 transform: [{scale: 1.2}],
24 },
25 100: {
26 transform: [{scale: 1}],
27 },
28})
29
30const circle1Keyframe = new Keyframe({
31 0: {
32 opacity: 0,
33 transform: [{scale: 0}],
34 },
35 10: {
36 opacity: 0.4,
37 },
38 40: {
39 transform: [{scale: 1.5}],
40 },
41 95: {
42 opacity: 0.4,
43 },
44 100: {
45 opacity: 0,
46 transform: [{scale: 1.5}],
47 },
48})
49
50const circle2Keyframe = new Keyframe({
51 0: {
52 opacity: 0,
53 transform: [{scale: 0}],
54 },
55 10: {
56 opacity: 1,
57 },
58 40: {
59 transform: [{scale: 0}],
60 },
61 95: {
62 opacity: 1,
63 },
64 100: {
65 opacity: 0,
66 transform: [{scale: 1.5}],
67 },
68})
69
70export function AnimatedLikeIcon({
71 isLiked,
72 big,
73 hasBeenToggled,
74}: {
75 isLiked: boolean
76 big?: boolean
77 hasBeenToggled: boolean
78}) {
79 const t = useTheme()
80 const size = big ? 22 : 18
81 const shouldAnimate = !useReducedMotion() && hasBeenToggled
82
83 return (
84 <View>
85 <LayoutAnimationConfig skipEntering>
86 {isLiked ? (
87 <Animated.View
88 entering={shouldAnimate ? keyframe.duration(300) : undefined}>
89 <HeartIconFilled style={s.likeColor} width={size} />
90 </Animated.View>
91 ) : (
92 <HeartIconOutline
93 style={[{color: t.palette.contrast_500}, {pointerEvents: 'none'}]}
94 width={size}
95 />
96 )}
97 {isLiked && shouldAnimate ? (
98 <>
99 <Animated.View
100 entering={circle1Keyframe.duration(300)}
101 style={{
102 position: 'absolute',
103 backgroundColor: s.likeColor.color,
104 top: 0,
105 left: 0,
106 width: size,
107 height: size,
108 zIndex: -1,
109 pointerEvents: 'none',
110 borderRadius: size / 2,
111 }}
112 />
113 <Animated.View
114 entering={circle2Keyframe.duration(300)}
115 style={{
116 position: 'absolute',
117 backgroundColor: t.atoms.bg.backgroundColor,
118 top: 0,
119 left: 0,
120 width: size,
121 height: size,
122 zIndex: -1,
123 pointerEvents: 'none',
124 borderRadius: size / 2,
125 }}
126 />
127 </>
128 ) : null}
129 </LayoutAnimationConfig>
130 </View>
131 )
132}