Skip to content

Commit ab486ca

Browse files
authored
Merge pull request #36 from sendbird/feat/groupchannel-list/preview
Feat/Typing indicator, Receipt status in GroupChannelList [UIKIT-2111] [UIKIT-2112]
2 parents fce9cee + bbd34ce commit ab486ca

File tree

24 files changed

+444
-325
lines changed

24 files changed

+444
-325
lines changed

packages/uikit-chat-hooks/src/channel/useGroupChannelListWithCollection.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,13 @@ export const useGroupChannelListWithCollection: UseGroupChannelList = (sdk, user
9595
setLoading(false);
9696
}, [init, userId]);
9797

98-
useChannelHandler(
99-
sdk,
100-
`${HOOK_NAME}_${id}`,
101-
{
102-
onUserBanned: (channel, user) => {
103-
const isMe = user.userId === userId;
104-
if (isMe) deleteChannels([channel.url]);
105-
else updateChannels([channel], false);
106-
},
98+
useChannelHandler(sdk, `${HOOK_NAME}_${id}`, {
99+
onUserBanned: (channel, user) => {
100+
const isMe = user.userId === userId;
101+
if (isMe) deleteChannels([channel.url]);
102+
else updateChannels([channel], false);
107103
},
108-
[sdk, userId],
109-
);
104+
});
110105
// ---------- internal hooks ends ---------- //
111106

112107
// ---------- returns methods ---------- //

packages/uikit-chat-hooks/src/channel/useGroupChannelListWithQuery.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,29 +71,24 @@ export const useGroupChannelListWithQuery: UseGroupChannelList = (sdk, userId, o
7171
setLoading(false);
7272
}, [init, userId]);
7373

74-
useChannelHandler(
75-
sdk,
76-
HOOK_NAME,
77-
{
78-
onChannelChanged: (channel) => updateChannels([channel], false),
79-
onChannelFrozen: (channel) => updateChannels([channel], false),
80-
onChannelUnfrozen: (channel) => updateChannels([channel], false),
81-
onChannelMemberCountChanged: (channels) => updateChannels(channels, false),
82-
onChannelDeleted: (url) => deleteChannels([url]),
83-
onUserJoined: (channel) => updateChannels([channel], false),
84-
onUserLeft: (channel, user) => {
85-
const isMe = user.userId === userId;
86-
if (isMe) deleteChannels([channel.url]);
87-
else updateChannels([channel], false);
88-
},
89-
onUserBanned(channel, user) {
90-
const isMe = user.userId === userId;
91-
if (isMe) deleteChannels([channel.url]);
92-
else updateChannels([channel], false);
93-
},
74+
useChannelHandler(sdk, HOOK_NAME, {
75+
onChannelChanged: (channel) => updateChannels([channel], false),
76+
onChannelFrozen: (channel) => updateChannels([channel], false),
77+
onChannelUnfrozen: (channel) => updateChannels([channel], false),
78+
onChannelMemberCountChanged: (channels) => updateChannels(channels, false),
79+
onChannelDeleted: (url) => deleteChannels([url]),
80+
onUserJoined: (channel) => updateChannels([channel], false),
81+
onUserLeft: (channel, user) => {
82+
const isMe = user.userId === userId;
83+
if (isMe) deleteChannels([channel.url]);
84+
else updateChannels([channel], false);
9485
},
95-
[sdk, userId],
96-
);
86+
onUserBanned(channel, user) {
87+
const isMe = user.userId === userId;
88+
if (isMe) deleteChannels([channel.url]);
89+
else updateChannels([channel], false);
90+
},
91+
});
9792
// ---------- internal hooks ends ---------- //
9893

9994
// ---------- returns methods ---------- //

packages/uikit-chat-hooks/src/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
7373

7474
const updateChannel = (channel: SendbirdChannel) => {
7575
if (channel.isGroupChannel() && !isDifferentChannel(channel, activeChannel)) {
76-
setActiveChannel(channel);
7776
forceUpdate();
7877
}
7978
};
@@ -153,24 +152,19 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
153152
[sdk, activeChannel.url, options?.collectionCreator],
154153
);
155154

