@smart-link/rn-im 1.0.13 → 1.0.16
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/dist/components/ChatAvatar/ChatAvatarLocal.js +2 -1
- package/dist/pages/conversation/setting/SettingChatBg.js +4 -0
- package/dist/pages/message/MessageList.js +11 -1
- package/dist/pages/message/components/MessageItem.js +1 -1
- package/dist/pages/message/components/MessageOption.d.ts +2 -1
- package/dist/pages/message/components/MessageOption.js +6 -3
- package/dist/pages/message/components/MessagePictureAlbum.js +1 -1
- package/dist/pages/message/components/Payload/PayloadNotify.js +7 -0
- package/dist/pages/message/components/messageBar/OptionPanel.js +2 -2
- package/dist/pages/search/components/SearchPictures.js +93 -8
- package/dist/utils/file.js +4 -0
- package/package.json +2 -2
@@ -83,7 +83,8 @@ const ChatAvatarLocal = ({ fileId, size, name, defaultAvatar }) => {
|
|
83
83
|
(0, react_2.useEffect)(() => {
|
84
84
|
loadAvatar().then(_r => { });
|
85
85
|
}, [fileId]);
|
86
|
-
|
86
|
+
let hasCorrectAvatar = avatar ? avatar.indexOf("com.caih") > -1 || avatar.indexOf("http") > -1 : false;
|
87
|
+
if (ready && hasCorrectAvatar) {
|
87
88
|
return (<LocalImage_1.default localPath={avatar} style={size ? { width: size, height: size, borderRadius: size / 2 } : { width: 40, height: 40, borderRadius: 20 }}/>);
|
88
89
|
}
|
89
90
|
else if (ready) {
|
@@ -80,6 +80,10 @@ const SettingChatBg = ({ navigation }) => {
|
|
80
80
|
id: currentConversation.id,
|
81
81
|
imageBackground: fileId,
|
82
82
|
}));
|
83
|
+
yield imManager.db.updateConversationById({
|
84
|
+
id: currentConversation.id,
|
85
|
+
imageBackground: fileId,
|
86
|
+
});
|
83
87
|
// 更新本地资源存储
|
84
88
|
yield imManager.updateResource({
|
85
89
|
url: fileId,
|
@@ -55,6 +55,7 @@ const MessageList = ({ navigation }) => {
|
|
55
55
|
const [targetMessageSeq, setTargetMessageSeq] = (0, react_1.useState)('');
|
56
56
|
const [selectMessage, setSelectMessage] = (0, react_1.useState)();
|
57
57
|
const [nativeEvent, setNativeEvent] = (0, react_1.useState)();
|
58
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
58
59
|
const isB2C = (currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.type) === im_base_1.ConversationType.B2C;
|
59
60
|
(0, react_1.useEffect)(() => {
|
60
61
|
console.log('[进入会话]: ', currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.name);
|
@@ -162,7 +163,9 @@ const MessageList = ({ navigation }) => {
|
|
162
163
|
|
163
164
|
{tips && tips.type === im_base_1.TipsType.AT && (<MessageItemTips_1.default {...tips}/>)}
|
164
165
|
<VideoPlayer_1.default />
|
165
|
-
<MessageOption_1.default visible={Boolean(selectMessage)} nativeEvent={nativeEvent} message={selectMessage}
|
166
|
+
<MessageOption_1.default visible={Boolean(selectMessage)} nativeEvent={nativeEvent} message={selectMessage} setLoading={(value) => {
|
167
|
+
setLoading(value);
|
168
|
+
}} onClose={() => {
|
166
169
|
setNativeEvent(undefined);
|
167
170
|
setSelectMessage(undefined);
|
168
171
|
}}/>
|
@@ -170,6 +173,13 @@ const MessageList = ({ navigation }) => {
|
|
170
173
|
<MessagePictureAlbum_1.default visible={showAlbum} messages={messages} messageSeq={targetMessageSeq} onClose={() => {
|
171
174
|
setShowAlbum(false);
|
172
175
|
}}/>
|
176
|
+
|
177
|
+
{loading && (<react_native_1.View style={styles.loadingContainer}>
|
178
|
+
<react_native_1.ActivityIndicator size="large" color="#FFFFFF"/>
|
179
|
+
</react_native_1.View>)}
|
173
180
|
</rn_ui_1.NavigationPage>);
|
174
181
|
};
|
182
|
+
const styles = react_native_1.StyleSheet.create({
|
183
|
+
loadingContainer: Object.assign(Object.assign({}, react_native_1.StyleSheet.absoluteFillObject), { backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'center', alignItems: 'center', zIndex: 9999 }),
|
184
|
+
});
|
175
185
|
exports.default = MessageList;
|
@@ -51,7 +51,7 @@ const MessageItem = ({ isMultiple, multipleSelect, conversation, message, mine,
|
|
51
51
|
const isC2C = (conversation === null || conversation === void 0 ? void 0 : conversation.type) === im_base_1.ConversationType.C2C;
|
52
52
|
const isMultipleChecked = !!(multipleSelect === null || multipleSelect === void 0 ? void 0 : multipleSelect[message.messageSeq]);
|
53
53
|
const notArrow = [im_base_1.PayloadType.PICTURE, im_base_1.PayloadType.VIDEO].includes(message.payloadType);
|
54
|
-
const isUndo = message.messageStatus === im_base_1.MessageStatus.UNDO;
|
54
|
+
const isUndo = message.messageStatus === im_base_1.MessageStatus.UNDO || message.payloadType === im_base_1.PayloadType.CONVERSATION_MESSAGE_UNDO;
|
55
55
|
const isMessagePayload = !isB2C && !isNotify && !isUndo;
|
56
56
|
return (<react_native_1.View style={styles.root} onLayout={(e) => {
|
57
57
|
onLayoutItem(message, e);
|
@@ -6,6 +6,7 @@ type MessageOptionProps = {
|
|
6
6
|
visible: boolean;
|
7
7
|
nativeEvent?: NativeTouchEvent;
|
8
8
|
onClose: () => void;
|
9
|
+
setLoading: (loading: boolean) => void;
|
9
10
|
};
|
10
|
-
declare const _default: React.MemoExoticComponent<({ visible, message, nativeEvent, onClose }: MessageOptionProps) => React.JSX.Element | null>;
|
11
|
+
declare const _default: React.MemoExoticComponent<({ visible, message, nativeEvent, onClose, setLoading }: MessageOptionProps) => React.JSX.Element | null>;
|
11
12
|
export default _default;
|
@@ -52,7 +52,7 @@ const elements_1 = require("@react-navigation/elements");
|
|
52
52
|
const useImSelector_1 = require("../../../hooks/useImSelector");
|
53
53
|
const file_1 = require("../../../utils/file");
|
54
54
|
const ReceiptBack_1 = require("../../../pages/message/components/ReceiptBack");
|
55
|
-
const getMessageAction = (t, message, navigation) => {
|
55
|
+
const getMessageAction = (t, message, navigation, setLoading) => {
|
56
56
|
if (!message)
|
57
57
|
return [];
|
58
58
|
const actions = (0, im_base_1.getMessageActionKeys)(message.payloadType);
|
@@ -120,9 +120,12 @@ const getMessageAction = (t, message, navigation) => {
|
|
120
120
|
onPress: () => __awaiter(void 0, void 0, void 0, function* () {
|
121
121
|
(0, common_action_sheet_1.ConfirmActionSheet)(t('confirmUndoMessage'), () => __awaiter(void 0, void 0, void 0, function* () {
|
122
122
|
try {
|
123
|
+
setLoading(true);
|
123
124
|
yield (0, init_1.getImManager)().undoMessage(message);
|
125
|
+
setLoading(false);
|
124
126
|
}
|
125
127
|
catch (e) {
|
128
|
+
setLoading(false);
|
126
129
|
rn_ui_1.Toast.error(t('undoFail'));
|
127
130
|
}
|
128
131
|
}), t);
|
@@ -219,13 +222,13 @@ const renderOperations = (items, close) => {
|
|
219
222
|
})}
|
220
223
|
</react_native_1.View>);
|
221
224
|
};
|
222
|
-
const MessageOption = ({ visible, message, nativeEvent, onClose }) => {
|
225
|
+
const MessageOption = ({ visible, message, nativeEvent, onClose, setLoading }) => {
|
223
226
|
var _a;
|
224
227
|
const { t } = (0, useTranslation_1.default)();
|
225
228
|
const headerHeight = (0, elements_1.useHeaderHeight)();
|
226
229
|
const { messageBarHeight } = (0, useImSelector_1.usePanel)();
|
227
230
|
const navigation = (0, rn_ui_1.useNavigation)();
|
228
|
-
const items = getMessageAction(t, message, navigation);
|
231
|
+
const items = getMessageAction(t, message, navigation, setLoading);
|
229
232
|
const translateX = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
|
230
233
|
const translateY = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
|
231
234
|
const scale = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
|
@@ -72,7 +72,7 @@ const MessagePictureAlbum = ({ visible, onClose, messages, messageSeq }) => {
|
|
72
72
|
{visible && (<react_native_1.View style={styles.root}>
|
73
73
|
{react_native_1.Platform.OS === 'android' && <react_native_1.StatusBar backgroundColor={'#000'}/>}
|
74
74
|
<react_native_1.View style={{ width: width, height: height }}>
|
75
|
-
<rn_ui_1.AlbumView images={sources} defaultIndex={index}/>
|
75
|
+
<rn_ui_1.AlbumView images={sources} defaultIndex={index} onClose={onClose}/>
|
76
76
|
</react_native_1.View>
|
77
77
|
|
78
78
|
<react_native_1.TouchableOpacity style={styles.cancel} onPress={handleClose}>
|
@@ -48,6 +48,10 @@ const MemberRemove = ({ payload }) => {
|
|
48
48
|
const { t } = (0, useTranslation_1.default)();
|
49
49
|
return <react_native_1.Text style={styles.text}>{t('chatGroupRemoveMember', { content: payload.names.join('、') })}</react_native_1.Text>;
|
50
50
|
};
|
51
|
+
const MemberBeenRemove = ({ payload }) => {
|
52
|
+
const { t } = (0, useTranslation_1.default)();
|
53
|
+
return <react_native_1.Text style={styles.text}>{t('chatGroupBeenRemoveMember')}</react_native_1.Text>;
|
54
|
+
};
|
51
55
|
const MemberLeave = ({ payload }) => {
|
52
56
|
const { t } = (0, useTranslation_1.default)();
|
53
57
|
return <react_native_1.Text style={styles.text}>{t('chatGroupMemberLeave', { userName: payload.userName })}</react_native_1.Text>;
|
@@ -73,6 +77,9 @@ const PayloadNotify = ({ payload, payloadType }) => {
|
|
73
77
|
case im_base_1.PayloadType.GROUP_MEMBER_REMOVE_NOTICE:
|
74
78
|
content = <MemberRemove payload={payload}/>;
|
75
79
|
break;
|
80
|
+
case im_base_1.PayloadType.GROUP_MEMBER_BEEN_REMOVED:
|
81
|
+
content = <MemberBeenRemove payload={payload}/>;
|
82
|
+
break;
|
76
83
|
case im_base_1.PayloadType.GROUP_INVITE_VALIDATE_SWITCH:
|
77
84
|
content = <GroupInviteSwitch payload={payload}/>;
|
78
85
|
break;
|
@@ -123,12 +123,12 @@ const OptionPanel = (0, react_1.forwardRef)((props, ref) => {
|
|
123
123
|
const fileInfo = files[0];
|
124
124
|
console.log('chooseFile: ', fileInfo);
|
125
125
|
if (!fileInfo.uri) {
|
126
|
-
rn_ui_1.Toast.error(
|
126
|
+
rn_ui_1.Toast.error(t("failedToObtainFilePath"));
|
127
127
|
return;
|
128
128
|
}
|
129
129
|
const ext = (0, file_1.getExtensionFromMime)(fileInfo.type);
|
130
130
|
if (!ext) {
|
131
|
-
rn_ui_1.Toast.error(
|
131
|
+
rn_ui_1.Toast.error(t("unsupportedFileTypes"));
|
132
132
|
return;
|
133
133
|
}
|
134
134
|
if (!fileInfo.name.endsWith(ext)) {
|
@@ -48,15 +48,54 @@ const im_base_1 = require("@smart-link/im-base");
|
|
48
48
|
const useTranslation_1 = __importDefault(require("../../../hooks/useTranslation"));
|
49
49
|
const MessagePictureAlbum_1 = __importDefault(require("../../../pages/message/components/MessagePictureAlbum"));
|
50
50
|
const useSearchMessage_1 = require("../../../pages/search/components/useSearchMessage");
|
51
|
+
const video_action_1 = require("../../../slice/video/video.action");
|
51
52
|
const numColumns = 4;
|
52
53
|
const { width } = react_native_1.Dimensions.get('window');
|
53
54
|
const SearchPictures = ({ conversationId, multiple }) => {
|
54
|
-
|
55
|
+
// 分别获取图片和视频数据
|
56
|
+
const { data: pData, onLoadMore: onLoadMorePictures, reload: reloadPictures, } = (0, useSearchMessage_1.useSearchMessage)({
|
55
57
|
keyword: '',
|
56
58
|
conversationId,
|
57
59
|
payloadType: 'picture',
|
58
60
|
normalData: false,
|
59
61
|
});
|
62
|
+
const { data: vData, onLoadMore: onLoadMoreVideos, reload: reloadVideos, } = (0, useSearchMessage_1.useSearchMessage)({
|
63
|
+
keyword: '',
|
64
|
+
conversationId,
|
65
|
+
payloadType: 'video',
|
66
|
+
normalData: false,
|
67
|
+
});
|
68
|
+
// 合并数据并按时间排序(最新在前)
|
69
|
+
const data = [...pData, ...vData].sort((a, b) => {
|
70
|
+
return new Date(b.messageTime).getTime() - new Date(a.messageTime).getTime();
|
71
|
+
});
|
72
|
+
// 正确合并加载更多功能
|
73
|
+
const onLoadMore = () => __awaiter(void 0, void 0, void 0, function* () {
|
74
|
+
try {
|
75
|
+
yield Promise.all([
|
76
|
+
onLoadMorePictures(),
|
77
|
+
onLoadMoreVideos()
|
78
|
+
]);
|
79
|
+
}
|
80
|
+
catch (error) {
|
81
|
+
console.error('加载更多失败:', error);
|
82
|
+
// 可以添加错误处理逻辑
|
83
|
+
}
|
84
|
+
});
|
85
|
+
// 正确合并刷新功能
|
86
|
+
const reload = () => __awaiter(void 0, void 0, void 0, function* () {
|
87
|
+
try {
|
88
|
+
yield Promise.all([
|
89
|
+
reloadPictures(),
|
90
|
+
reloadVideos()
|
91
|
+
]);
|
92
|
+
}
|
93
|
+
catch (error) {
|
94
|
+
console.error('刷新失败:', error);
|
95
|
+
// 可以添加错误处理逻辑
|
96
|
+
}
|
97
|
+
});
|
98
|
+
// ...其他代码保持不变
|
60
99
|
const [checkedIds, setCheckedIds] = (0, react_1.useState)([]);
|
61
100
|
const navigation = (0, rn_ui_1.useNavigation)();
|
62
101
|
const { t } = (0, useTranslation_1.default)();
|
@@ -166,15 +205,38 @@ const SearchPictures = ({ conversationId, multiple }) => {
|
|
166
205
|
});
|
167
206
|
}
|
168
207
|
else {
|
169
|
-
//
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
208
|
+
// 根据类型处理预览
|
209
|
+
if (message.payloadType === im_base_1.PayloadType.PICTURE) {
|
210
|
+
// 预览图片
|
211
|
+
setPreview({
|
212
|
+
visible: true,
|
213
|
+
messages: [message],
|
214
|
+
messageSeq: message.messageSeq
|
215
|
+
});
|
216
|
+
}
|
217
|
+
else if (message.payloadType === im_base_1.PayloadType.VIDEO) {
|
218
|
+
// 播放视频
|
219
|
+
(0, init_1.getImManager)().store.dispatch((0, video_action_1.loadVideoPlayer)({
|
220
|
+
messageSeq: message.messageSeq,
|
221
|
+
payload: message.payload
|
222
|
+
}));
|
223
|
+
}
|
175
224
|
}
|
176
225
|
}}>
|
177
|
-
|
226
|
+
{/* 媒体内容容器 */}
|
227
|
+
<react_native_1.View style={styles.mediaContainer}>
|
228
|
+
{message.payloadType === im_base_1.PayloadType.PICTURE ? (
|
229
|
+
// 图片展示
|
230
|
+
<CachedImage_1.default style={styles.img} localPath={message.payload.localPath} fileId={message.payload.fileId}/>) : (
|
231
|
+
// 视频展示
|
232
|
+
<>
|
233
|
+
<CachedImage_1.default style={styles.img} localPath={message.payload.localPath} fileId={message.payload.fileId}/>
|
234
|
+
{/* 视频播放图标 */}
|
235
|
+
<react_native_1.View style={styles.playIcon}>
|
236
|
+
<react_native_1.Text style={styles.playIconText}>▶</react_native_1.Text>
|
237
|
+
</react_native_1.View>
|
238
|
+
</>)}
|
239
|
+
</react_native_1.View>
|
178
240
|
</react_native_1.TouchableOpacity>
|
179
241
|
<react_native_1.View style={styles.checkbox}>
|
180
242
|
{multiple && (<rn_ui_1.Checkbox style={{ pointerEvents: 'none' }} checked={checkedIds.includes(message.messageSeq)} size='s'/>)}
|
@@ -216,5 +278,28 @@ const styles = react_native_1.StyleSheet.create({
|
|
216
278
|
top: 0,
|
217
279
|
right: 0,
|
218
280
|
},
|
281
|
+
mediaContainer: {
|
282
|
+
position: 'relative',
|
283
|
+
width: '100%',
|
284
|
+
height: '100%',
|
285
|
+
},
|
286
|
+
playIcon: {
|
287
|
+
position: 'absolute',
|
288
|
+
top: '50%',
|
289
|
+
left: '50%',
|
290
|
+
transform: [{ translateX: -15 }, { translateY: -15 }],
|
291
|
+
width: 30,
|
292
|
+
height: 30,
|
293
|
+
borderRadius: 15,
|
294
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
295
|
+
justifyContent: 'center',
|
296
|
+
alignItems: 'center',
|
297
|
+
},
|
298
|
+
playIconText: {
|
299
|
+
color: 'white',
|
300
|
+
fontSize: 16,
|
301
|
+
fontWeight: 'bold',
|
302
|
+
marginLeft: 2, // 让播放图标稍微右移,看起来更居中
|
303
|
+
},
|
219
304
|
});
|
220
305
|
exports.default = exports.SearchPictures;
|
package/dist/utils/file.js
CHANGED
@@ -248,6 +248,10 @@ const extensions = {
|
|
248
248
|
'application/x-tar': '.tar',
|
249
249
|
'application/x-7z-compressed': '.7z',
|
250
250
|
'application/x-rar-compressed': '.rar',
|
251
|
+
// 安卓包
|
252
|
+
'application/octet-stream': '.apk',
|
253
|
+
'application/vnd.android.package-archive': '.apk',
|
254
|
+
'application/x-apk': '.apk',
|
251
255
|
};
|
252
256
|
function getExtensionFromMime(mime) {
|
253
257
|
return extensions[mime] || '';
|
package/package.json
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
{
|
2
2
|
"name": "@smart-link/rn-im",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.16",
|
4
4
|
"description": "",
|
5
5
|
"main": "./dist/index.js",
|
6
6
|
"dependencies": {
|
7
7
|
"color": "^5.0.0",
|
8
8
|
"lodash-es": "^4.17.21",
|
9
9
|
"emoji-regex": "^10.4.0",
|
10
|
-
"@smart-link/im-base": "^1.0.
|
10
|
+
"@smart-link/im-base": "^1.0.16"
|
11
11
|
},
|
12
12
|
"devDependencies": {
|
13
13
|
"@react-native/eslint-config": "0.73.2",
|