@ethora/chat-component-rn 26.7.3 → 26.7.4

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 (193) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +9 -8
  3. package/lib/commonjs/assets/icons.js +7 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/Header/HeaderRoomList.js +20 -6
  6. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  7. package/lib/commonjs/components/MainComponents/ChatRoom.js +26 -4
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/MessageList.js +2 -1
  10. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +5 -5
  12. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  13. package/lib/commonjs/components/MainComponents/RoomList.js +62 -32
  14. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  15. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +208 -70
  16. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  17. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +307 -99
  18. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  19. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +552 -213
  20. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  21. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +226 -0
  22. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  23. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
  24. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  25. package/lib/commonjs/components/Modals/Modal/Modal.js +8 -0
  26. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  27. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +202 -104
  28. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  29. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +556 -0
  30. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  31. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +210 -0
  32. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  33. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  34. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  35. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +507 -244
  36. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  37. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +74 -46
  38. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  39. package/lib/commonjs/components/Modals/styledModalComponents.js +9 -2
  40. package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
  41. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +17 -7
  42. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  43. package/lib/commonjs/components/styled/SendInput.js +80 -1
  44. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  45. package/lib/commonjs/components/styled/StyledComponents.js +9 -3
  46. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  47. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  48. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  49. package/lib/commonjs/helpers/getChatBackground.js +23 -0
  50. package/lib/commonjs/helpers/getChatBackground.js.map +1 -0
  51. package/lib/commonjs/helpers/mediaLibraryRuntime.js +31 -0
  52. package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +1 -0
  53. package/lib/commonjs/helpers/sheetGestures.js +32 -0
  54. package/lib/commonjs/helpers/sheetGestures.js.map +1 -0
  55. package/lib/commonjs/i18n/strings.js +121 -1
  56. package/lib/commonjs/i18n/strings.js.map +1 -1
  57. package/lib/commonjs/networking/api-requests/user.api.js +59 -0
  58. package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
  59. package/lib/commonjs/roomStore/chatSettingsSlice.js +3 -1
  60. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  61. package/lib/module/assets/icons.js +6 -1
  62. package/lib/module/assets/icons.js.map +1 -1
  63. package/lib/module/components/Header/HeaderRoomList.js +20 -6
  64. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  65. package/lib/module/components/MainComponents/ChatRoom.js +26 -4
  66. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  67. package/lib/module/components/MainComponents/MessageList.js +2 -1
  68. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  69. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +5 -5
  70. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  71. package/lib/module/components/MainComponents/RoomList.js +62 -32
  72. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  73. package/lib/module/components/Menu/HeaderRoomListMenu.js +211 -73
  74. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  75. package/lib/module/components/Modals/AttachSheet/AttachSheet.js +298 -102
  76. package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  77. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +555 -217
  78. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  79. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +223 -0
  80. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  81. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
  82. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  83. package/lib/module/components/Modals/Modal/Modal.js +9 -1
  84. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  85. package/lib/module/components/Modals/NewChatModal/NewChatModal.js +205 -106
  86. package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  87. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +548 -0
  88. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  89. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +205 -0
  90. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  91. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  92. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  93. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +509 -248
  94. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  95. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +76 -48
  96. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  97. package/lib/module/components/Modals/styledModalComponents.js +9 -2
  98. package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
  99. package/lib/module/components/RoomComponents/ChatRoomItem.js +17 -7
  100. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  101. package/lib/module/components/styled/SendInput.js +80 -1
  102. package/lib/module/components/styled/SendInput.js.map +1 -1
  103. package/lib/module/components/styled/StyledComponents.js +9 -3
  104. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  105. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  106. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  107. package/lib/module/helpers/getChatBackground.js +18 -0
  108. package/lib/module/helpers/getChatBackground.js.map +1 -0
  109. package/lib/module/helpers/mediaLibraryRuntime.js +25 -0
  110. package/lib/module/helpers/mediaLibraryRuntime.js.map +1 -0
  111. package/lib/module/helpers/sheetGestures.js +26 -0
  112. package/lib/module/helpers/sheetGestures.js.map +1 -0
  113. package/lib/module/i18n/strings.js +121 -1
  114. package/lib/module/i18n/strings.js.map +1 -1
  115. package/lib/module/networking/api-requests/user.api.js +56 -0
  116. package/lib/module/networking/api-requests/user.api.js.map +1 -1
  117. package/lib/module/roomStore/chatSettingsSlice.js +3 -1
  118. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  119. package/lib/typescript/assets/icons.d.ts +12 -0
  120. package/lib/typescript/assets/icons.d.ts.map +1 -1
  121. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  122. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  123. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  124. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  125. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  126. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +9 -0
  127. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
  128. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +10 -0
  129. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  130. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +9 -0
  131. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -0
  132. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  133. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  134. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
  135. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
  136. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +75 -0
  137. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -0
  138. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +25 -0
  139. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +1 -0
  140. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +6 -1
  141. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
  142. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +16 -0
  143. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  144. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +1 -0
  145. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
  146. package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
  147. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  148. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  149. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  150. package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
  151. package/lib/typescript/helpers/getChatBackground.d.ts +15 -0
  152. package/lib/typescript/helpers/getChatBackground.d.ts.map +1 -0
  153. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +3 -0
  154. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +1 -0
  155. package/lib/typescript/helpers/sheetGestures.d.ts +20 -0
  156. package/lib/typescript/helpers/sheetGestures.d.ts.map +1 -0
  157. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  158. package/lib/typescript/networking/api-requests/user.api.d.ts +27 -0
  159. package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
  160. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  161. package/lib/typescript/types/types.d.ts +8 -5
  162. package/lib/typescript/types/types.d.ts.map +1 -1
  163. package/package.json +6 -1
  164. package/src/assets/icons.tsx +29 -9
  165. package/src/components/Header/HeaderRoomList.tsx +20 -5
  166. package/src/components/MainComponents/ChatRoom.tsx +29 -7
  167. package/src/components/MainComponents/MessageList.tsx +2 -1
  168. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +5 -5
  169. package/src/components/MainComponents/RoomList.tsx +65 -34
  170. package/src/components/Menu/HeaderRoomListMenu.tsx +209 -64
  171. package/src/components/Modals/AttachSheet/AttachSheet.tsx +318 -86
  172. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +598 -279
  173. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +244 -0
  174. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +4 -2
  175. package/src/components/Modals/Modal/Modal.tsx +7 -0
  176. package/src/components/Modals/NewChatModal/NewChatModal.tsx +219 -117
  177. package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +615 -0
  178. package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +217 -0
  179. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +14 -4
  180. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +617 -307
  181. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +75 -58
  182. package/src/components/Modals/styledModalComponents.tsx +9 -2
  183. package/src/components/RoomComponents/ChatRoomItem.tsx +14 -7
  184. package/src/components/styled/SendInput.tsx +83 -2
  185. package/src/components/styled/StyledComponents.ts +9 -3
  186. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +11 -4
  187. package/src/helpers/getChatBackground.ts +18 -0
  188. package/src/helpers/mediaLibraryRuntime.ts +25 -0
  189. package/src/helpers/sheetGestures.ts +25 -0
  190. package/src/i18n/strings.ts +121 -1
  191. package/src/networking/api-requests/user.api.ts +71 -0
  192. package/src/roomStore/chatSettingsSlice.ts +3 -1
  193. package/src/types/types.ts +8 -5
