mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {Keyboard} from 'react-native'
3import {Gesture, GestureDetector} from 'react-native-gesture-handler'
4import Animated, {
5 cancelAnimation,
6 runOnJS,
7 useAnimatedStyle,
8 useSharedValue,
9 withTiming,
10} from 'react-native-reanimated'
11import {ChatBskyConvoDefs} from '@atproto/api'
12import {msg} from '@lingui/macro'
13import {useLingui} from '@lingui/react'
14
15import {HITSLOP_10} from '#/lib/constants'
16import {useHaptics} from '#/lib/haptics'
17import {atoms as a} from '#/alf'
18import {MessageMenu} from '#/components/dms/MessageMenu'
19import {useMenuControl} from '#/components/Menu'
20
21export function ActionsWrapper({
22 message,
23 isFromSelf,
24 children,
25}: {
26 message: ChatBskyConvoDefs.MessageView
27 isFromSelf: boolean
28 children: React.ReactNode
29}) {
30 const {_} = useLingui()
31 const playHaptic = useHaptics()
32 const menuControl = useMenuControl()
33
34 const scale = useSharedValue(1)
35
36 const animatedStyle = useAnimatedStyle(() => ({
37 transform: [{scale: scale.get()}],
38 }))
39
40 const open = React.useCallback(() => {
41 playHaptic()
42 Keyboard.dismiss()
43 menuControl.open()
44 }, [menuControl, playHaptic])
45
46 const shrink = React.useCallback(() => {
47 'worklet'
48 cancelAnimation(scale)
49 scale.set(() => withTiming(1, {duration: 200}))
50 }, [scale])
51
52 const doubleTapGesture = Gesture.Tap()
53 .numberOfTaps(2)
54 .hitSlop(HITSLOP_10)
55 .onEnd(open)
56 .runOnJS(true)
57
58 const pressAndHoldGesture = Gesture.LongPress()
59 .onStart(() => {
60 'worklet'
61 scale.set(() =>
62 withTiming(1.05, {duration: 200}, finished => {
63 if (!finished) return
64 runOnJS(open)()
65 shrink()
66 }),
67 )
68 })
69 .onTouchesUp(shrink)
70 .onTouchesMove(shrink)
71 .cancelsTouchesInView(false)
72
73 const composedGestures = Gesture.Exclusive(
74 doubleTapGesture,
75 pressAndHoldGesture,
76 )
77
78 return (
79 <GestureDetector gesture={composedGestures}>
80 <Animated.View
81 style={[
82 {
83 maxWidth: '80%',
84 },
85 isFromSelf ? a.self_end : a.self_start,
86 animatedStyle,
87 ]}
88 accessible={true}
89 accessibilityActions={[
90 {name: 'activate', label: _(msg`Open message options`)},
91 ]}
92 onAccessibilityAction={open}>
93 {children}
94 <MessageMenu message={message} control={menuControl} />
95 </Animated.View>
96 </GestureDetector>
97 )
98}