@ethora/chat-component-rn 26.5.16 → 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 (215) 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/ReduxWrapper.js +4 -0
  22. package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
  23. package/lib/commonjs/components/MainComponents/RoomList.js +2 -1
  24. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  25. package/lib/commonjs/components/MessageBubble/Avatar.js +16 -7
  26. package/lib/commonjs/components/MessageBubble/Avatar.js.map +1 -1
  27. package/lib/commonjs/components/MessageBubble/Message.js +16 -1
  28. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  29. package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js +9 -0
  30. package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
  31. package/lib/commonjs/components/styled/Button.js +4 -2
  32. package/lib/commonjs/components/styled/Button.js.map +1 -1
  33. package/lib/commonjs/components/styled/DateLabel.js +12 -4
  34. package/lib/commonjs/components/styled/DateLabel.js.map +1 -1
  35. package/lib/commonjs/components/styled/SendInput.js +4 -3
  36. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  37. package/lib/commonjs/context/xmppProvider.js +12 -1
  38. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  39. package/lib/commonjs/helpers/getAvatarColor.js +33 -0
  40. package/lib/commonjs/helpers/getAvatarColor.js.map +1 -0
  41. package/lib/commonjs/helpers/getDateLabelColor.js +9 -0
  42. package/lib/commonjs/helpers/getDateLabelColor.js.map +1 -0
  43. package/lib/commonjs/helpers/getIconColor.js +9 -0
  44. package/lib/commonjs/helpers/getIconColor.js.map +1 -0
  45. package/lib/commonjs/helpers/getSenderNameColor.js +9 -0
  46. package/lib/commonjs/helpers/getSenderNameColor.js.map +1 -0
  47. package/lib/commonjs/helpers/historyPreloadScheduler.js +118 -113
  48. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  49. package/lib/commonjs/hooks/useChatFonts.js +137 -0
  50. package/lib/commonjs/hooks/useChatFonts.js.map +1 -0
  51. package/lib/commonjs/hooks/useSendMessage.js +72 -22
  52. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  53. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +4 -2
  54. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  55. package/lib/commonjs/main.js +7 -0
  56. package/lib/commonjs/main.js.map +1 -1
  57. package/lib/commonjs/networking/outboundQueue.js +22 -4
  58. package/lib/commonjs/networking/outboundQueue.js.map +1 -1
  59. package/lib/commonjs/networking/xmppClient.js +50 -0
  60. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  61. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js +22 -0
  62. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  63. package/lib/commonjs/roomStore/roomsSlice.js +22 -2
  64. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  65. package/lib/module/assets/EmptyChatIllustration.js +99 -0
  66. package/lib/module/assets/EmptyChatIllustration.js.map +1 -0
  67. package/lib/module/assets/icons.js +13 -2
  68. package/lib/module/assets/icons.js.map +1 -1
  69. package/lib/module/components/DropdownMenu/DropdownMenu.js +2 -1
  70. package/lib/module/components/DropdownMenu/DropdownMenu.js.map +1 -1
  71. package/lib/module/components/MainComponents/ChatHeader.js +2 -1
  72. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  73. package/lib/module/components/MainComponents/ChatRoom.js +5 -2
  74. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  75. package/lib/module/components/MainComponents/ChooseChatMessage.js +9 -2
  76. package/lib/module/components/MainComponents/ChooseChatMessage.js.map +1 -1
  77. package/lib/module/components/MainComponents/EditWrapper.js +12 -4
  78. package/lib/module/components/MainComponents/EditWrapper.js.map +1 -1
  79. package/lib/module/components/MainComponents/MessageList.js +2 -1
  80. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  81. package/lib/module/components/MainComponents/NoMessagesPlaceholder.js +11 -3
  82. package/lib/module/components/MainComponents/NoMessagesPlaceholder.js.map +1 -1
  83. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +12 -7
  84. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  85. package/lib/module/components/MainComponents/ReduxWrapper.js +4 -0
  86. package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
  87. package/lib/module/components/MainComponents/RoomList.js +2 -1
  88. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  89. package/lib/module/components/MessageBubble/Avatar.js +16 -7
  90. package/lib/module/components/MessageBubble/Avatar.js.map +1 -1
  91. package/lib/module/components/MessageBubble/Message.js +16 -1
  92. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  93. package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js +9 -0
  94. package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
  95. package/lib/module/components/styled/Button.js +4 -2
  96. package/lib/module/components/styled/Button.js.map +1 -1
  97. package/lib/module/components/styled/DateLabel.js +12 -4
  98. package/lib/module/components/styled/DateLabel.js.map +1 -1
  99. package/lib/module/components/styled/SendInput.js +4 -3
  100. package/lib/module/components/styled/SendInput.js.map +1 -1
  101. package/lib/module/context/xmppProvider.js +13 -2
  102. package/lib/module/context/xmppProvider.js.map +1 -1
  103. package/lib/module/helpers/getAvatarColor.js +28 -0
  104. package/lib/module/helpers/getAvatarColor.js.map +1 -0
  105. package/lib/module/helpers/getDateLabelColor.js +4 -0
  106. package/lib/module/helpers/getDateLabelColor.js.map +1 -0
  107. package/lib/module/helpers/getIconColor.js +4 -0
  108. package/lib/module/helpers/getIconColor.js.map +1 -0
  109. package/lib/module/helpers/getSenderNameColor.js +4 -0
  110. package/lib/module/helpers/getSenderNameColor.js.map +1 -0
  111. package/lib/module/helpers/historyPreloadScheduler.js +119 -114
  112. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  113. package/lib/module/hooks/useChatFonts.js +132 -0
  114. package/lib/module/hooks/useChatFonts.js.map +1 -0
  115. package/lib/module/hooks/useSendMessage.js +72 -22
  116. package/lib/module/hooks/useSendMessage.js.map +1 -1
  117. package/lib/module/hooks/useUnreadMessagesCounter.js +4 -2
  118. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  119. package/lib/module/main.js +2 -0
  120. package/lib/module/main.js.map +1 -1
  121. package/lib/module/networking/outboundQueue.js +21 -4
  122. package/lib/module/networking/outboundQueue.js.map +1 -1
  123. package/lib/module/networking/xmppClient.js +50 -0
  124. package/lib/module/networking/xmppClient.js.map +1 -1
  125. package/lib/module/roomStore/Middleware/newMessageMidlleware.js +22 -0
  126. package/lib/module/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  127. package/lib/module/roomStore/roomsSlice.js +20 -1
  128. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  129. package/lib/typescript/assets/EmptyChatIllustration.d.ts +10 -0
  130. package/lib/typescript/assets/EmptyChatIllustration.d.ts.map +1 -0
  131. package/lib/typescript/assets/icons.d.ts +3 -12
  132. package/lib/typescript/assets/icons.d.ts.map +1 -1
  133. package/lib/typescript/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  134. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  135. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  136. package/lib/typescript/components/MainComponents/ChooseChatMessage.d.ts.map +1 -1
  137. package/lib/typescript/components/MainComponents/EditWrapper.d.ts +5 -1
  138. package/lib/typescript/components/MainComponents/EditWrapper.d.ts.map +1 -1
  139. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  140. package/lib/typescript/components/MainComponents/NoMessagesPlaceholder.d.ts.map +1 -1
  141. package/lib/typescript/components/MainComponents/ProfileImagePlaceholder.d.ts.map +1 -1
  142. package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
  143. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  144. package/lib/typescript/components/MessageBubble/Avatar.d.ts.map +1 -1
  145. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  146. package/lib/typescript/components/Modals/ModalWrapper/ModalWrapper.d.ts.map +1 -1
  147. package/lib/typescript/components/styled/Button.d.ts +1 -0
  148. package/lib/typescript/components/styled/Button.d.ts.map +1 -1
  149. package/lib/typescript/components/styled/DateLabel.d.ts +9 -8
  150. package/lib/typescript/components/styled/DateLabel.d.ts.map +1 -1
  151. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  152. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  153. package/lib/typescript/helpers/getAvatarColor.d.ts +7 -0
  154. package/lib/typescript/helpers/getAvatarColor.d.ts.map +1 -0
  155. package/lib/typescript/helpers/getDateLabelColor.d.ts +8 -0
  156. package/lib/typescript/helpers/getDateLabelColor.d.ts.map +1 -0
  157. package/lib/typescript/helpers/getIconColor.d.ts +8 -0
  158. package/lib/typescript/helpers/getIconColor.d.ts.map +1 -0
  159. package/lib/typescript/helpers/getSenderNameColor.d.ts +8 -0
  160. package/lib/typescript/helpers/getSenderNameColor.d.ts.map +1 -0
  161. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  162. package/lib/typescript/hooks/useChatFonts.d.ts +23 -0
  163. package/lib/typescript/hooks/useChatFonts.d.ts.map +1 -0
  164. package/lib/typescript/hooks/useSendMessage.d.ts +1 -1
  165. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  166. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts +1 -0
  167. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
  168. package/lib/typescript/main.d.ts +2 -1
  169. package/lib/typescript/main.d.ts.map +1 -1
  170. package/lib/typescript/networking/outboundQueue.d.ts +16 -1
  171. package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
  172. package/lib/typescript/networking/xmppClient.d.ts +3 -0
  173. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  174. package/lib/typescript/roomStore/Middleware/newMessageMidlleware.d.ts.map +1 -1
  175. package/lib/typescript/roomStore/roomsSlice.d.ts +3 -1
  176. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  177. package/lib/typescript/types/models/message.model.d.ts +1 -0
  178. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  179. package/lib/typescript/types/types.d.ts +53 -0
  180. package/lib/typescript/types/types.d.ts.map +1 -1
  181. package/package.json +5 -1
  182. package/src/assets/EmptyChatIllustration.tsx +49 -0
  183. package/src/assets/icons.tsx +64 -81
  184. package/src/components/DropdownMenu/DropdownMenu.tsx +2 -1
  185. package/src/components/MainComponents/ChatHeader.tsx +2 -1
  186. package/src/components/MainComponents/ChatRoom.tsx +5 -2
  187. package/src/components/MainComponents/ChooseChatMessage.tsx +5 -2
  188. package/src/components/MainComponents/EditWrapper.tsx +9 -6
  189. package/src/components/MainComponents/MessageList.tsx +2 -1
  190. package/src/components/MainComponents/NoMessagesPlaceholder.tsx +4 -1
  191. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +14 -7
  192. package/src/components/MainComponents/ReduxWrapper.tsx +4 -0
  193. package/src/components/MainComponents/RoomList.tsx +2 -1
  194. package/src/components/MessageBubble/Avatar.tsx +18 -9
  195. package/src/components/MessageBubble/Message.tsx +16 -1
  196. package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +6 -0
  197. package/src/components/styled/Button.tsx +5 -1
  198. package/src/components/styled/DateLabel.tsx +10 -7
  199. package/src/components/styled/SendInput.tsx +4 -3
  200. package/src/context/xmppProvider.tsx +11 -1
  201. package/src/helpers/getAvatarColor.ts +31 -0
  202. package/src/helpers/getDateLabelColor.ts +3 -0
  203. package/src/helpers/getIconColor.ts +3 -0
  204. package/src/helpers/getSenderNameColor.ts +3 -0
  205. package/src/helpers/historyPreloadScheduler.ts +7 -1
  206. package/src/hooks/useChatFonts.ts +153 -0
  207. package/src/hooks/useSendMessage.tsx +101 -58
  208. package/src/hooks/useUnreadMessagesCounter.ts +5 -2
  209. package/src/main.ts +4 -0
  210. package/src/networking/outboundQueue.ts +25 -4
  211. package/src/networking/xmppClient.ts +47 -0
  212. package/src/roomStore/Middleware/newMessageMidlleware.tsx +25 -0
  213. package/src/roomStore/roomsSlice.ts +26 -1
  214. package/src/types/models/message.model.ts +3 -0
  215. package/src/types/types.ts +59 -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
  )}
