├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── app ├── chat │ ├── ChatItem.js │ ├── ChatView.js │ ├── ImageMessage.js │ ├── InputBar.js │ ├── InputBarControl │ │ ├── Container.js │ │ ├── Input.js │ │ ├── Voice.js │ │ ├── VoiceButton.js │ │ └── index.js │ ├── TextMessage.js │ ├── VideoMessage.js │ ├── VoiceMessage.js │ ├── VoiceView.js │ ├── components │ │ ├── android-container │ │ │ └── index.js │ │ └── pop-view │ │ │ ├── ActionPopover │ │ │ ├── ActionPopover.js │ │ │ ├── ActionPopoverItem.js │ │ │ └── ActionPopoverView.js │ │ │ ├── KeyboardSpace │ │ │ └── KeyboardSpace.js │ │ │ ├── Overlay │ │ │ ├── Overlay.js │ │ │ ├── OverlayPopView.js │ │ │ ├── OverlayPopoverView.js │ │ │ ├── OverlayPullView.js │ │ │ ├── OverlayView.js │ │ │ └── TopView.js │ │ │ ├── Popover │ │ │ └── Popover.js │ │ │ └── index.js │ ├── del │ │ └── index.js │ ├── emoji │ │ ├── control.js │ │ ├── index.android.js │ │ └── index.ios.js │ ├── index.js │ ├── panelContainer │ │ ├── index.android.js │ │ └── index.ios.js │ ├── plus │ │ ├── index.android.js │ │ └── index.ios.js │ └── utils.js └── source │ ├── emojis │ ├── aixin.png │ ├── aohuo.png │ ├── aoman.png │ ├── baiyan.png │ ├── baoquan.png │ ├── beishang.png │ ├── bianbian.png │ ├── bishi.png │ ├── bizui.png │ ├── buxie.png │ ├── cahan.png │ ├── caidao.png │ ├── daku.png │ ├── dangao.png │ ├── deyi.png │ ├── diaoxie.png │ ├── fa.png │ ├── fadai.png │ ├── fadou.png │ ├── fanu.png │ ├── faxiao.png │ ├── fendou.png │ ├── ganga.png │ ├── gaoxing.png │ ├── gouying.png │ ├── guilian.png │ ├── guzhang.png │ ├── haixiu.png │ ├── hanxiao.png │ ├── haqian.png │ ├── heiha.png │ ├── heshi.png │ ├── hongbao.png │ ├── huaixiao.png │ ├── ic_emoji.png │ ├── ic_emoji_del.png │ ├── index.js │ ├── ji.png │ ├── jianxiao.png │ ├── jiayou.png │ ├── jinkong.png │ ├── jinya.png │ ├── jiong.png │ ├── jizhi.png │ ├── kafei.png │ ├── kelian.png │ ├── kongju.png │ ├── koubi.png │ ├── kouzhao.png │ ├── kuaikule.png │ ├── kulu.png │ ├── kun.png │ ├── liuhan.png │ ├── liulei.png │ ├── liwu.png │ ├── meigui.png │ ├── nanguo.png │ ├── ok.png │ ├── piezui.png │ ├── pijiu.png │ ├── qiang.png │ ├── qiaoda.png │ ├── qingzhu.png │ ├── qinqin.png │ ├── quantou.png │ ├── ruo.png │ ├── se.png │ ├── shadai.png │ ├── shengli.png │ ├── shuai.png │ ├── shui.png │ ├── taiyang.png │ ├── tiaopi.png │ ├── tiaotiao.png │ ├── tu.png │ ├── tushetou.png │ ├── weiqu.png │ ├── weixiao.png │ ├── woshou.png │ ├── wulian.png │ ├── xiaoku.png │ ├── xigua.png │ ├── xinsui.png │ ├── xu.png │ ├── ye.png │ ├── yinxian.png │ ├── yiwen.png │ ├── yongbao.png │ ├── youhengheng.png │ ├── youxian.png │ ├── yueliang.png │ ├── yukuai.png │ ├── yun.png │ ├── zaijian.png │ ├── zhadan.png │ ├── zhouma.png │ ├── zhoumei.png │ ├── zhuakuang.png │ ├── zhuanquan.png │ ├── zhutou.png │ ├── ziya.png │ ├── zuichun.png │ └── zuohengheng.png │ └── image │ ├── avatar.png │ ├── camera.png │ ├── check.png │ ├── defaultAvatar.png │ ├── delete.png │ ├── emoji.png │ ├── keyboard.png │ ├── more.png │ ├── photo.png │ ├── play.png │ ├── send.png │ ├── sendAble.png │ ├── speak0.png │ ├── speak1.png │ ├── speak2.png │ ├── speak3.png │ ├── speak4.png │ ├── speak5.png │ ├── speak6.png │ ├── speak7.png │ ├── speak8.png │ ├── voice.png │ ├── voiceCancel.png │ ├── voiceError.png │ ├── voiceLeft.png │ ├── voiceLeftOne.png │ ├── voiceLeftTwo.png │ ├── voiceRight.png │ ├── voiceRightOne.png │ ├── voiceRightTwo.png │ └── waring.png ├── cn └── README.md ├── example ├── .buckconfig ├── .eslintrc.js ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── App.js ├── __tests__ │ └── App-test.js ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── Podfile │ ├── Podfile.lock │ ├── example-tvOS │ │ └── Info.plist │ ├── example-tvOSTests │ │ └── Info.plist │ ├── example.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── example-tvOS.xcscheme │ │ │ └── example.xcscheme │ ├── example.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── exampleTests │ │ ├── Info.plist │ │ └── exampleTests.m ├── metro.config.js ├── package.json ├── src │ ├── navigator.js │ ├── source │ │ ├── avatar.png │ │ ├── bg.jpg │ │ ├── camera.png │ │ ├── defaultAvatar.png │ │ └── photo.png │ └── view │ │ ├── example │ │ └── index.js │ │ ├── home │ │ └── index.js │ │ └── index.js └── yarn.lock ├── index.d.ts ├── index.js ├── package.json ├── screenshots ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── alipay.jpg └── wechatPay.jpg └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | .expo/ 4 | examples/ 5 | npm-debug.log 6 | 7 | .idea 8 | .vscode 9 | Exponent-*.app 10 | *.log 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example/ 2 | examples/ 3 | screenshots/ 4 | node_modules/ 5 | .idea/ 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 DaiYz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/chat/ImageMessage.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | View, 4 | TouchableOpacity, 5 | StyleSheet, 6 | ActivityIndicator, 7 | Text 8 | } from 'react-native' 9 | export default class ImageMessage extends PureComponent { 10 | render () { 11 | const { message, messageErrorIcon, isSelf, isOpen, reSendMessage, chatType, showIsRead, isReadStyle, ImageComponent } = this.props 12 | return ( 13 | 14 | (this[`item_${this.props.rowId}`] = e)} 16 | activeOpacity={1} 17 | collapsable={false} 18 | disabled={isOpen} 19 | onPress={() => this.props.onMessagePress('image', parseInt(this.props.rowId), message.content.uri, message)} 20 | style={{ backgroundColor: 'transparent', padding: 5, borderRadius: 5 }} 21 | onLongPress={() => { 22 | this.props.onMessageLongPress(this[`item_${this.props.rowId}`], 'image', parseInt(this.props.rowId), message.content.uri, message) 23 | }} > 24 | 25 | 26 | {showIsRead && chatType !== 'group' && isSelf && ( 27 | 28 | {this.props.lastReadAt && this.props.lastReadAt - message.time > 0 ? '已读' : '未读'} 29 | 30 | )} 31 | 32 | 33 | 34 | {!isSelf 35 | ? null 36 | : message.sendStatus === undefined 37 | ? null 38 | : message.sendStatus === 0 39 | ? 40 | : message.sendStatus < 0 41 | ? { 45 | if (message.sendStatus === -2) { 46 | reSendMessage(message) 47 | } 48 | }}> 49 | {messageErrorIcon} 50 | 51 | : null 52 | } 53 | 54 | 55 | ) 56 | } 57 | } 58 | 59 | const styles = StyleSheet.create({ 60 | right: { 61 | flexDirection: 'row-reverse', 62 | marginRight: 10 63 | }, 64 | left: { 65 | flexDirection: 'row', 66 | marginLeft: 10 67 | } 68 | }) 69 | -------------------------------------------------------------------------------- /app/chat/InputBarControl/Container.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | Platform, 4 | View, 5 | Animated, StyleSheet, Dimensions 6 | } from 'react-native' 7 | 8 | const { width } = Dimensions.get('window') 9 | 10 | class Container extends PureComponent { 11 | render () { 12 | const { inputOutContainerStyle, isIphoneX, xHeight, inputContainerStyle, children, setInputHeight } = this.props 13 | return ( 14 | setInputHeight(e.nativeEvent.layout.height)} 23 | > 24 | 28 | {children} 29 | 30 | 31 | ) 32 | } 33 | } 34 | 35 | export default Container 36 | 37 | const styles = StyleSheet.create({ 38 | commentBar: { 39 | width: width, 40 | backgroundColor: '#f5f5f5', 41 | justifyContent: 'center', 42 | borderColor: '#ccc', 43 | borderTopWidth: StyleSheet.hairlineWidth 44 | } 45 | }) 46 | -------------------------------------------------------------------------------- /app/chat/InputBarControl/Input.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | Platform, 4 | StyleSheet, 5 | TouchableOpacity, 6 | TextInput 7 | } from 'react-native' 8 | 9 | class Input extends PureComponent { 10 | render () { 11 | const { enabled, onFocus, placeholder, onContentSizeChange, textChange, messageContent, inputHeightFix, inputChangeSize, inputStyle } = this.props 12 | return ( 13 | { 17 | onFocus() 18 | }} 19 | > 20 | (this.input = e)} 22 | multiline 23 | blurOnSubmit={false} 24 | editable={!enabled} 25 | placeholder={placeholder} 26 | placeholderTextColor='#5f5d70' 27 | onContentSizeChange={onContentSizeChange} 28 | underlineColorAndroid='transparent' 29 | onChangeText={textChange} 30 | value={messageContent} 31 | style={[styles.commentBar__input, { height: Math.max(35 + inputHeightFix, inputChangeSize) }, inputStyle]} 32 | /> 33 | 34 | ) 35 | } 36 | } 37 | 38 | export default Input 39 | 40 | const styles = StyleSheet.create({ 41 | commentBar__input: { 42 | borderRadius: 18, 43 | height: 26, 44 | width: '100%', 45 | padding: 0, 46 | paddingHorizontal: 16, 47 | paddingTop: Platform.OS === 'ios' ? 8 : 0 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /app/chat/InputBarControl/Voice.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | View, 4 | TouchableOpacity 5 | } from 'react-native' 6 | 7 | class Voice extends PureComponent { 8 | _renderContent = () => { 9 | const { showVoice, ImageComponent, keyboardIcon, voiceIcon } = this.props 10 | if (showVoice) { 11 | return keyboardIcon || 12 | } else { 13 | return voiceIcon || 14 | } 15 | } 16 | 17 | render () { 18 | const { 19 | inputHeightFix, 20 | onMethodChange 21 | } = this.props 22 | return ( 23 | 24 | 25 | {this._renderContent()} 26 | 27 | 28 | ) 29 | } 30 | } 31 | 32 | export default Voice 33 | -------------------------------------------------------------------------------- /app/chat/InputBarControl/VoiceButton.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | StyleSheet, 4 | View, 5 | Text, 6 | Platform, 7 | Dimensions 8 | } from 'react-native' 9 | import { PanGestureHandler, State, TapGestureHandler } from 'react-native-gesture-handler' 10 | const { height } = Dimensions.get('window') 11 | class VoiceButton extends PureComponent { 12 | constructor (props) { 13 | super(props) 14 | this.state = { 15 | state: State.UNDETERMINED 16 | } 17 | } 18 | 19 | _onPanState = (e) => { 20 | const { showVoice, voiceEnd } = this.props 21 | if (e.state === State.END) { 22 | // 结束 23 | if (showVoice) { 24 | voiceEnd() 25 | } 26 | } 27 | } 28 | 29 | _onPan = (e) => { 30 | const { inputHeight, changeVoiceStatus, audioHasPermission } = this.props 31 | const compare = height - inputHeight 32 | if (!audioHasPermission && Platform.OS === 'android') return null 33 | if (e.absoluteY < compare) { 34 | changeVoiceStatus(false) 35 | } else { 36 | changeVoiceStatus(true) 37 | } 38 | } 39 | 40 | _onTab = (e) => { 41 | const { showVoice, voiceStart, voiceEnd } = this.props 42 | if (e.state === State.BEGAN) { 43 | if (showVoice) { 44 | voiceStart() 45 | } 46 | } 47 | if (e.state === State.END) { 48 | // 结束 49 | if (showVoice) { 50 | voiceEnd() 51 | } 52 | } 53 | } 54 | 55 | render () { 56 | const { isVoiceEnd, inputHeightFix, pressOutText, pressInText } = this.props 57 | return ( 58 | this._onPan(e.nativeEvent)} onHandlerStateChange={(e) => this._onPanState(e.nativeEvent)}> 59 | this._onTab(e.nativeEvent)} 61 | > 62 | 63 | 64 | {isVoiceEnd ? `${pressOutText}` : `${pressInText}`} 65 | 66 | 67 | 68 | 69 | ) 70 | } 71 | } 72 | 73 | export default VoiceButton 74 | 75 | const styles = StyleSheet.create({ 76 | container: { 77 | borderRadius: 18, 78 | justifyContent: 'center', 79 | alignItems: 'center', 80 | flexDirection: 'row' 81 | }, 82 | text: { 83 | fontSize: 16, 84 | fontWeight: 'bold', 85 | color: '#555' 86 | } 87 | }) 88 | -------------------------------------------------------------------------------- /app/chat/InputBarControl/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | Platform, 4 | StyleSheet, 5 | TouchableOpacity, 6 | View, 7 | Dimensions 8 | } from 'react-native' 9 | import Container from './Container' 10 | import Voice from './Voice' 11 | import VoiceButton from './VoiceButton' 12 | import Input from './Input' 13 | const { width } = Dimensions.get('window') 14 | 15 | export default class InputBar extends PureComponent { 16 | constructor (props) { 17 | super(props) 18 | this.inputHeight = 0 19 | } 20 | 21 | setInputHeight = (height) => { 22 | this.inputHeight = height 23 | } 24 | 25 | renderIcon = () => { 26 | const { sendIcon, plusIcon, usePlus, messageContent, sendUnableIcon, ImageComponent } = this.props 27 | const sendAbleIcon = sendIcon || 28 | const sendUnableIconDefault = sendUnableIcon || 29 | if (usePlus) { 30 | if (messageContent.trim().length) { 31 | return sendAbleIcon 32 | } else { 33 | return plusIcon || 34 | } 35 | } else { 36 | return messageContent.trim().length ? sendAbleIcon : sendUnableIconDefault 37 | } 38 | } 39 | 40 | renderEmojieIcon = () => { 41 | const { isEmojiShow, keyboardIcon, emojiIcon, ImageComponent } = this.props 42 | if (isEmojiShow) { 43 | return keyboardIcon || 44 | } else { 45 | return emojiIcon || 46 | } 47 | } 48 | 49 | render () { 50 | const { 51 | messageContent, 52 | onSubmitEditing = () => {}, 53 | textChange = () => {}, onMethodChange = () => {}, onContentSizeChange = () => {}, 54 | inputStyle, 55 | inputOutContainerStyle, 56 | inputContainerStyle, 57 | inputHeightFix, 58 | xHeight, 59 | isVoiceEnd, 60 | useVoice, 61 | useEmoji, 62 | usePlus, 63 | inputChangeSize, 64 | placeholder, 65 | pressInText, 66 | pressOutText, 67 | isShowPanel, 68 | isPanelShow, 69 | audioHasPermission, 70 | onFocus, 71 | keyboardIcon, 72 | voiceIcon, 73 | isEmojiShow, 74 | isIphoneX, 75 | ImageComponent, 76 | showVoice, 77 | voiceStart, 78 | rootHeight, 79 | voiceEnd, 80 | changeVoiceStatus 81 | } = this.props 82 | const enabled = (() => { 83 | if (Platform.OS === 'android') { 84 | if (isPanelShow) { 85 | return true 86 | } 87 | if (isEmojiShow) { 88 | return true 89 | } 90 | return false 91 | } else { 92 | return false 93 | } 94 | })() 95 | return ( 96 | 103 | { 104 | useVoice 105 | ? 113 | : null 114 | } 115 | 116 | {showVoice 117 | ? 130 | : } 141 | 142 | 143 | { 144 | useEmoji 145 | ? this.props.showEmoji()} 148 | > 149 | {this.renderEmojieIcon()} 150 | 151 | : null 152 | } 153 | { 157 | if (messageContent.trim().length > 0) { 158 | onSubmitEditing('text', messageContent) 159 | } else { 160 | if (usePlus) { 161 | isShowPanel(!isPanelShow) 162 | } else { 163 | return null 164 | } 165 | } 166 | } 167 | } 168 | activeOpacity={0.7} 169 | > 170 | {this.renderIcon()} 171 | 172 | 173 | 174 | ) 175 | } 176 | } 177 | 178 | const styles = StyleSheet.create({ 179 | commentBar: { 180 | width: width, 181 | backgroundColor: '#f5f5f5', 182 | justifyContent: 'center', 183 | borderColor: '#ccc', 184 | borderTopWidth: StyleSheet.hairlineWidth 185 | }, 186 | container: { 187 | marginHorizontal: 8, 188 | borderRadius: 18, 189 | borderColor: '#ccc', 190 | flex: 1, 191 | borderWidth: StyleSheet.hairlineWidth, 192 | paddingVertical: 0.8 193 | }, 194 | commentBar__input: { 195 | borderRadius: 18, 196 | height: 26, 197 | width: '100%', 198 | padding: 0, 199 | paddingHorizontal: 20 200 | } 201 | }) 202 | -------------------------------------------------------------------------------- /app/chat/TextMessage.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | View, 4 | TouchableOpacity, 5 | ActivityIndicator, 6 | Platform, 7 | StyleSheet, 8 | Dimensions, 9 | Text 10 | } from 'react-native' 11 | import { changeEmojiText } from './utils' 12 | const { width } = Dimensions.get('window') 13 | 14 | const PATTERNS = { 15 | url: /(https?:\/\/|www\.)[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/i, 16 | phone: /[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,7}/, 17 | emoji: new RegExp('\\/\\{[a-zA-Z_]{1,14}\\}') 18 | } 19 | export default class TextMessage extends PureComponent { 20 | render () { 21 | const { isSelf, message, messageErrorIcon, views, isOpen, rightMessageBackground, leftMessageBackground, reSendMessage, chatType, isReadStyle, showIsRead, ImageComponent } = this.props 22 | return ( 23 | (this[`item_${this.props.rowId}`] = e)} 27 | > 28 | 38 | { 42 | this.props.onMessageLongPress(this[`item_${this.props.rowId}`], 'text', parseInt(this.props.rowId), changeEmojiText(this.props.message.content, 'en').join(''), message) 43 | }} 44 | onPress={() => { 45 | this.props.onMessagePress('text', parseInt(this.props.rowId), changeEmojiText(this.props.message.content, 'en').join(''), message) 46 | }} 47 | > 48 | 50 | {views} 51 | 52 | {chatType !== 'group' && isSelf && showIsRead && ( 53 | 54 | {this.props.lastReadAt && this.props.lastReadAt - message.time > 0 ? '已读' : '未读'} 55 | 56 | )} 57 | 58 | 59 | {!isSelf 60 | ? null 61 | : message.sendStatus === undefined 62 | ? null 63 | : message.sendStatus === 0 64 | ? 65 | : message.sendStatus < 0 66 | ? { 70 | if (message.sendStatus === -2) { 71 | reSendMessage(message) 72 | } 73 | }}> 74 | {messageErrorIcon ? messageErrorIcon : } 75 | 76 | : null 77 | } 78 | 79 | 80 | ) 81 | } 82 | } 83 | const styles = StyleSheet.create({ 84 | 85 | container: { 86 | flexDirection: 'row', 87 | alignItems: 'center', 88 | flexWrap: 'wrap', 89 | borderRadius: 12, 90 | paddingHorizontal: 15, 91 | paddingVertical: 15, 92 | maxWidth: width - 160, 93 | minHeight: 20, 94 | }, 95 | 96 | subEmojiStyle: { 97 | width: 25, 98 | height: 25 99 | }, 100 | triangle: { 101 | width: 0, 102 | height: 0, 103 | zIndex: 999, 104 | borderWidth: 6, 105 | borderTopColor: 'transparent', 106 | borderBottomColor: 'transparent', 107 | borderColor: '#fff', 108 | marginTop: 16 109 | }, 110 | left_triangle: { 111 | borderLeftWidth: 0, 112 | borderRightWidth: Platform.OS === 'android' ? 6 : 10, 113 | marginLeft: 5 114 | }, 115 | right_triangle: { 116 | borderRightWidth: 0, 117 | borderLeftWidth: Platform.OS === 'android' ? 6 : 10, 118 | borderColor: '#a0e75a', 119 | marginRight: 5 120 | }, 121 | right: { 122 | flexDirection: 'row-reverse', 123 | }, 124 | left: { 125 | flexDirection: 'row', 126 | } 127 | }) 128 | -------------------------------------------------------------------------------- /app/chat/VideoMessage.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, TouchableOpacity, StyleSheet, ActivityIndicator, Text } from 'react-native' 3 | export default class VideoMessage extends PureComponent { 4 | render() { 5 | const { message, messageErrorIcon, isSelf, isOpen, reSendMessage, chatType, showIsRead, isReadStyle, ImageComponent } = this.props 6 | return ( 7 | 8 | (this[`item_${this.props.rowId}`] = e)} 10 | activeOpacity={1} 11 | collapsable={false} 12 | disabled={isOpen} 13 | onPress={() => this.props.onMessagePress('video', parseInt(this.props.rowId), message.content.uri, message)} 14 | style={{ backgroundColor: 'transparent', padding: 5, borderRadius: 5 }} 15 | onLongPress={() => { 16 | this.props.onMessageLongPress( 17 | this[`item_${this.props.rowId}`], 18 | 'image', 19 | parseInt(this.props.rowId), 20 | message.content.uri, 21 | message 22 | ) 23 | }} 24 | > 25 | 26 | 30 | 34 | {chatType !== 'group' && isSelf && showIsRead &&( 35 | 36 | {this.props.lastReadAt && this.props.lastReadAt - message.time > 0 ? '已读' : '未读'} 37 | 38 | )} 39 | 40 | 41 | 42 | {!isSelf ? null : message.sendStatus === undefined ? null : message.sendStatus === 0 ? ( 43 | 44 | ) : message.sendStatus < 0 ? ( 45 | { 49 | if (message.sendStatus === -2) { 50 | reSendMessage(message) 51 | } 52 | }} 53 | > 54 | {messageErrorIcon} 55 | 56 | ) : null} 57 | 58 | 59 | ) 60 | } 61 | } 62 | 63 | const styles = StyleSheet.create({ 64 | right: { 65 | flexDirection: 'row-reverse', 66 | marginRight: 10, 67 | }, 68 | left: { 69 | flexDirection: 'row', 70 | marginLeft: 10, 71 | }, 72 | playIcon: { 73 | width: 50, 74 | height: 50, 75 | borderRadius: 25, 76 | position: 'absolute', 77 | top: '50%', 78 | left: '50%', 79 | marginLeft: -25, 80 | marginTop: -25, 81 | } 82 | }) 83 | -------------------------------------------------------------------------------- /app/chat/VoiceMessage.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { 3 | View, 4 | TouchableOpacity, 5 | StyleSheet, 6 | Text, 7 | ActivityIndicator, Dimensions, Platform 8 | } from 'react-native' 9 | const { width } = Dimensions.get('window') 10 | 11 | export default class VoiceMessage extends PureComponent { 12 | constructor (props) { 13 | super(props) 14 | this.playTime = null 15 | this.state = { 16 | loading: false, 17 | progress: 2 18 | } 19 | } 20 | 21 | UNSAFE_componentWillReceiveProps (next) { 22 | if (next.pressIndex === next.rowId) { 23 | this.setState({ loading: next.voiceLoading }) 24 | if (next.voicePlaying) { 25 | this._play() 26 | } else { 27 | this.playTime && clearInterval(this.playTime) 28 | this.setState({ progress: 2 }) 29 | } 30 | } else { 31 | this.setState({ loading: false, progress: 2 }) 32 | this.playTime && clearInterval(this.playTime) 33 | } 34 | } 35 | 36 | _play () { 37 | this.playTime && clearInterval(this.playTime) 38 | let index = 0 39 | const { progress } = this.state 40 | if (progress === 2) index = 2 41 | this.playTime = setInterval(() => { 42 | if (index === 2) { 43 | index = -1 44 | } 45 | index += 1 46 | this.setState({ progress: index }) 47 | }, 400) 48 | } 49 | 50 | _renderIcon = () => { 51 | const { isSelf, voiceLeftIcon, voiceRightIcon, ImageComponent } = this.props 52 | const { progress } = this.state 53 | if (isSelf) { 54 | if (voiceRightIcon) { 55 | return voiceRightIcon 56 | } else { 57 | return 69 | } 70 | } else { 71 | if (voiceLeftIcon) { 72 | return voiceLeftIcon 73 | } else { 74 | return 77 | } 78 | } 79 | } 80 | 81 | componentWillUnmount () { 82 | this.playTime && clearInterval(this.playTime) 83 | } 84 | 85 | render () { 86 | const { message, messageErrorIcon, isSelf, isOpen, reSendMessage, leftMessageBackground, rightMessageBackground, voiceRightLoadingColor, voiceLeftLoadingColor, chatType, isReadStyle, showIsRead} = this.props 87 | const { loading } = this.state 88 | return ( 89 | 90 | 91 | 101 | (this[`item_${this.props.rowId}`] = e)} 105 | > 106 | 107 | { 126 | this.props.savePressIndex(this.props.rowId) 127 | this.props.onMessagePress('voice', parseInt(this.props.rowId), message.content.uri, message) 128 | } 129 | } 130 | onLongPress={() => { 131 | this.props.onMessageLongPress(this[`item_${this.props.rowId}`], 'voice', parseInt(this.props.rowId), message.content.uri, message) 132 | }} 133 | > 134 | 1 ? message.content.length * 2 : 0) }, { maxWidth: width - 160 }, { flexDirection: isSelf ? 'row-reverse' : 'row' } 135 | ]}> 136 | {this._renderIcon()} 137 | 138 | 139 | {/*{chatType !== 'group' && isSelf && (*/} 140 | {/* */} 141 | {/* {this.props.lastReadAt && this.props.lastReadAt - message.time > 0 ? '已读' : '未读'}*/} 142 | {/* */} 143 | {/*)}*/} 144 | 145 | 146 | 147 | {`${message.content.length}"`} 148 | 149 | 150 | 151 | 152 | {!isSelf 153 | ? null 154 | : message.sendStatus === undefined 155 | ? null 156 | : message.sendStatus === 0 157 | ? 158 | : message.sendStatus < 0 159 | ? { 163 | if (message.sendStatus === -2) { 164 | reSendMessage(message) 165 | } 166 | }}> 167 | {messageErrorIcon} 168 | 169 | : null 170 | } 171 | 172 | 173 | {chatType !== 'group' && isSelf && showIsRead && ( 174 | 175 | {this.props.lastReadAt && this.props.lastReadAt - message.time > 0 ? '已读' : '未读'} 176 | 177 | )} 178 | 179 | ) 180 | } 181 | } 182 | 183 | const styles = StyleSheet.create({ 184 | triangle: { 185 | width: 0, 186 | height: 0, 187 | zIndex: 999, 188 | borderWidth: 6, 189 | borderTopColor: 'transparent', 190 | borderBottomColor: 'transparent', 191 | }, 192 | left_triangle: { 193 | borderLeftWidth: 0, 194 | borderRightWidth: Platform.OS === 'android' ? 6 : 10, 195 | marginLeft: 5 196 | }, 197 | right_triangle: { 198 | borderRightWidth: 0, 199 | borderLeftWidth: Platform.OS === 'android' ? 6 : 10, 200 | borderColor: '#a0e75a', 201 | marginRight: 5 202 | }, 203 | right: { 204 | flexDirection: 'row-reverse', 205 | alignItems: 'center', 206 | }, 207 | left: { 208 | flexDirection: 'row', 209 | alignItems: 'center' 210 | }, 211 | voiceArea: { 212 | paddingVertical: 8, 213 | borderRadius: 12, 214 | maxWidth: width - 160, 215 | justifyContent: 'center', 216 | minHeight: 30 217 | } 218 | }) 219 | -------------------------------------------------------------------------------- /app/chat/components/android-container/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View } from 'react-native' 3 | 4 | export default class ViewPagerAndroidContainer extends PureComponent { 5 | state = { 6 | width: 0, 7 | height: 0 8 | } 9 | 10 | render () { 11 | return ( 12 | 13 | {this.props.children} 14 | 15 | ) 16 | } 17 | 18 | _onLayoutChange = (e) => { 19 | const { width, height } = e.nativeEvent.layout 20 | this.setState({ width: width, height: height }) 21 | } 22 | } -------------------------------------------------------------------------------- /app/chat/components/pop-view/ActionPopover/ActionPopover.js: -------------------------------------------------------------------------------- 1 | // ActionPopover.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import {View} from 'react-native' 7 | 8 | import Overlay from '../Overlay/Overlay' 9 | import ActionPopoverView from './ActionPopoverView' 10 | 11 | export default class ActionPopover extends Overlay { 12 | static ActionPopoverView = ActionPopoverView; 13 | 14 | // fromBounds shape: x, y, width, height 15 | // items shape 16 | // title: PropTypes.string.isRequired, 17 | // onPress: PropTypes.func, 18 | static show (fromBounds, items, options = {}) { 19 | return super.show( 20 | 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/ActionPopover/ActionPopoverItem.js: -------------------------------------------------------------------------------- 1 | // ActionPopoverItem.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import PropTypes from 'prop-types' 7 | import {StyleSheet, View, Text, TouchableOpacity, PixelRatio} from 'react-native' 8 | const pixelSize = (function () { 9 | let pixelRatio = PixelRatio.get() 10 | if (pixelRatio >= 3) return 0.333 11 | else if (pixelRatio >= 2) return 0.5 12 | else return 1 13 | })() 14 | 15 | export default class ActionPopoverItem extends Component { 16 | static propTypes = { 17 | ...TouchableOpacity.propTypes, 18 | title: PropTypes.oneOfType([PropTypes.element, PropTypes.string, PropTypes.number]), 19 | leftSeparator: PropTypes.bool, 20 | rightSeparator: PropTypes.bool 21 | }; 22 | 23 | static defaultProps = { 24 | ...TouchableOpacity.defaultProps 25 | }; 26 | 27 | buildProps () { 28 | let {style, title, leftSeparator, rightSeparator, ...others} = this.props 29 | 30 | style = [{ 31 | paddingVertical: 8, 32 | paddingHorizontal: 12, 33 | borderColor: '#fff', 34 | borderLeftWidth: leftSeparator ? pixelSize : 0, 35 | borderRightWidth: rightSeparator ? pixelSize : 0 36 | }].concat(style) 37 | 38 | if ((title || title === '' || title === 0) && !React.isValidElement(title)) { 39 | let textStyle = { 40 | backgroundColor: 'rgba(0, 0, 0, 0)', 41 | color: '#fff', 42 | fontSize: 14 43 | } 44 | title = {title} 45 | } 46 | 47 | this.props = {style, title, leftSeparator, rightSeparator, ...others} 48 | } 49 | 50 | render () { 51 | this.buildProps() 52 | 53 | let {title, ...others} = this.props 54 | return ( 55 | 56 | {title} 57 | 58 | ) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/ActionPopover/ActionPopoverView.js: -------------------------------------------------------------------------------- 1 | // ActionPopoverView.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import PropTypes from 'prop-types' 7 | import Overlay from '../Overlay/Overlay' 8 | import ActionPopoverItem from './ActionPopoverItem' 9 | 10 | export default class ActionPopoverView extends Overlay.PopoverView { 11 | static propTypes = { 12 | ...Overlay.PopoverView.propTypes, 13 | items: PropTypes.arrayOf(PropTypes.shape({ 14 | title: PropTypes.string, 15 | onPress: PropTypes.func 16 | })).isRequired 17 | }; 18 | 19 | static defaultProps = { 20 | ...Overlay.PopoverView.defaultProps, 21 | direction: 'up', 22 | align: 'center', 23 | showArrow: true 24 | }; 25 | 26 | static Item = ActionPopoverItem; 27 | 28 | onItemPress (item) { 29 | this.close(false) 30 | item.onPress && item.onPress() 31 | } 32 | 33 | buildProps () { 34 | let {popoverStyle, directionInsets, items, children, ...others} = this.props 35 | 36 | popoverStyle = [{ 37 | backgroundColor: 'rgba(90, 74, 124, 0.9)', 38 | paddingVertical: 0, 39 | paddingHorizontal: 4, 40 | borderRadius: 8, 41 | flexDirection: 'row' 42 | }].concat(popoverStyle) 43 | 44 | if (!directionInsets && directionInsets !== 0) { 45 | directionInsets = 4 46 | } 47 | 48 | children = [] 49 | for (let i = 0; items && i < items.length; ++i) { 50 | let item = items[i] 51 | children.push( 52 | this.onItemPress(item)} 57 | /> 58 | ) 59 | } 60 | 61 | this.props = {popoverStyle, directionInsets, items, children, ...others} 62 | 63 | super.buildProps() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/KeyboardSpace/KeyboardSpace.js: -------------------------------------------------------------------------------- 1 | // KeyboardSpace.js 2 | // from https://github.com/Andr3wHur5t/react-native-keyboard-spacer 3 | 4 | 'use strict' 5 | 6 | import React, {Component} from 'react' 7 | import PropTypes from 'prop-types' 8 | import {StyleSheet, Platform, View, Keyboard, LayoutAnimation} from 'react-native' 9 | 10 | export default class KeyboardSpace extends Component { 11 | static propTypes = { 12 | topInsets: PropTypes.number 13 | }; 14 | 15 | static defaultProps = { 16 | topInsets: 0 17 | }; 18 | 19 | constructor (props) { 20 | super(props) 21 | this.showListener = null 22 | this.hideListener = null 23 | this.state = { 24 | keyboardHeight: 0 25 | } 26 | } 27 | 28 | componentDidMount () { 29 | if (!this.showListener) { 30 | let name = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow' 31 | this.showListener = Keyboard.addListener(name, e => this.onKeyboardShow(e)) 32 | } 33 | if (!this.hideListener) { 34 | let name = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide' 35 | this.hideListener = Keyboard.addListener(name, () => this.onKeyboardHide()) 36 | } 37 | } 38 | 39 | componentWillUnmount () { 40 | if (this.showListener) { 41 | this.showListener.remove() 42 | this.showListener = null 43 | } 44 | if (this.hideListener) { 45 | this.hideListener.remove() 46 | this.hideListener = null 47 | } 48 | } 49 | 50 | componentWillUpdate (props, state) { 51 | if (state.keyboardHeight !== this.state.keyboardHeight) { 52 | LayoutAnimation.configureNext({ 53 | duration: 500, 54 | create: { 55 | duration: 300, 56 | type: LayoutAnimation.Types.easeInEaseOut, 57 | property: LayoutAnimation.Properties.opacity 58 | }, 59 | update: { 60 | type: LayoutAnimation.Types.spring, 61 | springDamping: 200 62 | } 63 | }) 64 | } 65 | } 66 | 67 | onKeyboardShow (e) { 68 | if (!e || !e.endCoordinates || !e.endCoordinates.height) return 69 | let height = e.endCoordinates.height + (this.props.topInsets ? this.props.topInsets : 0) 70 | this.setState({keyboardHeight: height}) 71 | } 72 | 73 | onKeyboardHide () { 74 | this.setState({keyboardHeight: 0}) 75 | } 76 | 77 | render () { 78 | return ( 79 | 80 | ) 81 | } 82 | } 83 | 84 | const styles = StyleSheet.create({ 85 | keyboardSpace: { 86 | backgroundColor: 'rgba(0, 0, 0, 0)', 87 | left: 0, 88 | right: 0, 89 | bottom: 0 90 | } 91 | }) 92 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/Overlay/Overlay.js: -------------------------------------------------------------------------------- 1 | // Overlay.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import {View} from 'react-native' 7 | 8 | import TopView from './TopView' 9 | import OverlayView from './OverlayView' 10 | import OverlayPullView from './OverlayPullView' 11 | import OverlayPopView from './OverlayPopView' 12 | import OverlayPopoverView from './OverlayPopoverView' 13 | 14 | export default class Overlay { 15 | static View = OverlayView; 16 | static PullView = OverlayPullView; 17 | static PopView = OverlayPopView; 18 | static PopoverView = OverlayPopoverView; 19 | 20 | // base props 21 | // style: ViewPropTypes.style, 22 | // modal: PropTypes.bool, 23 | // animated: PropTypes.bool, 24 | // overlayOpacity: PropTypes.number, 25 | // overlayPointerEvents: ViewPropTypes.pointerEvents, 26 | static show (overlayView) { 27 | let key 28 | let onDisappearCompletedSave = overlayView.props.onDisappearCompleted 29 | let element = React.cloneElement(overlayView, { 30 | onDisappearCompleted: () => { 31 | TopView.remove(key) 32 | onDisappearCompletedSave && onDisappearCompletedSave() 33 | } 34 | }) 35 | key = TopView.add(element) 36 | return key 37 | } 38 | 39 | static hide (key) { 40 | TopView.remove(key) 41 | } 42 | 43 | static transformRoot (transform, animated, animatesOnly = null) { 44 | TopView.transform(transform, animated, animatesOnly) 45 | } 46 | 47 | static restoreRoot (animated, animatesOnly = null) { 48 | TopView.restore(animated, animatesOnly) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/Overlay/OverlayPopView.js: -------------------------------------------------------------------------------- 1 | // OverlayPopView.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import PropTypes from 'prop-types' 7 | import {Animated, View, ViewPropTypes} from 'react-native' 8 | 9 | import OverlayView from './OverlayView' 10 | 11 | export default class OverlayPopView extends OverlayView { 12 | static propTypes = { 13 | ...OverlayView.propTypes, 14 | type: PropTypes.oneOf(['zoomOut', 'zoomIn', 'custom']), 15 | containerStyle: ViewPropTypes.style, 16 | customBounds: PropTypes.shape({ 17 | x: PropTypes.number.isRequired, 18 | y: PropTypes.number.isRequired, 19 | width: PropTypes.number.isRequired, 20 | height: PropTypes.number.isRequired 21 | }) 22 | }; 23 | 24 | static defaultProps = { 25 | ...OverlayView.defaultProps, 26 | type: 'zoomOut', 27 | animated: true 28 | }; 29 | 30 | constructor (props) { 31 | super(props) 32 | this.viewLayout = {x: 0, y: 0, width: 0, height: 0} 33 | Object.assign(this.state, { 34 | opacity: new Animated.Value(1), 35 | translateX: new Animated.Value(0), 36 | translateY: new Animated.Value(0), 37 | scaleX: new Animated.Value(1), 38 | scaleY: new Animated.Value(1), 39 | showed: false 40 | }) 41 | } 42 | 43 | get appearAnimates () { 44 | let animates = super.appearAnimates 45 | let duration = 200 46 | animates = animates.concat([ 47 | Animated.timing(this.state.opacity, { 48 | toValue: 1, 49 | duration, 50 | useNativeDriver: true 51 | }), 52 | Animated.timing(this.state.translateX, { 53 | toValue: 0, 54 | duration, 55 | useNativeDriver: true 56 | }), 57 | Animated.timing(this.state.translateY, { 58 | toValue: 0, 59 | duration, 60 | useNativeDriver: true 61 | }), 62 | Animated.timing(this.state.scaleX, { 63 | toValue: 1, 64 | duration, 65 | useNativeDriver: true 66 | }), 67 | Animated.timing(this.state.scaleY, { 68 | toValue: 1, 69 | duration, 70 | useNativeDriver: true 71 | }) 72 | ]) 73 | return animates 74 | } 75 | 76 | get disappearAnimates () { 77 | let animates = super.disappearAnimates 78 | let duration = 200 79 | let ft = this.fromTransform 80 | animates = animates.concat([ 81 | Animated.timing(this.state.opacity, { 82 | toValue: 0, 83 | duration, 84 | useNativeDriver: true 85 | }), 86 | Animated.timing(this.state.translateX, { 87 | toValue: ft.translateX, 88 | duration, 89 | useNativeDriver: true 90 | }), 91 | Animated.timing(this.state.translateY, { 92 | toValue: ft.translateY, 93 | duration, 94 | useNativeDriver: true 95 | }), 96 | Animated.timing(this.state.scaleX, { 97 | toValue: ft.scaleX, 98 | duration, 99 | useNativeDriver: true 100 | }), 101 | Animated.timing(this.state.scaleY, { 102 | toValue: ft.scaleY, 103 | duration, 104 | useNativeDriver: true 105 | }) 106 | ]) 107 | return animates 108 | } 109 | 110 | get appearAfterMount () { 111 | return false 112 | } 113 | 114 | get fromBounds () { 115 | let {type, customBounds} = this.props 116 | let bounds 117 | if (type === 'custom' && !customBounds) { 118 | console.error('OverlayPopView: customBounds can not be null when type is "custom"') 119 | } 120 | if (type === 'custom' && customBounds) { 121 | bounds = customBounds 122 | } else { 123 | let zoomRate = type === 'zoomIn' ? 0.3 : 1.2 124 | let {x, y, width, height} = this.viewLayout 125 | bounds = { 126 | x: x - (width * zoomRate - width) / 2, 127 | y: y - (height * zoomRate - height) / 2, 128 | width: width * zoomRate, 129 | height: height * zoomRate 130 | } 131 | } 132 | return bounds 133 | } 134 | 135 | get fromTransform () { 136 | let fb = this.fromBounds 137 | let tb = this.viewLayout 138 | let transform = { 139 | translateX: (fb.x + fb.width / 2) - (tb.x + tb.width / 2), 140 | translateY: (fb.y + fb.height / 2) - (tb.y + tb.height / 2), 141 | scaleX: fb.width / tb.width, 142 | scaleY: fb.height / tb.height 143 | } 144 | return transform 145 | } 146 | 147 | appear (animated = this.props.animated) { 148 | if (animated) { 149 | let {opacity, translateX, translateY, scaleX, scaleY} = this.state 150 | let ft = this.fromTransform 151 | opacity.setValue(0) 152 | translateX.setValue(ft.translateX) 153 | translateY.setValue(ft.translateY) 154 | scaleX.setValue(ft.scaleX) 155 | scaleY.setValue(ft.scaleY) 156 | } 157 | super.appear(animated) 158 | } 159 | 160 | onLayout (e) { 161 | this.viewLayout = e.nativeEvent.layout 162 | if (!this.state.showed) { 163 | this.setState({showed: true}) 164 | this.appear() 165 | } 166 | } 167 | 168 | buildProps () { 169 | super.buildProps() 170 | 171 | let {containerStyle, ...others} = this.props 172 | let {opacity, translateX, translateY, scaleX, scaleY} = this.state 173 | 174 | containerStyle = [{ 175 | backgroundColor: '#292f4f', 176 | minWidth: 1, 177 | minHeight: 1 178 | }].concat(containerStyle).concat({ 179 | opacity: this.state.showed ? opacity : 0, 180 | transform: [{translateX}, {translateY}, {scaleX}, {scaleY}] 181 | }) 182 | 183 | this.props = {containerStyle, ...others} 184 | } 185 | 186 | renderContent () { 187 | let {containerStyle, children} = this.props 188 | return ( 189 | this.onLayout(e)}> 190 | {children} 191 | 192 | ) 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/Overlay/OverlayPopoverView.js: -------------------------------------------------------------------------------- 1 | // OverlayPopoverView.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import PropTypes from 'prop-types' 7 | import {View, Dimensions, Platform, StatusBar} from 'react-native' 8 | 9 | import OverlayView from './OverlayView' 10 | import Popover from '../Popover/Popover' 11 | 12 | export default class OverlayPopoverView extends OverlayView { 13 | static propTypes = { 14 | ...OverlayView.propTypes, 15 | popoverStyle: Popover.propTypes.style, 16 | fromBounds: PropTypes.shape({ 17 | x: PropTypes.number.isRequired, 18 | y: PropTypes.number.isRequired, 19 | width: PropTypes.number, 20 | height: PropTypes.number 21 | }).isRequired, 22 | direction: PropTypes.oneOf(['down', 'up', 'right', 'left']), 23 | autoDirection: PropTypes.bool, // down -> up, or right -> left 24 | directionInsets: PropTypes.number, 25 | align: PropTypes.oneOf(['start', 'center', 'end']), 26 | alignInsets: PropTypes.number, 27 | showArrow: PropTypes.bool, 28 | paddingCorner: Popover.propTypes.paddingCorner 29 | }; 30 | 31 | static defaultProps = { 32 | ...OverlayView.defaultProps, 33 | overlayOpacity: 0, 34 | direction: 'down', 35 | autoDirection: true, 36 | align: 'end', 37 | showArrow: true 38 | }; 39 | 40 | constructor (props) { 41 | super(props) 42 | Object.assign(this.state, { 43 | fromBounds: props.fromBounds, 44 | popoverWidth: null, 45 | popoverHeight: null 46 | }) 47 | } 48 | 49 | UNSAFE_componentWillReceiveProps (nextProps) { 50 | super.UNSAFE_componentWillReceiveProps && super.UNSAFE_componentWillReceiveProps(nextProps) 51 | if (JSON.stringify(nextProps.fromBounds) != JSON.stringify(this.state.fromBounds)) { 52 | this.setState({fromBounds: nextProps.fromBounds}) 53 | } 54 | } 55 | 56 | updateFromBounds (bounds) { 57 | this.setState({fromBounds: bounds}) 58 | } 59 | 60 | buildProps () { 61 | super.buildProps() 62 | 63 | let {fromBounds, popoverWidth, popoverHeight} = this.state 64 | if (popoverWidth === null || popoverHeight === null) { 65 | let {popoverStyle, direction, showArrow, arrow, ...others} = this.props 66 | if (!showArrow) arrow = 'none' 67 | else { 68 | switch (direction) { 69 | case 'right': arrow = 'left'; break 70 | case 'left': arrow = 'right'; break 71 | case 'up': arrow = 'bottom'; break 72 | default: arrow = 'top'; break 73 | } 74 | } 75 | popoverStyle = [].concat(popoverStyle).concat({position: 'absolute', left: 0, top: 0}) 76 | this.props = {popoverStyle, direction, showArrow, arrow, ...others} 77 | return 78 | } 79 | 80 | let {popoverStyle, direction, autoDirection, directionInsets, align, alignInsets, showArrow, arrow, ...others} = this.props 81 | let screenWidth = Dimensions.get('window').width 82 | let screenHeight = Dimensions.get('window').height 83 | let {x, y, width, height} = fromBounds || {} 84 | 85 | if (!x && x !== 0) x = screenWidth / 2 86 | if (!y && y !== 0) y = screenHeight / 2 87 | if (!width) width = 0 88 | if (!height) height = 0 89 | if (!directionInsets) directionInsets = 0 90 | if (!alignInsets) alignInsets = 0 91 | 92 | // auto direction 93 | let ph = popoverHeight + directionInsets 94 | let pw = popoverWidth + directionInsets 95 | switch (direction) { 96 | case 'right': 97 | if (autoDirection && x + width + pw > screenWidth && x >= pw) direction = 'left' 98 | break 99 | case 'left': 100 | if (autoDirection && x + width + pw <= screenWidth && x < pw) direction = 'right' 101 | break 102 | case 'up': 103 | if (autoDirection && y + height + ph <= screenHeight && y < ph) direction = 'down' 104 | break 105 | default: 106 | if (autoDirection && y + height + ph > screenHeight && y >= ph) direction = 'up' 107 | break 108 | } 109 | 110 | // calculate popover top-left position and arrow type 111 | let px, py 112 | switch (direction) { 113 | case 'right': 114 | px = x + width + directionInsets 115 | arrow = 'left' 116 | break 117 | case 'left': 118 | px = x - popoverWidth - directionInsets 119 | arrow = 'right' 120 | break 121 | case 'up': 122 | py = y - popoverHeight - directionInsets 123 | arrow = 'bottom' 124 | break 125 | default: 126 | py = y + height + directionInsets 127 | arrow = 'top' 128 | break 129 | } 130 | if (direction == 'down' || direction == 'up') { 131 | switch (align) { 132 | case 'start': 133 | px = x - alignInsets 134 | arrow += 'Left' 135 | break 136 | case 'center': 137 | px = x + width / 2 - popoverWidth / 2 138 | break 139 | default: 140 | px = x + width - popoverWidth + alignInsets 141 | arrow += 'Right' 142 | break 143 | } 144 | } else if (direction == 'right' || direction == 'left') { 145 | switch (align) { 146 | case 'end': 147 | py = y + height - popoverHeight + alignInsets 148 | arrow += 'Bottom' 149 | break 150 | case 'center': 151 | py = y + height / 2 - popoverHeight / 2 152 | break 153 | default: 154 | py = y - alignInsets 155 | arrow += 'Top' 156 | break 157 | } 158 | } 159 | 160 | popoverStyle = [].concat(popoverStyle).concat({ 161 | position: 'absolute', 162 | left: px, 163 | top: py 164 | }) 165 | if (!showArrow) arrow = 'none' 166 | 167 | this.props = {popoverStyle, direction, autoDirection, directionInsets, align, alignInsets, showArrow, arrow, ...others} 168 | } 169 | 170 | onPopoverLayout (e) { 171 | if (Platform.OS === 'android' && (this.state.popoverWidth !== null || this.state.popoverHeight != null)) { 172 | // android calls many times... 173 | return 174 | } 175 | let {width, height} = e.nativeEvent.layout 176 | if (width !== this.state.popoverWidth || height !== this.state.popoverHeight) { 177 | this.setState({popoverWidth: width, popoverHeight: height}) 178 | } 179 | } 180 | 181 | renderContent () { 182 | let {popoverStyle, arrow, paddingCorner, children} = this.props 183 | 184 | // in react native 0.49, this.props will not reset at rerender, then move opacity=0 to here 185 | let {popoverWidth, popoverHeight} = this.state 186 | if (popoverWidth === null || popoverHeight === null) { 187 | popoverStyle = popoverStyle.concat({opacity: 0}) 188 | } 189 | 190 | return ( 191 | this.onPopoverLayout(e)} 196 | > 197 | {children} 198 | 199 | ) 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/Overlay/OverlayPullView.js: -------------------------------------------------------------------------------- 1 | // OverlayPullView.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import PropTypes from 'prop-types' 7 | import {Animated, View, ViewPropTypes} from 'react-native' 8 | 9 | import TopView from './TopView' 10 | import OverlayView from './OverlayView' 11 | 12 | export default class OverlayPullView extends OverlayView { 13 | static propTypes = { 14 | ...OverlayView.propTypes, 15 | side: PropTypes.oneOf(['top', 'bottom', 'left', 'right']), 16 | containerStyle: ViewPropTypes.style, 17 | rootTransform: PropTypes.oneOfType([ 18 | PropTypes.oneOf(['none', 'translate', 'scale']), 19 | PropTypes.arrayOf(PropTypes.shape({ 20 | translateX: PropTypes.number, 21 | translateY: PropTypes.number, 22 | scaleX: PropTypes.number, 23 | scaleY: PropTypes.number 24 | })) 25 | ]) 26 | }; 27 | 28 | static defaultProps = { 29 | ...OverlayView.defaultProps, 30 | side: 'bottom', 31 | animated: true, 32 | rootTransform: 'none' 33 | }; 34 | 35 | constructor (props) { 36 | super(props) 37 | this.viewLayout = {x: 0, y: 0, width: 0, height: 0} 38 | Object.assign(this.state, { 39 | marginValue: new Animated.Value(0), 40 | showed: false 41 | }) 42 | } 43 | 44 | get appearAnimates () { 45 | let animates = super.appearAnimates 46 | animates.push( 47 | Animated.spring(this.state.marginValue, { 48 | toValue: 0, 49 | friction: 9 50 | }) 51 | ) 52 | return animates 53 | } 54 | 55 | get disappearAnimates () { 56 | let animates = super.disappearAnimates 57 | animates.push( 58 | Animated.spring(this.state.marginValue, { 59 | toValue: this.marginSize, 60 | friction: 9 61 | }) 62 | ) 63 | return animates 64 | } 65 | 66 | get appearAfterMount () { 67 | return false 68 | } 69 | 70 | get marginSize () { 71 | let {side} = this.props 72 | if (side === 'left' || side === 'right') return -this.viewLayout.width 73 | else return -this.viewLayout.height 74 | } 75 | 76 | get rootTransformValue () { 77 | let {side, rootTransform} = this.props 78 | if (!rootTransform || rootTransform === 'none') { 79 | return [] 80 | } 81 | let transform 82 | switch (rootTransform) { 83 | case 'translate': 84 | switch (side) { 85 | case 'top': return [{translateY: this.viewLayout.height}] 86 | case 'left': return [{translateX: this.viewLayout.width}] 87 | case 'right': return [{translateX: -this.viewLayout.width}] 88 | default: return [{translateY: -this.viewLayout.height}] 89 | } 90 | break 91 | case 'scale': 92 | return [{scaleX: 0.93}, {scaleY: 0.93}] 93 | default: 94 | return rootTransform 95 | } 96 | } 97 | 98 | appear (animated = this.props.animated) { 99 | if (animated) { 100 | this.state.marginValue.setValue(this.marginSize) 101 | } 102 | super.appear(animated) 103 | 104 | let {rootTransform} = this.props 105 | if (rootTransform && rootTransform !== 'none') { 106 | TopView.transform(this.rootTransformValue, animated) 107 | } 108 | } 109 | 110 | disappear (animated = this.props.animated) { 111 | let {rootTransform} = this.props 112 | if (rootTransform && rootTransform !== 'none') { 113 | TopView.restore(animated) 114 | } 115 | 116 | super.disappear(animated) 117 | } 118 | 119 | onLayout (e) { 120 | this.viewLayout = e.nativeEvent.layout 121 | if (!this.state.showed) { 122 | this.setState({showed: true}) 123 | this.appear() 124 | } 125 | } 126 | 127 | buildProps () { 128 | super.buildProps() 129 | 130 | let {side, style, containerStyle, ...others} = this.props 131 | 132 | let sideStyle, contentStyle 133 | // Set flexDirection so that the content view will fill the side 134 | switch (side) { 135 | case 'top': 136 | sideStyle = {flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'stretch'} 137 | contentStyle = {marginTop: this.state.marginValue} 138 | break 139 | case 'left': 140 | sideStyle = {flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'stretch'} 141 | contentStyle = {marginLeft: this.state.marginValue} 142 | break 143 | case 'right': 144 | sideStyle = {flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'stretch'} 145 | contentStyle = {marginRight: this.state.marginValue} 146 | break 147 | default: 148 | sideStyle = {flexDirection: 'column', justifyContent: 'flex-end', alignItems: 'stretch'} 149 | contentStyle = {marginBottom: this.state.marginValue} 150 | } 151 | style = [].concat(style).concat(sideStyle) 152 | contentStyle.opacity = this.state.showed ? 1 : 0 153 | containerStyle = [{ 154 | backgroundColor: 'rgba(0, 0, 0, 0)' 155 | }].concat(containerStyle).concat(contentStyle) 156 | 157 | this.props = {side, style, containerStyle, ...others} 158 | } 159 | 160 | renderContent () { 161 | let {containerStyle, children} = this.props 162 | return ( 163 | this.onLayout(e)}> 164 | {children} 165 | 166 | ) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/Overlay/OverlayView.js: -------------------------------------------------------------------------------- 1 | // OverlayView.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import PropTypes from 'prop-types' 7 | import ReactNative, {StyleSheet, Animated, View, PanResponder, Platform, ViewPropTypes} from 'react-native' 8 | 9 | import KeyboardSpace from '../KeyboardSpace/KeyboardSpace' 10 | 11 | export default class OverlayView extends Component { 12 | static propTypes = { 13 | style: ViewPropTypes.style, 14 | modal: PropTypes.bool, 15 | animated: PropTypes.bool, 16 | overlayOpacity: PropTypes.number, 17 | overlayPointerEvents: ViewPropTypes.pointerEvents, 18 | autoKeyboardInsets: PropTypes.bool, 19 | onAppearCompleted: PropTypes.func, 20 | onDisappearCompleted: PropTypes.func, 21 | onCloseRequest: PropTypes.func // (overlayView) 22 | }; 23 | 24 | static defaultProps = { 25 | modal: false, 26 | animated: false, 27 | overlayPointerEvents: 'auto', 28 | autoKeyboardInsets: false 29 | }; 30 | 31 | constructor (props) { 32 | super(props) 33 | this.panResponder = PanResponder.create({ 34 | onStartShouldSetPanResponder: (e, gestureState) => true, 35 | onPanResponderGrant: (e, gestureState) => this.touchStateID = gestureState.stateID, 36 | onPanResponderRelease: (e, gestureState) => this.touchStateID == gestureState.stateID ? this.closeRequest() : null 37 | }) 38 | this.state = { 39 | overlayOpacity: new Animated.Value(0) 40 | } 41 | } 42 | componentDidMount () { 43 | if (Platform.OS === 'android') { 44 | let BackHandler = ReactNative.BackHandler ? ReactNative.BackHandler : ReactNative.BackAndroid 45 | this.backListener = BackHandler.addEventListener('hardwareBackPress', () => { 46 | this.closeRequest() 47 | return true 48 | }) 49 | } 50 | this.appearAfterMount && this.appear() 51 | } 52 | 53 | componentWillUnmount () { 54 | this.removeBackListener() 55 | } 56 | 57 | removeBackListener () { 58 | if (this.backListener) { 59 | this.backListener.remove() 60 | this.backListener = null 61 | } 62 | } 63 | 64 | get overlayOpacity () { 65 | let {overlayOpacity} = this.props 66 | return (overlayOpacity || overlayOpacity === 0) ? overlayOpacity : 0.4 67 | } 68 | 69 | get appearAnimates () { 70 | let duration = 200 71 | let animates = [ 72 | Animated.timing(this.state.overlayOpacity, { 73 | toValue: this.overlayOpacity, 74 | duration, 75 | useNativeDriver: true 76 | }) 77 | ] 78 | return animates 79 | } 80 | 81 | get disappearAnimates () { 82 | let duration = 200 83 | let animates = [ 84 | Animated.timing(this.state.overlayOpacity, { 85 | toValue: 0, 86 | duration, 87 | useNativeDriver: true 88 | }) 89 | ] 90 | return animates 91 | } 92 | 93 | get appearAfterMount () { 94 | return true 95 | } 96 | 97 | appear (animated = this.props.animated, additionAnimates = null) { 98 | if (animated) { 99 | this.state.overlayOpacity.setValue(0) 100 | Animated.parallel(this.appearAnimates.concat(additionAnimates)).start(e => this.appearCompleted()) 101 | } else { 102 | this.state.overlayOpacity.setValue(this.overlayOpacity) 103 | this.appearCompleted() 104 | } 105 | } 106 | 107 | disappear (animated = this.props.animated, additionAnimates = null) { 108 | if (animated) { 109 | Animated.parallel(this.disappearAnimates.concat(additionAnimates)).start(e => this.disappearCompleted()) 110 | this.state.overlayOpacity.addListener(e => { 111 | if (e.value < 0.01) { 112 | this.state.overlayOpacity.stopAnimation() 113 | this.state.overlayOpacity.removeAllListeners() 114 | } 115 | }) 116 | } else { 117 | this.disappearCompleted() 118 | } 119 | } 120 | 121 | appearCompleted () { 122 | let {onAppearCompleted} = this.props 123 | onAppearCompleted && onAppearCompleted() 124 | } 125 | 126 | disappearCompleted () { 127 | let {onDisappearCompleted} = this.props 128 | onDisappearCompleted && onDisappearCompleted() 129 | } 130 | 131 | close (animated = this.props.animated) { 132 | if (this.closed) return true 133 | this.closed = true 134 | this.removeBackListener() 135 | this.disappear(animated) 136 | return true 137 | } 138 | 139 | closeRequest () { 140 | let {modal, onCloseRequest} = this.props 141 | if (onCloseRequest) onCloseRequest(this) 142 | else if (!modal) this.close() 143 | } 144 | 145 | buildProps () { 146 | let {style, ...others} = this.props 147 | style = [{backgroundColor: 'rgba(0, 0, 0, 0)', flex: 1}].concat(style) 148 | this.props = {style, ...others} 149 | } 150 | 151 | renderContent () { 152 | return this.props.children 153 | } 154 | 155 | render () { 156 | this.buildProps() 157 | 158 | let {style, overlayPointerEvents, autoKeyboardInsets, ...others} = this.props 159 | return ( 160 | 161 | 165 | 166 | {this.renderContent()} 167 | 168 | {autoKeyboardInsets ? : null} 169 | 170 | ) 171 | } 172 | } 173 | 174 | var styles = StyleSheet.create({ 175 | screen: { 176 | backgroundColor: 'rgba(0, 0, 0, 0)', 177 | position: 'absolute', 178 | top: 0, 179 | left: 0, 180 | right: 0, 181 | bottom: 0 182 | } 183 | }) 184 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/Overlay/TopView.js: -------------------------------------------------------------------------------- 1 | // TopView.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component, PureComponent} from 'react' 6 | import {StyleSheet, AppRegistry, DeviceEventEmitter, View, Animated} from 'react-native' 7 | // import {Symbol} from 'core-js'; 8 | 9 | let keyValue = 0 10 | 11 | export default class TopView extends Component { 12 | static add (element) { 13 | let key = ++keyValue 14 | DeviceEventEmitter.emit('addOverlay', {key, element}) 15 | return key 16 | } 17 | 18 | static remove (key) { 19 | DeviceEventEmitter.emit('removeOverlay', {key}) 20 | } 21 | 22 | static removeAll () { 23 | DeviceEventEmitter.emit('removeAllOverlay', {}) 24 | } 25 | 26 | static transform (transform, animated, animatesOnly = null) { 27 | DeviceEventEmitter.emit('transformRoot', {transform, animated, animatesOnly}) 28 | } 29 | 30 | static restore (animated, animatesOnly = null) { 31 | DeviceEventEmitter.emit('restoreRoot', {animated, animatesOnly}) 32 | } 33 | 34 | constructor (props) { 35 | super(props) 36 | this.state = { 37 | elements: [], 38 | translateX: new Animated.Value(0), 39 | translateY: new Animated.Value(0), 40 | scaleX: new Animated.Value(1), 41 | scaleY: new Animated.Value(1) 42 | } 43 | } 44 | 45 | componentDidMount() { 46 | DeviceEventEmitter.addListener('addOverlay', e => this.add(e)) 47 | DeviceEventEmitter.addListener('removeOverlay', e => this.remove(e)) 48 | DeviceEventEmitter.addListener('removeAllOverlay', e => this.removeAll(e)) 49 | DeviceEventEmitter.addListener('transformRoot', e => this.transform(e)) 50 | DeviceEventEmitter.addListener('restoreRoot', e => this.restore(e)) 51 | } 52 | 53 | componentWillUnmount () { 54 | DeviceEventEmitter.removeAllListeners('addOverlay') 55 | DeviceEventEmitter.removeAllListeners('removeOverlay') 56 | DeviceEventEmitter.removeAllListeners('removeAllOverlay') 57 | DeviceEventEmitter.removeAllListeners('transformRoot') 58 | DeviceEventEmitter.removeAllListeners('restoreRoot') 59 | } 60 | 61 | add (e) { 62 | let {elements} = this.state 63 | elements.push(e) 64 | this.setState({elements}) 65 | } 66 | 67 | remove (e) { 68 | let {elements} = this.state 69 | for (let i = elements.length - 1; i >= 0; --i) { 70 | if (elements[i].key === e.key) { 71 | elements.splice(i, 1) 72 | break 73 | } 74 | } 75 | this.setState({elements}) 76 | } 77 | 78 | removeAll (e) { 79 | let {elements} = this.state 80 | this.setState({elements: []}) 81 | } 82 | 83 | transform (e) { 84 | let {translateX, translateY, scaleX, scaleY} = this.state 85 | let {transform, animated, animatesOnly} = e 86 | let tx = 0, ty = 0, sx = 1, sy = 1 87 | transform.map(item => { 88 | if (item && typeof item === 'object') { 89 | for (let name in item) { 90 | let value = item[name] 91 | switch (name) { 92 | case 'translateX': tx = value; break 93 | case 'translateY': ty = value; break 94 | case 'scaleX': sx = value; break 95 | case 'scaleY': sy = value; break 96 | } 97 | } 98 | } 99 | }) 100 | if (animated) { 101 | let animates = [ 102 | Animated.spring(translateX, {toValue: tx, friction: 9}), 103 | Animated.spring(translateY, {toValue: ty, friction: 9}), 104 | Animated.spring(scaleX, {toValue: sx, friction: 9}), 105 | Animated.spring(scaleY, {toValue: sy, friction: 9}) 106 | ] 107 | animatesOnly ? animatesOnly(animates) : Animated.parallel(animates).start() 108 | } else { 109 | if (animatesOnly) { 110 | let animates = [ 111 | Animated.timing(translateX, {toValue: tx, duration: 1, useNativeDriver: true}), 112 | Animated.timing(translateY, {toValue: ty, duration: 1, useNativeDriver: true}), 113 | Animated.timing(scaleX, {toValue: sx, duration: 1, useNativeDriver: true}), 114 | Animated.timing(scaleY, {toValue: sy, duration: 1, useNativeDriver: true}) 115 | ] 116 | animatesOnly(animates) 117 | } else { 118 | translateX.setValue(tx) 119 | translateY.setValue(ty) 120 | scaleX.setValue(sx) 121 | scaleY.setValue(sy) 122 | } 123 | } 124 | } 125 | 126 | restore (e) { 127 | let {translateX, translateY, scaleX, scaleY} = this.state 128 | let {animated, animatesOnly} = e 129 | if (animated) { 130 | let animates = [ 131 | Animated.spring(translateX, {toValue: 0, friction: 9}), 132 | Animated.spring(translateY, {toValue: 0, friction: 9}), 133 | Animated.spring(scaleX, {toValue: 1, friction: 9}), 134 | Animated.spring(scaleY, {toValue: 1, friction: 9}) 135 | ] 136 | animatesOnly ? animatesOnly(animates) : Animated.parallel(animates).start() 137 | } else { 138 | if (animatesOnly) { 139 | let animates = [ 140 | Animated.timing(translateX, {toValue: 0, duration: 1, useNativeDriver: true}), 141 | Animated.timing(translateY, {toValue: 0, duration: 1, useNativeDriver: true}), 142 | Animated.timing(scaleX, {toValue: 1, duration: 1, useNativeDriver: true}), 143 | Animated.timing(scaleY, {toValue: 1, duration: 1, useNativeDriver: true}) 144 | ] 145 | animatesOnly(animates) 146 | } else { 147 | translateX.setValue(0) 148 | translateY.setValue(0) 149 | scaleX.setValue(1) 150 | scaleY.setValue(1) 151 | } 152 | } 153 | } 154 | 155 | render () { 156 | let {elements, translateX, translateY, scaleX, scaleY} = this.state 157 | let transform = [{translateX}, {translateY}, {scaleX}, {scaleY}] 158 | return ( 159 | 160 | 161 | 162 | {this.props.children} 163 | 164 | 165 | {elements.map((item, index) => { 166 | return ( 167 | 168 | {item.element} 169 | 170 | ) 171 | })} 172 | 173 | ) 174 | } 175 | } 176 | 177 | var styles = StyleSheet.create({ 178 | overlay: { 179 | backgroundColor: 'rgba(0, 0, 0, 0)', 180 | position: 'absolute', 181 | top: 0, 182 | left: 0, 183 | right: 0, 184 | bottom: 0 185 | } 186 | }) 187 | 188 | class PureView extends PureComponent { 189 | render () { 190 | return ( 191 | 192 | {this.props.children} 193 | 194 | ) 195 | } 196 | } 197 | 198 | if (!AppRegistry.registerComponentOld) { 199 | AppRegistry.registerComponentOld = AppRegistry.registerComponent 200 | } 201 | 202 | AppRegistry.registerComponent = function (appKey, componentProvider) { 203 | class RootElement extends Component { 204 | render () { 205 | let Component = componentProvider() 206 | return ( 207 | 208 | 209 | 210 | ) 211 | } 212 | } 213 | 214 | return AppRegistry.registerComponentOld(appKey, () => RootElement) 215 | } 216 | -------------------------------------------------------------------------------- /app/chat/components/pop-view/index.js: -------------------------------------------------------------------------------- 1 | // ActionPopover.js 2 | 3 | 'use strict' 4 | 5 | import React, {Component} from 'react' 6 | import {View} from 'react-native' 7 | 8 | import Overlay from './Overlay/Overlay' 9 | import ActionPopoverView from './ActionPopover/ActionPopoverView' 10 | 11 | export default class PopView extends Overlay { 12 | static ActionPopoverView = ActionPopoverView; 13 | 14 | // fromBounds shape: x, y, width, height 15 | // items shape 16 | // title: PropTypes.string.isRequired, 17 | // onPress: PropTypes.func, 18 | static show (fromBounds, items, options = {}) { 19 | return super.show( 20 | 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/chat/del/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, StyleSheet, Animated, TouchableOpacity } from 'react-native' 3 | 4 | export default class DelPanel extends PureComponent { 5 | constructor (props) { 6 | super(props) 7 | const { isIphoneX, iphoneXBottomPadding, delPanelStyle } = props 8 | this.height = delPanelStyle?.height ? delPanelStyle.height : 54 9 | this.totalHeight = this.height + (isIphoneX ? iphoneXBottomPadding : 0) 10 | } 11 | 12 | render () { 13 | const { ImageComponent } = this.props 14 | return ( 15 | 31 | 32 | { 33 | this.props.renderDelPanel === undefined 34 | ? this.props.delMessage(this.props.messageSelected, this.props.isInverted)} 38 | > 39 | {this.props.messageDelIcon 40 | ? this.props.messageDelIcon 41 | : } 42 | 43 | : this.props.renderDelPanel(this.props.messageSelected) 44 | } 45 | 46 | 47 | ) 48 | } 49 | } 50 | 51 | const styles = StyleSheet.create({ 52 | button: { 53 | backgroundColor: '#fff', 54 | borderTopWidth: StyleSheet.hairlineWidth, 55 | borderColor: '#ccc', 56 | alignItems: 'center', 57 | justifyContent: 'center' 58 | } 59 | }) 60 | -------------------------------------------------------------------------------- /app/chat/emoji/control.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { StyleSheet, View, ViewPropTypes } from 'react-native' 4 | export default class Control extends PureComponent { 5 | static propTypes = { 6 | ...ViewPropTypes, 7 | dot: PropTypes.element, 8 | activeDot: PropTypes.element 9 | }; 10 | 11 | static defaultProps = { 12 | ...View.defaultProps 13 | }; 14 | 15 | renderDot (dotIndex) { 16 | let { dot, carousel } = this.props 17 | if (React.isValidElement(dot)) { 18 | dot = React.cloneElement(dot, { key: dotIndex, onPress: () => carousel && carousel.scrollToPage(dotIndex) }) 19 | return dot 20 | } 21 | return ( 22 | 32 | ) 33 | } 34 | 35 | renderActiveDot (dotIndex) { 36 | let { activeDot } = this.props 37 | if (React.isValidElement(activeDot)) { 38 | activeDot = React.cloneElement(activeDot, { key: dotIndex }) 39 | return activeDot 40 | } 41 | return ( 42 | 52 | ) 53 | } 54 | 55 | renderDots () { 56 | let { index, total } = this.props 57 | let dots = [] 58 | for (let i = 0; i < total; ++i) { 59 | if (i === index) dots.push(this.renderActiveDot(i)) 60 | else dots.push(this.renderDot(i)) 61 | } 62 | return dots 63 | } 64 | 65 | render () { 66 | let { style, index, total, ...others } = this.props 67 | return ( 68 | 69 | 70 | {this.renderDots()} 71 | 72 | 73 | ) 74 | } 75 | } 76 | 77 | var styles = StyleSheet.create({ 78 | container: { 79 | position: 'absolute', 80 | left: 0, 81 | right: 0, 82 | top: 0, 83 | bottom: 8, 84 | padding: 4, 85 | flexDirection: 'column', 86 | justifyContent: 'flex-end', 87 | alignItems: 'center' 88 | } 89 | }) 90 | -------------------------------------------------------------------------------- /app/chat/emoji/index.android.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, ScrollView, StyleSheet, Platform, Dimensions, Animated, TouchableOpacity } from 'react-native' 3 | import ViewPagerAndroid from 'react-native-pager-view' 4 | import ViewPagerAndroidContainer from '../components/android-container' 5 | import Control from './control' 6 | import { EMOJIS_DATA, DEFAULT_EMOJI } from '../../source/emojis' 7 | const { width, height } = Dimensions.get('window') 8 | 9 | export default class EmojiPanel extends PureComponent { 10 | constructor (props) { 11 | super(props) 12 | this.state = { 13 | pageIndex: 0 14 | } 15 | this.total = 0 16 | } 17 | 18 | switchComponent (e) { 19 | if (Platform.OS === 'ios') { 20 | let { x } = e.nativeEvent.contentOffset 21 | let cardIndex = Math.round(x / width) 22 | if (x >= width / 2 && x < width / 2 + 10) this.scroll.scrollTo({ x: width * cardIndex, y: 0, animated: true }) 23 | this.setState({ pageIndex: cardIndex }) 24 | } else { 25 | let { position, offset } = e.nativeEvent 26 | if (offset === 0) { 27 | this.setState({ pageIndex: position }) 28 | } 29 | } 30 | } 31 | 32 | render () { 33 | const { panelContainerHeight, ImageComponent } = this.props 34 | const ContainerComponent = Platform.select({ ios: ScrollView, android: ViewPagerAndroid }) 35 | this.total = 0 36 | return ( 37 | 48 | 49 | {/* 视图容器 */} 50 | { this.scroll = e }} 52 | onScroll={(e) => this.switchComponent(e)} 53 | onPageScroll={(e) => this.switchComponent(e)} 54 | horizontal 55 | style={{ flex: 1 }} 56 | pagingEnabled 57 | showsHorizontalScrollIndicator={false} 58 | bounces={false} 59 | automaticallyAdjustContentInsets={false} 60 | scrollEventThrottle={200} 61 | > 62 | { 63 | DEFAULT_EMOJI.map((item, index) => { 64 | this.total += 1 65 | return 66 | { 67 | item.map((list, i) => 68 | { 73 | this.props.onPress(list.value) 74 | } 75 | } 76 | > 77 | 79 | 80 | ) 81 | } 82 | 83 | } 84 | ) 85 | } 86 | 87 | 88 | 89 | 90 | {/* */} 91 | {/* */} 92 | {/* /!**!/ */} 93 | {/* */} 94 | {/* */} 95 | 96 | 97 | ) 98 | } 99 | } 100 | 101 | const styles = StyleSheet.create({ 102 | container: { 103 | backgroundColor: '#f9f9f9', 104 | borderTopWidth: StyleSheet.hairlineWidth, 105 | borderColor: '#ccc', 106 | overflow: 'hidden' 107 | } 108 | }) 109 | -------------------------------------------------------------------------------- /app/chat/emoji/index.ios.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, ScrollView, StyleSheet, Platform, Dimensions, Animated, TouchableOpacity } from 'react-native' 3 | import ViewPagerAndroidContainer from '../components/android-container' 4 | import ViewPagerAndroid from '@react-native-community/viewpager' 5 | import Control from './control' 6 | import { EMOJIS_DATA, DEFAULT_EMOJI } from '../../source/emojis' 7 | const { width, height } = Dimensions.get('window') 8 | 9 | export default class EmojiPanel extends PureComponent { 10 | constructor (props) { 11 | super(props) 12 | const { allPanelHeight, isIphoneX, iphoneXBottomPadding } = props 13 | this.totalHeight = allPanelHeight + (isIphoneX ? iphoneXBottomPadding : 0) 14 | this.state = { 15 | pageIndex: 0 16 | } 17 | this.total = 0 18 | } 19 | 20 | switchComponent (e) { 21 | if (Platform.OS === 'ios') { 22 | const { x } = e.nativeEvent.contentOffset 23 | const cardIndex = Math.round(x / width) 24 | if (x >= width / 2 && x < width / 2 + 10) this.scroll.scrollTo({ x: width * cardIndex, y: 0, animated: true }) 25 | this.setState({ pageIndex: cardIndex }) 26 | } else { 27 | const { position, offset } = e.nativeEvent 28 | if (offset === 0) { 29 | this.setState({ pageIndex: position }) 30 | } 31 | } 32 | } 33 | 34 | render () { 35 | const { panelContainerHeight, ImageComponent } = this.props 36 | const ContainerComponent = Platform.select({ ios: ScrollView, android: ViewPagerAndroid }) 37 | this.total = 0 38 | return ( 39 | 53 | 54 | {/* 视图容器 */} 55 | { this.scroll = e }} 57 | onScroll={(e) => this.switchComponent(e)} 58 | onPageScroll={(e) => this.switchComponent(e)} 59 | horizontal 60 | style={{ flex: 1 }} 61 | pagingEnabled 62 | showsHorizontalScrollIndicator={false} 63 | bounces={false} 64 | automaticallyAdjustContentInsets={false} 65 | scrollEventThrottle={200} 66 | > 67 | { 68 | DEFAULT_EMOJI.map((item, index) => { 69 | this.total += 1 70 | return 71 | { 72 | item.map((list, i) => 73 | { 78 | this.props.onPress(list.value) 79 | }} 80 | > 81 | 85 | 86 | ) 87 | } 88 | 89 | } 90 | ) 91 | } 92 | 93 | 94 | 95 | 96 | {/* */} 97 | {/* */} 98 | {/* /!**!/ */} 99 | {/* */} 100 | {/* */} 101 | 102 | 103 | ) 104 | } 105 | } 106 | 107 | const styles = StyleSheet.create({ 108 | container: { 109 | backgroundColor: '#f9f9f9', 110 | borderTopWidth: StyleSheet.hairlineWidth, 111 | borderColor: '#ccc', 112 | overflow: 'hidden' 113 | } 114 | }) 115 | -------------------------------------------------------------------------------- /app/chat/index.js: -------------------------------------------------------------------------------- 1 | import ChatScreen from './ChatView' 2 | import PopView from './components/pop-view' 3 | export { 4 | ChatScreen, 5 | PopView 6 | } 7 | -------------------------------------------------------------------------------- /app/chat/panelContainer/index.android.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, StyleSheet, Dimensions, Animated, Platform } from 'react-native' 3 | const { width, height } = Dimensions.get('window') 4 | import EmojiPanel from '../emoji' 5 | import PlusPanel from '../plus' 6 | export default class PanelContainer extends PureComponent { 7 | constructor (props) { 8 | super(props) 9 | } 10 | 11 | render () { 12 | const { panelContainerHeight, visibleHeight, ImageComponent, panelHeight, emojiHeight, onEmojiSelected} = this.props 13 | return ( 14 | 16 | { 17 | this.props.usePlus 18 | ? 25 | : null 26 | } 27 | { 28 | this.props.useEmoji 29 | ? 35 | : null 36 | } 37 | 38 | ) 39 | } 40 | } 41 | 42 | const styles = StyleSheet.create({ 43 | container: { 44 | flex: 1, 45 | backgroundColor: '#f5f5f5', 46 | borderTopWidth: StyleSheet.hairlineWidth, 47 | borderColor: '#ccc', 48 | paddingHorizontal: 15, 49 | paddingTop: 10, 50 | flexDirection: 'row', 51 | flexWrap: 'wrap' 52 | } 53 | }) 54 | -------------------------------------------------------------------------------- /app/chat/panelContainer/index.ios.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, StyleSheet, Dimensions, Animated, Platform } from 'react-native' 3 | import EmojiPanel from '../emoji' 4 | import PlusPanel from '../plus' 5 | const { width, height } = Dimensions.get('window') 6 | export default class PanelContainer extends PureComponent { 7 | constructor (props) { 8 | super(props) 9 | } 10 | 11 | render () { 12 | const { panelContainerHeight, visibleHeight, ImageComponent, panelHeight, emojiHeight, panelContainerBackgroundColor, onEmojiSelected } = this.props 13 | return ( 14 | 30 | { 31 | this.props.usePlus 32 | ? 39 | : null 40 | } 41 | { 42 | this.props.useEmoji 43 | ? 49 | : null 50 | } 51 | 52 | ) 53 | } 54 | } 55 | 56 | const styles = StyleSheet.create({ 57 | container: { 58 | flex: 1, 59 | backgroundColor: '#f5f5f5', 60 | borderTopWidth: StyleSheet.hairlineWidth, 61 | borderColor: '#ccc', 62 | paddingHorizontal: 15, 63 | paddingTop: 10, 64 | flexDirection: 'row', 65 | flexWrap: 'wrap' 66 | } 67 | }) 68 | -------------------------------------------------------------------------------- /app/chat/plus/index.android.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, StyleSheet, Dimensions, Animated, Platform } from 'react-native' 3 | const { width, height } = Dimensions.get('window') 4 | 5 | export default class PlusPanel extends PureComponent { 6 | constructor (props) { 7 | super(props) 8 | const { allPanelHeight, isIphoneX, iphoneXBottomPadding } = props 9 | this.totalHeight = allPanelHeight + (isIphoneX ? iphoneXBottomPadding : 0) 10 | } 11 | 12 | render () { 13 | const { panelContainerHeight, panelHeight, panelContainerStyle } = this.props 14 | return ( 15 | 30 | 31 | {this.props.panelSource.map((item, index) => 32 | this.props.renderPanelRow(item, index)) 33 | } 34 | 35 | 36 | ) 37 | } 38 | } 39 | 40 | const styles = StyleSheet.create({ 41 | container: { 42 | flex: 1, 43 | backgroundColor: '#f5f5f5', 44 | borderTopWidth: StyleSheet.hairlineWidth, 45 | borderColor: '#ccc', 46 | paddingHorizontal: 15, 47 | paddingTop: 10, 48 | flexDirection: 'row', 49 | flexWrap: 'wrap' 50 | } 51 | }) 52 | -------------------------------------------------------------------------------- /app/chat/plus/index.ios.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { View, StyleSheet, Dimensions, Animated } from 'react-native' 3 | const { width } = Dimensions.get('window') 4 | 5 | export default class PlusPanel extends PureComponent { 6 | 7 | render () { 8 | const { panelContainerHeight, panelHeight, panelContainerStyle } = this.props 9 | return ( 10 | 27 | 28 | {this.props.panelSource.map((item, index) => 29 | this.props.renderPanelRow(item, index)) 30 | } 31 | 32 | 33 | ) 34 | } 35 | } 36 | 37 | const styles = StyleSheet.create({ 38 | container: { 39 | flex: 1, 40 | backgroundColor: '#f5f5f5', 41 | borderTopWidth: StyleSheet.hairlineWidth, 42 | borderColor: '#ccc', 43 | paddingHorizontal: 15, 44 | paddingTop: 10, 45 | flexDirection: 'row', 46 | flexWrap: 'wrap' 47 | } 48 | }) 49 | -------------------------------------------------------------------------------- /app/chat/utils.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | import {Dimensions, Platform} from 'react-native' 3 | import { EMOJIS_ZH, invertKeyValues } from '../source/emojis' 4 | const X_WIDTH = 375 5 | const X_HEIGHT = 812 6 | const XSMAX_WIDTH = 414 7 | const XSMAX_HEIGHT = 896 8 | const PAD_WIDTH = 768 9 | const PAD_HEIGHT = 1024 10 | const IPADPRO11_WIDTH = 834 11 | const IPADPRO11_HEIGHT = 1194 12 | const IPADPRO129_HEIGHT = 1024 13 | const IPADPRO129_WIDTH = 1366 14 | 15 | const { height: D_HEIGHT, width: D_WIDTH } = Dimensions.get('window') 16 | 17 | const getCurrentTime = (time = 0) => { 18 | const nowTime = new Date() // 当前日前对象 19 | const myyear = nowTime.getFullYear() // 当前年份 20 | const myday = nowTime.getDay() // 当前星期 21 | const delay = moment().diff(moment(time).toArray().slice(0, 3), 'days') // 时间差 22 | const old = new Date(parseInt(time)) // 目标日期对象 23 | const oldyear = old.getFullYear() // 目标年份 24 | const oldm = old.getMonth() + 1 // 目标月份 25 | const oldd = old.getDate() // 目标日期 26 | const oldday = old.getDay() // 目标星期 27 | const oldh = old.getHours() // 目标时 28 | const oldmin = old.getMinutes() < 10 ? `0${old.getMinutes()}` : old.getMinutes() // 目标分 29 | // 时间在一天之内只返回时分 30 | if (delay == 0) { 31 | return `${oldh}:${oldmin}` 32 | } 33 | // 时间在两天之内的 34 | if (delay == 1) { 35 | return `昨天 ${oldh}:${oldmin}` 36 | } 37 | 38 | // 当前星期内 39 | if (delay > 1 && myday > oldday && delay < 7) { 40 | let xingqi 41 | switch (oldday) { 42 | case 0: 43 | xingqi = `星期日` 44 | break 45 | case 1: 46 | xingqi = `星期一` 47 | break 48 | case 2: 49 | xingqi = `星期二` 50 | break 51 | case 3: 52 | xingqi = `星期三` 53 | break 54 | case 4: 55 | xingqi = `星期四` 56 | break 57 | case 5: 58 | xingqi = `星期五` 59 | break 60 | case 6: 61 | xingqi = `星期六` 62 | break 63 | } 64 | return `${xingqi} ${oldh}:${oldmin}` 65 | } 66 | 67 | if (delay > 1 && myday === oldday && oldyear === myyear) { 68 | return `${oldm}/${oldd} ${oldh}:${oldmin}` 69 | } 70 | 71 | if (delay > 1 && myday === oldday && oldyear < myyear) { 72 | return `${oldyear}/${oldm}/${oldd} ${oldh}:${oldmin}` 73 | } 74 | 75 | if (delay > 1 && myday < oldday && oldyear === myyear) { 76 | return `${oldm}/${oldd} ${oldh}:${oldmin}` 77 | } 78 | 79 | if (delay > 1 && myday > oldday && oldyear === myyear && delay > 7) { 80 | return `${oldm}/${oldd} ${oldh}:${oldmin}` 81 | } 82 | 83 | if (delay > 1 && myday > oldday && delay >= 7 && oldyear < myyear) { 84 | return `${oldyear}/${oldm}/${oldd} ${oldh}:${oldmin}` 85 | } 86 | 87 | if (delay > 1 && myday < oldday && oldyear < myyear) { 88 | return `${oldyear}/${oldm}/${oldd} ${oldh}:${oldmin}` 89 | } 90 | } 91 | 92 | const _matchContentString = (textContent, data, reg, type) => { 93 | if (textContent.length === 0) return 94 | 95 | // 匹配得到index并放入数组中 96 | let currentTextLength = textContent.length 97 | 98 | let emojiIndex = textContent.search(reg) 99 | 100 | let checkIndexArray = [] 101 | 102 | // 若匹配不到,则直接返回一个全文本 103 | if (emojiIndex === -1) { 104 | data.push(textContent.substring(0, currentTextLength)) 105 | } else { 106 | if (emojiIndex !== -1) { 107 | checkIndexArray.push(emojiIndex) 108 | } 109 | 110 | // 取index最小者 111 | let minIndex = Math.min(...checkIndexArray) 112 | 113 | // 将0-index部分返回文本 114 | data.push(textContent.substring(0, minIndex)) 115 | 116 | // 将index部分作分别处理 117 | _matchEmojiString(textContent.substring(minIndex), data, reg, type) 118 | } 119 | } 120 | 121 | const _matchEmojiString = (emojiStr, data, reg, type) => { 122 | let castStr = emojiStr.match(reg) 123 | let emojiLength = castStr[0].length 124 | let emotoinsCode = EMOJIS_ZH 125 | if (type === 'zh') { 126 | emotoinsCode = invertKeyValues(EMOJIS_ZH) 127 | } 128 | if(emotoinsCode[castStr[0]]){ 129 | data.push(emotoinsCode[castStr[0]]) 130 | }else { 131 | return data.push(emojiStr) 132 | } 133 | _matchContentString(emojiStr.substring(emojiLength), data, reg, type) 134 | } 135 | 136 | const changeEmojiText = (textContent, type = 'zh') => { 137 | let data = [] 138 | let emojiReg = null 139 | if (type === 'zh') { 140 | emojiReg = new RegExp('\\[[^\\]]+\\]', 'g') 141 | } else { 142 | emojiReg = new RegExp('\\/\\{[a-zA-Z_]{1,14}\\}', 'g') 143 | } 144 | _matchContentString(textContent, data, emojiReg, type) 145 | return data 146 | } 147 | 148 | const isIPhoneX = () => { 149 | return ( 150 | (Platform.OS === 'ios' && 151 | ((D_HEIGHT === X_HEIGHT && D_WIDTH === X_WIDTH) || 152 | (D_HEIGHT === X_WIDTH && D_WIDTH === X_HEIGHT))) || 153 | ((D_HEIGHT === XSMAX_HEIGHT && D_WIDTH === XSMAX_WIDTH) || 154 | (D_HEIGHT === XSMAX_WIDTH && D_WIDTH === XSMAX_HEIGHT)) 155 | ) 156 | } 157 | export { 158 | getCurrentTime, 159 | changeEmojiText, 160 | isIPhoneX 161 | } 162 | -------------------------------------------------------------------------------- /app/source/emojis/aixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/aixin.png -------------------------------------------------------------------------------- /app/source/emojis/aohuo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/aohuo.png -------------------------------------------------------------------------------- /app/source/emojis/aoman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/aoman.png -------------------------------------------------------------------------------- /app/source/emojis/baiyan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/baiyan.png -------------------------------------------------------------------------------- /app/source/emojis/baoquan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/baoquan.png -------------------------------------------------------------------------------- /app/source/emojis/beishang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/beishang.png -------------------------------------------------------------------------------- /app/source/emojis/bianbian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/bianbian.png -------------------------------------------------------------------------------- /app/source/emojis/bishi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/bishi.png -------------------------------------------------------------------------------- /app/source/emojis/bizui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/bizui.png -------------------------------------------------------------------------------- /app/source/emojis/buxie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/buxie.png -------------------------------------------------------------------------------- /app/source/emojis/cahan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/cahan.png -------------------------------------------------------------------------------- /app/source/emojis/caidao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/caidao.png -------------------------------------------------------------------------------- /app/source/emojis/daku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/daku.png -------------------------------------------------------------------------------- /app/source/emojis/dangao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/dangao.png -------------------------------------------------------------------------------- /app/source/emojis/deyi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/deyi.png -------------------------------------------------------------------------------- /app/source/emojis/diaoxie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/diaoxie.png -------------------------------------------------------------------------------- /app/source/emojis/fa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/fa.png -------------------------------------------------------------------------------- /app/source/emojis/fadai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/fadai.png -------------------------------------------------------------------------------- /app/source/emojis/fadou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/fadou.png -------------------------------------------------------------------------------- /app/source/emojis/fanu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/fanu.png -------------------------------------------------------------------------------- /app/source/emojis/faxiao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/faxiao.png -------------------------------------------------------------------------------- /app/source/emojis/fendou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/fendou.png -------------------------------------------------------------------------------- /app/source/emojis/ganga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ganga.png -------------------------------------------------------------------------------- /app/source/emojis/gaoxing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/gaoxing.png -------------------------------------------------------------------------------- /app/source/emojis/gouying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/gouying.png -------------------------------------------------------------------------------- /app/source/emojis/guilian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/guilian.png -------------------------------------------------------------------------------- /app/source/emojis/guzhang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/guzhang.png -------------------------------------------------------------------------------- /app/source/emojis/haixiu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/haixiu.png -------------------------------------------------------------------------------- /app/source/emojis/hanxiao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/hanxiao.png -------------------------------------------------------------------------------- /app/source/emojis/haqian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/haqian.png -------------------------------------------------------------------------------- /app/source/emojis/heiha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/heiha.png -------------------------------------------------------------------------------- /app/source/emojis/heshi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/heshi.png -------------------------------------------------------------------------------- /app/source/emojis/hongbao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/hongbao.png -------------------------------------------------------------------------------- /app/source/emojis/huaixiao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/huaixiao.png -------------------------------------------------------------------------------- /app/source/emojis/ic_emoji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ic_emoji.png -------------------------------------------------------------------------------- /app/source/emojis/ic_emoji_del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ic_emoji_del.png -------------------------------------------------------------------------------- /app/source/emojis/ji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ji.png -------------------------------------------------------------------------------- /app/source/emojis/jianxiao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/jianxiao.png -------------------------------------------------------------------------------- /app/source/emojis/jiayou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/jiayou.png -------------------------------------------------------------------------------- /app/source/emojis/jinkong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/jinkong.png -------------------------------------------------------------------------------- /app/source/emojis/jinya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/jinya.png -------------------------------------------------------------------------------- /app/source/emojis/jiong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/jiong.png -------------------------------------------------------------------------------- /app/source/emojis/jizhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/jizhi.png -------------------------------------------------------------------------------- /app/source/emojis/kafei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/kafei.png -------------------------------------------------------------------------------- /app/source/emojis/kelian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/kelian.png -------------------------------------------------------------------------------- /app/source/emojis/kongju.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/kongju.png -------------------------------------------------------------------------------- /app/source/emojis/koubi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/koubi.png -------------------------------------------------------------------------------- /app/source/emojis/kouzhao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/kouzhao.png -------------------------------------------------------------------------------- /app/source/emojis/kuaikule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/kuaikule.png -------------------------------------------------------------------------------- /app/source/emojis/kulu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/kulu.png -------------------------------------------------------------------------------- /app/source/emojis/kun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/kun.png -------------------------------------------------------------------------------- /app/source/emojis/liuhan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/liuhan.png -------------------------------------------------------------------------------- /app/source/emojis/liulei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/liulei.png -------------------------------------------------------------------------------- /app/source/emojis/liwu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/liwu.png -------------------------------------------------------------------------------- /app/source/emojis/meigui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/meigui.png -------------------------------------------------------------------------------- /app/source/emojis/nanguo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/nanguo.png -------------------------------------------------------------------------------- /app/source/emojis/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ok.png -------------------------------------------------------------------------------- /app/source/emojis/piezui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/piezui.png -------------------------------------------------------------------------------- /app/source/emojis/pijiu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/pijiu.png -------------------------------------------------------------------------------- /app/source/emojis/qiang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/qiang.png -------------------------------------------------------------------------------- /app/source/emojis/qiaoda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/qiaoda.png -------------------------------------------------------------------------------- /app/source/emojis/qingzhu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/qingzhu.png -------------------------------------------------------------------------------- /app/source/emojis/qinqin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/qinqin.png -------------------------------------------------------------------------------- /app/source/emojis/quantou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/quantou.png -------------------------------------------------------------------------------- /app/source/emojis/ruo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ruo.png -------------------------------------------------------------------------------- /app/source/emojis/se.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/se.png -------------------------------------------------------------------------------- /app/source/emojis/shadai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/shadai.png -------------------------------------------------------------------------------- /app/source/emojis/shengli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/shengli.png -------------------------------------------------------------------------------- /app/source/emojis/shuai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/shuai.png -------------------------------------------------------------------------------- /app/source/emojis/shui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/shui.png -------------------------------------------------------------------------------- /app/source/emojis/taiyang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/taiyang.png -------------------------------------------------------------------------------- /app/source/emojis/tiaopi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/tiaopi.png -------------------------------------------------------------------------------- /app/source/emojis/tiaotiao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/tiaotiao.png -------------------------------------------------------------------------------- /app/source/emojis/tu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/tu.png -------------------------------------------------------------------------------- /app/source/emojis/tushetou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/tushetou.png -------------------------------------------------------------------------------- /app/source/emojis/weiqu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/weiqu.png -------------------------------------------------------------------------------- /app/source/emojis/weixiao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/weixiao.png -------------------------------------------------------------------------------- /app/source/emojis/woshou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/woshou.png -------------------------------------------------------------------------------- /app/source/emojis/wulian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/wulian.png -------------------------------------------------------------------------------- /app/source/emojis/xiaoku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/xiaoku.png -------------------------------------------------------------------------------- /app/source/emojis/xigua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/xigua.png -------------------------------------------------------------------------------- /app/source/emojis/xinsui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/xinsui.png -------------------------------------------------------------------------------- /app/source/emojis/xu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/xu.png -------------------------------------------------------------------------------- /app/source/emojis/ye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ye.png -------------------------------------------------------------------------------- /app/source/emojis/yinxian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/yinxian.png -------------------------------------------------------------------------------- /app/source/emojis/yiwen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/yiwen.png -------------------------------------------------------------------------------- /app/source/emojis/yongbao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/yongbao.png -------------------------------------------------------------------------------- /app/source/emojis/youhengheng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/youhengheng.png -------------------------------------------------------------------------------- /app/source/emojis/youxian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/youxian.png -------------------------------------------------------------------------------- /app/source/emojis/yueliang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/yueliang.png -------------------------------------------------------------------------------- /app/source/emojis/yukuai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/yukuai.png -------------------------------------------------------------------------------- /app/source/emojis/yun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/yun.png -------------------------------------------------------------------------------- /app/source/emojis/zaijian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zaijian.png -------------------------------------------------------------------------------- /app/source/emojis/zhadan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zhadan.png -------------------------------------------------------------------------------- /app/source/emojis/zhouma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zhouma.png -------------------------------------------------------------------------------- /app/source/emojis/zhoumei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zhoumei.png -------------------------------------------------------------------------------- /app/source/emojis/zhuakuang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zhuakuang.png -------------------------------------------------------------------------------- /app/source/emojis/zhuanquan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zhuanquan.png -------------------------------------------------------------------------------- /app/source/emojis/zhutou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zhutou.png -------------------------------------------------------------------------------- /app/source/emojis/ziya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/ziya.png -------------------------------------------------------------------------------- /app/source/emojis/zuichun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zuichun.png -------------------------------------------------------------------------------- /app/source/emojis/zuohengheng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/emojis/zuohengheng.png -------------------------------------------------------------------------------- /app/source/image/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/avatar.png -------------------------------------------------------------------------------- /app/source/image/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/camera.png -------------------------------------------------------------------------------- /app/source/image/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/check.png -------------------------------------------------------------------------------- /app/source/image/defaultAvatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/defaultAvatar.png -------------------------------------------------------------------------------- /app/source/image/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/delete.png -------------------------------------------------------------------------------- /app/source/image/emoji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/emoji.png -------------------------------------------------------------------------------- /app/source/image/keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/keyboard.png -------------------------------------------------------------------------------- /app/source/image/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/more.png -------------------------------------------------------------------------------- /app/source/image/photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/photo.png -------------------------------------------------------------------------------- /app/source/image/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/play.png -------------------------------------------------------------------------------- /app/source/image/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/send.png -------------------------------------------------------------------------------- /app/source/image/sendAble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/sendAble.png -------------------------------------------------------------------------------- /app/source/image/speak0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak0.png -------------------------------------------------------------------------------- /app/source/image/speak1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak1.png -------------------------------------------------------------------------------- /app/source/image/speak2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak2.png -------------------------------------------------------------------------------- /app/source/image/speak3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak3.png -------------------------------------------------------------------------------- /app/source/image/speak4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak4.png -------------------------------------------------------------------------------- /app/source/image/speak5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak5.png -------------------------------------------------------------------------------- /app/source/image/speak6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak6.png -------------------------------------------------------------------------------- /app/source/image/speak7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak7.png -------------------------------------------------------------------------------- /app/source/image/speak8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/speak8.png -------------------------------------------------------------------------------- /app/source/image/voice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voice.png -------------------------------------------------------------------------------- /app/source/image/voiceCancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceCancel.png -------------------------------------------------------------------------------- /app/source/image/voiceError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceError.png -------------------------------------------------------------------------------- /app/source/image/voiceLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceLeft.png -------------------------------------------------------------------------------- /app/source/image/voiceLeftOne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceLeftOne.png -------------------------------------------------------------------------------- /app/source/image/voiceLeftTwo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceLeftTwo.png -------------------------------------------------------------------------------- /app/source/image/voiceRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceRight.png -------------------------------------------------------------------------------- /app/source/image/voiceRightOne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceRightOne.png -------------------------------------------------------------------------------- /app/source/image/voiceRightTwo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/voiceRightTwo.png -------------------------------------------------------------------------------- /app/source/image/waring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/app/source/image/waring.png -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore polyfills 9 | node_modules/react-native/Libraries/polyfills/.* 10 | 11 | ; These should not be required directly 12 | ; require from fbjs/lib instead: require('fbjs/lib/warning') 13 | node_modules/warning/.* 14 | 15 | ; Flow doesn't support platforms 16 | .*/Libraries/Utilities/LoadingView.js 17 | 18 | [untyped] 19 | .*/node_modules/@react-native-community/cli/.*/.* 20 | 21 | [include] 22 | 23 | [libs] 24 | node_modules/react-native/Libraries/react-native/react-native-interface.js 25 | node_modules/react-native/flow/ 26 | 27 | [options] 28 | emoji=true 29 | 30 | esproposal.optional_chaining=enable 31 | esproposal.nullish_coalescing=enable 32 | 33 | module.file_ext=.js 34 | module.file_ext=.json 35 | module.file_ext=.ios.js 36 | 37 | munge_underscores=true 38 | 39 | module.name_mapper='^react-native$' -> '/node_modules/react-native/Libraries/react-native/react-native-implementation' 40 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' 41 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' 42 | 43 | suppress_type=$FlowIssue 44 | suppress_type=$FlowFixMe 45 | suppress_type=$FlowFixMeProps 46 | suppress_type=$FlowFixMeState 47 | 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 51 | 52 | [lints] 53 | sketchy-null-number=warn 54 | sketchy-null-mixed=warn 55 | sketchy-number=warn 56 | untyped-type-import=warn 57 | nonstrict-import=warn 58 | deprecated-type=warn 59 | unsafe-getters-setters=warn 60 | inexact-spread=warn 61 | unnecessary-invariant=warn 62 | signature-verification-failure=warn 63 | deprecated-utility=error 64 | 65 | [strict] 66 | deprecated-type 67 | nonstrict-import 68 | sketchy-null 69 | unclear-type 70 | unsafe-getters-setters 71 | untyped-import 72 | untyped-type-import 73 | 74 | [version] 75 | ^0.105.0 76 | -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | yarn-error.log 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | !debug.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | /ios/Pods/ 60 | /src/app 61 | -------------------------------------------------------------------------------- /example/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Platform, StyleSheet, Text, View } from 'react-native' 3 | import Navigator from './src/navigator' 4 | 5 | export default class App extends Component { 6 | render () { 7 | return ( 8 | 9 | 10 | 11 | ) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /example/android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.example", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.example", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format 22 | * bundleCommand: "ram-bundle", 23 | * 24 | * // whether to bundle JS and assets in debug mode 25 | * bundleInDebug: false, 26 | * 27 | * // whether to bundle JS and assets in release mode 28 | * bundleInRelease: true, 29 | * 30 | * // whether to bundle JS and assets in another build variant (if configured). 31 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 32 | * // The configuration property can be in the following formats 33 | * // 'bundleIn${productFlavor}${buildType}' 34 | * // 'bundleIn${buildType}' 35 | * // bundleInFreeDebug: true, 36 | * // bundleInPaidRelease: true, 37 | * // bundleInBeta: true, 38 | * 39 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 40 | * // for example: to disable dev mode in the staging build type (if configured) 41 | * devDisabledInStaging: true, 42 | * // The configuration property can be in the following formats 43 | * // 'devDisabledIn${productFlavor}${buildType}' 44 | * // 'devDisabledIn${buildType}' 45 | * 46 | * // the root of your project, i.e. where "package.json" lives 47 | * root: "../../", 48 | * 49 | * // where to put the JS bundle asset in debug mode 50 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 51 | * 52 | * // where to put the JS bundle asset in release mode 53 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 54 | * 55 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 56 | * // require('./image.png')), in debug mode 57 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 58 | * 59 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 60 | * // require('./image.png')), in release mode 61 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 62 | * 63 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 64 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 65 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 66 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 67 | * // for example, you might want to remove it from here. 68 | * inputExcludes: ["android/**", "ios/**"], 69 | * 70 | * // override which node gets called and with what additional arguments 71 | * nodeExecutableAndArgs: ["node"], 72 | * 73 | * // supply additional arguments to the packager 74 | * extraPackagerArgs: [] 75 | * ] 76 | */ 77 | 78 | project.ext.react = [ 79 | entryFile: "index.js", 80 | enableHermes: false, // clean and rebuild if changing 81 | ] 82 | 83 | apply from: "../../node_modules/react-native/react.gradle" 84 | 85 | /** 86 | * Set this to true to create two separate APKs instead of one: 87 | * - An APK that only works on ARM devices 88 | * - An APK that only works on x86 devices 89 | * The advantage is the size of the APK is reduced by about 4MB. 90 | * Upload all the APKs to the Play Store and people will download 91 | * the correct one based on the CPU architecture of their device. 92 | */ 93 | def enableSeparateBuildPerCPUArchitecture = false 94 | 95 | /** 96 | * Run Proguard to shrink the Java bytecode in release builds. 97 | */ 98 | def enableProguardInReleaseBuilds = false 99 | 100 | /** 101 | * The preferred build flavor of JavaScriptCore. 102 | * 103 | * For example, to use the international variant, you can use: 104 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 105 | * 106 | * The international variant includes ICU i18n library and necessary data 107 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 108 | * give correct results when using with locales other than en-US. Note that 109 | * this variant is about 6MiB larger per architecture than default. 110 | */ 111 | def jscFlavor = 'org.webkit:android-jsc:+' 112 | 113 | /** 114 | * Whether to enable the Hermes VM. 115 | * 116 | * This should be set on project.ext.react and mirrored here. If it is not set 117 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode 118 | * and the benefits of using Hermes will therefore be sharply reduced. 119 | */ 120 | def enableHermes = project.ext.react.get("enableHermes", false); 121 | 122 | android { 123 | compileSdkVersion rootProject.ext.compileSdkVersion 124 | 125 | compileOptions { 126 | sourceCompatibility JavaVersion.VERSION_1_8 127 | targetCompatibility JavaVersion.VERSION_1_8 128 | } 129 | 130 | defaultConfig { 131 | applicationId "com.example" 132 | minSdkVersion rootProject.ext.minSdkVersion 133 | targetSdkVersion rootProject.ext.targetSdkVersion 134 | versionCode 1 135 | versionName "1.0" 136 | } 137 | splits { 138 | abi { 139 | reset() 140 | enable enableSeparateBuildPerCPUArchitecture 141 | universalApk false // If true, also generate a universal APK 142 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" 143 | } 144 | } 145 | signingConfigs { 146 | debug { 147 | storeFile file('debug.keystore') 148 | storePassword 'android' 149 | keyAlias 'androiddebugkey' 150 | keyPassword 'android' 151 | } 152 | } 153 | buildTypes { 154 | debug { 155 | signingConfig signingConfigs.debug 156 | } 157 | release { 158 | // Caution! In production, you need to generate your own keystore file. 159 | // see https://facebook.github.io/react-native/docs/signed-apk-android. 160 | signingConfig signingConfigs.debug 161 | minifyEnabled enableProguardInReleaseBuilds 162 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 163 | } 164 | } 165 | // applicationVariants are e.g. debug, release 166 | applicationVariants.all { variant -> 167 | variant.outputs.each { output -> 168 | // For each separate APK per architecture, set a unique version code as described here: 169 | // https://developer.android.com/studio/build/configure-apk-splits.html 170 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 171 | def abi = output.getFilter(OutputFile.ABI) 172 | if (abi != null) { // null for the universal-debug, universal-release variants 173 | output.versionCodeOverride = 174 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 175 | } 176 | 177 | } 178 | } 179 | } 180 | 181 | dependencies { 182 | apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" 183 | implementation fileTree(dir: "libs", include: ["*.jar"]) 184 | implementation "com.facebook.react:react-native:+" // From node_modules 185 | 186 | if (enableHermes) { 187 | def hermesPath = "../../node_modules/hermes-engine/android/"; 188 | debugImplementation files(hermesPath + "hermes-debug.aar") 189 | releaseImplementation files(hermesPath + "hermes-release.aar") 190 | } else { 191 | implementation jscFlavor 192 | } 193 | } 194 | 195 | // Run this once to be able to run the application with BUCK 196 | // puts all compile dependencies into folder libs for BUCK to use 197 | task copyDownloadableDepsToLibs(type: Copy) { 198 | from configurations.compile 199 | into 'libs' 200 | } 201 | 202 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 203 | -------------------------------------------------------------------------------- /example/android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /example/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/debug.keystore -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. This is used to schedule 9 | * rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "example"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import com.facebook.react.PackageList; 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.soloader.SoLoader; 10 | import java.lang.reflect.InvocationTargetException; 11 | import java.util.List; 12 | 13 | public class MainApplication extends Application implements ReactApplication { 14 | 15 | private final ReactNativeHost mReactNativeHost = 16 | new ReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return BuildConfig.DEBUG; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | @SuppressWarnings("UnnecessaryLocalVariable") 25 | List packages = new PackageList(this).getPackages(); 26 | // Packages that cannot be autolinked yet can be added manually here, for example: 27 | // packages.add(new MyReactNativePackage()); 28 | return packages; 29 | } 30 | 31 | @Override 32 | protected String getJSMainModuleName() { 33 | return "index"; 34 | } 35 | }; 36 | 37 | @Override 38 | public ReactNativeHost getReactNativeHost() { 39 | return mReactNativeHost; 40 | } 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | SoLoader.init(this, /* native exopackage */ false); 46 | initializeFlipper(this); // Remove this line if you don't want Flipper enabled 47 | } 48 | 49 | /** 50 | * Loads Flipper in React Native templates. 51 | * 52 | * @param context 53 | */ 54 | private static void initializeFlipper(Context context) { 55 | if (BuildConfig.DEBUG) { 56 | try { 57 | /* 58 | We use reflection here to pick up the class that initializes Flipper, 59 | since Flipper library is not available in release mode 60 | */ 61 | Class aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper"); 62 | aClass.getMethod("initializeFlipper", Context.class).invoke(null, context); 63 | } catch (ClassNotFoundException e) { 64 | e.printStackTrace(); 65 | } catch (NoSuchMethodException e) { 66 | e.printStackTrace(); 67 | } catch (IllegalAccessException e) { 68 | e.printStackTrace(); 69 | } catch (InvocationTargetException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | example 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "28.0.3" 6 | minSdkVersion = 16 7 | compileSdkVersion = 28 8 | targetSdkVersion = 28 9 | } 10 | repositories { 11 | google() 12 | jcenter() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle:3.4.2") 16 | 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | mavenLocal() 25 | maven { 26 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 27 | url("$rootDir/../node_modules/react-native/android") 28 | } 29 | maven { 30 | // Android JSC is installed from npm 31 | url("$rootDir/../node_modules/jsc-android/dist") 32 | } 33 | 34 | google() 35 | jcenter() 36 | maven { url 'https://jitpack.io' } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useAndroidX=true 21 | android.enableJetifier=true 22 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'example' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "displayName": "example" 4 | } -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import { AppRegistry } from 'react-native' 6 | import App from './App' 7 | import { name as appName } from './app.json' 8 | 9 | AppRegistry.registerComponent(appName, () => App) 10 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.0' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | target 'example' do 5 | # Pods for example 6 | pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" 7 | pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" 8 | pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" 9 | pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" 10 | pod 'React', :path => '../node_modules/react-native/' 11 | pod 'React-Core', :path => '../node_modules/react-native/' 12 | pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' 13 | pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' 14 | pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' 15 | pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' 16 | pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' 17 | pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' 18 | pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' 19 | pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' 20 | pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' 21 | pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' 22 | pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' 23 | pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' 24 | 25 | pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' 26 | pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' 27 | pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' 28 | pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' 29 | pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon" 30 | pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" 31 | pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' 32 | 33 | pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' 34 | pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' 35 | pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' 36 | 37 | 38 | use_native_modules! 39 | end 40 | -------------------------------------------------------------------------------- /example/ios/example-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /example/ios/example-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/ios/example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (nonatomic, strong) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import "AppDelegate.h" 9 | 10 | #import 11 | #import 12 | #import 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 19 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge 20 | moduleName:@"example" 21 | initialProperties:nil]; 22 | 23 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 24 | 25 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 26 | UIViewController *rootViewController = [UIViewController new]; 27 | rootViewController.view = rootView; 28 | self.window.rootViewController = rootViewController; 29 | [self.window makeKeyAndVisible]; 30 | return YES; 31 | } 32 | 33 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 34 | { 35 | #if DEBUG 36 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 37 | #else 38 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 39 | #endif 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /example/ios/example/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /example/ios/example/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSExceptionDomains 32 | 33 | localhost 34 | 35 | NSExceptionAllowsInsecureHTTPLoads 36 | 37 | 38 | 39 | 40 | NSLocationWhenInUseUsageDescription 41 | 42 | NSMicrophoneUsageDescription 43 | This sample uses the microphone to record your speech and convert it to text. 44 | UIAppFonts 45 | 46 | AntDesign.ttf 47 | Entypo.ttf 48 | EvilIcons.ttf 49 | Feather.ttf 50 | FontAwesome.ttf 51 | FontAwesome5_Brands.ttf 52 | FontAwesome5_Regular.ttf 53 | FontAwesome5_Solid.ttf 54 | Foundation.ttf 55 | Ionicons.ttf 56 | MaterialIcons.ttf 57 | MaterialCommunityIcons.ttf 58 | SimpleLineIcons.ttf 59 | Octicons.ttf 60 | Zocial.ttf 61 | 62 | UILaunchStoryboardName 63 | LaunchScreen 64 | UIRequiredDeviceCapabilities 65 | 66 | armv7 67 | 68 | UISupportedInterfaceOrientations 69 | 70 | UIInterfaceOrientationPortrait 71 | 72 | UIViewControllerBasedStatusBarAppearance 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /example/ios/example/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/ios/exampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/exampleTests/exampleTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 16 | 17 | @interface exampleTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation exampleTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | #ifdef DEBUG 44 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 45 | if (level >= RCTLogLevelError) { 46 | redboxError = message; 47 | } 48 | }); 49 | #endif 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | #ifdef DEBUG 64 | RCTSetLogFunction(RCTDefaultLogFunction); 65 | #endif 66 | 67 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 68 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 69 | } 70 | 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | module.exports = { 9 | transformer: { 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: false, 14 | }, 15 | }), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "test": "jest", 10 | "lint": "eslint ." 11 | }, 12 | "dependencies": { 13 | "@react-native-community/viewpager": "^3.3.0", 14 | "moment": "^2.24.0", 15 | "react": "16.9.0", 16 | "react-native": "0.61.5", 17 | "react-native-audio": "^4.3.0", 18 | "react-native-device-info": "^8.0.1", 19 | "react-native-fast-image": "^7.0.2", 20 | "react-native-fs": "^2.16.2", 21 | "react-native-gesture-handler": "^1.9.0", 22 | "react-native-sound": "^0.11.0", 23 | "react-native-vector-icons": "^6.6.0", 24 | "react-navigation": "^3.3.2" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "^7.7.7", 28 | "@babel/runtime": "^7.7.7", 29 | "@react-native-community/eslint-config": "^0.0.5", 30 | "babel-jest": "^24.9.0", 31 | "eslint": "^6.8.0", 32 | "jest": "^24.9.0", 33 | "metro-react-native-babel-preset": "^0.57.0", 34 | "react-test-renderer": "16.9.0" 35 | }, 36 | "jest": { 37 | "preset": "react-native" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /example/src/navigator.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { TouchableOpacity, Text, StyleSheet, Dimensions, View } from 'react-native' 3 | import { createStackNavigator, createBottomTabNavigator, createAppContainer, createSwitchNavigator } from 'react-navigation' 4 | import Material from 'react-native-vector-icons/MaterialIcons' 5 | import Views from './view' 6 | const { width } = Dimensions.get('window') 7 | const _HEADER_BACK_BUTTON = (navigation) => { 8 | const { routeName } = navigation.state 9 | return ( navigation.goBack()} 13 | > 14 | 15 | ) 16 | } 17 | const MODAL_DEFAULT_OPTIONS = { 18 | mode: 'modal', 19 | headerMode: 'none' 20 | } 21 | 22 | const STACKNAVIGATOR_DEFAULT_OPTIONS = { 23 | defaultNavigationOptions: ({ navigation }) => { 24 | let options = { 25 | headerTitle: ( 26 | null 27 | ), 28 | drawerLockMode: 'locked-closed', 29 | headerStyle: { 30 | backgroundColor: '#fff', 31 | shadowOffset: { width: 0, height: 0 }, 32 | shadowColor: 'transparent', 33 | shadowOpacity: 0, 34 | borderBottomWidth: 0, 35 | borderBottomColor: 'transparent', 36 | elevation: 0 37 | }, 38 | headerTintColor: '#333', 39 | headerTitleStyle: { fontSize: 17, fontWeight: '600' }, 40 | headerBackTitle: null, 41 | headerRight: 42 | } 43 | if (!('index' in navigation.state)) { 44 | options = { ...options, headerLeft: _HEADER_BACK_BUTTON(navigation) } 45 | } 46 | return options 47 | } 48 | } 49 | 50 | const AppNavigator = createStackNavigator({ ...Views }, { ...STACKNAVIGATOR_DEFAULT_OPTIONS }) 51 | 52 | const IncludeModalContainerNavigator = createStackNavigator({ 53 | Base: { screen: AppNavigator } 54 | /* add modal screen */ 55 | }, { ...MODAL_DEFAULT_OPTIONS }) 56 | 57 | const Base = createSwitchNavigator({ 58 | // Load: ExtraViews.Loading, 59 | App: IncludeModalContainerNavigator, 60 | Auth: Views.Home 61 | }, { initialRouteName: 'Auth' }) 62 | 63 | const AppContainer = createAppContainer(IncludeModalContainerNavigator) 64 | 65 | export default AppContainer 66 | -------------------------------------------------------------------------------- /example/src/source/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/src/source/avatar.png -------------------------------------------------------------------------------- /example/src/source/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/src/source/bg.jpg -------------------------------------------------------------------------------- /example/src/source/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/src/source/camera.png -------------------------------------------------------------------------------- /example/src/source/defaultAvatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/src/source/defaultAvatar.png -------------------------------------------------------------------------------- /example/src/source/photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/example/src/source/photo.png -------------------------------------------------------------------------------- /example/src/view/home/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | * @flow 7 | * @lint-ignore-every XPLATJSCOPYRIGHT1 8 | */ 9 | 10 | import React, {Component} from 'react'; 11 | import {Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native'; 12 | import Example from "../example"; 13 | 14 | const instructions = Platform.select({ 15 | ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu', 16 | android: 17 | 'Double tap R on your keyboard to reload,\n' + 18 | 'Shake or press menu button for dev menu', 19 | }); 20 | 21 | type Props = {}; 22 | export default class Home extends Component { 23 | static navigationOptions = ({ navigation }) => { 24 | return { 25 | header: null 26 | } 27 | } 28 | render() { 29 | return ( 30 | 31 | this.props.navigation.navigate('Example')}> 32 | 聊天测试 33 | 34 | 35 | ); 36 | } 37 | } 38 | 39 | const styles = StyleSheet.create({ 40 | container: { 41 | flex: 1, 42 | justifyContent: 'center', 43 | alignItems: 'center', 44 | backgroundColor: '#F5FCFF', 45 | }, 46 | welcome: { 47 | fontSize: 20, 48 | textAlign: 'center', 49 | margin: 10, 50 | }, 51 | instructions: { 52 | textAlign: 'center', 53 | color: '#333333', 54 | marginBottom: 5, 55 | }, 56 | }); 57 | -------------------------------------------------------------------------------- /example/src/view/index.js: -------------------------------------------------------------------------------- 1 | 2 | import Home from './home' 3 | import Example from './example' 4 | export default { 5 | Home, 6 | Example 7 | } 8 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import ChatScreen from './app/chat/ChatView' 2 | import PopView from './app/chat/components/pop-view' 3 | import { EMOJIS_DATA } from './app/source/emojis/index' 4 | export { 5 | ChatScreen, 6 | PopView, 7 | EMOJIS_DATA 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-easy-chat-ui", 3 | "version": "0.4.14", 4 | "description": "chat UI for React Native", 5 | "main": "index.js", 6 | "directories": { 7 | "example": "Demo" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/DaiYz/react-native-chat.git" 15 | }, 16 | "keywords": [ 17 | "ios", 18 | "android", 19 | "react-native", 20 | "wechat", 21 | "IM", 22 | "chat" 23 | ], 24 | "author": "DaiYz", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/DaiYz/react-native-chat/issues" 28 | }, 29 | "homepage": "https://github.com/DaiYz/react-native-chat#readme", 30 | "peerDependencies": { 31 | "react": "*", 32 | "prop-types": "*", 33 | "react-native": "*" 34 | }, 35 | "dependencies": { 36 | "moment": "^2.22.2" 37 | }, 38 | "devDependencies": { 39 | "react": "16.2.0", 40 | "react-native": "0.52.2", 41 | "prop-types": "15.6.2", 42 | "babel-jest": "23.6.0", 43 | "babel-preset-react-native": "4.0.1", 44 | "jest": "23.6.0", 45 | "react-test-renderer": "16.2.0" 46 | }, 47 | "jest": { 48 | "preset": "react-native" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/2.png -------------------------------------------------------------------------------- /screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/3.png -------------------------------------------------------------------------------- /screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/4.png -------------------------------------------------------------------------------- /screenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/5.png -------------------------------------------------------------------------------- /screenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/6.png -------------------------------------------------------------------------------- /screenshots/alipay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/alipay.jpg -------------------------------------------------------------------------------- /screenshots/wechatPay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYz/react-native-easy-chat-ui/4bcdcaf834d84c0638ce8a81e93666d90928a07d/screenshots/wechatPay.jpg --------------------------------------------------------------------------------