├── .babelrc ├── .flowconfig ├── .gitignore ├── .travis.yml ├── .watchmanconfig ├── LICENSE ├── README.md ├── android ├── AirMapsExplorer.iml ├── GeoEncoding.iml ├── app │ ├── app.iml │ ├── build.gradle │ ├── proguard-rules.pro │ ├── react.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── fonts │ │ │ ├── Entypo.ttf │ │ │ ├── EvilIcons.ttf │ │ │ ├── FontAwesome.ttf │ │ │ ├── Foundation.ttf │ │ │ ├── Ionicons.ttf │ │ │ ├── MaterialIcons.ttf │ │ │ ├── Octicons.ttf │ │ │ └── Zocial.ttf │ │ ├── ic_launcher-web.png │ │ ├── java │ │ └── com │ │ │ └── geoencoding │ │ │ └── MainActivity.java │ │ └── res │ │ ├── drawable │ │ └── splash.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app ├── __mocks__ │ ├── mockResponse.js │ ├── mockStore.js │ └── react-native.js ├── actions │ ├── __tests__ │ │ └── addressActions.spec.js │ ├── accountActions.js │ ├── actionTypes.js │ ├── addressActions.js │ ├── databaseActions.js │ ├── downloadActions.js │ └── routerActions.js ├── components │ ├── Banner.js │ ├── TabBarItem.js │ ├── __tests__ │ │ └── addressList.spec.js │ ├── addressDetails.js │ ├── addressList.js │ ├── cameraPage.js │ ├── customScrollView.js │ ├── downloadList.js │ ├── favourites.js │ ├── featureList.js │ ├── imagePickerPage.js │ ├── launch.js │ ├── login.js │ ├── myAccount.js │ ├── signUp.js │ ├── tabBar.js │ ├── toast.ios.js │ └── videoPage.js ├── containers │ ├── RouterContainerStyles.js │ ├── app.js │ └── geoEncodingApp.js ├── database │ └── database.js ├── index.js ├── lib │ └── Video.js ├── reducers │ ├── __tests__ │ │ └── address.spec.js │ ├── account.js │ ├── address.js │ ├── downloads.js │ ├── index.js │ └── router.js └── store │ ├── configureStore.dev.js │ ├── configureStore.js │ ├── configureStore.prod.js │ └── globals.js ├── assets ├── __mocks__ │ └── index.js ├── downloads.png ├── ic_stat_delete.png ├── ic_stat_fav.png ├── ic_stat_notfav.png ├── ic_stat_refresh.png ├── index.js ├── loading_streetview.png ├── thin-0046_home_house.png ├── thin-0046_home_house@2x.png ├── thin-0091_file_profile_user_personal.png ├── thin-0091_file_profile_user_personal@2x.png ├── thin-0592_tv_televison_movie_news.png └── thin-0592_tv_televison_movie_news@2x.png ├── index.android.js ├── index.ios.js ├── ios ├── GeoEncoding.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── GeoEncoding DEBUG.xcscheme │ │ ├── GeoEncoding RELEASE.xcscheme │ │ └── GeoEncoding RUN_DEVICE.xcscheme ├── GeoEncoding │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── splash.png │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-40.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-76.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-83.5@2x.png │ │ │ ├── Icon-Small.png │ │ │ ├── Icon-Small@2x.png │ │ │ └── Icon-Small@3x.png │ │ ├── Contents.json │ │ ├── LaunchImage.launchimage │ │ │ ├── Contents.json │ │ │ ├── Default-568h@2x-1.png │ │ │ ├── Default-568h@2x-2.png │ │ │ ├── Default-568h@2x-3.png │ │ │ ├── Default-568h@2x.png │ │ │ ├── Default-667h@2x.png │ │ │ ├── Default-Landscape-736h@3x-1.png │ │ │ ├── Default-Landscape-736h@3x.png │ │ │ ├── Default-Portrait-736h@3x.png │ │ │ └── Default@2x.png │ │ └── splash.imageset │ │ │ ├── Contents.json │ │ │ └── Default-667h@2x.png │ ├── Info.plist │ └── main.m ├── GeoEncodingTests │ ├── GeoEncodingTests.m │ └── Info.plist ├── Mapbox.bundle │ ├── Compass.png │ ├── Compass@2x.png │ ├── Compass@3x.png │ ├── README │ ├── api_mapbox_com-digicert.der │ ├── api_mapbox_com-geotrust.der │ ├── default_marker.png │ ├── default_marker@2x.png │ ├── default_marker@3x.png │ ├── mapbox.png │ ├── mapbox@2x.png │ ├── mapbox@3x.png │ └── star_tilestream_net.der └── Settings.bundle │ └── Root.plist ├── jestSupport ├── customMatchers.js └── scriptPreprocess.js ├── package.json ├── release └── assets │ └── assets │ ├── ic_stat_delete.png │ ├── ic_stat_fav.png │ ├── ic_stat_notfav.png │ └── loading_streetview.png └── test ├── actions-addressActions.js ├── mock └── response.js └── reducers-address.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-native/packager/react-packager/.babelrc" 3 | } 4 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.web.js 5 | .*/*.android.js 6 | 7 | # Some modules have their own node_modules with overlap 8 | .*/node_modules/node-haste/.* 9 | 10 | # Ugh 11 | .*/node_modules/babel.* 12 | .*/node_modules/babylon.* 13 | .*/node_modules/invariant.* 14 | 15 | # Ignore react and fbjs where there are overlaps, but don't ignore 16 | # anything that react-native relies on 17 | .*/node_modules/fbjs-haste/.*/__tests__/.* 18 | .*/node_modules/fbjs-haste/__forks__/Map.js 19 | .*/node_modules/fbjs-haste/__forks__/Promise.js 20 | .*/node_modules/fbjs-haste/__forks__/fetch.js 21 | .*/node_modules/fbjs-haste/core/ExecutionEnvironment.js 22 | .*/node_modules/fbjs-haste/core/isEmpty.js 23 | .*/node_modules/fbjs-haste/crypto/crc32.js 24 | .*/node_modules/fbjs-haste/stubs/ErrorUtils.js 25 | .*/node_modules/react-haste/React.js 26 | .*/node_modules/react-haste/renderers/dom/ReactDOM.js 27 | .*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js 28 | 29 | # Ignore commoner tests 30 | .*/node_modules/commoner/test/.* 31 | 32 | # See https://github.com/facebook/flow/issues/442 33 | .*/react-tools/node_modules/commoner/lib/reader.js 34 | 35 | # Ignore jest 36 | .*/node_modules/jest-cli/.* 37 | 38 | # Ignore Website 39 | .*/website/.* 40 | 41 | [include] 42 | 43 | [libs] 44 | node_modules/react-native/Libraries/react-native/react-native-interface.js 45 | 46 | [options] 47 | module.system=haste 48 | 49 | munge_underscores=true 50 | 51 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 52 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub' 53 | 54 | suppress_type=$FlowIssue 55 | suppress_type=$FlowFixMe 56 | suppress_type=$FixMe 57 | 58 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 59 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+ 60 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 61 | 62 | [version] 63 | 0.19.0 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IJ 26 | # 27 | .idea 28 | .gradle 29 | local.properties 30 | *.keystore 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | main.jsbundle 37 | 38 | # jest 39 | coverage/ 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7 3 | xcode_sdk: iphonesimulator9.0 4 | 5 | cache: 6 | directories: 7 | - node_modules 8 | - ios/Pods 9 | - ~/.nvm 10 | 11 | before_install: 12 | - which nvm || curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash 13 | - export NVM_DIR=~/.nvm 14 | - source ~/.nvm/nvm.sh --install 15 | - nvm install 4.2.3 16 | - brew update 17 | - brew reinstall xctool 18 | - brew reinstall watchman 19 | - npm install rnpm -g 20 | - npm install 21 | 22 | script: 23 | - npm run simpletest 24 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GeoEncoding [![Build Status](https://travis-ci.org/LynxITDigital/GeoEncoding.svg?branch=master)](https://travis-ci.org/LynxITDigital/GeoEncoding) 2 | 3 | A react-native example for ListView, MapView, ImageView, NavigationBar, react-redux which runs on both iOS and Android 4 | 5 | #Features 6 | - [x] Listview 7 | - [x] Imageview 8 | - [x] Mapview 9 | - [x] Redux 10 | - [x] Router 11 | - [x] Jest tests 12 | - [x] Sqlite 13 | - [x] Tabbar 14 | - [x] CodePush 15 | - [x] Travis 16 | - [x] Video Player 17 | - [x] Network request 18 | - [x] Toast notification (When adding an address to Favourites) 19 | - [x] Custom splash screen 20 | - [x] Network download 21 | - [x] Network upload - Login / Account Manage feature 22 | - [ ] Barcode scanner 23 | - [ ] Location update (background) 24 | - [ ] Push notification 25 | - [ ] Expandable listview 26 | - [ ] Thumbnail view with preview 27 | - [ ] Sidebar drawer 28 | - [ ] Performance testing for listview (load a few thousands record to our listview) 29 | - [ ] 'Share' functionality 30 | - [ ] Custom Video controls 31 | - [ ] Whiteboard? - demonstrate touch tracking and graphics libraries 32 | 33 | 34 | Install node modeules 35 | ```shell 36 | npm install 37 | ``` 38 | 39 | # CodePush 40 | Now you can update your app remotely without going through app store using CodePush. It works with both iOS and Android. 41 | 42 | To bundle 43 | ```shell 44 | react-native bundle --platform ios --entry-file index.ios.js --bundle-output main.jsbundle --dev false 45 | ``` 46 | 47 | To release 48 | ```shell 49 | code-push release GeoEncoding main.jsbundle 1.0.0 --deploymentName Production 50 | ``` 51 | # Jest Tests 52 | * run the tests 53 | * Run "npm test " to test a special suit; 54 | * or simply run "npm test" to get through all test suits in verbose mode. 55 | 56 | * generate test coverage 57 | * Run "npm run coverage" to generate both a simple coverage chart within console and html coverage report under /coverage/ 58 | 59 | ![alt tag](https://github.com/LynxITDigital/Screenshots/blob/master/test_coverage.png) 60 | 61 | 62 | #Screenshots 63 | ## Search 64 | 65 | ![alt tag](https://github.com/LynxITDigital/Screenshots/blob/master/Search.gif) 66 | 67 | ## Toast 68 | ### iOS 69 | ![alt tag](https://github.com/LynxITDigital/Screenshots/blob/master/Toast.gif) 70 | 71 | ### Android 72 | ![alt tag](https://github.com/LynxITDigital/Screenshots/blob/master/Toast_Android.gif) 73 | 74 | ## Tab Bar 75 | ### iOS 76 | ![alt tag](https://github.com/LynxITDigital/Screenshots/blob/master/Tabbar_iOS.gif) 77 | 78 | ### Android 79 | ![alt tag](https://github.com/LynxITDigital/Screenshots/blob/master/Tabbar_Android.gif) 80 | -------------------------------------------------------------------------------- /android/AirMapsExplorer.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /android/GeoEncoding.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | /** 4 | * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets. 5 | * These basically call `react-native bundle` with the correct arguments during the Android build 6 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 7 | * bundle directly from the development server. Below you can see all the possible configurations 8 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 9 | * `apply from: "react.gradle"` line. 10 | * 11 | * project.ext.react = [ 12 | * // the name of the generated asset file containing your JS bundle 13 | * bundleAssetName: "index.android.bundle", 14 | * 15 | * // the entry file for bundle generation 16 | * entryFile: "index.android.js", 17 | * 18 | * // whether to bundle JS and assets in debug mode 19 | * bundleInDebug: false, 20 | * 21 | * // whether to bundle JS and assets in release mode 22 | * bundleInRelease: true, 23 | * 24 | * // the root of your project, i.e. where "package.json" lives 25 | * root: "../../", 26 | * 27 | * // where to put the JS bundle asset in debug mode 28 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 29 | * 30 | * // where to put the JS bundle asset in release mode 31 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 32 | * 33 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 34 | * // require('./image.png')), in debug mode 35 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 36 | * 37 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 38 | * // require('./image.png')), in release mode 39 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 40 | * 41 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 42 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 43 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 44 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 45 | * // for example, you might want to remove it from here. 46 | * inputExcludes: ["android/**", "ios/**"] 47 | * ] 48 | */ 49 | 50 | apply from: "react.gradle" 51 | 52 | android { 53 | compileSdkVersion 23 54 | buildToolsVersion "23.0.1" 55 | 56 | defaultConfig { 57 | applicationId "com.geoencoding" 58 | minSdkVersion 16 59 | targetSdkVersion 22 60 | versionCode 3 61 | versionName "1.0.3" 62 | ndk { 63 | abiFilters "armeabi-v7a", "x86" 64 | } 65 | } 66 | signingConfigs { 67 | release { 68 | if(System.getenv("GEOENCODING_RELEASE_KEY_ALIAS") == "release-geo-alias"){ 69 | storeFile file(System.getenv("GEOENCODING_RELEASE_STORE_FILE")) 70 | storePassword System.getenv("GEOENCODING_RELEASE_STORE_PASSWORD") 71 | keyAlias System.getenv("GEOENCODING_RELEASE_KEY_ALIAS") 72 | keyPassword System.getenv("GEOENCODING_RELEASE_KEY_PASSWORD") 73 | } 74 | } 75 | } 76 | buildTypes { 77 | release { 78 | minifyEnabled false // Set this to true to enable Proguard 79 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 80 | signingConfig signingConfigs.release 81 | } 82 | } 83 | } 84 | 85 | dependencies { 86 | compile project(':react-native-image-picker') 87 | compile project(':react-native-orientation') 88 | compile project(':react-native-video') 89 | compile project(':react-native-maps') 90 | compile project(':@remobile/react-native-splashscreen') 91 | compile fileTree(dir: 'libs', include: ['*.jar']) 92 | compile 'com.android.support:appcompat-v7:23.0.1' 93 | compile 'com.facebook.react:react-native:0.17.+' 94 | compile project(':react-native-sqlite-storage') 95 | compile project(':react-native-code-push') 96 | compile project(':react-native-fs') 97 | compile project(':react-native-vector-icons') 98 | } 99 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | 30 | # Do not strip any method/class that is annotated with @DoNotStrip 31 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 32 | -keepclassmembers class * { 33 | @com.facebook.proguard.annotations.DoNotStrip *; 34 | } 35 | 36 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 37 | void set*(***); 38 | *** get*(); 39 | } 40 | 41 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 42 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 43 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 44 | -keepclassmembers class * { @com.facebook.react.uimanager.ReactProp ; } 45 | -keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup ; } 46 | 47 | # okhttp 48 | 49 | -keepattributes Signature 50 | -keepattributes *Annotation* 51 | -keep class com.squareup.okhttp.** { *; } 52 | -keep interface com.squareup.okhttp.** { *; } 53 | -dontwarn com.squareup.okhttp.** 54 | 55 | # okio 56 | 57 | -keep class sun.misc.Unsafe { *; } 58 | -dontwarn java.nio.file.* 59 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 60 | -dontwarn okio.** 61 | -------------------------------------------------------------------------------- /android/app/react.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os 2 | 3 | def config = project.hasProperty("react") ? project.react : []; 4 | 5 | def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" 6 | def entryFile = config.entryFile ?: "index.android.js" 7 | 8 | // because elvis operator 9 | def elvisFile(thing) { 10 | return thing ? file(thing) : null; 11 | } 12 | 13 | def reactRoot = elvisFile(config.root) ?: file("../../") 14 | def jsBundleDirDebug = elvisFile(config.jsBundleDirDebug) ?: 15 | file("$buildDir/intermediates/assets/debug") 16 | def jsBundleDirRelease = elvisFile(config.jsBundleDirRelease) ?: 17 | file("$buildDir/intermediates/assets/release") 18 | def resourcesDirDebug = elvisFile(config.resourcesDirDebug) ?: 19 | file("$buildDir/intermediates/res/merged/debug") 20 | def resourcesDirRelease = elvisFile(config.resourcesDirRelease) ?: 21 | file("$buildDir/intermediates/res/merged/release") 22 | def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] 23 | 24 | def jsBundleFileDebug = file("$jsBundleDirDebug/$bundleAssetName") 25 | def jsBundleFileRelease = file("$jsBundleDirRelease/$bundleAssetName") 26 | 27 | task bundleDebugJsAndAssets(type: Exec) { 28 | // create dirs if they are not there (e.g. the "clean" task just ran) 29 | doFirst { 30 | jsBundleDirDebug.mkdirs() 31 | resourcesDirDebug.mkdirs() 32 | } 33 | 34 | // set up inputs and outputs so gradle can cache the result 35 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes) 36 | outputs.dir jsBundleDirDebug 37 | outputs.dir resourcesDirDebug 38 | 39 | // set up the call to the react-native cli 40 | workingDir reactRoot 41 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 42 | commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file", 43 | entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug 44 | } else { 45 | commandLine "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file", 46 | entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug 47 | } 48 | 49 | enabled config.bundleInDebug ?: false 50 | } 51 | 52 | task bundleReleaseJsAndAssets(type: Exec) { 53 | // create dirs if they are not there (e.g. the "clean" task just ran) 54 | doFirst { 55 | jsBundleDirRelease.mkdirs() 56 | resourcesDirRelease.mkdirs() 57 | } 58 | 59 | // set up inputs and outputs so gradle can cache the result 60 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes) 61 | outputs.dir jsBundleDirRelease 62 | outputs.dir resourcesDirRelease 63 | 64 | // set up the call to the react-native cli 65 | workingDir reactRoot 66 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 67 | commandLine "cmd","/c", "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file", 68 | entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease 69 | } else { 70 | commandLine "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file", 71 | entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease 72 | } 73 | 74 | enabled config.bundleInRelease ?: true 75 | } 76 | 77 | gradle.projectsEvaluated { 78 | // hook bundleDebugJsAndAssets into the android build process 79 | bundleDebugJsAndAssets.dependsOn mergeDebugResources 80 | bundleDebugJsAndAssets.dependsOn mergeDebugAssets 81 | processDebugResources.dependsOn bundleDebugJsAndAssets 82 | 83 | // hook bundleReleaseJsAndAssets into the android build process 84 | bundleReleaseJsAndAssets.dependsOn mergeReleaseResources 85 | bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets 86 | processReleaseResources.dependsOn bundleReleaseJsAndAssets 87 | } 88 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /android/app/src/main/java/com/geoencoding/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.geoencoding; 2 | 3 | import android.app.Activity; 4 | import com.imagepicker.ImagePickerPackage; 5 | import com.github.yamill.orientation.OrientationPackage; 6 | import com.brentvatne.react.ReactVideoPackage; 7 | import com.AirMaps.AirPackage; 8 | import com.remobile.splashscreen.RCTSplashScreenPackage; 9 | import android.os.Bundle; 10 | import android.support.v4.app.FragmentActivity; 11 | import android.view.KeyEvent; 12 | import android.content.Intent; 13 | import android.content.res.Configuration; 14 | 15 | import com.facebook.react.LifecycleState; 16 | import com.facebook.react.ReactInstanceManager; 17 | import com.facebook.react.ReactRootView; 18 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; 19 | import com.facebook.react.shell.MainReactPackage; 20 | import com.facebook.soloader.SoLoader; 21 | 22 | import org.pgsqlite.SQLitePluginPackage; 23 | 24 | import com.microsoft.codepush.react.CodePush; 25 | import android.support.v4.app.FragmentActivity; 26 | 27 | import com.rnfs.RNFSPackage; 28 | 29 | import com.oblador.vectoricons.VectorIconsPackage; 30 | 31 | 32 | public class MainActivity extends FragmentActivity implements DefaultHardwareBackBtnHandler { 33 | 34 | private ReactInstanceManager mReactInstanceManager; 35 | private ReactRootView mReactRootView; 36 | private ImagePickerPackage mImagePicker; 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | CodePush codePush = new CodePush("9OcY7WuRIwcigP2x6H5z8bTZPLN94yXS9p7Fg", this, BuildConfig.DEBUG); 42 | 43 | mReactRootView = new ReactRootView(this); 44 | 45 | 46 | // instantiate package 47 | mImagePicker = new ImagePickerPackage(this); 48 | 49 | 50 | mReactInstanceManager = ReactInstanceManager.builder() 51 | .setApplication(getApplication()) 52 | // .setBundleAssetName("index.android.bundle") 53 | .setJSBundleFile(codePush.getBundleUrl("index.android.bundle")) 54 | .setJSMainModuleName("index.android") 55 | .addPackage(new MainReactPackage()) 56 | .addPackage(mImagePicker) 57 | .addPackage(new OrientationPackage(this)) 58 | .addPackage(new ReactVideoPackage()) 59 | .addPackage(new AirPackage()) 60 | .addPackage(new RCTSplashScreenPackage(this)) 61 | .addPackage(new SQLitePluginPackage(this)) // register SQLite Plugin here 62 | .addPackage(new RNFSPackage()) 63 | .addPackage(new VectorIconsPackage()) 64 | .addPackage(codePush.getReactPackage()) 65 | .setUseDeveloperSupport(BuildConfig.DEBUG) 66 | .setInitialLifecycleState(LifecycleState.RESUMED) 67 | .build(); 68 | 69 | mReactRootView.startReactApplication(mReactInstanceManager, "GeoEncoding", null); 70 | 71 | setContentView(mReactRootView); 72 | } 73 | 74 | @Override 75 | public boolean onKeyUp(int keyCode, KeyEvent event) { 76 | if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { 77 | mReactInstanceManager.showDevOptionsDialog(); 78 | return true; 79 | } 80 | return super.onKeyUp(keyCode, event); 81 | } 82 | 83 | @Override 84 | public void onBackPressed() { 85 | if (mReactInstanceManager != null) { 86 | mReactInstanceManager.onBackPressed(); 87 | } else { 88 | super.onBackPressed(); 89 | } 90 | } 91 | 92 | @Override 93 | public void invokeDefaultOnBackPressed() { 94 | super.onBackPressed(); 95 | } 96 | 97 | @Override 98 | protected void onPause() { 99 | super.onPause(); 100 | 101 | if (mReactInstanceManager != null) { 102 | mReactInstanceManager.onPause(); 103 | } 104 | } 105 | 106 | @Override 107 | protected void onResume() { 108 | super.onResume(); 109 | 110 | if (mReactInstanceManager != null) { 111 | mReactInstanceManager.onResume(this, this); 112 | } 113 | } 114 | 115 | @Override 116 | public void onConfigurationChanged(Configuration newConfig) { 117 | super.onConfigurationChanged(newConfig); 118 | Intent intent = new Intent("onConfigurationChanged"); 119 | intent.putExtra("newConfig", newConfig); 120 | this.sendBroadcast(intent); 121 | } 122 | 123 | @Override 124 | public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { 125 | super.onActivityResult(requestCode, resultCode, data); 126 | mImagePicker.handleActivityResult(requestCode, resultCode, data); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/res/drawable/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GeoEncoding 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LynxITDigital/GeoEncoding/2c89f9e3a330c2a7c58ea20a08a5981de2b4cb41/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'GeoEncoding' 2 | 3 | include ':app' 4 | 5 | include ':react-native-sqlite-storage' 6 | project(':react-native-sqlite-storage').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sqlite-storage/src/android') 7 | 8 | include ':react-native-code-push' 9 | project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app') 10 | 11 | include ':react-native-fs' 12 | project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android') 13 | 14 | include ':react-native-vector-icons' 15 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') 16 | include ':@remobile/react-native-splashscreen' 17 | project(':@remobile/react-native-splashscreen').projectDir = new File(rootProject.projectDir, '../node_modules/@remobile/react-native-splashscreen/android') 18 | include ':react-native-maps' 19 | project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/android') 20 | include ':react-native-video' 21 | project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android') 22 | include ':react-native-orientation' 23 | project(':react-native-orientation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation/android') 24 | include ':react-native-image-picker' 25 | project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android') 26 | -------------------------------------------------------------------------------- /app/__mocks__/mockResponse.js: -------------------------------------------------------------------------------- 1 | module.exports.response1 = {results :[ 2 | { 3 | address_components: [ 4 | { 5 | long_name: "Melbourne", 6 | short_name: "Melbourne", 7 | types: [ 8 | "locality", 9 | "political" 10 | ] 11 | }, 12 | { 13 | long_name: "Brevard County", 14 | short_name: "Brevard County", 15 | types: [ 16 | "administrative_area_level_2", 17 | "political" 18 | ] 19 | }, 20 | { 21 | long_name: "Florida", 22 | short_name: "FL", 23 | types: [ 24 | "administrative_area_level_1", 25 | "political" 26 | ] 27 | }, 28 | { 29 | long_name: "United States", 30 | short_name: "US", 31 | types: [ 32 | "country", 33 | "political" 34 | ] 35 | } 36 | ], 37 | formatted_address: "Melbourne, FL, USA", 38 | geometry: { 39 | bounds: { 40 | northeast: { 41 | lat: 28.199865, 42 | lng: -80.57501289999999 43 | }, 44 | southwest: { 45 | lat: 28.035096, 46 | lng: -80.73554209999999 47 | } 48 | }, 49 | location: { 50 | lat: 28.0836269, 51 | lng: -80.60810889999999 52 | }, 53 | location_type: "APPROXIMATE", 54 | viewport: { 55 | northeast: { 56 | lat: 28.199865, 57 | lng: -80.57501289999999 58 | }, 59 | southwest: { 60 | lat: 28.035096, 61 | lng: -80.73554209999999 62 | } 63 | } 64 | }, 65 | place_id: "ChIJTZlxRywO3ogRqNIMqVSyzYs", 66 | types: [ 67 | "locality", 68 | "political" 69 | ] 70 | } 71 | ] 72 | } 73 | 74 | 75 | module.exports.response2 = {results :[ 76 | { 77 | address_components: [ 78 | { 79 | long_name: "Melbourne111", 80 | short_name: "Melbourne", 81 | types: [ 82 | "locality", 83 | "political" 84 | ] 85 | }, 86 | { 87 | long_name: "Brevard County", 88 | short_name: "Brevard County", 89 | types: [ 90 | "administrative_area_level_2", 91 | "political" 92 | ] 93 | }, 94 | { 95 | long_name: "Florida", 96 | short_name: "FL", 97 | types: [ 98 | "administrative_area_level_1", 99 | "political" 100 | ] 101 | }, 102 | { 103 | long_name: "United States", 104 | short_name: "US", 105 | types: [ 106 | "country", 107 | "political" 108 | ] 109 | } 110 | ], 111 | formatted_address: "Melbourne, FL, USA", 112 | geometry: { 113 | bounds: { 114 | northeast: { 115 | lat: 28.199865, 116 | lng: -80.57501289999999 117 | }, 118 | southwest: { 119 | lat: 28.035096, 120 | lng: -80.73554209999999 121 | } 122 | }, 123 | location: { 124 | lat: 28.0836269, 125 | lng: -80.60810889999999 126 | }, 127 | location_type: "APPROXIMATE", 128 | viewport: { 129 | northeast: { 130 | lat: 28.199865, 131 | lng: -80.57501289999999 132 | }, 133 | southwest: { 134 | lat: 28.035096, 135 | lng: -80.73554209999999 136 | } 137 | } 138 | }, 139 | place_id: "ChIJTZlxRywO3ogRqNIMqVSyzYs", 140 | types: [ 141 | "locality", 142 | "political" 143 | ] 144 | } 145 | ] 146 | } 147 | -------------------------------------------------------------------------------- /app/__mocks__/mockStore.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # Store.js 3 | * 4 | * This mocks the Redux store 5 | */ 6 | 'use strict'; 7 | /** 8 | * ## Imports 9 | * 10 | * same middleWare as the app uses 11 | */ 12 | const { applyMiddleware } = require('redux'); 13 | const thunk = require('redux-thunk'); 14 | 15 | 16 | const middlewares = [thunk]; 17 | 18 | /** 19 | * ## mockStore 20 | * 21 | * @param {Object} state - initialState 22 | * @param {Object} expectedActions - array of actions 23 | * 24 | * @see http://rackt.org/redux/docs/recipes/WritingTests.html 25 | */ 26 | export default function mockStore(state, expectedActions) { 27 | if (!Array.isArray(expectedActions)) { 28 | throw new Error('expectedActions should be an array of expected actions.'); 29 | } 30 | /** 31 | * ### mockStoreWithoutMiddleware 32 | * 33 | * if the state is a function, execute it 34 | */ 35 | function mockStoreWithoutMiddleware() { 36 | return { 37 | getState() { 38 | return typeof state === 'function' ? state() : state; 39 | }, 40 | /** 41 | * #### dispatch 42 | * each time the action being tested, dispatches an action 43 | * confirm that it is in order, and that all of them have been processed 44 | */ 45 | dispatch(action) { 46 | const expectedAction = expectedActions.shift(); 47 | try { 48 | expect(action).toEqual(expectedAction); 49 | return action; 50 | } catch (e) { 51 | throw new Error(e); 52 | } 53 | } 54 | }; 55 | } 56 | /** 57 | * ## basic testing setup 58 | */ 59 | const mockStoreWithMiddleware = applyMiddleware( 60 | ...middlewares 61 | )(mockStoreWithoutMiddleware); 62 | 63 | return mockStoreWithMiddleware(); 64 | } 65 | -------------------------------------------------------------------------------- /app/__mocks__/react-native.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react'); 4 | var ReactNative = React; 5 | 6 | ReactNative.StyleSheet = { 7 | create: function(styles) { 8 | return styles; 9 | } 10 | }; 11 | 12 | class View extends React.Component {} 13 | class TouchableWithoutFeedback extends React.Component {} 14 | class TouchableHighlight extends React.Component {} 15 | class TouchableOpacity extends React.Component {} 16 | class ScrollView extends React.Component {} 17 | class ActivityIndicatorIOS extends React.Component {} 18 | class Text extends React.Component {} 19 | class TextInput extends React.Component {} 20 | class ListView extends React.Component {} 21 | class Easing extends React.Component {} 22 | class Animated extends React.Component {} 23 | 24 | // class requireNativeComponent extends React.Component {} 25 | // class Platform extends React.Component {} 26 | 27 | ReactNative.View = View; 28 | ReactNative.TouchableWithoutFeedback = TouchableWithoutFeedback; 29 | ReactNative.TouchableHighlight = TouchableHighlight; 30 | ReactNative.ScrollView = ScrollView; 31 | ReactNative.TouchableOpacity = TouchableOpacity; 32 | ReactNative.ActivityIndicatorIOS = ActivityIndicatorIOS; 33 | ReactNative.Text = Text; 34 | ReactNative.TextInput = TextInput; 35 | 36 | // mocks for ListView 37 | ReactNative.ListView = ListView; 38 | class ListViewDataSource { 39 | cloneWithRows() { 40 | return new ListViewDataSource(); 41 | } 42 | } 43 | ReactNative.ListView.DataSource = () => { 44 | return new ListViewDataSource(); 45 | }; 46 | 47 | ReactNative.Easing = Easing; 48 | ReactNative.Easing.in = () => {}; 49 | ReactNative.Easing.out = () => {}; 50 | ReactNative.Easing.inOut = () => {}; 51 | ReactNative.Animated = Animated; 52 | ReactNative.Animated.createAnimatedComponent = () => {}; 53 | 54 | ReactNative.requireNativeComponent = () => {}; 55 | ReactNative.Platform = {}; 56 | 57 | // mocks for react-native-fs 58 | ReactNative.NativeModules = {}; 59 | ReactNative.NativeModules.RNFSManager = {}; 60 | ReactNative.NativeModules.RNFSManager.readDir = () => {}; 61 | ReactNative.NativeModules.RNFSManager.stat = () => {}; 62 | ReactNative.NativeModules.RNFSManager.readFile = () => {}; 63 | ReactNative.NativeModules.RNFSManager.writeFile = () => {}; 64 | ReactNative.NativeModules.RNFSManager.moveFile = () => {}; 65 | ReactNative.NativeModules.RNFSManager.unlink = () => {}; 66 | ReactNative.NativeModules.RNFSManager.mkdir = () => {}; 67 | ReactNative.NativeModules.RNFSManager.downloadFile = () => {}; 68 | ReactNative.NativeModules.RNFSManager.pathForBundle = () => {}; 69 | 70 | module.exports = ReactNative; 71 | -------------------------------------------------------------------------------- /app/actions/__tests__/addressActions.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const nock = require('nock'); 4 | const mockStore = require('../../__mocks__/mockStore').default; 5 | 6 | import fetch from 'isomorphic-fetch'; 7 | const mockResponse = require('../../__mocks__/mockResponse'); 8 | 9 | import * as actionTypes from '../actionTypes'; 10 | 11 | // use dontMock+require syntax to fix coverage disappearing bug 12 | jest.dontMock('../addressActions'); 13 | const actions = require('../addressActions'); 14 | // require.requireActual works fine for tests, however it makes test coverage disappearing currently 15 | // const actions = require.requireActual('../../app/actions/addressActions'); 16 | 17 | describe('addressActions', () => { 18 | let searchString; 19 | 20 | /** 21 | * setup 22 | */ 23 | beforeEach(() => { 24 | searchString = "melbourne"; 25 | }); 26 | 27 | /** 28 | * teardown 29 | */ 30 | afterEach(() => { 31 | // cleanup for network mocks 32 | nock.cleanAll(); 33 | }); 34 | 35 | /** 36 | * sync ations 37 | */ 38 | it('should creates an action to change search text', () => { 39 | const expectedAction = { 40 | type: actionTypes.CHANGE_SEARCH_TEXT, 41 | searchString: searchString 42 | }; 43 | 44 | expect(actions.changeSearchText(searchString)).toEqual(expectedAction); 45 | }); 46 | 47 | /** 48 | * async actions 49 | */ 50 | pit('should creates an action to fetchAddresses', () => { 51 | const url = 'https://maps.googleapis.com' 52 | const getString = '/maps/api/geocode/json?address=' 53 | nock(url) 54 | .get(getString + searchString) 55 | .reply(200, mockResponse.response); 56 | 57 | const prevState = { 58 | addresses : [], 59 | searchString : searchString, 60 | routes : {} 61 | }; 62 | const expectedActions = [ 63 | { type: actionTypes.REQUEST_ADDRESS, url : url + getString + searchString}, 64 | { type: actionTypes.RECEIVE_ADDRESS, addresses: mockResponse.response1.results} 65 | ]; 66 | 67 | const store = mockStore(prevState, expectedActions); 68 | return store.dispatch(actions.fetchAddresses(searchString)); 69 | }); 70 | 71 | }); 72 | -------------------------------------------------------------------------------- /app/actions/accountActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./actionTypes'); 2 | import * as routerActions from '../actions/routerActions'; 3 | import Database from '../database/database'; 4 | 5 | 6 | function requestData() { 7 | return { 8 | type: types.REQUEST_ACCOUNT_DATA 9 | }; 10 | } 11 | 12 | 13 | function receiveLogin(response) { 14 | return { 15 | type: types.RECEIVE_LOGIN, 16 | response 17 | }; 18 | } 19 | 20 | function receiveAccountData(response) { 21 | return { 22 | type: types.RECEIVE_ACCOUNT_DATA, 23 | response 24 | }; 25 | } 26 | 27 | var host = '192.168.48.17'; 28 | 29 | /** 30 | Fetch download records from DB 31 | **/ 32 | module.exports.doLogin = function(data) { 33 | 34 | //console.log("LOGGING IN"); 35 | return dispatch=>{ 36 | dispatch(requestData()) 37 | return fetch("http://" + host + ":3000/ws/login", { 38 | method: 'POST', 39 | headers: { 40 | 'Accept': 'application/json', 41 | 'Content-Type': 'application/json' 42 | }, 43 | body: JSON.stringify(data) 44 | }) 45 | .then(response => 46 | response.json() 47 | ) 48 | .then((json) => { 49 | console.log(json); 50 | dispatch(receiveLogin(json)) 51 | }) 52 | .catch((error) => { 53 | console.log("Action - FETCH ERROR " + error); 54 | }) 55 | 56 | 57 | //Send Login Request 58 | }; 59 | } 60 | 61 | module.exports.signUp = function(data){ 62 | 63 | //console.log("SIGNING UP"); 64 | return dispatch=>{ 65 | dispatch(requestData()) 66 | 67 | return fetch("http://" + host + ":3000/db/users", { 68 | method: 'POST', 69 | headers: { 70 | 'Accept': 'application/json', 71 | 'Content-Type': 'application/json' 72 | }, 73 | body: JSON.stringify(data) 74 | }) 75 | .then(response => 76 | response.json() 77 | ) 78 | .then((json) => { 79 | console.log(json); 80 | dispatch(receiveAccountData(json)); 81 | }) 82 | .catch((error) => { 83 | console.log("Action - FETCH ERROR " + error); 84 | dispatch(receiveAccountData(json)); 85 | }) 86 | 87 | 88 | //Send Login Request 89 | }; 90 | } 91 | 92 | 93 | 94 | module.exports.updateAccount = function(data){ 95 | 96 | // console.log("UPDATING ACCOUNT"); 97 | return dispatch=>{ 98 | dispatch(requestData()) 99 | 100 | return fetch("http://" + host + ":3000/db/users/"+data._id, { 101 | method: 'PUT', 102 | headers: { 103 | 'Accept': 'application/json', 104 | 'Content-Type': 'application/json' 105 | }, 106 | body: JSON.stringify(data) 107 | }) 108 | .then(response => 109 | response.json() 110 | ) 111 | .then((json) => { 112 | console.log(json); 113 | dispatch(receiveAccountData(json)); 114 | }) 115 | .catch((error) => { 116 | console.log("Action - FETCH ERROR " + error); 117 | }) 118 | 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /app/actions/actionTypes.js: -------------------------------------------------------------------------------- 1 | //Address Actions 2 | exports.CHANGE_SEARCH_TEXT = 'CHANGE_SEARCH_TEXT' 3 | exports.REQUEST_ADDRESS = 'REQUEST_ADDRESS' 4 | exports.RECEIVE_ADDRESS = 'RECEIVE_ADDRESS' 5 | exports.RECEIVE_EMPTY = 'RECEIVE_EMPTY' 6 | exports.ROW_PRESS = 'ROW_PRESS' 7 | 8 | //Route Actions 9 | exports.RESET_STATE = 'RESET_STATE' 10 | exports.ROUTE_POP = 'ROUTE_POP' 11 | 12 | //DB Acctions 13 | exports.REQUEST_DB_DATA = 'REQUEST_DB_DATA' 14 | exports.RECEIVE_DB_DATA = 'RECEIVE_DB_DATA' 15 | exports.DB_FAV_ADDED = 'DB_FAV_ADDED' 16 | exports.DB_UNFAV = 'DB_UNFAV' 17 | exports.DB_FAV_REMOVED = 'DB_FAV_REMOVED' 18 | exports.DB_UPDATED = 'DB_UPDATED' 19 | 20 | //Download Actions 21 | exports.REQUEST_DOWNLOAD_LIST = 'REQUEST_DOWNLOAD_LIST' 22 | exports.RECEIVE_DOWNLOAD_LIST = 'RECEIVE_DOWNLOAD_LIST' 23 | exports.REQUEST_DOWNLOAD_ITEM = 'REQUEST_DOWNLOAD_ITEM' 24 | exports.RECEIVE_DOWNLOAD_ITEM = 'RECEIVE_DOWNLOAD_ITEM' 25 | exports.UPDATE_DOWNLOAD_ITEM = 'UPDATE_DOWNLOAD_ITEM' 26 | exports.DELETE_DOWNLOAD_ITEM = 'DELETE_DOWNLOAD_ITEM' 27 | 28 | //Login 29 | exports.REQUEST_ACCOUNT_DATA = 'REQUEST_ACCOUNT_DATA' 30 | exports.RECEIVE_LOGIN = 'RECEIVE_LOGIN' 31 | exports.RECEIVE_ACCOUNT_DATA = 'RECEIVE_ACCOUNT_DATA' 32 | 33 | exports.ACK_NOTIFICATION = 'ACK_NOTIFICATION' 34 | -------------------------------------------------------------------------------- /app/actions/addressActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./actionTypes'); 2 | 3 | function requestPosts(url) { 4 | return { 5 | type: types.REQUEST_ADDRESS, 6 | url 7 | }; 8 | } 9 | 10 | function receivePosts(results) { 11 | return { 12 | type: types.RECEIVE_ADDRESS, 13 | addresses: results 14 | }; 15 | } 16 | 17 | function receiveEmpty() { 18 | return { 19 | type: types.RECEIVE_EMPTY 20 | }; 21 | } 22 | 23 | 24 | export function changeSearchText(searchString){ 25 | return{ 26 | type: types.CHANGE_SEARCH_TEXT, 27 | searchString: searchString 28 | } 29 | } 30 | 31 | function reset(){ 32 | return{ 33 | type: types.RESET_STATE 34 | } 35 | } 36 | 37 | function getDetials(routerAction){ 38 | return{ 39 | type: types.ROW_PRESS, 40 | routerAction: routerAction 41 | } 42 | 43 | } 44 | 45 | function routePop(fnPop, num){ 46 | return{ 47 | type: types.ROUTE_POP, 48 | num : num, 49 | fnPop : fnPop 50 | } 51 | } 52 | 53 | module.exports.resetState = function(){ 54 | return dispatch=>{ 55 | dispatch(reset()) 56 | 57 | } 58 | } 59 | 60 | module.exports.rowPress = function(routerAction){ 61 | return dispatch=>{ 62 | dispatch(getDetials(routerAction)) 63 | // routerAction() 64 | } 65 | } 66 | 67 | module.exports.onRoutePop = function(fnPop, num){ 68 | return dispatch=>{ 69 | dispatch(routePop(fnPop, num)) 70 | } 71 | } 72 | 73 | module.exports.checkAllFav = function(addresses, database, dispatch) { 74 | newAddresses = []; 75 | var promises = []; 76 | for(i in addresses) { 77 | var address = addresses[i].formatted_address; 78 | promises.push(checkFav(database, address, i, addresses, newAddresses)); 79 | } 80 | 81 | Promise.all(promises).then(() => { 82 | // // console.log("CHECKED FAVS: " + newAddresses); 83 | dispatch(receivePosts(newAddresses)); 84 | }); 85 | } 86 | 87 | function checkFav(database, address, index, addresses, newAddresses) { 88 | return new Promise((resolve, reject) => { 89 | database.isFav(address) 90 | .then((results) => { 91 | if(results[0].rows.length > 0) { 92 | newAddresses.push(Object.assign({}, addresses[index], {isFav: true})); 93 | } else { 94 | newAddresses.push(Object.assign({}, addresses[index], {isFav: false})); 95 | } 96 | resolve(); 97 | }) 98 | .catch((error) => { 99 | console.error("Action - FETCH ERROR " + error); 100 | reject(); 101 | }) 102 | }); 103 | } 104 | 105 | module.exports.fetchAddresses = function(searchString, database){ 106 | var url = "https://maps.googleapis.com/maps/api/geocode/json?address=" + encodeURIComponent(searchString); 107 | return dispatch=>{ 108 | dispatch(requestPosts(url)) 109 | 110 | var jsonData; 111 | return fetch(url) 112 | .then(response => 113 | response.json() 114 | ) 115 | .then((json) => { 116 | if(json.status == "OK"){ 117 | module.exports.checkAllFav(json.results, database, dispatch); 118 | } else { 119 | dispatch(receiveEmpty()); 120 | } 121 | }) 122 | .catch((error) => { 123 | // // console.log("Action - FETCH ERROR " + error); 124 | }) 125 | }; 126 | } 127 | -------------------------------------------------------------------------------- /app/actions/databaseActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./actionTypes'); 2 | var addressActions = require('./addressActions'); 3 | 4 | 5 | function requestFavDB() { 6 | return { 7 | type: types.REQUEST_DB_DATA 8 | }; 9 | } 10 | 11 | function receiveFavDB(results) { 12 | return { 13 | type: types.RECEIVE_DB_DATA, 14 | results 15 | }; 16 | } 17 | 18 | function insertFavDB(index, id) { 19 | return { 20 | type: types.DB_FAV_ADDED, 21 | index, 22 | id 23 | }; 24 | } 25 | 26 | function unFav(index, address) { 27 | return { 28 | type: types.DB_UNFAV, 29 | index, 30 | address 31 | }; 32 | } 33 | 34 | function removeFav(index) { 35 | return { 36 | type: types.DB_FAV_REMOVED, 37 | index 38 | }; 39 | } 40 | 41 | function dbUpdated(results) { 42 | return { 43 | type: types.DB_UPDATED, 44 | } 45 | } 46 | 47 | module.exports.insertFavourites = function(db, address, index){ 48 | return dispatch=>{ 49 | return db.insertAddress(address).then((id) => { 50 | dispatch(insertFavDB(index, id)); 51 | }) 52 | .catch((error) => { 53 | // // console.log("Action - DB ERROR " + error); 54 | }) 55 | }; 56 | } 57 | 58 | /** 59 | Called by AddressList - needs to remove favourite and update 'addresses' array 60 | */ 61 | module.exports.unFavourite = function(db, address, index){ 62 | return dispatch=>{ 63 | return db.removeFavourite(address).then(() => { 64 | dispatch(unFav(index, address)); 65 | }) 66 | .then(() => { 67 | //re-fetch favourites? 68 | }) 69 | .catch((error) => { 70 | // // console.log("Action - DB ERROR " + error); 71 | }) 72 | }; 73 | } 74 | 75 | 76 | 77 | 78 | /** 79 | Called from Favourites - needs to remove from DB and 'favourites' array 80 | */ 81 | module.exports.removeFavourite = function(db, id, index, searchAddresses){ 82 | 83 | // // console.log("REMOVING FAVS"); 84 | return dispatch=>{ 85 | 86 | return db.removeAddress(id) 87 | .then((tx, result) => { 88 | dispatch(removeFav(index)); 89 | if(searchAddresses) { 90 | addressActions.checkAllFav(searchAddresses, db, dispatch); 91 | } 92 | }) 93 | .catch((error) => { 94 | // // console.log("Action - DB REMOVE ERROR " + error); 95 | }) 96 | }; 97 | } 98 | 99 | 100 | 101 | 102 | module.exports.fetchFavourites = function(db){ 103 | 104 | // // console.log("FETCHING FAVS"); 105 | return dispatch=>{ 106 | dispatch(requestFavDB()) 107 | 108 | return db.getFavourites().then((favourites) => { 109 | dispatch(receiveFavDB(favourites)); 110 | }) 111 | .catch((error) => { 112 | // // console.log("Action - DB ERROR " + error); 113 | }) 114 | }; 115 | } 116 | -------------------------------------------------------------------------------- /app/actions/downloadActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./actionTypes'); 2 | var RNFS = require('react-native-fs'); 3 | var path = require('path'); 4 | /* 5 | PushNotification.configure({ 6 | onRegister: function(token) { 7 | // console.log("REGISTER: " + token); 8 | }, 9 | getNotifications: function(notification) { 10 | // console.log("NOTIFICATION: " + notification); 11 | }, 12 | permissions: { 13 | alert: true 14 | }, 15 | requestPermissions: true 16 | }); 17 | */ 18 | import Database from '../database/database'; 19 | 20 | 21 | function requestDownloadList() { 22 | return { 23 | type: types.REQUEST_DOWNLOAD_LIST 24 | }; 25 | } 26 | 27 | 28 | function receiveDownloadList(downloads) { 29 | return { 30 | type: types.RECEIVE_DOWNLOAD_LIST, 31 | downloads 32 | }; 33 | } 34 | 35 | function requestDownloadItem(idx) { 36 | return { 37 | type: types.REQUEST_DOWNLOAD_ITEM, 38 | idx 39 | }; 40 | } 41 | 42 | 43 | 44 | 45 | function updateDownloadItem(idx, status, displayname = null, jobId = null) { 46 | return { 47 | type: types.UPDATE_DOWNLOAD_ITEM, 48 | idx, 49 | status, 50 | displayname, 51 | jobId 52 | }; 53 | } 54 | 55 | 56 | function deleteDownloadItem(idx, status) { 57 | return { 58 | type: types.DELETE_DOWNLOAD_ITEM, 59 | idx 60 | }; 61 | } 62 | 63 | 64 | module.exports.resetDownload = function(id, idx, jobId) { 65 | return dispatch => { 66 | if(jobId) { 67 | RNFS.stopDownload(jobId); 68 | } 69 | Database.updateDownloadStatus(id, 0).then( 70 | dispatch(updateDownloadItem(idx, 0)) 71 | ); 72 | } 73 | } 74 | 75 | 76 | module.exports.removeDownload = function(id, idx) { 77 | return dispatch => { 78 | Database.removeDownload(id).then(dispatch(deleteDownloadItem(idx))); 79 | } 80 | } 81 | 82 | 83 | 84 | 85 | 86 | module.exports.downloadItem = function(item, idx) { 87 | var parentDir = path.dirname(item.filepath); 88 | 89 | return dispatch=>{ 90 | //dispatch(requestDownloadItem); 91 | dispatch(updateDownloadItem(idx, 1)); 92 | RNFS.mkdir(parentDir).then(() => { 93 | RNFS.downloadFile(item.url, item.filepath, function(info){ 94 | Database.startDownload(item.id, info.jobId); 95 | dispatch(updateDownloadItem(idx, 2, null, info.jobId)); 96 | } 97 | ) 98 | .then((result) => { 99 | Database.downloadComplete(item.id, true); 100 | /* PushNotification.localNotification({ 101 | message: "Background download complete: " + path.basename(item.filepath), 102 | }); 103 | PushNotification.localNotificationSchedule({ 104 | message: "download complete", 105 | date: new Date() 106 | });*/ 107 | dispatch(updateDownloadItem(idx, 3, item.displayname)); 108 | 109 | //module.exports.fetchDownloads(); 110 | }); 111 | }) 112 | .catch((error) => { 113 | console.error(error); 114 | }); 115 | } 116 | } 117 | 118 | /** 119 | Fetch download records from DB 120 | **/ 121 | module.exports.fetchDownloads = function() { 122 | 123 | // console.log("GETTING FILES"); 124 | return dispatch=>{ 125 | dispatch(requestDownloadList()) 126 | Database.loadDB() 127 | .then(Database.getDownloads() 128 | .then((files) => { 129 | // console.log("GOT FILES"); 130 | // console.log(files); 131 | dispatch(receiveDownloadList(files)); 132 | })) 133 | .catch((error) => { 134 | // console.log("Fetch Download - DB ERROR: " + error); 135 | }) 136 | }; 137 | } 138 | 139 | /** 140 | Note Currently used - an example of printing directory listing 141 | **/ 142 | module.exports.fetchDownloadFiles = function(){ 143 | 144 | // console.log("GETTING FILES"); 145 | return dispatch=>{ 146 | dispatch(requestDownloadList()) 147 | 148 | return RNFS.readDir(dlPath).then((files) => { 149 | allFiles = files.map(file => file.name + ' (' + Math.round(file.size / 1024 / 1024, 2) + 'Mb) '); 150 | // console.log("GOT FILES"); 151 | // console.log(allFiles); 152 | dispatch(receiveDownloadList(allFiles)); 153 | }) 154 | .catch((error) => { 155 | // // console.log("Action - DB ERROR " + error); 156 | }) 157 | }; 158 | } 159 | -------------------------------------------------------------------------------- /app/actions/routerActions.js: -------------------------------------------------------------------------------- 1 | var actions = exports = module.exports 2 | 3 | exports.ON_PUSH = "ON_PUSH"; 4 | exports.ON_POP = "ON_POP"; 5 | exports.ON_REPLACE = "ON_REPLACE"; 6 | 7 | exports.onPush = function onPush(route){ 8 | // // console.log("PUSH ACTION"); 9 | return { 10 | type: actions.ON_PUSH, 11 | route: route 12 | } 13 | } 14 | 15 | 16 | exports.onPop = function onPop(){ 17 | // // console.log("POP ACTION"); 18 | return { 19 | type: actions.ON_POP 20 | } 21 | } 22 | 23 | 24 | 25 | 26 | exports.onReplace = function onPop(route){ 27 | // // console.log("REPLACE ACTION"); 28 | return { 29 | type: actions.ON_REPLACE, 30 | route: route 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/components/Banner.js: -------------------------------------------------------------------------------- 1 | // import React from 'react-native'; 2 | var React = require('react-native') 3 | const { 4 | View, 5 | TouchableWithoutFeedback, 6 | Text, 7 | StyleSheet 8 | } = React; 9 | 10 | const styles = StyleSheet.create({ 11 | container: { 12 | backgroundColor: '#4b91df', 13 | padding: 20 14 | } 15 | }); 16 | 17 | class Banner extends View { 18 | static get defaultProps() { 19 | return { 20 | title: 'MyBanner' 21 | }; 22 | } 23 | 24 | static get propTypes() { 25 | return { 26 | title: React.PropTypes.string 27 | }; 28 | } 29 | 30 | constructor(props) { 31 | super(props); 32 | 33 | this.state = { 34 | clicks: 0 35 | }; 36 | } 37 | 38 | onClick() { 39 | this.setState({ 40 | clicks: this.state.clicks + 1 41 | }); 42 | } 43 | 44 | render() { 45 | const title = this.props.title; 46 | const clicks = this.state.clicks; 47 | 48 | return ( 49 | this.onClick(e)} style={styles.container}> 50 | 51 | {title} 52 | Clicks: {clicks} 53 | 54 | 55 | ); 56 | } 57 | } 58 | module.exports = Banner 59 | -------------------------------------------------------------------------------- /app/components/TabBarItem.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react-native' 4 | const { 5 | View, 6 | Image, 7 | Text, 8 | Component, 9 | StyleSheet, 10 | Platform 11 | } = React; 12 | var IonIcon = require('react-native-vector-icons/Ionicons'); 13 | 14 | 15 | const styles = StyleSheet.create({ 16 | tabContainerStyle: { 17 | alignItems: 'center', 18 | justifyContent: 'center', 19 | height: 50, 20 | }, 21 | }); 22 | 23 | const getTabImageStyle = props => ({ 24 | color: props.selected ? '#ff9900' : "#929292", 25 | height: 25, 26 | width: 30, 27 | marginLeft: 3 28 | }); 29 | 30 | const getTabTextStyle = props => ({ 31 | color: props.selected ? '#ff9900' : '#929292', 32 | fontSize: (Platform.OS ==='ios') ? 10 : 14, 33 | letterSpacing: 0.2, 34 | marginBottom: 2, 35 | marginTop: 5 36 | }); 37 | 38 | 39 | export default class TabBarItem extends Component { 40 | render() { 41 | const { tabBarItem } = this.props; 42 | var icon; 43 | var selected = this.props.selected; 44 | let title = tabBarItem.title; 45 | if (selected){ 46 | switch (title) { 47 | case "Geo Encoding": 48 | icon = ; 49 | break; 50 | case "Favourites": 51 | icon = ; 52 | break; 53 | case "Video": 54 | icon = ; 55 | break; 56 | case "Download": 57 | icon = ; 58 | break; 59 | case "More": 60 | icon = ; 61 | break; 62 | /* 63 | case "Camera": 64 | icon = ; 65 | break; 66 | */ 67 | 68 | } 69 | } else { 70 | switch (title) { 71 | case "Geo Encoding": 72 | icon = ; 73 | break; 74 | case "Favourites": 75 | icon = ; 76 | break; 77 | case "Video": 78 | icon = ; 79 | break; 80 | case "Download": 81 | icon = ; 82 | break; 83 | case "More": 84 | icon = ; 85 | break; 86 | /* 87 | case "Camera": 88 | icon = ; 89 | break; 90 | */ 91 | } 92 | } 93 | 94 | return ( 95 | 96 | {icon} 97 | {Platform.OS === 'ios' && tabBarItem.title && 98 | {tabBarItem.title} 99 | } 100 | 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/components/__tests__/addressList.spec.js: -------------------------------------------------------------------------------- 1 | const React = require('react-native'); 2 | const utils = require('react-addons-test-utils'); 3 | 4 | // use dontMock+require syntax to fix coverage disappearing bug 5 | jest.dontMock('../addressList'); 6 | var AddressList = require('../addressList'); 7 | // require.requireActual works fine for tests, however it makes test coverage disappearing currently 8 | // const AddressList = require.requireActual('../../app/components/addressList'); 9 | 10 | // const shallowHelpers = require('react-shallow-renderer-helpers'); 11 | // const shallowRenderer = shallowHelpers.createRenderer(); 12 | 13 | describe('AddressList', function() { 14 | 15 | function renderAddressList(props) { 16 | const renderer = utils.createRenderer(); 17 | renderer.render(); 18 | return renderer.getRenderOutput(); 19 | } 20 | 21 | beforeEach(() => { 22 | 23 | }); 24 | 25 | it('should render correct TextInput placeholder', () => { 26 | const props = { 27 | }; 28 | const output = renderAddressList(props); 29 | expect(output.props.children[1].props.children.props.placeholder).toEqual('Search location'); 30 | }); 31 | 32 | it('should not render wrong TextInput placeholder', () => { 33 | const props = { 34 | }; 35 | const output = renderAddressList(props); 36 | expect(output.props.children[1].props.children.props.placeholder).toNotEqual(''); 37 | }); 38 | 39 | it('should render searchString property', () => { 40 | const props = { 41 | searchString: "melbourne" 42 | }; 43 | const output = renderAddressList(props); 44 | expect(output.props.children[1].props.children.props.value).toEqual(props.searchString); 45 | }); 46 | 47 | // it('should render TextInput placeholder', () => { 48 | // shallowRenderer.render(() => ); 49 | // let output = shallowRenderer.getRenderOutput(); 50 | // expect("Search location").toBe(output.props.children[1].props.children.props.placeholder); 51 | // }); 52 | // 53 | // it('should render searchString property', () => { 54 | // shallowRenderer.render(() => ); 55 | // let output = shallowRenderer.getRenderOutput(); 56 | // expect("melbourne").toBe(output.props.children[1].props.children.props.value); 57 | // }); 58 | 59 | }); 60 | -------------------------------------------------------------------------------- /app/components/addressDetails.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react-native'); 4 | 5 | var MapView = require('react-native-maps'); 6 | 7 | var { 8 | StyleSheet, 9 | Image, 10 | View, 11 | Text, 12 | Component, 13 | TouchableHighlight, 14 | PropTypes, 15 | LinkingIOS, 16 | Platform, 17 | ScrollView 18 | } = React 19 | 20 | /* 21 | const LATITUDE = 37.78825; 22 | const LONGITUDE = -122.4324; 23 | const LATITUDE_DELTA = 0.0922; 24 | const LONGITUDE_DELTA = LATITUDE_DELTA * 1; 25 | const SPACE = 0.01; 26 | */ 27 | 28 | class AddressDetails extends Component { 29 | 30 | constructor(props) { 31 | super(props); 32 | 33 | this.state = {appleMaps: false, googleMaps: false}; 34 | 35 | // Early binding 36 | this.onApplePressed = this.onApplePressed.bind(this) 37 | this.onGooglePressed = this.onGooglePressed.bind(this) 38 | this.componentWillMount = this.componentWillMount.bind(this) 39 | } 40 | 41 | componentWillMount() { 42 | if(Platform.OS ==='ios') { 43 | let apple = 'http://maps.apple.com/?q=Lynx+office'; 44 | let google = 'comgooglemaps://?daddr=Lynx+office'; 45 | LinkingIOS.canOpenURL(apple, (supported) => { 46 | if(supported){ 47 | this.setState({appleMaps: true}); 48 | } else { 49 | this.setState({appleMaps: false}); 50 | } 51 | }); 52 | 53 | LinkingIOS.canOpenURL(google, (supported) => { 54 | if(supported){ 55 | this.setState({googleMaps: true}); 56 | } else { 57 | this.setState({googleMaps: false}); 58 | } 59 | }); 60 | } 61 | } 62 | 63 | onApplePressed(){ 64 | var url = 'http://maps.apple.com/?daddr=' + this.props.data.geometry.location.lat + ',' + this.props.data.geometry.location.lng + '&dirflg=d'; 65 | LinkingIOS.openURL(url); 66 | } 67 | 68 | onGooglePressed(){ 69 | var url = 'comgooglemaps://?daddr=' + this.props.data.geometry.location.lat + ',' + this.props.data.geometry.location.lng; 70 | LinkingIOS.openURL(url); 71 | } 72 | 73 | render(){ 74 | 75 | const rowData = this.props.data; 76 | const { lat, lng } = rowData.geometry.location; 77 | 78 | var title = rowData.formatted_address; 79 | var latLong = 'Lat : ' + lat + '\nLong :' + lng; 80 | // var latLong = 'Lat - xxx : Long - xxx '; 81 | 82 | var region = { 83 | latitude: lat, 84 | longitude: lng, 85 | latitudeDelta: 0.01, 86 | longitudeDelta: 0.01 87 | }; 88 | 89 | var latlng = { 90 | latitude: lat, 91 | longitude: lng, 92 | }; 93 | 94 | var appleButton = this.state.appleMaps ? 95 | ( 98 | Apple 99 | ): 100 | ( ); 101 | 102 | var googleButton = this.state.googleMaps ? 103 | ( 106 | Google 107 | ): 108 | ( ); 109 | 110 | return ( 111 | 112 | 113 | {title} 114 | 115 | 116 | {latLong} 117 | 118 | 123 | 126 | 127 | 128 | 129 | {appleButton} 130 | {googleButton} 131 | 132 | 133 | 134 | ); 135 | 136 | } 137 | } 138 | 139 | AddressDetails.propTypes = { 140 | data : PropTypes.object, 141 | routes : PropTypes.objectOf(PropTypes.func) 142 | } 143 | 144 | var styles = StyleSheet.create({ 145 | container: { 146 | flex:1, 147 | marginTop: (Platform.OS ==='ios') ? 80 : 120, 148 | marginBottom: (Platform.OS ==='ios') ? 55 : 0 149 | }, 150 | heading: { 151 | }, 152 | separator: { 153 | height: 1, 154 | backgroundColor: '#DDDDDD' 155 | }, 156 | title: { 157 | fontSize: 20, 158 | marginLeft: 10, 159 | marginRight: 10, 160 | color: '#656565' 161 | }, 162 | buttonContainer: { 163 | flexDirection: 'row', 164 | marginBottom: 10 165 | }, 166 | description: { 167 | fontSize: 16, 168 | marginLeft: 10, 169 | marginRight: 10, 170 | marginBottom: 10, 171 | color: '#656565' 172 | }, 173 | map: { 174 | height: 300, 175 | marginRight: 10, 176 | marginLeft: 10, 177 | marginBottom: 10, 178 | borderWidth: 1, 179 | borderColor: '#000000', 180 | }, 181 | buttonText: { 182 | fontSize: 18, 183 | color: 'white', 184 | alignSelf: 'center' 185 | }, 186 | button: { 187 | height: 36, 188 | flexDirection: 'row', 189 | flex: 1, 190 | backgroundColor: '#ff9900', 191 | borderRadius: 8, 192 | marginLeft: 10, 193 | marginRight: 10, 194 | alignSelf: 'stretch', 195 | justifyContent: 'center' 196 | } 197 | }); 198 | 199 | 200 | module.exports = AddressDetails 201 | -------------------------------------------------------------------------------- /app/components/cameraPage.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | 'use strict'; 4 | import React, { 5 | AppRegistry, 6 | Component, 7 | Dimensions, 8 | StyleSheet, 9 | Text, 10 | TouchableHighlight, 11 | View 12 | } from 'react-native'; 13 | import Camera from 'react-native-camera'; 14 | 15 | class BadInstagramCloneApp extends Component { 16 | render() { 17 | return ( 18 | 19 | { 21 | this.camera = cam; 22 | }} 23 | style={styles.preview} 24 | aspect={Camera.constants.Aspect.Fill}> 25 | [CAPTURE] 26 | 27 | 28 | ); 29 | } 30 | 31 | takePicture() { 32 | this.camera.capture() 33 | .then((data) => console.log(data)) 34 | .catch(err => console.error(err)); 35 | } 36 | } 37 | 38 | const styles = StyleSheet.create({ 39 | container: { 40 | flex: 1 41 | }, 42 | preview: { 43 | flex: 1, 44 | justifyContent: 'flex-end', 45 | alignItems: 'center', 46 | height: Dimensions.get('window').height, 47 | width: Dimensions.get('window').width 48 | }, 49 | capture: { 50 | flex: 0, 51 | backgroundColor: '#fff', 52 | borderRadius: 5, 53 | color: '#000', 54 | padding: 10, 55 | margin: 40 56 | } 57 | }); 58 | 59 | module.exports = CameraPage; 60 | */ 61 | -------------------------------------------------------------------------------- /app/components/customScrollView.js: -------------------------------------------------------------------------------- 1 | import React, { ScrollView } from 'react-native'; 2 | var { Animated, Component } = React; 3 | 4 | var AnimatedScrollView = Animated.createAnimatedComponent(ScrollView); 5 | 6 | // var _ = require('lodash'); 7 | 8 | export default class CustomScrollView extends Component { 9 | constructor(props) { 10 | super(props); 11 | this.state = { 12 | fadeAnim: new Animated.Value(1) 13 | }; 14 | } 15 | 16 | /* 17 | componentDidMount() { 18 | this.debouncedFade = _.debounce(this.fadeOut, 50); 19 | } */ 20 | 21 | fadeOut() { 22 | Animated.timing( 23 | this.state.fadeAnim, 24 | {toValue: 0, 25 | duration: 500,}, 26 | ).start(); 27 | } 28 | 29 | componentWillUpdate() { 30 | // this.fadeOut(); 31 | } 32 | 33 | render() { 34 | return ( 35 | 37 | {this.props.children} 38 | 39 | ); 40 | } 41 | } 42 | 43 | module.exports = CustomScrollView; 44 | -------------------------------------------------------------------------------- /app/components/downloadList.js: -------------------------------------------------------------------------------- 1 | var downloads = [ {title: "Sample 480", url: "https://www.dropbox.com/s/gzf7bel1a1nyyof/Sample480.mov?dl=0"} ]; 2 | 3 | import React, { 4 | StyleSheet, 5 | Component, 6 | View, 7 | Text, 8 | TextInput, 9 | TouchableHighlight, 10 | ListView, 11 | ScrollView, 12 | PropTypes, 13 | Image, 14 | Button, 15 | Platform 16 | } from 'react-native'; 17 | 18 | var RNFS = require('react-native-fs'); 19 | var SGListView = require('react-native-sglistview'); 20 | import Toast from './toast.ios'; 21 | import globals from '../store/globals'; 22 | var Icon = require('react-native-vector-icons/FontAwesome'); 23 | 24 | //const dlPath = RNFS.DocumentDirectoryPath + '/downloads/'; 25 | 26 | class DownloadList extends Component { 27 | 28 | constructor(props) { 29 | super(props); 30 | 31 | // Early binding 32 | this.renderDownload = this.renderDownload.bind(this) 33 | this.startDownload = this.startDownload.bind(this) 34 | this.viewDownload = this.viewDownload.bind(this) 35 | this.resetDownload = this.resetDownload.bind(this) 36 | this.deleteDownload = this.deleteDownload.bind(this) 37 | } 38 | 39 | componentDidMount() { 40 | this.props.actions.fetchDownloads(); 41 | } 42 | 43 | 44 | hideTopToast() { 45 | if(this.props.routerState[0] == 'launch'){ 46 | this.setState({isVisible: false}); 47 | } 48 | } 49 | 50 | 51 | startDownload(rowData, idx) { 52 | this.props.actions.downloadItem(rowData, idx); 53 | } 54 | 55 | viewDownload(filepath) { 56 | this.props.navActions.dlvideo({uri:filepath}); 57 | } 58 | 59 | resetDownload(rowData, idx) { 60 | this.props.actions.resetDownload(rowData.id, idx, rowData.jobId); 61 | } 62 | 63 | deleteDownload(id, idx) { 64 | this.props.actions.removeDownload(id, idx); 65 | } 66 | 67 | 68 | renderDownload(rowData, section, row) { 69 | var status; 70 | var style; 71 | var onClick; 72 | switch(rowData.status) { 73 | case(0): 74 | status = 'Tap to Download'; 75 | style= styles.new; 76 | onClick = this.startDownload.bind(this, rowData, row); 77 | break; 78 | case(1): 79 | status = 'Download Pending' 80 | style = styles.inProgress; 81 | onClick = this.resetDownload.bind(this, rowData, row); 82 | break; 83 | case(2): 84 | status = 'Download in progress (Tap to Cancel)' 85 | style = styles.inProgress; 86 | onClick = this.resetDownload.bind(this, rowData, row); 87 | break; 88 | case(3): 89 | status = 'Downloaded (Tap to View)' 90 | style = styles.complete; 91 | onClick = this.viewDownload.bind(this, rowData.filepath);; 92 | break; 93 | } 94 | 95 | return ( 96 | 97 | 98 | 99 | {rowData.displayname} 100 | 101 | 102 | 103 | 104 | 105 | 106 | {status} 107 | 108 | 109 | 110 | 111 | 112 | 113 | ); 114 | } 115 | 116 | render() { 117 | const { downloaded } = this.props; 118 | const url = "https://www.dropbox.com/s/gzf7bel1a1nyyof/Sample480.mov?dl=1"; 119 | return ( 120 | 121 | 122 | 127 | 128 | 129 | ) 130 | } 131 | } 132 | 133 | const styles = StyleSheet.create({ 134 | container: { 135 | marginTop:70, 136 | flexDirection:'column', 137 | marginTop: (Platform.OS ==='ios') ? 70 : 110 138 | }, 139 | listContainer: { 140 | flexDirection:'row', 141 | alignItems: 'center', 142 | alignSelf:'stretch', 143 | flex: 1 144 | }, 145 | separator:{ 146 | height:1, 147 | backgroundColor:'gray' 148 | }, 149 | addressWrap: { 150 | flex: 9 151 | }, 152 | rowAddress:{ 153 | padding: 5, 154 | flexDirection: 'row', 155 | alignItems: 'center', 156 | justifyContent: 'space-between', 157 | }, 158 | url: { 159 | fontSize: 14, 160 | }, 161 | new: { 162 | color: '#000' 163 | }, 164 | inProgress: { 165 | color: '#AA4' 166 | }, 167 | complete: { 168 | color: '#090' 169 | }, 170 | imgButton: { 171 | alignSelf: 'center', 172 | width: 20, 173 | height: 20, 174 | flex: 1 175 | } 176 | }); 177 | module.exports = DownloadList; 178 | -------------------------------------------------------------------------------- /app/components/favourites.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | Component, 4 | View, 5 | Text, 6 | TextInput, 7 | TouchableHighlight, 8 | ListView, 9 | ScrollView, 10 | PropTypes, 11 | Image, 12 | Button, 13 | Platform, 14 | ToastAndroid 15 | } from 'react-native'; 16 | var Icon = require('react-native-vector-icons/FontAwesome'); 17 | var SGListView = require('react-native-sglistview'); 18 | import Toast from './toast.ios'; 19 | 20 | import Database from '../database/database'; 21 | 22 | import globals from '../store/globals'; 23 | 24 | class Favourites extends Component { 25 | 26 | constructor(props) { 27 | super(props); 28 | this.favDataSource = new ListView.DataSource( { 29 | rowHasChanged: (row1, row2) => row1 !== row2 30 | }); 31 | 32 | this.state = {toastText: '',isVisible: false}; 33 | 34 | // Early binding 35 | this.renderFav = this.renderFav.bind(this) 36 | this.hideToast = this.hideToast.bind(this) 37 | } 38 | 39 | componentDidMount() { 40 | Database.loadDB().then((db) => { 41 | //this.loadFavourites(); 42 | // // console.log(Database); 43 | this.props.actions.fetchFavourites(Database); 44 | }); 45 | } 46 | 47 | loadFavourites() { 48 | var favs = Database.getFavourites(); 49 | this.favDataSource.cloneWithRows(favs); 50 | } 51 | 52 | onRemovePressed(addressID, i) { 53 | let message = "Removed"; 54 | if(Platform.OS ==='ios') { 55 | this.setState({toastText: message}); 56 | this.setState({isVisible: true}); 57 | setTimeout(this.hideToast, 800); 58 | } 59 | else { 60 | ToastAndroid.show(message, ToastAndroid.SHORT); 61 | } 62 | this.props.actions.removeFavourite(Database, addressID, i, this.props.addresses._dataBlob.s1); 63 | } 64 | 65 | hideToast() { 66 | if(this.props.routerState[0] == 'favourites'){ 67 | this.setState({isVisible: false}); 68 | } 69 | } 70 | 71 | renderFav(rowData, i, j) { 72 | return( 73 | 74 | 75 | 76 | {this.state.toastText} 77 | 78 | 79 | 80 | 81 | 82 | {rowData.address} 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | ); 92 | } 93 | 94 | 95 | render() { 96 | const { favourites } = this.props; 97 | return ( 98 | 99 | 100 | 104 | 105 | 106 | ); 107 | } 108 | } 109 | 110 | const styles = StyleSheet.create({ 111 | container: { 112 | flex: 1, 113 | marginTop: 70, 114 | marginBottom: (Platform.OS ==='ios') ? 55 : 0, 115 | marginTop: (Platform.OS ==='ios') ? 80 : 100 116 | }, 117 | listContainer: { 118 | flexDirection:'row', 119 | alignItems: 'center', 120 | alignSelf:'stretch', 121 | }, 122 | separator:{ 123 | height:1, 124 | backgroundColor:'gray' 125 | }, 126 | addressWrap: { 127 | flex: 9 128 | }, 129 | rowAddress:{ 130 | padding: 5, 131 | flexDirection: 'row', 132 | alignItems: 'center', 133 | justifyContent: 'space-between', 134 | marginTop: 5, 135 | marginBottom: 5, 136 | }, 137 | address: { 138 | fontSize: 14, 139 | }, 140 | button: { 141 | alignSelf: 'center', 142 | width: 20, 143 | height: 20, 144 | flex: 1 145 | }, 146 | }); 147 | module.exports = Favourites 148 | -------------------------------------------------------------------------------- /app/components/featureList.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | StyleSheet, 5 | Component, 6 | Platform, 7 | View, 8 | Text 9 | } from 'react-native'; 10 | 11 | 12 | var isTab = true; 13 | 14 | class FeatureList extends Component { 15 | constructor(props) { 16 | super(props); 17 | } 18 | 19 | render() { 20 | 21 | return ( 22 | 23 | 24 | { this.props.navActions.loginpage() } }> 26 | Account 27 | 28 | 29 | 30 | { this.props.navActions.picker() } }> 32 | Camera / Image Picker 33 | 34 | 35 | 36 | ) 37 | } 38 | } 39 | 40 | const styles = StyleSheet.create({ 41 | container: { 42 | flex: 1, 43 | marginTop: (Platform.OS ==='ios') ? 50 : 50, 44 | flexDirection:'column', 45 | alignItems:'center', 46 | justifyContent:'center' 47 | }, 48 | button:{ 49 | padding :5, 50 | height: 36, 51 | backgroundColor:'#F90', 52 | alignSelf:'stretch', 53 | justifyContent:'center', 54 | borderRadius: 8, 55 | margin: 10 56 | }, 57 | buttonText:{ 58 | fontSize:18, 59 | color:'white' 60 | }, 61 | }); 62 | 63 | module.exports = FeatureList 64 | -------------------------------------------------------------------------------- /app/components/imagePickerPage.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | Component, 4 | View, 5 | Text, 6 | TextInput, 7 | TouchableHighlight, 8 | PropTypes, 9 | Image, 10 | Platform 11 | } from 'react-native'; 12 | 13 | var UIImagePickerManager = require('NativeModules').UIImagePickerManager; 14 | 15 | class ImagePicker extends Component { 16 | 17 | constructor(props) { 18 | super(props); 19 | 20 | this.state = {imgSource: {}}; 21 | this.onPickPressed = this.onPickPressed.bind(this); 22 | } 23 | 24 | 25 | onPickPressed(){ 26 | let options = { 27 | title: 'Select Image', // specify null or empty string to remove the title 28 | cancelButtonTitle: 'Cancel', 29 | takePhotoButtonTitle: 'Take Photo', // specify null or empty string to remove this button 30 | chooseFromLibraryButtonTitle: 'Choose from Library', // specify null or empty string to remove this button 31 | cameraType: 'back', // 'front' or 'back' 32 | mediaType: 'photo', // 'photo' or 'video' 33 | videoQuality: 'high', // 'low', 'medium', or 'high' 34 | aspectX: 1, // aspectX:aspectY, the cropping image's ratio of width to height 35 | aspectY: 1, // aspectX:aspectY, the cropping image's ratio of width to height 36 | quality: (Platform.OS == 'ios' ) ? 100 : 1, // photos only 37 | angle: 0, // photos only 38 | allowsEditing: false, // Built in functionality to resize/reposition the image 39 | noData: true, // photos only - disables the base64 `data` field from being generated (greatly improves performance on large photos) 40 | storageOptions: { // if this key is provided, the image will get saved in the documents/pictures directory (rather than a temporary directory) 41 | skipBackup: true, // image will NOT be backed up to icloud 42 | path: 'images' // will save image at /Documents/images rather than the root 43 | } 44 | }; 45 | 46 | UIImagePickerManager.showImagePicker(options, (response) => { 47 | console.log('Response = ', response); 48 | 49 | if (response.didCancel) { 50 | console.log('User cancelled image picker'); 51 | } 52 | else if (response.error) { 53 | console.log('UIImagePickerManager Error: ', response.error); 54 | } else { 55 | var source; 56 | if(Platform.OS === 'ios'){ 57 | source = {uri: response.uri.replace('file://', ''), isStatic: true}; 58 | } else { 59 | source = {uri: response.uri, isStatic: true}; 60 | } 61 | this.setState({ 62 | imgSource: source 63 | }); 64 | } 65 | }); 66 | } 67 | 68 | render() { 69 | return ( 70 | 71 | 72 | Select Image 73 | 74 | 75 | 76 | ); 77 | } 78 | } 79 | 80 | const styles = StyleSheet.create({ 81 | container: { 82 | flex: 1, 83 | marginBottom: (Platform.OS ==='ios') ? 55 : 0, 84 | marginTop: (Platform.OS ==='ios') ? 80 : 120 85 | }, 86 | buttonText: { 87 | fontSize: 18, 88 | color: 'white', 89 | alignSelf: 'center' 90 | }, 91 | button: { 92 | height: 36, 93 | flexDirection: 'row', 94 | backgroundColor: '#ff9900', 95 | borderRadius: 8, 96 | marginLeft: 10, 97 | marginRight: 10, 98 | alignSelf: 'stretch', 99 | justifyContent: 'center' 100 | }, 101 | image: { 102 | flex: 1, 103 | marginRight: 10, 104 | marginLeft: 10, 105 | marginBottom: 10, 106 | marginTop: 20, 107 | borderWidth: 1, 108 | borderColor: '#000000', 109 | }, 110 | }); 111 | module.exports = ImagePicker 112 | -------------------------------------------------------------------------------- /app/components/launch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react-native'); 4 | var {View, Text, StyleSheet, TouchableHighlight} = React; 5 | var Button = require('react-native-button'); 6 | 7 | class Launch extends React.Component { 8 | render(){ 9 | var Actions = this.props.routes; 10 | // // console.log("Launc : " + this.props) 11 | return ( 12 | 13 | Launch page 14 | 15 | ); 16 | } 17 | } 18 | 19 | var styles = StyleSheet.create({ 20 | container: { 21 | flex: 1, 22 | justifyContent: 'center', 23 | alignItems: 'center', 24 | backgroundColor: 'transparent', 25 | } 26 | }); 27 | 28 | module.exports = Launch; 29 | -------------------------------------------------------------------------------- /app/components/login.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | StyleSheet, 5 | Component, 6 | Text, 7 | Platform, 8 | View, 9 | TextInput, 10 | TouchableHighlight 11 | } from 'react-native'; 12 | var Button = require('react-native-button'); 13 | 14 | var login = ''; 15 | var password = ''; 16 | 17 | class LoginPage extends Component { 18 | 19 | constructor(props) { 20 | super(props); 21 | 22 | // Early binding 23 | this.onLoginPressed = this.onLoginPressed.bind(this) 24 | this.onSignUpPressed = this.onSignUpPressed.bind(this) 25 | // this.componentWillReceiveProps = this.componentWillReceiveProps.bind(this); 26 | // this.componentWillMount = this.componentWillMount.bind(this) 27 | } 28 | 29 | componentWillMount() { 30 | console.log("CHECKING LOGIN"); 31 | // if(this.props.state.user._id !== undefined) { 32 | // this.props.navActions.myAccount(); 33 | // } 34 | } 35 | 36 | onLoginPressed() { 37 | console.log(login); 38 | console.log(password); 39 | this.props.actions.doLogin({'login': login, 'password': password}); 40 | //this.props.navActions.account(); 41 | 42 | } 43 | 44 | onSignUpPressed() { 45 | this.props.navActions.signup(); 46 | } 47 | 48 | onLoginTextChanged(event) { 49 | login = event.nativeEvent.text; 50 | } 51 | 52 | onPasswordTextChanged(event) { 53 | password = event.nativeEvent.text; 54 | } 55 | 56 | 57 | componentWillReceiveProps(props) { 58 | if(props.user._id && props.routerState.length == 2) { 59 | props.navActions.account(); 60 | } 61 | } 62 | 63 | 64 | render(){ 65 | var Actions = this.props.routes; 66 | var account = this.props.accountState; 67 | 68 | return ( 69 | 70 | 71 | {account.error ? account.error : ''} 72 | 73 | 78 | 79 | 80 | 86 | 87 | 88 | 89 | 92 | Login 93 | 94 | 95 | 98 | Sign Up 99 | 100 | 101 | 102 | ); 103 | } 104 | } 105 | 106 | var styles = StyleSheet.create({ 107 | container: { 108 | flex: 1, 109 | marginTop: (Platform.OS ==='ios') ? 80 : 120, 110 | justifyContent: 'flex-start', 111 | alignItems: 'center', 112 | backgroundColor: 'transparent', 113 | }, 114 | inputContainer: { 115 | // marginTop:80, 116 | flexDirection:'row', 117 | alignItems: 'center', 118 | alignSelf:'stretch' 119 | }, 120 | error: { 121 | color: "red" 122 | }, 123 | textInput: { 124 | flex: 1, 125 | height: 36, 126 | padding: 4, 127 | margin : 10, 128 | fontSize: 18, 129 | color: 'gray', 130 | borderWidth: 1, 131 | borderColor: 'gray', 132 | borderRadius: 8, 133 | backgroundColor: '#fff5e6' 134 | }, 135 | buttonRow: { 136 | flexDirection: 'row', 137 | alignSelf: 'stretch', 138 | }, 139 | button: { 140 | flex: 1, 141 | height: 36, 142 | backgroundColor: '#ff9900', 143 | borderColor: '#F90', 144 | borderWidth: 1, 145 | borderRadius: 8, 146 | margin: 10, 147 | alignSelf: 'stretch', 148 | justifyContent: 'center' 149 | }, 150 | buttonOther: { 151 | flex: 1, 152 | height: 36, 153 | backgroundColor: '#FFF', 154 | borderColor: '#F90', 155 | borderWidth: 1, 156 | borderRadius: 8, 157 | margin: 10, 158 | alignSelf: 'stretch', 159 | justifyContent: 'center' 160 | }, 161 | buttonText: { 162 | fontSize: 18, 163 | color: 'white', 164 | alignSelf: 'center' 165 | }, 166 | buttonOtherText: { 167 | fontSize: 18, 168 | color: '#F90', 169 | alignSelf: 'center' 170 | }, 171 | }); 172 | 173 | 174 | module.exports = LoginPage 175 | -------------------------------------------------------------------------------- /app/components/myAccount.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | StyleSheet, 5 | Component, 6 | Text, 7 | Platform, 8 | View, 9 | TextInput, 10 | TouchableHighlight 11 | } from 'react-native'; 12 | var Button = require('react-native-button'); 13 | 14 | var fullname = ''; 15 | var email = ''; 16 | var dob = ''; 17 | 18 | class MyAccount extends Component { 19 | 20 | constructor(props) { 21 | super(props); 22 | 23 | // Early binding 24 | //this.onSavePressed = this.onSavePressed.bind(this) 25 | this.componentDidUpdate = this.componentDidUpdate.bind(this) 26 | } 27 | 28 | 29 | onSavePressed(user) { 30 | this.props.actions.updateAccount({'_id':user._id, 'login':user.login, 'password': user.password, 'fullname': fullname, 'email': email, 'dob': dob}); 31 | } 32 | 33 | 34 | onfullnameTextChanged(event) { 35 | fullname = event.nativeEvent.text; 36 | } 37 | 38 | onEmailTextChanged(event) { 39 | email = event.nativeEvent.text; 40 | } 41 | 42 | onDOBTextChanged(event) { 43 | dob = event.nativeEvent.text; 44 | } 45 | 46 | 47 | 48 | componentDidUpdate() { 49 | // if(!this.props.user._id && (this.props.routerState.length == 2)) { 50 | // this.props.navActions.pop(); 51 | // } 52 | } 53 | 54 | 55 | render(){ 56 | var account = this.props.user; 57 | var error = this.props.accountState.error; 58 | 59 | // // console.log("Launc : " + this.props) 60 | return ( 61 | 62 | {error ? error : ''} 63 | 64 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 87 | 88 | 89 | 90 | 93 | Save 94 | 95 | 96 | 97 | 98 | ); 99 | } 100 | } 101 | 102 | var styles = StyleSheet.create({ 103 | container: { 104 | flex: 1, 105 | marginTop: (Platform.OS ==='ios') ? 80 : 120, 106 | justifyContent: 'flex-start', 107 | alignItems: 'center', 108 | backgroundColor: 'transparent', 109 | }, 110 | inputContainer: { 111 | // marginTop:80, 112 | flexDirection:'row', 113 | alignItems: 'center', 114 | alignSelf:'stretch' 115 | }, 116 | error: { 117 | color: "red" 118 | }, 119 | textInput: { 120 | flex: 1, 121 | height: 36, 122 | padding: 4, 123 | margin : 10, 124 | fontSize: 18, 125 | color: 'gray', 126 | borderWidth: 1, 127 | borderColor: 'gray', 128 | borderRadius: 8, 129 | backgroundColor: '#fff5e6' 130 | }, 131 | buttonRow: { 132 | flexDirection: 'row', 133 | alignSelf: 'stretch', 134 | }, 135 | button: { 136 | flex: 1, 137 | height: 36, 138 | backgroundColor: '#ff9900', 139 | borderColor: '#F90', 140 | borderWidth: 1, 141 | borderRadius: 8, 142 | margin: 10, 143 | alignSelf: 'stretch', 144 | justifyContent: 'center' 145 | }, 146 | buttonOther: { 147 | flex: 1, 148 | height: 36, 149 | backgroundColor: '#FFF', 150 | borderColor: '#F90', 151 | borderWidth: 1, 152 | borderRadius: 8, 153 | margin: 10, 154 | alignSelf: 'stretch', 155 | justifyContent: 'center' 156 | }, 157 | buttonText: { 158 | fontSize: 18, 159 | color: 'white', 160 | alignSelf: 'center' 161 | }, 162 | buttonOtherText: { 163 | fontSize: 18, 164 | color: '#F90', 165 | alignSelf: 'center' 166 | }, 167 | }); 168 | 169 | 170 | module.exports = MyAccount 171 | -------------------------------------------------------------------------------- /app/components/signUp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | StyleSheet, 5 | Component, 6 | Text, 7 | Platform, 8 | View, 9 | TextInput, 10 | TouchableHighlight 11 | } from 'react-native'; 12 | var Button = require('react-native-button'); 13 | 14 | var login = 'oliver'; 15 | var password = 'test'; 16 | var pwConfirm = 'test'; 17 | var fullname = 'O J'; 18 | var email = 'oli@oli.com'; 19 | var dob = ''; 20 | 21 | class SignUp extends Component { 22 | 23 | constructor(props) { 24 | super(props); 25 | 26 | // Early binding 27 | this.onSignUpPressed = this.onSignUpPressed.bind(this) 28 | this.componentWillReceiveProps = this.componentWillReceiveProps.bind(this) 29 | } 30 | 31 | onSignUpPressed() { 32 | if(password == pwConfirm) { 33 | this.props.actions.signUp({'login':login, 'password':password, 'name': fullname, 'email': email, 'dob': dob}); 34 | this.props.navActions.account(); 35 | } 36 | } 37 | 38 | 39 | onfullnameTextChanged(event) { 40 | fullname = event.nativeEvent.text; 41 | } 42 | 43 | onEmailTextChanged(event) { 44 | email = event.nativeEvent.text; 45 | } 46 | 47 | onDOBTextChanged(event) { 48 | dob = event.nativeEvent.text; 49 | } 50 | 51 | componentWillReceiveProps() { 52 | // if(this.props.user._id !== undefined) { 53 | // this.props.navActions.account(); 54 | // } 55 | } 56 | 57 | render(){ 58 | var Actions = this.props.routes; 59 | var error = this.props.accountState.error; 60 | // // console.log("Launc : " + this.props) 61 | return ( 62 | 63 | {error ? error : ''} 64 | 65 | { login = event.nativeEvent.text }} 69 | placeholder="Login"/> 70 | 71 | 72 | { password = event.nativeEvent.text }} 77 | placeholder="password"/> 78 | 79 | 80 | { pwConfirm = event.nativeEvent.text }} 85 | placeholder="confirm password"/> 86 | 87 | 88 | 92 | 93 | 94 | 99 | 100 | 101 | 102 | 103 | 108 | 109 | 110 | 111 | 114 | Sign Up 115 | 116 | 117 | 118 | 119 | ); 120 | } 121 | } 122 | 123 | var styles = StyleSheet.create({ 124 | container: { 125 | flex: 1, 126 | marginTop: (Platform.OS ==='ios') ? 80 : 120, 127 | justifyContent: 'flex-start', 128 | alignItems: 'center', 129 | backgroundColor: 'transparent', 130 | }, 131 | inputContainer: { 132 | // marginTop:80, 133 | flexDirection:'row', 134 | alignItems: 'center', 135 | alignSelf:'stretch' 136 | }, 137 | error: { 138 | color: "red" 139 | }, 140 | textInput: { 141 | flex: 1, 142 | height: 36, 143 | padding: 4, 144 | margin : 10, 145 | fontSize: 18, 146 | color: 'gray', 147 | borderWidth: 1, 148 | borderColor: 'gray', 149 | borderRadius: 8, 150 | backgroundColor: '#fff5e6' 151 | }, 152 | buttonRow: { 153 | flexDirection: 'row', 154 | alignSelf: 'stretch', 155 | }, 156 | button: { 157 | flex: 1, 158 | height: 36, 159 | backgroundColor: '#ff9900', 160 | borderColor: '#F90', 161 | borderWidth: 1, 162 | borderRadius: 8, 163 | margin: 10, 164 | alignSelf: 'stretch', 165 | justifyContent: 'center' 166 | }, 167 | buttonOther: { 168 | flex: 1, 169 | height: 36, 170 | backgroundColor: '#FFF', 171 | borderColor: '#F90', 172 | borderWidth: 1, 173 | borderRadius: 8, 174 | margin: 10, 175 | alignSelf: 'stretch', 176 | justifyContent: 'center' 177 | }, 178 | buttonText: { 179 | fontSize: 18, 180 | color: 'white', 181 | alignSelf: 'center' 182 | }, 183 | buttonOtherText: { 184 | fontSize: 18, 185 | color: '#F90', 186 | alignSelf: 'center' 187 | }, 188 | }); 189 | 190 | 191 | module.exports = SignUp 192 | -------------------------------------------------------------------------------- /app/components/tabBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react-native' 2 | const {View, InteractionManager} = React; 3 | import Tabs from 'react-native-tabs'; 4 | 5 | import Actions from '../actions/actionTypes'; 6 | export default class TabBar extends React.Component { 7 | constructor(props){ 8 | 9 | // // console.log("SHOWING TAB BAR"); 10 | super(props); 11 | 12 | // Early binding 13 | this.onSelect = this.onSelect.bind(this) 14 | } 15 | onSelect(el){ 16 | if (!Actions[el.props.name]){ 17 | throw new Error("No action is defined for name="+el.props.name+" actions:"+JSON.stringify(Object.keys(Actions))); 18 | } 19 | if (el.props.selected && Actions[el.props.defaultRoute]) { 20 | Actions[el.props.defaultRoute](); 21 | } else { 22 | Actions[el.props.name](); 23 | } 24 | InteractionManager.runAfterInteractions(() => 25 | this.setState({hideTabBar: el.props.hideTabBar})); 26 | return {selected: true}; 27 | } 28 | getChildrenState(selectedRoute){ 29 | var self = this; 30 | let selected = false; 31 | var children = []; 32 | React.Children.forEach(this.props.children, function(el, index){ 33 | const schema = self.props.router && self.props.router.schemas[el.props.schema] ? self.props.router.schemas[el.props.schema] : {}; 34 | let props = {...schema, ...el.props}; 35 | if (!el.props.name) 36 | console.error("No name is defined for element"); 37 | if (selectedRoute){ 38 | if (selectedRoute == el.props.name){ 39 | props.selected = true; 40 | } else { 41 | props.selected = false; 42 | } 43 | } 44 | 45 | var Icon = props.icon || console.error("No icon class is defined for "+el.name); 46 | children.push(); 47 | if (props.selected || index === 0){ 48 | selected = el; 49 | } 50 | }); 51 | return {children, hideTabBar: selected.props.hideTabBar}; 52 | } 53 | componentWillMount(){ 54 | if (!this.props.children){ 55 | return; 56 | } 57 | this.state = this.getChildrenState(this.props.selected); 58 | 59 | } 60 | 61 | componentWillReceiveProps({selected}){ 62 | //// // console.log("TABBAR "+selected); 63 | InteractionManager.runAfterInteractions(() => 64 | this.setState(this.getChildrenState(selected))); 65 | } 66 | render(){ 67 | 68 | // // console.log("SHOWING TAB BAR"); 69 | return ( 70 | 71 | {this.state.children} 72 | 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/components/toast.ios.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | View, 3 | ActivityIndicatorIOS, 4 | StyleSheet, 5 | TouchableOpacity, 6 | Text, 7 | Component, 8 | Dimensions 9 | } from 'react-native'; 10 | var Overlay = require('react-native-overlay'); 11 | var BlurView = require('react-native-blur').BlurView; 12 | var Icon = require('react-native-vector-icons/FontAwesome'); 13 | 14 | class Toast extends Component { 15 | render() { 16 | var positionStyle; 17 | if(this.props.position == 'top' || !this.props.position){ 18 | positionStyle = styles.top; 19 | } else { 20 | positionStyle = styles.bottom; 21 | } 22 | 23 | var top = (Dimensions.get('window').height/2) - 75; 24 | // console.log(top); 25 | var added = false; 26 | if(this.props.children.props.children.props.children == "Added"){ 27 | added = true; 28 | } 29 | var icon = added ? 30 | ( ): 31 | ( ); 32 | return ( 33 | 34 | 35 | {icon} 36 | 37 | {this.props.children} 38 | 39 | 40 | 41 | ); 42 | } 43 | } 44 | 45 | var styles = StyleSheet.create({ 46 | top: { 47 | width: 150, 48 | height: 150, 49 | borderRadius: 20, 50 | flexDirection: 'column', 51 | overflow: 'hidden', 52 | alignItems: 'center', 53 | alignSelf: 'center' 54 | }, 55 | icon: { 56 | flex: 9, 57 | marginTop: 25 58 | }, 59 | bottom: { 60 | position: 'absolute', 61 | bottom: 0, 62 | left: 0, 63 | top: 0, 64 | right: 0, 65 | flexDirection: 'row', 66 | alignItems: 'center' 67 | }, 68 | content: { 69 | flex: 3, 70 | marginBottom: 20 71 | } 72 | }); 73 | 74 | module.exports = Toast; 75 | -------------------------------------------------------------------------------- /app/components/videoPage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | StyleSheet, 5 | Component, 6 | Platform, 7 | View, 8 | ProgressBarAndroid 9 | } from 'react-native'; 10 | import Video from '../lib/Video'; 11 | 12 | 13 | var isTab = true; 14 | 15 | class VideoPage extends Component { 16 | constructor(props) { 17 | super(props); 18 | 19 | this.state = {paused: true, loading: true, isTab: true}; 20 | 21 | if(props.uri) { 22 | this.uri = props.uri; 23 | this.state.isTab = false 24 | } else { 25 | this.uri = "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4"; 26 | this.state.isTab = true 27 | } 28 | } 29 | 30 | render() { 31 | if(Platform.OS ==='ios') { 32 | // on iOS there is already visual feedback that there is a video loading, 33 | // so do not require a spinner 34 | var spinner = 35 | ( ); 36 | } else { 37 | var spinner = 38 | ( 39 | 40 | ); 41 | } 42 | 43 | 44 | var isLoading = this.state.loading ? 45 | ( 46 | {spinner} 47 | ): 48 | (); 49 | 50 | 51 | var videoForPlatform = Platform.OS === 'ios' ? 52 | ( 53 | ): 63 | ( 64 | ); 76 | 77 | return ( 78 | 79 | { isLoading } 80 | { videoForPlatform } 81 | 82 | ) 83 | } 84 | } 85 | 86 | const styles = StyleSheet.create({ 87 | container: { 88 | flex: 1, 89 | // marginTop: (Platform.OS ==='ios') ? 50 : 50 90 | // flexDirection:'row', 91 | // alignItems:'center', 92 | // justifyContent:'center' 93 | }, 94 | fullScreenTab: { 95 | position: 'absolute', 96 | top: 50, 97 | left: 0, 98 | bottom: 55, 99 | right: 0 100 | }, 101 | fullScreen: { 102 | position: 'absolute', 103 | top: 50, 104 | left: 0, 105 | bottom: 0, 106 | right: 0 107 | }, 108 | spinner: { 109 | marginTop: 200, 110 | alignSelf: 'center' 111 | }, 112 | }); 113 | 114 | module.exports = VideoPage 115 | -------------------------------------------------------------------------------- /app/containers/RouterContainerStyles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { 4 | StyleSheet, 5 | Platform 6 | } from 'react-native'; 7 | 8 | const styles = StyleSheet.create({ 9 | sceneStyle: { 10 | // marginTop: (Platform.OS ==='ios') ? 0 : 20, 11 | }, 12 | }); 13 | 14 | const getTabBarStyle = props => ({ 15 | top: (Platform.OS ==='ios') ? undefined : 50, 16 | backgroundColor: '#f9f9f9', 17 | borderTopColor: '#d8d8d8', 18 | borderTopWidth: 1, 19 | height: 55 20 | }); 21 | 22 | const navBarStyle = (Platform.OS == 'ios') ? {backgroundColor: "#ff9900"} : { alignItems: "stretch", justifyContent: "center", marginLeft: 0, paddingTop: 10, backgroundColor: "#ff9900", height: 55} 23 | 24 | const navTextStyle = (Platform.OS == 'ios') ? {color: "#FFF"} : {alignSelf: "center", marginLeft: -80, marginBottom: -50, fontSize: 20, fontWeight: "bold", color: "#FFF"} 25 | 26 | 27 | const barButtonIconStyle = { tintColor: "#FFF" }; //, backgroundColor: "#F00"} ; 28 | 29 | 30 | module.exports = { 31 | sceneStyle: styles.sceneStyle, 32 | getTabBarStyle, 33 | navBarStyle, 34 | navTextStyle, 35 | barButtonIconStyle 36 | }; 37 | -------------------------------------------------------------------------------- /app/containers/app.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react-native'; 2 | import { Provider } from 'react-redux/native'; 3 | 4 | import configureStore from '../store/configureStore'; 5 | import GeoEncodingApp from './geoEncodingApp'; 6 | import CodePush from 'react-native-code-push'; 7 | 8 | var SplashScreen = require('@remobile/react-native-splashscreen'); 9 | 10 | const store = configureStore(); 11 | export default class App extends Component { 12 | componentDidMount(){ 13 | CodePush.sync({ updateDialog: true, installMode: CodePush.InstallMode.IMMEDIATE }); 14 | SplashScreen.hide(); 15 | } 16 | render() { 17 | return ( 18 | 19 | {()=> } 20 | 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/containers/geoEncodingApp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | Component, 5 | Navigator, 6 | BackAndroid, 7 | Platform 8 | } from 'react-native'; 9 | import {bindActionCreators} from 'redux'; 10 | 11 | import { connect } from 'react-redux/native'; 12 | // import { 13 | // actions as routerActions, 14 | // Route, 15 | // Router, 16 | // Schema 17 | // } from 'react-native-router-redux'; 18 | 19 | import {Router, Route, Schema, Animations, TabBar, Actions} from 'react-native-router-flux' 20 | import {ExRouter} from 'react-native-router-flux/ExRouter' 21 | import * as styles from './RouterContainerStyles'; 22 | import TabBarItem from '../components/TabBarItem'; 23 | 24 | 25 | //import TabBar from '../components/tabBar'; 26 | 27 | import * as addressActions from '../actions/addressActions'; 28 | import * as databaseActions from '../actions/databaseActions'; 29 | import * as downloadActions from '../actions/downloadActions'; 30 | import * as routerActions from '../actions/routerActions'; 31 | import * as accountActions from '../actions/accountActions'; 32 | import AddressList from '../components/addressList'; 33 | import Favourites from '../components/favourites'; 34 | import AddressDetails from '../components/addressDetails'; 35 | import Launch from '../components/launch'; 36 | import VideoPage from '../components/videoPage'; 37 | import LoginPage from '../components/login'; 38 | import SignUp from '../components/signUp'; 39 | import MyAccount from '../components/myAccount'; 40 | import DownloadList from '../components/downloadList'; 41 | import FeatureList from '../components/featureList'; 42 | import ImagePicker from '../components/imagePickerPage'; 43 | //import CameraPage from '../components/cameraPage'; 44 | 45 | var Orientation = require('react-native-orientation'); 46 | 47 | 48 | const mapStateToProps = state => ({ 49 | addresses : state.addressesByGeoEncoding.addresses, 50 | favourites : state.addressesByGeoEncoding.favourites, 51 | searchString : state.addressesByGeoEncoding.searchString, 52 | downloaded : state.downloadState.downloaded, 53 | routes : state.routes, 54 | routerState: state.router.routerState, 55 | isLoading: state.addressesByGeoEncoding.isLoading, 56 | isEmpty: state.addressesByGeoEncoding.isEmpty, 57 | accountState : state.account, 58 | user : state.account.user, 59 | }); 60 | 61 | const mapDispatchToProps = (dispatch) => ({ 62 | actions: bindActionCreators({ 63 | ...addressActions, 64 | ...databaseActions, 65 | ...downloadActions, 66 | ...accountActions, 67 | }, dispatch), 68 | routerActions: bindActionCreators({ 69 | ...routerActions, 70 | }, dispatch), 71 | navActions: Actions 72 | }); 73 | 74 | // const defaultSchema = { 75 | // statusStyle: 'light-content', 76 | // }; 77 | 78 | const favComp = connect(mapStateToProps,mapDispatchToProps)(Favourites); 79 | const addrComp = connect(mapStateToProps,mapDispatchToProps)(AddressList); 80 | const dlComp = connect(mapStateToProps,mapDispatchToProps)(DownloadList); 81 | const featureComp = connect(mapStateToProps,mapDispatchToProps)(FeatureList); 82 | const loginComp = connect(mapStateToProps,mapDispatchToProps)(LoginPage); 83 | const signUpComp = connect(mapStateToProps,mapDispatchToProps)(SignUp); 84 | const myAccountComp = connect(mapStateToProps,mapDispatchToProps)(MyAccount); 85 | 86 | 87 | 88 | class GeoEncodingApp extends Component { 89 | constructor(props) { 90 | super(props); 91 | } 92 | 93 | componentDidMount() { 94 | Orientation.lockToPortrait(); 95 | } 96 | 97 | render(){ 98 | BackAndroid.addEventListener('hardwareBackPress', () => { 99 | try { 100 | return Actions.pop(); 101 | } 102 | catch (err) { 103 | return false; 104 | } 105 | }); 106 | 107 | var login = (this.props.user._id == undefined); 108 | var iOS = (Platform.OS == 'ios'); 109 | 110 | return( 111 | {this.props.routerActions.onPush(route.name); return true}} 117 | onPop={()=>{this.props.routerActions.onPop(); return true}} 118 | onReplace={(route)=>{this.props.routerActions.onReplace(route.name); return true}} 119 | renderScene={() => { console.log("RENDER SCNENE LOGIN (TAB)");}} 120 | > 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | {this.props.routerActions.onPush(route.name); return true}} 130 | onPop={()=>{this.props.routerActions.onPop(); return true}} 131 | onReplace={(route)=>{this.props.routerActions.onReplace(route.name); return true}} 132 | > 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | ); 159 | } 160 | 161 | } 162 | 163 | 164 | // export default connect((state) => ( 165 | // {addressesByGeoEncoding: state.addressesByGeoEncoding, 166 | // router: Object.assign({},state,{router:state.router}).router}), mapDispatchToProps)(GeoEncodingApp); 167 | 168 | export default connect(mapStateToProps, mapDispatchToProps)(GeoEncodingApp); 169 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | */ 5 | 'use strict'; 6 | import 'babel-polyfill'; 7 | 8 | import { createStore, applyMiddleware } from 'redux'; 9 | import thunkMiddleware from 'redux-thunk' 10 | 11 | import createLogger from 'redux-logger'; 12 | import fetchAddresses from './actions/addressActions'; 13 | import * as rootReducer from './reducers'; 14 | 15 | var React = require('react-native'); 16 | var ProgressBar = require('ProgressBarAndroid'); 17 | var SGListView = require('react-native-sglistview'); 18 | 19 | 20 | var { 21 | AppRegistry, 22 | StyleSheet, 23 | View, 24 | TextInput, 25 | TouchableHighlight, 26 | Text, 27 | ListView, 28 | ActivityIndicatorIOS, 29 | Platform 30 | } = React; 31 | 32 | class GeoEncoding extends React.Component{ 33 | 34 | constructor(props){ 35 | super(props); 36 | var ds = new ListView.DataSource({ rowHasChanged:(r1,r2) => r1.place_id !== r2.place_id }); 37 | this.state={ 38 | dataSource: ds.cloneWithRows([]), 39 | searchString: '135 city road', 40 | isLoading:false, 41 | message:'' 42 | } 43 | } 44 | render() { 45 | var spinner = this.state.isLoading? 46 | ((Platform.OS==='ios')?