@@ -1,18 +1,16 @@
1
- import React, { useCallback, useMemo } from 'react';
1
+ /** @format */
2
2
 
3
- import {
4
- ModalContainerFullScreen,
5
- Viewider,
6
- Label,
7
- LabelData,
8
- BorderedContainer,
9
- CenterContainer,
10
- } from '../styledModalComponents';
11
- import ModalHeaderComponent from '../ModalHeaderComponent';
12
- import Button from '../../styled/Button';
3
+ import React, { useCallback, useMemo } from 'react';
4
+ import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
13
5
  import { useDispatch } from 'react-redux';
6
+ import { ModalContainerFullScreen } from '../styledModalComponents';
7
+ import ModalHeaderComponent from '../ModalHeaderComponent';
8
+ import { ArowDownIcon } from '../../../assets/icons';
14
9
  import { setActiveModal } from '../../../roomStore/chatSettingsSlice';
15
10
  import { MODAL_TYPES } from '../../../helpers/constants/MODAL_TYPES';
11
+ import { useChatSettingState } from '../../../hooks/useChatSettingState';
12
+ import { chatTextStyle } from '../../../helpers/typography';
13
+ import { useT } from '../../../i18n/useT';
16
14
 
17
15
  interface UserSettingsModalProps {
18
16
  handleCloseModal: any;
@@ -21,65 +19,84 @@ interface UserSettingsModalProps {
21
19
  const UserSettingsModal: React.FC<UserSettingsModalProps> = ({
22
20
  handleCloseModal,
23
21
  }) => {
22
+ const t = useT();
23
+ const dispatch = useDispatch();
24
+ const { config } = useChatSettingState();
25
+
24
26
  const options = useMemo(
25
27
  () => [
26
- { value: 'Manage Data', key: MODAL_TYPES.MANAGE_DATA },
27
- { value: 'Visiblility', key: MODAL_TYPES.VISIBILITY },
28
- // { value: 'Profile Shares', key: MODAL_TYPES.PROFILE_SHARES },
29
- // { value: 'Document Shares', key: MODAL_TYPES.DOCUMENT_SHARES },
30
- // { value: 'Blocked Users', key: MODAL_TYPES.BLOCKED_USERS },
31
- // { value: 'Referrals', key: MODAL_TYPES.REFERRALS },
28
+ { label: t('settings.manageData.title'), key: MODAL_TYPES.MANAGE_DATA },
29
+ { label: t('settings.visibility.title'), key: MODAL_TYPES.VISIBILITY },
32
30
  ],
33
- []
31
+ [t]
34
32
  );
35
33
 
36
- const dispatch = useDispatch();
37
-
38
- const handleClick = useCallback((key: string) => {
39
- dispatch(setActiveModal(key as any));
40
- }, []);
34
+ const handleClick = useCallback(
35
+ (key: string) => {
36
+ dispatch(setActiveModal(key as any));
37
+ },
38
+ [dispatch]
39
+ );
41
40
 
42
41
  return (
43
- <ModalContainerFullScreen>
42
+ <ModalContainerFullScreen style={styles.screen}>
44
43
  <ModalHeaderComponent
45
44
  handleCloseModal={handleCloseModal}
46
- headerTitle={'Settings'}
45
+ headerTitle={t('settings.menu.title')}
46
+ titleStyle={chatTextStyle(config?.typography?.profile?.screenTitle)}
47
47
  />
48
- <CenterContainer>
49
- <BorderedContainer
50
- style={{
51
- padding: 16,
52
- display: 'flex',
53
- flexDirection: 'column',
54
- gap: 8,
55
- }}
56
- >
57
- {options.map((option: { value: string; key: string }, index) => (
58
- <>
59
- <Button
60
- variant="default"
61
- style={{
62
- minHeight: 40,
63
- display: 'flex',
64
- flexDirection: 'column',
65
- gap: 2,
66
- width: '100%',
67
- justifyContent: 'center',
68
- borderRadius: 0,
69
- alignItems: 'flex-start',
70
- }}
71
- onPress={() => handleClick(option.key)}
72
- >
73
- <Label style={{ textAlign: 'center' }}>{option.value}</Label>
74
- {[2, 3, 4].includes(index) && <LabelData>0</LabelData>}
75
- </Button>
76
- {index < 5 && <Viewider />}
77
- </>
78
- ))}
79
- </BorderedContainer>
80
- </CenterContainer>
48
+ {/* One card per entry, rather than a single bordered block with
49
+ * hairline dividers — the rows are separate destinations, and the
50
+ * design gives each its own surface. */}
51
+ <View style={styles.body}>
52
+ {options.map((option) => (
53
+ <TouchableOpacity
54
+ key={option.key}
55
+ testID={`settings-row-${option.key}`}
56
+ activeOpacity={0.7}
57
+ style={styles.card}
58
+ onPress={() => handleClick(option.key)}
59
+ >
60
+ <Text style={styles.label}>{option.label}</Text>
61
+ <ArowDownIcon color="#8C8C8C" width={20} height={20} style={styles.chevron} />
62
+ </TouchableOpacity>
63
+ ))}
64
+ </View>
81
65
  </ModalContainerFullScreen>
82
66
  );
83
67
  };
84
68
 
69
+ const styles = StyleSheet.create({
70
+ screen: {
71
+ backgroundColor: '#E8EDF2',
72
+ },
73
+ body: {
74
+ width: '100%',
75
+ padding: 12,
76
+ gap: 12,
77
+ },
78
+ card: {
79
+ flexDirection: 'row',
80
+ alignItems: 'center',
81
+ justifyContent: 'space-between',
82
+ backgroundColor: '#FFFFFF',
83
+ borderRadius: 20,
84
+ paddingHorizontal: 20,
85
+ paddingVertical: 22,
86
+ shadowColor: '#101828',
87
+ shadowOffset: { width: 0, height: 4 },
88
+ shadowOpacity: 0.06,
89
+ shadowRadius: 12,
90
+ elevation: 3,
91
+ },
92
+ label: {
93
+ fontSize: 17,
94
+ fontWeight: '500',
95
+ color: '#141414',
96
+ },
97
+ chevron: {
98
+ transform: [{ rotate: '-90deg' }],
99
+ },
100
+ });
101
+
85
102
  export default UserSettingsModal;
@@ -86,8 +86,15 @@ export const HeaderContainer = styled.View`
86
86
  * button and 8px below — properly sized and properly centered. */
87
87
  padding: 8px 16px;
88
88
  background-color: #fff;
89
- border-bottom-width: 1px;
90
- border-bottom-color: #f0f0f0;
89
+ /* Same card treatment as the room-list header: rounded bottom corners
90
+ * and a soft drop shadow instead of a hairline rule. */
91
+ border-bottom-left-radius: 20px;
92
+ border-bottom-right-radius: 20px;
93
+ shadow-color: #101828;
94
+ shadow-offset: 0px 4px;
95
+ shadow-opacity: 0.06;
96
+ shadow-radius: 12px;
97
+ elevation: 4;
91
98
  z-index: 1;
92
99
  flex-direction: row;
93
100
  justify-content: space-between;
@@ -90,11 +90,13 @@ const ChatRoomItem: React.FC<ChatRoomItemProps> = ({
90
90
 
91
91
  return (
92
92
  <ChatItem key={index}>
93
- <ProfileImagePlaceholder
94
- name={displayName}
95
- icon={appendFileToken(chat?.icon, fileToken)}
96
- active={false}
97
- />
93
+ <View pointerEvents="none">
94
+ <ProfileImagePlaceholder
95
+ name={displayName}
96
+ icon={appendFileToken(chat?.icon, fileToken)}
97
+ active={false}
98
+ />
99
+ </View>
98
100
  <View
99
101
  style={{
100
102
  flexDirection: 'column',
@@ -104,7 +106,9 @@ const ChatRoomItem: React.FC<ChatRoomItemProps> = ({
104
106
  paddingVertical: 8,
105
107
  paddingRight: 8,
106
108
  borderBottomWidth: 1,
107
- borderBottomColor: '#F0F0F0',
109
+ // Reads against the list's #E8EDF2 ground; #F0F0F0 was lighter
110
+ // than the ground itself, so the row separators vanished.
111
+ borderBottomColor: '#C6CFDA',
108
112
  }}
109
113
  >
110
114
  <View
@@ -215,8 +219,11 @@ const ChatRoomItem: React.FC<ChatRoomItemProps> = ({
215
219
  ) : null}
216
220
  </View>
217
221
  {isDriver && (
222
+ // Darker than the list's own ground (#E8EDF2), otherwise the
223
+ // separator disappears into it — white and the old #0052CD0D
224
+ // hairline both did.
218
225
  <View
219
- style={{ height: 1, backgroundColor: '#0052CD0D', marginTop: 8 }}
226
+ style={{ height: 1, backgroundColor: '#C6CFDA', marginTop: 8 }}
220
227
  />
221
228
  )}
222
229
  </View>
@@ -10,14 +10,16 @@ import { IConfig, MediaFile } from '../../types/types';
10
10
  import Button from './Button';
11
11
  import { SendIcon, AttachIcon, RecordIcon } from '../../assets/icons';
12
12
  import { KeyboardAvoidingView, Platform, View, Text, TouchableOpacity, Alert, Linking } from 'react-native';
13
- import AttachSheet from '../Modals/AttachSheet/AttachSheet';
13
+ import AttachSheet, { PickedMedia } from '../Modals/AttachSheet/AttachSheet';
14
14
  import { MediaFilePreview } from './MediaFilePreview';
15
15
  import { getIconColor } from '../../helpers/getIconColor';
16
16
  import { getElementFont } from '../../helpers/getElementFont';
17
17
  import { useT } from '../../i18n/useT';
18
+ import { getMediaLibrary } from '../../helpers/mediaLibraryRuntime';
18
19
  import * as ImagePicker from 'expo-image-picker';
19
20
  import * as DocumentPicker from 'expo-document-picker';
20
21
  import * as ImageManipulator from 'expo-image-manipulator';
22
+ import * as FileSystem from 'expo-file-system/legacy';
21
23
  // expo-audio replaces the discontinued expo-av: `useAudioRecorder` owns a
22
24
  // single reusable recorder for this input's lifetime (prepare → record →
23
25
  // stop → prepare again), and the module-level helpers cover permissions
@@ -259,6 +261,53 @@ const SendInput: React.FC<SendInputProps> = ({
259
261
  }
260
262
  };
261
263
 
264
+ // A tap on a thumbnail in the attach sheet's recents strip. The sheet
265
+ // already resolved the asset to a real on-disk uri (iOS `ph://` ids are
266
+ // not uploadable); here we apply the same treatment the full-blown
267
+ // pickers get — HEIC→JPEG for images, and a size probe so the 50 MB cap
268
+ // is enforced before anything hits the network.
269
+ const handleRecentMediaSelection = async (media: PickedMedia) => {
270
+ try {
271
+ let size: number | undefined;
272
+ try {
273
+ const info = await FileSystem.getInfoAsync(media.uri);
274
+ if (info.exists && typeof (info as any).size === 'number') {
275
+ size = (info as any).size;
276
+ }
277
+ } catch {
278
+ // Size is a nice-to-have; the backend still rejects oversized bodies.
279
+ }
280
+
281
+ if (media.isVideo) {
282
+ handleFileSelect([
283
+ {
284
+ uri: media.uri,
285
+ type: media.mimeType || 'video/mp4',
286
+ name: media.name,
287
+ size,
288
+ },
289
+ ]);
290
+ return;
291
+ }
292
+
293
+ const normalized = await normalizeImageAsset({
294
+ uri: media.uri,
295
+ mimeType: media.mimeType,
296
+ fileName: media.name,
297
+ } as ImagePicker.ImagePickerAsset);
298
+ handleFileSelect([
299
+ {
300
+ uri: normalized.uri,
301
+ type: normalized.mime,
302
+ name: normalized.name,
303
+ size,
304
+ },
305
+ ]);
306
+ } catch (error) {
307
+ console.error('Recent media error:', error);
308
+ }
309
+ };
310
+
262
311
  const handleFileSelection = async () => {
263
312
  // Drop overlapping invocations — a second getDocumentAsync while the
264
313
  // first is still presented throws PickingInProgressException on iOS.
@@ -287,8 +336,39 @@ const SendInput: React.FC<SendInputProps> = ({
287
336
  }
288
337
  };
289
338
 
339
+ // Photo-library access is requested HERE, not inside the sheet: iOS
340
+ // cannot present the permission alert while an RN <Modal> owns the
341
+ // screen (the same UIKit limitation that used to swallow the pickers),
342
+ // so asking from inside resolved to a silent "denied" and the recents
343
+ // strip stayed empty forever. Asking on the paperclip tap puts the
344
+ // system alert over the plain chat screen, where it can actually show.
345
+ // Only the first tap ever waits on it — afterwards the status is
346
+ // already determined and `getPermissionsAsync` returns immediately.
347
+ const ensureLibraryPermission = async () => {
348
+ const MediaLibrary = getMediaLibrary();
349
+ if (!MediaLibrary?.getPermissionsAsync) {return;}
350
+ try {
351
+ const perm = await MediaLibrary.getPermissionsAsync();
352
+ if (perm?.granted || perm?.canAskAgain === false) {return;}
353
+ await MediaLibrary.requestPermissionsAsync();
354
+ } catch (err) {
355
+ // Optional peer / unsupported platform: the sheet just shows the
356
+ // camera tile and the full-library route.
357
+ console.warn('Media library permission check failed:', err);
358
+ }
359
+ };
360
+
361
+ // Only the very first tap of a session goes through the permission
362
+ // check; afterwards the sheet opens with zero added latency.
363
+ const libraryPermissionCheckedRef = useRef(false);
364
+
290
365
  const handleAttachPress = () => {
291
- setShowMediaMenu(true);
366
+ if (libraryPermissionCheckedRef.current) {
367
+ setShowMediaMenu(true);
368
+ return;
369
+ }
370
+ libraryPermissionCheckedRef.current = true;
371
+ ensureLibraryPermission().finally(() => setShowMediaMenu(true));
292
372
  };
293
373
 
294
374
  // ─── Voice recording ──────────────────────────────────────────────
@@ -692,6 +772,7 @@ const SendInput: React.FC<SendInputProps> = ({
692
772
  onCamera={handleCameraSelection}
693
773
  onGallery={handleGallerySelection}
694
774
  onDocument={handleFileSelection}
775
+ onPickMedia={handleRecentMediaSelection}
695
776
  primaryColor={getIconColor(config)}
696
777
  />
697
778
  </InputContainer>
@@ -28,9 +28,15 @@ export const ChatContainerHeader = styled.View`
28
28
  background-color: #ffffff;
29
29
  align-items: center;
30
30
  justify-content: space-between;
31
- border-bottom-width: 1px;
32
- border-bottom-color: #e5e7eb;
33
- border-style: solid;
31
+ /* Rounded bottom corners + a soft drop shadow instead of the hairline
32
+ * rule, so the header reads as a card over the conversation. */
33
+ border-bottom-left-radius: 20px;
34
+ border-bottom-right-radius: 20px;
35
+ shadow-color: #101828;
36
+ shadow-offset: 0px 4px;
37
+ shadow-opacity: 0.06;
38
+ shadow-radius: 12px;
39
+ elevation: 4;
34
40
  z-index: 1000;
35
41
  `;
36
42
 
@@ -13,14 +13,21 @@ const colors = {
13
13
 
14
14
  export const InputContainer = styled.View<{ isText?: boolean }>`
15
15
  flex-direction: column;
16
- padding: 8px 16px 4px 16px;
17
- background-color: ${colors.white};
16
+ padding: 12px 16px 8px 16px;
17
+ /* Transparent, so the dock's white surface — and its rounded top
18
+ * corners — are what shows. An opaque child painted straight over those
19
+ * corners (a parent's border radius does not clip children without
20
+ * overflow:hidden, and that would clip the dock's shadow too). */
21
+ background-color: transparent;
18
22
  z-index: 100;
19
23
  width: 100%;
20
24
  bottom: 0;
21
25
  left: 0;
22
- border-top-width: 1px;
23
- border-top-color: #e5e7eb;
26
+ /* No radius or shadow here: the dock this sits in (ChatRoom's
27
+ * InputDockTag) is the composer's outer surface and carries both. Having
28
+ * them on this inner view too drew its shadow onto the dock's white
29
+ * background — the faint seam that made the strip below look like a
30
+ * different colour. */
24
31
  `;
25
32
 
26
33
  export const MediaContainer = styled.View`
@@ -0,0 +1,18 @@
1
+ /** @format */
2
+
3
+ import type { IConfig } from '../types/types';
4
+
5
+ /** Ground behind the conversation, and behind the rounded corners of the
6
+ * header and the composer that sit over it. */
7
+ export const DEFAULT_CHAT_BACKGROUND = '#F3F6FC';
8
+
9
+ /**
10
+ * One place for the conversation's background colour.
11
+ *
12
+ * The message list has always painted it; the chat container behind it was
13
+ * plain white, which is what made the header's rounded bottom corners and
14
+ * the composer's rounded top corners invisible — the corners revealed the
15
+ * white parent, not the conversation.
16
+ */
17
+ export const getChatBackgroundColor = (config?: IConfig): string =>
18
+ config?.backgroundChat?.color || DEFAULT_CHAT_BACKGROUND;
@@ -0,0 +1,25 @@
1
+ let cached: any | undefined;
2
+
3
+ export const getMediaLibrary = (): any | null => {
4
+ if (cached !== undefined) {return cached;}
5
+ try {
6
+ const legacy = require('expo-media-library/legacy');
7
+
8
+ if (legacy?.getAssetsAsync) {
9
+ cached = legacy;
10
+ return cached;
11
+ }
12
+ } catch {
13
+ }
14
+
15
+ try {
16
+ cached = require('expo-media-library') ?? null;
17
+ } catch {
18
+ cached = null;
19
+ }
20
+ return cached;
21
+ };
22
+
23
+ export const __resetMediaLibraryCache = () => {
24
+ cached = undefined;
25
+ };
@@ -0,0 +1,25 @@
1
+ /** @format */
2
+
3
+ /**
4
+ * Shared thresholds for the drag-to-dismiss gesture on bottom sheets (the
5
+ * attach sheet, the profile headers, the room-list menu). Kept in one
6
+ * place so a pull feels identical wherever the user does it — and so the
7
+ * numbers are unit-testable without a touch event.
8
+ */
9
+
10
+ /** Drag past this many points and letting go dismisses the sheet. */
11
+ export const DISMISS_DISTANCE = 90;
12
+ /** …or flick faster than this, however short the drag. */
13
+ export const DISMISS_VELOCITY = 0.8;
14
+
15
+ /**
16
+ * Claim a drag only once it is clearly a downward pull, so a tap on a row
17
+ * still registers and a horizontal swipe stays with whatever scrolls
18
+ * sideways inside the sheet.
19
+ */
20
+ export const shouldClaimVerticalDrag = (dy: number, dx: number) =>
21
+ dy > 6 && Math.abs(dy) > Math.abs(dx) * 1.5;
22
+
23
+ /** Far enough / fast enough to let go of the sheet. */
24
+ export const shouldDismissOnDrag = (dy: number, vy: number) =>
25
+ dy > DISMISS_DISTANCE || vy > DISMISS_VELOCITY;