├── assets
├── icon.png
├── favicon.png
├── splash.png
└── adaptive-icon.png
├── images
└── profile.png
├── babel.config.js
├── App.js
├── routes
└── homeStack.js
├── app.json
├── package.json
├── screens
├── Home.js
├── ContactDetail.js
└── ContactsList.js
└── .gitignore
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/ContactApp/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/ContactApp/HEAD/assets/favicon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/ContactApp/HEAD/assets/splash.png
--------------------------------------------------------------------------------
/images/profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/ContactApp/HEAD/images/profile.png
--------------------------------------------------------------------------------
/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/ContactApp/HEAD/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import { StatusBar } from 'expo-status-bar';
2 | import React from 'react';
3 | import { StyleSheet, Text, View } from 'react-native';
4 | import Navigator from './routes/homeStack'
5 | export default function App() {
6 | return (
7 |
8 | );
9 | }
10 |
11 | const styles = StyleSheet.create({
12 | container: {
13 | flex: 1,
14 | backgroundColor: '#fff',
15 | alignItems: 'center',
16 | justifyContent: 'center',
17 | },
18 | });
19 |
--------------------------------------------------------------------------------
/routes/homeStack.js:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from 'react-navigation-stack';
2 | import { createAppContainer } from 'react-navigation'
3 | import Home from '../screens/Home';
4 | import ContactsList from '../screens/ContactsList';
5 | import ContactDetail from '../screens/ContactDetail';
6 |
7 | const screens = {
8 | Contacts: {
9 | screen: Home
10 | },
11 | ContactList: {
12 | screen: ContactsList
13 | },
14 | Detail: {
15 | screen: ContactDetail
16 | }
17 | }
18 |
19 | const homeStack = createStackNavigator(screens)
20 | export default createAppContainer(homeStack)
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "contactapp",
4 | "slug": "contactapp",
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 |
--------------------------------------------------------------------------------
/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-navigation/native": "^5.9.4",
13 | "expo": "~41.0.1",
14 | "expo-contacts": "~9.1.2",
15 | "expo-status-bar": "~1.0.4",
16 | "react": "16.13.1",
17 | "react-dom": "16.13.1",
18 | "react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
19 | "react-native-elements": "^3.4.2",
20 | "react-native-gesture-handler": "~1.10.2",
21 | "react-native-reanimated": "~2.1.0",
22 | "react-native-safe-area-context": "3.2.0",
23 | "react-native-screens": "~3.0.0",
24 | "react-native-web": "~0.13.12",
25 | "react-navigation": "^4.4.4",
26 | "react-navigation-stack": "^2.10.4"
27 | },
28 | "devDependencies": {
29 | "@babel/core": "^7.9.0"
30 | },
31 | "private": true
32 | }
33 |
--------------------------------------------------------------------------------
/screens/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { TouchableWithoutFeedback } from 'react-native'
3 | import { View, Text, StyleSheet, Button } from 'react-native'
4 |
5 | export default function Home({ navigation }) {
6 | const navigationHandler = () => {
7 | navigation.navigate("ContactList")
8 | }
9 | return (
10 |
11 | {/* */}
12 |
13 | To view your contacts please press the button bellow
14 |
15 |
16 |
17 |
18 | Contacts
19 |
20 |
21 |
22 |
23 | )
24 | }
25 |
26 | const styles = StyleSheet.create({
27 | container: {
28 | alignItems: "center",
29 | flex: 1,
30 | },
31 | button: {
32 | padding: 20,
33 | borderRadius: 10,
34 | marginTop: "30%",
35 | backgroundColor: "#87CEEB",
36 | color: "white"
37 | },
38 | heading: {
39 | fontSize: 18,
40 | marginTop: "30%"
41 | },
42 | buttonText: {
43 | color: "white",
44 | fontWeight: "bold",
45 | fontSize: 16
46 | }
47 | })
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/screens/ContactDetail.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View, Text, StyleSheet, TextInput } from 'react-native'
3 | import { Avatar } from 'react-native-elements';
4 | export default function ContactDetail({ navigation }) {
5 | return (
6 |
7 |
8 |
9 | {
10 | navigation.getParam('image') !== "" ?
11 | :
18 |
23 | }
24 |
25 |
26 |
27 | {navigation.getParam('name')}
28 |
29 |
30 |
31 | Phone Number:
32 |
33 |
37 |
38 |
39 | )
40 | }
41 |
42 | const styles = StyleSheet.create({
43 | container: {
44 | // alignItems: "center"
45 | },
46 | imageContainer: {
47 | flex: 1,
48 | alignItems: 'center',
49 | justifyContent: 'center',
50 | },
51 | imageContainerWraper: {
52 | height: 150
53 | },
54 | inputField: {
55 | fontWeight: "400",
56 | fontSize: 20,
57 | width: "60%",
58 | alignItems: "center",
59 | borderBottomColor: "black",
60 | borderBottomWidth: 1,
61 | paddingLeft: 30
62 | },
63 | name: {
64 | alignItems: "center",
65 | height: 40,
66 | justifyContent: "center"
67 | },
68 | nameText: {
69 | fontSize: 22,
70 | fontWeight: "bold"
71 | },
72 | phno: {
73 | flexDirection: "row",
74 | marginTop: 20,
75 | height: 50
76 |
77 | },
78 | heading: {
79 | fontSize: 16,
80 | fontWeight: "bold",
81 | marginTop: "4%",
82 | marginLeft: 10
83 | }
84 | })
--------------------------------------------------------------------------------
/screens/ContactsList.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { View, Text, StyleSheet, FlatList, ActivityIndicator } from 'react-native'
3 | import * as Contacts from 'expo-contacts'
4 | import { Avatar } from 'react-native-elements';
5 | import { TouchableOpacity } from 'react-native';
6 | export default function ContactsList({ navigation }) {
7 | const [isLoading, setIsLoading] = useState(true)
8 | const [contacts, setContact] = useState([])
9 | useEffect(() => {
10 | (async () => {
11 | const { status } = await Contacts.requestPermissionsAsync();
12 | if (status === 'granted') {
13 | const { data } = await Contacts.getContactsAsync({
14 | fields: [Contacts.Fields.Emails, Contacts.Fields.PhoneNumbers, Contacts.Fields.Image],
15 | });
16 | if (data.length > 0) {
17 | setContact(data)
18 | setIsLoading(false)
19 | }
20 | }
21 | })();
22 | }, [])
23 |
24 | const renderItems = ({ item }) => {
25 | return (
26 | navigation.navigate("Detail", {
27 | name: item.name,
28 | phone: item.phoneNumbers[0].number,
29 | image: item.image ? item.image.uri : ""
30 | })}>
31 |
32 |
33 | {
34 | item.imageAvailable ?
35 | :
42 |
47 | }
48 |
49 |
50 | {item.name}
51 | {item?.phoneNumbers ? item.phoneNumbers[0].number : null}
52 |
53 |
54 |
55 | )
56 | }
57 | const emptyComponent = () => {
58 | return (
59 |
60 | No Contact Found
61 |
62 | )
63 | }
64 | return (
65 |
66 |
67 | {
68 | isLoading ?
69 |
70 |
71 | : null
72 | }
73 |
78 |
79 |
80 | )
81 | }
82 |
83 | const styles = StyleSheet.create({
84 | container: {
85 | flex: 1,
86 | },
87 | searchField: {
88 | backgroundColor: "#d3d3d3",
89 | height: 50,
90 | fontSize: 36,
91 | paddingLeft: 10
92 | },
93 | listSection: {
94 | flex: 1,
95 | marginLeft: 10
96 | },
97 | contactNotFoundText: {
98 | color: "red"
99 | },
100 | contactNotFoundView: {
101 | flex: 1,
102 | alignItems: "center",
103 | marginTop: 20
104 | },
105 | renderContainer: {
106 | flex: 1,
107 | flexDirection: "row",
108 | marginBottom: 5,
109 | height: 60,
110 | alignItems: "center",
111 | borderBottomWidth: 1,
112 | borderColor: "#D4D4D4"
113 | },
114 | contactName: {
115 | fontSize: 16,
116 | fontWeight: "bold",
117 | marginBottom: 5
118 | },
119 | details: {
120 | marginLeft: 10
121 | }
122 |
123 | })
--------------------------------------------------------------------------------