@ethora/chat-component-rn 26.7.2 → 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.
- package/CHANGELOG.md +45 -0
- package/README.md +9 -8
- package/lib/commonjs/assets/icons.js +7 -2
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/Header/HeaderRoomList.js +20 -6
- package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js +86 -7
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +18 -0
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageList.js +11 -4
- package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +5 -5
- package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomList.js +62 -32
- package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
- package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +208 -70
- package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +307 -99
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +544 -200
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +226 -0
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js +8 -0
- package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +202 -104
- package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +556 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +210 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
- package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
- package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +507 -244
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +74 -46
- package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
- package/lib/commonjs/components/Modals/styledModalComponents.js +9 -2
- package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +17 -7
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +80 -1
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/StyledComponents.js +9 -3
- package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +12 -0
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/getChatBackground.js +23 -0
- package/lib/commonjs/helpers/getChatBackground.js.map +1 -0
- package/lib/commonjs/helpers/historyPreloadScheduler.js +65 -2
- package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/commonjs/helpers/mediaLibraryRuntime.js +31 -0
- package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +1 -0
- package/lib/commonjs/helpers/shallowEqual.js +36 -0
- package/lib/commonjs/helpers/shallowEqual.js.map +1 -0
- package/lib/commonjs/helpers/sheetGestures.js +32 -0
- package/lib/commonjs/helpers/sheetGestures.js.map +1 -0
- package/lib/commonjs/hooks/useChatWrapperInit.js +15 -0
- package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/commonjs/hooks/useComposing.js +27 -0
- package/lib/commonjs/hooks/useComposing.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +27 -1
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js +6 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/commonjs/i18n/strings.js +121 -1
- package/lib/commonjs/i18n/strings.js.map +1 -1
- package/lib/commonjs/networking/api-requests/user.api.js +59 -0
- package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +6 -2
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/chatSettingsSlice.js +3 -1
- package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +2 -2
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/assets/icons.js +6 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/Header/HeaderRoomList.js +20 -6
- package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +87 -8
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +19 -1
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MessageList.js +11 -4
- package/lib/module/components/MainComponents/MessageList.js.map +1 -1
- package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +5 -5
- package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
- package/lib/module/components/MainComponents/RoomList.js +62 -32
- package/lib/module/components/MainComponents/RoomList.js.map +1 -1
- package/lib/module/components/Menu/HeaderRoomListMenu.js +211 -73
- package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js +298 -102
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +547 -204
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +223 -0
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/Modal/Modal.js +9 -1
- package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/module/components/Modals/NewChatModal/NewChatModal.js +205 -106
- package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +548 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +205 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
- package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
- package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +509 -248
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +76 -48
- package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
- package/lib/module/components/Modals/styledModalComponents.js +9 -2
- package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js +17 -7
- package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +80 -1
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/StyledComponents.js +9 -3
- package/lib/module/components/styled/StyledComponents.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/module/context/xmppProvider.js +12 -0
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/getChatBackground.js +18 -0
- package/lib/module/helpers/getChatBackground.js.map +1 -0
- package/lib/module/helpers/historyPreloadScheduler.js +66 -3
- package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/module/helpers/mediaLibraryRuntime.js +25 -0
- package/lib/module/helpers/mediaLibraryRuntime.js.map +1 -0
- package/lib/module/helpers/shallowEqual.js +31 -0
- package/lib/module/helpers/shallowEqual.js.map +1 -0
- package/lib/module/helpers/sheetGestures.js +26 -0
- package/lib/module/helpers/sheetGestures.js.map +1 -0
- package/lib/module/hooks/useChatWrapperInit.js +15 -0
- package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/module/hooks/useComposing.js +28 -1
- package/lib/module/hooks/useComposing.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +28 -2
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js +6 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/module/i18n/strings.js +121 -1
- package/lib/module/i18n/strings.js.map +1 -1
- package/lib/module/networking/api-requests/user.api.js +56 -0
- package/lib/module/networking/api-requests/user.api.js.map +1 -1
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +6 -2
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/chatSettingsSlice.js +3 -1
- package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +1 -1
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/typescript/assets/icons.d.ts +12 -0
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MessageList.d.ts +10 -1
- package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
- package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +9 -0
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +10 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +9 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -0
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
- package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +75 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +25 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +1 -0
- package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +6 -1
- package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +16 -0
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +1 -0
- package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/getChatBackground.d.ts +15 -0
- package/lib/typescript/helpers/getChatBackground.d.ts.map +1 -0
- package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
- package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +3 -0
- package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +1 -0
- package/lib/typescript/helpers/shallowEqual.d.ts +11 -0
- package/lib/typescript/helpers/shallowEqual.d.ts.map +1 -0
- package/lib/typescript/helpers/sheetGestures.d.ts +20 -0
- package/lib/typescript/helpers/sheetGestures.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
- package/lib/typescript/hooks/useComposing.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts +1 -0
- package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
- package/lib/typescript/i18n/strings.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/user.api.d.ts +27 -0
- package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +1 -0
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +1 -0
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +1 -0
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +9 -5
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/assets/icons.tsx +29 -9
- package/src/components/Header/HeaderRoomList.tsx +20 -5
- package/src/components/MainComponents/ChatRoom.tsx +92 -8
- package/src/components/MainComponents/ChatWrapper.tsx +19 -1
- package/src/components/MainComponents/MessageList.tsx +21 -3
- package/src/components/MainComponents/ProfileImagePlaceholder.tsx +5 -5
- package/src/components/MainComponents/RoomList.tsx +65 -34
- package/src/components/Menu/HeaderRoomListMenu.tsx +209 -64
- package/src/components/Modals/AttachSheet/AttachSheet.tsx +318 -86
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +599 -278
- package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +244 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +4 -2
- package/src/components/Modals/Modal/Modal.tsx +7 -0
- package/src/components/Modals/NewChatModal/NewChatModal.tsx +219 -117
- package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +615 -0
- package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +217 -0
- package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +14 -4
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +617 -307
- package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +75 -58
- package/src/components/Modals/styledModalComponents.tsx +9 -2
- package/src/components/RoomComponents/ChatRoomItem.tsx +14 -7
- package/src/components/styled/SendInput.tsx +83 -2
- package/src/components/styled/StyledComponents.ts +9 -3
- package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +11 -4
- package/src/context/xmppProvider.tsx +14 -0
- package/src/helpers/getChatBackground.ts +18 -0
- package/src/helpers/historyPreloadScheduler.ts +80 -3
- package/src/helpers/mediaLibraryRuntime.ts +25 -0
- package/src/helpers/shallowEqual.ts +33 -0
- package/src/helpers/sheetGestures.ts +25 -0
- package/src/hooks/useChatWrapperInit.ts +15 -0
- package/src/hooks/useComposing.tsx +37 -1
- package/src/hooks/useSendMessage.tsx +32 -2
- package/src/hooks/useUnreadMessagesCounter.ts +11 -0
- package/src/i18n/strings.ts +121 -1
- package/src/networking/api-requests/user.api.ts +71 -0
- package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +17 -3
- package/src/networking/xmppClient.ts +5 -1
- package/src/roomStore/chatSettingsSlice.ts +3 -1
- package/src/roomStore/roomsSlice.ts +1 -1
- package/src/types/types.ts +16 -5
|
@@ -20,6 +20,7 @@ import NewChatModal from '../Modals/NewChatModal/NewChatModal';
|
|
|
20
20
|
import { EditWrapper } from './EditWrapper';
|
|
21
21
|
import { EmptyChatIllustration } from '../../assets/EmptyChatIllustration';
|
|
22
22
|
import { getIconColor } from '../../helpers/getIconColor';
|
|
23
|
+
import { getChatBackgroundColor } from '../../helpers/getChatBackground';
|
|
23
24
|
import { ChooseChatMessage } from './ChooseChatMessage';
|
|
24
25
|
import { useRoomUrl } from '../../hooks/useRoomUrl';
|
|
25
26
|
import { useSendMessage } from '../../hooks/useSendMessage';
|
|
@@ -31,6 +32,9 @@ import CustomTypingIndicator from '../styled/StyledInputComponents/CustomTypingI
|
|
|
31
32
|
// import {PanGestureHandler} from 'react-native-gesture-handler';
|
|
32
33
|
import { FlatList } from 'react-native';
|
|
33
34
|
import {
|
|
35
|
+
AppState,
|
|
36
|
+
AppStateStatus,
|
|
37
|
+
Keyboard,
|
|
34
38
|
Platform,
|
|
35
39
|
TouchableWithoutFeedback,
|
|
36
40
|
View,
|
|
@@ -106,6 +110,45 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
|
|
|
106
110
|
configWithEventHandlers || storeConfig,
|
|
107
111
|
);
|
|
108
112
|
|
|
113
|
+
// Under the sticky keyboard strategy, the input dock's position is
|
|
114
|
+
// driven by KeyboardStickyView's native-animated offset. If the app
|
|
115
|
+
// is backgrounded while the keyboard-close animation hasn't finished,
|
|
116
|
+
// the OS removes the keyboard from the app-switcher snapshot but the
|
|
117
|
+
// shared value hasn't caught up to "closed" yet, so the input appears
|
|
118
|
+
// to float in that preview.
|
|
119
|
+
//
|
|
120
|
+
// NOTE on what this does and doesn't fix: iOS actually captures that
|
|
121
|
+
// preview during the active→inactive transition, BEFORE 'background'
|
|
122
|
+
// fires — so dismissing here on 'background' lands too late to affect
|
|
123
|
+
// the snapshot already taken, and is effectively a no-op for the exact
|
|
124
|
+
// iOS symptom in bug #37. An earlier version keyed this off 'inactive'
|
|
125
|
+
// instead, which does land in time, but 'inactive' also fires for
|
|
126
|
+
// Control Center, share sheets, and permission prompts — none of which
|
|
127
|
+
// should close the user's keyboard — so that traded a rare cosmetic
|
|
128
|
+
// preview glitch for a much more common false dismissal. Kept on
|
|
129
|
+
// 'background': it still resets the offset for genuine backgrounding
|
|
130
|
+
// (home button, app switch) and for Android's recents preview (RN's
|
|
131
|
+
// AppState has no 'inactive' there), at the cost of leaving the iOS
|
|
132
|
+
// switcher-preview glitch itself unresolved. Both symptoms are cosmetic
|
|
133
|
+
// per the QA report, which explicitly accepted leaving this imperfect
|
|
134
|
+
// rather than risk destabilizing the sticky strategy. Sticky-only;
|
|
135
|
+
// doesn't touch the other keyboard strategies.
|
|
136
|
+
const stickyInputEnabled =
|
|
137
|
+
!configWithEventHandlers?.disableKeyboardAvoidingView &&
|
|
138
|
+
!!configWithEventHandlers?.keyboardStickyInput;
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (!stickyInputEnabled) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const onAppStateChange = (nextState: AppStateStatus) => {
|
|
144
|
+
if (nextState === 'background') {
|
|
145
|
+
Keyboard.dismiss();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const subscription = AppState.addEventListener('change', onAppStateChange);
|
|
149
|
+
return () => subscription.remove();
|
|
150
|
+
}, [stickyInputEnabled]);
|
|
151
|
+
|
|
109
152
|
const sendMessage = useCallback(
|
|
110
153
|
(message: string) => {
|
|
111
154
|
if (!activeRoomJID) {
|
|
@@ -170,15 +213,28 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
|
|
|
170
213
|
clientRef.current = client;
|
|
171
214
|
}, [client]);
|
|
172
215
|
|
|
216
|
+
// Tracks what the user actually saw: `null` while they're at the
|
|
217
|
+
// bottom (safe to mark everything read), or the timestamp of the
|
|
218
|
+
// newest message visible when they scrolled away from it. Reported
|
|
219
|
+
// by MessageList via onReadBoundaryChange. Without this, leaving a
|
|
220
|
+
// room (or backgrounding) while scrolled up stamped `now()` as read
|
|
221
|
+
// and silently discarded genuinely-unread messages. Customer-
|
|
222
|
+
// reported #33.
|
|
223
|
+
const readBoundaryRef = useRef<number | null>(null);
|
|
224
|
+
const handleReadBoundaryChange = useCallback((boundaryTs: number | null) => {
|
|
225
|
+
readBoundaryRef.current = boundaryTs;
|
|
226
|
+
}, []);
|
|
227
|
+
|
|
173
228
|
useEffect(() => {
|
|
174
229
|
if (!activeRoomJID) {
|
|
175
230
|
return;
|
|
176
231
|
}
|
|
177
232
|
|
|
233
|
+
readBoundaryRef.current = null;
|
|
178
234
|
dispatch(setVisibleRoom({ roomJID: activeRoomJID }));
|
|
179
235
|
setIsLoadingMore(false);
|
|
180
236
|
return () => {
|
|
181
|
-
const timestamp = new Date().getTime();
|
|
237
|
+
const timestamp = readBoundaryRef.current ?? new Date().getTime();
|
|
182
238
|
dispatch(
|
|
183
239
|
setLastViewedTimestamp({
|
|
184
240
|
chatJID: activeRoomJID,
|
|
@@ -191,6 +247,12 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
|
|
|
191
247
|
liveClient
|
|
192
248
|
.flushLastViewedToPrivateStoreStanza(store.getState().rooms?.rooms, {
|
|
193
249
|
visibleRoomJID: activeRoomJID,
|
|
250
|
+
// Carry the same boundary to the SERVER marker. Without
|
|
251
|
+
// this the flush defaults to Date.now() for the visible
|
|
252
|
+
// room, so messages the user never scrolled down to come
|
|
253
|
+
// back as read on the next login — the local count was
|
|
254
|
+
// right but the server overrode it.
|
|
255
|
+
visibleRoomTs: readBoundaryRef.current,
|
|
194
256
|
})
|
|
195
257
|
.catch(() => {});
|
|
196
258
|
}
|
|
@@ -279,7 +341,20 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
|
|
|
279
341
|
? KeyboardStickyView
|
|
280
342
|
: View;
|
|
281
343
|
const inputDockProps: any = {
|
|
282
|
-
|
|
344
|
+
// The dock carries the composer's white surface all the way to the
|
|
345
|
+
// bottom edge, so it needs the same rounded top and upward shadow —
|
|
346
|
+
// a square white block behind a rounded composer just hid the corners.
|
|
347
|
+
style: {
|
|
348
|
+
paddingBottom: inputDockPaddingBottom,
|
|
349
|
+
backgroundColor: '#fff',
|
|
350
|
+
borderTopLeftRadius: 20,
|
|
351
|
+
borderTopRightRadius: 20,
|
|
352
|
+
shadowColor: '#101828',
|
|
353
|
+
shadowOffset: { width: 0, height: -4 },
|
|
354
|
+
shadowOpacity: 0.06,
|
|
355
|
+
shadowRadius: 12,
|
|
356
|
+
elevation: 8,
|
|
357
|
+
},
|
|
283
358
|
...(stickyInput
|
|
284
359
|
? { offset: { closed: 0, opened: keyboardVerticalOffset } }
|
|
285
360
|
: {}),
|
|
@@ -288,11 +363,15 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
|
|
|
288
363
|
return (
|
|
289
364
|
<KeyboardWrapper {...keyboardWrapperProps}>
|
|
290
365
|
<ChatContainer
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
366
|
+
// The conversation's own colour, not white: the header's rounded
|
|
367
|
+
// bottom corners and the composer's rounded top corners reveal
|
|
368
|
+
// THIS view, so a white parent made both look square.
|
|
369
|
+
style={[
|
|
370
|
+
{ backgroundColor: getChatBackgroundColor(configWithEventHandlers) },
|
|
371
|
+
configWithEventHandlers?.chatRoomStyles as
|
|
372
|
+
| import('react-native').ViewStyle
|
|
373
|
+
| undefined,
|
|
374
|
+
]}
|
|
296
375
|
>
|
|
297
376
|
{!configWithEventHandlers?.disableHeader && (
|
|
298
377
|
<ChatHeader
|
|
@@ -331,7 +410,11 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
|
|
|
331
410
|
flex: 1,
|
|
332
411
|
justifyContent: 'center',
|
|
333
412
|
alignItems: 'center',
|
|
334
|
-
|
|
413
|
+
// Empty rooms used to flip to white, which broke the
|
|
414
|
+
// header's rounded corners in exactly the same way.
|
|
415
|
+
backgroundColor: getChatBackgroundColor(
|
|
416
|
+
configWithEventHandlers
|
|
417
|
+
),
|
|
335
418
|
}}
|
|
336
419
|
>
|
|
337
420
|
<NoMessagesPlaceholder />
|
|
@@ -404,6 +487,7 @@ const ChatRoom: React.FC<ChatRoomProps> = React.memo(
|
|
|
404
487
|
config={configWithEventHandlers}
|
|
405
488
|
loading={isLoadingMore}
|
|
406
489
|
isReply={false}
|
|
490
|
+
onReadBoundaryChange={handleReadBoundaryChange}
|
|
407
491
|
/>
|
|
408
492
|
)}
|
|
409
493
|
</View>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {FC, useEffect, useMemo, useState} from 'react';
|
|
1
|
+
import React, {FC, useEffect, useMemo, useRef, useState} from 'react';
|
|
2
2
|
import {useDispatch, useSelector} from 'react-redux';
|
|
3
3
|
import ChatRoom from './ChatRoom';
|
|
4
4
|
import {
|
|
@@ -34,6 +34,7 @@ import {DeviceEventEmitter, Pressable, Text, View} from 'react-native';
|
|
|
34
34
|
import {pushLog as devPushLog} from '../../utils/devLogger';
|
|
35
35
|
import {normalizeRoomJid} from '../../helpers/normalizeRoomJid';
|
|
36
36
|
import {buildSeedRoom} from '../../helpers/buildSeedRoom';
|
|
37
|
+
import {shallowEqual} from '../../helpers/shallowEqual';
|
|
37
38
|
import {InteractionsOverlayProvider} from '../MessageBubble/InteractionsOverlay';
|
|
38
39
|
|
|
39
40
|
interface ChatWrapperProps {
|
|
@@ -161,6 +162,23 @@ const ChatWrapper: FC<ChatWrapperProps> = ({
|
|
|
161
162
|
dispatch(addRoom({roomData: buildSeedRoom(seededRoomJID)}));
|
|
162
163
|
}, [seededRoomJID, seededRoomMissing, dispatch]);
|
|
163
164
|
|
|
165
|
+
// Presentational config flags (e.g. `disableHeader`) can change while the
|
|
166
|
+
// chat stays mounted — sync them to redux whenever `config` actually
|
|
167
|
+
// changes, not just at init. Kept separate from the init effect below so
|
|
168
|
+
// toggling a flag doesn't re-run client/token setup. Guarded with a
|
|
169
|
+
// shallow-equal check (not just the `config` reference) because hosts
|
|
170
|
+
// commonly pass an inline object literal (`<Chat config={{...}}/>`) that
|
|
171
|
+
// is a new reference on every render even when nothing in it changed —
|
|
172
|
+
// dispatching unconditionally there would re-render every config
|
|
173
|
+
// consumer (ChatRoom, modals, ...) on every host render.
|
|
174
|
+
const lastSyncedConfigRef = useRef<IConfig | undefined>(undefined);
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (config && !shallowEqual(lastSyncedConfigRef.current, config)) {
|
|
177
|
+
lastSyncedConfigRef.current = config;
|
|
178
|
+
dispatch(setConfig(config));
|
|
179
|
+
}
|
|
180
|
+
}, [config, dispatch]);
|
|
181
|
+
|
|
164
182
|
useEffect(() => {
|
|
165
183
|
if (roomJID) {
|
|
166
184
|
dispatch(
|
|
@@ -28,6 +28,7 @@ import Loader from '../styled/Loader';
|
|
|
28
28
|
import { ArowDownIcon } from '../../assets/icons';
|
|
29
29
|
import CustomTypingIndicator from '../styled/StyledInputComponents/CustomTypingIndicator';
|
|
30
30
|
import { getIconColor } from '../../helpers/getIconColor';
|
|
31
|
+
import { getChatBackgroundColor } from '../../helpers/getChatBackground';
|
|
31
32
|
|
|
32
33
|
interface MessageListProps<TMessage extends IMessage> {
|
|
33
34
|
CustomMessage?: React.ComponentType<{
|
|
@@ -53,6 +54,15 @@ interface MessageListProps<TMessage extends IMessage> {
|
|
|
53
54
|
config?: IConfig;
|
|
54
55
|
isReply: boolean;
|
|
55
56
|
activeMessage?: IMessage;
|
|
57
|
+
/**
|
|
58
|
+
* Fired whenever the "read up to" boundary changes: `null` while the
|
|
59
|
+
* user is at the bottom (everything is read), or the timestamp of the
|
|
60
|
+
* newest message they'd actually seen when they scrolled away from it.
|
|
61
|
+
* Lets the host mark only what was actually viewed as read instead of
|
|
62
|
+
* stamping "now" on unmount/leave, which would wrongly clear unread
|
|
63
|
+
* messages the user scrolled up and never got back down to.
|
|
64
|
+
*/
|
|
65
|
+
onReadBoundaryChange?: (boundaryTs: number | null) => void;
|
|
56
66
|
}
|
|
57
67
|
|
|
58
68
|
const MessageList = <TMessage extends IMessage>({
|
|
@@ -66,6 +76,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
66
76
|
loading,
|
|
67
77
|
isReply,
|
|
68
78
|
activeMessage,
|
|
79
|
+
onReadBoundaryChange,
|
|
69
80
|
}: MessageListProps<TMessage>) => {
|
|
70
81
|
const { composing, messages, composingList } = useRoomState(roomJID)
|
|
71
82
|
.room! as IRoom;
|
|
@@ -332,6 +343,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
332
343
|
// counter so the badge disappears with the arrow.
|
|
333
344
|
setUnreadWhileScrolledUp(0);
|
|
334
345
|
newestSeenTsRef.current = null;
|
|
346
|
+
onReadBoundaryChange?.(null);
|
|
335
347
|
} else {
|
|
336
348
|
isUserAtBottomRef.current = false;
|
|
337
349
|
if (hasUserScrolledRef.current) {
|
|
@@ -349,11 +361,12 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
349
361
|
},
|
|
350
362
|
0
|
|
351
363
|
);
|
|
364
|
+
onReadBoundaryChange?.(newestSeenTsRef.current);
|
|
352
365
|
}
|
|
353
366
|
setIsUserAtBottom(false);
|
|
354
367
|
}
|
|
355
368
|
},
|
|
356
|
-
[memoizedMessages]
|
|
369
|
+
[memoizedMessages, onReadBoundaryChange]
|
|
357
370
|
);
|
|
358
371
|
|
|
359
372
|
// Keep the badge in sync with messages that arrive while the user is
|
|
@@ -382,6 +395,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
382
395
|
setIsUserAtBottom(true);
|
|
383
396
|
setUnreadWhileScrolledUp(0);
|
|
384
397
|
newestSeenTsRef.current = null;
|
|
398
|
+
onReadBoundaryChange?.(null);
|
|
385
399
|
scrollToBottom();
|
|
386
400
|
};
|
|
387
401
|
|
|
@@ -392,6 +406,8 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
392
406
|
setIsUserAtBottom(true);
|
|
393
407
|
setUnreadWhileScrolledUp(0);
|
|
394
408
|
newestSeenTsRef.current = null;
|
|
409
|
+
onReadBoundaryChange?.(null);
|
|
410
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
395
411
|
}, [roomJID]);
|
|
396
412
|
|
|
397
413
|
const BackgroundImage = useMemo(() => {
|
|
@@ -413,7 +429,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
413
429
|
<View
|
|
414
430
|
style={[
|
|
415
431
|
styles.container,
|
|
416
|
-
{ backgroundColor: config
|
|
432
|
+
{ backgroundColor: getChatBackgroundColor(config) },
|
|
417
433
|
]}
|
|
418
434
|
>
|
|
419
435
|
<View style={styles.backgroundImageContainer}>{BackgroundImage}</View>
|
|
@@ -442,7 +458,9 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
442
458
|
onLayout={handleLayout}
|
|
443
459
|
inverted={true}
|
|
444
460
|
keyboardShouldPersistTaps="handled"
|
|
445
|
-
keyboardDismissMode=
|
|
461
|
+
keyboardDismissMode={
|
|
462
|
+
config?.keepKeyboardOpenOnScroll ? 'none' : 'interactive'
|
|
463
|
+
}
|
|
446
464
|
contentContainerStyle={styles.flatListContent}
|
|
447
465
|
ListFooterComponent={
|
|
448
466
|
loading && memoizedMessages.length > 15 ? (
|
|
@@ -69,27 +69,27 @@ export const ProfileImagePlaceholder: React.FC<
|
|
|
69
69
|
if (words.length === 0) {return '';}
|
|
70
70
|
|
|
71
71
|
if (words.length >= 2) {
|
|
72
|
-
const firstLetter = /^[
|
|
72
|
+
const firstLetter = /^[\p{L}\p{N}]$/u.test(words[0]?.[0] || '')
|
|
73
73
|
? words[0][0].toUpperCase()
|
|
74
74
|
: '';
|
|
75
|
-
const secondLetter = /^[
|
|
75
|
+
const secondLetter = /^[\p{L}\p{N}]$/u.test(words[1]?.[0] || '')
|
|
76
76
|
? words[1][0].toUpperCase()
|
|
77
77
|
: '';
|
|
78
78
|
return firstLetter + secondLetter;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
if (words.length === 1 && words[0].length >= 2) {
|
|
82
|
-
const firstLetter = /^[
|
|
82
|
+
const firstLetter = /^[\p{L}\p{N}]$/u.test(words[0][0] || '')
|
|
83
83
|
? words[0][0].toUpperCase()
|
|
84
84
|
: '';
|
|
85
|
-
const secondLetter = /^[
|
|
85
|
+
const secondLetter = /^[\p{L}\p{N}]$/u.test(words[0][1] || '')
|
|
86
86
|
? words[0][1].toUpperCase()
|
|
87
87
|
: '';
|
|
88
88
|
return firstLetter + secondLetter;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
if (words.length === 1 && words[0].length === 1) {
|
|
92
|
-
return /^[
|
|
92
|
+
return /^[\p{L}\p{N}]$/u.test(words[0][0] || '')
|
|
93
93
|
? words[0][0].toUpperCase()
|
|
94
94
|
: '';
|
|
95
95
|
}
|
|
@@ -35,6 +35,14 @@ interface RoomListProps {
|
|
|
35
35
|
onRoomClick?: (chat: IRoom) => void;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/** Page ground behind the room list, the search field and the header's
|
|
39
|
+
* rounded bottom corners. */
|
|
40
|
+
const LIST_BACKGROUND = '#E8EDF2';
|
|
41
|
+
|
|
42
|
+
/** First-paint fallback until the floating search strip reports its real
|
|
43
|
+
* height; the list's top padding follows the measurement after that. */
|
|
44
|
+
const SEARCH_BAR_ESTIMATE = 60;
|
|
45
|
+
|
|
38
46
|
const RoomList: React.FC<RoomListProps> = ({
|
|
39
47
|
chats,
|
|
40
48
|
burgerMenu = false,
|
|
@@ -120,6 +128,10 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
120
128
|
}
|
|
121
129
|
}, [burgerMenu]);
|
|
122
130
|
|
|
131
|
+
// Measured, so the list's top padding always matches the floating
|
|
132
|
+
// search strip — including when a larger font or a taller field grows it.
|
|
133
|
+
const [searchBarHeight, setSearchBarHeight] = useState(SEARCH_BAR_ESTIMATE);
|
|
134
|
+
|
|
123
135
|
const toggleDrawer = () => {
|
|
124
136
|
if (isDrawerOpen) {
|
|
125
137
|
closeDrawer();
|
|
@@ -180,39 +192,50 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
180
192
|
<>
|
|
181
193
|
<View style={styles.scrollContainer}>
|
|
182
194
|
<HeaderRoomList setDrawerOpen={toggleDrawer} />
|
|
183
|
-
{/*
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
<View style={styles.
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
{/* The search field floats OVER the list rather than
|
|
196
|
+
sitting above it in the column: its strip is transparent
|
|
197
|
+
and the rooms scroll underneath, which is what the design
|
|
198
|
+
shows. It is still fixed (not a ListHeaderComponent), so
|
|
199
|
+
it stays reachable however far the list is scrolled — as a
|
|
200
|
+
list header it scrolled away behind the opaque header. */}
|
|
201
|
+
<View style={styles.listArea}>
|
|
202
|
+
<FlatList
|
|
203
|
+
data={filteredChats}
|
|
204
|
+
keyExtractor={(item) => item.jid}
|
|
205
|
+
// Clears the floating field on first paint; scrolling
|
|
206
|
+
// then slides the rooms under it.
|
|
207
|
+
contentContainerStyle={{ paddingTop: searchBarHeight }}
|
|
208
|
+
renderItem={({ item }) => (
|
|
209
|
+
<Pressable
|
|
210
|
+
// Stable testID so e2e drivers can target a room
|
|
211
|
+
// row by its jid local-part (e.g. Main chat under
|
|
212
|
+
// app id `..._...759` → testID `room-...759`).
|
|
213
|
+
testID={`room-${(item.jid || '').split('@')[0]}`}
|
|
214
|
+
accessibilityLabel={`room-${item.title || item.name}`}
|
|
215
|
+
onPress={() => performClick(item)}
|
|
216
|
+
onPressIn={handlePressIn}
|
|
217
|
+
onPressOut={handlePressOut}
|
|
218
|
+
>
|
|
219
|
+
<ChatRoomItem chat={item} config={config} />
|
|
220
|
+
</Pressable>
|
|
221
|
+
)}
|
|
222
|
+
style={styles.chatList}
|
|
195
223
|
/>
|
|
224
|
+
<View
|
|
225
|
+
testID="room-list-search"
|
|
226
|
+
style={styles.searchBar}
|
|
227
|
+
onLayout={(e) =>
|
|
228
|
+
setSearchBarHeight(e.nativeEvent.layout.height)
|
|
229
|
+
}
|
|
230
|
+
>
|
|
231
|
+
<SearchInput
|
|
232
|
+
icon={<SearchIcon height={20} />}
|
|
233
|
+
value={searchTerm}
|
|
234
|
+
onChangeText={handleSearchChange}
|
|
235
|
+
placeholder={t('search.placeholder')}
|
|
236
|
+
/>
|
|
237
|
+
</View>
|
|
196
238
|
</View>
|
|
197
|
-
<FlatList
|
|
198
|
-
data={filteredChats}
|
|
199
|
-
keyExtractor={(item) => item.jid}
|
|
200
|
-
renderItem={({ item }) => (
|
|
201
|
-
<Pressable
|
|
202
|
-
// Stable testID so e2e drivers can target a room
|
|
203
|
-
// row by its jid local-part (e.g. Main chat under
|
|
204
|
-
// app id `..._...759` → testID `room-...759`).
|
|
205
|
-
testID={`room-${(item.jid || '').split('@')[0]}`}
|
|
206
|
-
accessibilityLabel={`room-${item.title || item.name}`}
|
|
207
|
-
onPress={() => performClick(item)}
|
|
208
|
-
onPressIn={handlePressIn}
|
|
209
|
-
onPressOut={handlePressOut}
|
|
210
|
-
>
|
|
211
|
-
<ChatRoomItem chat={item} config={config} />
|
|
212
|
-
</Pressable>
|
|
213
|
-
)}
|
|
214
|
-
style={styles.chatList}
|
|
215
|
-
/>
|
|
216
239
|
|
|
217
240
|
<HeaderRoomListMenu
|
|
218
241
|
closeDrawer={closeDrawer}
|
|
@@ -238,7 +261,7 @@ const styles = StyleSheet.create({
|
|
|
238
261
|
width: '100%',
|
|
239
262
|
height: '100%',
|
|
240
263
|
flex: 1,
|
|
241
|
-
backgroundColor:
|
|
264
|
+
backgroundColor: LIST_BACKGROUND,
|
|
242
265
|
},
|
|
243
266
|
scrollContainer: {
|
|
244
267
|
flexGrow: 1,
|
|
@@ -249,6 +272,9 @@ const styles = StyleSheet.create({
|
|
|
249
272
|
padding: 16,
|
|
250
273
|
justifyContent: 'space-between',
|
|
251
274
|
},
|
|
275
|
+
listArea: {
|
|
276
|
+
flex: 1,
|
|
277
|
+
},
|
|
252
278
|
searchBar: {
|
|
253
279
|
// `row` matters: SearchInputWrapper is `flex: 1` plus a fixed 44px
|
|
254
280
|
// height. In a column parent that flex resolves VERTICALLY against a
|
|
@@ -256,14 +282,19 @@ const styles = StyleSheet.create({
|
|
|
256
282
|
// but its magnifier. As a row it resolves to width, which is what it
|
|
257
283
|
// meant back when the field was a list-header child.
|
|
258
284
|
flexDirection: 'row',
|
|
285
|
+
position: 'absolute',
|
|
286
|
+
top: 0,
|
|
287
|
+
left: 0,
|
|
288
|
+
right: 0,
|
|
259
289
|
paddingTop: 8,
|
|
290
|
+
paddingBottom: 8,
|
|
260
291
|
paddingHorizontal: 16,
|
|
261
|
-
backgroundColor: '
|
|
292
|
+
backgroundColor: 'transparent',
|
|
262
293
|
},
|
|
263
294
|
chatList: {
|
|
264
295
|
flex: 1,
|
|
265
296
|
paddingHorizontal: 16,
|
|
266
|
-
backgroundColor:
|
|
297
|
+
backgroundColor: LIST_BACKGROUND,
|
|
267
298
|
},
|
|
268
299
|
});
|
|
269
300
|
|