@smart-link/rn-im 1.0.2 → 1.0.5

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.
@@ -47,26 +47,11 @@ const user_1 = require("../../api/user");
47
47
  const useImSelector_1 = require("../../hooks/useImSelector");
48
48
  const file_1 = require("../../utils/file");
49
49
  const ChatAvatarId_1 = __importDefault(require("../../components/ChatAvatar/ChatAvatarId"));
50
+ const useImReady_1 = __importDefault(require("../../hooks/useImReady"));
50
51
  const ChatAvatar = ({ id, name, url: fileId, size = (0, rn_ui_1.dp)(40), disabled, type = im_base_1.ConversationType.C2C, editable, onUpdate, priority = 'cache' }) => {
51
52
  const { user } = (0, useImSelector_1.useAuth)();
52
53
  const navigation = (0, rn_ui_1.useNavigation)();
53
- const [ready, setReady] = (0, react_1.useState)(false);
54
- (0, react_1.useEffect)(() => {
55
- let imManager = (0, init_1.getImManager)();
56
- if (!imManager) {
57
- const cycle = setInterval(() => {
58
- imManager = (0, init_1.getImManager)();
59
- if (imManager) {
60
- clearInterval(cycle);
61
- setReady(true);
62
- return;
63
- }
64
- }, 100);
65
- }
66
- else {
67
- setReady(true);
68
- }
69
- }, []);
54
+ const ready = (0, useImReady_1.default)();
70
55
  const defaultAvatar = {
71
56
  [im_base_1.ConversationType.C2C]: default_assets_1.defaultAvatars.EMPTY,
72
57
  [im_base_1.ConversationType.C2G]: default_assets_1.defaultAvatars.GROUP,
@@ -17,23 +17,30 @@ const react_native_1 = require("react-native");
17
17
  const rn_ui_1 = require("@smart-link/rn-ui");
18
18
  const react_2 = require("react");
19
19
  const init_1 = require("../../init");
20
- const file_1 = require("../../utils/file");
21
20
  const react_native_fs_1 = __importDefault(require("react-native-fs"));
22
- ;
21
+ const LocalImage_1 = __importDefault(require("../../components/LocalImage"));
23
22
  // 防止重复下载
24
23
  const downloadMap = Object.create(null);
24
+ const cacheMap = Object.create(null);
25
25
  const ChatAvatarLocal = ({ fileId, size, name, defaultAvatar }) => {
26
- const [avatar, setAvatar] = (0, react_2.useState)('');
26
+ const [avatar, setAvatar] = (0, react_2.useState)(fileId ? cacheMap[fileId] : '');
27
+ const [ready, setReady] = (0, react_2.useState)(false);
27
28
  const loadAvatar = () => __awaiter(void 0, void 0, void 0, function* () {
28
- console.log('loadResourceFromCache: ', fileId);
29
+ if (fileId && cacheMap[fileId]) {
30
+ setAvatar(cacheMap[fileId]);
31
+ setReady(true);
32
+ return;
33
+ }
29
34
  if (fileId) {
30
35
  const imManager = (0, init_1.getImManager)();
31
36
  const localPath = yield imManager.loadResourceFromCache(fileId);
32
- console.log('loadResourceFromCache: ', localPath);
37
+ // console.log('loadResourceFromCache: ', localPath)
33
38
  if (localPath) {
34
39
  const exists = yield react_native_fs_1.default.exists(localPath);
35
40
  if (exists) {
36
- setAvatar((0, file_1.toAbsolutePath)(localPath));
41
+ cacheMap[fileId] = localPath;
42
+ setAvatar(localPath);
43
+ setReady(true);
37
44
  return;
38
45
  }
39
46
  }
@@ -50,7 +57,9 @@ const ChatAvatarLocal = ({ fileId, size, name, defaultAvatar }) => {
50
57
  filename: `${fileId}.jpg`,
51
58
  resourceType: 'avatars',
52
59
  });
53
- setAvatar((0, file_1.toAbsolutePath)(localPath));
60
+ cacheMap[fileId] = localPath;
61
+ setAvatar(localPath);
62
+ setReady(true);
54
63
  // 更新资源
55
64
  imManager.updateResource({
56
65
  url: fileId,
@@ -58,19 +67,30 @@ const ChatAvatarLocal = ({ fileId, size, name, defaultAvatar }) => {
58
67
  });
59
68
  }
60
69
  else {
70
+ cacheMap[fileId] = fileId;
61
71
  setAvatar(fileId);
72
+ setReady(true);
62
73
  }
63
74
  }
64
75
  catch (e) {
65
76
  downloadMap[fileId] = false;
66
77
  }
67
78
  }
79
+ else {
80
+ setReady(true);
81
+ }
68
82
  });
69
83
  (0, react_2.useEffect)(() => {
70
- loadAvatar();
84
+ loadAvatar().then(_r => { });
71
85
  }, [fileId]);
72
- return (<rn_ui_1.Avatar src={avatar} icon={<react_native_1.Image style={{ width: size, height: size }} source={defaultAvatar}/>} style={size ? { width: size, height: size } : {}}>
73
- {name === null || name === void 0 ? void 0 : name[0]}
74
- </rn_ui_1.Avatar>);
86
+ if (ready && avatar) {
87
+ return (<LocalImage_1.default localPath={avatar} style={size ? { width: size, height: size, borderRadius: size / 2 } : { width: 40, height: 40, borderRadius: 20 }}/>);
88
+ }
89
+ else if (ready) {
90
+ return (<rn_ui_1.Avatar icon={<react_native_1.Image style={{ width: size, height: size }} source={defaultAvatar}/>} style={size ? { width: size, height: size } : {}}>
91
+ {name === null || name === void 0 ? void 0 : name[0]}
92
+ </rn_ui_1.Avatar>);
93
+ }
94
+ return <react_native_1.View style={size ? { width: size, height: size } : { width: 40, height: 40 }}/>;
75
95
  };
