@ethora/chat-component-rn 26.5.17 → 26.5.18

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 (181) hide show
  1. package/lib/commonjs/assets/EmptyChatIllustration.js +106 -0
  2. package/lib/commonjs/assets/EmptyChatIllustration.js.map +1 -0
  3. package/lib/commonjs/assets/icons.js +13 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/DropdownMenu/DropdownMenu.js +2 -1
  6. package/lib/commonjs/components/DropdownMenu/DropdownMenu.js.map +1 -1
  7. package/lib/commonjs/components/MainComponents/ChatHeader.js +2 -1
  8. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/ChatRoom.js +5 -2
  10. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/ChooseChatMessage.js +9 -2
  12. package/lib/commonjs/components/MainComponents/ChooseChatMessage.js.map +1 -1
  13. package/lib/commonjs/components/MainComponents/EditWrapper.js +12 -4
  14. package/lib/commonjs/components/MainComponents/EditWrapper.js.map +1 -1
  15. package/lib/commonjs/components/MainComponents/MessageList.js +2 -1
  16. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  17. package/lib/commonjs/components/MainComponents/NoMessagesPlaceholder.js +11 -3
  18. package/lib/commonjs/components/MainComponents/NoMessagesPlaceholder.js.map +1 -1
  19. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +12 -7
  20. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  21. package/lib/commonjs/components/MainComponents/RoomList.js +2 -1
  22. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  23. package/lib/commonjs/components/MessageBubble/Avatar.js +16 -7
  24. package/lib/commonjs/components/MessageBubble/Avatar.js.map +1 -1
  25. package/lib/commonjs/components/MessageBubble/Message.js +16 -1
  26. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  27. package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js +9 -0
  28. package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
  29. package/lib/commonjs/components/styled/Button.js +4 -2
  30. package/lib/commonjs/components/styled/Button.js.map +1 -1
  31. package/lib/commonjs/components/styled/DateLabel.js +12 -4
  32. package/lib/commonjs/components/styled/DateLabel.js.map +1 -1
  33. package/lib/commonjs/components/styled/SendInput.js +4 -3
  34. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  35. package/lib/commonjs/context/xmppProvider.js +8 -1
  36. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  37. package/lib/commonjs/helpers/getAvatarColor.js +33 -0
  38. package/lib/commonjs/helpers/getAvatarColor.js.map +1 -0
  39. package/lib/commonjs/helpers/getDateLabelColor.js +9 -0
  40. package/lib/commonjs/helpers/getDateLabelColor.js.map +1 -0
  41. package/lib/commonjs/helpers/getIconColor.js +9 -0
  42. package/lib/commonjs/helpers/getIconColor.js.map +1 -0
  43. package/lib/commonjs/helpers/getSenderNameColor.js +9 -0
  44. package/lib/commonjs/helpers/getSenderNameColor.js.map +1 -0
  45. package/lib/commonjs/hooks/useSendMessage.js +72 -22
  46. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  47. package/lib/commonjs/networking/outboundQueue.js +22 -4
  48. package/lib/commonjs/networking/outboundQueue.js.map +1 -1
  49. package/lib/commonjs/networking/xmppClient.js +50 -0
  50. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  51. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js +22 -0
  52. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  53. package/lib/commonjs/roomStore/roomsSlice.js +13 -1
  54. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  55. package/lib/module/assets/EmptyChatIllustration.js +99 -0
  56. package/lib/module/assets/EmptyChatIllustration.js.map +1 -0
  57. package/lib/module/assets/icons.js +13 -2
  58. package/lib/module/assets/icons.js.map +1 -1
  59. package/lib/module/components/DropdownMenu/DropdownMenu.js +2 -1
  60. package/lib/module/components/DropdownMenu/DropdownMenu.js.map +1 -1
  61. package/lib/module/components/MainComponents/ChatHeader.js +2 -1
  62. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  63. package/lib/module/components/MainComponents/ChatRoom.js +5 -2
  64. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  65. package/lib/module/components/MainComponents/ChooseChatMessage.js +9 -2
  66. package/lib/module/components/MainComponents/ChooseChatMessage.js.map +1 -1
  67. package/lib/module/components/MainComponents/EditWrapper.js +12 -4
  68. package/lib/module/components/MainComponents/EditWrapper.js.map +1 -1
  69. package/lib/module/components/MainComponents/MessageList.js +2 -1
  70. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  71. package/lib/module/components/MainComponents/NoMessagesPlaceholder.js +11 -3
  72. package/lib/module/components/MainComponents/NoMessagesPlaceholder.js.map +1 -1
  73. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +12 -7
  74. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  75. package/lib/module/components/MainComponents/RoomList.js +2 -1
  76. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  77. package/lib/module/components/MessageBubble/Avatar.js +16 -7
  78. package/lib/module/components/MessageBubble/Avatar.js.map +1 -1
  79. package/lib/module/components/MessageBubble/Message.js +16 -1
  80. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  81. package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js +9 -0
  82. package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
  83. package/lib/module/components/styled/Button.js +4 -2
  84. package/lib/module/components/styled/Button.js.map +1 -1
  85. package/lib/module/components/styled/DateLabel.js +12 -4
  86. package/lib/module/components/styled/DateLabel.js.map +1 -1
  87. package/lib/module/components/styled/SendInput.js +4 -3
  88. package/lib/module/components/styled/SendInput.js.map +1 -1
  89. package/lib/module/context/xmppProvider.js +8 -1
  90. package/lib/module/context/xmppProvider.js.map +1 -1
  91. package/lib/module/helpers/getAvatarColor.js +28 -0
  92. package/lib/module/helpers/getAvatarColor.js.map +1 -0
  93. package/lib/module/helpers/getDateLabelColor.js +4 -0
  94. package/lib/module/helpers/getDateLabelColor.js.map +1 -0
  95. package/lib/module/helpers/getIconColor.js +4 -0
  96. package/lib/module/helpers/getIconColor.js.map +1 -0
  97. package/lib/module/helpers/getSenderNameColor.js +4 -0
  98. package/lib/module/helpers/getSenderNameColor.js.map +1 -0
  99. package/lib/module/hooks/useSendMessage.js +72 -22
  100. package/lib/module/hooks/useSendMessage.js.map +1 -1
  101. package/lib/module/networking/outboundQueue.js +21 -4
  102. package/lib/module/networking/outboundQueue.js.map +1 -1
  103. package/lib/module/networking/xmppClient.js +50 -0
  104. package/lib/module/networking/xmppClient.js.map +1 -1
  105. package/lib/module/roomStore/Middleware/newMessageMidlleware.js +22 -0
  106. package/lib/module/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  107. package/lib/module/roomStore/roomsSlice.js +13 -1
  108. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  109. package/lib/typescript/assets/EmptyChatIllustration.d.ts +10 -0
  110. package/lib/typescript/assets/EmptyChatIllustration.d.ts.map +1 -0
  111. package/lib/typescript/assets/icons.d.ts +3 -12
  112. package/lib/typescript/assets/icons.d.ts.map +1 -1
  113. package/lib/typescript/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  114. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  115. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  116. package/lib/typescript/components/MainComponents/ChooseChatMessage.d.ts.map +1 -1
  117. package/lib/typescript/components/MainComponents/EditWrapper.d.ts +5 -1
  118. package/lib/typescript/components/MainComponents/EditWrapper.d.ts.map +1 -1
  119. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  120. package/lib/typescript/components/MainComponents/NoMessagesPlaceholder.d.ts.map +1 -1
  121. package/lib/typescript/components/MainComponents/ProfileImagePlaceholder.d.ts.map +1 -1
  122. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  123. package/lib/typescript/components/MessageBubble/Avatar.d.ts.map +1 -1
  124. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  125. package/lib/typescript/components/Modals/ModalWrapper/ModalWrapper.d.ts.map +1 -1
  126. package/lib/typescript/components/styled/Button.d.ts +1 -0
  127. package/lib/typescript/components/styled/Button.d.ts.map +1 -1
  128. package/lib/typescript/components/styled/DateLabel.d.ts +9 -8
  129. package/lib/typescript/components/styled/DateLabel.d.ts.map +1 -1
  130. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  131. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  132. package/lib/typescript/helpers/getAvatarColor.d.ts +7 -0
  133. package/lib/typescript/helpers/getAvatarColor.d.ts.map +1 -0
  134. package/lib/typescript/helpers/getDateLabelColor.d.ts +8 -0
  135. package/lib/typescript/helpers/getDateLabelColor.d.ts.map +1 -0
  136. package/lib/typescript/helpers/getIconColor.d.ts +8 -0
  137. package/lib/typescript/helpers/getIconColor.d.ts.map +1 -0
  138. package/lib/typescript/helpers/getSenderNameColor.d.ts +8 -0
  139. package/lib/typescript/helpers/getSenderNameColor.d.ts.map +1 -0
  140. package/lib/typescript/hooks/useSendMessage.d.ts +1 -1
  141. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  142. package/lib/typescript/networking/outboundQueue.d.ts +16 -1
  143. package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
  144. package/lib/typescript/networking/xmppClient.d.ts +3 -0
  145. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  146. package/lib/typescript/roomStore/Middleware/newMessageMidlleware.d.ts.map +1 -1
  147. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  148. package/lib/typescript/types/models/message.model.d.ts +1 -0
  149. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  150. package/lib/typescript/types/types.d.ts +14 -0
  151. package/lib/typescript/types/types.d.ts.map +1 -1
  152. package/package.json +1 -1
  153. package/src/assets/EmptyChatIllustration.tsx +49 -0
  154. package/src/assets/icons.tsx +64 -81
  155. package/src/components/DropdownMenu/DropdownMenu.tsx +2 -1
  156. package/src/components/MainComponents/ChatHeader.tsx +2 -1
  157. package/src/components/MainComponents/ChatRoom.tsx +5 -2
  158. package/src/components/MainComponents/ChooseChatMessage.tsx +5 -2
  159. package/src/components/MainComponents/EditWrapper.tsx +9 -6
  160. package/src/components/MainComponents/MessageList.tsx +2 -1
  161. package/src/components/MainComponents/NoMessagesPlaceholder.tsx +4 -1
  162. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +14 -7
  163. package/src/components/MainComponents/RoomList.tsx +2 -1
  164. package/src/components/MessageBubble/Avatar.tsx +18 -9
  165. package/src/components/MessageBubble/Message.tsx +16 -1
  166. package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +6 -0
  167. package/src/components/styled/Button.tsx +5 -1
  168. package/src/components/styled/DateLabel.tsx +10 -7
  169. package/src/components/styled/SendInput.tsx +4 -3
  170. package/src/context/xmppProvider.tsx +6 -1
  171. package/src/helpers/getAvatarColor.ts +31 -0
  172. package/src/helpers/getDateLabelColor.ts +3 -0
  173. package/src/helpers/getIconColor.ts +3 -0
  174. package/src/helpers/getSenderNameColor.ts +3 -0
  175. package/src/hooks/useSendMessage.tsx +101 -58
  176. package/src/networking/outboundQueue.ts +25 -4
  177. package/src/networking/xmppClient.ts +47 -0
  178. package/src/roomStore/Middleware/newMessageMidlleware.tsx +25 -0
  179. package/src/roomStore/roomsSlice.ts +15 -1
  180. package/src/types/models/message.model.ts +3 -0
  181. package/src/types/types.ts +18 -1
