@smart-link/rn-im 1.0.24 → 1.0.26
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/assets/file-dir.jpg +0 -0
- package/dist/components/ChatAvatar/ChatAvatarLocal.js +0 -1
- package/dist/default-assets.d.ts +1 -0
- package/dist/default-assets.js +1 -0
- package/dist/interface.d.ts +9 -0
- package/dist/pages/conversation/setting/OptionAvatars.d.ts +1 -1
- package/dist/pages/conversation/setting/OptionGroup.d.ts +1 -1
- package/dist/pages/conversation/setting/Setting.js +2 -3
- package/dist/pages/message/FileSelector.d.ts +6 -0
- package/dist/pages/message/FileSelector.js +235 -0
- package/dist/pages/message/MessageList.js +19 -15
- package/dist/pages/message/MessageRecord.js +33 -22
- package/dist/pages/message/components/MessageItem.d.ts +2 -1
- package/dist/pages/message/components/MessageItem.js +6 -5
- package/dist/pages/message/components/MessageOption.d.ts +7 -3
- package/dist/pages/message/components/MessageOption.js +13 -16
- package/dist/pages/message/components/MessagePayload.d.ts +2 -1
- package/dist/pages/message/components/Payload/PayloadFile.d.ts +1 -1
- package/dist/pages/message/components/Payload/PayloadFile.js +11 -11
- package/dist/pages/message/components/Payload/PayloadMultiple.js +9 -5
- package/dist/pages/message/components/Payload/PayloadPicture.d.ts +1 -1
- package/dist/pages/message/components/Payload/PayloadPicture.js +3 -4
- package/dist/pages/message/components/Payload/PayloadVideo.js +2 -1
- package/dist/pages/message/components/Payload/PayloadVoice.js +1 -1
- package/dist/pages/message/components/Payload/PayloadWrapper.d.ts +2 -1
- package/dist/pages/message/components/Payload/PayloadWrapper.js +8 -3
- package/dist/pages/message/components/Payload/type.d.ts +2 -1
- package/dist/pages/message/components/ReceiptBack.js +2 -2
- package/dist/pages/message/components/TextMixQuote.js +7 -12
- package/dist/pages/message/components/TextMixQuoteMessage.js +3 -3
- package/dist/pages/message/components/messageBar/OptionPanel.js +6 -31
- package/dist/pages/message/message.routes.js +10 -0
- package/dist/pages/types.d.ts +4 -2
- package/dist/slice/video/video.action.js +9 -1
- package/dist/utils/file.d.ts +10 -2
- package/dist/utils/file.js +140 -27
- package/dist/utils/upload.js +1 -1
- package/package.json +2 -2
- package/dist/slice/contact/contact.action.d.ts +0 -1
- package/dist/slice/contact/contact.action.js +0 -1
Binary file
|
@@ -81,7 +81,6 @@ const ChatAvatarLocal = ({ fileId, size, name, defaultAvatar }) => {
|
|
81
81
|
return;
|
82
82
|
}
|
83
83
|
loadAvatar().then(_r => { });
|
84
|
-
console.log('fileId: ', fileId, name);
|
85
84
|
}, [fileId]);
|
86
85
|
if (ready && avatar) {
|
87
86
|
return (<LocalImage localPath={avatar} style={size ? { width: size, height: size, borderRadius: size / 2 } : { width: 40, height: 40, borderRadius: 20 }}/>);
|
package/dist/default-assets.d.ts
CHANGED
package/dist/default-assets.js
CHANGED
package/dist/interface.d.ts
CHANGED
@@ -4,7 +4,7 @@ import { ViewProps } from "react-native/Libraries/Components/View/ViewPropTypes"
|
|
4
4
|
interface IOptionGroupProps extends ViewProps {
|
5
5
|
id: string;
|
6
6
|
name: string;
|
7
|
-
avatars
|
7
|
+
avatars?: string;
|
8
8
|
notice: string;
|
9
9
|
memberLevel: MemberLevel;
|
10
10
|
enableInviteValidate: string;
|
@@ -110,13 +110,12 @@ const ConversationSetting = ({ navigation }) => {
|
|
110
110
|
switch (type) {
|
111
111
|
case ConversationType.C2C:
|
112
112
|
content = (<>
|
113
|
-
<OptionAvatars list={
|
113
|
+
<OptionAvatars list={[
|
114
114
|
{
|
115
115
|
userId: id,
|
116
116
|
userName: name,
|
117
|
-
avatars,
|
118
117
|
},
|
119
|
-
]
|
118
|
+
]} showAdd={true} showDelete={false} showMore={false} addUser={() => {
|
120
119
|
getImManager().store.dispatch(startCreateGroup());
|
121
120
|
navigation.navigate('ChooseContact', {
|
122
121
|
chooseOrg: true,
|
@@ -0,0 +1,6 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import { NativeStackScreenProps } from "@react-navigation/native-stack/lib/typescript/src/types";
|
3
|
+
import { IMPageParamList } from "../types";
|
4
|
+
type FileSelectorProps = NativeStackScreenProps<IMPageParamList, 'FileSelector'>;
|
5
|
+
declare const FileSelector: ({ navigation }: FileSelectorProps) => React.JSX.Element;
|
6
|
+
export default FileSelector;
|
@@ -0,0 +1,235 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
10
|
+
// @flow
|
11
|
+
import * as React from 'react';
|
12
|
+
import { dp, NavigationPage, SearchInput } from "@smart-link/rn-ui";
|
13
|
+
import { View, StyleSheet, TouchableOpacity, ScrollView, Text, FlatList } from "react-native";
|
14
|
+
import { Fragment, useCallback, useEffect, useState } from "react";
|
15
|
+
import { getFileRootItem, getFileType, isImage, numberToFileSize, readFileDir, selectFile } from "../../utils/file";
|
16
|
+
import { getImManager } from "../../init";
|
17
|
+
import AntDesign from "react-native-vector-icons/AntDesign";
|
18
|
+
import useTranslation from "../../hooks/useTranslation";
|
19
|
+
import { findSvgIcon } from "../../utils/file-icon";
|
20
|
+
import FastImage from "react-native-fast-image";
|
21
|
+
import { dirImg } from "../../default-assets";
|
22
|
+
import { formatTime } from "../../hooks/useFormatMsgTime";
|
23
|
+
import { useConversation } from "../../hooks/useImSelector";
|
24
|
+
const getIcon = (item) => {
|
25
|
+
if (item.isDir) {
|
26
|
+
return <FastImage style={styles.fileImage} source={dirImg}/>;
|
27
|
+
}
|
28
|
+
if (isImage(item.path)) {
|
29
|
+
return <FastImage style={styles.fileImage} source={{ uri: 'file://' + item.path }}/>;
|
30
|
+
}
|
31
|
+
if (item.thumbPath) {
|
32
|
+
return <FastImage style={styles.fileImage} source={{ uri: 'file://' + item.thumbPath }}/>;
|
33
|
+
}
|
34
|
+
const Icon = findSvgIcon(getFileType(item.path));
|
35
|
+
return <Icon style={styles.fileImage}/>;
|
36
|
+
};
|
37
|
+
const FileSelector = ({ navigation }) => {
|
38
|
+
const scrollHolder = {};
|
39
|
+
const [data, setData] = useState([]);
|
40
|
+
const [keyword, setKeyword] = useState('');
|
41
|
+
const [pathItems, setPathItems] = useState([]);
|
42
|
+
const imManager = getImManager();
|
43
|
+
const { t, i18n } = useTranslation();
|
44
|
+
const { currentConversation } = useConversation();
|
45
|
+
useEffect(() => {
|
46
|
+
navigation.setOptions({
|
47
|
+
headerLeft({ tintColor }) {
|
48
|
+
return (<TouchableOpacity activeOpacity={0.5} style={{ padding: dp(10) }} onPress={() => {
|
49
|
+
navigation.goBack();
|
50
|
+
}}>
|
51
|
+
<Text style={{ color: tintColor }}>{t('cancel')}</Text>
|
52
|
+
</TouchableOpacity>);
|
53
|
+
},
|
54
|
+
title: t('file')
|
55
|
+
});
|
56
|
+
getFileRootItem(imManager).then(items => {
|
57
|
+
setData(items);
|
58
|
+
});
|
59
|
+
}, [navigation, t]);
|
60
|
+
const onPressItem = (item) => __awaiter(void 0, void 0, void 0, function* () {
|
61
|
+
if (!item.isDir) {
|
62
|
+
const localPath = yield selectFile(imManager, item.path, item.name);
|
63
|
+
const file = {
|
64
|
+
filename: item.name,
|
65
|
+
localPath: localPath,
|
66
|
+
size: item.size,
|
67
|
+
type: getFileType(item.path),
|
68
|
+
lastModified: item.time,
|
69
|
+
};
|
70
|
+
navigation.goBack();
|
71
|
+
if (isImage(file.localPath)) {
|
72
|
+
imManager.sendPictureMessage(currentConversation, file);
|
73
|
+
}
|
74
|
+
else {
|
75
|
+
imManager.sendFileMessage(currentConversation, file);
|
76
|
+
}
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
setPathItems([...pathItems.filter(pathItem => pathItem.path !== item.path), item]);
|
80
|
+
scrollHolder.scroll.scrollToEnd();
|
81
|
+
readFileDir(imManager, item.path, keyword).then(items => {
|
82
|
+
setData(items);
|
83
|
+
});
|
84
|
+
});
|
85
|
+
const onChangeText = useCallback((keyword) => {
|
86
|
+
setKeyword(keyword);
|
87
|
+
if (pathItems.length === 0) {
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
readFileDir(imManager, pathItems[pathItems.length - 1].path, keyword).then(items => {
|
91
|
+
setData(items);
|
92
|
+
});
|
93
|
+
}, [pathItems]);
|
94
|
+
const onPressPathRoot = useCallback(() => {
|
95
|
+
setPathItems([]);
|
96
|
+
getFileRootItem(imManager).then(items => {
|
97
|
+
setData(items);
|
98
|
+
});
|
99
|
+
}, []);
|
100
|
+
const onPressPathItem = useCallback((item) => {
|
101
|
+
setPathItems([
|
102
|
+
...pathItems.filter(source => source.path.indexOf(item.path) === -1),
|
103
|
+
item
|
104
|
+
]);
|
105
|
+
readFileDir(imManager, item.path, keyword).then(items => {
|
106
|
+
setData(items);
|
107
|
+
});
|
108
|
+
}, [pathItems, keyword]);
|
109
|
+
const listHeaderComponent = data.length === 0 ? null : <View style={styles.listHeaderLine}/>;
|
110
|
+
const listFooterComponent = data.length === 0 ? null : <View style={styles.listFooterLine}/>;
|
111
|
+
const itemSeparatorComponent = () => <View style={styles.separator}/>;
|
112
|
+
const keyExtractor = (item) => item.name + '_' + item.size;
|
113
|
+
const renderItem = ({ item }) => {
|
114
|
+
const icon = getIcon(item);
|
115
|
+
const extText = item.isDir ? (item.childrenCount + t('items')) : numberToFileSize(item.size);
|
116
|
+
return (<TouchableOpacity style={styles.item} onPress={() => {
|
117
|
+
onPressItem && onPressItem(item);
|
118
|
+
}}>
|
119
|
+
|
120
|
+
{icon}
|
121
|
+
<View style={styles.width15}/>
|
122
|
+
<View style={styles.left}>
|
123
|
+
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'middle'}>
|
124
|
+
{item.name}
|
125
|
+
</Text>
|
126
|
+
<Text style={styles.time} numberOfLines={1} ellipsizeMode={'middle'}>
|
127
|
+
{(item.time ? (formatTime(item.time, t, i18n) + ' - ') : '') + extText}
|
128
|
+
</Text>
|
129
|
+
</View>
|
130
|
+
{item.isDir &&
|
131
|
+
<AntDesign name='right' size={dp(14)} color={'#666'} style={styles.accessory}/>}
|
132
|
+
|
133
|
+
</TouchableOpacity>);
|
134
|
+
};
|
135
|
+
return (<NavigationPage noPadding>
|
136
|
+
<View style={styles.selector}>
|
137
|
+
<View style={styles.search}>
|
138
|
+
<SearchInput style={{
|
139
|
+
height: dp(32),
|
140
|
+
backgroundColor: '#ececec',
|
141
|
+
}} value={keyword} onChange={onChangeText} onSubmitEditing={() => { }}/>
|
142
|
+
</View>
|
143
|
+
<View style={styles.scroll}>
|
144
|
+
<TouchableOpacity onPress={onPressPathRoot} style={styles.scrollVertical}>
|
145
|
+
<Text style={styles.pathText}>{t('position')}</Text>
|
146
|
+
</TouchableOpacity>
|
147
|
+
<AntDesign name='right' size={dp(16)} color={'#333'} style={styles.scrollVertical}/>
|
148
|
+
<ScrollView style={styles.scrollVertical} horizontal={true} ref={v => scrollHolder.scroll = v}>
|
149
|
+
|
150
|
+
{pathItems.map((pathItem, index) => {
|
151
|
+
const disabled = index === pathItems.length - 1;
|
152
|
+
return (<Fragment key={index}>
|
153
|
+
<TouchableOpacity disabled={disabled} onPress={() => {
|
154
|
+
onPressPathItem && onPressPathItem(pathItem);
|
155
|
+
}}>
|
156
|
+
<Text style={styles.pathText}>{pathItem.name}</Text>
|
157
|
+
</TouchableOpacity>
|
158
|
+
<AntDesign name='right' size={dp(16)} color={'#333'}/>
|
159
|
+
</Fragment>);
|
160
|
+
})}
|
161
|
+
</ScrollView>
|
162
|
+
</View>
|
163
|
+
<FlatList contentContainerStyle={styles.list} ItemSeparatorComponent={itemSeparatorComponent} ListHeaderComponent={listHeaderComponent} ListFooterComponent={listFooterComponent} initialNumToRender={20} numColumns={1} data={data} keyboardShouldPersistTaps={'handled'} keyExtractor={keyExtractor} renderItem={renderItem}/>
|
164
|
+
</View>
|
165
|
+
</NavigationPage>);
|
166
|
+
};
|
167
|
+
const styles = StyleSheet.create({
|
168
|
+
selector: {
|
169
|
+
flex: 1,
|
170
|
+
backgroundColor: '#fff',
|
171
|
+
},
|
172
|
+
scroll: {
|
173
|
+
flexDirection: 'row',
|
174
|
+
paddingHorizontal: dp(8),
|
175
|
+
},
|
176
|
+
scrollVertical: {
|
177
|
+
paddingBottom: dp(10),
|
178
|
+
},
|
179
|
+
pathText: {
|
180
|
+
paddingHorizontal: dp(5),
|
181
|
+
fontSize: dp(14),
|
182
|
+
lineHeight: dp(16),
|
183
|
+
color: '#666',
|
184
|
+
},
|
185
|
+
search: {
|
186
|
+
backgroundColor: '#fff',
|
187
|
+
padding: dp(10),
|
188
|
+
},
|
189
|
+
list: {
|
190
|
+
paddingHorizontal: dp(15),
|
191
|
+
},
|
192
|
+
listFooterLine: {},
|
193
|
+
listHeaderLine: {},
|
194
|
+
separator: {
|
195
|
+
marginLeft: dp(65),
|
196
|
+
marginVertical: dp(10),
|
197
|
+
height: dp(1),
|
198
|
+
backgroundColor: '#ececec'
|
199
|
+
},
|
200
|
+
width15: {
|
201
|
+
width: dp(15),
|
202
|
+
},
|
203
|
+
width10: {
|
204
|
+
width: dp(10),
|
205
|
+
},
|
206
|
+
item: {
|
207
|
+
flexDirection: 'row',
|
208
|
+
alignItems: 'center',
|
209
|
+
},
|
210
|
+
fileImage: {
|
211
|
+
borderRadius: dp(5),
|
212
|
+
width: dp(49),
|
213
|
+
height: dp(49)
|
214
|
+
},
|
215
|
+
left: {
|
216
|
+
justifyContent: 'space-around'
|
217
|
+
},
|
218
|
+
name: {
|
219
|
+
color: '#333',
|
220
|
+
fontSize: dp(15),
|
221
|
+
lineHeight: dp(20),
|
222
|
+
width: dp(260),
|
223
|
+
},
|
224
|
+
time: {
|
225
|
+
color: '#666',
|
226
|
+
fontSize: dp(12),
|
227
|
+
lineHeight: dp(18),
|
228
|
+
},
|
229
|
+
accessory: {
|
230
|
+
alignSelf: 'center',
|
231
|
+
position: 'absolute',
|
232
|
+
right: dp(15),
|
233
|
+
}
|
234
|
+
});
|
235
|
+
export default FileSelector;
|
@@ -27,9 +27,9 @@ const MessageList = ({ navigation }) => {
|
|
27
27
|
const [showAlbum, setShowAlbum] = useState(false);
|
28
28
|
const [targetMessageSeq, setTargetMessageSeq] = useState('');
|
29
29
|
const [selectMessage, setSelectMessage] = useState();
|
30
|
-
const [nativeEvent, setNativeEvent] = useState();
|
31
30
|
const [loading, setLoading] = useState(false);
|
32
|
-
const
|
31
|
+
const [touchPoint, setTouchPoint] = useState();
|
32
|
+
const [targetLayout, setTargetLayout] = useState();
|
33
33
|
const isB2C = (currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.type) === ConversationType.B2C;
|
34
34
|
useEffect(() => {
|
35
35
|
console.log('[进入会话]: ', currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.name);
|
@@ -62,7 +62,7 @@ const MessageList = ({ navigation }) => {
|
|
62
62
|
InteractionManager.runAfterInteractions(() => {
|
63
63
|
imManager.store.dispatch(MessagePanelActions.saveDraftText(imManager));
|
64
64
|
imManager.leaveConversation();
|
65
|
-
imManager.store.dispatch(MessageActions.resetState());
|
65
|
+
imManager.store.dispatch(MessageActions.resetState({}));
|
66
66
|
});
|
67
67
|
}
|
68
68
|
});
|
@@ -81,12 +81,22 @@ const MessageList = ({ navigation }) => {
|
|
81
81
|
getImManager().store.dispatch(MessageActions.setIsSearch(false));
|
82
82
|
}
|
83
83
|
}, [isSearch]);
|
84
|
-
const
|
85
|
-
|
84
|
+
const onPressPopover = useCallback((message, nativeEvent) => {
|
85
|
+
if (message.payloadType === PayloadType.PICTURE) {
|
86
|
+
setShowAlbum(true);
|
87
|
+
setSelectMessage(undefined);
|
88
|
+
setTargetMessageSeq(message.messageSeq);
|
89
|
+
}
|
90
|
+
}, []);
|
91
|
+
const onLongPressPopover = useCallback((message, nativeEvent, layout) => {
|
86
92
|
setSelectMessage(message);
|
93
|
+
setTouchPoint({
|
94
|
+
x: nativeEvent.pageX - nativeEvent.locationX,
|
95
|
+
y: nativeEvent.pageY - nativeEvent.locationY
|
96
|
+
});
|
97
|
+
setTargetLayout(layout);
|
87
98
|
}, []);
|
88
99
|
const onLayoutItem = useMemoizedFn((message, e) => {
|
89
|
-
itemLayout.current[message.messageSeq] = e.nativeEvent.layout.height;
|
90
100
|
if (rangeList.length > 0 && message.messageSeq === (tips === null || tips === void 0 ? void 0 : tips.messageSeq)) {
|
91
101
|
const imManager = getImManager();
|
92
102
|
imManager.store.dispatch(MessagePanelActions.onRangeLayout(imManager));
|
@@ -113,13 +123,6 @@ const MessageList = ({ navigation }) => {
|
|
113
123
|
var _a;
|
114
124
|
(_a = bar.current) === null || _a === void 0 ? void 0 : _a.reset();
|
115
125
|
}, []);
|
116
|
-
const onPressPopover = useCallback((message, nativeEvent) => {
|
117
|
-
if (message.payloadType === PayloadType.PICTURE) {
|
118
|
-
setNativeEvent(nativeEvent);
|
119
|
-
setShowAlbum(true);
|
120
|
-
setTargetMessageSeq(message.messageSeq);
|
121
|
-
}
|
122
|
-
}, []);
|
123
126
|
const onKeyboardAt = () => {
|
124
127
|
if ((currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.type) === ConversationType.C2G) {
|
125
128
|
Keyboard.dismiss();
|
@@ -161,11 +164,12 @@ const MessageList = ({ navigation }) => {
|
|
161
164
|
{!isB2C && (isMultiple ? <MultipleBar /> : <MessageBar ref={bar} onKeyboardAt={onKeyboardAt}/>)}
|
162
165
|
|
163
166
|
{tips && tips.type !== TipsType.NONE && (<MessageItemTips {...tips}/>)}
|
164
|
-
<MessageOption visible={Boolean(selectMessage)}
|
167
|
+
<MessageOption visible={Boolean(selectMessage)} touchPoint={touchPoint} nativeEventLayout={targetLayout} message={selectMessage} setLoading={(value) => {
|
165
168
|
setLoading(value);
|
166
169
|
}} onClose={() => {
|
167
|
-
setNativeEvent(undefined);
|
168
170
|
setSelectMessage(undefined);
|
171
|
+
setTargetLayout(undefined);
|
172
|
+
setTouchPoint(undefined);
|
169
173
|
}}/>
|
170
174
|
|
171
175
|
<MessagePictureAlbum visible={showAlbum} messages={messages} messageSeq={targetMessageSeq} onClose={() => {
|
@@ -1,47 +1,63 @@
|
|
1
1
|
import ChatAvatar from '../../components/ChatAvatar/ChatAvatar';
|
2
2
|
import FormatTimeText from '../../components/FormatTimeText';
|
3
3
|
import { dp, NavigationPage } from '@smart-link/rn-ui';
|
4
|
-
import React, { useEffect } from 'react';
|
4
|
+
import React, { useEffect, useMemo } from 'react';
|
5
5
|
import { View, StyleSheet, FlatList, Text } from 'react-native';
|
6
6
|
import MessagePayload from './components/MessagePayload';
|
7
|
+
import { MessageListActions } from '@smart-link/im-base';
|
7
8
|
import MessagePictureAlbum from "./components/MessagePictureAlbum";
|
8
|
-
import {
|
9
|
+
import { useMessage } from "../../hooks/useImSelector";
|
10
|
+
import { getImManager } from "../../init";
|
11
|
+
import { loadVideoPlayer } from "../../slice/video/video.action";
|
9
12
|
const MessageRecord = ({ navigation, route: { params } }) => {
|
10
|
-
const {
|
13
|
+
const { messageSeq, title } = params;
|
14
|
+
const { messageListData } = useMessage();
|
11
15
|
useEffect(() => {
|
12
16
|
navigation.setOptions({
|
13
17
|
title,
|
14
18
|
});
|
19
|
+
return () => {
|
20
|
+
console.log('back');
|
21
|
+
getImManager().store.dispatch(MessageListActions.removeMessageListData());
|
22
|
+
};
|
15
23
|
}, [navigation, title]);
|
16
24
|
const listRef = React.useRef(null);
|
17
|
-
const [updateMessages, setUpdateMessages] = React.useState([]);
|
18
25
|
const [previewMessages, setPreviewMessages] = React.useState([]);
|
19
26
|
const [showAlbum, setShowAlbum] = React.useState(false);
|
20
27
|
const [targetMessageSeq, setTargetMessageSeq] = React.useState('');
|
28
|
+
const data = useMemo(() => {
|
29
|
+
var _a;
|
30
|
+
return ((_a = messageListData.find(item => item.messageSeq === messageSeq)) === null || _a === void 0 ? void 0 : _a.childMessages) || [];
|
31
|
+
}, [messageSeq, messageListData]);
|
21
32
|
useEffect(() => {
|
22
33
|
var _a;
|
23
|
-
setUpdateMessages(cloneDeep(messages));
|
24
34
|
(_a = listRef.current) === null || _a === void 0 ? void 0 : _a.scrollToOffset({ animated: false, offset: 0 });
|
25
|
-
}, [
|
35
|
+
}, [messageSeq]);
|
26
36
|
const onPress = (item) => {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
if (item.payload.quote) {
|
38
|
+
if (item.payload.quote.quoteMessage.payloadType === 'picture') {
|
39
|
+
setShowAlbum(true);
|
40
|
+
setTargetMessageSeq(item.payload.quote.quoteMessage.messageSeq);
|
41
|
+
setPreviewMessages([item.payload.quote.quoteMessage]);
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
if (item.payload.quote.quoteMessage.payloadType === 'video') {
|
45
|
+
getImManager().store.dispatch(loadVideoPlayer({
|
46
|
+
messageSeq: item.payload.quote.quoteMessage.messageSeq,
|
47
|
+
payload: item.payload.quote.quoteMessage.payload,
|
48
|
+
isRecord: true
|
49
|
+
}));
|
50
|
+
}
|
34
51
|
}
|
35
52
|
if (item.payloadType === 'picture') {
|
36
53
|
setShowAlbum(true);
|
37
54
|
setTargetMessageSeq(item.messageSeq);
|
38
|
-
setPreviewMessages(
|
55
|
+
setPreviewMessages(data);
|
39
56
|
}
|
40
57
|
};
|
41
58
|
return (<NavigationPage noPadding>
|
42
|
-
<FlatList ref={listRef} contentContainerStyle={styles.list} data={
|
43
|
-
|
44
|
-
const isSamePerson = index > 0 && updateMessages.length > 1 && updateMessages[index - 1].messageFrom === item.messageFrom;
|
59
|
+
<FlatList ref={listRef} contentContainerStyle={styles.list} data={data} renderItem={({ item, index }) => {
|
60
|
+
const isSamePerson = index > 0 && data.length > 1 && data[index - 1].messageFrom === item.messageFrom;
|
45
61
|
return (<View style={styles.messageItem}>
|
46
62
|
<View style={styles.avatar}>
|
47
63
|
{!isSamePerson && (<ChatAvatar id={item.messageFrom} url={item.payload.avatars} size={dp(40)} name={item.messageFromName}/>)}
|
@@ -53,11 +69,6 @@ const MessageRecord = ({ navigation, route: { params } }) => {
|
|
53
69
|
</View>
|
54
70
|
<MessagePayload {...item} isRecord direction="left" showArrow={false} onPress={() => {
|
55
71
|
onPress(item);
|
56
|
-
}} onLoad={(localPath) => {
|
57
|
-
console.log('localPath: ', localPath);
|
58
|
-
if (!item.payload.localPath) {
|
59
|
-
item.payload.localPath = localPath;
|
60
|
-
}
|
61
72
|
}}/>
|
62
73
|
</View>
|
63
74
|
</View>);
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { IConversation, IMessage } from '@smart-link/im-base';
|
2
2
|
import React from 'react';
|
3
3
|
import { NativeTouchEvent, LayoutChangeEvent } from 'react-native';
|
4
|
+
import { NativeEventLayout } from "../../types";
|
4
5
|
type MessageItemProps = {
|
5
6
|
isMultiple?: boolean;
|
6
7
|
multipleSelect?: Record<string, IMessage>;
|
@@ -8,7 +9,7 @@ type MessageItemProps = {
|
|
8
9
|
message: IMessage;
|
9
10
|
mine: boolean;
|
10
11
|
showTimeLine: boolean;
|
11
|
-
onLongPressPopover: (message: IMessage, nativeEvent: NativeTouchEvent) => void;
|
12
|
+
onLongPressPopover: (message: IMessage, nativeEvent: NativeTouchEvent, layout: NativeEventLayout) => void;
|
12
13
|
onPressPopover: (message: IMessage, nativeEvent: NativeTouchEvent) => void;
|
13
14
|
onLayoutItem: (item: IMessage, e: LayoutChangeEvent) => void;
|
14
15
|
};
|
@@ -33,7 +33,7 @@ const MessageItem = ({ isMultiple, multipleSelect, conversation, message, mine,
|
|
33
33
|
{isNotify && <PayloadNotify {...message}/>}
|
34
34
|
{isUndo && <MessageUndo messageSeq={message.messageSeq} text={mine ? t('youWithdrawMsg') : `"${message.messageFromName}" ${t('withdrawMsg')}`} undoText={message.payload.text} haveBackgroundImage={false} edit={mine && message.payloadType === 'text'}/>}
|
35
35
|
{isMessagePayload && (<>
|
36
|
-
{isMultiple && (<TouchableWithoutFeedback onPress={() => {
|
36
|
+
{isMultiple && message.payloadType !== 'voice' && (<TouchableWithoutFeedback onPress={() => {
|
37
37
|
getImManager().store.dispatch(MessagePanelActions.onMultipleSelect(message.messageSeq));
|
38
38
|
}}>
|
39
39
|
<View style={styles.multipleWrap}/>
|
@@ -45,7 +45,7 @@ const MessageItem = ({ isMultiple, multipleSelect, conversation, message, mine,
|
|
45
45
|
justifyContent: 'flex-start',
|
46
46
|
},
|
47
47
|
]}>
|
48
|
-
{mine && isMultiple && (<Checkbox checked={isMultipleChecked} style={[styles.multipleCheckbox]}/>)}
|
48
|
+
{mine && isMultiple && message.payloadType !== 'voice' && (<Checkbox checked={isMultipleChecked} style={[styles.multipleCheckbox]}/>)}
|
49
49
|
<ChatAvatar name={message.messageFromName} id={message.messageFrom} size={dp(40)}/>
|
50
50
|
<View style={[
|
51
51
|
{
|
@@ -58,6 +58,7 @@ const MessageItem = ({ isMultiple, multipleSelect, conversation, message, mine,
|
|
58
58
|
]}>
|
59
59
|
{!mine && message.conversationType !== ConversationType.C2C && (<Text style={[styles.name, {
|
60
60
|
marginLeft: notArrow ? 0 : dp(10),
|
61
|
+
marginBottom: dp(5),
|
61
62
|
}]}>{message.messageFromName}</Text>)}
|
62
63
|
<View>
|
63
64
|
<MessagePayload style={[
|
@@ -70,10 +71,10 @@ const MessageItem = ({ isMultiple, multipleSelect, conversation, message, mine,
|
|
70
71
|
e.stopPropagation();
|
71
72
|
e.preventDefault();
|
72
73
|
onPressPopover(message, e.nativeEvent);
|
73
|
-
}} onLongPress={e => {
|
74
|
+
}} onLongPress={(e, layout) => {
|
74
75
|
e.stopPropagation();
|
75
76
|
e.preventDefault();
|
76
|
-
onLongPressPopover(message, e.nativeEvent);
|
77
|
+
onLongPressPopover(message, e.nativeEvent, layout);
|
77
78
|
}}/>
|
78
79
|
{isC2C && mine && <MessageReceiptStatus {...message}/>}
|
79
80
|
</View>
|
@@ -82,7 +83,7 @@ const MessageItem = ({ isMultiple, multipleSelect, conversation, message, mine,
|
|
82
83
|
<Icon name="info" size={dp(20)} color={theme.errorColor}/>
|
83
84
|
</Text>)}
|
84
85
|
{mine && message.messageStatus === MessageStatus.EMITTING && (<ActivityIndicator size="small" color={'#666'} animating={true}/>)}
|
85
|
-
{!mine && isMultiple && (<Checkbox checked={isMultipleChecked} style={[styles.multipleCheckbox, styles.multipleCheckboxRight]}/>)}
|
86
|
+
{!mine && isMultiple && message.payloadType !== 'voice' && (<Checkbox checked={isMultipleChecked} style={[styles.multipleCheckbox, styles.multipleCheckboxRight]}/>)}
|
86
87
|
</View>
|
87
88
|
</>)}
|
88
89
|
{message.messageStatus === MessageStatus.EMIT_ERROR && (<>
|
@@ -1,12 +1,16 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { NativeTouchEvent } from 'react-native';
|
3
2
|
import { IMessage } from '@smart-link/im-base';
|
3
|
+
import { NativeEventLayout } from '../../../pages';
|
4
4
|
type MessageOptionProps = {
|
5
5
|
message?: IMessage;
|
6
6
|
visible: boolean;
|
7
|
-
|
7
|
+
touchPoint?: {
|
8
|
+
x: number;
|
9
|
+
y: number;
|
10
|
+
};
|
11
|
+
nativeEventLayout?: NativeEventLayout;
|
8
12
|
onClose: () => void;
|
9
13
|
setLoading: (loading: boolean) => void;
|
10
14
|
};
|
11
|
-
declare const _default: React.MemoExoticComponent<({ visible, message,
|
15
|
+
declare const _default: React.MemoExoticComponent<({ visible, message, nativeEventLayout, touchPoint, onClose, setLoading }: MessageOptionProps) => React.JSX.Element | null>;
|
12
16
|
export default _default;
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
8
8
|
});
|
9
9
|
};
|
10
10
|
import React, { memo, useRef } from 'react';
|
11
|
-
import { Animated, Text, StyleSheet, TouchableOpacity, View, TouchableWithoutFeedback, Dimensions,
|
11
|
+
import { Animated, Text, StyleSheet, TouchableOpacity, View, TouchableWithoutFeedback, Dimensions, StatusBar, Modal, } from 'react-native';
|
12
12
|
import Clipboard from '@react-native-clipboard/clipboard';
|
13
13
|
import { getMessageActionKeys, MessageActions, MessagePanelActions, MessageStatus, PayloadType, ConversationType, } from '@smart-link/im-base';
|
14
14
|
import AntDesign from 'react-native-vector-icons/AntDesign';
|
@@ -198,7 +198,7 @@ const renderOperations = (items, close) => {
|
|
198
198
|
})}
|
199
199
|
</View>);
|
200
200
|
};
|
201
|
-
const MessageOption = ({ visible, message,
|
201
|
+
const MessageOption = ({ visible, message, nativeEventLayout, touchPoint, onClose, setLoading }) => {
|
202
202
|
var _a;
|
203
203
|
const { t } = useTranslation();
|
204
204
|
const headerHeight = useHeaderHeight();
|
@@ -258,20 +258,17 @@ const MessageOption = ({ visible, message, nativeEvent, onClose, setLoading }) =
|
|
258
258
|
const { width: contentWidth, height: contentHeight } = e.nativeEvent.layout;
|
259
259
|
// 计算操作项的显示位置
|
260
260
|
// 判断点击位置是否存在
|
261
|
-
if (
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
}
|
273
|
-
showAnimation(displayArea.x + displayArea.width - contentWidth, targetY);
|
274
|
-
});
|
261
|
+
if (nativeEventLayout && touchPoint) {
|
262
|
+
const { height } = nativeEventLayout;
|
263
|
+
const { x, y } = touchPoint;
|
264
|
+
let safePageY = !isNaN(y) ? y : displayArea.y;
|
265
|
+
let targetY = safePageY + height + contentHeight > displayArea.height
|
266
|
+
? safePageY - contentHeight
|
267
|
+
: safePageY + height;
|
268
|
+
let targetX = x + contentWidth > displayArea.width
|
269
|
+
? displayArea.width - contentWidth
|
270
|
+
: x;
|
271
|
+
showAnimation(targetX, targetY);
|
275
272
|
}
|
276
273
|
else {
|
277
274
|
showAnimation(displayArea.x + displayArea.width - contentWidth, displayArea.y + displayArea.height / 2 - contentHeight / 2);
|
@@ -3,13 +3,14 @@ import { IMessage } from '@smart-link/im-base';
|
|
3
3
|
import { StyleProp } from 'react-native';
|
4
4
|
import { ViewStyle } from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
|
5
5
|
import { GestureResponderEvent } from 'react-native/Libraries/Types/CoreEventTypes';
|
6
|
+
import { NativeEventLayout } from "../../types";
|
6
7
|
export interface MessagePayloadProps extends IMessage {
|
7
8
|
style?: StyleProp<ViewStyle>;
|
8
9
|
direction?: 'left' | 'right';
|
9
10
|
showArrow?: boolean;
|
10
11
|
isRecord?: boolean;
|
11
12
|
onPress?: (e: GestureResponderEvent) => void;
|
12
|
-
onLongPress?: (e: GestureResponderEvent) => void;
|
13
|
+
onLongPress?: (e: GestureResponderEvent, layout: NativeEventLayout) => void;
|
13
14
|
onLoad?: (localPath: string) => void;
|
14
15
|
}
|
15
16
|
declare const _default: React.NamedExoticComponent<MessagePayloadProps>;
|
@@ -1,4 +1,4 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { PayloadProps } from './type';
|
3
|
-
declare const _default: React.MemoExoticComponent<({ payload, messageSeq, direction, showArrow, isRecord, messageStatus, sendSize, style, onLongPress }: PayloadProps) => React.JSX.Element>;
|
3
|
+
declare const _default: React.MemoExoticComponent<({ payload, messageSeq, direction, showArrow, isRecord, messageStatus, jobId, sendSize, style, onLongPress }: PayloadProps) => React.JSX.Element>;
|
4
4
|
export default _default;
|