@momo-kits/avatar 0.0.62-beta → 0.0.62-beta.1
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/Avatar.js +312 -422
- package/Avatar.web.js +73 -4
- package/package.json +14 -14
- package/publish.sh +1 -1
package/Avatar.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
/* eslint-disable indent */
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import React, { Component } from 'react';
|
|
4
|
-
import {
|
|
5
|
-
View, StyleSheet, TouchableOpacity, Dimensions
|
|
6
|
-
} from 'react-native';
|
|
7
|
-
import { get, isEqual } from 'lodash';
|
|
8
2
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
Colors,
|
|
4
|
+
Image,
|
|
5
|
+
Radius,
|
|
6
|
+
ScaleSize,
|
|
7
|
+
Text,
|
|
8
|
+
ValueUtil,
|
|
9
|
+
} from '@momo-kits/core-v2';
|
|
10
|
+
import PropTypes from 'prop-types';
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
|
13
|
+
|
|
14
|
+
export const AvatarQuality = {
|
|
15
|
+
low: 'low',
|
|
16
|
+
medium: 'medium',
|
|
17
|
+
high: 'high',
|
|
18
|
+
};
|
|
11
19
|
|
|
12
20
|
export const AvatarSize = {
|
|
13
21
|
tiny: 'tiny',
|
|
@@ -15,315 +23,191 @@ export const AvatarSize = {
|
|
|
15
23
|
medium: 'medium',
|
|
16
24
|
large: 'large',
|
|
17
25
|
giant: 'giant',
|
|
18
|
-
size8: 'size8',
|
|
19
|
-
size24: 'size24',
|
|
20
|
-
size36: 'size36',
|
|
21
|
-
size44: 'size44',
|
|
22
|
-
size48: 'size48',
|
|
23
|
-
size52: 'size52',
|
|
24
|
-
size56: 'size56',
|
|
25
|
-
size64: 'size64',
|
|
26
|
-
size72: 'size72',
|
|
27
|
-
size80: 'size80',
|
|
28
|
-
size88: 'size88',
|
|
29
|
-
size96: 'size96'
|
|
30
26
|
};
|
|
31
27
|
|
|
32
28
|
export const SubIconType = {
|
|
33
29
|
momo: 'momo',
|
|
34
30
|
online: 'online',
|
|
35
31
|
key: 'key',
|
|
36
|
-
none: 'none'
|
|
32
|
+
none: 'none',
|
|
37
33
|
};
|
|
38
34
|
|
|
39
35
|
const styles = StyleSheet.create({
|
|
40
36
|
container: {
|
|
41
37
|
justifyContent: 'center',
|
|
42
|
-
alignItems: 'center'
|
|
38
|
+
alignItems: 'center',
|
|
43
39
|
},
|
|
44
40
|
shortNameView: {
|
|
41
|
+
backgroundColor: Colors.pink_09,
|
|
45
42
|
justifyContent: 'center',
|
|
46
43
|
alignItems: 'center',
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
width: '100%',
|
|
50
|
-
height: '100%'
|
|
44
|
+
borderWidth: 1,
|
|
45
|
+
borderColor: Colors.black_04,
|
|
51
46
|
},
|
|
52
47
|
shortNameText: {
|
|
53
48
|
// fontSize: 17,
|
|
54
|
-
color:
|
|
49
|
+
color: Colors.pink_03,
|
|
50
|
+
},
|
|
51
|
+
shortNameTextCustom: {
|
|
52
|
+
color: '#f6f6f6',
|
|
55
53
|
},
|
|
56
54
|
absolute: {
|
|
57
55
|
position: 'absolute',
|
|
58
56
|
top: 0,
|
|
59
57
|
left: 0,
|
|
60
58
|
right: 0,
|
|
61
|
-
bottom: 0
|
|
59
|
+
bottom: 0,
|
|
62
60
|
},
|
|
63
61
|
subIcon: {
|
|
64
62
|
position: 'absolute',
|
|
65
63
|
bottom: 0,
|
|
66
|
-
right: 0
|
|
64
|
+
right: 0,
|
|
65
|
+
},
|
|
66
|
+
topIcon: {
|
|
67
|
+
position: 'absolute',
|
|
68
|
+
top: 0,
|
|
69
|
+
right: 0,
|
|
67
70
|
},
|
|
68
71
|
subIconImage: {
|
|
69
72
|
width: 22,
|
|
70
|
-
height: 22
|
|
73
|
+
height: 22,
|
|
71
74
|
},
|
|
72
75
|
subIconImageOnline: {
|
|
73
76
|
backgroundColor: Colors.kiwi_green,
|
|
74
77
|
borderColor: 'white',
|
|
75
|
-
borderWidth: 1
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const subIconSize = (width) => ({
|
|
80
|
-
tiny: {
|
|
81
|
-
width: 8,
|
|
82
|
-
height: 8,
|
|
83
|
-
borderRadius: 4
|
|
84
|
-
},
|
|
85
|
-
small: {
|
|
86
|
-
width: 10,
|
|
87
|
-
height: 10,
|
|
88
|
-
borderRadius: 5
|
|
89
|
-
},
|
|
90
|
-
medium: {
|
|
91
|
-
width: 12,
|
|
92
|
-
height: 12,
|
|
93
|
-
borderRadius: 6
|
|
78
|
+
borderWidth: 1,
|
|
94
79
|
},
|
|
95
|
-
large: {
|
|
96
|
-
width: 16,
|
|
97
|
-
height: 16,
|
|
98
|
-
borderRadius: 8
|
|
99
|
-
},
|
|
100
|
-
size8: {
|
|
101
|
-
width: 8,
|
|
102
|
-
height: 8,
|
|
103
|
-
borderRadius: 4
|
|
104
|
-
},
|
|
105
|
-
size24: {
|
|
106
|
-
width: 10,
|
|
107
|
-
height: 10,
|
|
108
|
-
borderRadius: 5
|
|
109
|
-
},
|
|
110
|
-
size36: {
|
|
111
|
-
width: 10,
|
|
112
|
-
height: 10,
|
|
113
|
-
borderRadius: 5
|
|
114
|
-
},
|
|
115
|
-
size44: {
|
|
116
|
-
width: 14,
|
|
117
|
-
height: 14,
|
|
118
|
-
borderRadius: 7
|
|
119
|
-
},
|
|
120
|
-
size48: {
|
|
121
|
-
width: 14,
|
|
122
|
-
height: 14,
|
|
123
|
-
borderRadius: 7
|
|
124
|
-
},
|
|
125
|
-
size52: {
|
|
126
|
-
width: 16,
|
|
127
|
-
height: 16,
|
|
128
|
-
borderRadius: 8
|
|
129
|
-
},
|
|
130
|
-
size56: {
|
|
131
|
-
width: 16,
|
|
132
|
-
height: 16,
|
|
133
|
-
borderRadius: 8
|
|
134
|
-
},
|
|
135
|
-
size64: {
|
|
136
|
-
width: 16,
|
|
137
|
-
height: 16,
|
|
138
|
-
borderRadius: 8,
|
|
139
|
-
top: -2,
|
|
140
|
-
left: -2,
|
|
141
|
-
},
|
|
142
|
-
size72: {
|
|
143
|
-
width: 18,
|
|
144
|
-
height: 18,
|
|
145
|
-
borderRadius: 9,
|
|
146
|
-
top: -3,
|
|
147
|
-
left: -3,
|
|
148
|
-
},
|
|
149
|
-
size80: {
|
|
150
|
-
width: 18,
|
|
151
|
-
height: 18,
|
|
152
|
-
borderRadius: 9,
|
|
153
|
-
top: -3,
|
|
154
|
-
left: -3,
|
|
155
|
-
},
|
|
156
|
-
size88: {
|
|
157
|
-
width: 18,
|
|
158
|
-
height: 18,
|
|
159
|
-
borderRadius: 9,
|
|
160
|
-
top: -4,
|
|
161
|
-
left: -4,
|
|
162
|
-
},
|
|
163
|
-
size96: {
|
|
164
|
-
width: 20,
|
|
165
|
-
height: 20,
|
|
166
|
-
borderRadius: 10,
|
|
167
|
-
top: -4,
|
|
168
|
-
left: -4,
|
|
169
|
-
},
|
|
170
|
-
giant: {
|
|
171
|
-
top: -5,
|
|
172
|
-
left: -5,
|
|
173
|
-
width: 24,
|
|
174
|
-
height: 24,
|
|
175
|
-
borderRadius: 12
|
|
176
|
-
}
|
|
177
80
|
});
|
|
178
81
|
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
width: 24,
|
|
212
|
-
height: 24,
|
|
213
|
-
borderRadius: 12
|
|
214
|
-
},
|
|
215
|
-
size36: {
|
|
216
|
-
width: 36,
|
|
217
|
-
height: 36,
|
|
218
|
-
borderRadius: 18
|
|
219
|
-
},
|
|
220
|
-
size44: {
|
|
221
|
-
width: 44,
|
|
222
|
-
height: 44,
|
|
223
|
-
borderRadius: 22
|
|
224
|
-
},
|
|
225
|
-
size48: {
|
|
226
|
-
width: 48,
|
|
227
|
-
height: 48,
|
|
228
|
-
borderRadius: 24
|
|
229
|
-
},
|
|
230
|
-
size52: {
|
|
231
|
-
width: 52,
|
|
232
|
-
height: 52,
|
|
233
|
-
borderRadius: 26
|
|
234
|
-
},
|
|
235
|
-
size56: {
|
|
236
|
-
width: 56,
|
|
237
|
-
height: 56,
|
|
238
|
-
borderRadius: 28
|
|
239
|
-
},
|
|
240
|
-
size64: {
|
|
241
|
-
width: 64,
|
|
242
|
-
height: 64,
|
|
243
|
-
borderRadius: 32
|
|
244
|
-
},
|
|
245
|
-
size72: {
|
|
246
|
-
width: 72,
|
|
247
|
-
height: 72,
|
|
248
|
-
borderRadius: 36
|
|
249
|
-
},
|
|
250
|
-
size80: {
|
|
251
|
-
width: 80,
|
|
252
|
-
height: 80,
|
|
253
|
-
borderRadius: 40
|
|
254
|
-
},
|
|
255
|
-
size88: {
|
|
256
|
-
width: 88,
|
|
257
|
-
height: 88,
|
|
258
|
-
borderRadius: 44
|
|
259
|
-
},
|
|
260
|
-
size96: {
|
|
261
|
-
width: 96,
|
|
262
|
-
height: 96,
|
|
263
|
-
borderRadius: 48
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
const shortName = (width) => ({
|
|
268
|
-
tiny: {
|
|
269
|
-
fontSize: ScaleSize(5, width)
|
|
270
|
-
},
|
|
271
|
-
small: {
|
|
272
|
-
fontSize: ScaleSize(11, width)
|
|
273
|
-
},
|
|
274
|
-
medium: {
|
|
275
|
-
fontSize: ScaleSize(15, width)
|
|
276
|
-
},
|
|
277
|
-
large: {
|
|
278
|
-
fontSize: ScaleSize(20, width)
|
|
279
|
-
},
|
|
280
|
-
giant: {
|
|
281
|
-
fontSize: ScaleSize(25, width)
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
export default class Avatar extends Component {
|
|
286
|
-
constructor(props) {
|
|
287
|
-
super(props);
|
|
288
|
-
this.state = {
|
|
289
|
-
hideSource: false,
|
|
290
|
-
ownUpdate: false,
|
|
291
|
-
source: props.source,
|
|
292
|
-
dimensions: {}
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
componentDidMount() {
|
|
297
|
-
const { scaleSize } = this.props;
|
|
298
|
-
if (scaleSize) {
|
|
299
|
-
this.subscription = Dimensions.addEventListener(
|
|
300
|
-
'change',
|
|
301
|
-
({ window }) => {
|
|
302
|
-
this.setState({ dimensions: window });
|
|
303
|
-
}
|
|
304
|
-
);
|
|
305
|
-
}
|
|
82
|
+
const subIconSize = (size) => {
|
|
83
|
+
switch (size) {
|
|
84
|
+
case 'giant':
|
|
85
|
+
return {
|
|
86
|
+
width: 12,
|
|
87
|
+
height: 12,
|
|
88
|
+
borderRadius: 6,
|
|
89
|
+
};
|
|
90
|
+
case 'small':
|
|
91
|
+
return {
|
|
92
|
+
width: 8,
|
|
93
|
+
height: 8,
|
|
94
|
+
borderRadius: 4,
|
|
95
|
+
};
|
|
96
|
+
case 'medium':
|
|
97
|
+
return {
|
|
98
|
+
width: 12,
|
|
99
|
+
height: 12,
|
|
100
|
+
borderRadius: 6,
|
|
101
|
+
};
|
|
102
|
+
case 'large':
|
|
103
|
+
return {
|
|
104
|
+
width: 12,
|
|
105
|
+
height: 12,
|
|
106
|
+
borderRadius: 6,
|
|
107
|
+
};
|
|
108
|
+
default:
|
|
109
|
+
return {
|
|
110
|
+
width: 12,
|
|
111
|
+
height: 12,
|
|
112
|
+
borderRadius: 6,
|
|
113
|
+
};
|
|
306
114
|
}
|
|
115
|
+
};
|
|
307
116
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
117
|
+
const avatarSize = (size) => {
|
|
118
|
+
switch (size) {
|
|
119
|
+
case 'tiny':
|
|
120
|
+
return {
|
|
121
|
+
width: 16,
|
|
122
|
+
height: 16,
|
|
123
|
+
};
|
|
124
|
+
case 'small': {
|
|
125
|
+
return {
|
|
126
|
+
width: 32,
|
|
127
|
+
height: 32,
|
|
128
|
+
};
|
|
312
129
|
}
|
|
130
|
+
case 'medium':
|
|
131
|
+
return {
|
|
132
|
+
width: 40,
|
|
133
|
+
height: 40,
|
|
134
|
+
};
|
|
135
|
+
case 'large':
|
|
136
|
+
return {
|
|
137
|
+
width: 56,
|
|
138
|
+
height: 56,
|
|
139
|
+
};
|
|
140
|
+
case 'giant':
|
|
141
|
+
return {
|
|
142
|
+
width: 72,
|
|
143
|
+
height: 72,
|
|
144
|
+
};
|
|
145
|
+
default:
|
|
146
|
+
return {
|
|
147
|
+
width: 40,
|
|
148
|
+
height: 40,
|
|
149
|
+
};
|
|
313
150
|
}
|
|
151
|
+
};
|
|
314
152
|
|
|
315
|
-
|
|
316
|
-
|
|
153
|
+
const shortName = (size) => {
|
|
154
|
+
switch (size) {
|
|
155
|
+
case 'tiny':
|
|
317
156
|
return {
|
|
318
|
-
|
|
157
|
+
fontSize: ScaleSize(8),
|
|
158
|
+
lineHeight: 16,
|
|
159
|
+
};
|
|
160
|
+
case 'small':
|
|
161
|
+
return {
|
|
162
|
+
fontSize: ScaleSize(14),
|
|
163
|
+
lineHeight: 20,
|
|
164
|
+
};
|
|
165
|
+
case 'medium':
|
|
166
|
+
return {
|
|
167
|
+
fontSize: ScaleSize(18),
|
|
168
|
+
lineHeight: 22,
|
|
169
|
+
};
|
|
170
|
+
case 'large':
|
|
171
|
+
return {
|
|
172
|
+
fontSize: ScaleSize(25),
|
|
173
|
+
};
|
|
174
|
+
case 'giant':
|
|
175
|
+
return {
|
|
176
|
+
fontSize: ScaleSize(32),
|
|
177
|
+
};
|
|
178
|
+
default:
|
|
179
|
+
return {
|
|
180
|
+
fontSize: ScaleSize(18),
|
|
181
|
+
lineHeight: 22,
|
|
319
182
|
};
|
|
320
|
-
} if (!isEqual(nextProps.source, prevState.source)) {
|
|
321
|
-
return { source: nextProps.source, hideSource: false };
|
|
322
|
-
}
|
|
323
|
-
return null;
|
|
324
183
|
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const Avatar = ({
|
|
187
|
+
resizeMode,
|
|
188
|
+
cached,
|
|
189
|
+
quality,
|
|
190
|
+
size,
|
|
191
|
+
shape,
|
|
192
|
+
name,
|
|
193
|
+
source,
|
|
194
|
+
onPress,
|
|
195
|
+
style,
|
|
196
|
+
subIcon,
|
|
197
|
+
topIcon,
|
|
198
|
+
loading,
|
|
199
|
+
}) => {
|
|
200
|
+
const { width, height } = avatarSize(size);
|
|
201
|
+
const { fontSize, lineHeight } = shortName(size);
|
|
202
|
+
const {
|
|
203
|
+
width: iconWidth,
|
|
204
|
+
height: iconHeight,
|
|
205
|
+
borderRadius: iconRadius,
|
|
206
|
+
} = subIconSize(size);
|
|
207
|
+
|
|
208
|
+
const imageSource = ValueUtil.getImageSource(source);
|
|
325
209
|
|
|
326
|
-
getContactShortName = (name) => {
|
|
210
|
+
const getContactShortName = (name) => {
|
|
327
211
|
if (!name) return '';
|
|
328
212
|
const shortNameList = name.split(' ', 2);
|
|
329
213
|
const alphabet = [];
|
|
@@ -333,185 +217,191 @@ export default class Avatar extends Component {
|
|
|
333
217
|
}
|
|
334
218
|
});
|
|
335
219
|
return alphabet.join('');
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const shortedName = this.getContactShortName(name);
|
|
341
|
-
const shortNameStyle = this.mapShortNameStyle(size);
|
|
342
|
-
return (
|
|
343
|
-
<View style={[styles.shortNameView, avatarStyle]}>
|
|
344
|
-
<Text.H4 style={[styles.shortNameText, shortNameStyle]}>{shortedName}</Text.H4>
|
|
345
|
-
</View>
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
return <View />;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
isUrl(url) {
|
|
352
|
-
const expression = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/gi;
|
|
220
|
+
};
|
|
221
|
+
const isUrl = (url) => {
|
|
222
|
+
const expression =
|
|
223
|
+
/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/gi;
|
|
353
224
|
return expression.test(url);
|
|
354
|
-
}
|
|
225
|
+
};
|
|
355
226
|
|
|
356
|
-
isValidImageUrl = (source) => {
|
|
357
|
-
const validSource = source &&
|
|
227
|
+
const isValidImageUrl = (source) => {
|
|
228
|
+
const validSource = source && source.uri && isUrl(source.uri);
|
|
358
229
|
return validSource;
|
|
359
|
-
}
|
|
230
|
+
};
|
|
360
231
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
let shortNameStyle = {};
|
|
371
|
-
const { dimensions } = this.state;
|
|
372
|
-
switch (size) {
|
|
373
|
-
case AvatarSize.tiny: {
|
|
374
|
-
shortNameStyle = shortName(dimensions?.width || null).tiny;
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
377
|
-
case AvatarSize.small: {
|
|
378
|
-
shortNameStyle = shortName(dimensions?.width || null).small;
|
|
379
|
-
break;
|
|
380
|
-
}
|
|
381
|
-
case AvatarSize.medium: {
|
|
382
|
-
shortNameStyle = shortName(dimensions?.width || null).medium;
|
|
383
|
-
break;
|
|
384
|
-
}
|
|
385
|
-
case AvatarSize.large: {
|
|
386
|
-
shortNameStyle = shortName(dimensions?.width || null).large;
|
|
387
|
-
break;
|
|
388
|
-
}
|
|
389
|
-
case AvatarSize.giant: {
|
|
390
|
-
shortNameStyle = shortName(dimensions?.width || null).giant;
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
default:
|
|
394
|
-
shortNameStyle = shortName(dimensions?.width || null).small;
|
|
232
|
+
const mapAvatarQuality = (url, quality) => {
|
|
233
|
+
if (!quality || quality === AvatarQuality.medium) {
|
|
234
|
+
return url;
|
|
235
|
+
}
|
|
236
|
+
if (quality === AvatarQuality.low) {
|
|
237
|
+
return url.replace('.png', '_s64.png');
|
|
238
|
+
}
|
|
239
|
+
if (quality === AvatarQuality.high) {
|
|
240
|
+
return url.replace('.png', '_s512.png');
|
|
395
241
|
}
|
|
396
|
-
return shortNameStyle;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
mapSubIconSize = (size) => {
|
|
400
|
-
const { dimensions } = this.state;
|
|
401
|
-
const subIconStyle = subIconSize(dimensions?.width || null).small;
|
|
402
|
-
if (subIconSize(dimensions?.width || null)[size]) return subIconSize(dimensions?.width || null)[size];
|
|
403
|
-
return subIconStyle;
|
|
404
|
-
}
|
|
405
242
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const borderWidth = get(style, 'borderWidth', 1);
|
|
409
|
-
const containerWidth = Math.round(avatarStyle.width + 2 + borderWidth);
|
|
410
|
-
return {
|
|
411
|
-
width: containerWidth,
|
|
412
|
-
height: containerWidth,
|
|
413
|
-
borderRadius: containerWidth / 2,
|
|
414
|
-
borderWidth,
|
|
415
|
-
borderColor: Colors.black_01
|
|
416
|
-
};
|
|
417
|
-
}
|
|
243
|
+
return url;
|
|
244
|
+
};
|
|
418
245
|
|
|
419
|
-
onLoadSourceError = () => {
|
|
420
|
-
this.
|
|
421
|
-
|
|
246
|
+
const onLoadSourceError = (imageSource) => {
|
|
247
|
+
if (this.imageSource?.uri !== imageSource?.uri) {
|
|
248
|
+
this.imageSource = imageSource;
|
|
249
|
+
this.setState({ hideSource: true, ownUpdate: true });
|
|
250
|
+
}
|
|
251
|
+
};
|
|
422
252
|
|
|
423
|
-
renderSubIcon = () => {
|
|
424
|
-
const
|
|
425
|
-
if (
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
253
|
+
const renderSubIcon = () => {
|
|
254
|
+
// const subIconSizeStyle = this.mapSubIconSize(size);
|
|
255
|
+
if (subIcon && shape === 'circle' && size !== 'tiny') {
|
|
256
|
+
return (
|
|
257
|
+
<View style={styles.subIcon}>
|
|
258
|
+
<Image
|
|
259
|
+
source={subIcon}
|
|
260
|
+
style={[
|
|
261
|
+
{
|
|
262
|
+
width: iconWidth,
|
|
263
|
+
height: iconHeight,
|
|
264
|
+
borderRadius: iconRadius,
|
|
265
|
+
bottom: iconWidth / 2 - 2,
|
|
266
|
+
right: iconWidth / 2 - 2,
|
|
267
|
+
},
|
|
268
|
+
]}
|
|
269
|
+
/>
|
|
270
|
+
</View>
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
440
274
|
|
|
441
|
-
|
|
275
|
+
const renderTopIcon = () => {
|
|
276
|
+
if (topIcon && shape === 'circle' && size !== 'tiny') {
|
|
277
|
+
return (
|
|
278
|
+
<View style={styles.topIcon}>
|
|
442
279
|
<Image
|
|
443
|
-
|
|
444
|
-
|
|
280
|
+
source={topIcon}
|
|
281
|
+
style={[
|
|
282
|
+
{
|
|
283
|
+
width: iconWidth,
|
|
284
|
+
height: iconHeight,
|
|
285
|
+
borderRadius: iconRadius,
|
|
286
|
+
top: iconWidth / 2 - 2,
|
|
287
|
+
right: iconWidth / 2 - 2,
|
|
288
|
+
},
|
|
289
|
+
]}
|
|
445
290
|
/>
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
291
|
+
</View>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
451
295
|
|
|
452
|
-
|
|
453
|
-
const { onPress } = this.props;
|
|
296
|
+
const onPressIcon = () => {
|
|
454
297
|
if (onPress && typeof onPress === 'function') onPress();
|
|
455
|
-
}
|
|
298
|
+
};
|
|
456
299
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const { hideSource } = this.state;
|
|
462
|
-
const avatarStyle = this.mapStyleFromSize(size);
|
|
463
|
-
const containerSize = this.extractSize(avatarStyle);
|
|
464
|
-
const imageSource = ValueUtil.getImageSource(source);
|
|
465
|
-
const showName = typeof imageSource === 'object' && Object.keys(imageSource).length === 0 && typeof imageSource !== 'number';
|
|
466
|
-
const inner = (
|
|
467
|
-
<View style={[styles.container, containerSize, style]}>
|
|
468
|
-
{(showName || hideSource) ? this.renderShortName(name, avatarStyle, size) : <View />}
|
|
469
|
-
{this.isValidImageUrl(imageSource) && !hideSource
|
|
470
|
-
? (
|
|
471
|
-
<Image
|
|
472
|
-
cached={cached}
|
|
473
|
-
loading={loading || isShowLoading}
|
|
474
|
-
source={imageSource}
|
|
475
|
-
onError={this.onLoadSourceError}
|
|
476
|
-
style={avatarStyle}
|
|
477
|
-
resizeMode={resizeMode}
|
|
478
|
-
{...extraPropsImage}
|
|
479
|
-
/>
|
|
480
|
-
) : <View />}
|
|
481
|
-
{this.renderSubIcon()}
|
|
482
|
-
</View>
|
|
483
|
-
);
|
|
484
|
-
if (onPress) {
|
|
300
|
+
const renderShortName = () => {
|
|
301
|
+
if (name) {
|
|
302
|
+
const shortedName = getContactShortName(name);
|
|
303
|
+
// const shortNameStyle = mapShortNameStyle(size);
|
|
485
304
|
return (
|
|
486
|
-
<
|
|
487
|
-
{
|
|
488
|
-
|
|
305
|
+
<View
|
|
306
|
+
style={[
|
|
307
|
+
{
|
|
308
|
+
width,
|
|
309
|
+
height,
|
|
310
|
+
borderRadius:
|
|
311
|
+
shape === 'circle' ? width / 2 : Radius.XS,
|
|
312
|
+
},
|
|
313
|
+
styles.shortNameView,
|
|
314
|
+
]}>
|
|
315
|
+
<Text
|
|
316
|
+
style={{ fontSize, lineHeight, color: Colors.pink_03 }}>
|
|
317
|
+
{shortedName}
|
|
318
|
+
</Text>
|
|
319
|
+
</View>
|
|
489
320
|
);
|
|
490
321
|
}
|
|
491
|
-
return
|
|
322
|
+
return <View />;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
if (imageSource?.uri) {
|
|
326
|
+
imageSource.priority = 'high';
|
|
327
|
+
imageSource.uri = mapAvatarQuality(imageSource.uri, quality);
|
|
328
|
+
// if doest not have time query, set default cache time to 1 day
|
|
329
|
+
if (!imageSource.uri?.includes('?') && cached) {
|
|
330
|
+
const midnight = new Date().setHours(0, 0, 0, 0);
|
|
331
|
+
imageSource.uri = `${imageSource.uri}?time=${midnight}`;
|
|
332
|
+
}
|
|
492
333
|
}
|
|
493
|
-
|
|
334
|
+
|
|
335
|
+
const renderImage = () => {
|
|
336
|
+
return (
|
|
337
|
+
<Image
|
|
338
|
+
cached={cached}
|
|
339
|
+
resizeMode={resizeMode}
|
|
340
|
+
onLoadSourceError={() => onLoadSourceError(source)}
|
|
341
|
+
source={source}
|
|
342
|
+
loading={loading}
|
|
343
|
+
style={[
|
|
344
|
+
{
|
|
345
|
+
width,
|
|
346
|
+
height,
|
|
347
|
+
borderRadius:
|
|
348
|
+
shape === 'circle' ? width / 2 : Radius.XS,
|
|
349
|
+
},
|
|
350
|
+
]}
|
|
351
|
+
/>
|
|
352
|
+
);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<TouchableOpacity
|
|
357
|
+
activeOpacity={!!onPress ? 0.5 : 1}
|
|
358
|
+
style={[style]}
|
|
359
|
+
onPress={onPressIcon}>
|
|
360
|
+
<View
|
|
361
|
+
style={{
|
|
362
|
+
alignSelf: 'baseline',
|
|
363
|
+
}}>
|
|
364
|
+
{!!imageSource && isValidImageUrl(imageSource)
|
|
365
|
+
? renderImage()
|
|
366
|
+
: renderShortName()}
|
|
367
|
+
{renderTopIcon()}
|
|
368
|
+
{renderSubIcon()}
|
|
369
|
+
</View>
|
|
370
|
+
</TouchableOpacity>
|
|
371
|
+
);
|
|
372
|
+
};
|
|
494
373
|
|
|
495
374
|
Avatar.propTypes = {
|
|
496
375
|
name: PropTypes.string,
|
|
497
|
-
|
|
498
|
-
size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'giant',
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
376
|
+
quality: PropTypes.oneOf(['low', 'medium', 'high']),
|
|
377
|
+
size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'giant']),
|
|
378
|
+
source: PropTypes.oneOfType([
|
|
379
|
+
PropTypes.shape({ uri: PropTypes.string }),
|
|
380
|
+
PropTypes.number,
|
|
381
|
+
PropTypes.string,
|
|
382
|
+
]),
|
|
383
|
+
subIcon: PropTypes.string,
|
|
384
|
+
topIcon: PropTypes.string,
|
|
385
|
+
subIconSource: PropTypes.oneOfType([
|
|
386
|
+
PropTypes.shape({ uri: PropTypes.string }),
|
|
387
|
+
PropTypes.number,
|
|
388
|
+
PropTypes.string,
|
|
389
|
+
]),
|
|
505
390
|
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
506
391
|
onPress: PropTypes.func,
|
|
507
392
|
loading: PropTypes.bool,
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
extraPropsImage: PropTypes.object
|
|
393
|
+
extraPropsImage: PropTypes.object,
|
|
394
|
+
shape: PropTypes.oneOf(['circle', 'square']),
|
|
511
395
|
};
|
|
512
396
|
|
|
513
397
|
Avatar.defaultProps = {
|
|
514
398
|
resizeMode: 'cover',
|
|
515
399
|
cached: true,
|
|
516
|
-
scaleSize: false
|
|
400
|
+
scaleSize: false,
|
|
401
|
+
quality: 'medium',
|
|
402
|
+
size: 'small',
|
|
403
|
+
shape: 'circle',
|
|
404
|
+
name: '',
|
|
517
405
|
};
|
|
406
|
+
|
|
407
|
+
export default Avatar;
|
package/Avatar.web.js
CHANGED
|
@@ -11,6 +11,35 @@ import { Icons as IconSource } from '../../core/icons';
|
|
|
11
11
|
import Text from '../../core/components/typography';
|
|
12
12
|
import { RFValueHorizontal as ScaleSize } from '../../core/components/typography/reponsiveSize';
|
|
13
13
|
|
|
14
|
+
export const AvatarQuality = {
|
|
15
|
+
low: 'low',
|
|
16
|
+
medium: 'medium',
|
|
17
|
+
high: 'high',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const COLORS = [
|
|
21
|
+
'#3683f3',
|
|
22
|
+
'#ea63af',
|
|
23
|
+
'#f94889',
|
|
24
|
+
'#82b6da',
|
|
25
|
+
'#2fc093',
|
|
26
|
+
'#7b4a41',
|
|
27
|
+
'#ff97bc',
|
|
28
|
+
'#4130d7',
|
|
29
|
+
'#c3c3c3',
|
|
30
|
+
'#f7ae2f',
|
|
31
|
+
'#b04595',
|
|
32
|
+
'#57b748',
|
|
33
|
+
'#ff8900',
|
|
34
|
+
'#7841bf',
|
|
35
|
+
'#be3f3e',
|
|
36
|
+
'#c51515',
|
|
37
|
+
'#8e6472',
|
|
38
|
+
'#fed27d',
|
|
39
|
+
'#ff6f5d',
|
|
40
|
+
'#05b8ae',
|
|
41
|
+
];
|
|
42
|
+
|
|
14
43
|
export const AvatarSize = {
|
|
15
44
|
tiny: 'tiny',
|
|
16
45
|
small: 'small',
|
|
@@ -287,6 +316,7 @@ const shortName = (width) => ({
|
|
|
287
316
|
export default class Avatar extends Component {
|
|
288
317
|
constructor(props) {
|
|
289
318
|
super(props);
|
|
319
|
+
this.color = this.getAvatarColor(props.name);
|
|
290
320
|
this.state = {
|
|
291
321
|
hideSource: false,
|
|
292
322
|
ownUpdate: false,
|
|
@@ -301,7 +331,9 @@ export default class Avatar extends Component {
|
|
|
301
331
|
this.subscription = Dimensions.addEventListener(
|
|
302
332
|
'change',
|
|
303
333
|
({ window }) => {
|
|
304
|
-
|
|
334
|
+
if(window?.height > 0 && window?.width > 0) {
|
|
335
|
+
this.setState({ dimensions: window });
|
|
336
|
+
}
|
|
305
337
|
}
|
|
306
338
|
);
|
|
307
339
|
}
|
|
@@ -356,10 +388,24 @@ export default class Avatar extends Component {
|
|
|
356
388
|
}
|
|
357
389
|
|
|
358
390
|
isValidImageUrl = (source) => {
|
|
359
|
-
const validSource = source &&
|
|
391
|
+
const validSource = source && source.uri && this.isUrl(source.uri);
|
|
360
392
|
return validSource;
|
|
361
393
|
}
|
|
362
394
|
|
|
395
|
+
mapAvatarQuality = (url, quality) => {
|
|
396
|
+
if (!quality || quality === AvatarQuality.medium) {
|
|
397
|
+
return url;
|
|
398
|
+
}
|
|
399
|
+
if (quality === AvatarQuality.low) {
|
|
400
|
+
return url.replace('.png', '_s64.png');
|
|
401
|
+
}
|
|
402
|
+
if (quality === AvatarQuality.high) {
|
|
403
|
+
return url.replace('.png', '_s512.png');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return url;
|
|
407
|
+
}
|
|
408
|
+
|
|
363
409
|
mapStyleFromSize = (size) => {
|
|
364
410
|
const { dimensions } = this.state;
|
|
365
411
|
const avatarStyle = avatarSize(dimensions?.width || null).small;
|
|
@@ -418,6 +464,16 @@ export default class Avatar extends Component {
|
|
|
418
464
|
};
|
|
419
465
|
}
|
|
420
466
|
|
|
467
|
+
getAvatarColor(name) {
|
|
468
|
+
const shortName = this.getContactShortName(name)
|
|
469
|
+
if (!shortName) return "#d5d6d6"
|
|
470
|
+
const firstLetter = shortName[0].charCodeAt(0)
|
|
471
|
+
let colorIndex = Number(firstLetter) % 26
|
|
472
|
+
if (colorIndex > 19) colorIndex = 25 - colorIndex
|
|
473
|
+
return COLORS[colorIndex]
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
|
|
421
477
|
onLoadSourceError = () => {
|
|
422
478
|
this.setState({ hideSource: true, ownUpdate: true });
|
|
423
479
|
}
|
|
@@ -458,13 +514,24 @@ export default class Avatar extends Component {
|
|
|
458
514
|
|
|
459
515
|
render() {
|
|
460
516
|
const {
|
|
461
|
-
size, source, name, resizeMode, style, onPress, isShowLoading, loading, cached, extraPropsImage
|
|
517
|
+
size, source, name, resizeMode, style, onPress, isShowLoading, loading, cached, extraPropsImage, quality
|
|
462
518
|
} = this.props;
|
|
463
519
|
const { hideSource } = this.state;
|
|
464
520
|
const avatarStyle = this.mapStyleFromSize(size);
|
|
465
521
|
const containerSize = this.extractSize(avatarStyle);
|
|
466
522
|
const imageSource = ValueUtil.getImageSource(source);
|
|
467
523
|
const showName = typeof imageSource === 'object' && Object.keys(imageSource).length === 0 && typeof imageSource !== 'number';
|
|
524
|
+
// add priority high for avatar
|
|
525
|
+
if (imageSource?.uri) {
|
|
526
|
+
imageSource.priority = 'high';
|
|
527
|
+
imageSource.uri = this.mapAvatarQuality(imageSource.uri, quality);
|
|
528
|
+
// if doest not have time query, set default cache time to 1 day
|
|
529
|
+
if (!imageSource.uri?.includes('?') && cached) {
|
|
530
|
+
const midnight = new Date().setHours(0, 0, 0, 0);
|
|
531
|
+
imageSource.uri = `${imageSource.uri}?time=${midnight}`;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
468
535
|
const inner = (
|
|
469
536
|
<View style={[styles.container, containerSize, style]}>
|
|
470
537
|
{(showName || hideSource) ? this.renderShortName(name, avatarStyle, size) : <View />}
|
|
@@ -497,6 +564,7 @@ export default class Avatar extends Component {
|
|
|
497
564
|
Avatar.propTypes = {
|
|
498
565
|
name: PropTypes.string,
|
|
499
566
|
resizeMode: PropTypes.string,
|
|
567
|
+
quality: PropTypes.oneOf(['low', 'medium', 'high']),
|
|
500
568
|
size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'giant', 'size8', 'size24', 'size36', 'size44', 'size48', 'size52', 'size56', 'size64', 'size72', 'size80', 'size88', 'size96',
|
|
501
569
|
PropTypes.shape({
|
|
502
570
|
width: PropTypes.number, height: PropTypes.number, borderRadius: PropTypes.number
|
|
@@ -515,5 +583,6 @@ Avatar.propTypes = {
|
|
|
515
583
|
Avatar.defaultProps = {
|
|
516
584
|
resizeMode: 'cover',
|
|
517
585
|
cached: true,
|
|
518
|
-
scaleSize: false
|
|
586
|
+
scaleSize: false,
|
|
587
|
+
quality: 'medium',
|
|
519
588
|
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
"name": "@momo-kits/avatar",
|
|
3
|
+
"version": "0.0.62-beta.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"dependencies": {},
|
|
7
|
+
"peerDependencies": {
|
|
8
|
+
"react-native": ">=0.55",
|
|
9
|
+
"prop-types": "^15.7.2",
|
|
10
|
+
"react": "16.9.0",
|
|
11
|
+
"@momo-kits/core-v2": ">=0.0.5-beta",
|
|
12
|
+
"lodash": "^4.17.15"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {},
|
|
15
|
+
"license": "MoMo"
|
|
16
16
|
}
|