@@ -12,6 +12,7 @@ import {
12
12
  import { BurgerMenuIcon } from '../../assets/icons';
13
13
  import { IConfig } from '../../types/types';
14
14
  import Button from '../styled/Button';
15
+ import { getIconColor } from '../../helpers/getIconColor';
15
16
 
16
17
  const positionMenu = {
17
18
  right: { top: 95, right: 10 },
@@ -104,7 +105,7 @@ const DropdownMenu: React.FC<DropdownMenuProps> = ({
104
105
  }}
105
106
  color="black"
106
107
  unstyled
107
- EndIcon={<BurgerMenuIcon color={config?.colors?.primary} />}
108
+ EndIcon={<BurgerMenuIcon color={getIconColor(config)} />}
108
109
  onPress={toggleMenu}
109
110
  />
110
111
  )}
@@ -27,6 +27,7 @@ import { RoomMenu } from '../MenuRoom/MenuRoom';
27
27
  import { useRoomState } from '../../hooks/useRoomState';
28
28
  import { useChatSettingState } from '../../hooks/useChatSettingState';
29
29
  import { View, StyleSheet, Text, Keyboard } from 'react-native';
30
+ import { getIconColor } from '../../helpers/getIconColor';
30
31
 
31
32
  interface ChatHeaderProps {
32
33
  currentRoom: IRoom;
@@ -89,7 +90,7 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
89
90
  style={styles.menuButton}
90
91
  color="black"
91
92
  unstyled
92
- EndIcon={<BurgerMenuIcon color={config?.colors?.primary} />}
93
+ EndIcon={<BurgerMenuIcon color={getIconColor(config)} />}
93
94
  onPress={handleHeaderChatMenu}
94
95
  />
95
96
  </View>
@@ -18,7 +18,8 @@ import ChatHeader from './ChatHeader';
18
18
  import NoMessagesPlaceholder from './NoMessagesPlaceholder';
19
19
  import NewChatModal from '../Modals/NewChatModal/NewChatModal';
20
20
  import { EditWrapper } from './EditWrapper';
21
- import { NoSelectedChatIcon } from '../../assets/icons';
21
+ import { EmptyChatIllustration } from '../../assets/EmptyChatIllustration';
22
+ import { getIconColor } from '../../helpers/getIconColor';
22
23
  import { ChooseChatMessage } from './ChooseChatMessage';
23
24
  import { useRoomUrl } from '../../hooks/useRoomUrl';
24
25
  import { useSendMessage } from '../../hooks/useSendMessage';
@@ -320,7 +321,9 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
320
321
  alignItems: 'center',
321
322
  }}
