Last active
October 15, 2021 07:56
-
-
Save hieptl/fff5782ebe43be5cb9ee067700f45aed to your computer and use it in GitHub Desktop.
App.js - Audio & Video Call - React Native Gifted Chat App
This file contains hidden or 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
... | |
const App = () => { | |
const callListenerId = useRef(uuidv4()); | |
... | |
const [callType, setCallType] = useState(null); | |
const [callSettings, setCallSettings] = useState(null); | |
const [call, setCall] = useState(null); | |
const [isSomeoneCalling, setIsSomeoneCalling] = useState(false); | |
useEffect(() => { | |
... | |
return () => { | |
setCallType(null); | |
setCall(null); | |
setCallSettings(null); | |
setIsSomeoneCalling(false); | |
cometChat.removeUserListener(userOnlineListenerId); | |
} | |
}, []); | |
useEffect(() => { | |
if (cometChat) { | |
listenForCall(); | |
} | |
}, [cometChat]); | |
useEffect(() => { | |
if (callType && selectedConversation) { | |
initialCall(); | |
} | |
}, [callType]); | |
... | |
const startAudioCall = () => { | |
if (cometChat && selectedConversation) { | |
setCallType(cometChat.CALL_TYPE.AUDIO); | |
} | |
}; | |
const startVideoCall = () => { | |
if (cometChat && selectedConversation) { | |
setCallType(cometChat.CALL_TYPE.VIDEO); | |
} | |
}; | |
const rejectCall = (status, call) => { | |
if (status && call) { | |
cometChat.rejectCall(call.sessionId, status).then( | |
call => { | |
console.log("Call rejected successfully", call); | |
setCallSettings(null); | |
setCallType(null); | |
setCall(null); | |
setIsSomeoneCalling(false); | |
}, | |
error => { | |
console.log("Call rejection failed with error:", error); | |
} | |
); | |
} | |
}; | |
const startCall = (call) => { | |
const sessionId = call.sessionId; | |
const callType = call.type; | |
const callListener = new cometChat.OngoingCallListener({ | |
onUserJoined: user => { | |
/* Notification received here if another user joins the call. */ | |
console.log("User joined call:", user); | |
/* this method can be use to display message or perform any actions if someone joining the call */ | |
}, | |
onUserLeft: user => { | |
/* Notification received here if another user left the call. */ | |
console.log("User left call:", user); | |
/* this method can be use to display message or perform any actions if someone leaving the call */ | |
}, | |
onUserListUpdated: userList => { | |
console.log("user list:", userList); | |
}, | |
onCallEnded: call => { | |
/* Notification received here if current ongoing call is ended. */ | |
console.log("Call ended:", call); | |
/* hiding/closing the call screen can be done here. */ | |
const status = cometChat.CALL_STATUS.CANCELLED; | |
rejectCall(status, call.sessionId); | |
setCallSettings(null); | |
setCallType(null); | |
setCall(null); | |
setIsSomeoneCalling(false); | |
}, | |
onError: error => { | |
console.log("Error :", error); | |
/* hiding/closing the call screen can be done here. */ | |
setCallSettings(null); | |
setCallType(null); | |
setCall(null); | |
setIsSomeoneCalling(false); | |
}, | |
onAudioModesUpdated: (audioModes) => { | |
console.log("audio modes:", audioModes); | |
}, | |
}); | |
const callSettings = new cometChat.CallSettingsBuilder() | |
.setSessionID(sessionId) | |
.enableDefaultLayout(true) | |
.setIsAudioOnlyCall(callType == cometChat.CALL_TYPE.AUDIO ? true : false) | |
.setCallEventListener(callListener) | |
.build(); | |
setCallSettings(() => callSettings); | |
}; | |
const acceptCall = (call) => { | |
if (call) { | |
cometChat.acceptCall(call.sessionId).then( | |
call => { | |
console.log("Call accepted successfully:", call); | |
// start the call using the startCall() method | |
startCall(call); | |
setIsSomeoneCalling(false); | |
}, | |
error => { | |
console.log("Call acceptance failed with error", error); | |
// handle exception | |
} | |
); | |
} | |
}; | |
const confirmCall = (call) => { | |
if (call) { | |
setIsSomeoneCalling(true); | |
} | |
}; | |
const listenForCall = () => { | |
cometChat.addCallListener( | |
callListenerId, | |
new cometChat.CallListener({ | |
onIncomingCallReceived(call) { | |
console.log("Incoming call:", call); | |
const callInitiatorUid = call.callInitiator.uid; | |
if (callInitiatorUid && callInitiatorUid !== user.uid) { | |
setCall(call); | |
confirmCall(call); | |
} | |
}, | |
onOutgoingCallAccepted(call) { | |
console.log("Outgoing call accepted:", call); | |
startCall(call); | |
}, | |
onOutgoingCallRejected(call) { | |
console.log("Outgoing call rejected:", call); | |
setCallSettings(null); | |
setCallType(null); | |
setCall(null); | |
setIsSomeoneCalling(null); | |
}, | |
onIncomingCallCancelled(call) { | |
console.log("Incoming call calcelled:", call); | |
setCallSettings(null); | |
setCallType(null); | |
setCall(null); | |
setIsSomeoneCalling(null); | |
} | |
}) | |
); | |
}; | |
const isGroup = () => { | |
return selectedConversation && selectedConversation.guid; | |
}; | |
const initialCall = () => { | |
const receiverID = isGroup() ? selectedConversation.guid : selectedConversation.uid; | |
const receiverType = isGroup() ? cometChat.RECEIVER_TYPE.GROUP : cometChat.RECEIVER_TYPE.USER; | |
const call = new cometChat.Call(receiverID, callType, receiverType); | |
cometChat.initiateCall(call).then( | |
outGoingCall => { | |
console.log("Call initiated successfully:", outGoingCall); | |
setCall(outGoingCall); | |
// perform action on success. Like show your calling screen. | |
}, | |
error => { | |
console.log("Call initialization failed with exception:", error); | |
} | |
); | |
}; | |
const cancelCall = () => { | |
const status = cometChat.CALL_STATUS.CANCELLED; | |
rejectCall(status, call); | |
}; | |
const handleRejectCall = () => { | |
const status = cometChat.CALL_STATUS.REJECTED; | |
rejectCall(status, call); | |
}; | |
const handleAcceptCall = () => { | |
acceptCall(call); | |
}; | |
... | |
const renderChatHeaderRight = (navigation) => { | |
if (selectedConversation && selectedConversation.contactType === 1 && selectedConversation.owner === user.uid) { | |
return ( | |
<View style={styles.chatHeaderActions}> | |
<TouchableOpacity onPress={startAudioCall}> | |
<Image | |
style={{ width: 24, height: 24, marginRight: 8 }} | |
source={audioCallIcon} | |
/> | |
</TouchableOpacity> | |
<TouchableOpacity onPress={startVideoCall}> | |
<Image | |
style={{ width: 32, height: 24, marginRight: 8 }} | |
source={videoCallIcon} | |
/> | |
</TouchableOpacity> | |
<TouchableOpacity onPress={manageGroup(navigation)}> | |
<Image | |
style={{ width: 24, height: 24 }} | |
source={settingsIcon} | |
/> | |
</TouchableOpacity> | |
</View> | |
); | |
} | |
return ( | |
<View style={styles.chatHeaderActions}> | |
<TouchableOpacity onPress={startAudioCall}> | |
<Image | |
style={{ width: 24, height: 24, marginRight: 8 }} | |
source={audioCallIcon} | |
/> | |
</TouchableOpacity> | |
<TouchableOpacity onPress={startVideoCall}> | |
<Image | |
style={{ width: 32, height: 24 }} | |
source={videoCallIcon} | |
/> | |
</TouchableOpacity> | |
</View> | |
); | |
} | |
if (callType && selectedConversation && !callSettings) { | |
return ( | |
<Modal animated animationType="fade"> | |
<View style={styles.waitingForCallContainer}> | |
<Text style={styles.waitingForCallContainerTitle}>Calling {selectedConversation.name}...</Text> | |
<View style={styles.waitingForCallImageContainer}> | |
<Image style={{ width: 128, height: 128 }} source={{ uri: selectedConversation.avatar }}></Image> | |
</View> | |
<TouchableOpacity style={styles.cancelCallBtn} onPress={cancelCall}> | |
<Text style={styles.cancelCallLabel}>Cancel Call</Text> | |
</TouchableOpacity> | |
</View> | |
</Modal> | |
); | |
} | |
if (callSettings) { | |
return ( | |
<Modal animated animationType="fade"> | |
<View style={styles.callingScreenContainer}> | |
<KeepAwake /> | |
<cometChat.CallingComponent | |
callsettings={callSettings} | |
/> | |
</View> | |
</Modal> | |
); | |
} | |
if (user && !callSettings) { | |
return ( | |
<Context.Provider value={{ cometChat, user, setUser, selectedConversation, setSelectedConversation }}> | |
<NavigationContainer> | |
<Stack.Navigator> | |
<Stack.Screen name="Home" component={Home} options={({ navigation }) => ({ | |
headerLeft: () => ( | |
<TouchableOpacity onPress={logout(navigation)}> | |
<Image | |
style={{ width: 24, height: 24, marginRight: 8 }} | |
source={{ | |
uri: 'https://findicons.com/files/icons/2711/free_icons_for_windows8_metro/512/exit.png' | |
}} | |
/> | |
</TouchableOpacity> | |
), | |
headerRight: () => ( | |
<TouchableOpacity onPress={createGroup(navigation)}> | |
<Image | |
style={{ width: 24, height: 24 }} | |
source={{ | |
uri: 'https://cdn2.iconfinder.com/data/icons/ios-7-icons/50/plus-512.png' | |
}} | |
/> | |
</TouchableOpacity> | |
), | |
})} /> | |
<Stack.Screen name="Create Group" component={CreateGroup} /> | |
<Stack.Screen name="Chat" component={Chat} options={({ navigation }) => ({ | |
headerTitle: () => renderChatHeaderTitle(), | |
headerRight: () => renderChatHeaderRight(navigation), | |
})} /> | |
<Stack.Screen name="Manage Group" component={ManageGroup} /> | |
<Stack.Screen name="Add Members" component={AddGroupMembers} /> | |
<Stack.Screen name="Remove Members" component={RemoveGroupMembers} /> | |
</Stack.Navigator> | |
</NavigationContainer> | |
{isSomeoneCalling && call && <Modal animated animationType="fade"> | |
<View style={styles.waitingForCallContainer}> | |
<Text style={styles.waitingForCallContainerTitle}>You are having a call from {call.sender.name}</Text> | |
<View style={styles.waitingForCallImageContainer}> | |
<Image style={{ width: 128, height: 128 }} source={{ uri: call.sender.avatar }}></Image> | |
</View> | |
<TouchableOpacity style={styles.acceptCallBtn} onPress={handleAcceptCall}> | |
<Text style={styles.acceptCallLabel}>Accept Call</Text> | |
</TouchableOpacity> | |
<TouchableOpacity style={styles.cancelCallBtn} onPress={handleRejectCall}> | |
<Text style={styles.cancelCallLabel}>Reject Call</Text> | |
</TouchableOpacity> | |
</View> | |
</Modal>} | |
</Context.Provider> | |
); | |
} | |
... | |
}; | |
const styles = StyleSheet.create({ | |
... | |
callingScreenContainer: { | |
height: '100%', | |
position: 'relative', | |
width: '100%', | |
}, | |
waitingForCallContainer: { | |
flexDirection: 'column', | |
height: '100%', | |
position: 'relative', | |
width: '100%', | |
flex: 1, | |
paddingTop: 128 | |
}, | |
waitingForCallContainerTitle: { | |
fontSize: 24, | |
fontWeight: 'bold', | |
paddingVertical: 12, | |
textAlign: 'center', | |
}, | |
waitingForCallImageContainer: { | |
justifyContent: 'center', | |
alignItems: 'center', | |
}, | |
cancelCallBtn: { | |
backgroundColor: '#EF4444', | |
borderRadius: 8, | |
fontSize: 16, | |
marginHorizontal: 24, | |
marginVertical: 8, | |
padding: 16, | |
}, | |
cancelCallLabel: { | |
color: '#fff', | |
fontWeight: 'bold', | |
textAlign: 'center', | |
textTransform: 'uppercase', | |
}, | |
acceptCallBtn: { | |
backgroundColor: '#3B82F6', | |
borderRadius: 8, | |
fontSize: 16, | |
marginHorizontal: 24, | |
marginVertical: 8, | |
padding: 16, | |
}, | |
acceptCallLabel: { | |
color: '#fff', | |
fontWeight: 'bold', | |
textAlign: 'center', | |
textTransform: 'uppercase', | |
}, | |
... | |
}); | |
... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment