import React from 'react'; import { View } from 'react-native'; import Animated, { useAnimatedStyle, interpolate, withSpring, runOnJS, useAnimatedReaction, useSharedValue } from 'react-native-reanimated'; import { RectButton } from 'react-native-gesture-handler'; import * as Haptics from 'expo-haptics'; import { CustomIcon } from '../CustomIcon'; import { DisplayMode } from '../../lib/constants'; import styles, { ACTION_WIDTH, LONG_SWIPE, ROW_HEIGHT_CONDENSED } from './styles'; import { ILeftActionsProps, IRightActionsProps } from './interfaces'; import { useTheme } from '../../theme'; import I18n from '../../i18n'; const CONDENSED_ICON_SIZE = 24; const EXPANDED_ICON_SIZE = 28; export const LeftActions = React.memo(({ transX, isRead, width, onToggleReadPress, displayMode }: ILeftActionsProps) => { const { colors } = useTheme(); const animatedStyles = useAnimatedStyle(() => ({ transform: [{ translateX: transX.value }] })); const isCondensed = displayMode === DisplayMode.Condensed; const viewHeight = isCondensed ? { height: ROW_HEIGHT_CONDENSED } : null; return ( ); }); export const RightActions = React.memo(({ transX, favorite, width, toggleFav, onHidePress, displayMode }: IRightActionsProps) => { const { colors } = useTheme(); const animatedFavStyles = useAnimatedStyle(() => ({ transform: [{ translateX: transX.value }] })); const translateXHide = useSharedValue(0); const triggerHideAnimation = (toValue: number) => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); translateXHide.value = withSpring(toValue, { overshootClamping: true, mass: 0.7 }); }; useAnimatedReaction( () => transX.value, (currentTransX, previousTransX) => { // Triggers the animation and hapticFeedback if swipe reaches/unreaches the threshold. if (I18n.isRTL) { if (previousTransX && currentTransX > LONG_SWIPE && previousTransX <= LONG_SWIPE) { runOnJS(triggerHideAnimation)(ACTION_WIDTH); } else if (previousTransX && currentTransX <= LONG_SWIPE && previousTransX > LONG_SWIPE) { runOnJS(triggerHideAnimation)(0); } } else if (previousTransX && currentTransX < -LONG_SWIPE && previousTransX >= -LONG_SWIPE) { runOnJS(triggerHideAnimation)(-ACTION_WIDTH); } else if (previousTransX && currentTransX >= -LONG_SWIPE && previousTransX < -LONG_SWIPE) { runOnJS(triggerHideAnimation)(0); } } ); const animatedHideStyles = useAnimatedStyle(() => { if (I18n.isRTL) { if (transX.value < LONG_SWIPE && transX.value >= 2 * ACTION_WIDTH) { const parallaxSwipe = interpolate( transX.value, [2 * ACTION_WIDTH, LONG_SWIPE], [ACTION_WIDTH, ACTION_WIDTH + 0.1 * transX.value] ); return { transform: [{ translateX: parallaxSwipe + translateXHide.value }] }; } return { transform: [{ translateX: transX.value - ACTION_WIDTH + translateXHide.value }] }; } if (transX.value > -LONG_SWIPE && transX.value <= -2 * ACTION_WIDTH) { const parallaxSwipe = interpolate( transX.value, [-2 * ACTION_WIDTH, -LONG_SWIPE], [-ACTION_WIDTH, -ACTION_WIDTH + 0.1 * transX.value] ); return { transform: [{ translateX: parallaxSwipe + translateXHide.value }] }; } return { transform: [{ translateX: transX.value + ACTION_WIDTH + translateXHide.value }] }; }); const isCondensed = displayMode === DisplayMode.Condensed; const viewHeight = isCondensed ? { height: ROW_HEIGHT_CONDENSED } : null; return ( ); });