Skip to content

Commit 44be128

Browse files
committed
fix: chnage Swipeable to custom Gesture Pan
1 parent c3968fa commit 44be128

File tree

3 files changed

+503
-501
lines changed

3 files changed

+503
-501
lines changed

package/src/components/Message/MessageSimple/MessageSimple.tsx

Lines changed: 101 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1-
import React, { useRef, useState } from 'react';
1+
import React, { useState } from 'react';
22
import { LayoutChangeEvent, StyleSheet, View } from 'react-native';
33

4-
import Swipeable, { SwipeableMethods } from 'react-native-gesture-handler/ReanimatedSwipeable';
4+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
5+
6+
import Animated, {
7+
Extrapolation,
8+
interpolate,
9+
runOnJS,
10+
useAnimatedStyle,
11+
useSharedValue,
12+
withSpring,
13+
} from 'react-native-reanimated';
514

615
import {
716
MessageContextValue,
@@ -24,10 +33,9 @@ const styles = StyleSheet.create({
2433
},
2534
contentContainer: {},
2635
contentWrapper: {
36+
alignItems: 'center',
2737
flexDirection: 'row',
28-
overflow: 'visible',
2938
},
30-
3139
lastMessageContainer: {
3240
marginBottom: 12,
3341
},
@@ -41,6 +49,9 @@ const styles = StyleSheet.create({
4149
rightAlignItems: {
4250
alignItems: 'flex-end',
4351
},
52+
swipeContentContainer: {
53+
position: 'absolute',
54+
},
4455
});
4556

4657
export type MessageSimplePropsWithContext<
@@ -86,7 +97,6 @@ const MessageSimpleWithContext = <
8697
props: MessageSimplePropsWithContext<StreamChatGenerics>,
8798
) => {
8899
const [messageContentWidth, setMessageContentWidth] = useState(0);
89-
const swipeableRef = useRef<SwipeableMethods | null>(null);
90100

91101
const {
92102
alignment,
@@ -134,6 +144,7 @@ const MessageSimpleWithContext = <
134144
messageGroupedSingleOrBottomContainer,
135145
messageGroupedTopContainer,
136146
reactionListTop: { position: reactionPosition },
147+
swipeContentContainer,
137148
},
138149
},
139150
} = useTheme();
@@ -190,8 +201,78 @@ const MessageSimpleWithContext = <
190201

191202
const repliesCurveColor = isMessageReceivedOrErrorType ? grey_gainsboro : backgroundColor;
192203

204+
const translateX = useSharedValue(0);
205+
const touchStart = useSharedValue<{ x: number; y: number } | null>(null);
206+
207+
const onSwipeToReply = () => {
208+
clearQuotedMessageState();
209+
setQuotedMessageState(message);
210+
};
211+
212+
const THRESHOLD = 25;
213+
214+
const swipeGesture = Gesture.Pan()
215+
.manualActivation(true)
216+
.onBegin((event) => {
217+
touchStart.value = { x: event.x, y: event.y };
218+
})
219+
.onTouchesMove((event, state) => {
220+
if (!touchStart.value || !event.changedTouches.length) {
221+
state.fail();
222+
return;
223+
}
224+
225+
const xDiff = Math.abs(event.changedTouches[0].x - touchStart.value.x);
226+
const yDiff = Math.abs(event.changedTouches[0].y - touchStart.value.y);
227+
const isHorizontalPanning = xDiff > yDiff;
228+
229+
if (isHorizontalPanning) {
230+
state.activate();
231+
} else {
232+
state.fail();
233+
}
234+
})
235+
.onStart(() => {
236+
translateX.value = 0;
237+
})
238+
.onChange(({ translationX }) => {
239+
if (translationX > 0) {
240+
translateX.value = translationX;
241+
}
242+
})
243+
.onEnd(() => {
244+
if (translateX.value >= THRESHOLD) {
245+
runOnJS(onSwipeToReply)();
246+
runOnJS(triggerHaptic)('impactMedium');
247+
}
248+
translateX.value = withSpring(0, {
249+
dampingRatio: 1,
250+
duration: 500,
251+
overshootClamping: true,
252+
stiffness: 1,
253+
});
254+
});
255+
256+
const messageBubbleAnimatedStyle = useAnimatedStyle(() => ({
257+
transform: [{ translateX: translateX.value }],
258+
}));
259+
260+
const swipeContentAnimatedStyle = useAnimatedStyle(() => ({
261+
opacity: interpolate(translateX.value, [0, THRESHOLD], [0, 1]),
262+
transform: [
263+
{
264+
translateX: interpolate(
265+
translateX.value,
266+
[0, THRESHOLD],
267+
[-THRESHOLD, 0],
268+
Extrapolation.CLAMP,
269+
),
270+
},
271+
],
272+
}));
273+
193274
const renderMessageBubble = (
194-
<>
275+
<View style={[styles.contentWrapper, contentWrapper]}>
195276
<MessageContent
196277
backgroundColor={backgroundColor}
197278
noBorder={noBorder}
@@ -200,18 +281,21 @@ const MessageSimpleWithContext = <
200281
{reactionListPosition === 'top' && ReactionListTop ? (
201282
<ReactionListTop messageContentWidth={messageContentWidth} />
202283
) : null}
203-
</>
284+
</View>
204285
);
205286

206-
const leftAlignmentProps = {
207-
leftThreshold: 100,
208-
renderLeftActions: () => (MessageSwipeContent ? <MessageSwipeContent /> : null),
209-
};
210-
211-
const rightAlignmentProps = {
212-
renderRightActions: () => (MessageSwipeContent ? <MessageSwipeContent /> : null),
213-
rightThreshold: 100,
214-
};
287+
const renderAnimatedMessageBubble = (
288+
<GestureDetector gesture={swipeGesture}>
289+
<View style={[styles.contentWrapper, contentWrapper]}>
290+
<Animated.View
291+
style={[styles.swipeContentContainer, swipeContentAnimatedStyle, swipeContentContainer]}
292+
>
293+
{MessageSwipeContent ? <MessageSwipeContent /> : null}
294+
</Animated.View>
295+
<Animated.View style={messageBubbleAnimatedStyle}>{renderMessageBubble}</Animated.View>
296+
</View>
297+
</GestureDetector>
298+
);
215299

216300
return (
217301
<View
@@ -271,27 +355,7 @@ const MessageSimpleWithContext = <
271355
)}
272356
{message.pinned ? <MessagePinnedHeader /> : null}
273357
</View>
274-
275-
{enableSwipeToReply ? (
276-
<Swipeable
277-
containerStyle={[styles.contentWrapper, contentWrapper]}
278-
friction={2}
279-
onSwipeableWillOpen={() => {
280-
if (!swipeableRef.current) return;
281-
clearQuotedMessageState();
282-
setQuotedMessageState(message);
283-
triggerHaptic('impactLight');
284-
swipeableRef.current.close();
285-
}}
286-
ref={swipeableRef}
287-
{...(alignment === 'left' ? leftAlignmentProps : rightAlignmentProps)}
288-
>
289-
{renderMessageBubble}
290-
</Swipeable>
291-
) : (
292-
renderMessageBubble
293-
)}
294-
358+
{enableSwipeToReply ? renderAnimatedMessageBubble : renderMessageBubble}
295359
{reactionListPosition === 'bottom' && ReactionListBottom ? <ReactionListBottom /> : null}
296360
<MessageReplies noBorder={noBorder} repliesCurveColor={repliesCurveColor} />
297361
<MessageFooter date={message.created_at} isDeleted={!!isMessageTypeDeleted} />

0 commit comments

Comments
 (0)