├── .expo-shared └── assets.json ├── .gitignore ├── App.js ├── README.md ├── api └── pexels.js ├── app.json ├── assets ├── adaptive-icon.png ├── favicon.png ├── icon.png ├── pexels.jpg └── splash.png ├── babel.config.js ├── components ├── CardImage.js └── ImageList.js ├── package-lock.json ├── package.json └── views ├── HomeScreen.js └── ImageScreen.js /.expo-shared/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, 3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true 4 | } 5 | -------------------------------------------------------------------------------- /.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 | 15 | 16 | # environment varaibles 17 | .env -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { NavigationContainer } from "@react-navigation/native"; 3 | import { createNativeStackNavigator } from "@react-navigation/native-stack"; 4 | import { StatusBar } from "expo-status-bar"; 5 | import { Image, Text, StyleSheet } from "react-native"; 6 | import pexelsLogo from "./assets/pexels.jpg"; 7 | 8 | import HomeScreen from "./views/HomeScreen"; 9 | import ImageScreen from "./views/ImageScreen"; 10 | 11 | const Stack = createNativeStackNavigator(); 12 | 13 | const App = () => { 14 | const [openSearch, setOpenSearch] = useState(false); 15 | 16 | return ( 17 | 18 | 19 | , 23 | headerRight: () => ( 24 | setOpenSearch(!openSearch)} 27 | > 28 | {openSearch ? "Close" : "Search"} 29 | 30 | ), 31 | title: "Pexels App", 32 | headerTintColor: "#fff", 33 | headerTitleStyle: { 34 | fontWeight: "bold", 35 | }, 36 | headerStyle: { 37 | backgroundColor: "#0D0D0D", 38 | }, 39 | }} 40 | > 41 | {(props) => } 42 | 43 | 57 | 58 | 59 | 60 | ); 61 | }; 62 | 63 | const styles = StyleSheet.create({ 64 | logo: { 65 | width: 37, 66 | height: 37, 67 | marginEnd: 5, 68 | borderRadius: 5, 69 | }, 70 | }); 71 | 72 | export default App; 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Image Gallery Pexels API 2 | 3 | -------------------------------------------------------------------------------- /api/pexels.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export const getImages = async (searchTerm = "technology") => 4 | await axios.get(`https://api.pexels.com/v1/search?query=${searchTerm}`, { 5 | headers: { 6 | Authorization: process.env.API_KEY, 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "react-native-pexels-api", 4 | "slug": "react-native-pexels-api", 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/fazt/react-native-pexels-api/aca3af9c37fd07fc5b46b9070f79950cde1ad18a/assets/adaptive-icon.png -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fazt/react-native-pexels-api/aca3af9c37fd07fc5b46b9070f79950cde1ad18a/assets/favicon.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fazt/react-native-pexels-api/aca3af9c37fd07fc5b46b9070f79950cde1ad18a/assets/icon.png -------------------------------------------------------------------------------- /assets/pexels.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fazt/react-native-pexels-api/aca3af9c37fd07fc5b46b9070f79950cde1ad18a/assets/pexels.jpg -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fazt/react-native-pexels-api/aca3af9c37fd07fc5b46b9070f79950cde1ad18a/assets/splash.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ["babel-preset-expo"], 5 | plugins: ["inline-dotenv"], 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /components/CardImage.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, TouchableOpacity, Image } from "react-native"; 3 | import { useNavigation } from "@react-navigation/native"; 4 | 5 | const CardImage = ({ image }) => { 6 | const navigation = useNavigation(); 7 | 8 | return ( 9 | navigation.navigate("ImageScreen", { image })} 11 | style={styles.cardImage} 12 | > 13 | 21 | 22 | ); 23 | }; 24 | 25 | const styles = StyleSheet.create({ 26 | cardImage: { 27 | display: "flex", 28 | width: "49.5%", 29 | margin: 4, 30 | justifyContent: "space-between", 31 | backgroundColor: "#2C292C", 32 | borderWidth: 0, 33 | borderRadius: 5, 34 | }, 35 | }); 36 | 37 | export default CardImage; 38 | -------------------------------------------------------------------------------- /components/ImageList.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Text, StyleSheet, FlatList } from "react-native"; 3 | import CardImage from "../components/CardImage"; 4 | 5 | const ImageList = ({ photos }) => { 6 | const renderItem = ({ item, index }) => ; 7 | 8 | if (photos.length === 0) return Loading; 9 | 10 | return ( 11 | 17 | ); 18 | }; 19 | 20 | const styles = StyleSheet.create({ 21 | container: {}, 22 | }); 23 | 24 | export default ImageList; 25 | -------------------------------------------------------------------------------- /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-navigation/native": "^6.0.2", 12 | "@react-navigation/native-stack": "^6.1.0", 13 | "axios": "^0.21.1", 14 | "babel-plugin-inline-dotenv": "^1.6.0", 15 | "expo": "~42.0.1", 16 | "expo-file-system": "~11.1.3", 17 | "expo-media-library": "~12.1.2", 18 | "expo-status-bar": "~1.0.4", 19 | "expo-web-browser": "~9.2.0", 20 | "react": "16.13.1", 21 | "react-dom": "16.13.1", 22 | "react-native": "https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz", 23 | "react-native-elements": "^3.4.2", 24 | "react-native-safe-area-context": "3.2.0", 25 | "react-native-screens": "~3.4.0", 26 | "react-native-vector-icons": "^8.1.0", 27 | "react-native-web": "~0.13.12" 28 | }, 29 | "devDependencies": { 30 | "@babel/core": "^7.9.0" 31 | }, 32 | "private": true 33 | } 34 | -------------------------------------------------------------------------------- /views/HomeScreen.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { StyleSheet, View, Text } from "react-native"; 3 | import ImageList from "../components/ImageList"; 4 | import { Input, Button } from "react-native-elements"; 5 | 6 | import { getImages } from "../api/pexels"; 7 | 8 | export default function Home({ openSearch }) { 9 | const [searchTerm, setSearchTerm] = useState(""); 10 | const [photos, setPhotos] = useState([]); 11 | const [totalResults, setTotalResults] = useState(0); 12 | 13 | const loadImages = async (searchTerm) => { 14 | const res = await getImages(searchTerm); 15 | setPhotos(res.data.photos); 16 | setTotalResults(res.data.total_results); 17 | }; 18 | 19 | useEffect(() => { 20 | loadImages(); 21 | }, []); 22 | 23 | const handleSearch = async () => await loadImages(searchTerm); 24 | 25 | return ( 26 | <> 27 | {/* Searching Section */} 28 | {openSearch && ( 29 | 30 | setSearchTerm(value)} 35 | inputContainerStyle={styles.searchInput} 36 | leftIconContainerStyle={styles.searchLeftIcon} 37 | /> 38 |