Skip to content

Commit

Permalink
swipeable comments plus more refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
gkasdorf committed Oct 15, 2023
1 parent 9086c77 commit d60af21
Show file tree
Hide file tree
Showing 17 changed files with 438 additions and 143 deletions.
78 changes: 61 additions & 17 deletions src/components/Comment/components/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@ import CommentHeader from '@components/Comment/components/CommentHeader';
import CommentContent from '@components/Comment/components/CommentContent';
import { Pressable } from 'react-native';
import { Separator } from 'tamagui';
import { SwipeableRow } from '@components/Common/SwipeableRow/SwipeableRow';
import { useCommentGesturesEnabled } from '@src/state/settings/settingsStore';
import { LeftOptions } from '@components/Common/SwipeableRow/LeftOptions';
import { SwipeableActionParams } from '@components/Common/SwipeableRow/actions';
import { useCommentPostId } from '@src/state/comment/commentStore';
import { useNavigation } from '@react-navigation/core';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RightOptions } from '@components/Common/SwipeableRow/RightOptions';
import { ISwipeableOptions } from '@components/Common/SwipeableRow/types';

interface IProps {
itemId: number;
depth?: number;
onPress?: () => unknown | Promise<unknown>;
collapsed?: boolean;
leftOptions?: ISwipeableOptions;
rightOptions?: ISwipeableOptions;
}

const depthToColor = (depth: number): string => {
Expand All @@ -36,29 +47,54 @@ function Comment({
depth = 0,
onPress,
collapsed = false,
leftOptions,
rightOptions,
}: IProps): React.JSX.Element {
const navigation = useNavigation<NativeStackNavigationProp<any>>();

const postId = useCommentPostId(itemId);
const swipesEnabled = useCommentGesturesEnabled();

const borderWidth = useMemo(() => (depth > 0 ? 2 : 0), [depth]);
const borderColor = useMemo(() => depthToColor(depth), [depth]);

if (onPress != null) {
return <PressableComment itemId={itemId} depth={depth} onPress={onPress} />;
}
const actionParams = useMemo<SwipeableActionParams>(
() => ({
postId,
commentId: itemId,
navigation,
}),
[itemId],
);

return (
<VStack backgroundColor="$fg">
<VStack
marginLeft={depth * 10}
marginVertical="$2"
borderLeftColor={borderColor}
borderLeftWidth={borderWidth}
paddingHorizontal="$2"
paddingVertical="$1"
>
<CommentHeader itemId={itemId} />
{!collapsed && <CommentContent itemId={itemId} />}
<SwipeableRow
leftOption={
swipesEnabled && leftOptions?.actions.first != null ? (
<LeftOptions options={leftOptions} actionParams={actionParams} />
) : undefined
}
rightOption={
swipesEnabled && rightOptions?.actions.first != null ? (
<RightOptions options={rightOptions} actionParams={actionParams} />
) : undefined
}
>
<VStack backgroundColor="$fg">
<VStack
marginLeft={depth * 10}
marginVertical="$2"
borderLeftColor={borderColor}
borderLeftWidth={borderWidth}
paddingHorizontal="$2"
paddingVertical="$1"
>
<CommentHeader itemId={itemId} />
{!collapsed && <CommentContent itemId={itemId} />}
</VStack>
<Separator borderColor="$bg" marginLeft={depth * 10 + 10} />
</VStack>
<Separator borderColor="$bg" marginLeft={depth * 10 + 10} />
</VStack>
</SwipeableRow>
);
}

Expand All @@ -67,10 +103,18 @@ export const PressableComment = React.memo(function pressableComment({
depth = 0,
onPress,
collapsed = false,
leftOptions,
rightOptions,
}: IProps): React.JSX.Element {
return (
<Pressable onPress={onPress}>
<Comment itemId={itemId} depth={depth} collapsed={collapsed} />
<Comment
itemId={itemId}
depth={depth}
collapsed={collapsed}
leftOptions={leftOptions}
rightOptions={rightOptions}
/>
</Pressable>
);
});
Expand Down
13 changes: 12 additions & 1 deletion src/components/Comment/components/CommentChain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ICommentInfo } from '@src/types';
import { PressableComment } from '@components/Comment/components/Comment';
import { setPostCommentHidden } from '@src/state/post/actions/setPostCommentHidden';
import CommentShowMoreButton from '@components/Comment/components/CommentShowMoreButton';
import { useCommentGesturesCollapse } from '@src/state/settings/settingsStore';
import { useCommentSwipeOptions } from '@components/Common/SwipeableRow/hooks/useCommentSwipeOptions';