322
323
  >
323
- <NoSelectedChatIcon />
324
+ <EmptyChatIllustration
325
+ color={getIconColor(configWithEventHandlers)}
326
+ />
324
327
  </View>
325
328
  ) : !roomMessages || roomMessages.length === 0 ? (
326
329
  <View
@@ -1,5 +1,7 @@
1
1
  import { styled } from 'styled-components/native';
2
- import { NoSelectedChatIcon } from '../../assets/icons';
2
+ import { EmptyChatIllustration } from '../../assets/EmptyChatIllustration';
3
+ import { useChatSettingState } from '../../hooks/useChatSettingState';
4
+ import { getIconColor } from '../../helpers/getIconColor';
3
5
 
4
6
  export const ChooseChatMessageContainer = styled.View`
5
7
  height: 100%;
@@ -30,9 +32,10 @@ export const ChooseChatDescription = styled.Text`
30
32
  `;
31
33
 
32
34
  export const ChooseChatMessage = () => {
35
+ const { config } = useChatSettingState();
33
36
  return (
34
37
  <ChooseChatMessageContainer>
35
- <NoSelectedChatIcon />
38
+ <EmptyChatIllustration color={getIconColor(config)} />
36
39
  <ChooseChatMessageContainerBoxText>
37
40
  <ChooseChatTitle>Start a Conversation</ChooseChatTitle>
38
41
  <ChooseChatDescription>
@@ -2,9 +2,11 @@ import React, { FC } from 'react';
2
2
  import { EditIcon } from '../../assets/icons';
3
3
  import { styled } from 'styled-components/native';
4
4
  import { Text, TouchableOpacity, View } from 'react-native';
5
+ import { useChatSettingState } from '../../hooks/useChatSettingState';
6
+ import { getIconColor } from '../../helpers/getIconColor';
5
7
 
6
- export const EditContainer = styled.View`
7
- background-color: #0052cd0d;
8
+ export const EditContainer = styled.View<{ accentColor?: string }>`
9
+ background-color: ${({ accentColor }) => (accentColor || '#0052cd') + '0d'};
8
10
  padding: 12px 24px;
9
11
  flex-direction: row;
10
12
  align-items: center;
@@ -36,9 +38,10 @@ interface EditWrapperProps {
36
38
  }
37
39
 
38
40
  export const EditWrapper: FC<EditWrapperProps> = ({ text, onClose }) => {
39
- console.log('text', text);
41
+ const { config } = useChatSettingState();
42
+ const iconColor = getIconColor(config);
40
43
  return (
41
- <EditContainer>
44
+ <EditContainer accentColor={iconColor}>
42
45
  <EditInfoBox>
43
46
  <View
44
47
  style={{
@@ -46,11 +49,11 @@ export const EditWrapper: FC<EditWrapperProps> = ({ text, onClose }) => {
46
49
  paddingRight: 20,
47
50
  paddingLeft: 0,
48
51
  borderRightWidth: 1,
49
- borderRightColor: '#0052CD',
52
+ borderRightColor: iconColor,
50
53
  borderStyle: 'solid',
51
54
  }}
52
55
  >
53
- <EditIcon color="#0052CD" />
56
+ <EditIcon color={iconColor} />
54
57
  </View>
55
58
  <View style={{ paddingLeft: 20 }}>
56
59
  <EditTitle>Edit Message</EditTitle>
@@ -27,6 +27,7 @@ import { useRoomState } from '../../hooks/useRoomState';
27
27
  import Loader from '../styled/Loader';
28
28
  import { ArowDownIcon } from '../../assets/icons';
29
29
  import CustomTypingIndicator from '../styled/StyledInputComponents/CustomTypingIndicator';
30
+ import { getIconColor } from '../../helpers/getIconColor';
30
31
 
31
32
  interface MessageListProps<TMessage extends IMessage> {
32
33
  CustomMessage?: React.ComponentType<{
@@ -453,7 +454,7 @@ const MessageList = <TMessage extends IMessage>({
453
454
  <TouchableOpacity
454
455
  style={[
455
456
  styles.newMessageIndicator,
456
- { backgroundColor: config?.colors?.primary || '#0052CD' },
457
+ { backgroundColor: getIconColor(config) },
457
458
  ]}
458
459
  onPress={handleNewMessageIndicatorPress}
459
460
  >
@@ -1,7 +1,10 @@
1
1
  import { Text, View } from 'react-native';
2
2
  import { NoMessages } from '../../assets/icons';
3
+ import { useChatSettingState } from '../../hooks/useChatSettingState';
4
+ import { getIconColor } from '../../helpers/getIconColor';
3
5
 
4
6
  const NoMessagesPlaceholder = () => {
7
+ const { config } = useChatSettingState();
5
8
  return (
6
9
  <View
7
10
  style={{
@@ -11,7 +14,7 @@ const NoMessagesPlaceholder = () => {
11
14
  }}
12
15
  >
13
16
  <View style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
14
- {/* <NoMessages /> */}
17
+ <NoMessages color={getIconColor(config)} />
15
18
  <View
16
19
  style={{
17
20
  flexDirection: 'column',
@@ -11,7 +11,11 @@ import {
11
11
  RemoveButtonText,
12
12
  Wrapper,
13
13
  } from '../styled/StyledComponents';
14
- import { nameToColor } from '../../helpers/hashcolor';
14
+ import { useChatSettingState } from '../../hooks/useChatSettingState';
15
+ import {
16
+ getAvatarColor,
17
+ getAvatarTextColor,
18
+ } from '../../helpers/getAvatarColor';
15
19
 
16
20
  interface ProfileImagePlaceholderProps {
17
21
  name?: string;
@@ -49,12 +53,13 @@ export const ProfileImagePlaceholder: React.FC<
49
53
  placeholderIcon,
50
54
  disableOverlay,
51
55
  }) => {
56
+ const { config } = useChatSettingState();
52
57
  const backgroundColor = useMemo(() => {
53
58
  if(!name) {
54
59
  return { backgroundColor: 'transparent' };
55
60
  }
56
- return nameToColor(name);
57
- }, [name]);
61
+ return { backgroundColor: getAvatarColor(name, config) };
62
+ }, [name, config]);
58
63
 
59
64
  const getTwoUppercaseLetters = (fullName: string) => {
60
65
  if (!fullName) {return '';}
@@ -120,10 +125,12 @@ export const ProfileImagePlaceholder: React.FC<
120
125
  ) : placeholderIcon ? (
121
126
  placeholderIcon
122
127
  ) : (
123
- // Black initials on the pastel hash-color bg — white text
124
- // on these light backgrounds is unreadable (matches web's
125
- // default-color behavior).
126
- <InitialsText size={size} color="#141414">
128
+ // Black initials on the light pastel hash-colors; a dark
129
+ // configured colors.avatar flips them to white.
130
+ <InitialsText
131
+ size={size}
132
+ color={getAvatarTextColor(backgroundColor?.backgroundColor)}
133
+ >
127
134
  {getInitials()}
128
135
  </InitialsText>
129
136
  )}
@@ -24,6 +24,7 @@ import { useChatSettingState } from '../../hooks/useChatSettingState';
24
24
  import Button from '../styled/Button';
25
25
  import { HeaderRoomList } from '../Header/HeaderRoomList';
26
26
  import { HeaderRoomListMenu } from '../Menu/HeaderRoomListMenu';
27
+ import { getIconColor } from '../../helpers/getIconColor';
27
28
 
28
29
  const LONG_PRESS_THRESHOLD = 200;
29
30
 
@@ -165,7 +166,7 @@ const RoomList: React.FC<RoomListProps> = ({
165
166
  }}
166
167
  color="black"
167
168
  unstyled
168
- EndIcon={<BurgerMenuIcon color={config?.colors?.primary} />}
169
+ EndIcon={<BurgerMenuIcon color={getIconColor(config)} />}
169
170
  onPress={() => setOpen(!open)}
170
171
  />
171
172
  )}
@@ -1,6 +1,10 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import styled from 'styled-components/native';
3
- import { nameToColor } from '../../helpers/hashcolor';
3
+ import { useChatSettingState } from '../../hooks/useChatSettingState';
4
+ import {
5
+ getAvatarColor,
6
+ getAvatarTextColor,
7
+ } from '../../helpers/getAvatarColor';
4
8
 
5
9
  interface AvatarProps {
6
10
  username?: string | null;
@@ -23,13 +27,13 @@ const AvatarCircle = styled.View<{ bgColor?: string }>`
23
27
  elevation: 4;
24
28
  `;
25
29
 
26
- const AvatarText = styled.Text`
30
+ const AvatarText = styled.Text<{ color?: string }>`
27
31
  font-size: 16px;
28
32
  font-weight: bold;
29
- // Pastel backgrounds from nameToColor() are all light (#E2F4FB,
30
- // #EEE6F9, #F5F2BC, ...). White text on light = invisible — web
31
- // uses default-black text on the same palette. Match it.
32
- color: #141414;
33
+ // Pastel backgrounds from the hash palette are all light, so the
34
+ // default is dark text; a configured colors.avatar may be dark, in
35
+ // which case getAvatarTextColor flips this to white.
36
+ color: ${({ color }) => color || '#141414'};
33
37
  `;
34
38
 
35
39
  export const Avatar: React.FC<AvatarProps> = ({
@@ -38,12 +42,15 @@ export const Avatar: React.FC<AvatarProps> = ({
38
42
  lastName,
39
43
  style,
40
44
  }) => {
45
+ const { config } = useChatSettingState();
41
46
  const backgroundColor = useMemo(() => {
42
47
  if (!username && !firstName) {
43
48
  return { backgroundColor: 'transparent' };
44
49
  }
45
- return nameToColor(username ? username : firstName || '');
46
- }, [username, firstName]);
50
+ return {
51
+ backgroundColor: getAvatarColor(username || firstName, config),
52
+ };
53
+ }, [username, firstName, config]);
47
54
 
48
55
  const getInitials = () => {
49
56
  const isAlphabetic = (char: string) => /^[a-zA-Zа-яА-ЯёЁ]$/.test(char);
@@ -78,7 +85,9 @@ export const Avatar: React.FC<AvatarProps> = ({
78
85
 
79
86
  return (
80
87
  <AvatarCircle style={style} bgColor={backgroundColor?.backgroundColor}>
81
- <AvatarText>{getInitials()}</AvatarText>
88
+ <AvatarText color={getAvatarTextColor(backgroundColor?.backgroundColor)}>
89
+ {getInitials()}
90
+ </AvatarText>
82
91
  </AvatarCircle>
83
92
  );
84
93
  };
@@ -28,6 +28,7 @@ import MediaMessage from '../MainComponents/MediaMessage';
28
28
  import MessageTranslations from './MessageTranslations';
29
29
  import { useChatSettingState } from '../../hooks/useChatSettingState';
30
30
  import { parseMessageBody } from '../../helpers/parseMessageBody';
31
+ import { getSenderNameColor } from '../../helpers/getSenderNameColor';
31
32
  import { useMessageHeapState } from '../../hooks/useMessageHeapState';
32
33
  import { DoubleTick } from '../../assets/icons';
33
34
  import { useXmppClient } from '../../context/xmppProvider';
@@ -367,7 +368,7 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
367
368
  backgroundMessage={config?.messageColor?.backgroundMessage}
368
369
  >
369
370
  {!isUser && (
370
- <CustomUserName color={config?.colors?.primary} media={message?.isMediafile === 'true'}>
371
+ <CustomUserName color={getSenderNameColor(config)} media={message?.isMediafile === 'true'}>
371
372
  {message.user.name}
372
373
  </CustomUserName>
373
374
  )}
@@ -425,6 +426,9 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
425
426
  ! Failed — tap to retry
426
427
  </Text>
427
428
  )}
429
+ {message?.isEdited && !message?.isDeleted && (
430
+ <Text style={styles.editedText}>edited</Text>
431
+ )}
428
432
  <Text style={styles.timestampText}>
429
433
  {new Date(message.date).toLocaleTimeString([], {
430
434
  hour: '2-digit',
@@ -525,4 +529,15 @@ const styles = StyleSheet.create({
525
529
  includeFontPadding: false,
526
530
  textAlignVertical: 'center',
527
531
  },
532
+ // Small muted "edited" marker shown before the timestamp (Slack/WhatsApp
533
+ // style). Italic + same muted grey so it reads as metadata, not content.
534
+ editedText: {
535
+ fontSize: 11,
536
+ lineHeight: 16,
537
+ color: '#999',
538
+ fontStyle: 'italic',
539
+ marginRight: 6,
540
+ includeFontPadding: false,
541
+ textAlignVertical: 'center',
542
+ },
528
543
  });
@@ -10,6 +10,8 @@ import {
10
10
  import { TextareaInput } from '../../styled/StyledInputComponents/StyledInputComponents';
11
11
  import Button from '../../styled/Button';
12
12
  import { Modal, Text, TextInput, View, StyleSheet } from 'react-native';
13
+ import { useChatSettingState } from '../../../hooks/useChatSettingState';
14
+ import { getIconColor } from '../../../helpers/getIconColor';
13
15
 
14
16
  interface ModalWrapperProps {
15
17
  iconTitle?: any;
@@ -44,6 +46,7 @@ export const ModalWrapper: FC<ModalWrapperProps> = ({
44
46
  compact = false,
45
47
  }) => {
46
48
  const textareaRef = useRef<TextInput>(null);
49
+ const { config } = useChatSettingState();
47
50
 
48
51
  // const handleInput = () => {
49
52
  // const textarea = textareaRef.current;
@@ -73,6 +76,9 @@ export const ModalWrapper: FC<ModalWrapperProps> = ({
73
76
  style={{ width: '100%' }}
74
77
  unstyled
75
78
  variant="outlined"
79
+ // Outlined Button draws its border from `backgroundColor`
80
+ // (defaults to the hardcoded blue) — feed it the themed color.
81
+ borderColor={getIconColor(config)}
76
82
  />
77
83
  {buttonText && (
78
84
  <Button
@@ -15,11 +15,12 @@ import { getTintedColor } from '../../helpers/getTintedColor';
15
15
  const CustomButton = styled(TouchableOpacity)<{
16
16
  disabled: boolean;
17
17
  backgroundColor?: string;
18
+ borderColor?: string;
18
19
  unstyled?: boolean;
19
20
  variant?: 'default' | 'filled' | 'outlined';
20
21
  }>`
21
22
  border-width: ${({ variant }) => (variant === 'outlined' ? 1 : 0)}px;
22
- border-color: ${({ backgroundColor }) => backgroundColor || '#0052CD'};
23
+ border-color: ${({ borderColor }) => borderColor || '#0052CD'};
23
24
  border-radius: 20px;
24
25
  background-color: ${({ variant, backgroundColor }) =>
25
26
  variant === 'filled' ? backgroundColor || '#0052CD' : 'transparent'};
@@ -52,6 +53,7 @@ export interface ButtonProps {
52
53
  unstyled?: boolean;
53
54
  variant?: 'default' | 'filled' | 'outlined';
54
55
  backgroundColor?: string;
56
+ borderColor?: string;
55
57
  color?: string;
56
58
  style?: ViewStyle;
57
59
  onPress?: () => void;
@@ -71,6 +73,7 @@ const Button: React.FC<ButtonProps> = ({
71
73
  unstyled = false,
72
74
  variant = 'default',
73
75
  backgroundColor,
76
+ borderColor,
74
77
  onPress,
75
78
  StartIcon,
76
79
  style: containerStyle,
@@ -90,6 +93,7 @@ const Button: React.FC<ButtonProps> = ({
90
93
  onPress={onPress}
91
94
  variant={variant}
92
95
  backgroundColor={backgroundColor}
96
+ borderColor={borderColor}
93
97
  >
94
98
  {loading && <Loader size={24} />}
95
99
  {!loading && StartIcon && <View style={styles.icon}>{StartIcon}</View>}
@@ -2,10 +2,11 @@ import React from 'react';
2
2
  import styled from 'styled-components/native';
3
3
  import { Line } from './StyledComponents';
4
4
  import { Text } from 'react-native';
5
+ import { getDateLabelColor } from '../../helpers/getDateLabelColor';
5
6
 
6
7
  interface DateLabelProps {
7
8
  date: Date;
8
- colors?: { primary?: string; secondary?: string };
9
+ colors?: { primary?: string; secondary?: string; dateLabel?: string };
9
10
  }
10
11
 
11
12
  const Container = styled.View`
@@ -19,7 +20,7 @@ const Container = styled.View`
19
20
  `;
20
21
 
21
22
  export const StyledDateLabel = styled.View<{
22
- secondary?: string;
23
+ bgColor?: string;
23
24
  }>`
24
25
  margin: 0;
25
26
  border-radius: 118px;
@@ -27,11 +28,11 @@ export const StyledDateLabel = styled.View<{
27
28
  flex-direction: row;
28
29
  align-items: center;
29
30
  justify-content: center;
30
- background-color: ${(props) => '#e7edf9'};
31
+ background-color: ${({ bgColor }) => bgColor || '#e7edf9'};
31
32
  `;
32
33
 
33
- export const StyledDateText = styled.Text<{ primary?: string }>`
34
- color: ${(props) => '#0052cd'};
34
+ export const StyledDateText = styled.Text<{ color?: string }>`
35
+ color: ${({ color }) => color || '#0052cd'};
35
36
  font-size: 12px;
36
37
  font-weight: 400;
37
38
  line-height: 14px;
@@ -63,11 +64,13 @@ const DateLabel: React.FC<DateLabelProps> = ({ date, colors }) => {
63
64
  label = date.toLocaleDateString('en-US', options);
64
65
  }
65
66
 
67
+ const textColor = getDateLabelColor({ colors });
68
+
66
69
  return (
67
70
  <Container>
68
71
  <Line />
69
- <StyledDateLabel secondary={colors?.secondary}>
70
- <StyledDateText primary={colors?.primary}>{label}</StyledDateText>
72
+ <StyledDateLabel bgColor={colors?.secondary}>
73
+ <StyledDateText color={textColor}>{label}</StyledDateText>
71
74
  </StyledDateLabel>
72
75
  <Line />
73
76
  </Container>
@@ -12,6 +12,7 @@ import { SendIcon, AttachIcon, RecordIcon } from '../../assets/icons';
12
12
  import { KeyboardAvoidingView, Platform, View, Text, TouchableOpacity, Alert, Linking } from 'react-native';
13
13
  import AttachSheet from '../Modals/AttachSheet/AttachSheet';
14
14
  import { MediaFilePreview } from './MediaFilePreview';
15
+ import { getIconColor } from '../../helpers/getIconColor';
15
16
  import * as ImagePicker from 'expo-image-picker';
16
17
  import * as DocumentPicker from 'expo-document-picker';
17
18
  import * as ImageManipulator from 'expo-image-manipulator';
@@ -486,7 +487,7 @@ const SendInput: React.FC<SendInputProps> = ({
486
487
  }}
487
488
  activeOpacity={0.7}
488
489
  >
489
- <AttachIcon color={config?.colors?.primary || '#0052CD'} />
490
+ <AttachIcon color={getIconColor(config)} />
490
491
  </TouchableOpacity>
491
492
  )}
492
493
  <MessageInput
@@ -615,7 +616,7 @@ const SendInput: React.FC<SendInputProps> = ({
615
616
  marginLeft: 0,
616
617
  marginRight: 0,
617
618
  backgroundColor: filled
618
- ? config?.colors?.primary
619
+ ? getIconColor(config)
619
620
  : 'transparent',
620
621
  opacity: filled ? 1 : 0.5,
621
622
  }}
@@ -629,7 +630,7 @@ const SendInput: React.FC<SendInputProps> = ({
629
630
  onCamera={handleCameraSelection}
630
631
  onGallery={handleGallerySelection}
631
632
  onDocument={handleFileSelection}
632
- primaryColor={config?.colors?.primary}
633
+ primaryColor={getIconColor(config)}
633
634
  />
634
635
  </InputContainer>
635
636
  );
@@ -507,9 +507,12 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
507
507
  if (!client) {return;}
508
508
  const id = setInterval(() => {
509
509
  if (AppState.currentState !== 'active') {return;}
510
- if (client.status !== 'online' && !client.suppressReconnect) {
510
+ if (client.suppressReconnect) {return;}
511
+ if (client.status !== 'online') {
511
512
  devPushLog('rn', `watchdog: client ${client.status} → forceReconnect`);
512
513
  client.forceReconnect();
514
+ } else {
515
+ client.ensureStreamAlive?.();
513
516
  }
514
517
  }, 30000);
515
518
  return () => clearInterval(id);
@@ -713,6 +716,8 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
713
716
  if (client.status === 'offline' || client.status === 'error') {
714
717
  devPushLog('rn', `NetInfo: reachable & client ${client.status} → forceReconnect`);
715
718
  client.forceReconnect();
719
+ } else if (client.status === 'online') {
720
+ client.ensureStreamAlive?.();
716
721
  }
717
722
  });
718
723
  return () => unsub();
@@ -0,0 +1,31 @@
1
+ import { nameToColor } from './hashcolor';
2
+
3
+ // Background for initials avatars. When `colors.avatar` is set in the
4
+ // config every avatar uses it; otherwise each user keeps their per-name
5
+ // pastel from the hash palette (the current default).
6
+ export const getAvatarColor = (
7
+ name?: string | null,
8
+ config?: { colors?: { avatar?: string } }
9
+ ) => config?.colors?.avatar || nameToColor(name || '')?.backgroundColor;
10
+
11
+ // The default pastels are all light, so initials are dark (#141414). A
12
+ // configured avatar color may be dark (e.g. brand primary) — flip the
13
+ // initials to white when the background is too dark to read on.
14
+ export const getAvatarTextColor = (bg?: string) => {
15
+ if (!bg || !bg.startsWith('#')) {
16
+ return '#141414';
17
+ }
18
+ let hex = bg.slice(1);
19
+ if (hex.length === 3) {
20
+ hex = hex
21
+ .split('')
22
+ .map((c) => c + c)
23
+ .join('');
24
+ }
25
+ const num = parseInt(hex.slice(0, 6), 16);
26
+ const r = (num >> 16) & 255;
27
+ const g = (num >> 8) & 255;
28
+ const b = num & 255;
29
+ const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
30
+ return luminance > 150 ? '#141414' : '#FFFFFF';
31
+ };
@@ -0,0 +1,3 @@
1
+ export const getDateLabelColor = (config?: {
2
+ colors?: { primary?: string; secondary?: string; dateLabel?: string };
3
+ }) => config?.colors?.dateLabel || config?.colors?.primary || '#0052CD';
@@ -0,0 +1,3 @@
1
+ export const getIconColor = (config?: {
2
+ colors?: { primary?: string; secondary?: string; icon?: string };
3
+ }) => config?.colors?.icon || config?.colors?.primary || '#0052CD';
@@ -0,0 +1,3 @@
1
+ export const getSenderNameColor = (config?: {
2
+ colors?: { primary?: string; secondary?: string; senderName?: string };
3
+ }) => config?.colors?.senderName || config?.colors?.primary || '#0052CD';