Skip to content

Commit

Permalink
chore: apply details
Browse files Browse the repository at this point in the history
  • Loading branch information
bang9 committed Nov 14, 2023
1 parent 2614459 commit 2e75a9c
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type Props = React.PropsWithChildren<{
styles?: {
borderWidth?: number;
borderColor?: string;
remainsTextColor?: string;
remainsBackgroundColor?: string;
};
}>;

Expand All @@ -29,20 +31,26 @@ const AvatarStack = ({
size = DEFAULT_AVATAR_SIZE,
avatarGap = DEFAULT_AVATAR_GAP,
}: Props) => {
const { colors, palette } = useUIKitTheme();
const defaultStyles = { borderWidth: DEFAULT_BORDER_WIDTH, borderColor: colors.background };
const { colors, palette, select } = useUIKitTheme();
const defaultStyles = {
borderWidth: DEFAULT_BORDER_WIDTH,
borderColor: colors.background,
remainsTextColor: colors.onBackground02,
remainsBackgroundColor: select({ light: palette.background100, dark: palette.background600 }),
};
const avatarStyles = { ...defaultStyles, ...styles };

const childrenArray = React.Children.toArray(children).filter((it) => React.isValidElement(it));
const remains = childrenArray.length - maxAvatar;
const shouldRenderRemains = remains > 0;

const actualSize = size + avatarStyles.borderWidth * 2;
const actualGap = avatarGap - avatarStyles.borderWidth;

const renderAvatars = () => {
return childrenArray.slice(0, maxAvatar).map((child, index) =>
React.cloneElement(child as ReactElement, {
size,
size: actualSize,
containerStyle: {
left: actualGap * index,
borderWidth: avatarStyles.borderWidth,
Expand All @@ -60,32 +68,32 @@ const AvatarStack = ({
avatarStyles,
{
left: actualGap * maxAvatar,
width: size,
height: size,
borderRadius: size / 2,
width: actualSize,
height: actualSize,
borderRadius: actualSize / 2,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: palette.background100,
backgroundColor: avatarStyles.remainsBackgroundColor,
},
]}
>
<Text style={{ color: colors.onBackground02, fontSize: 8 }} caption4>
<Text style={{ color: avatarStyles.remainsTextColor, fontSize: 8 }} caption4>
{`+${Math.min(remains, DEFAULT_REMAINS_MAX)}`}
</Text>
</View>
);
};

const calculateWidth = () => {
const widthEach = size + actualGap;
const widthEach = actualSize + actualGap;
const avatarCountOffset = shouldRenderRemains ? 1 : 0;
const avatarCount = shouldRenderRemains ? maxAvatar : childrenArray.length;
const count = avatarCount + avatarCountOffset;
return widthEach * count - actualGap;
return widthEach * count + avatarStyles.borderWidth;
};

return (
<View style={[containerStyle, { flexDirection: 'row', width: calculateWidth() }]}>
<View style={[containerStyle, { left: -avatarStyles.borderWidth, flexDirection: 'row', width: calculateWidth() }]}>
{renderAvatars()}
{renderRemainsCount()}
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,42 @@ import Avatar from '../Avatar';
type Props = {
typingUsers: SendbirdUser[];
containerStyle?: StyleProp<ViewStyle>;
styles?: {};

maxAvatar?: number;
};

const MessageTypingBubble = ({ typingUsers, containerStyle, maxAvatar }: Props) => {
const { select, palette, colors } = useUIKitTheme();

if (typingUsers.length === 0) return null;

return (
<Box flexDirection={'row'} justifyContent={'flex-start'} alignItems={'center'} style={containerStyle}>
<Avatar.Stack size={26} maxAvatar={maxAvatar} containerStyle={{ marginRight: 12 }}>
<Avatar.Stack
size={26}
maxAvatar={maxAvatar}
styles={{
remainsTextColor: colors.onBackground02,
remainsBackgroundColor: select({ light: palette.background100, dark: palette.background400 }),
}}
containerStyle={{ marginRight: 12 }}
>
{typingUsers.map((user, index) => (
<Avatar key={index} uri={user.profileUrl} />
))}
</Avatar.Stack>
<TypingDots />
<TypingDots
dotColor={select({ light: palette.background100, dark: palette.background400 })}
backgroundColor={colors.onBackground02}
/>
</Box>
);
};

const TypingDots = () => {
const { select, palette, colors } = useUIKitTheme();
type TypingDotsProps = {
dotColor: string;
backgroundColor: string;
};
const TypingDots = ({ dotColor, backgroundColor }: TypingDotsProps) => {
const animation = useRef(new Animated.Value(0)).current;
const dots = matrix.map(([timeline, scale, opacity]) => [
animation.interpolate({ inputRange: timeline, outputRange: scale, extrapolate: 'clamp' }),
Expand All @@ -55,7 +69,7 @@ const TypingDots = () => {
borderRadius={16}
paddingHorizontal={12}
height={34}
backgroundColor={select({ light: palette.background100, dark: palette.background600 })}
backgroundColor={dotColor}
>
{dots.map(([scale, opacity], index) => {
return (
Expand All @@ -67,7 +81,7 @@ const TypingDots = () => {
marginRight: index === dots.length - 1 ? 0 : 6,
opacity: opacity,
transform: [{ scale: scale }],
backgroundColor: colors.onBackground02,
backgroundColor: backgroundColor,
},
]}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
focused,
prevMessage,
nextMessage,
isFirstItem,
}) => {
const { typingUsers } = useContext(GroupChannelContexts.TypingIndicator);
const playerUnsubscribes = useRef<(() => void)[]>([]);
const { palette } = useUIKitTheme();
const { sbOptions, currentUser, mentionManager } = useSendbirdChat();
Expand Down Expand Up @@ -293,19 +291,25 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
}
});

const renderTypingBubble = () => {
if (!isFirstItem) return null;
if (!sbOptions.uikit.groupChannel.channel.enableTypingIndicator) return null;
if (!sbOptions.uikit.groupChannel.channel.typingIndicatorTypes.has('bubble')) return null;

return <MessageTypingBubble typingUsers={typingUsers} containerStyle={{ marginTop: 20 }} />;
};

return (
<Box paddingHorizontal={16} marginBottom={messageGap}>
<GroupChannelMessageDateSeparator message={message} prevMessage={prevMessage} />
<GroupChannelMessageFocusAnimation focused={focused}>{renderMessage()}</GroupChannelMessageFocusAnimation>
{renderTypingBubble()}
</Box>
);
};

export const GroupChannelMessageTypingBubble = () => {
const { sbOptions } = useSendbirdChat();
const { typingUsers } = useContext(GroupChannelContexts.TypingIndicator);

if (typingUsers.length === 0) return null;
if (!sbOptions.uikit.groupChannel.channel.enableTypingIndicator) return null;
if (!sbOptions.uikit.groupChannel.channel.typingIndicatorTypes.has('bubble')) return null;

return (
<Box paddingHorizontal={16} marginTop={4} marginBottom={16}>
<MessageTypingBubble typingUsers={typingUsers.concat(typingUsers, typingUsers, typingUsers, typingUsers)} />
</Box>
);
};
Expand Down
5 changes: 5 additions & 0 deletions packages/uikit-react-native/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ export const MESSAGE_FOCUS_ANIMATION_DELAY = 250;
export const UNKNOWN_USER_ID = '##__USER_ID_IS_NOT_PROVIDED__##';
export const VOICE_MESSAGE_META_ARRAY_DURATION_KEY = 'KEY_VOICE_MESSAGE_DURATION';
export const VOICE_MESSAGE_META_ARRAY_MESSAGE_TYPE_KEY = 'KEY_INTERNAL_MESSAGE_TYPE';

export enum TypingIndicatorType {
Text = 'text',
Bubble = 'bubble',
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';

import { ReplyType } from '@sendbird/chat/message';
import { useGroupChannelMessages } from '@sendbird/uikit-chat-hooks';
import { Box } from '@sendbird/uikit-react-native-foundation';
import {
NOOP,
PASS,
Expand All @@ -14,7 +15,9 @@ import {
useRefTracker,
} from '@sendbird/uikit-utils';

import GroupChannelMessageRenderer from '../components/GroupChannelMessageRenderer';
import GroupChannelMessageRenderer, {
GroupChannelMessageTypingBubble,
} from '../components/GroupChannelMessageRenderer';
import NewMessagesButton from '../components/NewMessagesButton';
import ScrollToBottomButton from '../components/ScrollToBottomButton';
import StatusComposition from '../components/StatusComposition';
Expand Down Expand Up @@ -123,8 +126,13 @@ const createGroupChannelFragment = (initModule?: Partial<GroupChannelModule>): G
}, []);

const renderItem: GroupChannelProps['MessageList']['renderMessage'] = useFreshCallback((props) => {
if (renderMessage) return renderMessage(props);
return <GroupChannelMessageRenderer {...props} />;
const content = renderMessage ? renderMessage(props) : <GroupChannelMessageRenderer {...props} />;
return (
<Box>
{content}
{props.isFirstItem && !hasNext() && <GroupChannelMessageTypingBubble />}
</Box>
);
});

const memoizedFlatListProps = useMemo(
Expand Down
2 changes: 1 addition & 1 deletion packages/uikit-react-native/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export { default as SendbirdUIKitContainer, SendbirdUIKit } from './containers/S
export type { SendbirdUIKitContainerProps } from './containers/SendbirdUIKitContainer';
export { default as SBUError } from './libs/SBUError';
export { default as SBUUtils } from './libs/SBUUtils';

export { TypingIndicatorType } from './constants';
export * from './types';

Logger.setLogLevel(__DEV__ ? 'warn' : 'none');
Expand Down
4 changes: 2 additions & 2 deletions sample/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DarkTheme, DefaultTheme, NavigationContainer } from '@react-navigation/
import React, { useEffect } from 'react';
import { AppState } from 'react-native';

import { SendbirdUIKitContainer, useSendbirdChat } from '@sendbird/uikit-react-native';
import { SendbirdUIKitContainer, TypingIndicatorType, useSendbirdChat } from '@sendbird/uikit-react-native';
import { DarkUIKitTheme, LightUIKitTheme } from '@sendbird/uikit-react-native-foundation';

// import LogView from './components/LogView';
Expand Down Expand Up @@ -60,7 +60,7 @@ const App = () => {
},
groupChannel: {
enableMention: true,
typingIndicatorTypes: new Set(['bubble']),
typingIndicatorTypes: new Set([TypingIndicatorType.Text, TypingIndicatorType.Bubble]),
},
groupChannelList: {
enableTypingIndicator: true,
Expand Down

0 comments on commit 2e75a9c

Please sign in to comment.