interface IProps {
commentInfo: ICommentInfo;
Expand All @@ -13,9 +15,16 @@ function CommentChain({
commentInfo,
ignoreLoadMore = false,
}: IProps): React.JSX.Element | null {
const collapseOnTap = useCommentGesturesCollapse();

const leftOptions = useCommentSwipeOptions('left');
const rightOptions = useCommentSwipeOptions('right');

const onCommentPress = useCallback(() => {
if (!collapseOnTap) return;

setPostCommentHidden(commentInfo, !commentInfo.collapsed);
}, [commentInfo.collapsed]);
}, [commentInfo.collapsed, collapseOnTap]);

if (commentInfo.hidden) {
return null;
Expand All @@ -31,6 +40,8 @@ function CommentChain({
itemId={commentInfo.commentId}
depth={commentInfo.depth}
collapsed={commentInfo.collapsed}
leftOptions={leftOptions}
rightOptions={rightOptions}
/>
);
}
Expand Down
8 changes: 4 additions & 4 deletions src/components/Common/SwipeableRow/LeftOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { StyleSheet } from 'react-native';
import { playHaptic } from '@helpers/haptics';
import { SwipeableActionParams } from '@components/Common/SwipeableRow/actions';
import { useSwipeableRow } from '@components/Common/SwipeableRow/SwipeableRowProvider';
import { useSwipeOptions } from '@components/Common/SwipeableRow/hooks/useSwipeOptions';
import { UsePostSwipeOptions } from '@components/Common/SwipeableRow/hooks/usePostSwipeOptions';
import { IconMap, IconType } from '@src/types/IconMap';
import { styled } from 'tamagui';

Expand All @@ -24,7 +24,7 @@ const DEFAULT_STOPS: Stops = [75, 150];
const [firstStop, secondStop] = DEFAULT_STOPS;

interface Props {
type: 'post' | 'comment';
options: UsePostSwipeOptions;
flipFlop?: boolean;
actionParams: SwipeableActionParams;
}
Expand All @@ -36,14 +36,14 @@ const buzz = (): void => {
};

export function LeftOptions({
type,
options,
flipFlop = false,
actionParams,
}: Props): React.JSX.Element {
const isFrozen = useSharedValue(false);
const { subscribe, translateX } = useSwipeableRow();

const { colors, actions, icons } = useSwipeOptions(type, 'left');
const { colors, actions, icons } = options;

const [icon, setIcon] = useState<IconType | undefined>(icons.first);

Expand Down
8 changes: 4 additions & 4 deletions src/components/Common/SwipeableRow/RightOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import { playHaptic } from '@helpers/haptics';
import { IconMap, IconType } from '@src/types/IconMap';
import { styled } from 'tamagui';
import { SwipeableActionParams } from '@components/Common/SwipeableRow/actions';
import { useSwipeOptions } from '@components/Common/SwipeableRow/hooks/useSwipeOptions';
import { UsePostSwipeOptions } from '@components/Common/SwipeableRow/hooks/usePostSwipeOptions';

type Stops = [first: number, second: number];
const DEFAULT_STOPS: Stops = [-75, -150];
const [firstStop, secondStop] = DEFAULT_STOPS;
const SCREEN_WIDTH = Dimensions.get('screen').width;

interface Props {
type: 'post' | 'comment';
options: UsePostSwipeOptions;
flipFlop?: boolean;
actionParams: SwipeableActionParams;
}
Expand All @@ -37,14 +37,14 @@ const buzz = (): void => {
};

export function RightOptions({
type,
options,
flipFlop = false,
actionParams,
}: Props): React.JSX.Element {
const isFrozen = useSharedValue(false);
const { subscribe, translateX } = useSwipeableRow();

const { colors, actions, icons } = useSwipeOptions(type, 'right');
const { colors, actions, icons } = options;

const [icon, setIcon] = useState<IconType | undefined>(icons.first);

Expand Down
9 changes: 9 additions & 0 deletions src/components/Common/SwipeableRow/actions/customOption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { SwipeableActionParams } from '@components/Common/SwipeableRow/actions/swipeableActions';

export const customOption = (params: SwipeableActionParams): void => {
const { custom } = params;

if (custom == null) return;

custom(params);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { downvoteCommentOption } from '@components/Common/SwipeableRow/actions/d
import { savePostOption } from '@components/Common/SwipeableRow/actions/savePostOption';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { replyOption } from '@components/Common/SwipeableRow/actions/replyOption';
import { customOption } from '@components/Common/SwipeableRow/actions/customOption';

export interface SwipeableActionParams {
commentId?: number;
postId?: number;
screenId?: string;
navigation: NativeStackNavigationProp<any>;
custom?: (params?: SwipeableActionParams) => unknown;
}

export const postSwipeableActions: Record<
Expand All @@ -23,6 +25,7 @@ export const postSwipeableActions: Record<
save: savePostOption,
hide: () => {},
reply: replyOption,
custom: customOption,
};

export const commentSwipeableActions: Record<
Expand All @@ -34,4 +37,5 @@ export const commentSwipeableActions: Record<
save: () => {},
collapse: () => {},
reply: () => {},
hide: () => {},
};
77 changes: 77 additions & 0 deletions src/components/Common/SwipeableRow/hooks/useCommentSwipeOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useTheme } from 'tamagui';
import { useMemo } from 'react';
import {
useCommentGesturesFirstLeft,
useCommentGesturesFirstRight,
useCommentGesturesSecondLeft,
useCommentGesturesSecondRight,
} from '@src/state/settings/settingsStore';
import { commentSwipeableActions } from '@components/Common/SwipeableRow/actions';
import { IPostGestureOption } from '@src/types';
import {
ISwipeableActions,
ISwipeableColors,
ISwipeableOptions,
} from '@components/Common/SwipeableRow/types';

export const useCommentSwipeOptions = (
side: 'right' | 'left',
): ISwipeableOptions => {
const theme = useTheme();

const firstLeft = useCommentGesturesFirstLeft();
const firstRight = useCommentGesturesFirstRight();
const secondLeft = useCommentGesturesSecondLeft();
const secondRight = useCommentGesturesSecondRight();

const swipeColorOptions = useMemo<Record<IPostGestureOption, string>>(
() => ({
upvote: theme.upvote.val,
downvote: theme.downvote.val,
save: theme.bookmark.val,
hide: theme.warn.val,
reply: theme.accent.val,
collapse: theme.warn.val,
}),
[theme],
);

const swipeActions = useMemo<ISwipeableActions>(() => {
const first = side === 'left' ? firstLeft : firstRight;
const second = side === 'left' ? secondLeft : secondRight;

return {
first: first !== 'none' ? commentSwipeableActions[first] : undefined,
second: second !== 'none' ? commentSwipeableActions[second] : undefined,
};
}, [firstLeft, firstRight, secondLeft, secondRight]);

const swipeColors = useMemo<ISwipeableColors>(() => {
const first = side === 'left' ? firstLeft : firstRight;
const second = side === 'left' ? secondLeft : secondRight;

return {
first:
first !== 'none' ? swipeColorOptions[first] ?? '$accent' : '$accent',
second:
second !== 'none' ? swipeColorOptions[second] ?? undefined : undefined,
};
}, [firstLeft, firstRight, secondLeft, secondRight, swipeColorOptions]);

// @ts-expect-error TODO Fix this
const swipeIcons = useMemo<ISwipeableIcons>(() => {
const first = side === 'left' ? firstLeft : firstRight;
const second = side === 'left' ? secondLeft : secondRight;

return {
first: first !== 'none' ? first : undefined,
second: second !== 'none' ? second : undefined,
};
}, [firstLeft, firstRight, secondLeft, secondRight]);

return {
actions: swipeActions,
colors: swipeColors,
icons: swipeIcons,
};
};
Loading

0 comments on commit d60af21

Please sign in to comment.