diff --git a/android/app/build.gradle b/android/app/build.gradle index 66375a0..92cf5ac 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -129,6 +129,7 @@ android { dependencies { compile project(':react-native-vector-icons') + compile project(':react-native-spinkit') compile fileTree(dir: "libs", include: ["*.jar"]) compile "com.android.support:appcompat-v7:23.0.1" compile "com.facebook.react:react-native:+" // From node_modules diff --git a/android/app/src/main/java/org/gdgsrilanka/codelanka/eznet/MainApplication.java b/android/app/src/main/java/org/gdgsrilanka/codelanka/eznet/MainApplication.java index ec00077..0008938 100644 --- a/android/app/src/main/java/org/gdgsrilanka/codelanka/eznet/MainApplication.java +++ b/android/app/src/main/java/org/gdgsrilanka/codelanka/eznet/MainApplication.java @@ -12,6 +12,7 @@ import com.facebook.soloader.SoLoader; import java.util.Arrays; import java.util.List; +import com.react.rnspinkit.RNSpinkitPackage; import io.invertase.firebase.RNFirebasePackage; import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage; @@ -34,7 +35,8 @@ protected List getPackages() { new RNFirebaseAnalyticsPackage(), new RNFirebaseCrashPackage(), new RNFirebasePerformancePackage(), - new VectorIconsPackage() + new VectorIconsPackage(), + new RNSpinkitPackage() ); } }; diff --git a/android/build.gradle b/android/build.gradle index f29d315..ac38d1e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,6 +21,7 @@ allprojects { jcenter() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "https://jitpack.io" url "$rootDir/../node_modules/react-native/android" } } diff --git a/android/settings.gradle b/android/settings.gradle index 9d64f29..c21b8f3 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -3,5 +3,6 @@ include ':react-native-vector-icons' project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') include ':react-native-firebase' project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android') - +include ':react-native-spinkit' +project(':react-native-spinkit').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spinkit/android') include ':app' diff --git a/ios/EZNet.xcodeproj/project.pbxproj b/ios/EZNet.xcodeproj/project.pbxproj index 8da0166..2c83353 100644 --- a/ios/EZNet.xcodeproj/project.pbxproj +++ b/ios/EZNet.xcodeproj/project.pbxproj @@ -47,6 +47,9 @@ 8EB94ED2666648F3ACD427C1 /* rubicon-icon-font.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2F9381A263934921AA18C788 /* rubicon-icon-font.ttf */; }; EFC080D9C57740B9BE42CFA6 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FDD3CCE7476B4FCBB6E40BE9 /* SimpleLineIcons.ttf */; }; E36E03D4C0614347BD1FF529 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C5F2973332314F3090CE044D /* Zocial.ttf */; }; + F90355EC5AE4488D8AC3A076 /* libRNFetchBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F2D9265AA354DE6B759F93A /* libRNFetchBlob.a */; }; + 0FCD125FCBB04C22BBC14E4F /* libRNFirebase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C82810B0F72E44CFBF184C10 /* libRNFirebase.a */; }; + AA38DD42A61547279DB2065B /* libRNSpinkit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D9C33604EAF4733B1678344 /* libRNSpinkit.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -278,6 +281,12 @@ 2F9381A263934921AA18C788 /* rubicon-icon-font.ttf */ = {isa = PBXFileReference; name = "rubicon-icon-font.ttf"; path = "../node_modules/native-base/Fonts/rubicon-icon-font.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; FDD3CCE7476B4FCBB6E40BE9 /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; name = "SimpleLineIcons.ttf"; path = "../node_modules/native-base/Fonts/SimpleLineIcons.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; C5F2973332314F3090CE044D /* Zocial.ttf */ = {isa = PBXFileReference; name = "Zocial.ttf"; path = "../node_modules/native-base/Fonts/Zocial.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; + A8C244E03280488FA985513C /* RNFetchBlob.xcodeproj */ = {isa = PBXFileReference; name = "RNFetchBlob.xcodeproj"; path = "../node_modules/react-native-fetch-blob/ios/RNFetchBlob.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + 0F2D9265AA354DE6B759F93A /* libRNFetchBlob.a */ = {isa = PBXFileReference; name = "libRNFetchBlob.a"; path = "libRNFetchBlob.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; + B6BA648C8AF7429A99A5114F /* RNFirebase.xcodeproj */ = {isa = PBXFileReference; name = "RNFirebase.xcodeproj"; path = "../node_modules/react-native-firebase/ios/RNFirebase.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + C82810B0F72E44CFBF184C10 /* libRNFirebase.a */ = {isa = PBXFileReference; name = "libRNFirebase.a"; path = "libRNFirebase.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; + 46590D2B8FCD42468A97733B /* RNSpinkit.xcodeproj */ = {isa = PBXFileReference; name = "RNSpinkit.xcodeproj"; path = "../node_modules/react-native-spinkit/ios/RNSpinkit.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + 7D9C33604EAF4733B1678344 /* libRNSpinkit.a */ = {isa = PBXFileReference; name = "libRNSpinkit.a"; path = "libRNSpinkit.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -304,6 +313,9 @@ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, + F90355EC5AE4488D8AC3A076 /* libRNFetchBlob.a in Frameworks */, + 0FCD125FCBB04C22BBC14E4F /* libRNFirebase.a in Frameworks */, + AA38DD42A61547279DB2065B /* libRNSpinkit.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -470,6 +482,9 @@ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, + A8C244E03280488FA985513C /* RNFetchBlob.xcodeproj */, + B6BA648C8AF7429A99A5114F /* RNFirebase.xcodeproj */, + 46590D2B8FCD42468A97733B /* RNSpinkit.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -1028,6 +1043,18 @@ ); PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/EZNet.app/EZNet"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)\..\node_modules\react-native-fetch-blob\ios/**", + "$(SRCROOT)\..\node_modules\react-native-firebase\ios\RNFirebase/**", + "$(SRCROOT)\..\node_modules\react-native-spinkit\ios/**", + ); }; name = Debug; }; @@ -1045,6 +1072,18 @@ ); PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/EZNet.app/EZNet"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)\..\node_modules\react-native-fetch-blob\ios/**", + "$(SRCROOT)\..\node_modules\react-native-firebase\ios\RNFirebase/**", + "$(SRCROOT)\..\node_modules\react-native-spinkit\ios/**", + ); }; name = Release; }; @@ -1063,6 +1102,12 @@ ); PRODUCT_NAME = EZNet; VERSIONING_SYSTEM = "apple-generic"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)\..\node_modules\react-native-fetch-blob\ios/**", + "$(SRCROOT)\..\node_modules\react-native-firebase\ios\RNFirebase/**", + "$(SRCROOT)\..\node_modules\react-native-spinkit\ios/**", + ); }; name = Debug; }; @@ -1080,6 +1125,12 @@ ); PRODUCT_NAME = EZNet; VERSIONING_SYSTEM = "apple-generic"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)\..\node_modules\react-native-fetch-blob\ios/**", + "$(SRCROOT)\..\node_modules\react-native-firebase\ios\RNFirebase/**", + "$(SRCROOT)\..\node_modules\react-native-spinkit\ios/**", + ); }; name = Release; }; @@ -1106,6 +1157,18 @@ SDKROOT = appletvos; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)\..\node_modules\react-native-fetch-blob\ios/**", + "$(SRCROOT)\..\node_modules\react-native-firebase\ios\RNFirebase/**", + "$(SRCROOT)\..\node_modules\react-native-spinkit\ios/**", + ); }; name = Debug; }; @@ -1132,6 +1195,18 @@ SDKROOT = appletvos; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)\..\node_modules\react-native-fetch-blob\ios/**", + "$(SRCROOT)\..\node_modules\react-native-firebase\ios\RNFirebase/**", + "$(SRCROOT)\..\node_modules\react-native-spinkit\ios/**", + ); }; name = Release; }; @@ -1153,6 +1228,12 @@ SDKROOT = appletvos; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/EZNet-tvOS.app/EZNet-tvOS"; TVOS_DEPLOYMENT_TARGET = 10.1; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); }; name = Debug; }; @@ -1174,6 +1255,12 @@ SDKROOT = appletvos; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/EZNet-tvOS.app/EZNet-tvOS"; TVOS_DEPLOYMENT_TARGET = 10.1; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); }; name = Release; }; diff --git a/package.json b/package.json index dba9b0b..b162728 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "test": "jest" }, "dependencies": { + "react-native-spinkit": "^1.1.1", "native-base": "^2.2.0", "prop-types": "^15.5.10", "react": "16.0.0-alpha.12", diff --git a/src/actions/index.js b/src/actions/index.js index 6a1cee9..6e0165b 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,8 +1,14 @@ -import { FETCH_DATA } from './types'; +import { FETCHED_DATA, START_FETCHING } from './types'; -import { categories as data } from './../api/dummy_api'; +import Api from '../api/Api'; -export const actionFetchData = () => ({ - type: FETCH_DATA, - payload: data, -}); +export const actionFetchData = () => (dispatch) => { + dispatch({ type: START_FETCHING }); + Api.getCombinedData(Api.getCategories, Api.getSites, Api.getThumbnail) + .then((data) => { + dispatch({ + type: FETCHED_DATA, + payload: data, + }); + }); +}; diff --git a/src/actions/types.js b/src/actions/types.js index 3b73c42..8c53aad 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -1 +1,3 @@ -export const FETCH_DATA = 'fetch_data'; +export const FETCHED_DATA = 'fetched_data'; +export const START_FETCHING = 'start_fetching'; + diff --git a/src/components/App.js b/src/components/App.js index 19a3edf..2ad69b7 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -7,6 +7,7 @@ import { Container, Content } from 'native-base'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; +import Loading from './Loading'; import TwoColumnView from './common/TwoColumnView'; import BoxItem from './common/BoxItem'; @@ -15,13 +16,15 @@ import * as actions from './../actions'; const styles = StyleSheet.create({ container: { flex: 1, + alignItems: 'center', }, }); class Categories extends Component { static propTypes = { actionFetchData: PropTypes.func.isRequired, - categoryData: PropTypes.array.isRequired, + categories: PropTypes.array.isRequired, + isFetching: PropTypes.bool.isRequired, navigation: PropTypes.object.isRequired, }; @@ -34,9 +37,10 @@ class Categories extends Component { } renderCategories() { + const { categories } = this.props; const { navigate } = this.props.navigation; - const nodes = this.props.categoryData.map(category => ( + const nodes = categories.map(category => ( navigate('Detail', { title: category.title, items: category.items })} @@ -44,7 +48,7 @@ class Categories extends Component { /> )); - return ( + return nodes === null ? null : ( {nodes} @@ -52,11 +56,12 @@ class Categories extends Component { } render() { + const { isFetching } = this.props; return ( - {this.renderCategories()} + { isFetching ? : this.renderCategories() } @@ -64,8 +69,9 @@ class Categories extends Component { } } -const mapStateToProps = ({ data }) => ({ - categoryData: data, +const mapStateToProps = ({ data: { categories, isFetching } }) => ({ + categories, + isFetching, }); export default connect(mapStateToProps, actions)(Categories); diff --git a/src/components/Loading.js b/src/components/Loading.js new file mode 100644 index 0000000..128ba4b --- /dev/null +++ b/src/components/Loading.js @@ -0,0 +1,23 @@ +import React from 'react'; + +import Spinner from 'react-native-spinkit'; + +import { Stylesheet } from 'react-native'; + +const TYPE = 'ChasingDots'; +const COLOR = '#3F51B5'; +const SIZE = 100; + +const styles = Stylesheet.create({ + loader: { marginTop: '50%' }, +}}; + +const Loading = () => ( + + ); +export default Loading; diff --git a/src/reducers/data_reducer.js b/src/reducers/data_reducer.js index ff3818d..ff7fe5e 100644 --- a/src/reducers/data_reducer.js +++ b/src/reducers/data_reducer.js @@ -1,13 +1,16 @@ -import { FETCH_DATA } from './../actions/types'; +import { FETCHED_DATA, START_FETCHING } from './../actions/types'; -const InitialState = []; +const InitialState = { + isFetching: false, + categories: [], +}; export default (state = InitialState, action) => { switch (action.type) { - case FETCH_DATA: - { - return action.payload; - } + case FETCHED_DATA: + return { ...state, categories: action.payload, isFetching: false }; + case START_FETCHING: + return { ...state, categories: [], isFetching: true }; default: return state; }