@@ -10,6 +10,7 @@ import {ToastProvider} from '../../context/ToastContext';
10
10
  import LoginWrapper from './LoginWrapper';
11
11
  import '../../helpers/storeConsole';
12
12
  import {installPromiseRejectionTracker} from '../../utils/installPromiseRejectionTracker';
13
+ import {useChatFonts} from '../../hooks/useChatFonts';
13
14
 
14
15
  // Mount-time, dev-only — wire a global unhandled-promise-rejection
15
16
  // tracker so any future leak surfaces with a real stack trace in Metro
@@ -33,6 +34,9 @@ export const ReduxWrapper: React.FC<ChatWrapperProps> = React.memo(
33
34
  return props.config;
34
35
  }, [props.config]);
35
36
 
37
+ // Load + apply the host-provided font (no-op when typography is unset).
38
+ useChatFonts(memoizedConfig?.typography);
39
+
36
40
  // Host apps that own their keyboard handling (their own
37
41
  // KeyboardProvider + KeyboardAvoidingView around <Chat>) set
38
42
  // `disableKeyboardAvoidingView` — drop the built-in KeyboardProvider
@@ -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
  );
@@ -45,6 +45,7 @@ import {
45
45
  setLastViewedTimestamp,
46
46
  deleteRoomMessage,
47
47
  msgSortableMs,
48
+ setUnreadSyncing,
48
49
  } from '../roomStore/roomsSlice';
