Last active
November 3, 2020 21:46
-
-
Save vishalnarkhede/f337314921224c57bcf0950482611bab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// src/components/InpuBoxThread.js | |
import React, {useRef, useState} from 'react'; | |
import {TouchableOpacity, Animated, View, StyleSheet} from 'react-native'; | |
import { | |
AutoCompleteInput, | |
SendButton, | |
useChannelContext, | |
} from 'stream-chat-react-native'; | |
import {getChannelDisplayName} from '../utils'; | |
import {useTheme} from '@react-navigation/native'; | |
import {SVGIcon} from './SVGIcon'; | |
import CheckBox from '@react-native-community/checkbox'; | |
import {SCText} from './SCText'; | |
export const InputBoxThread = props => { | |
const {colors} = useTheme(); | |
const [leftMenuActive, setLeftMenuActive] = useState(true); | |
const {channel} = useChannelContext(); | |
const transform = useRef(new Animated.Value(0)).current; | |
const translateMenuLeft = useRef(new Animated.Value(0)).current; | |
const translateMenuRight = useRef(new Animated.Value(300)).current; | |
const opacityMenuLeft = useRef(new Animated.Value(1)).current; | |
const opacityMenuRight = useRef(new Animated.Value(0)).current; | |
const isDirectMessagingConversation = !channel.data.name; | |
return ( | |
<View style={[styles.container, {backgroundColor: colors.background}]}> | |
<AutoCompleteInput {...props} /> | |
<View | |
style={[styles.actionsContainer, {backgroundColor: colors.background}]}> | |
<Animated.View // Special animatable View | |
style={{ | |
transform: [ | |
{ | |
rotate: transform.interpolate({ | |
inputRange: [0, 180], | |
outputRange: ['0deg', '180deg'], | |
}), | |
}, | |
{perspective: 1000}, | |
], // Bind opacity to animated value | |
}}> | |
<TouchableOpacity | |
onPress={() => { | |
Animated.parallel([ | |
Animated.timing(transform, { | |
toValue: leftMenuActive ? 180 : 0, | |
duration: 200, | |
useNativeDriver: false, | |
}), | |
Animated.timing(translateMenuLeft, { | |
toValue: leftMenuActive ? -300 : 0, | |
duration: 200, | |
useNativeDriver: false, | |
}), | |
Animated.timing(translateMenuRight, { | |
toValue: leftMenuActive ? 0 : 300, | |
duration: 200, | |
useNativeDriver: false, | |
}), | |
Animated.timing(opacityMenuLeft, { | |
toValue: leftMenuActive ? 0 : 1, | |
duration: leftMenuActive ? 50 : 200, | |
useNativeDriver: false, | |
}), | |
Animated.timing(opacityMenuRight, { | |
toValue: leftMenuActive ? 1 : 0, | |
duration: leftMenuActive ? 50 : 200, | |
useNativeDriver: false, | |
}), | |
]).start(); | |
setLeftMenuActive(!leftMenuActive); | |
}} | |
style={[ | |
{ | |
padding: 1.5, | |
paddingRight: 6, | |
paddingLeft: 6, | |
borderRadius: 10, | |
backgroundColor: colors.linkText, | |
}, | |
]}> | |
<SCText style={{fontWeight: '900', color: 'white'}}>{'<'}</SCText> | |
</TouchableOpacity> | |
</Animated.View> | |
<View | |
style={{ | |
flexGrow: 1, | |
flexShrink: 1, | |
flexDirection: 'row', | |
marginLeft: 20, | |
}}> | |
<Animated.View | |
style={{ | |
flexDirection: 'row', | |
alignItems: 'center', | |
transform: [{translateX: translateMenuLeft}], | |
opacity: opacityMenuLeft, | |
}}> | |
<CheckBox | |
boxType="square" | |
disabled={false} | |
style={{width: 15, height: 15}} | |
onValueChange={newValue => | |
props.setSendMessageInChannel(newValue) | |
} | |
/> | |
<SCText style={{marginLeft: 12, fontSize: 14}}> | |
Also send to{' '} | |
{isDirectMessagingConversation | |
? 'group' | |
: getChannelDisplayName(channel, true)} | |
</SCText> | |
</Animated.View> | |
<Animated.View | |
style={{ | |
position: 'absolute', | |
width: '100%', | |
alignItems: 'center', | |
alignSelf: 'center', | |
justifyContent: 'center', | |
flexDirection: 'row', | |
transform: [ | |
{translateX: translateMenuRight}, | |
{perspective: 1000}, | |
], | |
opacity: opacityMenuRight, | |
}}> | |
<View style={styles.row}> | |
<TouchableOpacity | |
onPress={() => { | |
props.appendText('@'); | |
}}> | |
<SCText style={styles.textActionLabel}>@</SCText> | |
</TouchableOpacity> | |
{/* Text editor is not functional yet. We will cover it in some future tutorials */} | |
<TouchableOpacity style={styles.textEditorContainer}> | |
<SCText style={styles.textActionLabel}>Aa</SCText> | |
</TouchableOpacity> | |
</View> | |
<View | |
style={[ | |
styles.row, | |
{ | |
justifyContent: 'flex-end', | |
}, | |
]}> | |
<TouchableOpacity | |
onPress={props._pickFile} | |
style={styles.fileAttachmentIcon}> | |
<SVGIcon type="file-attachment" height="18" width="18" /> | |
</TouchableOpacity> | |
<TouchableOpacity | |
onPress={props._pickImage} | |
style={styles.imageAttachmentIcon}> | |
<SVGIcon type="image-attachment" height="18" width="18" /> | |
</TouchableOpacity> | |
</View> | |
</Animated.View> | |
</View> | |
<SendButton | |
{...props} | |
sendMessage={() => { | |
props.sendMessage(props.channel); | |
}} | |
/> | |
</View> | |
</View> | |
); | |
}; | |
const styles = StyleSheet.create({ | |
container: { | |
flexDirection: 'column', | |
width: '100%', | |
height: 60, | |
}, | |
actionsContainer: { | |
flexDirection: 'row', | |
width: '100%', | |
alignItems: 'center', | |
}, | |
row: { | |
flex: 1, | |
flexDirection: 'row', | |
width: '100%', | |
}, | |
textActionLabel: { | |
fontSize: 18, | |
}, | |
textEditorContainer: { | |
marginLeft: 10, | |
}, | |
fileAttachmentIcon: { | |
marginRight: 10, | |
marginLeft: 10, | |
alignSelf: 'center', | |
}, | |
imageAttachmentIcon: { | |
marginRight: 10, | |
marginLeft: 10, | |
alignSelf: 'flex-end', | |
}, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// src/screens/ThreadScreen.js | |
import React, {useEffect, useState} from 'react'; | |
import {View, SafeAreaView, Platform, StyleSheet} from 'react-native'; | |
import { | |
Chat, | |
Channel, | |
KeyboardCompatibleView, | |
Thread, | |
Message as DefaultMessage, | |
} from 'stream-chat-react-native'; | |
import {useNavigation, useTheme} from '@react-navigation/native'; | |
import {MessageSlack} from '../components/MessageSlack'; | |
import { | |
getChannelDisplayName, | |
useStreamChatTheme, | |
ChatClientService, | |
truncate, | |
} from '../utils'; | |
import {ModalScreenHeader} from '../components/ModalScreenHeader'; | |
import {InputBoxThread} from '../components/InputBoxThread'; | |
import {SVGIcon} from '../components/SVGIcon'; | |
import {SCText} from '../components/SCText'; | |
const CustomKeyboardCompatibleView = ({children}) => ( | |
<KeyboardCompatibleView | |
keyboardVerticalOffset={Platform.OS === 'ios' ? 120 : -200} | |
behavior={Platform.OS === 'ios' ? 'padding' : 'position'}> | |
{children} | |
</KeyboardCompatibleView> | |
); | |
export function ThreadScreen({ | |
route: { | |
params: {channelId = null, threadId = null}, | |
}, | |
}) { | |
const {colors} = useTheme(); | |
const chatStyles = useStreamChatTheme(); | |
const chatClient = ChatClientService.getClient(); | |
const navigation = useNavigation(); | |
const [channel, setChannel] = useState(null); | |
const [thread, setThread] = useState(); | |
const [sendMessageInChannel, setSendMessageInChannel] = useState(false); | |
const [isReady, setIsReady] = useState(false); | |
const goBack = () => { | |
navigation.goBack(); | |
}; | |
useEffect(() => { | |
const getThread = async () => { | |
const res = await chatClient.getMessage(threadId); | |
setThread(res.message); | |
}; | |
getThread(); | |
}, [chatClient, threadId]); | |
useEffect(() => { | |
if (!channelId) { | |
navigation.goBack(); | |
} else { | |
const _channel = chatClient.channel('messaging', channelId); | |
setChannel(_channel); | |
setIsReady(true); | |
} | |
}, [channelId, threadId]); | |
if (!isReady || !thread) { | |
return null; | |
} | |
return ( | |
<SafeAreaView | |
style={{ | |
backgroundColor: colors.background, | |
}}> | |
<View style={styles.channelScreenContainer}> | |
<ModalScreenHeader | |
title={'Thread'} | |
goBack={goBack} | |
subTitle={truncate(getChannelDisplayName(channel, true), 35)} | |
/> | |
<View | |
style={[ | |
styles.chatContainer, | |
{ | |
backgroundColor: colors.background, | |
}, | |
]}> | |
<Chat client={chatClient} style={chatStyles}> | |
<Channel | |
channel={channel} | |
thread={thread} | |
doSendMessageRequest={async (cid, message) => { | |
const newMessage = { | |
...message, | |
show_in_channel: sendMessageInChannel, | |
parentMessageText: sendMessageInChannel | |
? thread.text | |
: undefined, | |
}; | |
return channel.sendMessage(newMessage); | |
}} | |
KeyboardCompatibleView={CustomKeyboardCompatibleView}> | |
<Thread | |
additionalMessageInputProps={{ | |
Input: props => ( | |
<InputBoxThread | |
{...props} | |
setSendMessageInChannel={setSendMessageInChannel} | |
/> | |
), | |
additionalTextInputProps: { | |
placeholderTextColor: '#979A9A', | |
placeholder: | |
channel && channel.data.name | |
? 'Message #' + | |
channel.data.name.toLowerCase().replace(' ', '_') | |
: 'Message', | |
}, | |
}} | |
additionalMessageListProps={{ | |
Message: MessageSlack, | |
DateSeparator: () => null, | |
HeaderComponent: () => { | |
return ( | |
<> | |
<DefaultMessage | |
groupStyles={['single']} | |
message={thread} | |
Message={MessageSlack} | |
threadList | |
/> | |
<View | |
style={[ | |
styles.threadHeaderSeparator, | |
{ | |
backgroundColor: colors.background, | |
borderTopColor: colors.border, | |
borderBottomColor: colors.border, | |
}, | |
]}> | |
{thread.reply_count > 0 ? ( | |
<SCText>{thread.reply_count} replies</SCText> | |
) : ( | |
<View | |
style={styles.emptyThreadHeaderSeparatorContent}> | |
<SVGIcon type="threads" height="15" width="15" /> | |
<SCText style={{marginLeft: 10}}> | |
reply in thread | |
</SCText> | |
</View> | |
)} | |
</View> | |
</> | |
); | |
}, | |
}} | |
/> | |
</Channel> | |
</Chat> | |
</View> | |
</View> | |
</SafeAreaView> | |
); | |
} | |
const styles = StyleSheet.create({ | |
channelScreenContainer: {flexDirection: 'column', height: '100%'}, | |
container: { | |
flex: 1, | |
backgroundColor: 'white', | |
}, | |
drawerNavigator: { | |
backgroundColor: '#3F0E40', | |
width: 350, | |
}, | |
chatContainer: { | |
flexGrow: 1, | |
flexShrink: 1, | |
}, | |
threadHeaderSeparator: { | |
padding: 10, | |
borderTopWidth: 1, | |
borderBottomWidth: 1, | |
marginBottom: 20, | |
}, | |
emptyThreadHeaderSeparatorContent: { | |
flexDirection: 'row', | |
alignItems: 'center', | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment