react-native-gifted-chat 2.4.1 → 2.6.0
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/README.md +34 -14
- package/lib/Actions.d.ts +5 -6
- package/lib/Actions.js +16 -13
- package/lib/Actions.js.map +1 -1
- package/lib/Avatar.d.ts +9 -25
- package/lib/Avatar.js +12 -18
- package/lib/Avatar.js.flow +1 -1
- package/lib/Avatar.js.map +1 -1
- package/lib/Bubble.d.ts +29 -30
- package/lib/Bubble.js +99 -92
- package/lib/Bubble.js.flow +2 -2
- package/lib/Bubble.js.map +1 -1
- package/lib/Composer.d.ts +1 -1
- package/lib/Composer.js +30 -32
- package/lib/Composer.js.map +1 -1
- package/lib/Constant.js +1 -0
- package/lib/Constant.js.map +1 -1
- package/lib/Day.d.ts +3 -15
- package/lib/Day.js +2 -14
- package/lib/Day.js.flow +1 -1
- package/lib/Day.js.map +1 -1
- package/lib/GiftedAvatar.d.ts +7 -7
- package/lib/GiftedAvatar.js +30 -29
- package/lib/GiftedAvatar.js.map +1 -1
- package/lib/GiftedChat.d.ts +15 -89
- package/lib/GiftedChat.js +204 -350
- package/lib/GiftedChat.js.flow +1 -3
- package/lib/GiftedChat.js.map +1 -1
- package/lib/GiftedChatContext.d.ts +2 -1
- package/lib/GiftedChatContext.js.map +1 -1
- package/lib/InputToolbar.d.ts +7 -5
- package/lib/InputToolbar.js +41 -34
- package/lib/InputToolbar.js.map +1 -1
- package/lib/LoadEarlier.d.ts +4 -4
- package/lib/LoadEarlier.js +8 -6
- package/lib/LoadEarlier.js.map +1 -1
- package/lib/Message.d.ts +8 -9
- package/lib/Message.js +47 -40
- package/lib/Message.js.flow +1 -1
- package/lib/Message.js.map +1 -1
- package/lib/MessageAudio.d.ts +2 -1
- package/lib/MessageAudio.js +4 -4
- package/lib/MessageAudio.js.flow +1 -1
- package/lib/MessageAudio.js.map +1 -1
- package/lib/MessageContainer.d.ts +17 -17
- package/lib/MessageContainer.js +33 -51
- package/lib/MessageContainer.js.map +1 -1
- package/lib/MessageImage.d.ts +5 -4
- package/lib/MessageImage.js +4 -5
- package/lib/MessageImage.js.flow +1 -1
- package/lib/MessageImage.js.map +1 -1
- package/lib/MessageText.d.ts +11 -10
- package/lib/MessageText.js +5 -10
- package/lib/MessageText.js.flow +1 -1
- package/lib/MessageText.js.map +1 -1
- package/lib/MessageVideo.d.ts +2 -1
- package/lib/MessageVideo.js +4 -4
- package/lib/MessageVideo.js.flow +1 -1
- package/lib/MessageVideo.js.map +1 -1
- package/lib/Models.d.ts +7 -7
- package/lib/QuickReplies.d.ts +3 -3
- package/lib/QuickReplies.js +8 -14
- package/lib/QuickReplies.js.flow +1 -1
- package/lib/QuickReplies.js.map +1 -1
- package/lib/Send.d.ts +4 -4
- package/lib/Send.js +6 -9
- package/lib/Send.js.map +1 -1
- package/lib/SystemMessage.d.ts +6 -5
- package/lib/SystemMessage.js +1 -2
- package/lib/SystemMessage.js.flow +1 -1
- package/lib/SystemMessage.js.map +1 -1
- package/lib/Time.d.ts +7 -6
- package/lib/Time.js +1 -3
- package/lib/Time.js.flow +1 -1
- package/lib/Time.js.map +1 -1
- package/lib/TypingIndicator.d.ts +2 -1
- package/lib/TypingIndicator.js +5 -5
- package/lib/TypingIndicator.js.map +1 -1
- package/lib/hooks/useUpdateLayoutEffect.js +2 -4
- package/lib/hooks/useUpdateLayoutEffect.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/logging.d.ts +2 -2
- package/lib/logging.js.map +1 -1
- package/lib/types.js.flow +1 -1
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +2 -4
- package/lib/utils.js.map +1 -1
- package/package.json +86 -59
- package/src/Actions.tsx +114 -0
- package/src/Avatar.tsx +178 -0
- package/src/Bubble.tsx +596 -0
- package/src/Color.ts +17 -0
- package/src/Composer.tsx +147 -0
- package/src/Constant.ts +18 -0
- package/src/Day.tsx +71 -0
- package/src/GiftedAvatar.tsx +205 -0
- package/src/GiftedChat.tsx +670 -0
- package/src/GiftedChatContext.ts +23 -0
- package/src/InputToolbar.tsx +113 -0
- package/src/LoadEarlier.tsx +108 -0
- package/src/Message.tsx +229 -0
- package/src/MessageAudio.tsx +19 -0
- package/src/MessageContainer.tsx +362 -0
- package/src/MessageImage.tsx +78 -0
- package/src/MessageText.tsx +187 -0
- package/src/MessageVideo.tsx +19 -0
- package/src/Models.ts +84 -0
- package/src/QuickReplies.tsx +186 -0
- package/src/Send.tsx +102 -0
- package/src/SystemMessage.tsx +61 -0
- package/src/Time.tsx +97 -0
- package/src/TypingIndicator.tsx +108 -0
- package/src/__tests__/Actions.test.tsx +10 -0
- package/src/__tests__/Avatar.test.tsx +13 -0
- package/src/__tests__/Bubble.test.tsx +23 -0
- package/src/__tests__/Color.test.tsx +5 -0
- package/src/__tests__/Composer.test.tsx +11 -0
- package/src/__tests__/Constant.test.tsx +5 -0
- package/src/__tests__/Day.test.tsx +23 -0
- package/src/__tests__/GiftedAvatar.test.tsx +11 -0
- package/src/__tests__/GiftedChat.test.tsx +36 -0
- package/src/__tests__/InputToolbar.test.tsx +11 -0
- package/src/__tests__/LoadEarlier.test.tsx +11 -0
- package/src/__tests__/Message.test.tsx +77 -0
- package/src/__tests__/MessageContainer.test.tsx +11 -0
- package/src/__tests__/MessageImage.test.tsx +27 -0
- package/src/__tests__/MessageText.test.tsx +11 -0
- package/src/__tests__/Send.test.tsx +22 -0
- package/src/__tests__/SystemMessage.test.tsx +27 -0
- package/src/__tests__/Time.test.tsx +29 -0
- package/src/__tests__/__snapshots__/Actions.test.tsx.snap +76 -0
- package/src/__tests__/__snapshots__/Avatar.test.tsx.snap +17 -0
- package/src/__tests__/__snapshots__/Bubble.test.tsx.snap +145 -0
- package/src/__tests__/__snapshots__/Color.test.tsx.snap +21 -0
- package/src/__tests__/__snapshots__/Composer.test.tsx.snap +35 -0
- package/src/__tests__/__snapshots__/Constant.test.tsx.snap +16 -0
- package/src/__tests__/__snapshots__/Day.test.tsx.snap +37 -0
- package/src/__tests__/__snapshots__/GiftedAvatar.test.tsx.snap +22 -0
- package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +15 -0
- package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +60 -0
- package/src/__tests__/__snapshots__/LoadEarlier.test.tsx.snap +74 -0
- package/src/__tests__/__snapshots__/Message.test.tsx.snap +628 -0
- package/src/__tests__/__snapshots__/MessageContainer.test.tsx.snap +127 -0
- package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +38 -0
- package/src/__tests__/__snapshots__/MessageText.test.tsx.snap +30 -0
- package/src/__tests__/__snapshots__/Send.test.tsx.snap +129 -0
- package/src/__tests__/__snapshots__/SystemMessage.test.tsx.snap +38 -0
- package/src/__tests__/__snapshots__/Time.test.tsx.snap +33 -0
- package/src/__tests__/data.ts +8 -0
- package/src/__tests__/utils.test.ts +31 -0
- package/src/hooks/useUpdateLayoutEffect.ts +21 -0
- package/src/index.ts +4 -0
- package/src/logging.ts +8 -0
- package/src/utils.ts +39 -0
- package/.eslintignore +0 -2
- package/.eslintrc.js +0 -21
- package/jest.config.js +0 -15
package/src/Composer.tsx
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React, { useCallback, useRef } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
Platform,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
TextInput,
|
|
7
|
+
TextInputProps,
|
|
8
|
+
NativeSyntheticEvent,
|
|
9
|
+
TextInputContentSizeChangeEventData,
|
|
10
|
+
} from 'react-native'
|
|
11
|
+
import { MIN_COMPOSER_HEIGHT, DEFAULT_PLACEHOLDER } from './Constant'
|
|
12
|
+
import Color from './Color'
|
|
13
|
+
import { StylePropType } from './utils'
|
|
14
|
+
import { useCallbackOne } from 'use-memo-one'
|
|
15
|
+
|
|
16
|
+
export interface ComposerProps {
|
|
17
|
+
composerHeight?: number
|
|
18
|
+
text?: string
|
|
19
|
+
placeholder?: string
|
|
20
|
+
placeholderTextColor?: string
|
|
21
|
+
textInputProps?: Partial<TextInputProps>
|
|
22
|
+
textInputStyle?: TextInputProps['style']
|
|
23
|
+
textInputAutoFocus?: boolean
|
|
24
|
+
keyboardAppearance?: TextInputProps['keyboardAppearance']
|
|
25
|
+
multiline?: boolean
|
|
26
|
+
disableComposer?: boolean
|
|
27
|
+
onTextChanged?(text: string): void
|
|
28
|
+
onInputSizeChanged?(layout: { width: number, height: number }): void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function Composer ({
|
|
32
|
+
composerHeight = MIN_COMPOSER_HEIGHT,
|
|
33
|
+
disableComposer = false,
|
|
34
|
+
keyboardAppearance = 'default',
|
|
35
|
+
multiline = true,
|
|
36
|
+
onInputSizeChanged,
|
|
37
|
+
onTextChanged,
|
|
38
|
+
placeholder = DEFAULT_PLACEHOLDER,
|
|
39
|
+
placeholderTextColor = Color.defaultColor,
|
|
40
|
+
text = '',
|
|
41
|
+
textInputAutoFocus = false,
|
|
42
|
+
textInputProps,
|
|
43
|
+
textInputStyle,
|
|
44
|
+
}: ComposerProps): React.ReactElement {
|
|
45
|
+
const dimensionsRef = useRef<{ width: number, height: number }>()
|
|
46
|
+
|
|
47
|
+
const determineInputSizeChange = useCallbackOne(
|
|
48
|
+
(dimensions: { width: number, height: number }) => {
|
|
49
|
+
// Support earlier versions of React Native on Android.
|
|
50
|
+
if (!dimensions)
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
if (
|
|
54
|
+
!dimensionsRef.current ||
|
|
55
|
+
(dimensionsRef.current &&
|
|
56
|
+
(dimensionsRef.current.width !== dimensions.width ||
|
|
57
|
+
dimensionsRef.current.height !== dimensions.height))
|
|
58
|
+
) {
|
|
59
|
+
dimensionsRef.current = dimensions
|
|
60
|
+
onInputSizeChanged?.(dimensions)
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
[onInputSizeChanged]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
const handleContentSizeChange = useCallback(
|
|
67
|
+
({
|
|
68
|
+
nativeEvent: { contentSize },
|
|
69
|
+
}: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) =>
|
|
70
|
+
determineInputSizeChange(contentSize),
|
|
71
|
+
[determineInputSizeChange]
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<TextInput
|
|
76
|
+
testID={placeholder}
|
|
77
|
+
accessible
|
|
78
|
+
accessibilityLabel={placeholder}
|
|
79
|
+
placeholder={placeholder}
|
|
80
|
+
placeholderTextColor={placeholderTextColor}
|
|
81
|
+
multiline={multiline}
|
|
82
|
+
editable={!disableComposer}
|
|
83
|
+
onContentSizeChange={handleContentSizeChange}
|
|
84
|
+
onChangeText={onTextChanged}
|
|
85
|
+
style={[
|
|
86
|
+
styles.textInput,
|
|
87
|
+
textInputStyle,
|
|
88
|
+
{
|
|
89
|
+
height: composerHeight,
|
|
90
|
+
...Platform.select({
|
|
91
|
+
web: {
|
|
92
|
+
outlineWidth: 0,
|
|
93
|
+
outlineColor: 'transparent',
|
|
94
|
+
outlineOffset: 0,
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
]}
|
|
99
|
+
autoFocus={textInputAutoFocus}
|
|
100
|
+
value={text}
|
|
101
|
+
enablesReturnKeyAutomatically
|
|
102
|
+
underlineColorAndroid='transparent'
|
|
103
|
+
keyboardAppearance={keyboardAppearance}
|
|
104
|
+
{...textInputProps}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
Composer.propTypes = {
|
|
110
|
+
composerHeight: PropTypes.number,
|
|
111
|
+
text: PropTypes.string,
|
|
112
|
+
placeholder: PropTypes.string,
|
|
113
|
+
placeholderTextColor: PropTypes.string,
|
|
114
|
+
textInputProps: PropTypes.object,
|
|
115
|
+
onTextChanged: PropTypes.func,
|
|
116
|
+
onInputSizeChanged: PropTypes.func,
|
|
117
|
+
multiline: PropTypes.bool,
|
|
118
|
+
disableComposer: PropTypes.bool,
|
|
119
|
+
textInputStyle: StylePropType,
|
|
120
|
+
textInputAutoFocus: PropTypes.bool,
|
|
121
|
+
keyboardAppearance: PropTypes.string,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const styles = StyleSheet.create({
|
|
125
|
+
textInput: {
|
|
126
|
+
flex: 1,
|
|
127
|
+
marginLeft: 10,
|
|
128
|
+
fontSize: 16,
|
|
129
|
+
lineHeight: 22,
|
|
130
|
+
...Platform.select({
|
|
131
|
+
web: {
|
|
132
|
+
paddingTop: 6,
|
|
133
|
+
paddingLeft: 4,
|
|
134
|
+
},
|
|
135
|
+
}),
|
|
136
|
+
marginTop: Platform.select({
|
|
137
|
+
ios: 6,
|
|
138
|
+
android: 0,
|
|
139
|
+
web: 6,
|
|
140
|
+
}),
|
|
141
|
+
marginBottom: Platform.select({
|
|
142
|
+
ios: 5,
|
|
143
|
+
android: 3,
|
|
144
|
+
web: 4,
|
|
145
|
+
}),
|
|
146
|
+
},
|
|
147
|
+
})
|
package/src/Constant.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Platform } from 'react-native'
|
|
2
|
+
|
|
3
|
+
export const MIN_COMPOSER_HEIGHT = Platform.select({
|
|
4
|
+
ios: 33,
|
|
5
|
+
android: 41,
|
|
6
|
+
web: 34,
|
|
7
|
+
windows: 34,
|
|
8
|
+
})
|
|
9
|
+
export const MAX_COMPOSER_HEIGHT = 200
|
|
10
|
+
export const DEFAULT_PLACEHOLDER = 'Type a message...'
|
|
11
|
+
export const DATE_FORMAT = 'll'
|
|
12
|
+
export const TIME_FORMAT = 'LT'
|
|
13
|
+
|
|
14
|
+
export const TEST_ID = {
|
|
15
|
+
WRAPPER: 'GC_WRAPPER',
|
|
16
|
+
LOADING_WRAPPER: 'GC_LOADING_CONTAINER',
|
|
17
|
+
SEND_TOUCHABLE: 'GC_SEND_TOUCHABLE',
|
|
18
|
+
}
|
package/src/Day.tsx
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import {
|
|
3
|
+
StyleSheet,
|
|
4
|
+
Text,
|
|
5
|
+
View,
|
|
6
|
+
StyleProp,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
TextStyle,
|
|
9
|
+
TextProps,
|
|
10
|
+
} from 'react-native'
|
|
11
|
+
import dayjs from 'dayjs'
|
|
12
|
+
|
|
13
|
+
import Color from './Color'
|
|
14
|
+
import { isSameDay } from './utils'
|
|
15
|
+
import { DATE_FORMAT } from './Constant'
|
|
16
|
+
import { IMessage } from './Models'
|
|
17
|
+
|
|
18
|
+
import { useChatContext } from './GiftedChatContext'
|
|
19
|
+
|
|
20
|
+
const styles = StyleSheet.create({
|
|
21
|
+
container: {
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
justifyContent: 'center',
|
|
24
|
+
marginTop: 5,
|
|
25
|
+
marginBottom: 10,
|
|
26
|
+
},
|
|
27
|
+
text: {
|
|
28
|
+
backgroundColor: Color.backgroundTransparent,
|
|
29
|
+
color: Color.defaultColor,
|
|
30
|
+
fontSize: 12,
|
|
31
|
+
fontWeight: '600',
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export interface DayProps<TMessage extends IMessage = IMessage> {
|
|
36
|
+
currentMessage: TMessage
|
|
37
|
+
nextMessage?: TMessage
|
|
38
|
+
previousMessage?: TMessage
|
|
39
|
+
containerStyle?: StyleProp<ViewStyle>
|
|
40
|
+
wrapperStyle?: StyleProp<ViewStyle>
|
|
41
|
+
textStyle?: StyleProp<TextStyle>
|
|
42
|
+
textProps?: TextProps
|
|
43
|
+
dateFormat?: string
|
|
44
|
+
inverted?: boolean
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function Day<TMessage extends IMessage = IMessage> ({
|
|
48
|
+
dateFormat = DATE_FORMAT,
|
|
49
|
+
currentMessage,
|
|
50
|
+
previousMessage,
|
|
51
|
+
containerStyle,
|
|
52
|
+
wrapperStyle,
|
|
53
|
+
textStyle,
|
|
54
|
+
}: DayProps<TMessage>) {
|
|
55
|
+
const { getLocale } = useChatContext()
|
|
56
|
+
|
|
57
|
+
if (currentMessage == null || isSameDay(currentMessage, previousMessage))
|
|
58
|
+
return null
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<View style={[styles.container, containerStyle]}>
|
|
62
|
+
<View style={wrapperStyle}>
|
|
63
|
+
<Text style={[styles.text, textStyle]}>
|
|
64
|
+
{dayjs(currentMessage.createdAt)
|
|
65
|
+
.locale(getLocale())
|
|
66
|
+
.format(dateFormat)}
|
|
67
|
+
</Text>
|
|
68
|
+
</View>
|
|
69
|
+
</View>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import {
|
|
4
|
+
Image,
|
|
5
|
+
Text,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
View,
|
|
8
|
+
StyleSheet,
|
|
9
|
+
StyleProp,
|
|
10
|
+
ImageStyle,
|
|
11
|
+
TextStyle,
|
|
12
|
+
} from 'react-native'
|
|
13
|
+
import Color from './Color'
|
|
14
|
+
import { User } from './Models'
|
|
15
|
+
import { StylePropType } from './utils'
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
carrot,
|
|
19
|
+
emerald,
|
|
20
|
+
peterRiver,
|
|
21
|
+
wisteria,
|
|
22
|
+
alizarin,
|
|
23
|
+
turquoise,
|
|
24
|
+
midnightBlue,
|
|
25
|
+
} = Color
|
|
26
|
+
|
|
27
|
+
const styles = StyleSheet.create({
|
|
28
|
+
avatarStyle: {
|
|
29
|
+
justifyContent: 'center',
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
width: 40,
|
|
32
|
+
height: 40,
|
|
33
|
+
borderRadius: 20,
|
|
34
|
+
},
|
|
35
|
+
avatarTransparent: {
|
|
36
|
+
backgroundColor: Color.backgroundTransparent,
|
|
37
|
+
},
|
|
38
|
+
textStyle: {
|
|
39
|
+
color: Color.white,
|
|
40
|
+
fontSize: 16,
|
|
41
|
+
backgroundColor: Color.backgroundTransparent,
|
|
42
|
+
fontWeight: '100',
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
export interface GiftedAvatarProps {
|
|
47
|
+
user?: User
|
|
48
|
+
avatarStyle?: StyleProp<ImageStyle>
|
|
49
|
+
textStyle?: StyleProp<TextStyle>
|
|
50
|
+
onPress?: (props: GiftedAvatarProps) => void
|
|
51
|
+
onLongPress?: (props: GiftedAvatarProps) => void
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default class GiftedAvatar extends React.Component<GiftedAvatarProps> {
|
|
55
|
+
static defaultProps = {
|
|
56
|
+
user: {
|
|
57
|
+
name: null,
|
|
58
|
+
avatar: null,
|
|
59
|
+
},
|
|
60
|
+
onPress: undefined,
|
|
61
|
+
onLongPress: undefined,
|
|
62
|
+
avatarStyle: {},
|
|
63
|
+
textStyle: {},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static propTypes = {
|
|
67
|
+
user: PropTypes.object,
|
|
68
|
+
onPress: PropTypes.func,
|
|
69
|
+
onLongPress: PropTypes.func,
|
|
70
|
+
avatarStyle: StylePropType,
|
|
71
|
+
textStyle: StylePropType,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
avatarName?: string = undefined
|
|
75
|
+
avatarColor?: string = undefined
|
|
76
|
+
|
|
77
|
+
setAvatarColor () {
|
|
78
|
+
const userName = (this.props.user && this.props.user.name) || ''
|
|
79
|
+
const name = userName.toUpperCase().split(' ')
|
|
80
|
+
if (name.length === 1)
|
|
81
|
+
this.avatarName = `${name[0].charAt(0)}`
|
|
82
|
+
else if (name.length > 1)
|
|
83
|
+
this.avatarName = `${name[0].charAt(0)}${name[1].charAt(0)}`
|
|
84
|
+
else
|
|
85
|
+
this.avatarName = ''
|
|
86
|
+
|
|
87
|
+
let sumChars = 0
|
|
88
|
+
for (let i = 0; i < userName.length; i += 1)
|
|
89
|
+
sumChars += userName.charCodeAt(i)
|
|
90
|
+
|
|
91
|
+
// inspired by https://github.com/wbinnssmith/react-user-avatar
|
|
92
|
+
// colors from https://flatuicolors.com/
|
|
93
|
+
const colors = [
|
|
94
|
+
carrot,
|
|
95
|
+
emerald,
|
|
96
|
+
peterRiver,
|
|
97
|
+
wisteria,
|
|
98
|
+
alizarin,
|
|
99
|
+
turquoise,
|
|
100
|
+
midnightBlue,
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
this.avatarColor = colors[sumChars % colors.length]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
renderAvatar () {
|
|
107
|
+
const { user } = this.props
|
|
108
|
+
if (user)
|
|
109
|
+
if (typeof user.avatar === 'function')
|
|
110
|
+
return user.avatar([styles.avatarStyle, this.props.avatarStyle])
|
|
111
|
+
else if (typeof user.avatar === 'string')
|
|
112
|
+
return (
|
|
113
|
+
<Image
|
|
114
|
+
source={{ uri: user.avatar }}
|
|
115
|
+
style={[styles.avatarStyle, this.props.avatarStyle]}
|
|
116
|
+
/>
|
|
117
|
+
)
|
|
118
|
+
else if (typeof user.avatar === 'number')
|
|
119
|
+
return (
|
|
120
|
+
<Image
|
|
121
|
+
source={user.avatar}
|
|
122
|
+
style={[styles.avatarStyle, this.props.avatarStyle]}
|
|
123
|
+
/>
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
renderInitials () {
|
|
130
|
+
return (
|
|
131
|
+
<Text style={[styles.textStyle, this.props.textStyle]}>
|
|
132
|
+
{this.avatarName}
|
|
133
|
+
</Text>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
handleOnPress = () => {
|
|
138
|
+
const {
|
|
139
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
140
|
+
onPress,
|
|
141
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
142
|
+
...rest
|
|
143
|
+
} = this.props
|
|
144
|
+
|
|
145
|
+
if (this.props.onPress)
|
|
146
|
+
this.props.onPress(rest)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
handleOnLongPress = () => {
|
|
150
|
+
const {
|
|
151
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
152
|
+
onLongPress,
|
|
153
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
154
|
+
...rest
|
|
155
|
+
} = this.props
|
|
156
|
+
|
|
157
|
+
if (this.props.onLongPress)
|
|
158
|
+
this.props.onLongPress(rest)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
render () {
|
|
162
|
+
if (!this.props.user || (!this.props.user.name && !this.props.user.avatar))
|
|
163
|
+
// render placeholder
|
|
164
|
+
return (
|
|
165
|
+
<View
|
|
166
|
+
style={[
|
|
167
|
+
styles.avatarStyle,
|
|
168
|
+
styles.avatarTransparent,
|
|
169
|
+
this.props.avatarStyle,
|
|
170
|
+
]}
|
|
171
|
+
accessibilityRole='image'
|
|
172
|
+
/>
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if (this.props.user.avatar)
|
|
176
|
+
return (
|
|
177
|
+
<TouchableOpacity
|
|
178
|
+
disabled={!this.props.onPress}
|
|
179
|
+
onPress={this.handleOnPress}
|
|
180
|
+
onLongPress={this.handleOnLongPress}
|
|
181
|
+
accessibilityRole='image'
|
|
182
|
+
>
|
|
183
|
+
{this.renderAvatar()}
|
|
184
|
+
</TouchableOpacity>
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
this.setAvatarColor()
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<TouchableOpacity
|
|
191
|
+
disabled={!this.props.onPress}
|
|
192
|
+
onPress={this.handleOnPress}
|
|
193
|
+
onLongPress={this.handleOnLongPress}
|
|
194
|
+
style={[
|
|
195
|
+
styles.avatarStyle,
|
|
196
|
+
{ backgroundColor: this.avatarColor },
|
|
197
|
+
this.props.avatarStyle,
|
|
198
|
+
]}
|
|
199
|
+
accessibilityRole='image'
|
|
200
|
+
>
|
|
201
|
+
{this.renderInitials()}
|
|
202
|
+
</TouchableOpacity>
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
}
|