49
50
  import { runHistoryPreloadScheduler } from '../helpers/historyPreloadScheduler';
50
51
  import { asyncLocalStorage } from '../hooks/useLocalStorage';
@@ -272,6 +273,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
272
273
  devPushLog('warn', 'initBeforeLoad: time budget exceeded → failed');
273
274
  abortController.abort();
274
275
  inflightBootstrapKeyRef.current = '';
276
+ store.dispatch(setUnreadSyncing(false));
275
277
  setProviderBootstrapStatus('failed');
276
278
  }, BOOTSTRAP_BUDGET_MS);
277
279
  const clearBudget = () => {
@@ -304,6 +306,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
304
306
  }
305
307
  inflightBootstrapKeyRef.current = key;
306
308
  setProviderBootstrapStatus('running');
309
+ store.dispatch(setUnreadSyncing(true));
307
310
  devPushLog('rn', 'initBeforeLoad: running', {
308
311
  appId: config?.appId,
309
312
  baseUrl: config?.baseUrl,
@@ -338,6 +341,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
338
341
  });
339
342
  setProviderBootstrapStatus('failed');
340
343
  inflightBootstrapKeyRef.current = '';
344
+ store.dispatch(setUnreadSyncing(false));
341
345
  return;
342
346
  }
343
347
 
