agora-appbuilder-core 4.0.30 → 4.0.31-beta-2
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/package.json +1 -1
- package/template/customization-api/sub-components.ts +1 -0
- package/template/defaultConfig.js +2 -2
- package/template/package.json +1 -1
- package/template/src/components/ChatContext.ts +3 -0
- package/template/src/components/Controls.tsx +80 -18
- package/template/src/components/Navbar.tsx +29 -1
- package/template/src/components/chat/chatConfigure.native.tsx +85 -25
- package/template/src/components/chat/chatConfigure.tsx +99 -9
- package/template/src/components/chat-messages/useChatMessages.tsx +32 -39
- package/template/src/components/chat-ui/useChatUIControls.tsx +21 -0
- package/template/src/components/precall/joinWaitingRoomBtn.tsx +25 -6
- package/template/src/components/room-info/useRoomInfo.tsx +12 -0
- package/template/src/pages/Create.tsx +26 -1
- package/template/src/pages/video-call/VideoCallMobileView.tsx +3 -2
- package/template/src/pages/video-call/VideoCallScreen.tsx +3 -1
- package/template/src/subComponents/ChatBubble.tsx +388 -110
- package/template/src/subComponents/ChatContainer.tsx +76 -53
- package/template/src/subComponents/ChatInput.native.tsx +93 -14
- package/template/src/subComponents/ChatInput.tsx +41 -7
- package/template/src/subComponents/caption/Caption.tsx +14 -2
- package/template/src/subComponents/caption/CaptionContainer.tsx +24 -3
- package/template/src/subComponents/caption/CaptionText.tsx +13 -1
- package/template/src/subComponents/chat/ChatActionMenu.tsx +40 -3
- package/template/src/subComponents/chat/ChatAttachment.native.tsx +4 -2
- package/template/src/subComponents/chat/ChatEmoji.native.tsx +181 -22
- package/template/src/subComponents/chat/ChatEmoji.tsx +4 -3
- package/template/src/subComponents/chat/ChatQuickActionsMenu.tsx +70 -34
- package/template/src/subComponents/chat/ChatSendButton.tsx +42 -1
- package/template/src/subComponents/chat/PinnedMessage.tsx +207 -0
- package/template/src/utils/useCreateRoom.ts +23 -4
- package/template/src/utils/useJoinRoom.ts +76 -23
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
groupChatWelcomeContent,
|
|
59
59
|
} from '../language/default-labels/videoCallScreenLabels';
|
|
60
60
|
import CommonStyles from '../components/CommonStyles';
|
|
61
|
+
import PinnedMessage from './chat/PinnedMessage';
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
64
|
* Chat container is the component which renders all the chat messages
|
|
@@ -76,8 +77,15 @@ const ChatContainer = (props?: {
|
|
|
76
77
|
const {privateMessageStore, messageStore} = useChatMessages();
|
|
77
78
|
const messageStoreLengthRef = useRef(messageStore.length);
|
|
78
79
|
const {height, width} = useWindowDimensions();
|
|
79
|
-
const {
|
|
80
|
-
|
|
80
|
+
const {
|
|
81
|
+
chatType,
|
|
82
|
+
setChatType,
|
|
83
|
+
privateChatUser,
|
|
84
|
+
inputActive,
|
|
85
|
+
showEmojiPicker,
|
|
86
|
+
pinMsgId,
|
|
87
|
+
pinnedByUser,
|
|
88
|
+
} = useChatUIControls();
|
|
81
89
|
const privateMessageStoreRef = useRef(
|
|
82
90
|
privateMessageStore[privateChatUser]?.length,
|
|
83
91
|
);
|
|
@@ -212,6 +220,9 @@ const ChatContainer = (props?: {
|
|
|
212
220
|
) : (
|
|
213
221
|
<></>
|
|
214
222
|
)}
|
|
223
|
+
{pinMsgId && (
|
|
224
|
+
<PinnedMessage pinMsgId={pinMsgId} pinnedByUser={pinnedByUser} />
|
|
225
|
+
)}
|
|
215
226
|
<ScrollView
|
|
216
227
|
ref={scrollViewRef}
|
|
217
228
|
onContentSizeChange={onContentSizeChange}
|
|
@@ -223,6 +234,7 @@ const ChatContainer = (props?: {
|
|
|
223
234
|
{info1(messageStore?.length ? false : true)}
|
|
224
235
|
</Text>
|
|
225
236
|
</View>
|
|
237
|
+
|
|
226
238
|
{messageStore.map((message: messageStoreInterface, index) => (
|
|
227
239
|
<>
|
|
228
240
|
{messageStoreLengthRef.current === messageStore.length &&
|
|
@@ -241,34 +253,38 @@ const ChatContainer = (props?: {
|
|
|
241
253
|
) : (
|
|
242
254
|
<></>
|
|
243
255
|
)}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
256
|
+
{!message?.hide ? (
|
|
257
|
+
<ChatBubbleComponent
|
|
258
|
+
isLocal={localUid === message.uid}
|
|
259
|
+
isSameUser={
|
|
260
|
+
index !== 0 && messageStore[index - 1].uid === message.uid
|
|
261
|
+
? true
|
|
262
|
+
: false
|
|
263
|
+
}
|
|
264
|
+
previousMessageCreatedTimestamp={
|
|
265
|
+
index !== 0
|
|
266
|
+
? (messageStore[index - 1]
|
|
267
|
+
.createdTimestamp as unknown as string)
|
|
268
|
+
: ''
|
|
269
|
+
}
|
|
270
|
+
message={message.msg}
|
|
271
|
+
createdTimestamp={message.createdTimestamp}
|
|
272
|
+
updatedTimestamp={message.updatedTimestamp}
|
|
273
|
+
uid={message.uid}
|
|
274
|
+
key={message.msgId}
|
|
275
|
+
msgId={message.msgId}
|
|
276
|
+
isDeleted={message.isDeleted}
|
|
277
|
+
type={message.type}
|
|
278
|
+
url={message?.url}
|
|
279
|
+
thumb={message?.thumb}
|
|
280
|
+
fileName={message?.fileName}
|
|
281
|
+
ext={message?.ext}
|
|
282
|
+
reactions={message?.reactions}
|
|
283
|
+
scrollOffset={scrollOffset}
|
|
284
|
+
replyToMsgId={message?.replyToMsgId}
|
|
285
|
+
isLastMsg={messageStore.length - 1 === index}
|
|
286
|
+
/>
|
|
287
|
+
) : null}
|
|
272
288
|
{messageStore?.length - 1 === index ? (
|
|
273
289
|
<Spacer size={10} />
|
|
274
290
|
) : (
|
|
@@ -306,29 +322,36 @@ const ChatContainer = (props?: {
|
|
|
306
322
|
) : (
|
|
307
323
|
<></>
|
|
308
324
|
)}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
325
|
+
{!message?.hide ? (
|
|
326
|
+
<ChatBubbleComponent
|
|
327
|
+
isLocal={localUid === message.uid}
|
|
328
|
+
isSameUser={
|
|
329
|
+
index !== 0 &&
|
|
330
|
+
privateMessageStore[privateChatUser][index - 1].uid ===
|
|
331
|
+
message.uid
|
|
332
|
+
? true
|
|
333
|
+
: false
|
|
334
|
+
}
|
|
335
|
+
message={message.msg}
|
|
336
|
+
createdTimestamp={message.createdTimestamp}
|
|
337
|
+
updatedTimestamp={message.updatedTimestamp}
|
|
338
|
+
uid={message.uid}
|
|
339
|
+
key={message.msgId}
|
|
340
|
+
msgId={message.msgId}
|
|
341
|
+
isDeleted={message.isDeleted}
|
|
342
|
+
type={message.type}
|
|
343
|
+
url={message?.url}
|
|
344
|
+
thumb={message?.thumb}
|
|
345
|
+
fileName={message?.fileName}
|
|
346
|
+
ext={message?.ext}
|
|
347
|
+
reactions={message?.reactions}
|
|
348
|
+
replyToMsgId={message?.replyToMsgId}
|
|
349
|
+
isLastMsg={
|
|
350
|
+
privateMessageStore[privateChatUser].length - 1 ===
|
|
351
|
+
index
|
|
352
|
+
}
|
|
353
|
+
/>
|
|
354
|
+
) : null}
|
|
332
355
|
{privateMessageStore[privateChatUser]?.length - 1 ===
|
|
333
356
|
index ? (
|
|
334
357
|
<Spacer size={10} />
|
|
@@ -17,9 +17,10 @@ import {
|
|
|
17
17
|
Image,
|
|
18
18
|
Text,
|
|
19
19
|
TextInput,
|
|
20
|
+
ViewStyle,
|
|
20
21
|
} from 'react-native';
|
|
21
22
|
import {useString} from '../utils/useString';
|
|
22
|
-
import {ChatEmojiPicker, ChatEmojiButton} from './chat/ChatEmoji';
|
|
23
|
+
import {ChatEmojiPicker, ChatEmojiButton} from './chat/ChatEmoji.native';
|
|
23
24
|
|
|
24
25
|
import {
|
|
25
26
|
ChatType,
|
|
@@ -47,11 +48,31 @@ import {useChatConfigure} from '../components/chat/chatConfigure';
|
|
|
47
48
|
import {
|
|
48
49
|
ChatMessageType,
|
|
49
50
|
SDKChatType,
|
|
51
|
+
useChatMessages,
|
|
50
52
|
} from '../components/chat-messages/useChatMessages';
|
|
51
53
|
import hexadecimalTransparency from '../utils/hexadecimalTransparency';
|
|
52
54
|
import ChatUploadStatus from './chat/ChatUploadStatus';
|
|
53
55
|
import {isAndroid} from '../utils/common';
|
|
54
56
|
import Toast from '../../react-native-toast-message';
|
|
57
|
+
import {ReplyMessageBubble} from './ChatBubble';
|
|
58
|
+
import {
|
|
59
|
+
ChatError,
|
|
60
|
+
ChatMessage,
|
|
61
|
+
ChatMessageChatType,
|
|
62
|
+
} from 'react-native-agora-chat';
|
|
63
|
+
|
|
64
|
+
interface ExtendedChatMessage extends ChatMessage {
|
|
65
|
+
body: {
|
|
66
|
+
localPath?: string;
|
|
67
|
+
remotePath?: string;
|
|
68
|
+
type: ChatMessageType;
|
|
69
|
+
};
|
|
70
|
+
attributes: {
|
|
71
|
+
file_ext?: string;
|
|
72
|
+
file_name?: string;
|
|
73
|
+
replyToMsgId?: string;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
55
76
|
|
|
56
77
|
export interface ChatSendButtonProps {
|
|
57
78
|
render?: (onPress: () => void) => JSX.Element;
|
|
@@ -62,7 +83,7 @@ const ChatPanel = () => {
|
|
|
62
83
|
<View style={style.chatPanelContainer}>
|
|
63
84
|
<View style={style.chatPanel}>
|
|
64
85
|
<ChatAttachmentButton />
|
|
65
|
-
|
|
86
|
+
<ChatEmojiButton />
|
|
66
87
|
</View>
|
|
67
88
|
<ChatSendButton />
|
|
68
89
|
</View>
|
|
@@ -76,6 +97,7 @@ export interface ChatTextInputProps {
|
|
|
76
97
|
onSubmitEditing: () => void,
|
|
77
98
|
chatMessageInputPlaceholder: string,
|
|
78
99
|
) => JSX.Element;
|
|
100
|
+
style?: ViewStyle;
|
|
79
101
|
}
|
|
80
102
|
export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
81
103
|
const {
|
|
@@ -87,6 +109,7 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
87
109
|
uploadStatus,
|
|
88
110
|
inputHeight,
|
|
89
111
|
setInputHeight,
|
|
112
|
+
replyToMsgId,
|
|
90
113
|
} = useChatUIControls();
|
|
91
114
|
|
|
92
115
|
const {defaultContent} = useContent();
|
|
@@ -100,6 +123,8 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
100
123
|
privateChatInputPlaceHolderText,
|
|
101
124
|
);
|
|
102
125
|
|
|
126
|
+
const {addMessageToPrivateStore, addMessageToStore} = useChatMessages();
|
|
127
|
+
|
|
103
128
|
// React.useEffect(() => {
|
|
104
129
|
// if (message.length === 0) {
|
|
105
130
|
// setInputHeight(MIN_HEIGHT);
|
|
@@ -153,8 +178,36 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
153
178
|
from: data.uid.toString(),
|
|
154
179
|
to: privateChatUser ? privateChatUser.toString() : groupID,
|
|
155
180
|
msg: message,
|
|
181
|
+
ext: {
|
|
182
|
+
replyToMsgId,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
const onProgress = (localMsgId: string, progress: number) => {
|
|
186
|
+
console.warn('chat msg in progress', progress);
|
|
187
|
+
};
|
|
188
|
+
const onError = (localMsgId: string, error: ChatError) => {
|
|
189
|
+
console.warn('chat msg in error', error);
|
|
190
|
+
};
|
|
191
|
+
const onSuccess = (message: ExtendedChatMessage) => {
|
|
192
|
+
console.warn('chat msg in success', message);
|
|
193
|
+
// Text message added here , attachments are added in ChatAttachment.native
|
|
194
|
+
const messageData = {
|
|
195
|
+
msg: option.msg.replace(/^(\n)+|(\n)+$/g, ''),
|
|
196
|
+
createdTimestamp: message.localTime,
|
|
197
|
+
msgId: message.msgId,
|
|
198
|
+
isDeleted: false,
|
|
199
|
+
type: message.body.type,
|
|
200
|
+
replyToMsgId: message.attributes?.replyToMsgId,
|
|
201
|
+
};
|
|
202
|
+
console.warn('message data', messageData);
|
|
203
|
+
// this is local user messages
|
|
204
|
+
if (message.chatType === ChatMessageChatType.PeerChat) {
|
|
205
|
+
addMessageToPrivateStore(Number(message.to), messageData, true);
|
|
206
|
+
} else {
|
|
207
|
+
addMessageToStore(Number(message.from), messageData);
|
|
208
|
+
}
|
|
156
209
|
};
|
|
157
|
-
sendChatSDKMessage(option);
|
|
210
|
+
sendChatSDKMessage(option, {onProgress, onError, onSuccess});
|
|
158
211
|
setInputHeight(MIN_HEIGHT);
|
|
159
212
|
setMessage('');
|
|
160
213
|
};
|
|
@@ -199,6 +252,7 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
199
252
|
borderTopLeftRadius: isUploadStatusShown ? 0 : 8,
|
|
200
253
|
maxHeight: MAX_HEIGHT,
|
|
201
254
|
overflow: 'scroll',
|
|
255
|
+
...props.style,
|
|
202
256
|
}}
|
|
203
257
|
blurOnSubmit={false}
|
|
204
258
|
onSubmitEditing={onSubmitEditing}
|
|
@@ -216,20 +270,36 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
216
270
|
* Input component for the Chat interface
|
|
217
271
|
*/
|
|
218
272
|
const ChatInput = () => {
|
|
219
|
-
const {
|
|
273
|
+
const {
|
|
274
|
+
inputActive,
|
|
275
|
+
showEmojiPicker,
|
|
276
|
+
replyToMsgId,
|
|
277
|
+
setShowEmojiPicker,
|
|
278
|
+
setMessage,
|
|
279
|
+
} = useChatUIControls();
|
|
220
280
|
return (
|
|
221
|
-
<View
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
281
|
+
<View style={[style.inputContainer]}>
|
|
282
|
+
{showEmojiPicker && (
|
|
283
|
+
<ChatEmojiPicker
|
|
284
|
+
isEmojiPickerOpen={true}
|
|
285
|
+
setIsEmojiPickerOpen={setShowEmojiPicker}
|
|
286
|
+
onEmojiSelect={emoji => setMessage(prev => prev + ' ' + emoji)}
|
|
287
|
+
/>
|
|
288
|
+
)}
|
|
289
|
+
|
|
230
290
|
<View style={style.inputView}>
|
|
231
291
|
<ChatUploadStatus />
|
|
232
|
-
<
|
|
292
|
+
<View style={replyToMsgId ? [style.inputWrapper, {}] : {}}>
|
|
293
|
+
{replyToMsgId && (
|
|
294
|
+
<ReplyMessageBubble
|
|
295
|
+
repliedMsgId={replyToMsgId}
|
|
296
|
+
replyTxt={''}
|
|
297
|
+
showCoseIcon={true}
|
|
298
|
+
showPreview={false}
|
|
299
|
+
/>
|
|
300
|
+
)}
|
|
301
|
+
<ChatTextInput style={replyToMsgId ? {borderWidth: 0} : {}} />
|
|
302
|
+
</View>
|
|
233
303
|
<ChatPanel />
|
|
234
304
|
</View>
|
|
235
305
|
</View>
|
|
@@ -265,5 +335,14 @@ const style = StyleSheet.create({
|
|
|
265
335
|
chatPanel: {
|
|
266
336
|
flexDirection: 'row',
|
|
267
337
|
},
|
|
338
|
+
inputWrapper: {
|
|
339
|
+
paddingHorizontal: 12,
|
|
340
|
+
paddingTop: 12,
|
|
341
|
+
backgroundColor: $config.CARD_LAYER_2_COLOR,
|
|
342
|
+
borderWidth: 1,
|
|
343
|
+
borderColor: $config.CARD_LAYER_5_COLOR + hexadecimalTransparency['40%'],
|
|
344
|
+
borderRadius: 8,
|
|
345
|
+
borderTopWidth: 1,
|
|
346
|
+
},
|
|
268
347
|
});
|
|
269
348
|
export default ChatInput;
|
|
@@ -43,6 +43,7 @@ import ChatSendButton, {handleChatSend} from './chat/ChatSendButton';
|
|
|
43
43
|
import {
|
|
44
44
|
ChatMessageType,
|
|
45
45
|
SDKChatType,
|
|
46
|
+
useChatMessages,
|
|
46
47
|
} from '../components/chat-messages/useChatMessages';
|
|
47
48
|
import {
|
|
48
49
|
groupChatLiveInputPlaceHolderText,
|
|
@@ -52,7 +53,7 @@ import {
|
|
|
52
53
|
chatSendErrorTextSizeToastSubHeading,
|
|
53
54
|
} from '../language/default-labels/videoCallScreenLabels';
|
|
54
55
|
import ChatUploadStatus from './chat/ChatUploadStatus';
|
|
55
|
-
import {AttachmentBubble} from './ChatBubble';
|
|
56
|
+
import {AttachmentBubble, ReplyMessageBubble} from './ChatBubble';
|
|
56
57
|
import IconButton from '../atoms/IconButton';
|
|
57
58
|
import Toast from '../../react-native-toast-message';
|
|
58
59
|
|
|
@@ -93,9 +94,12 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
93
94
|
_handleHeightChange,
|
|
94
95
|
chatInputRef,
|
|
95
96
|
showEmojiPicker,
|
|
97
|
+
replyToMsgId,
|
|
98
|
+
setReplyToMsgId,
|
|
96
99
|
} = useChatUIControls();
|
|
97
100
|
const {defaultContent} = useContent();
|
|
98
101
|
const {sendChatSDKMessage, uploadAttachment} = useChatConfigure();
|
|
102
|
+
const {addMessageToPrivateStore, addMessageToStore} = useChatMessages();
|
|
99
103
|
|
|
100
104
|
React.useEffect(() => {
|
|
101
105
|
if (message.length === 0) {
|
|
@@ -155,6 +159,10 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
155
159
|
toastHeadingSize,
|
|
156
160
|
errorSubHeadingSize,
|
|
157
161
|
_resetTextareaHeight,
|
|
162
|
+
replyToMsgId,
|
|
163
|
+
setReplyToMsgId,
|
|
164
|
+
addMessageToStore,
|
|
165
|
+
addMessageToPrivateStore,
|
|
158
166
|
});
|
|
159
167
|
};
|
|
160
168
|
|
|
@@ -197,7 +205,7 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
197
205
|
fontFamily: ThemeConfig.FontFamily.sansPro,
|
|
198
206
|
fontWeight: '400',
|
|
199
207
|
height: inputHeight,
|
|
200
|
-
padding: 12,
|
|
208
|
+
padding: replyToMsgId ? 0 : 12,
|
|
201
209
|
fontSize: ThemeConfig.FontSize.small,
|
|
202
210
|
lineHeight: LINE_HEIGHT,
|
|
203
211
|
borderWidth: 1,
|
|
@@ -269,6 +277,17 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
269
277
|
/>
|
|
270
278
|
);
|
|
271
279
|
|
|
280
|
+
const renderReplyMsg = () => {
|
|
281
|
+
return (
|
|
282
|
+
<ReplyMessageBubble
|
|
283
|
+
repliedMsgId={replyToMsgId}
|
|
284
|
+
replyTxt={''}
|
|
285
|
+
showCoseIcon={true}
|
|
286
|
+
showPreview={false}
|
|
287
|
+
/>
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
|
|
272
291
|
return props?.render ? (
|
|
273
292
|
props.render(
|
|
274
293
|
message,
|
|
@@ -281,7 +300,8 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
281
300
|
{uploadedFiles.length > 0 ? (
|
|
282
301
|
<View
|
|
283
302
|
style={[
|
|
284
|
-
style.
|
|
303
|
+
style.inputWrapper,
|
|
304
|
+
{paddingBottom: replyToMsgId ? 12 : 0},
|
|
285
305
|
isUploadStatusShown
|
|
286
306
|
? {
|
|
287
307
|
borderTopLeftRadius: 0,
|
|
@@ -291,12 +311,26 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
|
|
|
291
311
|
: {borderRadius: 8, borderTopWidth: 1},
|
|
292
312
|
]}>
|
|
293
313
|
<ScrollView style={{maxHeight: showEmojiPicker ? 120 : '100%'}}>
|
|
294
|
-
{uploadedFiles.map(renderAttachmentBubble)}
|
|
295
|
-
{renderTextInput({borderWidth: 0, padddingLeft: 0})}
|
|
314
|
+
{!replyToMsgId && uploadedFiles.map(renderAttachmentBubble)}
|
|
315
|
+
{/* {replyToMsgId && renderTextInput({borderWidth: 0, padddingLeft: 0})} */}
|
|
316
|
+
<View>
|
|
317
|
+
{replyToMsgId && <View>{renderReplyMsg()}</View>}
|
|
318
|
+
{replyToMsgId && uploadedFiles.map(renderAttachmentBubble)}
|
|
319
|
+
{!replyToMsgId &&
|
|
320
|
+
renderTextInput({borderWidth: 0, padddingLeft: 0})}
|
|
321
|
+
</View>
|
|
296
322
|
</ScrollView>
|
|
297
323
|
</View>
|
|
298
324
|
) : (
|
|
299
|
-
|
|
325
|
+
<View
|
|
326
|
+
style={
|
|
327
|
+
replyToMsgId
|
|
328
|
+
? [style.inputWrapper, {borderRadius: 8, borderTopWidth: 1}]
|
|
329
|
+
: {}
|
|
330
|
+
}>
|
|
331
|
+
{replyToMsgId && <View>{renderReplyMsg()}</View>}
|
|
332
|
+
{renderTextInput({borderWidth: 0, padddingLeft: 0})}
|
|
333
|
+
</View>
|
|
300
334
|
)}
|
|
301
335
|
</>
|
|
302
336
|
);
|
|
@@ -330,7 +364,7 @@ const style = StyleSheet.create({
|
|
|
330
364
|
borderTopWidth: 1,
|
|
331
365
|
borderTopColor: $config.PRIMARY_ACTION_BRAND_COLOR,
|
|
332
366
|
},
|
|
333
|
-
|
|
367
|
+
inputWrapper: {
|
|
334
368
|
paddingHorizontal: 12,
|
|
335
369
|
paddingTop: 12,
|
|
336
370
|
backgroundColor: $config.CARD_LAYER_2_COLOR,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {StyleSheet, View} from 'react-native';
|
|
1
|
+
import {StyleSheet, TextStyle, View} from 'react-native';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import {useContent, useRtc} from 'customization-api';
|
|
4
4
|
import {useCaption} from './useCaption';
|
|
@@ -14,7 +14,15 @@ type WebStreamMessageArgs = [number, Uint8Array];
|
|
|
14
14
|
type NativeStreamMessageArgs = [{}, number, number, Uint8Array, number, number];
|
|
15
15
|
type StreamMessageArgs = WebStreamMessageArgs | NativeStreamMessageArgs;
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
interface CaptionProps {
|
|
18
|
+
captionTextStyle?: TextStyle;
|
|
19
|
+
captionUserStyle?: TextStyle;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const Caption: React.FC<CaptionProps> = ({
|
|
23
|
+
captionTextStyle = {},
|
|
24
|
+
captionUserStyle = {},
|
|
25
|
+
}) => {
|
|
18
26
|
const {RtcEngineUnsafe} = useRtc();
|
|
19
27
|
const {
|
|
20
28
|
isLangChangeInProgress,
|
|
@@ -97,6 +105,8 @@ const Caption: React.FC = () => {
|
|
|
97
105
|
setActiveLinesAvailable={setActiveLinesAvailable}
|
|
98
106
|
inActiveLinesAvailable={inActiveLinesAvailable}
|
|
99
107
|
setInActiveLinesAvaialble={setInActiveLinesAvaialble}
|
|
108
|
+
captionUserStyle={captionUserStyle}
|
|
109
|
+
captionTextStyle={captionTextStyle}
|
|
100
110
|
/>
|
|
101
111
|
) : (
|
|
102
112
|
<></>
|
|
@@ -112,6 +122,8 @@ const Caption: React.FC = () => {
|
|
|
112
122
|
setActiveLinesAvailable={setActiveLinesAvailable}
|
|
113
123
|
inActiveLinesAvailable={inActiveLinesAvailable}
|
|
114
124
|
setInActiveLinesAvaialble={setInActiveLinesAvaialble}
|
|
125
|
+
captionUserStyle={captionUserStyle}
|
|
126
|
+
captionTextStyle={captionTextStyle}
|
|
115
127
|
/>
|
|
116
128
|
) : (
|
|
117
129
|
<></>
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
StyleSheet,
|
|
3
|
+
Text,
|
|
4
|
+
TextStyle,
|
|
5
|
+
useWindowDimensions,
|
|
6
|
+
View,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from 'react-native';
|
|
2
9
|
import React from 'react';
|
|
3
10
|
|
|
4
11
|
import Caption from './Caption';
|
|
@@ -37,7 +44,17 @@ import {
|
|
|
37
44
|
} from '../../language/default-labels/videoCallScreenLabels';
|
|
38
45
|
import {logger, LogSource} from '../../logger/AppBuilderLogger';
|
|
39
46
|
|
|
40
|
-
|
|
47
|
+
interface CaptionContainerProps {
|
|
48
|
+
containerStyle?: ViewStyle;
|
|
49
|
+
captionUserStyle?: TextStyle;
|
|
50
|
+
captionTextStyle?: TextStyle;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const CaptionContainer: React.FC<CaptionContainerProps> = ({
|
|
54
|
+
containerStyle = {},
|
|
55
|
+
captionUserStyle = {},
|
|
56
|
+
captionTextStyle = {},
|
|
57
|
+
}) => {
|
|
41
58
|
const moreIconRef = React.useRef<View>(null);
|
|
42
59
|
const [actionMenuVisible, setActionMenuVisible] =
|
|
43
60
|
React.useState<boolean>(false);
|
|
@@ -90,6 +107,7 @@ const CaptionContainer = () => {
|
|
|
90
107
|
isMobileUA() ? styles.mobileContainer : styles.container,
|
|
91
108
|
isMobileUA() && {marginHorizontal: 0},
|
|
92
109
|
!isMobileUA() && isSmall() && {marginTop: 0},
|
|
110
|
+
containerStyle,
|
|
93
111
|
]}>
|
|
94
112
|
<CaptionsActionMenu
|
|
95
113
|
actionMenuVisible={actionMenuVisible}
|
|
@@ -104,7 +122,10 @@ const CaptionContainer = () => {
|
|
|
104
122
|
/>
|
|
105
123
|
)}
|
|
106
124
|
|
|
107
|
-
<Caption
|
|
125
|
+
<Caption
|
|
126
|
+
captionUserStyle={captionUserStyle}
|
|
127
|
+
captionTextStyle={captionTextStyle}
|
|
128
|
+
/>
|
|
108
129
|
</View>
|
|
109
130
|
</View>
|
|
110
131
|
</PlatformWrapper>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Text,
|
|
3
|
+
View,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
LayoutChangeEvent,
|
|
6
|
+
TextStyle,
|
|
7
|
+
} from 'react-native';
|
|
2
8
|
import React from 'react';
|
|
3
9
|
|
|
4
10
|
import ThemeConfig from '../../../src/theme';
|
|
@@ -14,6 +20,8 @@ interface CaptionTextProps {
|
|
|
14
20
|
setActiveLinesAvailable?: React.Dispatch<React.SetStateAction<number>>;
|
|
15
21
|
inActiveLinesAvailable?: number;
|
|
16
22
|
setInActiveLinesAvaialble?: React.Dispatch<React.SetStateAction<number>>;
|
|
23
|
+
captionUserStyle?: TextStyle;
|
|
24
|
+
captionTextStyle?: TextStyle;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
const DESKTOP_LINE_HEIGHT = 28;
|
|
@@ -29,6 +37,8 @@ const CaptionText = ({
|
|
|
29
37
|
setActiveLinesAvailable,
|
|
30
38
|
inActiveLinesAvailable,
|
|
31
39
|
setInActiveLinesAvaialble,
|
|
40
|
+
captionUserStyle = {},
|
|
41
|
+
captionTextStyle = {},
|
|
32
42
|
}: CaptionTextProps) => {
|
|
33
43
|
const isMobile = isMobileUA();
|
|
34
44
|
|
|
@@ -95,6 +105,7 @@ const CaptionText = ({
|
|
|
95
105
|
style={[
|
|
96
106
|
styles.captionUserName,
|
|
97
107
|
isMobile ? styles.mobileNameFontSize : styles.desktopNameFontSize,
|
|
108
|
+
captionUserStyle,
|
|
98
109
|
]}
|
|
99
110
|
numberOfLines={1}
|
|
100
111
|
textBreakStrategy="simple"
|
|
@@ -122,6 +133,7 @@ const CaptionText = ({
|
|
|
122
133
|
? styles.mobileCaptionFontSize
|
|
123
134
|
: styles.desktopCaptionFontSize,
|
|
124
135
|
isAndroid() && {lineHeight: MOBILE_LINE_HEIGHT - 2},
|
|
136
|
+
captionTextStyle,
|
|
125
137
|
]}>
|
|
126
138
|
{value}
|
|
127
139
|
</Text>
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import {StyleSheet, Text, useWindowDimensions, View} from 'react-native';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
calculatePosition,
|
|
5
|
+
isMobileUA,
|
|
6
|
+
isWebInternal,
|
|
7
|
+
trimText,
|
|
8
|
+
} from '../../utils/common';
|
|
4
9
|
import IconButton from '../../atoms/IconButton';
|
|
5
10
|
import hexadecimalTransparency from '../../utils/hexadecimalTransparency';
|
|
6
11
|
import ActionMenu, {ActionMenuItem} from '../../../src/atoms/ActionMenu';
|
|
@@ -60,7 +65,13 @@ export const ChatActionMenu = (props: ChatActionMenuProps) => {
|
|
|
60
65
|
userId,
|
|
61
66
|
} = props;
|
|
62
67
|
|
|
63
|
-
const {
|
|
68
|
+
const {
|
|
69
|
+
setChatType,
|
|
70
|
+
setPrivateChatUser,
|
|
71
|
+
setReplyToMsgId,
|
|
72
|
+
pinMsgId,
|
|
73
|
+
pinnedByUser,
|
|
74
|
+
} = useChatUIControls();
|
|
64
75
|
|
|
65
76
|
const actionMenuitems: ActionMenuItem[] = [];
|
|
66
77
|
const [modalPosition, setModalPosition] = React.useState({});
|
|
@@ -68,7 +79,8 @@ export const ChatActionMenu = (props: ChatActionMenuProps) => {
|
|
|
68
79
|
const [showDeleteMessageModal, setShowDeleteMessageModal] =
|
|
69
80
|
React.useState(false);
|
|
70
81
|
const {width: globalWidth, height: globalHeight} = useWindowDimensions();
|
|
71
|
-
const {downloadAttachment, deleteAttachment} =
|
|
82
|
+
const {downloadAttachment, deleteAttachment, pinMessage, unPinMessage} =
|
|
83
|
+
useChatConfigure();
|
|
72
84
|
const {removeMessageFromPrivateStore, removeMessageFromStore} =
|
|
73
85
|
useChatMessages();
|
|
74
86
|
const {defaultContent} = useContent();
|
|
@@ -96,6 +108,31 @@ export const ChatActionMenu = (props: ChatActionMenuProps) => {
|
|
|
96
108
|
);
|
|
97
109
|
}
|
|
98
110
|
const copiedToClipboardTextLabel = useString(copiedToClipboardText)();
|
|
111
|
+
const isMsgPinned = pinMsgId === msgId && pinnedByUser === userId;
|
|
112
|
+
|
|
113
|
+
actionMenuitems.push({
|
|
114
|
+
icon: 'reply',
|
|
115
|
+
iconColor: $config.SECONDARY_ACTION_COLOR,
|
|
116
|
+
textColor: $config.FONT_COLOR,
|
|
117
|
+
title: 'Reply',
|
|
118
|
+
onPress: () => {
|
|
119
|
+
setReplyToMsgId(msgId);
|
|
120
|
+
setActionMenuVisible(false);
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// native pin message to be released with 1.3.0 chat sdk
|
|
125
|
+
isWebInternal() &&
|
|
126
|
+
actionMenuitems.push({
|
|
127
|
+
icon: isMsgPinned ? 'unpin-outlined' : 'pin-outlined',
|
|
128
|
+
iconColor: $config.SECONDARY_ACTION_COLOR,
|
|
129
|
+
textColor: $config.FONT_COLOR,
|
|
130
|
+
title: isMsgPinned ? 'UnPin Message' : 'Pin Message',
|
|
131
|
+
onPress: () => {
|
|
132
|
+
isMsgPinned ? unPinMessage(msgId) : pinMessage(msgId);
|
|
133
|
+
setActionMenuVisible(false);
|
|
134
|
+
},
|
|
135
|
+
});
|
|
99
136
|
|
|
100
137
|
!isLocal &&
|
|
101
138
|
chatType == SDKChatType.GROUP_CHAT &&
|