From 25c8488808e47f4be7a58ef4b51ee9e29edbaf03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20My=C5=9Bliwiec?= Date: Tue, 9 Jan 2018 19:33:26 +0100 Subject: [PATCH 1/3] Add fancy loading indicator Added fancy loading indicator to show user that something is going on. --- android/app/build.gradle | 2 ++ .../codelanka/eznet/MainApplication.java | 2 ++ android/build.gradle | 2 ++ android/settings.gradle | 2 ++ ios/EZNet.xcodeproj/project.pbxproj | 17 +++++++++++++++++ package.json | 3 ++- src/actions/index.js | 6 ++++++ src/components/App.js | 16 ++++++++++++++-- src/reducers/data_reducer.js | 11 +++++++---- 9 files changed, 54 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index b0824b2..13ce189 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -138,6 +138,8 @@ dependencies { compile(project(':react-native-firebase')) { transitive = false } + compile project(':react-native-spinkit') + compile "com.google.firebase:firebase-core:11.0.0" compile "com.google.firebase:firebase-analytics:11.0.0" compile "com.google.firebase:firebase-perf:11.0.0" 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 420e767..176577e 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 @@ -4,6 +4,7 @@ import android.util.Log; import com.facebook.react.ReactApplication; +import com.react.rnspinkit.RNSpinkitPackage; import com.oblador.vectoricons.VectorIconsPackage; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; @@ -36,6 +37,7 @@ public boolean getUseDeveloperSupport() { protected List getPackages() { return Arrays.asList( new MainReactPackage(), + new RNSpinkitPackage(), new RNFirebasePackage(), new RNFirebaseAnalyticsPackage(), new RNFirebaseCrashPackage(), diff --git a/android/build.gradle b/android/build.gradle index f29d315..8532f99 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -19,6 +19,8 @@ allprojects { repositories { mavenLocal() jcenter() + // Add jitpack repository (added by react-native-spinkit) + maven { url "https://jitpack.io" } maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" diff --git a/android/settings.gradle b/android/settings.gradle index 2d2d342..dea38fa 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,6 @@ rootProject.name = 'EZNet' +include ':react-native-spinkit' +project(':react-native-spinkit').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spinkit/android') include ':react-native-fetch-blob' project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fetch-blob/android') include ':react-native-vector-icons' diff --git a/ios/EZNet.xcodeproj/project.pbxproj b/ios/EZNet.xcodeproj/project.pbxproj index c4dcbbb..2c83353 100644 --- a/ios/EZNet.xcodeproj/project.pbxproj +++ b/ios/EZNet.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 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 */ @@ -284,6 +285,8 @@ 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 */ @@ -312,6 +315,7 @@ 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, F90355EC5AE4488D8AC3A076 /* libRNFetchBlob.a in Frameworks */, 0FCD125FCBB04C22BBC14E4F /* libRNFirebase.a in Frameworks */, + AA38DD42A61547279DB2065B /* libRNSpinkit.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -480,6 +484,7 @@ 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, A8C244E03280488FA985513C /* RNFetchBlob.xcodeproj */, B6BA648C8AF7429A99A5114F /* RNFirebase.xcodeproj */, + 46590D2B8FCD42468A97733B /* RNSpinkit.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -1042,11 +1047,13 @@ "$(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; @@ -1069,11 +1076,13 @@ "$(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; @@ -1097,6 +1106,7 @@ "$(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; @@ -1119,6 +1129,7 @@ "$(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; @@ -1150,11 +1161,13 @@ "$(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; @@ -1186,11 +1199,13 @@ "$(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; @@ -1217,6 +1232,7 @@ "$(inherited)", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); }; name = Debug; @@ -1243,6 +1259,7 @@ "$(inherited)", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); }; name = Release; diff --git a/package.json b/package.json index e4fdcfa..ce0cd58 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "jest" }, "dependencies": { - "native-base": "^2.2.0", + "native-base": "2.2.0", "prop-types": "^15.5.10", "react": "16.0.0-alpha.12", "react-burger-menu": "^2.1.3", @@ -17,6 +17,7 @@ "react-native-firebase": "^2.0.2", "react-native-material-ui": "^1.12.0", "react-native-responsive-image": "^2.1.0", + "react-native-spinkit": "^1.1.1", "react-navigation": "^1.0.0-beta.11", "react-redux": "^5.0.5", "redux": "^3.7.1", diff --git a/src/actions/index.js b/src/actions/index.js index a18ffad..47c2f98 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -3,11 +3,17 @@ import { FETCH_DATA } from './types'; import Api from '../api/Api'; export const actionFetchData = () => (dispatch) => { + dispatch({ + type: FETCH_DATA, + payload: [], + isFetching: true, + }); Api.getCombinedData(Api.getCategories, Api.getSites, Api.getThumbnail) .then((data) => { dispatch({ type: FETCH_DATA, payload: data, + isFetching: false, }); }); }; diff --git a/src/components/App.js b/src/components/App.js index a2f2aba..0b2b38c 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 Spinner from 'react-native-spinkit'; import TwoColumnView from './common/TwoColumnView'; import BoxItem from './common/BoxItem'; @@ -15,13 +16,14 @@ 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, + categoryData: PropTypes.object.isRequired, navigation: PropTypes.object.isRequired, }; @@ -35,9 +37,19 @@ class Categories extends Component { renderCategories() { const { navigate } = this.props.navigation; + const { categories, isFetching } = this.props.categoryData; + if (isFetching) { + return ( + ); + } let nodes = null; - nodes = this.props.categoryData.map(category => ( + nodes = categories.map(category => ( navigate('Detail', { title: category.title, items: category.items })} diff --git a/src/reducers/data_reducer.js b/src/reducers/data_reducer.js index ff3818d..f7b1d05 100644 --- a/src/reducers/data_reducer.js +++ b/src/reducers/data_reducer.js @@ -1,13 +1,16 @@ import { FETCH_DATA } from './../actions/types'; -const InitialState = []; +const InitialState = { + isFetching: true, +}; export default (state = InitialState, action) => { switch (action.type) { case FETCH_DATA: - { - return action.payload; - } + return Object.assign({}, state, { + categories: action.payload, + isFetching: action.isFetching, + }); default: return state; } From 78483bbda04cbdccef20d9c0708293767b0fe375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20My=C5=9Bliwiec?= Date: Wed, 10 Jan 2018 17:25:26 +0100 Subject: [PATCH 2/3] Fix code readability and structure --- src/actions/index.js | 11 +++-------- src/actions/types.js | 3 ++- src/components/App.js | 27 ++++++++++----------------- src/components/Loading.js | 20 ++++++++++++++++++++ src/reducers/data_reducer.js | 12 +++++++++--- 5 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 src/components/Loading.js diff --git a/src/actions/index.js b/src/actions/index.js index 47c2f98..6e0165b 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,19 +1,14 @@ -import { FETCH_DATA } from './types'; +import { FETCHED_DATA, START_FETCHING } from './types'; import Api from '../api/Api'; export const actionFetchData = () => (dispatch) => { - dispatch({ - type: FETCH_DATA, - payload: [], - isFetching: true, - }); + dispatch({ type: START_FETCHING }); Api.getCombinedData(Api.getCategories, Api.getSites, Api.getThumbnail) .then((data) => { dispatch({ - type: FETCH_DATA, + type: FETCHED_DATA, payload: data, - isFetching: false, }); }); }; diff --git a/src/actions/types.js b/src/actions/types.js index 3b73c42..5955366 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -1 +1,2 @@ -export const FETCH_DATA = 'fetch_data'; +export const FETCHED_DATA = 'fetched_data'; +export const START_FETCHING = 'start_fetching'; \ No newline at end of file diff --git a/src/components/App.js b/src/components/App.js index 0b2b38c..2ad69b7 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -7,7 +7,7 @@ import { Container, Content } from 'native-base'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import Spinner from 'react-native-spinkit'; +import Loading from './Loading'; import TwoColumnView from './common/TwoColumnView'; import BoxItem from './common/BoxItem'; @@ -23,7 +23,8 @@ const styles = StyleSheet.create({ class Categories extends Component { static propTypes = { actionFetchData: PropTypes.func.isRequired, - categoryData: PropTypes.object.isRequired, + categories: PropTypes.array.isRequired, + isFetching: PropTypes.bool.isRequired, navigation: PropTypes.object.isRequired, }; @@ -36,20 +37,10 @@ class Categories extends Component { } renderCategories() { + const { categories } = this.props; const { navigate } = this.props.navigation; - const { categories, isFetching } = this.props.categoryData; - if (isFetching) { - return ( - ); - } - let nodes = null; - nodes = categories.map(category => ( + const nodes = categories.map(category => ( navigate('Detail', { title: category.title, items: category.items })} @@ -65,11 +56,12 @@ class Categories extends Component { } render() { + const { isFetching } = this.props; return ( - {this.renderCategories()} + { isFetching ? : this.renderCategories() } @@ -77,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..8ebdfc5 --- /dev/null +++ b/src/components/Loading.js @@ -0,0 +1,20 @@ +import React from 'react'; + +import Spinner from 'react-native-spinkit'; + +const loaderStyle = { + type: 'FoldingCube', + color: '#3F51B5', + size: 100, +} + +const Loading = () => ( + +); + +export default Loading; diff --git a/src/reducers/data_reducer.js b/src/reducers/data_reducer.js index f7b1d05..7519e08 100644 --- a/src/reducers/data_reducer.js +++ b/src/reducers/data_reducer.js @@ -1,15 +1,21 @@ -import { FETCH_DATA } from './../actions/types'; +import { FETCHED_DATA, START_FETCHING } from './../actions/types'; const InitialState = { isFetching: true, + categories: [], }; export default (state = InitialState, action) => { switch (action.type) { - case FETCH_DATA: + case FETCHED_DATA: return Object.assign({}, state, { categories: action.payload, - isFetching: action.isFetching, + isFetching: false, + }); + case START_FETCHING: + return Object.assign({}, state, { + categories: [], + isFetching: true, }); default: return state; From 77ab545ea5efcb2569b86dc6b7a9c1c76b6cd3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20My=C5=9Bliwiec?= Date: Wed, 10 Jan 2018 19:59:43 +0100 Subject: [PATCH 3/3] Modify Initial State --- src/reducers/data_reducer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reducers/data_reducer.js b/src/reducers/data_reducer.js index 7519e08..045c855 100644 --- a/src/reducers/data_reducer.js +++ b/src/reducers/data_reducer.js @@ -1,7 +1,7 @@ import { FETCHED_DATA, START_FETCHING } from './../actions/types'; const InitialState = { - isFetching: true, + isFetching: false, categories: [], };