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.
Files changed (32) hide show
  1. package/package.json +1 -1
  2. package/template/customization-api/sub-components.ts +1 -0
  3. package/template/defaultConfig.js +2 -2
  4. package/template/package.json +1 -1
  5. package/template/src/components/ChatContext.ts +3 -0
  6. package/template/src/components/Controls.tsx +80 -18
  7. package/template/src/components/Navbar.tsx +29 -1
  8. package/template/src/components/chat/chatConfigure.native.tsx +85 -25
  9. package/template/src/components/chat/chatConfigure.tsx +99 -9
  10. package/template/src/components/chat-messages/useChatMessages.tsx +32 -39
  11. package/template/src/components/chat-ui/useChatUIControls.tsx +21 -0
  12. package/template/src/components/precall/joinWaitingRoomBtn.tsx +25 -6
  13. package/template/src/components/room-info/useRoomInfo.tsx +12 -0
  14. package/template/src/pages/Create.tsx +26 -1
  15. package/template/src/pages/video-call/VideoCallMobileView.tsx +3 -2
  16. package/template/src/pages/video-call/VideoCallScreen.tsx +3 -1
  17. package/template/src/subComponents/ChatBubble.tsx +388 -110
  18. package/template/src/subComponents/ChatContainer.tsx +76 -53
  19. package/template/src/subComponents/ChatInput.native.tsx +93 -14
  20. package/template/src/subComponents/ChatInput.tsx +41 -7
  21. package/template/src/subComponents/caption/Caption.tsx +14 -2
  22. package/template/src/subComponents/caption/CaptionContainer.tsx +24 -3
  23. package/template/src/subComponents/caption/CaptionText.tsx +13 -1
  24. package/template/src/subComponents/chat/ChatActionMenu.tsx +40 -3
  25. package/template/src/subComponents/chat/ChatAttachment.native.tsx +4 -2
  26. package/template/src/subComponents/chat/ChatEmoji.native.tsx +181 -22
  27. package/template/src/subComponents/chat/ChatEmoji.tsx +4 -3
  28. package/template/src/subComponents/chat/ChatQuickActionsMenu.tsx +70 -34
  29. package/template/src/subComponents/chat/ChatSendButton.tsx +42 -1
  30. package/template/src/subComponents/chat/PinnedMessage.tsx +207 -0
  31. package/template/src/utils/useCreateRoom.ts +23 -4
  32. 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 {chatType, setChatType, privateChatUser, inputActive, showEmojiPicker} =
80
- useChatUIControls();
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
- <ChatBubbleComponent
245
- isLocal={localUid === message.uid}
246
- isSameUser={
247
- index !== 0 && messageStore[index - 1].uid === message.uid
248
- ? true
249
- : false
250
- }
251
- previousMessageCreatedTimestamp={
252
- index !== 0
253
- ? (messageStore[index - 1]
254
- .createdTimestamp as unknown as string)
255
- : ''
256
- }
257
- message={message.msg}
258
- createdTimestamp={message.createdTimestamp}
259
- updatedTimestamp={message.updatedTimestamp}
260
- uid={message.uid}
261
- key={message.msgId}
262
- msgId={message.msgId}
263
- isDeleted={message.isDeleted}
264
- type={message.type}
265
- url={message?.url}
266
- thumb={message?.thumb}
267
- fileName={message?.fileName}
268
- ext={message?.ext}
269
- reactions={message?.reactions}
270
- scrollOffset={scrollOffset}
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
- <ChatBubbleComponent
310
- isLocal={localUid === message.uid}
311
- isSameUser={
312
- index !== 0 &&
313
- privateMessageStore[privateChatUser][index - 1].uid ===
314
- message.uid
315
- ? true
316
- : false
317
- }
318
- message={message.msg}
319
- createdTimestamp={message.createdTimestamp}
320
- updatedTimestamp={message.updatedTimestamp}
321
- uid={message.uid}
322
- key={message.msgId}
323
- msgId={message.msgId}
324
- isDeleted={message.isDeleted}
325
- type={message.type}
326
- url={message?.url}
327
- thumb={message?.thumb}
328
- fileName={message?.fileName}
329
- ext={message?.ext}
330
- reactions={message?.reactions}
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
- {/* <ChatEmojiButton /> */}
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 {inputActive, showEmojiPicker} = useChatUIControls();
273
+ const {
274
+ inputActive,
275
+ showEmojiPicker,
276
+ replyToMsgId,
277
+ setShowEmojiPicker,
278
+ setMessage,
279
+ } = useChatUIControls();
220
280
  return (
221
- <View
222
- style={[
223
- style.inputContainer,
224
- showEmojiPicker
225
- ? {backgroundColor: 'transparent'}
226
- : {backgroundColor: $config.CARD_LAYER_1_COLOR},
227
- // inputActive ? style.inputActiveView : {},
228
- ]}>
229
- {showEmojiPicker && <ChatEmojiPicker />}
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
- <ChatTextInput />
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.attachmentContainer,
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
- renderTextInput()
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
- attachmentContainer: {
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
- const Caption: React.FC = () => {
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 {StyleSheet, Text, useWindowDimensions, View} from 'react-native';
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
- const CaptionContainer = () => {
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 {Text, View, StyleSheet, LayoutChangeEvent} from 'react-native';
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 {calculatePosition, isMobileUA, trimText} from '../../utils/common';
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 {setChatType, setPrivateChatUser} = useChatUIControls();
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} = useChatConfigure();
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 &&