2019-07-15 16:54:28 +00:00
|
|
|
import React from 'react';
|
2022-06-06 13:23:49 +00:00
|
|
|
import { View } from 'react-native';
|
|
|
|
import Animated, {
|
|
|
|
useAnimatedStyle,
|
|
|
|
interpolate,
|
|
|
|
withSpring,
|
|
|
|
runOnJS,
|
|
|
|
useAnimatedReaction,
|
|
|
|
useSharedValue
|
|
|
|
} from 'react-native-reanimated';
|
2019-07-15 16:54:28 +00:00
|
|
|
import { RectButton } from 'react-native-gesture-handler';
|
2022-06-06 13:23:49 +00:00
|
|
|
import * as Haptics from 'expo-haptics';
|
2019-07-15 16:54:28 +00:00
|
|
|
|
2022-05-02 19:21:15 +00:00
|
|
|
import { CustomIcon } from '../CustomIcon';
|
2022-06-06 13:23:49 +00:00
|
|
|
import { DisplayMode } from '../../lib/constants';
|
2021-10-06 20:30:10 +00:00
|
|
|
import styles, { ACTION_WIDTH, LONG_SWIPE, ROW_HEIGHT_CONDENSED } from './styles';
|
2022-04-20 21:37:54 +00:00
|
|
|
import { ILeftActionsProps, IRightActionsProps } from './interfaces';
|
2022-06-06 13:23:49 +00:00
|
|
|
import { useTheme } from '../../theme';
|
|
|
|
import I18n from '../../i18n';
|
2021-09-13 20:41:05 +00:00
|
|
|
|
2021-10-06 20:30:10 +00:00
|
|
|
const CONDENSED_ICON_SIZE = 24;
|
|
|
|
const EXPANDED_ICON_SIZE = 28;
|
2020-11-30 21:47:05 +00:00
|
|
|
|
2022-06-06 13:23:49 +00:00
|
|
|
export const LeftActions = React.memo(({ transX, isRead, width, onToggleReadPress, displayMode }: ILeftActionsProps) => {
|
|
|
|
const { colors } = useTheme();
|
|
|
|
|
|
|
|
const animatedStyles = useAnimatedStyle(() => ({
|
|
|
|
transform: [{ translateX: transX.value }]
|
|
|
|
}));
|
2021-10-06 20:30:10 +00:00
|
|
|
|
2022-01-11 14:47:23 +00:00
|
|
|
const isCondensed = displayMode === DisplayMode.Condensed;
|
2021-10-06 20:30:10 +00:00
|
|
|
const viewHeight = isCondensed ? { height: ROW_HEIGHT_CONDENSED } : null;
|
|
|
|
|
2019-07-15 16:54:28 +00:00
|
|
|
return (
|
2022-04-20 21:02:18 +00:00
|
|
|
<View style={[styles.actionsContainer, styles.actionsLeftContainer]} pointerEvents='box-none'>
|
2019-07-15 16:54:28 +00:00
|
|
|
<Animated.View
|
|
|
|
style={[
|
|
|
|
styles.actionLeftButtonContainer,
|
2022-06-06 13:23:49 +00:00
|
|
|
{ width: width * 2, backgroundColor: colors.tintColor, right: '100%' },
|
|
|
|
viewHeight,
|
|
|
|
animatedStyles
|
2022-08-08 21:02:08 +00:00
|
|
|
]}
|
|
|
|
>
|
2021-10-06 20:30:10 +00:00
|
|
|
<View style={[styles.actionLeftButtonContainer, viewHeight]}>
|
2019-07-15 16:54:28 +00:00
|
|
|
<RectButton style={styles.actionButton} onPress={onToggleReadPress}>
|
2021-10-06 20:30:10 +00:00
|
|
|
<CustomIcon
|
|
|
|
size={isCondensed ? CONDENSED_ICON_SIZE : EXPANDED_ICON_SIZE}
|
|
|
|
name={isRead ? 'flag' : 'check'}
|
2022-06-06 13:23:49 +00:00
|
|
|
color={colors.buttonText}
|
2021-10-06 20:30:10 +00:00
|
|
|
/>
|
2019-07-15 16:54:28 +00:00
|
|
|
</RectButton>
|
2020-11-30 21:47:05 +00:00
|
|
|
</View>
|
2019-07-15 16:54:28 +00:00
|
|
|
</Animated.View>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2022-06-06 13:23:49 +00:00
|
|
|
export const RightActions = React.memo(({ transX, favorite, width, toggleFav, onHidePress, displayMode }: IRightActionsProps) => {
|
|
|
|
const { colors } = useTheme();
|
2021-10-06 20:30:10 +00:00
|
|
|
|
2022-06-06 13:23:49 +00:00
|
|
|
const animatedFavStyles = useAnimatedStyle(() => ({ transform: [{ translateX: transX.value }] }));
|
2021-10-06 20:30:10 +00:00
|
|
|
|
2022-06-06 13:23:49 +00:00
|
|
|
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 (
|
|
|
|
<View style={[styles.actionsLeftContainer, viewHeight]} pointerEvents='box-none'>
|
|
|
|
<Animated.View
|
|
|
|
style={[
|
|
|
|
styles.actionRightButtonContainer,
|
|
|
|
{
|
|
|
|
width,
|
|
|
|
backgroundColor: colors.favoriteBackground,
|
|
|
|
left: '100%'
|
|
|
|
},
|
|
|
|
viewHeight,
|
|
|
|
animatedFavStyles
|
2022-08-08 21:02:08 +00:00
|
|
|
]}
|
|
|
|
>
|
2022-06-06 13:23:49 +00:00
|
|
|
<RectButton style={[styles.actionButton, { backgroundColor: colors.favoriteBackground }]} onPress={toggleFav}>
|
|
|
|
<CustomIcon
|
|
|
|
size={isCondensed ? CONDENSED_ICON_SIZE : EXPANDED_ICON_SIZE}
|
|
|
|
name={favorite ? 'star-filled' : 'star'}
|
|
|
|
color={colors.buttonText}
|
|
|
|
/>
|
|
|
|
</RectButton>
|
|
|
|
</Animated.View>
|
|
|
|
<Animated.View
|
|
|
|
style={[
|
|
|
|
styles.actionRightButtonContainer,
|
|
|
|
{
|
|
|
|
width: width * 2,
|
|
|
|
backgroundColor: colors.hideBackground,
|
|
|
|
left: '100%'
|
|
|
|
},
|
|
|
|
isCondensed && { height: ROW_HEIGHT_CONDENSED },
|
|
|
|
animatedHideStyles
|
2022-08-08 21:02:08 +00:00
|
|
|
]}
|
|
|
|
>
|
2022-06-06 13:23:49 +00:00
|
|
|
<RectButton style={[styles.actionButton, { backgroundColor: colors.hideBackground }]} onPress={onHidePress}>
|
|
|
|
<CustomIcon
|
|
|
|
size={isCondensed ? CONDENSED_ICON_SIZE : EXPANDED_ICON_SIZE}
|
|
|
|
name='unread-on-top-disabled'
|
|
|
|
color={colors.buttonText}
|
|
|
|
/>
|
|
|
|
</RectButton>
|
|
|
|
</Animated.View>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
});
|