156-
useChannelHandler(
157-
sdk,
158-
HOOK_NAME,
159-
{
160-
onUserBanned(channel, bannedUser) {
161-
disposeManuallyAfterUnmounted();
162-
if (channel.isGroupChannel() && !isDifferentChannel(channel, activeChannel)) {
163-
if (bannedUser.userId === sdk.currentUser.userId) {
164-
options?.onChannelDeleted?.();
165-
} else {
166-
setActiveChannel(channel);
167-
forceUpdate();
168-
}
155+
useChannelHandler(sdk, HOOK_NAME, {
156+
onUserBanned(channel, bannedUser) {
157+
disposeManuallyAfterUnmounted();
158+
if (channel.isGroupChannel() && !isDifferentChannel(channel, activeChannel)) {
159+
if (bannedUser.userId === sdk.currentUser.userId) {
160+
options?.onChannelDeleted?.();
161+
} else {
162+
setActiveChannel(channel);
163+
forceUpdate();
169164
}
170-
},
165+
}
171166
},
172-
[sdk],
173-
);
167+
});
174168

175169
useEffect(() => {
176170
// NOTE: Cache read is heavy synchronous task, and it prevents smooth ui transition

packages/uikit-chat-hooks/src/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.ts

Lines changed: 46 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -80,58 +80,53 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
8080
}
8181
};
8282

83-
useChannelHandler(
84-
sdk,
85-
HOOK_NAME,
86-
{
87-
// Messages
88-
onMessageReceived(eventChannel, message) {
89-
if (isDifferentChannel(activeChannel, eventChannel)) return;
90-
channelMarkAs();
91-
updateNextMessages([message], false, sdk.currentUser.userId);
92-
},
93-
onMessageUpdated(eventChannel, message) {
94-
if (isDifferentChannel(activeChannel, eventChannel)) return;
95-
updateMessages([message], false, sdk.currentUser.userId);
96-
},
97-
onMessageDeleted(eventChannel, messageId) {
98-
if (isDifferentChannel(activeChannel, eventChannel)) return;
99-
deleteMessages([messageId], []);
100-
deleteNextMessages([messageId], []);
101-
},
102-
// Channels
103-
onChannelChanged: channelUpdater,
104-
onChannelFrozen: channelUpdater,
105-
onChannelUnfrozen: channelUpdater,
106-
onChannelHidden: channelUpdater,
107-
onChannelMemberCountChanged(channels) {
108-
const channel = channels.find((c) => !isDifferentChannel(c, activeChannel));
109-
if (channel) channelUpdater(channel);
110-
},
111-
onChannelDeleted(channelUrl: string) {
112-
if (activeChannel.url === channelUrl) options?.onChannelDeleted?.();
113-
},
114-
// Users
115-
onOperatorUpdated: channelUpdater,
116-
onUserLeft: channelUpdater,
117-
onUserEntered: channelUpdater,
118-
onUserExited: channelUpdater,
119-
onUserJoined: channelUpdater,
120-
onUserUnbanned: channelUpdater,
121-
onUserMuted: channelUpdater,
122-
onUserUnmuted: channelUpdater,
123-
onUserBanned(eventChannel, bannedUser) {
124-
if (isDifferentChannel(activeChannel, eventChannel)) return;
125-
126-
if (bannedUser.userId === sdk.currentUser.userId) {
127-
options?.onChannelDeleted?.();
128-
} else {
129-
channelUpdater(eventChannel);
130-
}
131-
},
83+
useChannelHandler(sdk, HOOK_NAME, {
84+
// Messages
85+
onMessageReceived(eventChannel, message) {
86+
if (isDifferentChannel(activeChannel, eventChannel)) return;
87+
channelMarkAs();
88+
updateNextMessages([message], false, sdk.currentUser.userId);
13289
},
133-
[sdk],
134-
);
90+
onMessageUpdated(eventChannel, message) {
91+
if (isDifferentChannel(activeChannel, eventChannel)) return;
92+
updateMessages([message], false, sdk.currentUser.userId);
93+
},
94+
onMessageDeleted(eventChannel, messageId) {
95+
if (isDifferentChannel(activeChannel, eventChannel)) return;
96+
deleteMessages([messageId], []);
97+
deleteNextMessages([messageId], []);
98+
},
99+
// Channels
100+
onChannelChanged: channelUpdater,
101+
onChannelFrozen: channelUpdater,
102+
onChannelUnfrozen: channelUpdater,
103+
onChannelHidden: channelUpdater,
104+
onChannelMemberCountChanged(channels) {
105+
const channel = channels.find((c) => !isDifferentChannel(c, activeChannel));
106+
if (channel) channelUpdater(channel);
107+
},
108+
onChannelDeleted(channelUrl: string) {
109+
if (activeChannel.url === channelUrl) options?.onChannelDeleted?.();
110+
},
111+
// Users
112+
onOperatorUpdated: channelUpdater,
113+
onUserLeft: channelUpdater,
114+
onUserEntered: channelUpdater,
115+
onUserExited: channelUpdater,
116+
onUserJoined: channelUpdater,
117+
onUserUnbanned: channelUpdater,
118+
onUserMuted: channelUpdater,
119+
onUserUnmuted: channelUpdater,
120+
onUserBanned(eventChannel, bannedUser) {
121+
if (isDifferentChannel(activeChannel, eventChannel)) return;
122+
123+
if (bannedUser.userId === sdk.currentUser.userId) {
124+
options?.onChannelDeleted?.();
125+
} else {
126+
channelUpdater(eventChannel);
127+
}
128+
},
129+
});
135130

136131
useAsyncEffect(async () => {
137132
updateLoading(true);
Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,11 @@
1-
import { useMemo } from 'react';
2-
31
import { ApplicationAttributes, PremiumFeatures, SendbirdChatSDK } from '@sendbird/uikit-utils';
42

53
export const useAppFeatures = (sdk: SendbirdChatSDK) => {
6-
const deliveryReceiptEnabled = useMemo(() => {
7-
return Boolean(sdk.appInfo?.premiumFeatureList?.includes?.(PremiumFeatures.delivery_receipt));
8-
}, [sdk.appInfo?.premiumFeatureList]);
9-
10-
const broadcastChannelEnabled = useMemo(() => {
11-
return Boolean(sdk.appInfo?.applicationAttributes?.includes?.(ApplicationAttributes.allow_broadcast_channel));
12-
}, [sdk.appInfo?.applicationAttributes]);
13-
14-
const superGroupChannelEnabled = useMemo(() => {
15-
return Boolean(sdk.appInfo?.applicationAttributes?.includes?.(ApplicationAttributes.allow_super_group_channel));
16-
}, [sdk.appInfo?.applicationAttributes]);
17-
18-
const reactionEnabled = useMemo(() => {
19-
return Boolean(sdk.appInfo?.applicationAttributes?.includes?.(ApplicationAttributes.reactions));
20-
}, [sdk.appInfo?.applicationAttributes]);
21-
4+
const { premiumFeatureList = [], applicationAttributes = [] } = sdk.appInfo ?? {};
225
return {
23-
deliveryReceiptEnabled,
24-
broadcastChannelEnabled,
25-
superGroupChannelEnabled,
26-
reactionEnabled,
6+
deliveryReceiptEnabled: Boolean(premiumFeatureList.includes(PremiumFeatures.delivery_receipt)),
7+
broadcastChannelEnabled: Boolean(applicationAttributes.includes(ApplicationAttributes.allow_broadcast_channel)),
8+
superGroupChannelEnabled: Boolean(applicationAttributes.includes(ApplicationAttributes.allow_super_group_channel)),
9+
reactionEnabled: Boolean(applicationAttributes.includes(ApplicationAttributes.reactions)),
2710
};
2811
};
Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect } from 'react';
1+
import { useEffect, useLayoutEffect, useRef } from 'react';
22
import type Sendbird from 'sendbird';
33

44
import { Logger, SendbirdChatSDK } from '@sendbird/uikit-utils';
@@ -7,19 +7,25 @@ export const useChannelHandler = (
77
sdk: SendbirdChatSDK,
88
handlerId: string,
99
hookHandler: Partial<Sendbird.ChannelHandler>,
10-
deps: React.DependencyList = [],
1110
) => {
11+
const handlerRef = useRef(hookHandler);
12+
useLayoutEffect(() => {
13+
handlerRef.current = hookHandler;
14+
});
15+
1216
useEffect(() => {
1317
Logger.debug('[useChannelHandler] hook called by', handlerId);
1418

1519
const handler = new sdk.ChannelHandler();
1620
const handlerKeys = Object.keys(handler) as (keyof typeof handler)[];
1721
handlerKeys.forEach((key) => {
18-
const hookHandlerFn = hookHandler[key];
19-
if (hookHandlerFn) handler[key] = hookHandlerFn as () => unknown;
22+
handler[key] = (...args: unknown[]) => {
23+
// @ts-ignore
24+
handlerRef.current[key]?.(...args);
25+
};
2026
});
2127

2228
sdk.addChannelHandler(handlerId, handler);
2329
return () => sdk.removeChannelHandler(handlerId);
24-
}, [sdk, handlerId, ...deps]);
30+
}, [sdk, handlerId]);
2531
};

packages/uikit-react-native-foundation/src/styles/createScaleFactor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ const DESIGNED_DEVICE_WIDTH = 360;
66

77
const createScaleFactor = (deviceWidth = DESIGNED_DEVICE_WIDTH) => {
88
const ratio = Math.min(width, height) / deviceWidth;
9-
return (dp: number) => PixelRatio.roundToNearestPixel(dp * ratio);
9+
const rangedRatio = Math.min(Math.max(0.85, ratio), 1.25);
10+
return (dp: number) => PixelRatio.roundToNearestPixel(dp * rangedRatio);
1011
};
1112

1213
createScaleFactor.updateScaleFactor = (scaleFactor: (dp: number) => number) => {

packages/uikit-react-native-foundation/src/ui/GroupChannelPreview/index.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ type Props = {
1515
coverUrl: string;
1616

1717
title: string;
18+
1819
titleCaption: string;
20+
titleCaptionLeft?: React.ReactElement;
21+
1922
bodyIcon?: keyof typeof Icon.Assets;
2023
body: string;
2124

@@ -37,6 +40,7 @@ const GroupChannelPreview = ({
3740
bodyIcon,
3841
title,
3942
titleCaption,
43+
titleCaptionLeft,
4044
frozen,
4145
notificationOff,
4246
}: Props) => {
@@ -60,7 +64,7 @@ const GroupChannelPreview = ({
6064
</View>
6165
<View style={styles.rightSection}>
6266
<View style={styles.rightTopSection}>
63-
<View style={styles.channelInfo}>
67+
<View style={styles.channelInfoContainer}>
6468
<Text numberOfLines={1} subtitle1 style={styles.channelInfoTitle} color={color.default.none.textTitle}>
6569
{title}
6670
</Text>
@@ -74,8 +78,9 @@ const GroupChannelPreview = ({
7478
)}
7579
{notificationOff && <Icon size={16} icon={'notifications-off-filled'} color={colors.onBackground03} />}
7680
</View>
77-
<View style={styles.titleCaption}>
78-
<Text caption2 color={color.default.none.textTitleCaption}>
81+
<View style={styles.titleCaptionContainer}>
82+
{titleCaptionLeft}
83+
<Text caption2 color={color.default.none.textTitleCaption} style={styles.titleCaptionText}>
7984
{titleCaption}
8085
</Text>
8186
</View>
@@ -132,7 +137,7 @@ const styles = createStyleSheet({
132137
flexDirection: 'row',
133138
marginBottom: 4,
134139
},
135-
channelInfo: {
140+
channelInfoContainer: {
136141
flex: 1,
137142
marginRight: 4,
138143
alignItems: 'center',
@@ -149,9 +154,13 @@ const styles = createStyleSheet({
149154
channelInfoFrozen: {
150155
marginRight: 4,
151156
},
152-
titleCaption: {
157+
titleCaptionContainer: {
158+
alignItems: 'flex-start',
159+
flexDirection: 'row',
153160
marginLeft: 4,
154-
paddingTop: 2,
161+
},
162+
titleCaptionText: {
163+
marginTop: 2,
155164
},
156165
rightBottomSection: {
157166
flex: 1,
@@ -190,4 +199,4 @@ const styles = createStyleSheet({
190199
},
191200
});
192201

193-
export default React.memo(GroupChannelPreview);
202+
export default GroupChannelPreview;

packages/uikit-react-native/src/SendbirdUIKitContainer.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ export type SendbirdUIKitContainerProps = React.PropsWithChildren<{
4343
};
4444
chatOptions?: {
4545
localCacheStorage?: LocalCacheStorage;
46-
enableAutoPushTokenRegistration?: boolean;
4746
onInitialized?: (sdkInstance: SendbirdChatSDK) => SendbirdChatSDK;
47+
enableAutoPushTokenRegistration?: boolean;
48+
enableChannelListTypingIndicator?: boolean;
49+
enableChannelListMessageReceiptStatus?: boolean;
4850
};
4951
localization?: {
5052
stringSet?: StringSet;
@@ -132,6 +134,8 @@ const SendbirdUIKitContainer = ({
132134
<SendbirdChatProvider
133135
sdkInstance={sdkInstance}
134136
enableAutoPushTokenRegistration={chatOptions?.enableAutoPushTokenRegistration ?? true}
137+
enableChannelListTypingIndicator={chatOptions?.enableChannelListTypingIndicator ?? false}
138+
enableChannelListMessageReceiptStatus={chatOptions?.enableChannelListMessageReceiptStatus ?? false}
135139
>
136140
<LocalizationProvider stringSet={localization?.stringSet ?? StringSetEn}>
137141
<PlatformServiceProvider

0 commit comments

Comments
 (0)