@@ -447,6 +451,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
447
451
  });
448
452
  inflightBootstrapKeyRef.current = '';
449
453
  clearBudget();
454
+ store.dispatch(setUnreadSyncing(false));
450
455
  setProviderBootstrapStatus('failed');
451
456
  }
452
457
  };
@@ -502,9 +507,12 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
502
507
  if (!client) {return;}
503
508
  const id = setInterval(() => {
504
509
  if (AppState.currentState !== 'active') {return;}
505
- if (client.status !== 'online' && !client.suppressReconnect) {
510
+ if (client.suppressReconnect) {return;}
511
+ if (client.status !== 'online') {
506
512
  devPushLog('rn', `watchdog: client ${client.status} → forceReconnect`);
507
513
  client.forceReconnect();
514
+ } else {
515
+ client.ensureStreamAlive?.();
508
516
  }
509
517
  }, 30000);
510
518
  return () => clearInterval(id);
@@ -708,6 +716,8 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
708
716
  if (client.status === 'offline' || client.status === 'error') {
709
717
  devPushLog('rn', `NetInfo: reachable & client ${client.status} → forceReconnect`);
710
718
  client.forceReconnect();
719
+ } else if (client.status === 'online') {
720
+ client.ensureStreamAlive?.();
711
721
  }
712
722
  });
713
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';
@@ -1,7 +1,7 @@
1
1
  import { AppState } from 'react-native';
2
2
  import XmppClient from '../networking/xmppClient';
3
3
  import { store } from '../roomStore';
4
- import { applyRoomsPreloadBatch } from '../roomStore/roomsSlice';
4
+ import { applyRoomsPreloadBatch, setUnreadSyncing } from '../roomStore/roomsSlice';
5
5
  import { IMessage, IRoom } from '../types/types';
6
6
 
7
7
  interface HistoryPreloadSchedulerOptions {
@@ -112,6 +112,9 @@ export const runHistoryPreloadScheduler = async (
112
112
 
113
113
  if (signal?.aborted) {return;}
114
114
 
115
+ store.dispatch(setUnreadSyncing(true));
116
+ try {
117
+
115
118
  const state = store.getState();
116
119
  const rooms = (state.rooms.rooms || {}) as Record<string, IRoom>;
117
120
  const defaultSet = new Set(defaultRoomJids);
@@ -276,6 +279,9 @@ export const runHistoryPreloadScheduler = async (
276
279
  // Yield to JS event loop (no requestIdleCallback in RN).
277
280
  await new Promise((r) => setTimeout(r, 0));
278
281
  }
282
+ } finally {
283
+ store.dispatch(setUnreadSyncing(false));
284
+ }
279
285
  };
280
286
 
281
287
  export default runHistoryPreloadScheduler;