@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
@@ -11,26 +11,27 @@ import { dp, Toast } from '@smart-link/rn-ui';
|
|
11
11
|
import FileViewer from 'react-native-file-viewer';
|
12
12
|
import React, { memo, useRef, useState } from 'react';
|
13
13
|
import { View, Text, StyleSheet, Dimensions, } from 'react-native';
|
14
|
-
import { numberToFileSize } from '../../../../utils/file';
|
14
|
+
import { numberToFileSize, toAbsolutePath } from '../../../../utils/file';
|
15
15
|
import { MessageStatus } from '@smart-link/im-base';
|
16
16
|
import UploadProgress from '../UploadProgress';
|
17
17
|
import { getImManager } from '../../../../init';
|
18
18
|
import PayloadWrapper from './PayloadWrapper';
|
19
19
|
import { findSvgIcon } from '../../../../utils/file-icon';
|
20
20
|
import useTranslation from "../../../../hooks/useTranslation";
|
21
|
-
const PayloadFile = ({ payload, messageSeq, direction, showArrow = true, isRecord, messageStatus, sendSize, style, onLongPress }) => {
|
21
|
+
const PayloadFile = ({ payload, messageSeq, direction, showArrow = true, isRecord, messageStatus, jobId, sendSize, style, onLongPress }) => {
|
22
22
|
const ext = payload.filename.split('.').pop();
|
23
23
|
const Icon = findSvgIcon(ext);
|
24
24
|
const path = useRef('');
|
25
25
|
const downloading = useRef(false);
|
26
26
|
const { t } = useTranslation();
|
27
|
+
const width = Dimensions.get('window').width * 0.75 - dp(24);
|
27
28
|
const [download, setDownload] = useState({
|
28
29
|
progress: 0,
|
29
30
|
status: 'pending',
|
30
31
|
});
|
31
32
|
const openWithLocal = (path) => __awaiter(void 0, void 0, void 0, function* () {
|
32
33
|
try {
|
33
|
-
yield FileViewer.open(path);
|
34
|
+
yield FileViewer.open(toAbsolutePath(path));
|
34
35
|
}
|
35
36
|
catch (e) {
|
36
37
|
Toast.warning(t('fileOpenFail'));
|
@@ -48,7 +49,7 @@ const PayloadFile = ({ payload, messageSeq, direction, showArrow = true, isRecor
|
|
48
49
|
onProgress: (e) => {
|
49
50
|
setDownload({
|
50
51
|
progress: e.loaded,
|
51
|
-
status: 'downloading',
|
52
|
+
status: e.loaded === payload.size ? 'done' : 'downloading',
|
52
53
|
});
|
53
54
|
}
|
54
55
|
});
|
@@ -103,25 +104,24 @@ const PayloadFile = ({ payload, messageSeq, direction, showArrow = true, isRecor
|
|
103
104
|
yield openWithLocal(localPath);
|
104
105
|
}
|
105
106
|
});
|
106
|
-
return (<PayloadWrapper direction={direction} showArrow={showArrow} onLongPress={onLongPress} style={[style, styles.file]} onPress={pressFile}>
|
107
|
+
return (<PayloadWrapper direction={direction} showArrow={showArrow} onLongPress={onLongPress} style={[style, styles.file, { width: width + dp(12) }]} onPress={pressFile}>
|
107
108
|
<View style={{ flexDirection: 'row', alignItems: 'center', flex: 1 }}>
|
108
109
|
<Icon style={styles.fileIcon}/>
|
109
110
|
<View style={{ flex: 1 }}>
|
110
111
|
<Text numberOfLines={1} ellipsizeMode="middle">{payload.filename}</Text>
|
111
|
-
<Text style={styles.size}>{numberToFileSize(payload.size)}{payload.localPath ? t('downloaded') : ''}</Text>
|
112
|
+
<Text style={styles.size}>{numberToFileSize(payload.size)} {payload.localPath ? t('downloaded') : ''}</Text>
|
112
113
|
</View>
|
113
114
|
</View>
|
114
|
-
<UploadProgress show={download.status === 'downloading'} width={
|
115
|
-
<UploadProgress show={messageStatus === MessageStatus.EMITTING} width={
|
115
|
+
<UploadProgress show={download.status === 'downloading'} width={width} sendSize={download.progress} totalSize={payload.size}/>
|
116
|
+
<UploadProgress show={messageStatus === MessageStatus.EMITTING || Boolean(jobId)} width={width} sendSize={sendSize || 0} totalSize={payload.size}/>
|
116
117
|
</PayloadWrapper>);
|
117
118
|
};
|
118
119
|
const styles = StyleSheet.create({
|
119
120
|
file: {
|
120
|
-
|
121
|
+
flexDirection: 'column',
|
121
122
|
alignItems: 'center',
|
122
123
|
padding: dp(6),
|
123
|
-
borderRadius: dp(8)
|
124
|
-
width: Dimensions.get('window').width * 0.75,
|
124
|
+
borderRadius: dp(8)
|
125
125
|
},
|
126
126
|
fileIcon: {
|
127
127
|
marginRight: dp(8),
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { borderStyle, shadowStyle } from '../../../../components/styles';
|
2
2
|
import useTranslation from '../../../../hooks/useTranslation';
|
3
3
|
import { getImManager } from '../../../../init';
|
4
|
-
import { buildSimpleText, ConversationType } from '@smart-link/im-base';
|
4
|
+
import { buildSimpleText, ConversationType, MessageListActions } from '@smart-link/im-base';
|
5
5
|
import { dp, useNavigation } from '@smart-link/rn-ui';
|
6
6
|
import React, { memo } from 'react';
|
7
7
|
import { View, StyleSheet, Text, Dimensions } from 'react-native';
|
@@ -17,10 +17,14 @@ const PayloadMultiple = memo(({ payload, messageSeq, direction, showArrow = true
|
|
17
17
|
? t('multipleChatRecordTitle', { fromName, toName })
|
18
18
|
: t('multipleChatRecordTitleGroup');
|
19
19
|
return (<PayloadWrapper direction={direction} showArrow={showArrow} style={[style, styles.wrap]} onPress={() => {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
imManager.store.dispatch(MessageListActions.addMessageListData(imManager, messageSeq, selectedMessages));
|
21
|
+
navigation.navigate({
|
22
|
+
name: 'MessageRecord',
|
23
|
+
key: Date.now().toString(),
|
24
|
+
params: {
|
25
|
+
messageSeq,
|
26
|
+
title,
|
27
|
+
},
|
24
28
|
});
|
25
29
|
}} onLongPress={onLongPress}>
|
26
30
|
<Text style={styles.titleText} numberOfLines={2}>
|
@@ -1,4 +1,4 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { PayloadProps } from "./type";
|
3
|
-
declare const _default: React.MemoExoticComponent<({ payload, onLoad, ...retProps }: PayloadProps) => React.JSX.Element>;
|
3
|
+
declare const _default: React.MemoExoticComponent<({ payload, onLoad, isRecord, ...retProps }: PayloadProps) => React.JSX.Element>;
|
4
4
|
export default _default;
|
@@ -17,13 +17,12 @@ import { borderStyle, shadowStyle } from '../../../../components/styles';
|
|
17
17
|
import { dp } from '@smart-link/rn-ui';
|
18
18
|
import PayloadWrapper from './PayloadWrapper';
|
19
19
|
import Image from 'react-native-fast-image';
|
20
|
-
import useDownloadSource from "../../../../hooks/useDownloadSource";
|
21
20
|
import { toAbsolutePath } from "../../../../utils/file";
|
22
21
|
const { width: screenWidth } = Dimensions.get('window');
|
23
22
|
const PayloadPicture = (_a) => {
|
24
|
-
var { payload, onLoad } = _a, retProps = __rest(_a, ["payload", "onLoad"]);
|
23
|
+
var { payload, onLoad, isRecord } = _a, retProps = __rest(_a, ["payload", "onLoad", "isRecord"]);
|
25
24
|
const ext = payload.filename.split('.').pop();
|
26
|
-
const localPath =
|
25
|
+
const { localPath } = payload;
|
27
26
|
useEffect(() => {
|
28
27
|
if (localPath) {
|
29
28
|
onLoad === null || onLoad === void 0 ? void 0 : onLoad(localPath);
|
@@ -35,7 +34,7 @@ const PayloadPicture = (_a) => {
|
|
35
34
|
}
|
36
35
|
let content;
|
37
36
|
if (/svg/i.test(ext)) {
|
38
|
-
content = <SvgFromUri style={[borderStyle]} uri={localPath} viewBox={'0 0 1024 1024'} width={screenWidth * 0.4} height={screenWidth * 0.4}/>;
|
37
|
+
content = <SvgFromUri style={[borderStyle]} uri={toAbsolutePath(localPath)} viewBox={'0 0 1024 1024'} width={screenWidth * 0.4} height={screenWidth * 0.4}/>;
|
39
38
|
}
|
40
39
|
else {
|
41
40
|
content = <Image resizeMode="cover" style={[borderStyle, size]} source={{
|
@@ -11,10 +11,11 @@ import UploadProgress from '../UploadProgress';
|
|
11
11
|
import PayloadWrapper from './PayloadWrapper';
|
12
12
|
import { getImManager } from '../../../../init';
|
13
13
|
import Image from 'react-native-fast-image';
|
14
|
+
import { toAbsolutePath } from "../../../../utils/file";
|
14
15
|
const PayloadVideo = ({ messageStatus, messageSeq, payload, sendSize = 0, isRecord, onLongPress }) => {
|
15
16
|
const { width, height } = payload;
|
16
17
|
const size = calculate(height || dp(163), width || dp(100));
|
17
|
-
const thumbnail = payload.imagePath ? { uri:
|
18
|
+
const thumbnail = payload.imagePath ? { uri: toAbsolutePath(payload.imagePath) }
|
18
19
|
: { uri: getDownloadUrl(payload.imageFileId) };
|
19
20
|
return (<PayloadWrapper style={[styles.root, shadowStyle, borderStyle, size]} onPress={() => {
|
20
21
|
getImManager().store.dispatch(loadVideoPlayer({
|
@@ -83,7 +83,7 @@ const PayloadVoice = ({ payload, direction, style, messageSeq, showArrow = true,
|
|
83
83
|
return;
|
84
84
|
}
|
85
85
|
else {
|
86
|
-
const isExist = yield RNFS.exists(payload.localPath);
|
86
|
+
const isExist = yield RNFS.exists(toAbsolutePath(payload.localPath));
|
87
87
|
if (!isExist) {
|
88
88
|
console.log('path not exists');
|
89
89
|
const destPath = yield download();
|
@@ -1,12 +1,13 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { GestureResponderEvent } from 'react-native';
|
3
|
+
import { NativeEventLayout } from "../../../types";
|
3
4
|
export interface PayloadWrapperProps {
|
4
5
|
showArrow?: boolean;
|
5
6
|
direction?: 'left' | 'right';
|
6
7
|
children: React.ReactNode;
|
7
8
|
style?: any;
|
8
9
|
onPress?: (e: GestureResponderEvent) => void;
|
9
|
-
onLongPress?: (e: GestureResponderEvent) => void;
|
10
|
+
onLongPress?: (e: GestureResponderEvent, layout: NativeEventLayout) => void;
|
10
11
|
}
|
11
12
|
declare const PayloadWrapper: React.NamedExoticComponent<PayloadWrapperProps>;
|
12
13
|
export default PayloadWrapper;
|
@@ -10,11 +10,16 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
10
10
|
return t;
|
11
11
|
};
|
12
12
|
import { dp } from '@smart-link/rn-ui';
|
13
|
-
import React, { memo } from 'react';
|
13
|
+
import React, { memo, useState } from 'react';
|
14
14
|
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
15
15
|
const PayloadWrapper = memo((_a) => {
|
16
|
-
var { children, direction, showArrow } = _a, retProps = __rest(_a, ["children", "direction", "showArrow"]);
|
17
|
-
|
16
|
+
var { children, direction, showArrow, onLongPress } = _a, retProps = __rest(_a, ["children", "direction", "showArrow", "onLongPress"]);
|
17
|
+
const [layout, setLayout] = useState();
|
18
|
+
return (<TouchableOpacity {...retProps} onLayout={e => {
|
19
|
+
setLayout(e.nativeEvent.layout);
|
20
|
+
}} onLongPress={(e) => {
|
21
|
+
onLongPress && onLongPress(e, layout);
|
22
|
+
}}>
|
18
23
|
{showArrow && (<View style={[styles.arrow, direction === 'right' ? styles.rightArrow : styles.leftArrow]}/>)}
|
19
24
|
{children}
|
20
25
|
</TouchableOpacity>);
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import { IMessage } from "@smart-link/im-base";
|
2
2
|
import { GestureResponderEvent, StyleProp, ViewStyle } from "react-native";
|
3
|
+
import { NativeEventLayout } from "../../../types";
|
3
4
|
export interface PayloadProps extends IMessage {
|
4
5
|
style?: StyleProp<ViewStyle>;
|
5
6
|
direction?: 'left' | 'right';
|
6
7
|
showArrow?: boolean;
|
7
8
|
isRecord?: boolean;
|
8
9
|
onPress?: (e: GestureResponderEvent) => void;
|
9
|
-
onLongPress?: (e: GestureResponderEvent) => void;
|
10
|
+
onLongPress?: (e: GestureResponderEvent, layout: NativeEventLayout) => void;
|
10
11
|
onLoad?: (localPath: string) => void;
|
11
12
|
}
|
@@ -6,11 +6,11 @@ import useTranslation from "../../../hooks/useTranslation";
|
|
6
6
|
import dayjs from "dayjs";
|
7
7
|
export const ReceiptBack = ({ message }) => {
|
8
8
|
const { t } = useTranslation();
|
9
|
-
// console.log('ReceiptBack: '
|
9
|
+
// console.log('ReceiptBack: ', message.receiptBackList.length, message.receiptBackList);
|
10
10
|
return (<View style={styles.content}>
|
11
11
|
<View style={{ flexDirection: 'row' }}>
|
12
12
|
<Text style={[styles.text, { width: dp(165) }]}>
|
13
|
-
{dayjs(message.messageTime).format('YYYY-MM-DD
|
13
|
+
{dayjs(message.messageTime).format('YYYY-MM-DD HH:mm:ss')}
|
14
14
|
</Text>
|
15
15
|
<Text style={styles.text}>{message.messageStatus === MessageStatus.EMIT_ERROR ? t('sendFail') : t('sent')}</Text>
|
16
16
|
</View>
|
@@ -11,7 +11,6 @@ import LocalImage from '../../../components/LocalImage';
|
|
11
11
|
import useTranslation from '../../../hooks/useTranslation';
|
12
12
|
import { getImManager } from '../../../init';
|
13
13
|
import PayloadFile from './Payload/PayloadFile';
|
14
|
-
import useDownloadSource, { useDownloadImgSource } from "../../../hooks/useDownloadSource";
|
15
14
|
const voiceLeft = require('../../../../assets/voice-left.png');
|
16
15
|
const { width } = Dimensions.get('window');
|
17
16
|
export const QuoteTextMix = memo(props => {
|
@@ -27,10 +26,8 @@ export const QuoteTextMix = memo(props => {
|
|
27
26
|
});
|
28
27
|
export const QuotePicture = memo(props => {
|
29
28
|
const { quoteTitle, quoteMessage, quoteStyle, color, textStyle, borderColor, backgroundColor, onPressQuote } = props;
|
30
|
-
const { height, width } = quoteMessage.payload;
|
29
|
+
const { height, width, localPath } = quoteMessage.payload;
|
31
30
|
const theme = useTheme();
|
32
|
-
console.log('QuotePicture', quoteMessage);
|
33
|
-
const localImg = useDownloadSource(quoteMessage.payload);
|
34
31
|
const sizeStyle = calculate(height || 100, width || 61.8, 100);
|
35
32
|
return (<TouchableOpacity activeOpacity={0.5} onPress={onPressQuote} style={[quoteStyle, styles.leftBorder, { backgroundColor: dark(color, 6) }]}>
|
36
33
|
<Text style={[textStyle, styles.replyUserName]}>
|
@@ -38,7 +35,7 @@ export const QuotePicture = memo(props => {
|
|
38
35
|
{' : '}
|
39
36
|
</Text>
|
40
37
|
<View style={styles.h5}/>
|
41
|
-
{(!
|
38
|
+
{(!localPath) && (<View style={[
|
42
39
|
styles.pictureEmpty,
|
43
40
|
Object.assign({ backgroundColor,
|
44
41
|
borderColor }, sizeStyle),
|
@@ -47,23 +44,21 @@ export const QuotePicture = memo(props => {
|
|
47
44
|
<ActivityIndicator color={theme.primaryColor} animating={true}/>
|
48
45
|
</View>)}
|
49
46
|
|
50
|
-
{
|
47
|
+
{localPath && (<LocalImage style={sizeStyle} resizeMode="cover" localPath={localPath}/>)}
|
51
48
|
</TouchableOpacity>);
|
52
49
|
});
|
53
50
|
export const QuoteVideo = memo(props => {
|
54
51
|
const { quoteTitle, quoteMessage, quoteStyle, color, textStyle, borderColor, backgroundColor, onPressQuote } = props;
|
55
|
-
const { duration, height, width } = quoteMessage.payload;
|
52
|
+
const { duration, height, width, imagePath } = quoteMessage.payload;
|
56
53
|
const theme = useTheme();
|
57
|
-
console.log('QuoteVideo: ', quoteMessage);
|
58
54
|
const sizeStyle = calculate(height, width);
|
59
|
-
const localImg = useDownloadImgSource(quoteMessage.payload);
|
60
55
|
return (<TouchableOpacity activeOpacity={0.5} onPress={onPressQuote} style={[quoteStyle, styles.leftBorder, { backgroundColor: dark(color, 6) }]}>
|
61
56
|
<Text style={[textStyle, styles.replyUserName]}>
|
62
57
|
{quoteTitle}
|
63
58
|
{' : '}
|
64
59
|
</Text>
|
65
60
|
<View style={styles.h5}/>
|
66
|
-
{(!
|
61
|
+
{(!imagePath) && (<View style={[
|
67
62
|
styles.pictureEmpty,
|
68
63
|
Object.assign({ backgroundColor,
|
69
64
|
borderColor }, sizeStyle),
|
@@ -72,8 +67,8 @@ export const QuoteVideo = memo(props => {
|
|
72
67
|
<ActivityIndicator color={theme.primaryColor} animating={true}/>
|
73
68
|
</View>)}
|
74
69
|
|
75
|
-
{
|
76
|
-
<LocalImage style={sizeStyle} resizeMode="cover" localPath={
|
70
|
+
{imagePath && (<View style={{ width: sizeStyle.width }}>
|
71
|
+
<LocalImage style={sizeStyle} resizeMode="cover" localPath={imagePath}/>
|
77
72
|
<View style={styles.playView}>
|
78
73
|
<AntDesign size={30} name="playcircleo" color="#fff"/>
|
79
74
|
</View>
|
@@ -20,15 +20,15 @@ const TextMixQuoteMessage = memo(props => {
|
|
20
20
|
}}/>)}
|
21
21
|
|
22
22
|
{quotePayloadType === PICTURE && (<QuotePicture quoteTitle={quote.quoteTitle} quoteMessage={quote.quoteMessage} quoteStyle={quoteStyle} color={quoteBgColor} textStyle={textStyle} backgroundColor={quoteBgColor} borderColor={quoteBgColor} onPressQuote={() => {
|
23
|
-
onPressQuote
|
23
|
+
onPressQuote === null || onPressQuote === void 0 ? void 0 : onPressQuote(quoteMessageSeq);
|
24
24
|
}}/>)}
|
25
25
|
|
26
26
|
{quotePayloadType === VIDEO && (<QuoteVideo quoteTitle={quote.quoteTitle} quoteMessage={quote.quoteMessage} quoteStyle={quoteStyle} color={quoteBgColor} textStyle={textStyle} backgroundColor={quoteBgColor} borderColor={quoteBgColor} onPressQuote={() => {
|
27
|
-
onPressQuote
|
27
|
+
onPressQuote === null || onPressQuote === void 0 ? void 0 : onPressQuote(quoteMessageSeq);
|
28
28
|
}}/>)}
|
29
29
|
|
30
30
|
{quotePayloadType === FILE && (<QuoteFile quoteTitle={quote.quoteTitle} quoteMessage={quote.quoteMessage} color={quoteBgColor} textStyle={textStyle} onPressQuote={() => {
|
31
|
-
onPressQuote
|
31
|
+
onPressQuote === null || onPressQuote === void 0 ? void 0 : onPressQuote(quoteMessageSeq);
|
32
32
|
}}/>)}
|
33
33
|
|
34
34
|
{quotePayloadType === VOICE && (<QuoteVoice quoteTitle={quote.quoteTitle} quoteMessage={quote.quoteMessage} color={quoteBgColor} textStyle={textStyle} onPressQuote={() => {
|
@@ -7,8 +7,7 @@ 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 { dp,
|
11
|
-
import * as DocumentPicker from '@react-native-documents/picker';
|
10
|
+
import { dp, useNavigation } from '@smart-link/rn-ui';
|
12
11
|
import React, { forwardRef, memo, useImperativeHandle, useState } from 'react';
|
13
12
|
import { View, Text, FlatList, TouchableOpacity, Dimensions, StyleSheet, Animated } from 'react-native';
|
14
13
|
import { useConversation } from '../../../../hooks/useImSelector';
|
@@ -17,7 +16,7 @@ import { getImManager } from '../../../../init';
|
|
17
16
|
import { FileIcon, PhotosIcon, ShootingIcon, UserIcon } from './Icons';
|
18
17
|
import ImagePicker from 'react-native-image-crop-picker';
|
19
18
|
import { startSendContact } from '../../../../slice/contact/contact.slice';
|
20
|
-
import { copyFile
|
19
|
+
import { copyFile } from '../../../../utils/file';
|
21
20
|
import { scrollToBottom } from '../../../../utils/scroll';
|
22
21
|
import { takeCamera } from '../../../../utils/take-camera';
|
23
22
|
import FontAwesome from "react-native-vector-icons/FontAwesome";
|
@@ -63,8 +62,8 @@ const OptionPanel = forwardRef((props, ref) => {
|
|
63
62
|
compressImageMaxWidth: 1080,
|
64
63
|
});
|
65
64
|
console.log(images);
|
66
|
-
|
67
|
-
sendPicture({
|
65
|
+
for (const item of images) {
|
66
|
+
yield sendPicture({
|
68
67
|
filename: item.filename,
|
69
68
|
size: item.size,
|
70
69
|
localPath: item.path,
|
@@ -73,7 +72,7 @@ const OptionPanel = forwardRef((props, ref) => {
|
|
73
72
|
width: item.width,
|
74
73
|
height: item.height,
|
75
74
|
});
|
76
|
-
}
|
75
|
+
}
|
77
76
|
}
|
78
77
|
catch (e) {
|
79
78
|
console.log(e);
|
@@ -89,31 +88,7 @@ const OptionPanel = forwardRef((props, ref) => {
|
|
89
88
|
});
|
90
89
|
const pickFile = () => __awaiter(void 0, void 0, void 0, function* () {
|
91
90
|
try {
|
92
|
-
|
93
|
-
type: [DocumentPicker.types.allFiles],
|
94
|
-
});
|
95
|
-
const fileInfo = files[0];
|
96
|
-
console.log('chooseFile: ', fileInfo);
|
97
|
-
if (!fileInfo.uri) {
|
98
|
-
Toast.error(t("failedToObtainFilePath"));
|
99
|
-
return;
|
100
|
-
}
|
101
|
-
const ext = getExtensionFromMime(fileInfo.type);
|
102
|
-
if (!ext) {
|
103
|
-
Toast.error(t("unsupportedFileTypes"));
|
104
|
-
return;
|
105
|
-
}
|
106
|
-
if (!fileInfo.name.endsWith(ext)) {
|
107
|
-
fileInfo.name = fileInfo.name + ext;
|
108
|
-
}
|
109
|
-
yield sendFile({
|
110
|
-
// ios 中文名称编码了,需要解码
|
111
|
-
localPath: decodeURI(fileInfo.uri),
|
112
|
-
filename: fileInfo.name,
|
113
|
-
size: fileInfo.size,
|
114
|
-
type: fileInfo.type,
|
115
|
-
lastModified: Date.now(),
|
116
|
-
});
|
91
|
+
navigation.navigate('FileSelector');
|
117
92
|
}
|
118
93
|
catch (e) {
|
119
94
|
console.log(e);
|
@@ -2,6 +2,7 @@ import MessageList from './MessageList';
|
|
2
2
|
import ChooseMember from './ChooseMember';
|
3
3
|
import MessageRecord from './MessageRecord';
|
4
4
|
import MessageBackup, { StartBackupPage, RestoreBackupPage } from './MessageBackup';
|
5
|
+
import FileSelector from "./FileSelector";
|
5
6
|
export const messageRoutes = [
|
6
7
|
{
|
7
8
|
name: 'MessageList',
|
@@ -26,6 +27,15 @@ export const messageRoutes = [
|
|
26
27
|
title: '',
|
27
28
|
},
|
28
29
|
},
|
30
|
+
{
|
31
|
+
name: 'FileSelector',
|
32
|
+
component: FileSelector,
|
33
|
+
options: {
|
34
|
+
title: '',
|
35
|
+
animation: 'fade_from_bottom',
|
36
|
+
animationDuration: 150,
|
37
|
+
},
|
38
|
+
},
|
29
39
|
{
|
30
40
|
name: 'MessageBackup',
|
31
41
|
component: MessageBackup,
|
package/dist/pages/types.d.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { IConversation
|
2
|
+
import { IConversation } from '@smart-link/im-base';
|
3
3
|
import { IGroupCategory } from '../interface';
|
4
|
+
import { LayoutChangeEvent } from "react-native";
|
4
5
|
type StackAnimationTypes = 'default' | 'fade' | 'fade_from_bottom' | 'flip' | 'none' | 'simple_push' | 'slide_from_bottom' | 'slide_from_right' | 'slide_from_left';
|
5
6
|
export type IMPageParamList = {
|
6
7
|
ScanCode: undefined;
|
@@ -54,9 +55,9 @@ export type IMPageParamList = {
|
|
54
55
|
OptionGroupManage: undefined;
|
55
56
|
MessageRecord: {
|
56
57
|
messageSeq: string;
|
57
|
-
messages: IMessage[];
|
58
58
|
title: string;
|
59
59
|
};
|
60
|
+
FileSelector: undefined;
|
60
61
|
};
|
61
62
|
export type RouteConfig = {
|
62
63
|
name: string;
|
@@ -68,4 +69,5 @@ export type RouteConfig = {
|
|
68
69
|
animationDuration?: number;
|
69
70
|
};
|
70
71
|
};
|
72
|
+
export type NativeEventLayout = LayoutChangeEvent['nativeEvent']['layout'];
|
71
73
|
export {};
|
@@ -12,13 +12,14 @@ import { setVideoDownloadProgress, showVideoPlayer, setVideoDownloadError, cance
|
|
12
12
|
import { dp } from '@smart-link/rn-ui';
|
13
13
|
import { getDownloadUrl } from '../../api/file';
|
14
14
|
import { getImManager } from '../../init';
|
15
|
+
import { toAbsolutePath } from "../../utils/file";
|
15
16
|
let stopFn = () => { };
|
16
17
|
export const loadVideoPlayer = message => (dispatch) => __awaiter(void 0, void 0, void 0, function* () {
|
17
18
|
console.log('loadVideoPlayer: ', message);
|
18
19
|
const { payload, messageSeq, isRecord } = message;
|
19
20
|
const { width = dp(100), height = dp(163), localPath } = payload;
|
20
21
|
const thumbnail = payload.imagePath
|
21
|
-
? { uri:
|
22
|
+
? { uri: toAbsolutePath(payload.imagePath) }
|
22
23
|
: { uri: getDownloadUrl(payload.imageFileId) };
|
23
24
|
const imManager = getImManager();
|
24
25
|
const download = () => __awaiter(void 0, void 0, void 0, function* () {
|
@@ -28,6 +29,7 @@ export const loadVideoPlayer = message => (dispatch) => __awaiter(void 0, void 0
|
|
28
29
|
resourceType: 'video',
|
29
30
|
filename: payload.filename || (payload.fileId + '.mp4'),
|
30
31
|
onProgress(o) {
|
32
|
+
console.log('download video: ', o);
|
31
33
|
dispatch(setVideoDownloadProgress(o.loaded / Number(o.total || payload.size)));
|
32
34
|
},
|
33
35
|
onStart: (stop) => {
|
@@ -70,6 +72,12 @@ export const loadVideoPlayer = message => (dispatch) => __awaiter(void 0, void 0
|
|
70
72
|
}
|
71
73
|
else if (!localPath && isRecord) {
|
72
74
|
// 下载文件,缓存资源
|
75
|
+
dispatch(showVideoPlayer({
|
76
|
+
videoLocalPath: '',
|
77
|
+
videoImageHeight: height,
|
78
|
+
videoImageWidth: width,
|
79
|
+
videoImagePath: thumbnail.uri,
|
80
|
+
}));
|
73
81
|
let destPath = yield imManager.loadResourceFromCache(payload.fileId);
|
74
82
|
console.log('video cache: ', destPath);
|
75
83
|
if (!destPath) {
|
package/dist/utils/file.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { IUser, IDownloadOptions, ImManager, ResourceType } from '@smart-link/im-base';
|
2
|
+
import { IPathItem } from "../interface";
|
2
3
|
declare const resourceDirBase: {
|
3
4
|
readonly avatars: "/avatars";
|
4
5
|
readonly voice: "/voice";
|
@@ -14,10 +15,17 @@ export declare function toAbsolutePath(filePath: string): string;
|
|
14
15
|
export declare function toRelativePath(filePath: string): string;
|
15
16
|
export declare const numberToFileSize: (number: number) => string;
|
16
17
|
export declare const moveFile: (filePath: string, filename: string, resourceType: ResourceDir) => Promise<string>;
|
17
|
-
export declare const copyFile: (localPath: string, filename: string, resourceType
|
18
|
+
export declare const copyFile: (localPath: string, filename: string, resourceType: ResourceDir) => Promise<string>;
|
18
19
|
export declare const getSuffix: (filename: string) => string;
|
19
|
-
export declare const download: ({ fileId,
|
20
|
+
export declare const download: ({ fileId, resourceType, filename, onProgress, onStart }: IDownloadOptions) => Promise<string>;
|
20
21
|
export declare function saveToAlbum(imManager: ImManager, localPath: string, showTips?: boolean): Promise<boolean>;
|
21
22
|
export declare function requestSaveFilePermissionIfAndroid(imManager: ImManager): Promise<boolean>;
|
22
23
|
export declare function getExtensionFromMime(mime: string): string;
|
24
|
+
export declare function selectFile(imManager: ImManager, filePath: string, filename: string): Promise<string | undefined>;
|
25
|
+
export declare function readFileDir(imManager: ImManager, path: string, keyword?: string): Promise<IPathItem[]>;
|
26
|
+
export declare function getChildrenCount(imManager: ImManager, isDir: boolean, path: string): Promise<number>;
|
27
|
+
export declare function getFileRootItem(imManager: ImManager): Promise<IPathItem[]>;
|
28
|
+
export declare function createRootItem(imManager: ImManager, name: string, path: string): Promise<IPathItem>;
|
29
|
+
export declare function getFileType(path: string): string;
|
30
|
+
export declare function isImage(path: string): boolean;
|
23
31
|
export {};
|