@smart-link/rn-im 1.1.2 → 1.1.3
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/Camera/Camera.js +1 -2
- package/dist/components/Camera/CameraCapture.js +7 -2
- package/dist/components/ChatAvatar/ChatAvatarLocal.js +4 -0
- package/dist/components/Highlighter.d.ts +2 -1
- package/dist/components/Highlighter.js +2 -2
- package/dist/components/LocalImage.js +1 -0
- package/dist/pages/conversation/{List.d.ts → ConversationList.d.ts} +2 -2
- package/dist/pages/conversation/{List.js → ConversationList.js} +23 -4
- package/dist/pages/conversation/conversation.routes.js +2 -2
- package/dist/pages/message/FileSelector.js +3 -3
- package/dist/pages/message/MessageList.js +2 -2
- package/dist/pages/message/components/MessagePayload.js +4 -3
- package/dist/pages/message/components/Payload/PayloadText.js +1 -1
- package/dist/pages/message/components/Payload/PayloadWrapper.d.ts +1 -0
- package/dist/pages/message/components/Payload/PayloadWrapper.js +4 -1
- package/dist/pages/search/components/SearchUser.js +7 -2
- package/dist/utils/file.d.ts +2 -0
- package/dist/utils/file.js +12 -2
- package/dist/utils/request.d.ts +2 -1
- package/dist/utils/request.js +4 -1
- package/dist/utils/upload.js +37 -7
- package/package.json +4 -1
|
@@ -44,8 +44,7 @@ const Camera = memo(props => {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
|
-
return (<Modal animationType="slide"
|
|
48
|
-
}}>
|
|
47
|
+
return (<Modal animationType="slide" visible={true} transparent statusBarTranslucent onRequestClose={cancelCamera}>
|
|
49
48
|
{Platform.OS === 'android' &&
|
|
50
49
|
<StatusBar backgroundColor={'#000'}/>}
|
|
51
50
|
{resultSource &&
|
|
@@ -33,7 +33,12 @@ const CameraCapture = memo(props => {
|
|
|
33
33
|
const microphone = useMicrophonePermission();
|
|
34
34
|
const device = useCameraDevice(CameraTypeValue[cameraTypeIndex]);
|
|
35
35
|
const format = useCameraFormat(device, [
|
|
36
|
-
{
|
|
36
|
+
{
|
|
37
|
+
videoAspectRatio: SCREEN_HEIGHT / SCREEN_WIDTH,
|
|
38
|
+
fps: 30,
|
|
39
|
+
photoResolution: 'max',
|
|
40
|
+
videoHdr: false
|
|
41
|
+
},
|
|
37
42
|
{
|
|
38
43
|
photoAspectRatio: SCREEN_HEIGHT / SCREEN_WIDTH,
|
|
39
44
|
photoResolution: 'max',
|
|
@@ -148,7 +153,7 @@ const CameraCapture = memo(props => {
|
|
|
148
153
|
};
|
|
149
154
|
}, []);
|
|
150
155
|
return (<View style={styles.camera}>
|
|
151
|
-
{device ? (<Camera ref={camera} device={device} format={format} isActive={true} style={styles.preview} photo={true} video={true} audio={microphone.hasPermission} outputOrientation="portrait" onInitialized={() => {
|
|
156
|
+
{device ? (<Camera ref={camera} device={device} format={format} isActive={true} style={styles.preview} photo={true} video={true} pixelFormat={'yuv'} audio={microphone.hasPermission} outputOrientation="portrait" onInitialized={() => {
|
|
152
157
|
console.log('Camera initialized!');
|
|
153
158
|
}} onError={error => {
|
|
154
159
|
console.log(error);
|
|
@@ -99,6 +99,10 @@ const ChatAvatarLocal = ({ fileId, size, name, defaultAvatar }) => {
|
|
|
99
99
|
return (<LocalImage localPath={avatar} style={size ? { width: size, height: size, borderRadius: size / 2 } : { width: 40, height: 40, borderRadius: 20 }}/>);
|
|
100
100
|
}
|
|
101
101
|
else {
|
|
102
|
+
// console.log(
|
|
103
|
+
// '[ChatAvatarLocal] defaultAvatar:',
|
|
104
|
+
// defaultAvatar
|
|
105
|
+
// );
|
|
102
106
|
return (<Avatar icon={<Image style={{ width: size, height: size }} source={defaultAvatar}/>} style={size ? { width: size, height: size } : {}}>
|
|
103
107
|
{name === null || name === void 0 ? void 0 : name[0]}
|
|
104
108
|
</Avatar>);
|
|
@@ -4,6 +4,7 @@ type HighlighterProps = {
|
|
|
4
4
|
style?: TextStyle;
|
|
5
5
|
searchWord: string;
|
|
6
6
|
textToHighlight: string;
|
|
7
|
+
numberOfLines?: number;
|
|
7
8
|
};
|
|
8
|
-
declare const _default: React.MemoExoticComponent<({ style, searchWord, textToHighlight }: HighlighterProps) => React.JSX.Element>;
|
|
9
|
+
declare const _default: React.MemoExoticComponent<({ style, searchWord, textToHighlight, numberOfLines }: HighlighterProps) => React.JSX.Element>;
|
|
9
10
|
export default _default;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useTheme } from '@smart-link/rn-ui';
|
|
2
2
|
import React, { memo } from 'react';
|
|
3
3
|
import { Text } from 'react-native';
|
|
4
|
-
const Highlighter = ({ style, searchWord, textToHighlight }) => {
|
|
4
|
+
const Highlighter = ({ style, searchWord, textToHighlight, numberOfLines }) => {
|
|
5
5
|
const theme = useTheme();
|
|
6
6
|
// 高亮显示搜索关键字
|
|
7
|
-
return (<Text style={style}>
|
|
7
|
+
return (<Text style={style} numberOfLines={numberOfLines}>
|
|
8
8
|
{textToHighlight.split(new RegExp(`(${searchWord})`, 'gi')).map((part, index) => {
|
|
9
9
|
return part.toLowerCase() === searchWord.toLowerCase() ? (<Text key={index} style={{
|
|
10
10
|
color: theme.primaryColor,
|
|
@@ -7,6 +7,7 @@ const LocalImage = memo(props => {
|
|
|
7
7
|
if (Object.prototype.toString.call(localPath) === '[object String]') {
|
|
8
8
|
source = { uri: toAbsolutePath(localPath) };
|
|
9
9
|
}
|
|
10
|
+
// console.log('LocalImage: ', source);
|
|
10
11
|
return <Image style={style} resizeMode={resizeMode} source={source} onError={(e) => {
|
|
11
12
|
console.log('local image error: ', localPath);
|
|
12
13
|
}}/>;
|
|
@@ -2,5 +2,5 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack/lib/types
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { IMPageParamList } from '../../pages';
|
|
4
4
|
type ConversationListProps = NativeStackScreenProps<IMPageParamList, 'ConversationList'>;
|
|
5
|
-
declare const
|
|
6
|
-
export default
|
|
5
|
+
declare const ConversationList: ({ navigation }: ConversationListProps) => React.JSX.Element;
|
|
6
|
+
export default ConversationList;
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { ConnectStatus, ConversationActions } from '@smart-link/im-base';
|
|
11
11
|
import { CaihIcon, dp, Popover, SearchBar } from '@smart-link/rn-ui';
|
|
12
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
12
|
+
import React, { memo, useEffect, useRef, useState } from 'react';
|
|
13
13
|
import { StyleSheet, View, FlatList, TouchableOpacity, Vibration, DevSettings, } from 'react-native';
|
|
14
14
|
import IndicatorText from '../../components/IndicatorText';
|
|
15
15
|
import NetworkUnconnected from '../../components/NetworkUnconnected';
|
|
@@ -20,7 +20,13 @@ import ConversationCard from './components/ConversationCard';
|
|
|
20
20
|
import ConversationOption from './components/ConversationOption';
|
|
21
21
|
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
|
22
22
|
import { startCreateGroup } from '../../slice/contact/contact.slice';
|
|
23
|
-
|
|
23
|
+
import AntDesign from "react-native-vector-icons/AntDesign";
|
|
24
|
+
const BackButton = memo(({ onBack }) => {
|
|
25
|
+
return (<TouchableOpacity style={styles.backButton} onPress={onBack}>
|
|
26
|
+
<AntDesign name='up' size={dp(20)} color={'#999'}/>
|
|
27
|
+
</TouchableOpacity>);
|
|
28
|
+
});
|
|
29
|
+
const ConversationList = ({ navigation }) => {
|
|
24
30
|
const { t } = useTranslation();
|
|
25
31
|
const { connectStatus, conversations } = useConversation();
|
|
26
32
|
const [nativeEvent, setNativeEvent] = useState();
|
|
@@ -29,6 +35,7 @@ const List = ({ navigation }) => {
|
|
|
29
35
|
const lastPressTime = useRef(0);
|
|
30
36
|
const lastIndex = useRef(0);
|
|
31
37
|
const flatListRef = useRef(null);
|
|
38
|
+
const [scrollY, setScrollY] = useState(0);
|
|
32
39
|
useEffect(() => {
|
|
33
40
|
let headerTitle = t('message');
|
|
34
41
|
switch (connectStatus) {
|
|
@@ -173,11 +180,23 @@ const List = ({ navigation }) => {
|
|
|
173
180
|
index,
|
|
174
181
|
});
|
|
175
182
|
return (<View style={{ flex: 1 }}>
|
|
176
|
-
<FlatList ref={flatListRef} contentContainerStyle={styles.contentContainerStyle} keyboardShouldPersistTaps={'handled'} data={conversations} ListHeaderComponent={listHeaderComponent} ListFooterComponent={listFooterComponent} ItemSeparatorComponent={itemSeparatorComponent} getItemLayout={getItemLayout} renderItem={renderItem} numColumns={1} keyExtractor={keyExtractor}
|
|
183
|
+
<FlatList ref={flatListRef} contentContainerStyle={styles.contentContainerStyle} keyboardShouldPersistTaps={'handled'} data={conversations} ListHeaderComponent={listHeaderComponent} ListFooterComponent={listFooterComponent} ItemSeparatorComponent={itemSeparatorComponent} getItemLayout={getItemLayout} renderItem={renderItem} numColumns={1} keyExtractor={keyExtractor} onScroll={(e) => {
|
|
184
|
+
setScrollY(e.nativeEvent.contentOffset.y);
|
|
185
|
+
}}/>
|
|
177
186
|
<ConversationOption conversation={conversation} nativeEvent={nativeEvent} visible={popoverVisible} onClose={() => {
|
|
178
187
|
setPopoverVisible(false);
|
|
179
188
|
setConversation(undefined);
|
|
180
189
|
}}/>
|
|
190
|
+
|
|
191
|
+
{scrollY > dp(50) && (<BackButton onBack={() => {
|
|
192
|
+
var _a;
|
|
193
|
+
(_a = flatListRef.current) === null || _a === void 0 ? void 0 : _a.scrollToOffset({
|
|
194
|
+
offset: 0,
|
|
195
|
+
animated: true,
|
|
196
|
+
});
|
|
197
|
+
}}/>)}
|
|
198
|
+
|
|
199
|
+
|
|
181
200
|
</View>);
|
|
182
201
|
};
|
|
183
202
|
const styles = StyleSheet.create({
|
|
@@ -213,4 +232,4 @@ const styles = StyleSheet.create({
|
|
|
213
232
|
right: dp(15),
|
|
214
233
|
},
|
|
215
234
|
});
|
|
216
|
-
export default
|
|
235
|
+
export default ConversationList;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ConversationList from './ConversationList';
|
|
2
2
|
import Setting from './setting/Setting';
|
|
3
3
|
import SettingChatBg from './setting/SettingChatBg';
|
|
4
4
|
import ForwardToConversation from './ForwardToConversation';
|
|
@@ -9,7 +9,7 @@ import OptionGroupMoreMember from "./setting/OptionGroupMoreMember";
|
|
|
9
9
|
export const conversationRoutes = [
|
|
10
10
|
{
|
|
11
11
|
name: 'ConversationList',
|
|
12
|
-
component:
|
|
12
|
+
component: ConversationList,
|
|
13
13
|
options: {
|
|
14
14
|
title: '',
|
|
15
15
|
}
|
|
@@ -70,10 +70,10 @@ const FileSelector = ({ navigation }) => {
|
|
|
70
70
|
};
|
|
71
71
|
navigation.goBack();
|
|
72
72
|
if (isImage(file.localPath)) {
|
|
73
|
-
imManager.sendPictureMessage(currentConversation, file);
|
|
73
|
+
imManager.sendPictureMessage(Object.assign({}, currentConversation), file);
|
|
74
74
|
}
|
|
75
75
|
else {
|
|
76
|
-
imManager.sendFileMessage(currentConversation, file);
|
|
76
|
+
imManager.sendFileMessage(Object.assign({}, currentConversation), file);
|
|
77
77
|
}
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
@@ -99,7 +99,7 @@ const FileSelector = ({ navigation }) => {
|
|
|
99
99
|
// ios 中文名称编码了,需要解码
|
|
100
100
|
fileInfo.uri = decodeURI(fileInfo.uri);
|
|
101
101
|
const localPath = yield copyFile(fileInfo.uri, fileInfo.name, 'file');
|
|
102
|
-
imManager.sendFileMessage(currentConversation, {
|
|
102
|
+
imManager.sendFileMessage(Object.assign({}, currentConversation), {
|
|
103
103
|
localPath: localPath,
|
|
104
104
|
filename: fileInfo.name,
|
|
105
105
|
size: fileInfo.size,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConversationType, MessageActions, MessagePanelActions, PayloadType, TipsType, showTimeLine, } from '@smart-link/im-base';
|
|
2
2
|
import { dp, HeaderBackButton, Input, NavigationPage } from '@smart-link/rn-ui';
|
|
3
3
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
-
import { View, Text, FlatList, TouchableOpacity, Keyboard,
|
|
4
|
+
import { View, Text, FlatList, TouchableOpacity, Keyboard, StyleSheet, ActivityIndicator, TouchableWithoutFeedback } from 'react-native';
|
|
5
5
|
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
|
6
6
|
import { useAuth, useConversation, useMessage } from '../../hooks/useImSelector';
|
|
7
7
|
import useTranslation from '../../hooks/useTranslation';
|
|
@@ -71,7 +71,7 @@ const MessageList = ({ navigation }) => {
|
|
|
71
71
|
imManager.store.dispatch(MessagePanelActions.cancelMultipleSelect());
|
|
72
72
|
}
|
|
73
73
|
else {
|
|
74
|
-
|
|
74
|
+
requestIdleCallback(() => {
|
|
75
75
|
imManager.store.dispatch(MessagePanelActions.saveDraftText(imManager));
|
|
76
76
|
imManager.leaveConversation();
|
|
77
77
|
imManager.store.dispatch(MessageActions.resetState());
|
|
@@ -24,12 +24,13 @@ import PayloadMultiple from './Payload/PayloadMultiple';
|
|
|
24
24
|
import PayloadWrapper from './Payload/PayloadWrapper';
|
|
25
25
|
import PayloadShare from "../../../pages/message/components/Payload/PayloadShare";
|
|
26
26
|
const MessagePayload = props => {
|
|
27
|
-
const { style: outStyle } = props, retProps = __rest(props, ["style"]);
|
|
27
|
+
const { style: outStyle, isRecord } = props, retProps = __rest(props, ["style", "isRecord"]);
|
|
28
28
|
const { t } = useTranslation();
|
|
29
29
|
const payloadType = props.payloadType;
|
|
30
30
|
const noStylePayloadType = [PayloadType.PICTURE, PayloadType.VIDEO];
|
|
31
31
|
const style = !noStylePayloadType.includes(payloadType) ? outStyle : [];
|
|
32
|
-
const mergeProps = Object.assign(Object.assign({}, retProps), {
|
|
32
|
+
const mergeProps = Object.assign(Object.assign({}, retProps), { isRecord,
|
|
33
|
+
style });
|
|
33
34
|
let content;
|
|
34
35
|
switch (payloadType) {
|
|
35
36
|
case PayloadType.TEXT:
|
|
@@ -58,7 +59,7 @@ const MessagePayload = props => {
|
|
|
58
59
|
break;
|
|
59
60
|
default:
|
|
60
61
|
console.log('暂不支持的消息类型:', payloadType);
|
|
61
|
-
content = (<PayloadWrapper style={style} direction={mergeProps.direction}>
|
|
62
|
+
content = (<PayloadWrapper style={style} direction={mergeProps.direction} isRecord={isRecord}>
|
|
62
63
|
<Text style={plain}>[{t('msgTypeNotSupported')}]</Text>
|
|
63
64
|
</PayloadWrapper>);
|
|
64
65
|
break;
|
|
@@ -84,7 +84,7 @@ const PayloadText = ({ payload, onLongPress, onPress, isRecord, showArrow = true
|
|
|
84
84
|
const imManager = getImManager();
|
|
85
85
|
imManager.store.dispatch(MessagePanelActions.onPressQuote(imManager, quoteMessageSeq));
|
|
86
86
|
};
|
|
87
|
-
return (<PayloadWrapper direction={direction} showArrow={showArrow} onLongPress={onLongPress} style={[style, plain]}>
|
|
87
|
+
return (<PayloadWrapper isRecord={isRecord} direction={direction} showArrow={showArrow} onLongPress={onLongPress} style={[style, plain]}>
|
|
88
88
|
<TextMixQuoteMessage text={text} quote={quote} textStyle={[styles.text]} quoteStyle={styles.quote} quoteBgColor='#fff' onLongPressPhone={onLongPressPhone} onLongPressURL={onLongPressURL} onPressQuote={onPressQuote} atList={atList}/>
|
|
89
89
|
</PayloadWrapper>);
|
|
90
90
|
};
|
|
@@ -29,13 +29,16 @@ const SvgFromUri = ({ direction, focus }) => {
|
|
|
29
29
|
</Svg>);
|
|
30
30
|
};
|
|
31
31
|
const PayloadWrapper = memo((_a) => {
|
|
32
|
-
var { children, direction, showArrow, onLongPress, style } = _a, retProps = __rest(_a, ["children", "direction", "showArrow", "onLongPress", "style"]);
|
|
32
|
+
var { children, direction, isRecord, showArrow, onLongPress, style } = _a, retProps = __rest(_a, ["children", "direction", "isRecord", "showArrow", "onLongPress", "style"]);
|
|
33
33
|
const [layout, setLayout] = useState();
|
|
34
34
|
const [focus, setFocus] = useState(false);
|
|
35
35
|
let backgroundColor = direction === 'right' ? '#cde6f9' : '#fff';
|
|
36
36
|
if (focus) {
|
|
37
37
|
backgroundColor = Color(backgroundColor).darken(0.08).hex();
|
|
38
38
|
}
|
|
39
|
+
if (isRecord) {
|
|
40
|
+
backgroundColor = 'transparent';
|
|
41
|
+
}
|
|
39
42
|
return (<TouchableOpacity {...retProps} style={[
|
|
40
43
|
style,
|
|
41
44
|
{
|
|
@@ -16,9 +16,14 @@ import Highlighter from '../../../components/Highlighter';
|
|
|
16
16
|
import useTranslation from '../../../hooks/useTranslation';
|
|
17
17
|
import { getImManager } from '../../../init';
|
|
18
18
|
const RenderUserItem = (props) => {
|
|
19
|
+
const { keyword, data } = props;
|
|
19
20
|
return (<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
20
|
-
<ChatAvatar needUpdate id={
|
|
21
|
-
<
|
|
21
|
+
<ChatAvatar needUpdate id={data.userId} url={data.avatars} name={data.userName}/>
|
|
22
|
+
<View style={{ marginLeft: dp(10), flex: 1 }}>
|
|
23
|
+
<Highlighter searchWord={keyword} textToHighlight={data.userName} numberOfLines={1}/>
|
|
24
|
+
<Text numberOfLines={1} style={{ fontSize: dp(12), color: '#999' }}>{data.groupNamePaths}</Text>
|
|
25
|
+
</View>
|
|
26
|
+
|
|
22
27
|
</View>);
|
|
23
28
|
};
|
|
24
29
|
const SearchUser = ({ keyword }) => {
|
package/dist/utils/file.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ declare const resourceDirBase: {
|
|
|
7
7
|
readonly video: "/video";
|
|
8
8
|
readonly file: "/file";
|
|
9
9
|
readonly background: "/background";
|
|
10
|
+
readonly cache: "/cache";
|
|
10
11
|
};
|
|
11
12
|
type ResourceDir = keyof typeof resourceDirBase;
|
|
12
13
|
export declare function initDir(user: IUser): Promise<void>;
|
|
@@ -39,4 +40,5 @@ export declare function getSafeFilename(filename: string): string;
|
|
|
39
40
|
*/
|
|
40
41
|
export declare function truncateFilenameMiddle(filename: string, maxLength?: number): string;
|
|
41
42
|
export declare function getFileSize(filePath: string): Promise<number>;
|
|
43
|
+
export declare function sliceFile(filePath: string, start: number, end: number): Promise<string>;
|
|
42
44
|
export {};
|
package/dist/utils/file.js
CHANGED
|
@@ -19,6 +19,7 @@ const resourceDirBase = {
|
|
|
19
19
|
video: '/video',
|
|
20
20
|
file: '/file',
|
|
21
21
|
background: '/background',
|
|
22
|
+
cache: '/cache',
|
|
22
23
|
};
|
|
23
24
|
const resourceDir = {};
|
|
24
25
|
let userPath = '';
|
|
@@ -112,7 +113,7 @@ export const download = ({ fileId, resourceType, filename, onProgress, onStart }
|
|
|
112
113
|
progressDivider: 5,
|
|
113
114
|
begin: (e) => {
|
|
114
115
|
// 这个方法不能注释,否则 ios 不响应进度
|
|
115
|
-
|
|
116
|
+
console.log('download begin: ', e.jobId);
|
|
116
117
|
},
|
|
117
118
|
progress: (e) => {
|
|
118
119
|
// console.log('download progress: ', e);
|
|
@@ -127,7 +128,7 @@ export const download = ({ fileId, resourceType, filename, onProgress, onStart }
|
|
|
127
128
|
return relativePath;
|
|
128
129
|
}
|
|
129
130
|
catch (error) {
|
|
130
|
-
console.
|
|
131
|
+
console.warn('下载失败:', error);
|
|
131
132
|
throw error;
|
|
132
133
|
}
|
|
133
134
|
});
|
|
@@ -412,3 +413,12 @@ export function getFileSize(filePath) {
|
|
|
412
413
|
return stat.size;
|
|
413
414
|
});
|
|
414
415
|
}
|
|
416
|
+
export function sliceFile(filePath, start, end) {
|
|
417
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
418
|
+
// const destPath = `${userPath}/cache/${uuidv4()}.tmp`;
|
|
419
|
+
// 分片读取文件写入缓存文件
|
|
420
|
+
const base64 = yield RNFS.read(toAbsolutePath(filePath), end - start, start, 'base64');
|
|
421
|
+
// await RNFS.writeFile(destPath, base64, 'base64');
|
|
422
|
+
return base64;
|
|
423
|
+
});
|
|
424
|
+
}
|
package/dist/utils/request.d.ts
CHANGED
|
@@ -29,7 +29,8 @@ interface IRequest {
|
|
|
29
29
|
postForm<R, Q = any>(url: string, data?: Q, config?: AxiosRequestConfig): Promise<IResponse<R>>;
|
|
30
30
|
postFile<R, Q = any>(url: string, data?: Q, config?: AxiosRequestConfig): Promise<IResponse<R>>;
|
|
31
31
|
}
|
|
32
|
+
export declare const getStorage: () => Storage;
|
|
32
33
|
export declare const getBaseURL: () => string;
|
|
33
|
-
export declare const createRequest: (base: string,
|
|
34
|
+
export declare const createRequest: (base: string, _storage: Storage) => AxiosInstance;
|
|
34
35
|
declare const request: IRequest;
|
|
35
36
|
export default request;
|
package/dist/utils/request.js
CHANGED
|
@@ -21,9 +21,12 @@ export const Headers = {
|
|
|
21
21
|
};
|
|
22
22
|
let instance = null;
|
|
23
23
|
let baseURL = '';
|
|
24
|
+
let storage;
|
|
25
|
+
export const getStorage = () => storage;
|
|
24
26
|
export const getBaseURL = () => baseURL;
|
|
25
|
-
export const createRequest = (base,
|
|
27
|
+
export const createRequest = (base, _storage) => {
|
|
26
28
|
baseURL = base;
|
|
29
|
+
storage = _storage;
|
|
27
30
|
instance = axios.create({
|
|
28
31
|
baseURL: base,
|
|
29
32
|
timeout: 10000,
|
package/dist/utils/upload.js
CHANGED
|
@@ -7,18 +7,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import request, { getBaseURL } from './request';
|
|
11
|
-
import { toAbsolutePath } from './file';
|
|
10
|
+
import request, { getBaseURL, getStorage } from './request';
|
|
11
|
+
import { toAbsolutePath, toFullPath } from './file';
|
|
12
|
+
import { uploadFile as chunkUpload } from '@smart-link/chunk-upload';
|
|
13
|
+
const CHUNK_SIZE = 1024 * 1024 * 2;
|
|
12
14
|
const uploadFile = (filePath, type, onProgress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
+
const uploadUrl = `/api-file/file/uploadFile`;
|
|
16
|
+
const local = yield fetch(toAbsolutePath(filePath));
|
|
17
|
+
const file = yield local.blob();
|
|
18
|
+
const fileName = filePath.split('/').pop();
|
|
19
|
+
//
|
|
20
|
+
if (file.size > CHUNK_SIZE) {
|
|
21
|
+
return uploadBigFile(toFullPath(filePath), fileName, onProgress);
|
|
22
|
+
}
|
|
15
23
|
const formData = new FormData();
|
|
16
|
-
// @ts-ignore
|
|
17
24
|
formData.append('file', {
|
|
18
25
|
// @ts-ignore
|
|
19
26
|
uri: toAbsolutePath(filePath),
|
|
20
|
-
name:
|
|
21
|
-
type
|
|
27
|
+
name: fileName,
|
|
28
|
+
type,
|
|
22
29
|
});
|
|
23
30
|
const resp = yield request.postFile(uploadUrl, formData, {
|
|
24
31
|
onUploadProgress: onProgress,
|
|
@@ -26,4 +33,27 @@ const uploadFile = (filePath, type, onProgress) => __awaiter(void 0, void 0, voi
|
|
|
26
33
|
console.log('uploadFile: ', resp);
|
|
27
34
|
return resp.data;
|
|
28
35
|
});
|
|
36
|
+
const uploadBigFile = (filePath, fileName, onProgress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
const uploadBigFileURL = `/api-file/file/uploadBigFile`;
|
|
38
|
+
const cookie = yield getStorage().getItem('cookies');
|
|
39
|
+
const resp = yield chunkUpload({
|
|
40
|
+
filePath,
|
|
41
|
+
fileName,
|
|
42
|
+
chunkSize: CHUNK_SIZE,
|
|
43
|
+
uploadUrl: getBaseURL() + uploadBigFileURL,
|
|
44
|
+
headers: {
|
|
45
|
+
'Cookie': cookie,
|
|
46
|
+
},
|
|
47
|
+
onProgress: (o) => {
|
|
48
|
+
console.log('uploadBigFile: ', o);
|
|
49
|
+
onProgress && onProgress({
|
|
50
|
+
loaded: o.loaded,
|
|
51
|
+
total: o.total,
|
|
52
|
+
lengthComputable: true,
|
|
53
|
+
bytes: o.loaded,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
return resp.data;
|
|
58
|
+
});
|
|
29
59
|
export default uploadFile;
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smart-link/rn-im",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "./dist/index.js",
|
|
7
|
+
"module": "./src/index.ts",
|
|
6
8
|
"dependencies": {
|
|
7
9
|
"color": "^5.0.0",
|
|
8
10
|
"lodash-es": "^4.17.21",
|
|
@@ -34,6 +36,7 @@
|
|
|
34
36
|
"@react-navigation/native": "6.1.7",
|
|
35
37
|
"@react-navigation/native-stack": "6.9.13",
|
|
36
38
|
"@reduxjs/toolkit": "^1.5.0",
|
|
39
|
+
"@smart-link/chunk-upload": "^1.0.0",
|
|
37
40
|
"ahooks": "^3.8.0",
|
|
38
41
|
"axios": "^0.30.0",
|
|
39
42
|
"dayjs": "^1.11.9",
|