@sendbird/uikit-react-native 3.0.4-rc.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/ChannelInput/SendInput.js +151 -19
- package/lib/commonjs/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/commonjs/components/ChannelInput/index.js +5 -13
- package/lib/commonjs/components/ChannelInput/index.js.map +1 -1
- package/lib/commonjs/components/ChannelMessageList/index.js +34 -20
- package/lib/commonjs/components/ChannelMessageList/index.js.map +1 -1
- package/lib/commonjs/components/ChatFlatList/index.js +1 -1
- package/lib/commonjs/components/ChatFlatList/index.js.map +1 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js +4 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js.map +1 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +191 -0
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -0
- package/lib/commonjs/components/GroupChannelMessageRenderer/index.js +12 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/index.js.map +1 -1
- package/lib/commonjs/components/MessageSearchResultItem.js +2 -8
- package/lib/commonjs/components/MessageSearchResultItem.js.map +1 -1
- package/lib/commonjs/components/ReactionAddons/BottomSheetReactionAddon.js +8 -7
- package/lib/commonjs/components/ReactionAddons/BottomSheetReactionAddon.js.map +1 -1
- package/lib/commonjs/containers/GroupChannelPreviewContainer.js +3 -9
- package/lib/commonjs/containers/GroupChannelPreviewContainer.js.map +1 -1
- package/lib/commonjs/containers/SendbirdUIKitContainer.js +43 -9
- package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -1
- package/lib/commonjs/contexts/SendbirdChatCtx.js +5 -0
- package/lib/commonjs/contexts/SendbirdChatCtx.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelInput.js +5 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelInput.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +47 -10
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js +38 -3
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
- package/lib/commonjs/domain/openChannel/types.js.map +1 -1
- package/lib/commonjs/fragments/createGroupChannelFragment.js +19 -0
- package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/commonjs/hooks/useConnection.js +2 -1
- package/lib/commonjs/hooks/useConnection.js.map +1 -1
- package/lib/commonjs/hooks/useMentionSuggestion.js +1 -1
- package/lib/commonjs/hooks/useMentionSuggestion.js.map +1 -1
- package/lib/commonjs/hooks/useMentionTextInput.js +4 -3
- package/lib/commonjs/hooks/useMentionTextInput.js.map +1 -1
- package/lib/commonjs/libs/MentionManager.js.map +1 -1
- package/lib/commonjs/localization/StringSet.type.js.map +1 -1
- package/lib/commonjs/localization/createBaseStringSet.js +29 -0
- package/lib/commonjs/localization/createBaseStringSet.js.map +1 -1
- package/lib/commonjs/platform/createFileService.native.js +4 -1
- package/lib/commonjs/platform/createFileService.native.js.map +1 -1
- package/lib/commonjs/platform/createMediaService.native.js +1 -1
- package/lib/commonjs/platform/createMediaService.native.js.map +1 -1
- package/lib/commonjs/platform/types.js.map +1 -1
- package/lib/commonjs/utils/pubsub.js +3 -1
- package/lib/commonjs/utils/pubsub.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/module/components/ChannelInput/SendInput.js +153 -21
- package/lib/module/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/module/components/ChannelInput/index.js +6 -14
- package/lib/module/components/ChannelInput/index.js.map +1 -1
- package/lib/module/components/ChannelMessageList/index.js +34 -20
- package/lib/module/components/ChannelMessageList/index.js.map +1 -1
- package/lib/module/components/ChatFlatList/index.js +1 -1
- package/lib/module/components/ChatFlatList/index.js.map +1 -1
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js +4 -1
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js.map +1 -1
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +182 -0
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -0
- package/lib/module/components/GroupChannelMessageRenderer/index.js +13 -2
- package/lib/module/components/GroupChannelMessageRenderer/index.js.map +1 -1
- package/lib/module/components/MessageSearchResultItem.js +3 -9
- package/lib/module/components/MessageSearchResultItem.js.map +1 -1
- package/lib/module/components/ReactionAddons/BottomSheetReactionAddon.js +8 -7
- package/lib/module/components/ReactionAddons/BottomSheetReactionAddon.js.map +1 -1
- package/lib/module/containers/GroupChannelPreviewContainer.js +4 -10
- package/lib/module/containers/GroupChannelPreviewContainer.js.map +1 -1
- package/lib/module/containers/SendbirdUIKitContainer.js +43 -9
- package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -1
- package/lib/module/contexts/SendbirdChatCtx.js +6 -1
- package/lib/module/contexts/SendbirdChatCtx.js.map +1 -1
- package/lib/module/domain/groupChannel/component/GroupChannelInput.js +5 -1
- package/lib/module/domain/groupChannel/component/GroupChannelInput.js.map +1 -1
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +50 -13
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/module/domain/groupChannel/module/moduleContext.js +39 -4
- package/lib/module/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/module/domain/groupChannel/types.js.map +1 -1
- package/lib/module/domain/openChannel/types.js.map +1 -1
- package/lib/module/fragments/createGroupChannelFragment.js +19 -0
- package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/module/hooks/useConnection.js +2 -1
- package/lib/module/hooks/useConnection.js.map +1 -1
- package/lib/module/hooks/useMentionSuggestion.js +1 -1
- package/lib/module/hooks/useMentionSuggestion.js.map +1 -1
- package/lib/module/hooks/useMentionTextInput.js +4 -3
- package/lib/module/hooks/useMentionTextInput.js.map +1 -1
- package/lib/module/libs/MentionManager.js.map +1 -1
- package/lib/module/localization/StringSet.type.js.map +1 -1
- package/lib/module/localization/createBaseStringSet.js +30 -1
- package/lib/module/localization/createBaseStringSet.js.map +1 -1
- package/lib/module/platform/createFileService.native.js +5 -2
- package/lib/module/platform/createFileService.native.js.map +1 -1
- package/lib/module/platform/createMediaService.native.js +1 -1
- package/lib/module/platform/createMediaService.native.js.map +1 -1
- package/lib/module/platform/types.js.map +1 -1
- package/lib/module/utils/pubsub.js +3 -1
- package/lib/module/utils/pubsub.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/typescript/src/components/ChannelInput/index.d.ts +2 -0
- package/lib/typescript/src/components/ChannelMessageList/index.d.ts +4 -1
- package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.d.ts +9 -0
- package/lib/typescript/src/components/GroupChannelMessageRenderer/index.d.ts +1 -0
- package/lib/typescript/src/components/OpenChannelMessageRenderer/index.d.ts +1 -0
- package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +4 -2
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelMessageList.d.ts +4 -0
- package/lib/typescript/src/domain/groupChannel/types.d.ts +6 -2
- package/lib/typescript/src/domain/openChannel/component/OpenChannelHeader.d.ts +1 -1
- package/lib/typescript/src/domain/openChannel/types.d.ts +1 -2
- package/lib/typescript/src/libs/MentionManager.d.ts +1 -4
- package/lib/typescript/src/localization/StringSet.type.d.ts +7 -1
- package/lib/typescript/src/platform/types.d.ts +10 -11
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +7 -6
- package/src/components/ChannelInput/SendInput.tsx +184 -51
- package/src/components/ChannelInput/index.tsx +11 -15
- package/src/components/ChannelMessageList/index.tsx +45 -27
- package/src/components/ChatFlatList/index.tsx +1 -1
- package/src/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.tsx +5 -1
- package/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.tsx +177 -0
- package/src/components/GroupChannelMessageRenderer/index.tsx +16 -1
- package/src/components/MessageSearchResultItem.tsx +3 -5
- package/src/components/ReactionAddons/BottomSheetReactionAddon.tsx +6 -7
- package/src/containers/GroupChannelPreviewContainer.tsx +6 -7
- package/src/containers/SendbirdUIKitContainer.tsx +40 -10
- package/src/contexts/SendbirdChatCtx.tsx +7 -1
- package/src/domain/groupChannel/component/GroupChannelInput.tsx +5 -1
- package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +46 -13
- package/src/domain/groupChannel/module/moduleContext.tsx +38 -3
- package/src/domain/groupChannel/types.ts +8 -2
- package/src/domain/openChannel/types.ts +1 -2
- package/src/fragments/createGroupChannelFragment.tsx +15 -0
- package/src/hooks/useConnection.ts +1 -1
- package/src/hooks/useMentionSuggestion.ts +2 -1
- package/src/hooks/useMentionTextInput.ts +2 -2
- package/src/libs/MentionManager.tsx +1 -8
- package/src/localization/StringSet.type.ts +11 -0
- package/src/localization/createBaseStringSet.ts +30 -0
- package/src/platform/createFileService.native.ts +5 -1
- package/src/platform/createMediaService.native.tsx +1 -1
- package/src/platform/types.ts +9 -9
- package/src/utils/pubsub.ts +3 -1
- package/src/version.ts +1 -1
|
@@ -9,17 +9,31 @@ import {
|
|
|
9
9
|
} from 'react-native';
|
|
10
10
|
|
|
11
11
|
import { MentionType } from '@sendbird/chat/message';
|
|
12
|
+
import type { BottomSheetItem } from '@sendbird/uikit-react-native-foundation';
|
|
12
13
|
import {
|
|
13
14
|
Icon,
|
|
15
|
+
ImageWithPlaceholder,
|
|
16
|
+
Text,
|
|
14
17
|
TextInput,
|
|
18
|
+
VideoThumbnail,
|
|
15
19
|
createStyleSheet,
|
|
16
20
|
useAlert,
|
|
17
21
|
useBottomSheet,
|
|
18
22
|
useToast,
|
|
19
23
|
useUIKitTheme,
|
|
20
24
|
} from '@sendbird/uikit-react-native-foundation';
|
|
21
|
-
import
|
|
22
|
-
|
|
25
|
+
import {
|
|
26
|
+
FileIcon,
|
|
27
|
+
Logger,
|
|
28
|
+
SendbirdBaseMessage,
|
|
29
|
+
SendbirdChannel,
|
|
30
|
+
getAvailableUriFromFileMessage,
|
|
31
|
+
getFileIconFromMessageType,
|
|
32
|
+
getMessageType,
|
|
33
|
+
isImage,
|
|
34
|
+
shouldCompressImage,
|
|
35
|
+
useIIFE,
|
|
36
|
+
} from '@sendbird/uikit-utils';
|
|
23
37
|
|
|
24
38
|
import { useLocalization, usePlatformService, useSendbirdChat } from '../../hooks/useContext';
|
|
25
39
|
import SBUError from '../../libs/SBUError';
|
|
@@ -48,81 +62,192 @@ const SendInput = forwardRef<RNTextInput, SendInputProps>(function SendInput(
|
|
|
48
62
|
inputFrozen,
|
|
49
63
|
inputMuted,
|
|
50
64
|
channel,
|
|
65
|
+
messageToReply,
|
|
66
|
+
setMessageToReply,
|
|
51
67
|
},
|
|
52
68
|
ref,
|
|
53
69
|
) {
|
|
54
70
|
const { mentionManager, sbOptions } = useSendbirdChat();
|
|
71
|
+
const { select, colors, palette } = useUIKitTheme();
|
|
55
72
|
const { STRINGS } = useLocalization();
|
|
56
|
-
const { colors } = useUIKitTheme();
|
|
57
73
|
const { openSheet } = useBottomSheet();
|
|
58
74
|
const toast = useToast();
|
|
75
|
+
const { mediaService } = usePlatformService();
|
|
76
|
+
|
|
77
|
+
const messageReplyParams = useIIFE(() => {
|
|
78
|
+
const { groupChannel } = sbOptions.uikit;
|
|
79
|
+
if (!channel.isGroupChannel() || groupChannel.channel.replyType === 'none' || !messageToReply) return {};
|
|
80
|
+
return {
|
|
81
|
+
parentMessageId: messageToReply.messageId,
|
|
82
|
+
isReplyToChannel: true,
|
|
83
|
+
};
|
|
84
|
+
});
|
|
59
85
|
|
|
60
|
-
const
|
|
86
|
+
const messageMentionParams = useIIFE(() => {
|
|
87
|
+
const { groupChannel } = sbOptions.uikit;
|
|
88
|
+
if (!channel.isGroupChannel() || !groupChannel.channel.enableMention) return {};
|
|
89
|
+
return {
|
|
90
|
+
mentionType: MentionType.USERS,
|
|
91
|
+
mentionedUserIds: mentionedUsers.map((it) => it.user.userId),
|
|
92
|
+
mentionedMessageTemplate: mentionManager.textToMentionedMessageTemplate(
|
|
93
|
+
text,
|
|
94
|
+
mentionedUsers,
|
|
95
|
+
groupChannel.channel.enableMention,
|
|
96
|
+
),
|
|
97
|
+
};
|
|
98
|
+
});
|
|
61
99
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
text,
|
|
67
|
-
mentionedUsers,
|
|
68
|
-
sbOptions.uikit.groupChannel.channel.enableMention,
|
|
69
|
-
);
|
|
100
|
+
const onFailureToSend = (error: Error) => {
|
|
101
|
+
toast.show(STRINGS.TOAST.SEND_MSG_ERROR, 'error');
|
|
102
|
+
Logger.error(STRINGS.TOAST.SEND_MSG_ERROR, error);
|
|
103
|
+
};
|
|
70
104
|
|
|
105
|
+
const sendUserMessage = () => {
|
|
71
106
|
onPressSendUserMessage({
|
|
72
107
|
message: text,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
mentionedMessageTemplate,
|
|
108
|
+
...messageMentionParams,
|
|
109
|
+
...messageReplyParams,
|
|
76
110
|
}).catch(onFailureToSend);
|
|
77
111
|
|
|
78
112
|
onChangeText('');
|
|
113
|
+
setMessageToReply?.();
|
|
79
114
|
};
|
|
80
115
|
|
|
81
|
-
const
|
|
82
|
-
onPressSendFileMessage({
|
|
83
|
-
|
|
116
|
+
const sendFileMessage = (file: FileType) => {
|
|
117
|
+
onPressSendFileMessage({
|
|
118
|
+
file,
|
|
119
|
+
...messageReplyParams,
|
|
120
|
+
}).catch(onFailureToSend);
|
|
121
|
+
|
|
122
|
+
setMessageToReply?.();
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const sheetItems = useChannelInputItems(channel, sendFileMessage);
|
|
84
126
|
const onPressAttachment = () => openSheet({ sheetItems });
|
|
85
127
|
|
|
86
128
|
const getPlaceholder = () => {
|
|
87
|
-
if (!inputDisabled) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_ACTIVE;
|
|
88
|
-
if (inputFrozen) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
|
|
89
129
|
if (inputMuted) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_MUTED;
|
|
130
|
+
if (inputFrozen) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
|
|
131
|
+
if (inputDisabled) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
|
|
132
|
+
if (messageToReply) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_REPLY;
|
|
90
133
|
|
|
91
|
-
return STRINGS.LABELS.
|
|
134
|
+
return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_ACTIVE;
|
|
92
135
|
};
|
|
93
136
|
|
|
94
|
-
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
<TextInput
|
|
98
|
-
ref={ref}
|
|
99
|
-
multiline
|
|
100
|
-
disableFullscreenUI
|
|
101
|
-
onSelectionChange={onSelectionChange}
|
|
102
|
-
editable={!inputDisabled}
|
|
103
|
-
onChangeText={onChangeText}
|
|
104
|
-
style={styles.input}
|
|
105
|
-
placeholder={getPlaceholder()}
|
|
106
|
-
>
|
|
107
|
-
{mentionManager.textToMentionedComponents(
|
|
108
|
-
text,
|
|
109
|
-
mentionedUsers,
|
|
110
|
-
sbOptions.uikit.groupChannel.channel.enableMention,
|
|
111
|
-
)}
|
|
112
|
-
</TextInput>
|
|
137
|
+
const getFileIconAsImage = (url: string) => {
|
|
138
|
+
return <ImageWithPlaceholder source={{ uri: url }} style={styles.previewImage} />;
|
|
139
|
+
};
|
|
113
140
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
const getFileIconAsVideoThumbnail = (url: string) => {
|
|
142
|
+
return (
|
|
143
|
+
<VideoThumbnail
|
|
144
|
+
style={styles.previewImage}
|
|
145
|
+
iconSize={0}
|
|
146
|
+
videoSource={url}
|
|
147
|
+
fetchThumbnailFromVideoSource={(uri) => mediaService.getVideoThumbnail({ url: uri, timeMills: 1000 })}
|
|
148
|
+
/>
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const getFileIconAsSymbol = (icon: FileIcon) => {
|
|
153
|
+
return (
|
|
154
|
+
<Icon
|
|
155
|
+
icon={icon}
|
|
156
|
+
size={20}
|
|
157
|
+
color={colors.onBackground02}
|
|
158
|
+
containerStyle={{
|
|
159
|
+
backgroundColor: select({
|
|
160
|
+
light: palette.background100,
|
|
161
|
+
dark: palette.background500,
|
|
162
|
+
}),
|
|
163
|
+
width: 36,
|
|
164
|
+
height: 36,
|
|
165
|
+
borderRadius: 10,
|
|
166
|
+
marginRight: 10,
|
|
167
|
+
marginTop: 2,
|
|
168
|
+
}}
|
|
169
|
+
/>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const getFileIcon = (messageToReply: SendbirdBaseMessage) => {
|
|
174
|
+
if (messageToReply?.isFileMessage()) {
|
|
175
|
+
const messageType = getMessageType(messageToReply);
|
|
176
|
+
switch (messageType) {
|
|
177
|
+
case 'file.image':
|
|
178
|
+
return getFileIconAsImage(getAvailableUriFromFileMessage(messageToReply));
|
|
179
|
+
case 'file.video':
|
|
180
|
+
return getFileIconAsVideoThumbnail(getAvailableUriFromFileMessage(messageToReply));
|
|
181
|
+
default:
|
|
182
|
+
return getFileIconAsSymbol(getFileIconFromMessageType(messageType));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<View>
|
|
190
|
+
{messageToReply && (
|
|
191
|
+
<View
|
|
192
|
+
style={{
|
|
193
|
+
flexDirection: 'row',
|
|
194
|
+
paddingLeft: 18,
|
|
195
|
+
paddingRight: 16,
|
|
196
|
+
paddingTop: 10,
|
|
197
|
+
paddingBottom: 8,
|
|
198
|
+
alignItems: 'center',
|
|
199
|
+
borderTopWidth: 1,
|
|
200
|
+
borderColor: colors.onBackground04,
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
<View style={{ flex: 1, flexDirection: 'row' }}>
|
|
204
|
+
{getFileIcon(messageToReply)}
|
|
205
|
+
<View style={{ flex: 1, flexDirection: 'column' }}>
|
|
206
|
+
<Text numberOfLines={1} style={{ fontSize: 13, fontWeight: '900', marginBottom: 4 }}>
|
|
207
|
+
{STRINGS.LABELS.CHANNEL_INPUT_REPLY_PREVIEW_TITLE(messageToReply.sender)}
|
|
208
|
+
</Text>
|
|
209
|
+
<Text numberOfLines={1} style={{ fontSize: 13, color: colors.onBackground03 }}>
|
|
210
|
+
{STRINGS.LABELS.CHANNEL_INPUT_REPLY_PREVIEW_BODY(messageToReply)}
|
|
211
|
+
</Text>
|
|
212
|
+
</View>
|
|
213
|
+
</View>
|
|
214
|
+
<TouchableOpacity onPress={() => setMessageToReply?.(undefined)}>
|
|
215
|
+
<Icon icon={'close'} size={24} color={colors.onBackground01} containerStyle={styles.iconSend} />
|
|
216
|
+
</TouchableOpacity>
|
|
217
|
+
</View>
|
|
125
218
|
)}
|
|
219
|
+
<View style={styles.sendInputContainer}>
|
|
220
|
+
{AttachmentsButton && <AttachmentsButton onPress={onPressAttachment} disabled={inputDisabled} />}
|
|
221
|
+
<TextInput
|
|
222
|
+
ref={ref}
|
|
223
|
+
multiline
|
|
224
|
+
disableFullscreenUI
|
|
225
|
+
onSelectionChange={onSelectionChange}
|
|
226
|
+
editable={!inputDisabled}
|
|
227
|
+
onChangeText={onChangeText}
|
|
228
|
+
style={styles.input}
|
|
229
|
+
placeholder={getPlaceholder()}
|
|
230
|
+
>
|
|
231
|
+
{mentionManager.textToMentionedComponents(
|
|
232
|
+
text,
|
|
233
|
+
mentionedUsers,
|
|
234
|
+
sbOptions.uikit.groupChannel.channel.enableMention,
|
|
235
|
+
)}
|
|
236
|
+
</TextInput>
|
|
237
|
+
|
|
238
|
+
{Boolean(text.trim()) && (
|
|
239
|
+
<TouchableOpacity onPress={sendUserMessage} disabled={inputDisabled}>
|
|
240
|
+
<Icon
|
|
241
|
+
color={
|
|
242
|
+
inputDisabled ? colors.ui.input.default.disabled.highlight : colors.ui.input.default.active.highlight
|
|
243
|
+
}
|
|
244
|
+
icon={'send'}
|
|
245
|
+
size={24}
|
|
246
|
+
containerStyle={styles.iconSend}
|
|
247
|
+
/>
|
|
248
|
+
</TouchableOpacity>
|
|
249
|
+
)}
|
|
250
|
+
</View>
|
|
126
251
|
</View>
|
|
127
252
|
);
|
|
128
253
|
});
|
|
@@ -353,6 +478,14 @@ const styles = createStyleSheet({
|
|
|
353
478
|
marginLeft: 4,
|
|
354
479
|
padding: 4,
|
|
355
480
|
},
|
|
481
|
+
previewImage: {
|
|
482
|
+
width: 36,
|
|
483
|
+
height: 36,
|
|
484
|
+
borderRadius: 10,
|
|
485
|
+
marginTop: 2,
|
|
486
|
+
marginRight: 10,
|
|
487
|
+
overflow: 'hidden',
|
|
488
|
+
},
|
|
356
489
|
});
|
|
357
490
|
|
|
358
491
|
export default SendInput;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { MutableRefObject, useEffect,
|
|
1
|
+
import React, { MutableRefObject, useEffect, useState } from 'react';
|
|
2
2
|
import { KeyboardAvoidingView, Platform, TextInput, View } from 'react-native';
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
4
|
|
|
@@ -56,6 +56,10 @@ export type ChannelInputProps = {
|
|
|
56
56
|
messageToEdit: undefined | SendbirdUserMessage | SendbirdFileMessage;
|
|
57
57
|
setMessageToEdit: (message?: undefined | SendbirdUserMessage | SendbirdFileMessage) => void;
|
|
58
58
|
|
|
59
|
+
// reply - only available on group channel
|
|
60
|
+
messageToReply?: undefined | SendbirdUserMessage | SendbirdFileMessage;
|
|
61
|
+
setMessageToReply?: (message?: undefined | SendbirdUserMessage | SendbirdFileMessage) => void;
|
|
62
|
+
|
|
59
63
|
// mention
|
|
60
64
|
SuggestedMentionList?: (props: SuggestedMentionListProps) => JSX.Element | null;
|
|
61
65
|
|
|
@@ -83,9 +87,8 @@ const ChannelInput = (props: ChannelInputProps) => {
|
|
|
83
87
|
messageToEdit,
|
|
84
88
|
});
|
|
85
89
|
const inputMode = useIIFE(() => {
|
|
86
|
-
if (!messageToEdit) return '
|
|
87
|
-
|
|
88
|
-
return 'edit';
|
|
90
|
+
if (messageToEdit && !messageToEdit.isFileMessage()) return 'edit';
|
|
91
|
+
else return 'send';
|
|
89
92
|
});
|
|
90
93
|
|
|
91
94
|
const mentionAvailable =
|
|
@@ -95,7 +98,7 @@ const ChannelInput = (props: ChannelInputProps) => {
|
|
|
95
98
|
const [inputHeight, setInputHeight] = useState(styles.inputDefault.height);
|
|
96
99
|
|
|
97
100
|
useTypingTrigger(text, channel);
|
|
98
|
-
|
|
101
|
+
useTextClearOnDisabled(onChangeText, props.inputDisabled);
|
|
99
102
|
useAutoFocusOnEditMode(textInputRef, messageToEdit);
|
|
100
103
|
|
|
101
104
|
const onPressToMention = (user: SendbirdMember, searchStringRange: Range) => {
|
|
@@ -138,8 +141,8 @@ const ChannelInput = (props: ChannelInputProps) => {
|
|
|
138
141
|
onChangeText={onChangeText}
|
|
139
142
|
autoFocus={AUTO_FOCUS}
|
|
140
143
|
onSelectionChange={onSelectionChange}
|
|
141
|
-
messageToEdit={messageToEdit}
|
|
142
144
|
mentionedUsers={mentionedUsers}
|
|
145
|
+
messageToEdit={messageToEdit}
|
|
143
146
|
setMessageToEdit={setMessageToEdit}
|
|
144
147
|
/>
|
|
145
148
|
)}
|
|
@@ -171,16 +174,9 @@ const useTypingTrigger = (text: string, channel: SendbirdBaseChannel) => {
|
|
|
171
174
|
}
|
|
172
175
|
};
|
|
173
176
|
|
|
174
|
-
const
|
|
175
|
-
const textTmpRef = useRef('');
|
|
176
|
-
|
|
177
|
+
const useTextClearOnDisabled = (setText: (val: string) => void, chatDisabled: boolean) => {
|
|
177
178
|
useEffect(() => {
|
|
178
|
-
if (chatDisabled)
|
|
179
|
-
textTmpRef.current = text;
|
|
180
|
-
setText('');
|
|
181
|
-
} else {
|
|
182
|
-
setText(textTmpRef.current);
|
|
183
|
-
}
|
|
179
|
+
if (chatDisabled) setText('');
|
|
184
180
|
}, [chatDisabled]);
|
|
185
181
|
};
|
|
186
182
|
|
|
@@ -55,8 +55,10 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
|
|
|
55
55
|
onPressScrollToBottomButton: (animated?: boolean) => void;
|
|
56
56
|
|
|
57
57
|
onEditMessage: (message: HandleableMessage) => void;
|
|
58
|
+
onReplyMessage?: (message: HandleableMessage) => void; // only available on group channel
|
|
58
59
|
onDeleteMessage: (message: HandleableMessage) => Promise<void>;
|
|
59
60
|
onResendFailedMessage: (failedMessage: HandleableMessage) => Promise<void>;
|
|
61
|
+
onPressParentMessage?: (parentMessage: SendbirdMessage) => void;
|
|
60
62
|
onPressMediaMessage?: (message: SendbirdFileMessage, deleteMessage: () => Promise<void>, uri: string) => void;
|
|
61
63
|
|
|
62
64
|
renderMessage: (props: {
|
|
@@ -66,6 +68,7 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
|
|
|
66
68
|
nextMessage?: SendbirdMessage;
|
|
67
69
|
onPress?: () => void;
|
|
68
70
|
onLongPress?: () => void;
|
|
71
|
+
onPressParentMessage?: ChannelMessageListProps<T>['onPressParentMessage'];
|
|
69
72
|
onShowUserProfile?: UserProfileContextType['show'];
|
|
70
73
|
channel: T;
|
|
71
74
|
currentUserId?: ChannelMessageListProps<T>['currentUserId'];
|
|
@@ -91,9 +94,11 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
|
|
|
91
94
|
hasNext,
|
|
92
95
|
channel,
|
|
93
96
|
onEditMessage,
|
|
97
|
+
onReplyMessage,
|
|
94
98
|
onDeleteMessage,
|
|
95
99
|
onResendFailedMessage,
|
|
96
100
|
onPressMediaMessage,
|
|
101
|
+
onPressParentMessage,
|
|
97
102
|
currentUserId,
|
|
98
103
|
renderNewMessagesButton,
|
|
99
104
|
renderScrollToBottomButton,
|
|
@@ -119,6 +124,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
|
|
|
119
124
|
channel,
|
|
120
125
|
currentUserId,
|
|
121
126
|
onEditMessage,
|
|
127
|
+
onReplyMessage,
|
|
122
128
|
onDeleteMessage,
|
|
123
129
|
onResendFailedMessage,
|
|
124
130
|
onPressMediaMessage,
|
|
@@ -134,6 +140,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
|
|
|
134
140
|
nextMessage: messages[index - 1],
|
|
135
141
|
onPress,
|
|
136
142
|
onLongPress,
|
|
143
|
+
onPressParentMessage,
|
|
137
144
|
onShowUserProfile: show,
|
|
138
145
|
enableMessageGrouping,
|
|
139
146
|
channel,
|
|
@@ -188,11 +195,18 @@ const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpen
|
|
|
188
195
|
currentUserId,
|
|
189
196
|
onResendFailedMessage,
|
|
190
197
|
onEditMessage,
|
|
198
|
+
onReplyMessage,
|
|
191
199
|
onDeleteMessage,
|
|
192
200
|
onPressMediaMessage,
|
|
193
201
|
}: Pick<
|
|
194
202
|
ChannelMessageListProps<T>,
|
|
195
|
-
|
|
203
|
+
| 'channel'
|
|
204
|
+
| 'currentUserId'
|
|
205
|
+
| 'onEditMessage'
|
|
206
|
+
| 'onReplyMessage'
|
|
207
|
+
| 'onDeleteMessage'
|
|
208
|
+
| 'onResendFailedMessage'
|
|
209
|
+
| 'onPressMediaMessage'
|
|
196
210
|
>) => {
|
|
197
211
|
const { colors } = useUIKitTheme();
|
|
198
212
|
const { STRINGS } = useLocalization();
|
|
@@ -202,13 +216,18 @@ const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpen
|
|
|
202
216
|
const { clipboardService, fileService } = usePlatformService();
|
|
203
217
|
const { sbOptions } = useSendbirdChat();
|
|
204
218
|
|
|
219
|
+
const onFailureToReSend = (error: Error) => {
|
|
220
|
+
toast.show(STRINGS.TOAST.RESEND_MSG_ERROR, 'error');
|
|
221
|
+
Logger.error(STRINGS.TOAST.RESEND_MSG_ERROR, error);
|
|
222
|
+
};
|
|
223
|
+
|
|
205
224
|
const handleFailedMessage = (message: HandleableMessage) => {
|
|
206
225
|
openSheet({
|
|
207
226
|
sheetItems: [
|
|
208
227
|
{
|
|
209
228
|
title: STRINGS.LABELS.CHANNEL_MESSAGE_FAILED_RETRY,
|
|
210
229
|
onPress: () => {
|
|
211
|
-
onResendFailedMessage(message).catch(
|
|
230
|
+
onResendFailedMessage(message).catch(onFailureToReSend);
|
|
212
231
|
},
|
|
213
232
|
},
|
|
214
233
|
{
|
|
@@ -257,25 +276,7 @@ const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpen
|
|
|
257
276
|
toast.show(STRINGS.TOAST.COPY_OK, 'success');
|
|
258
277
|
},
|
|
259
278
|
});
|
|
260
|
-
|
|
261
|
-
if (!channel.isEphemeral) {
|
|
262
|
-
if (isMyMessage(msg, currentUserId) && msg.sendingStatus === 'succeeded') {
|
|
263
|
-
sheetItems.push(
|
|
264
|
-
{
|
|
265
|
-
icon: 'edit',
|
|
266
|
-
title: STRINGS.LABELS.CHANNEL_MESSAGE_EDIT,
|
|
267
|
-
onPress: () => onEditMessage(msg),
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
icon: 'delete',
|
|
271
|
-
title: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE,
|
|
272
|
-
onPress: () => confirmDelete(msg),
|
|
273
|
-
},
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
279
|
}
|
|
278
|
-
|
|
279
280
|
if (msg.isFileMessage()) {
|
|
280
281
|
sheetItems.push({
|
|
281
282
|
icon: 'download',
|
|
@@ -297,17 +298,34 @@ const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpen
|
|
|
297
298
|
});
|
|
298
299
|
},
|
|
299
300
|
});
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
}
|
|
302
|
+
if (!channel.isEphemeral) {
|
|
303
|
+
if (isMyMessage(msg, currentUserId) && msg.sendingStatus === 'succeeded') {
|
|
304
|
+
if (msg.isUserMessage()) {
|
|
303
305
|
sheetItems.push({
|
|
304
|
-
icon: '
|
|
305
|
-
title: STRINGS.LABELS.
|
|
306
|
-
onPress: () =>
|
|
306
|
+
icon: 'edit',
|
|
307
|
+
title: STRINGS.LABELS.CHANNEL_MESSAGE_EDIT,
|
|
308
|
+
onPress: () => onEditMessage(msg),
|
|
307
309
|
});
|
|
308
310
|
}
|
|
311
|
+
sheetItems.push({
|
|
312
|
+
disabled: msg.threadInfo ? msg.threadInfo.replyCount > 0 : undefined,
|
|
313
|
+
icon: 'delete',
|
|
314
|
+
title: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE,
|
|
315
|
+
onPress: () => confirmDelete(msg),
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
if (channel.isGroupChannel() && sbOptions.uikit.groupChannel.channel.replyType === 'quote_reply') {
|
|
319
|
+
sheetItems.push({
|
|
320
|
+
disabled: Boolean(msg.parentMessageId),
|
|
321
|
+
icon: 'reply',
|
|
322
|
+
title: STRINGS.LABELS.CHANNEL_MESSAGE_REPLY,
|
|
323
|
+
onPress: () => onReplyMessage?.(msg),
|
|
324
|
+
});
|
|
309
325
|
}
|
|
326
|
+
}
|
|
310
327
|
|
|
328
|
+
if (msg.isFileMessage()) {
|
|
311
329
|
const fileType = getFileType(msg.type || getFileExtension(msg.name));
|
|
312
330
|
switch (fileType) {
|
|
313
331
|
case 'image':
|
|
@@ -342,7 +360,7 @@ const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpen
|
|
|
342
360
|
if (msg.sendingStatus === 'failed') {
|
|
343
361
|
response.onLongPress = () => handleFailedMessage(msg);
|
|
344
362
|
response.onPress = () => {
|
|
345
|
-
onResendFailedMessage(msg).catch(
|
|
363
|
+
onResendFailedMessage(msg).catch(onFailureToReSend);
|
|
346
364
|
};
|
|
347
365
|
}
|
|
348
366
|
|
|
@@ -7,7 +7,7 @@ import { NOOP, SendbirdMessage, getMessageUniqId, useFreshCallback } from '@send
|
|
|
7
7
|
import FlatListInternal from './FlatListInternal';
|
|
8
8
|
|
|
9
9
|
let ANDROID_BUG_ALERT_SHOWED = Platform.OS !== 'android';
|
|
10
|
-
const BOTTOM_DETECT_THRESHOLD =
|
|
10
|
+
const BOTTOM_DETECT_THRESHOLD = 50;
|
|
11
11
|
const UNREACHABLE_THRESHOLD = Number.MIN_SAFE_INTEGER;
|
|
12
12
|
|
|
13
13
|
type Props = Omit<FlatListProps<SendbirdMessage>, 'onEndReached'> & {
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
2
|
import { Animated, Easing } from 'react-native';
|
|
3
3
|
|
|
4
|
+
import { useIsFirstMount } from '@sendbird/uikit-utils';
|
|
5
|
+
|
|
4
6
|
import { MESSAGE_FOCUS_ANIMATION_DELAY, MESSAGE_SEARCH_SAFE_SCROLL_DELAY } from '../../constants';
|
|
5
7
|
|
|
6
8
|
const GroupChannelMessageFocusAnimation = (props: React.PropsWithChildren<{ focused: boolean }>) => {
|
|
9
|
+
const isFirstMount = useIsFirstMount();
|
|
7
10
|
const translateY = useRef(new Animated.Value(0)).current;
|
|
8
11
|
|
|
9
12
|
useEffect(() => {
|
|
10
13
|
if (props.focused) {
|
|
14
|
+
const delay = MESSAGE_FOCUS_ANIMATION_DELAY + (isFirstMount ? MESSAGE_SEARCH_SAFE_SCROLL_DELAY : 0);
|
|
11
15
|
setTimeout(() => {
|
|
12
16
|
Animated.sequence(
|
|
13
17
|
[
|
|
@@ -19,7 +23,7 @@ const GroupChannelMessageFocusAnimation = (props: React.PropsWithChildren<{ focu
|
|
|
19
23
|
Animated.timing(translateY, { ...value, useNativeDriver: true, easing: Easing.inOut(Easing.ease) }),
|
|
20
24
|
),
|
|
21
25
|
).start();
|
|
22
|
-
},
|
|
26
|
+
}, delay);
|
|
23
27
|
}
|
|
24
28
|
}, [props.focused]);
|
|
25
29
|
|