├── .expo-shared
└── assets.json
├── .gitattributes
├── .gitignore
├── App.js
├── Components
├── CustomListItem.jsx
└── HomePage.jsx
├── README.md
├── app.json
├── assets
├── adaptive-icon.png
├── favicon.png
├── icon.png
└── splash.png
├── babel.config.js
├── firebase.js
├── package-lock.json
├── package.json
└── screens
├── AddChatScreen.js
├── ChatScreen.js
├── LoginScreen.js
└── RegisterScreen.js
/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import "react-native-gesture-handler";
2 | import React from "react";
3 | import { NavigationContainer } from "@react-navigation/native";
4 | import { createStackNavigator } from "@react-navigation/stack";
5 | import LoginScreen from "./screens/LoginScreen";
6 | import RegisterScreen from "./screens/RegisterScreen";
7 | import HomePage from "./Components/HomePage";
8 | import AddChatScreen from "./screens/AddChatScreen";
9 | import ChatScreen from "./screens/ChatScreen";
10 |
11 | const Stack = createStackNavigator();
12 | const globalScreenOptions = {
13 | headerStyle: { backgroundColor: "#2C6BED" },
14 | headerTitleStyle: { color: "white" },
15 | headerTintColor: "white",
16 | };
17 |
18 | export default function App() {
19 | return (
20 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/Components/CustomListItem.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { StyleSheet, View, TouchableOpacity } from "react-native";
3 | import { ListItem, Avatar } from "react-native-elements";
4 | import { db, auth } from "../firebase";
5 |
6 | const CustomListItem = ({ id, chatName, enterChat }) => {
7 | const [chatMessages, setChatMessages] = useState([]);
8 | useEffect(() => {
9 | const unsubscribe = db
10 | .collection("chats")
11 | .doc(id)
12 | .collection("messages")
13 | .orderBy("timestamp", "desc")
14 | .onSnapshot((snapshot) =>
15 | setChatMessages(snapshot.docs.map((doc) => doc.data()))
16 | );
17 |
18 | return unsubscribe;
19 | }, []);
20 |
21 | return (
22 |
23 | enterChat(id, chatName)}>
24 |
32 |
33 |
34 |
35 | {chatName}
36 |
37 |
38 | {chatMessages[0]?.displayName}: {chatMessages[0]?.message}
39 |
40 |
41 |
42 |
43 | );
44 | };
45 |
46 | export default CustomListItem;
47 |
48 | const styles = StyleSheet.create({});
49 |
--------------------------------------------------------------------------------
/Components/HomePage.jsx:
--------------------------------------------------------------------------------
1 | import React, { useLayoutEffect, useState, useEffect } from "react";
2 | import {
3 | StyleSheet,
4 | View,
5 | SafeAreaView,
6 | ScrollView,
7 | TouchableOpacity,
8 | } from "react-native";
9 | import { Avatar, Tooltip, Text } from "react-native-elements";
10 | import { auth, db } from "../firebase";
11 | import { AntDesign, SimpleLineIcons, Feather } from "@expo/vector-icons";
12 | import CustomListItem from "./CustomListItem";
13 |
14 | const HomePage = ({ navigation }) => {
15 | const [chats, setChats] = useState([]);
16 |
17 | useEffect(() => {
18 | const unsubscribe = db.collection("chats").onSnapshot((snapshot) =>
19 | setChats(
20 | snapshot.docs.map((doc) => ({
21 | id: doc.id,
22 | chat: doc.data(),
23 | }))
24 | )
25 | );
26 | return unsubscribe;
27 | }, []);
28 |
29 | const singOutUser = () => {
30 | auth
31 | .signOut()
32 | .then(() => {
33 | navigation.replace("Login");
34 | })
35 | .catch((error) => alert(error));
36 | };
37 |
38 | useLayoutEffect(() => {
39 | navigation.setOptions({
40 | title: "Chats",
41 | headerStyle: { backgroundColor: "#2C6BED" },
42 | headerTitleStyle: { color: "white" },
43 |
44 | headerLeft: () => (
45 |
46 |
47 |
48 |
49 |
50 | ),
51 | headerRight: () => (
52 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | navigation.navigate("AddChat")}
71 | >
72 | {/* Creat Your Own ChatRoom}> */}
73 |
74 | {/* */}
75 |
76 |
77 | ),
78 | });
79 | }, []);
80 | const enterChat = (id, chatName) => {
81 | navigation.navigate("Chat", {
82 | id,
83 | chatName,
84 | });
85 | };
86 |
87 | return (
88 |
89 |
90 | {chats.map(({ chat: { chatName }, id }) => (
91 |
97 | ))}
98 |
99 |
100 | );
101 | };
102 |
103 | export default HomePage;
104 |
105 | const styles = StyleSheet.create({});
106 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SIGNAL-Clone-with-React_Native
2 | Realtime Android and IOS and also Web chat application with firebase authentication
3 |
4 | Technology thats are used For This clone-->💯💯
5 |
6 | 0. Expo
7 | 1. React Native
8 | 2. Google Firebase Authontication
9 | 3. Material icons
10 | 4. React Hooks
11 | 5. Redux
12 | or React Context Api
13 | 6. Firebase Database
14 | 7. Firebase Hoasting
15 | 8. Node js
16 |
17 | In this clone, you have to first login or create an account with your email id and, Then you can also make your own group and also can share the link or the website link with your friend to start a conversation by sending message...
18 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "signal-clone-original",
4 | "slug": "signal-clone-original",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "android": {
23 | "adaptiveIcon": {
24 | "foregroundImage": "./assets/adaptive-icon.png",
25 | "backgroundColor": "#FFFFFF"
26 | }
27 | },
28 | "web": {
29 | "favicon": "./assets/favicon.png"
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniwaydev/ChatApp-with-React_Native/3793b142c7a5bdfe41ab17d49c04df3ab6fbb182/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniwaydev/ChatApp-with-React_Native/3793b142c7a5bdfe41ab17d49c04df3ab6fbb182/assets/favicon.png
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniwaydev/ChatApp-with-React_Native/3793b142c7a5bdfe41ab17d49c04df3ab6fbb182/assets/icon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uniwaydev/ChatApp-with-React_Native/3793b142c7a5bdfe41ab17d49c04df3ab6fbb182/assets/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/firebase.js:
--------------------------------------------------------------------------------
1 | import firebase from "firebase";
2 |
3 | const firebaseConfig = {
4 | apiKey: "AIzaSyA_VYvGTjbUQvgNtG-BzWnEqGxz0OLUT1Y",
5 | authDomain: "signal-clone-b0181.firebaseapp.com",
6 | projectId: "signal-clone-b0181",
7 | storageBucket: "signal-clone-b0181.appspot.com",
8 | messagingSenderId: "771530258",
9 | appId: "1:771530258:web:8c16ac236aab5a375dc2cb",
10 | measurementId: "G-YMDSNGT3ZT",
11 | };
12 |
13 | const firebaseApp = firebase.initializeApp(firebaseConfig);
14 | const db = firebaseApp.firestore();
15 | const auth = firebase.auth();
16 | export { db, auth };
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@react-native-community/masked-view": "0.1.10",
12 | "@react-native-firebase/app": "^12.1.0",
13 | "@react-navigation/native": "^5.9.4",
14 | "@react-navigation/stack": "^5.14.5",
15 | "expo": "~41.0.1",
16 | "expo-status-bar": "~1.0.4",
17 | "firebase": "8.2.3",
18 | "react": "16.13.1",
19 | "react-dom": "16.13.1",
20 | "react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
21 | "react-native-elements": "^3.4.2",
22 | "react-native-gesture-handler": "~1.10.2",
23 | "react-native-reanimated": "~2.1.0",
24 | "react-native-safe-area-context": "3.2.0",
25 | "react-native-screens": "~3.0.0",
26 | "react-native-vector-icons": "^8.1.0",
27 | "react-native-web": "^0.17.1"
28 | },
29 | "devDependencies": {
30 | "@babel/core": "^7.9.0"
31 | },
32 | "private": true
33 | }
34 |
--------------------------------------------------------------------------------
/screens/AddChatScreen.js:
--------------------------------------------------------------------------------
1 | import React, { useLayoutEffect, useState } from "react";
2 | import { StyleSheet, Text, View } from "react-native";
3 | import { Button, Input } from "react-native-elements";
4 | import Icon from "react-native-vector-icons/FontAwesome";
5 | import { db } from "../firebase";
6 |
7 | const AddChatScreen = ({ navigation }) => {
8 | const [input, setInput] = useState("");
9 |
10 | const createChat = async () => {
11 | db.collection("chats")
12 | .add({
13 | chatName: input,
14 | })
15 | .then(() => {
16 | navigation.goBack();
17 | })
18 | .catch((error) => alert(error));
19 | };
20 |
21 | useLayoutEffect(() => {
22 | navigation.setOptions({
23 | title: "Add a New Chat",
24 | headerBackTitle: "Chats", // just appied for an ios device
25 | });
26 | }, [navigation]);
27 |
28 | return (
29 |
30 | setInput(text)}
35 | leftIcon={
36 |
37 | }
38 | />
39 |
44 |
45 | );
46 | };
47 |
48 | export default AddChatScreen;
49 |
50 | const styles = StyleSheet.create({
51 | container: {
52 | backgroundColor: "white",
53 | padding: 30,
54 | height: "100%",
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/screens/ChatScreen.js:
--------------------------------------------------------------------------------
1 | import React, { useLayoutEffect, useState, useEffect } from "react";
2 | import {
3 | StyleSheet,
4 | View,
5 | TouchableOpacity,
6 | SafeAreaView,
7 | KeyboardAvoidingView,
8 | Platform,
9 | ScrollView,
10 | StatusBar,
11 | TextInput,
12 | } from "react-native";
13 | import { Avatar, Text } from "react-native-elements";
14 | import { Ionicons, FontAwesome, Entypo } from "@expo/vector-icons";
15 | import { db, auth } from "../firebase";
16 | import firebase from "firebase";
17 |
18 | const ChatScreen = ({ navigation, route }) => {
19 | const [input, setInput] = useState("");
20 | const [messages, setMessages] = useState([]);
21 | useLayoutEffect(() => {
22 | navigation.setOptions({
23 | title: `${route.params.chatName}`,
24 | headerTitleStyle: { color: "black" },
25 | headerTitle: () => (
26 |
27 |
35 |
36 | {route.params.chatName}
37 |
38 |
39 | ),
40 | headerRight: () => (
41 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | ),
62 | });
63 | }, [navigation, messages]);
64 |
65 | const sendMessage = () => {
66 | db.collection("chats").doc(route.params.id).collection("messages").add({
67 | message: input,
68 | displayName: auth.currentUser.displayName,
69 | emailId: auth.currentUser.email,
70 | photoURL: auth.currentUser.photoURL,
71 | timestamp: firebase.firestore.FieldValue.serverTimestamp(),
72 | });
73 | setInput("");
74 | };
75 |
76 | useEffect(() => {
77 | db.collection("chats")
78 | .doc(route.params.id)
79 | .collection("messages")
80 | .orderBy("timestamp", "desc")
81 | .onSnapshot((snapshot) =>
82 | setMessages(
83 | snapshot.docs.map((doc) => ({
84 | id: doc.id,
85 | data: doc.data(),
86 | }))
87 | )
88 | );
89 | }, []);
90 |
91 | return (
92 |
93 |
98 |
99 | {messages.map(({ id, data }) =>
100 | data.emailId === auth.currentUser.email ? (
101 |
102 |
115 | {data.message}
116 |
117 | ) : (
118 |
119 |
133 | {data.message}
134 | {data.displayName}
135 |
136 | )
137 | )}
138 |
139 |
140 | setInput(text)}
145 | style={styles.textInput}
146 | onSubmitEditing={sendMessage}
147 | />
148 |
153 |
154 |
155 |
156 |
157 |
158 | );
159 | };
160 |
161 | const styles = StyleSheet.create({
162 | container: { flex: 1 },
163 | footer: {
164 | flexDirection: "row",
165 | width: "100%",
166 | alignItems: "center",
167 | padding: 15,
168 | },
169 |
170 | textInput: {
171 | bottom: 0,
172 | height: 40,
173 | flex: 1,
174 | marginRight: 15,
175 | borderColor: "transparent",
176 | backgroundColor: "#ECECEC",
177 | padding: 10,
178 | borderRadius: 20,
179 | color: "grey",
180 | },
181 | sendMessages: {
182 | alignSelf: "flex-end",
183 | padding: 15,
184 | backgroundColor: "#ECECEC",
185 | borderRadius: 20,
186 | marginRight: 20,
187 | marginBottom: 20,
188 | maxWidth: "80%",
189 | position: "relative",
190 | marginBottom: 40,
191 | },
192 | receiveMessages: {
193 | alignSelf: "flex-start",
194 | padding: 15,
195 | backgroundColor: "#2B68E6",
196 | borderRadius: 20,
197 | marginLeft: 20,
198 | marginBottom: 20,
199 | maxWidth: "80%",
200 | position: "relative",
201 | marginBottom: 40,
202 | },
203 |
204 | sendMessagesText: {
205 | color: "black",
206 | fontWeight: "500",
207 | marginLeft: 10,
208 | },
209 | receiveMessagesText: {
210 | color: "white",
211 | left: 10,
212 | paddingRight: 10,
213 | },
214 | senderName: {
215 | left: 10,
216 | paddingRight: 10,
217 | fontSize: 7,
218 | color: "white",
219 | },
220 | });
221 |
222 | export default ChatScreen;
223 |
--------------------------------------------------------------------------------
/screens/LoginScreen.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import {
3 | StyleSheet,
4 | Text,
5 | View,
6 | KeyboardAvoidingView,
7 | Platform,
8 | } from "react-native";
9 | import { Button, Input, Image } from "react-native-elements";
10 | import { StatusBar } from "expo-status-bar";
11 | import { auth } from "../firebase";
12 |
13 | const LoginScreen = ({ navigation }) => {
14 | const [email, setEmail] = useState("");
15 | const [password, setPassword] = useState("");
16 |
17 | useEffect(() => {
18 | const unsubscribe = auth.onAuthStateChanged((authUser) => {
19 | console.log(authUser);
20 | if (authUser) {
21 | navigation.navigate("Home");
22 | }
23 | });
24 |
25 | return unsubscribe;
26 | }, []);
27 |
28 | const Login = () => {
29 | auth
30 | .signInWithEmailAndPassword(email, password)
31 | .catch((error) => alert(error));
32 | };
33 | return (
34 |
38 |
39 |
45 |
46 | setEmail(text)}
52 | />
53 | setPassword(text)}
59 | onSubmitEditing={Login}
60 | />
61 |
62 |
63 |
64 |
72 | );
73 | };
74 |
75 | const styles = StyleSheet.create({
76 | container: {
77 | backgroundColor: "white",
78 | flex: 1,
79 | alignItems: "center",
80 | justifyContent: "center",
81 | padding: 10,
82 | },
83 | InputContainer: {
84 | width: 300,
85 | marginTop: 12,
86 | },
87 | button: {
88 | marginBottom: 10,
89 | width: 200,
90 | },
91 | });
92 |
93 | export default LoginScreen;
94 |
--------------------------------------------------------------------------------
/screens/RegisterScreen.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useLayoutEffect } from "react";
2 | import { StyleSheet, View, KeyboardAvoidingView, Platform } from "react-native";
3 | import { Text, Input, Button } from "react-native-elements";
4 | import { auth } from "../firebase";
5 |
6 | const RegisterScreen = ({ navigation }) => {
7 | const [name, setName] = useState("");
8 | const [email, setEmail] = useState("");
9 | const [password, setPassword] = useState("");
10 | const [imageUrl, setImageUrl] = useState("");
11 |
12 | useLayoutEffect(() => {
13 | // applyed for just IOS
14 | navigation.setOptions({
15 | headerBackTitle: "Back to Home",
16 | });
17 | }, [navigation]);
18 |
19 | const register = () => {
20 | auth
21 | .createUserWithEmailAndPassword(email, password)
22 | .then((authUser) => {
23 | authUser.user.updateProfile({
24 | displayName: name,
25 | photoURL:
26 | imageUrl ||
27 | "https://cencup.com/wp-content/uploads/2019/07/avatar-placeholder.png",
28 | });
29 | })
30 | .catch((error) => alert(error.message));
31 | };
32 |
33 | return (
34 |
38 |
39 | Create a Signal Account Here
40 |
41 |
42 |
43 | setName(text)}
45 | value={name}
46 | type="text"
47 | autoFocus
48 | placeholder="Enter your Name "
49 | />
50 | setEmail(text)}
52 | value={email}
53 | type="email"
54 | placeholder="Type your Email Id "
55 | />
56 | setPassword(text)}
62 | />
63 | setImageUrl(text)}
65 | value={imageUrl}
66 | type="text"
67 | placeholder="Paste your ImageUrl (Opional)"
68 | onSubmitEditing={register}
69 | />
70 |
71 |
76 |
77 |
78 | );
79 | };
80 |
81 | export default RegisterScreen;
82 |
83 | const styles = StyleSheet.create({
84 | container: {
85 | flex: 1,
86 | alignItems: "center",
87 | justifyContent: "center",
88 | },
89 | InputContainer: { width: 300 },
90 | button: { width: 200 },
91 | });
92 |
--------------------------------------------------------------------------------