76
96
  exports.default = ChatAvatarLocal;
@@ -0,0 +1 @@
1
+ export default function useImReady(): boolean;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_1 = require("react");
4
+ const init_1 = require("../init");
5
+ let isReady = false;
6
+ function useImReady() {
7
+ const [ready, setReady] = (0, react_1.useState)(isReady);
8
+ (0, react_1.useEffect)(() => {
9
+ let imManager = (0, init_1.getImManager)();
10
+ if (!imManager) {
11
+ const cycle = setInterval(() => {
12
+ imManager = (0, init_1.getImManager)();
13
+ if (imManager) {
14
+ clearInterval(cycle);
15
+ isReady = true;
16
+ setReady(true);
17
+ return;
18
+ }
19
+ }, 100);
20
+ }
21
+ else {
22
+ setReady(true);
23
+ }
24
+ }, []);
25
+ return isReady || ready;
26
+ }
27
+ exports.default = useImReady;
package/dist/init.js CHANGED
@@ -39,7 +39,7 @@ const initImSdk = ({ user, storage, store, server, logo: outLogo, t, logout, und
39
39
  db,
40
40
  store,
41
41
  storage,
42
- server: server,
42
+ server,
43
43
  namespace: '/chat',
44
44
  user: (0, lodash_es_1.cloneDeep)(user),
45
45
  platform: react_native_1.Platform.OS === 'ios' ? im_base_1.Platform.IOS : im_base_1.Platform.ANDROID,
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const locale = {
4
- search: 'Search',
4
+ search: 'ຄົ້ນຫາ',
5
5
  addressList: 'ລາຍຊື່ການຕິດຕໍ່',
6
6
  groupChat: 'ກຸ່ມ',
7
7
  orgStructure: 'ໂຄງຮ່າງອົງການຈັດຕັ້ງ',
@@ -16,16 +16,16 @@ const locale = {
16
16
  byCharacters: 'ຈາກຕົວອັກສອນ',
17
17
  addingGroupMembers: 'ກຳລັງເພີ່ມສະມາຊິກ',
18
18
  creatingGroup: 'ກຸ່ມສົນທະນາກຳລັງລິເລີ່ມ',
19
- userDetail: 'User Detail',
19
+ userDetail: 'ລາຍລະອຽດຂອງຜູ້ໃຊ້',
20
20
  noData: 'ບໍ່ມີຂໍມູນ',
21
21
  loading: 'ກຳລັງໂຫຼດ',
22
22
  requestFail: 'ຮ້ອງຂໍລົ້ມເຫຼວ',
23
23
  userCode: 'ເລກທີຂອງພະນັກງານ',
24
24
  noAdd: 'ຍັງບໍ່ໄດ້ເພີ່ມ',
25
25
  mobile: 'ໂທລະສັບ',
26
- email: 'Email',
26
+ email: 'ອີເມວ',
27
27
  sendNews: 'ສົ່ງຂໍ້ຄວາມ',
28
- job: 'Job',
29
- otherJob: 'Other Job',
28
+ job: 'ວຽກ',
29
+ otherJob: 'ວຽກອື່ນໆ',
30
30
  };
31
31
  exports.default = locale;
@@ -33,16 +33,12 @@ const useTranslation_1 = __importDefault(require("../../hooks/useTranslation"));
33
33
  const Icons_1 = require("./Icons");
34
34
  const addressList_1 = require("../../api/addressList");
35
35
  const useImSelector_1 = require("../../hooks/useImSelector");
36
- const { width: screenWidth } = react_native_1.Dimensions.get('window');
37
36
  const AddressList = ({ navigation }) => {
38
37
  const [groupCategoryList, setGroupCategoryList] = (0, react_1.useState)([]);
39
38
  const { t } = (0, useTranslation_1.default)();
40
39
  const theme = (0, rn_ui_1.useTheme)();
41
40
  const { user } = (0, useImSelector_1.useAuth)();
42
41
  const compName = (user === null || user === void 0 ? void 0 : user.groupNamePath) || (user === null || user === void 0 ? void 0 : user.userName) || '';
43
- (0, react_1.useEffect)(() => {
44
- navigation.setOptions({ title: t('addressList') });
45
- }, [t, navigation]);
46
42
  (0, react_1.useEffect)(() => {
47
43
  (0, addressList_1.listGroupCategory)({ appType: null }).then(({ data }) => {
48
44
  setGroupCategoryList(data);
@@ -76,28 +76,39 @@ const List = ({ navigation }) => {
76
76
  headerTitle = t('message') + '(' + t('unConnect') + ')';
77
77
  break;
78
78
  }
79
+ const options = [
80
+ {
81
+ icon: <MaterialIcons_1.default name="person-add"/>,
82
+ content: t('createGroupChat'),
83
+ onPress: () => {
84
+ (0, init_1.getImManager)().store.dispatch((0, contact_slice_1.startCreateGroup)());
85
+ navigation.navigate('ChooseContact', {
86
+ chooseOrg: true,
87
+ checkMode: 'multi',
88
+ });
89
+ },
90
+ },
91
+ {
92
+ icon: <MaterialIcons_1.default name="qr-code-scanner"/>,
93
+ content: t('scan'),
94
+ onPress: () => {
95
+ navigation.navigate('ScanCode');
96
+ },
97
+ },
98
+ ];
99
+ if (__DEV__) {
100
+ options.push({
101
+ icon: <MaterialIcons_1.default name="settings"/>,
102
+ content: '清空数据并重启',
103
+ onPress: () => {
104
+ (0, init_1.getImManager)().db.clean();
105
+ react_native_1.DevSettings.reload();
106
+ },
107
+ });
108
+ }
79
109
  navigation.setOptions({
80
110
  headerTitle,
81
- headerRight: () => (<rn_ui_1.Popover type="dark" placement="bottom" layout="vertical" duration={100} options={[
82
- {
83
- icon: <MaterialIcons_1.default name="person-add"/>,
84
- content: t('createGroupChat'),
85
- onPress: () => {
86
- (0, init_1.getImManager)().store.dispatch((0, contact_slice_1.startCreateGroup)());
87
- navigation.navigate('ChooseContact', {
88
- chooseOrg: true,
89
- checkMode: 'multi',
90
- });
91
- },
92
- },
93
- {
94
- icon: <MaterialIcons_1.default name="qr-code-scanner"/>,
95
- content: t('scan'),
96
- onPress: () => {
97
- navigation.navigate('ScanCode');
98
- },
99
- },
100
- ]} contentStyle={{ borderRadius: (0, rn_ui_1.dp)(6) }}>
111
+ headerRight: () => (<rn_ui_1.Popover type="dark" placement="bottom" layout="vertical" duration={100} options={options} contentStyle={{ borderRadius: (0, rn_ui_1.dp)(6) }}>
101
112
  <react_native_1.TouchableOpacity style={{ marginHorizontal: (0, rn_ui_1.dp)(10), padding: (0, rn_ui_1.dp)(9) }}>
102
113
  <rn_ui_1.CaihIcon name="picker-add" size={(0, rn_ui_1.dp)(19)} color={'#f6f6f6'}/>
103
114
  </react_native_1.TouchableOpacity>
@@ -52,13 +52,20 @@ const SettingChatBg = ({ navigation }) => {
52
52
  }, [navigation, t]);
53
53
  const openAlbum = () => __awaiter(void 0, void 0, void 0, function* () {
54
54
  let toast;
55
+ let image;
55
56
  try {
56
- const image = yield react_native_image_crop_picker_1.default.openPicker({
57
+ image = yield react_native_image_crop_picker_1.default.openPicker({
57
58
  mediaType: 'photo',
58
59
  multiple: false,
59
60
  compressImageQuality: 0.7,
60
61
  compressImageMaxWidth: 1080,
61
62
  });
63
+ }
64
+ catch (e) {
65
+ console.log(e);
66
+ return;
67
+ }
68
+ try {
62
69
  toast = rn_ui_1.Toast.loading();
63
70
  const fileId = yield (0, upload_1.default)(image.path, image.mime);
64
71
  yield (0, im_base_1.updateOptionSetting)({
@@ -57,7 +57,7 @@ const MessageList = ({ navigation }) => {
57
57
  const [nativeEvent, setNativeEvent] = (0, react_1.useState)();
58
58
  const isB2C = (currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.type) === im_base_1.ConversationType.B2C;
59
59
  (0, react_1.useEffect)(() => {
60
- console.log('[进入会话]: ', currentConversation);
60
+ console.log('[进入会话]: ', currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.name);
61
61
  if (currentConversation) {
62
62
  navigation.setOptions({
63
63
  headerLeft: isMultiple
@@ -6,5 +6,5 @@ export interface MessagePictureAlbumProps {
6
6
  messageSeq: string;
7
7
  onClose: () => void;
8
8
  }
9
- declare const MessagePictureAlbum: ({ visible, onClose, messages, messageSeq }: MessagePictureAlbumProps) => React.JSX.Element;
10
- export default MessagePictureAlbum;
9
+ declare const _default: React.MemoExoticComponent<({ visible, onClose, messages, messageSeq }: MessagePictureAlbumProps) => React.JSX.Element>;
10
+ export default _default;
@@ -68,7 +68,7 @@ const MessagePictureAlbum = ({ visible, onClose, messages, messageSeq }) => {
68
68
  setSources([]);
69
69
  onClose();
70
70
  };
71
- return (<react_native_1.Modal visible={visible} onRequestClose={handleClose}>
71
+ return (<react_native_1.Modal style={{ flex: 1 }} statusBarTranslucent animationType="fade" visible={visible} onRequestClose={handleClose}>
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 }}>
@@ -87,7 +87,6 @@ const styles = react_native_1.StyleSheet.create({
87
87
  backgroundColor: '#000',
88
88
  justifyContent: 'center',
89
89
  alignItems: 'center',
90
- position: 'relative',
91
90
  },
92
91
  cancel: {
93
92
  height: (0, rn_ui_1.dp)(40),
@@ -102,4 +101,4 @@ const styles = react_native_1.StyleSheet.create({
102
101
  opacity: 0.7,
103
102
  },
104
103
  });
105
- exports.default = MessagePictureAlbum;
104
+ exports.default = (0, react_1.memo)(MessagePictureAlbum);
@@ -35,23 +35,23 @@ const golden_rectangle_1 = require("../../../../utils/golden-rectangle");
35
35
  const MaterialIcons_1 = __importDefault(require("react-native-vector-icons/MaterialIcons"));
36
36
  const video_action_1 = require("../../../../slice/video/video.action");
37
37
  const styles_1 = require("../../../../components/styles");
38
- const UploadProgress_1 = __importDefault(require("../../../../pages/message/components/UploadProgress"));
38
+ const UploadProgress_1 = __importDefault(require("../UploadProgress"));
39
39
  const PayloadWrapper_1 = __importDefault(require("./PayloadWrapper"));
40
40
  const init_1 = require("../../../../init");
41
41
  const react_native_fast_image_1 = __importDefault(require("react-native-fast-image"));
42
42
  const PayloadVideo = ({ messageStatus, messageSeq, payload, sendSize = 0, onLongPress }) => {
43
- const { width = (0, rn_ui_1.dp)(100), height = (0, rn_ui_1.dp)(163) } = payload;
44
- const size = (0, golden_rectangle_1.calculate)(height, width);
43
+ const { width, height } = payload;
44
+ const size = (0, golden_rectangle_1.calculate)(height || (0, rn_ui_1.dp)(163), width || (0, rn_ui_1.dp)(100));
45
45
  const thumbnail = payload.imagePath ? { uri: 'file://' + payload.imagePath }
46
46
  : { uri: (0, file_1.getDownloadUrl)(payload.imageFileId) };
47
- console.log('payload', payload);
47
+ console.log('payload video', payload);
48
48
  return (<PayloadWrapper_1.default style={[styles.root, styles_1.shadowStyle, styles_1.borderStyle, size]} onPress={() => {
49
49
  (0, init_1.getImManager)().store.dispatch((0, video_action_1.loadVideoPlayer)({
50
50
  messageSeq,
51
51
  payload
52
52
  }));
53
53
  }} onLongPress={onLongPress}>
54
- <react_native_fast_image_1.default style={[size, styles_1.borderStyle]} resizeMode='cover' source={thumbnail}/>
54
+ {payload.imagePath || payload.imageFileId ? <react_native_fast_image_1.default style={[size, styles_1.borderStyle]} resizeMode='cover' source={thumbnail}/> : <react_native_1.View style={[size, styles_1.borderStyle, { backgroundColor: '#000' }]}/>}
55
55
  <UploadProgress_1.default show={messageStatus === im_base_1.MessageStatus.EMITTING && !payload.fileId && payload.size > 0} width={size.width} sendSize={sendSize} totalSize={payload.size}/>
56
56
  <react_native_1.View style={styles.playView}>
57
57
  <MaterialIcons_1.default size={30} name='play-circle-outline' color='#fff'/>
@@ -114,7 +114,7 @@ const download = ({ fileId, fileSize, resourceType, filename, onProgress }) => _
114
114
  // 设置 background 为 false,确保 progress 回调能够正常触发
115
115
  background: true,
116
116
  progress: (e) => {
117
- console.log('download progress: ', e);
117
+ // console.log('download progress: ', e);
118
118
  onProgress === null || onProgress === void 0 ? void 0 : onProgress({ loaded: e.bytesWritten, total: e.contentLength });
119
119
  }
120
120
  });
@@ -138,7 +138,7 @@ const download = ({ fileId, fileSize, resourceType, filename, onProgress }) => _
138
138
  }
139
139
  const contentLength = resp.headers.get('Content-Length') || fileSize;
140
140
  const result = yield (0, react_native_compressor_1.download)(fileUrl, (progress) => {
141
- console.log('download progress: ', progress);
141
+ // console.log('download progress: ', progress);
142
142
  onProgress === null || onProgress === void 0 ? void 0 : onProgress({ loaded: progress * Number(contentLength), total: Number(contentLength) });
143
143
  });
144
144
  return yield (0, exports.moveFile)(result, filename, resourceType);
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@smart-link/rn-im",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
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.2"
10
+ "@smart-link/im-base": "^1.0.5"
11
11
  },
12
12
  "devDependencies": {
13
13
  "@react-native/eslint-config": "0.73.2",
@@ -18,7 +18,7 @@
18
18
  "@types/react-native-video": "5.0.19",
19
19
  "concurrently": "^9.1.0",
20
20
  "eslint-plugin-jest": "^26.5.3",
21
- "rimraf": "^5.0.1",
21
+ "rimraf": "^6.0.1",
22
22
  "tsc-alias": "^1.8.10",
23
23
  "typescript": "5.0.4",
24
24
  "react-native": "^0.73.0"
@@ -62,7 +62,7 @@
62
62
  "react-redux": "^8.1.3",
63
63
  "redux": "^4.2.1",
64
64
  "redux-thunk": "^2.4.2",
65
- "@smart-link/rn-ui": "^1.0.4",
65
+ "@smart-link/rn-ui": "^1.0.6",
66
66
  "@smart-link/rn-base": "^1.0.7"
67
67
  },
68
68
  "files": [
@@ -74,6 +74,6 @@
74
74
  "clean": "rimraf ./dist",
75
75
  "build": "pnpm run clean && tsc && tsc-alias",
76
76
  "build:watch": "concurrently \"tsc -w\" \"tsc-alias -w\"",
77
- "release": "pnpm publish --tag latest --access public --no-git-checks"
77
+ "release": "pnpm build && pnpm publish --tag latest --access public --no-git-checks"
78
78
  }
79
79
  }