From 97624c54b31c1a4eed3962cfca2b8678d575e8e5 Mon Sep 17 00:00:00 2001 From: Rich Paret <623643+rparet@users.noreply.github.com> Date: Sat, 21 Mar 2020 23:26:53 -0400 Subject: [PATCH 01/24] Checks for background geo authorization before updating state (#141) Per #129 if you denied permission in the system dialog, we'd still update the button as if you had started logging. This fix creates the desired behavior, setting the state back to the way it was before you requested permission. --- app/views/LocationTracking.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/app/views/LocationTracking.js b/app/views/LocationTracking.js index f996012bd0..ac66986c4b 100644 --- a/app/views/LocationTracking.js +++ b/app/views/LocationTracking.js @@ -16,6 +16,7 @@ import { } from 'react-native'; import colors from "../constants/colors"; import LocationServices from '../services/LocationService'; +import BackgroundGeolocation from '@mauron85/react-native-background-geolocation'; import exportImage from './../assets/images/export.png'; import news from './../assets/images/newspaper.png'; @@ -77,9 +78,22 @@ class LocationTracking extends Component { SetStoreData('PARTICIPATE', 'true').then(() => LocationServices.start() ); - this.setState({ - isLogging:true - }) + + // Check and see if they actually authorized in the system dialog. + // If not, stop services and set the state to !isLogging + // Fixes tripleblindmarket/private-kit#129 + BackgroundGeolocation.checkStatus(({ authorization }) => { + if (authorization === BackgroundGeolocation.AUTHORIZED) { + this.setState({ + isLogging:true + }) + } else if (authorization === BackgroundGeolocation.NOT_AUTHORIZED) { + LocationServices.stop(this.props.navigation) + this.setState({ + isLogging:false + }) + } + }); } setOptOut =()=>{ From 664279a3fe4c4045cf72939e3763531195a934d9 Mon Sep 17 00:00:00 2001 From: Enrico Santus Date: Sat, 21 Mar 2020 23:28:35 -0400 Subject: [PATCH 02/24] Update exportscreen.json (#121) Translating in Italian --- app/locales/it/exportscreen.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/locales/it/exportscreen.json b/app/locales/it/exportscreen.json index d834b2f95a..497c48e48a 100644 --- a/app/locales/it/exportscreen.json +++ b/app/locales/it/exportscreen.json @@ -1,6 +1,6 @@ { - "export_para_1":"You can share your location trail with anyone using the Share button below. Once you press the button it will ask you with whom and how you want to share it.", - "export_para_2":"Location is shared as a simple list of times and coordinates, no other identifying information.", - "share":"SHARE", - "data_hint":"Log has data of" -} \ No newline at end of file + "export_para_1":"Puoi condividere i tuoi movimenti con chiunque, premendo il tasto CONDIVIDI. Una volta premuto il tasto, l'applicazione ti chiederà con chi e come vuoi condivide le informazioni.", + "export_para_2":"La posizione è condivisa come una semplice lista di date e coordinate, senza alcuna informazione che possa permettere l'identificazione dell'utente.", + "share":"CONDIVIDI", + "data_hint":"Log contiene dati di" +} From d44e6437d9abaa536e46e93ef52f51f0c688cc5a Mon Sep 17 00:00:00 2001 From: Enrico Santus Date: Sat, 21 Mar 2020 23:28:53 -0400 Subject: [PATCH 03/24] Update import.json (#122) Translating to Italian --- app/locales/it/import.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/locales/it/import.json b/app/locales/it/import.json index 58e337de66..268dce5c65 100644 --- a/app/locales/it/import.json +++ b/app/locales/it/import.json @@ -1,5 +1,5 @@ { - "import_title":"Import Locations", - "import_step_1":"1. Login to your Google Account and Download your Location History", - "import_step_2":"2. After downloaded, open this screen again. The data will import automatically." -} \ No newline at end of file + "import_title":"Importa le Posizioni", + "import_step_1":"1. Fai login nel tuo account Google e scarica la storia dei tuoi movimenti.", + "import_step_2":"2. Una volta scaricati i movimenti, apri questa schermata. I dati saranno importati automaticamente." +} From 942d9f13ba0882b0da3f9e6dfdbaac8018542901 Mon Sep 17 00:00:00 2001 From: Enrico Santus Date: Sat, 21 Mar 2020 23:29:48 -0400 Subject: [PATCH 04/24] Update intro.json (#123) Translating to Italian --- app/locales/it/intro.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/locales/it/intro.json b/app/locales/it/intro.json index 9e1f07ae35..6e5364a3de 100644 --- a/app/locales/it/intro.json +++ b/app/locales/it/intro.json @@ -1,14 +1,14 @@ { "private_kit":"Private Kit", - "intro1_para1":"Designed with data security and privacy protection at its heart, MIT Private Kit is the next generation of secure location logging.", - "next":"NEXT", - "back":"BACK", - "start":"START", - "intro2_title1":"Less than 100KB", - "intro2_para1":"Private Kit’s trail generator logs your device’s location data in under 100KB of space – less space than a single picture.", - "intro2_title2":"You are in charge", - "intro2_para2":"Data Never Leaves Your Device Without Your Consent", - "intro3_title1":"The Future", - "intro3_para1":"The Next Step in Solving Today and Tomorrow’s Problems Enabling individuals to log their location trail offers new opportunities for researchers studying pandemic tracking, refugee migration, and community traffic analysis.", - "intro3_para2":"Learn More http://privatekit.mit.edu/" -} \ No newline at end of file + "intro1_para1":"Progettato tenendo a cuore la sicurezza dei dati e della privacy, MIT Private Kit è la nuova generazione di registrazione privata della localizzazione.", + "next":"PROSSIMO", + "back":"INDIETRO", + "start":"INIZIA", + "intro2_title1":"Meno di 100KB", + "intro2_para1":"I movimenti salvati da Private Kit occupano meno di 100KB di spazio – meno di una singola foto.", + "intro2_title2":"Sei tu che decidi", + "intro2_para2":"I tuoi dati non lasceranno mai il tuo telefono senza il tuo consenso", + "intro3_title1":"Il Futuro", + "intro3_para1":"Il prossimo passo per risolvere i problemi di oggi e di domani consiste nel permettere agli individui di salvare i propri movimenti, offrendo nuove opportunita' per ricercatori che studiano pandemie, migrazioni e spostamenti.", + "intro3_para2":"Scopri di piu' http://privatekit.mit.edu/" +} From 6dffa00d61b60e40332fd42daa19d4e20333ef82 Mon Sep 17 00:00:00 2001 From: Enrico Santus Date: Sat, 21 Mar 2020 23:30:11 -0400 Subject: [PATCH 05/24] Update locationTracking.json (#124) Translating to Italian --- app/locales/it/locationTracking.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/locales/it/locationTracking.json b/app/locales/it/locationTracking.json index c870947155..619e82b9de 100644 --- a/app/locales/it/locationTracking.json +++ b/app/locales/it/locationTracking.json @@ -1,12 +1,12 @@ { - "start_logging":"START LOGGING", - "stop_logging":"STOP LOGGING", - "logging_message":"It is currently logging your location privately every five minutes. Your location information will NOT leave your phone.", - "not_logging_message":"NOTE: After clicking this button you may be prompted to grant Private Kit access to your location.", - "import":"Import", - "export":"Export", - "news":"news", - "latest_news":"Latest News", - "url_info":"For more information visit the Private Kit hompage:", + "start_logging":"INIZIA A SALVARE", + "stop_logging":"SMETTI DI SALVARE", + "logging_message":"La APP sta attualmente salvando i tuoi movimenti in privato ogni 5 minuti. Queste informazioni sono salvate solo nel tuo telefono.", + "not_logging_message":"NOTA: Una volta premuto questo tasto, ti sarà richiesto di garantire l'accesso ai tuoi movimenti a Private Kit.", + "import":"Importa", + "export":"Esporta", + "news":"novità", + "latest_news":"Ultime Novità", + "url_info":"Per più informazioni, visita la homepage di Private Kit:", "private_kit_url":"privatekit.mit.edu" -} \ No newline at end of file +} From d44d24f053d5f75a1799d92400c8f0449f41ec80 Mon Sep 17 00:00:00 2001 From: Rich Paret <623643+rparet@users.noreply.github.com> Date: Sun, 22 Mar 2020 11:13:41 -0400 Subject: [PATCH 06/24] Readme updates (#143) * Added Slack channel * Cleared up the bold on the build note * Moved CONTRIBUTING.md to the top level * Removed Android testing versions (not accurate at the moment) --- .github/CONTRIBUTING.md => CONTRIBUTING.md | 0 README.md | 13 +++---------- 2 files changed, 3 insertions(+), 10 deletions(-) rename .github/CONTRIBUTING.md => CONTRIBUTING.md (100%) diff --git a/.github/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 100% rename from .github/CONTRIBUTING.md rename to CONTRIBUTING.md diff --git a/README.md b/README.md index 4eae2fc422..bfff1bf38a 100644 --- a/README.md +++ b/README.md @@ -50,20 +50,13 @@ or npx react-native run-ios --simulator="iPhone 8 Plus" ``` ----------------------------------------------------------------------------------- NOTE: In some cases, the abovementioned procedure leads to the error 'Failed to load bundle - Could not connect to development server'. In these cases, kill all other react-native processes and try it again. ----------------------------------------------------------------------------------- ## Contributing -Read the [contribution guidelines](./.github/CONTRIBUTING.md). +Read the [contribution guidelines](CONTRIBUTING.md). -Join the WhatsApp group - https://chat.whatsapp.com/HXonYGVeAwQIKxO0HYlxYL +WhatsApp: https://chat.whatsapp.com/HXonYGVeAwQIKxO0HYlxYL +Slack: https://safepathsprivatekit.slack.com/ -## Tested On - -| Device | Version | -| ------------- | ------------- | -| Android Pixel | API 28 | -| Android Pixel | API 29 | From 7b5f6eb0ef90049c0e383333146bb52c2b285943 Mon Sep 17 00:00:00 2001 From: Sam Stowers Date: Sun, 22 Mar 2020 12:08:21 -0500 Subject: [PATCH 07/24] Added a three-dot menu button and licenses page to the main screen (LocationTracking.js) (#142) * Update README * Add modal menu for licenses to main screen * Share action (#28) * Refactoring the copy-pasted buttons styles. (#26) * Refactoring the copy-pasted buttons styles. * Remove dead NegButton references This also includes some code reformatting from VS Code, but mainly it removes dangling references to the NegViews. Co-authored-by: Steve Penrod Co-authored-by: Steve Penrod * Fix botched merge (missing comma) (#30) * New Icon pack. (#32) Using Adaptive Icons Android and preparing the app for release on the Apple Store. * UI Tweaking and changed News URL (#33) * Massaged the look of the UI on the sub-pages and the main page * Added description text to the Export page * Changed the URL of the webview to: https://privatekit.mit.edu/views * Curate and collapse GPS location data (#35) This changes several things about the data being stored: * The time being stored in the structure is now UTC. It was previous local time * The data being stored is now simplified to: [ (utc_unix_time, GPS lat, GPS lon) ... ] * The stored data is now limited to 28 days * Version 0.4 (#36) * LocationServices Refactor (#37) Creates Statically Typed LocationServices class to handle all background instantiation once. BackgroundGeolocation is smart in itself and will handle any form of termination events. In addition, the onListen event `stop` was added where future release can include a local push notification to tell the user that location services were terminated. * Version0.4 for Apple Store. (#39) * Add file based sharing (#38) - Allows the file to be shared instead of raw string NOTES: This requires accessing the filesystem when you do an Export. Potentially we'll need to warn people this is going to cause a popup. * Google Auto Import (Prototype) (#34) Screen requests users to download the Google Takeout file for the Location History. After the download, users have to go back and come back to import. Watch the logs to see what the app is doing. We don't have the UI to let the user know the current progress yet. * Adding initial license file (MIT) (#41) lgtm * Add helper scripts and update help messages (#29) Adds two scripts to make it easy to start the react system and (re)run the application within the emulator. Simply run: 1_start_react.sh To install packages and start the react ecosystem, then run 2_start_android_app.sh To launch the application within the Android emulator (launching the emulator automatically if necessary). * Fix merge error (missing comma) Merge ended up with a missing comma in the package.json * Fix multi-log bug (#42) When the application is already running, clicking on the icon (at least under Android) would start another object for the logger. This does a quick instance count check to prevent multiple loggers. * Fix several crashes due to renamed variable (#43) It looks like the code got refactored and not all variables were renamed during that, leading to some exceptions during import. Just renamed vars as appropriate. * Version 0.5 (#44) Importing Google Location History Exporting functions * add whatsapp group for tech people (#46) * Updating README * Initialize .github files (#48) * Add contribution guide * Initialize .github files Helping others get started * Bugfix for v0.5 (#52) 1. Package.json format must follow 0.0.0 version names. 2. Version ID for the AppleStore and Android Stores are now the same. * Fix to replace code lost during merge #37 (#55) The LocationServices refactor merge lost the changes that happened to adding "curation" to the point data (PR #35). This restores it. * Add point count info, assists in debugging (#56) Now the Export screen shows a count of points to be exported. This is provides minimal information for debugging and to let the user understand that something is happening in the background. Co-authored-by: Abhishek Singh * GPS tracking wasn't running in many cases (#58) The HeadlessTask part of the BackgroundLocationTracker component wasn't being used. On Android, it spins up a special background task when the main application has been shutdown to continue grabbing points. * Add 'yarn' support when found (#59) Several people have said that 'yarn' works much better than 'npm', so I'm making it the default if found. If not, the script will still attempt to run 'npm. * add stationary location logging and savelocation in backgroundtask (#61) * Add missing notifications for Location Services (#64) * Add missing notifications for Location Services Several conditions cause Private Kit to stop failing when it cannot access GPS info. We should notify the user when this has happened. That includes: * The app doesn't have proper permissions * The permissions have been revoked * The location service has been shut down Still to do is a notification to show the user that the background service is not doing anything when the user turns off location services. * Fix auto-format errors The automatic formatting done in "Javascript" style instead of "React Native" * use 5 minute time interval Co-authored-by: Abhishek Singh * Andynuzzo/fix require cycles + Clearing all Warnings and Bug Fixes for iOS (#67) * updated README.md Made changes for developers on macOS with Xcode 10+ * Fixed Async storage, request cycles warnings * using patch-package to work around RNFetchBlob recursive importing * saving patch for RNFetchBlob recursive importing * Putting native background geo back. * re-fix AsyncStorage * Fixing Background services not existing on iOS * Fixing Internationalization on Xcode * Import Alert and add stationarylocation logging * capitalize L Co-authored-by: Andy Nuzzo <36167533+andreanuzzo@users.noreply.github.com> Co-authored-by: philrouge Co-authored-by: Abhishek Singh * Downloading a PR and Reviewing it. (#82) Added info on how to download a PR from a Forked Repo in order to review it. * RNFS.DownloadDirectoryPath is not defined on iOS. (#76) * RNFS.DownloadDirectoryPath is not defined on iOS. Figure out a way to access the Downloads folder. * Version 0.5.1 * Feature/new ui (#81) * UI changed, added Welcome Screens, changed location tracking screen * Moved Styles * Slider for welcome screens * Navigate through pagination * Set initial route * SafeAreaView for ios * Added image * Set state to true * Dot navigation fixed * Android backhandler * UI Designed for Export and Import Pages * Latest news page UI Co-authored-by: Harsh Vitra * Adding a MacOS GitHub Action to build both apps (#90) * Update README * RNFS.DownloadDirectoryPath is not defined on iOS. Figure out a way to access the Downloads folder. * Version 0.5.1 * Testing iOS Action * adding homebrew * Adding node and java * Installing Android Studio, SDK and Accepting licenses * Fixing java * Using cast for Android SDK * Proper way to accept licenses * Correct Android path * Build tools 28.0.3 * New Buildtools command * Fixing Parallelism and License Accept. * Fixing YAML indentation * Trying to see what the error code when accepting the license * Trying to get this licenses signed. * Removing license acceptance. * Fixing Node JS bug * Yet another tentative to get Android Tools signed. * Don't need to install NodeJS * Making sure we don't change this line. * Adding build step. * Moving from cocoa pods action to our own install. * Adding Android's assembleRelease step * Separating update pods. * Bundle is the right option * Changing bundleRelease (needs signature) to build. * Testing to see if react bundle is necessary * Adding react native bundle * Installing Android Support Library, google services and other images * Moving SDK update up top * New Android dependencies. * Fixing Command Line tools * Adding updates and platform tools * Fixing installation by accepting licenses at the moment of the download * Testing the need for Support libraries via cradle. * Reverting Library support * Adding MIT team for the release * Removing SDK Manager update * Adding a gradlew check before build. * Solving merge conflict. * Changing the name of the builder action * Adding working dir. * Keeping things that are working. * Only creates the directory if the directory does not exist. * Setting up Android's back button to go back to the main screen instead of leaving the app. Co-authored-by: David Biga * Made Android Studio steps optional, remove dev_setup2.sh (#98) I previous PR added a second version of dev_setup.sh that was identical except the Android Studio setup was commented out. This indicates a need, so now the main dev_setup.sh allows you to skip that step. The dev_setup2.sh has been removed. * Version 0.5.2 (#95) * Update README * RNFS.DownloadDirectoryPath is not defined on iOS. Figure out a way to access the Downloads folder. * Version 0.5.1 * Testing iOS Action * adding homebrew * Adding node and java * Installing Android Studio, SDK and Accepting licenses * Fixing java * Using cast for Android SDK * Proper way to accept licenses * Correct Android path * Build tools 28.0.3 * New Buildtools command * Fixing Parallelism and License Accept. * Fixing YAML indentation * Trying to see what the error code when accepting the license * Trying to get this licenses signed. * Removing license acceptance. * Fixing Node JS bug * Yet another tentative to get Android Tools signed. * Don't need to install NodeJS * Making sure we don't change this line. * Adding build step. * Moving from cocoa pods action to our own install. * Adding Android's assembleRelease step * Separating update pods. * Bundle is the right option * Changing bundleRelease (needs signature) to build. * Testing to see if react bundle is necessary * Adding react native bundle * Installing Android Support Library, google services and other images * Moving SDK update up top * New Android dependencies. * Fixing Command Line tools * Adding updates and platform tools * Fixing installation by accepting licenses at the moment of the download * Testing the need for Support libraries via cradle. * Reverting Library support * Adding MIT team for the release * Removing SDK Manager update * Adding a gradlew check before build. * Solving merge conflict. * Changing the name of the builder action * Adding working dir. * Keeping things that are working. * Only creates the directory if the directory does not exist. * Setting up Android's back button to go back to the main screen instead of leaving the app. * Version 0.5.2 New UI (#81, #90) Co-authored-by: David Biga * Fix Notification Issue (#115) Co-authored-by: Harsh Vitra * Cleanup onboarding (#100) * Made Android Studio steps optional, remove dev_setup2.sh I previous PR added a second version of dev_setup.sh that was identical except the Android Studio setup was commented out. This indicates a need, so now the main dev_setup.sh allows you to skip that step. The dev_setup2.sh has been removed. * Updated the CONTRIBUTING guide with better instructions The guide was originally written from the perspective of "internal" people with write access. Changed instruction to the perspective of an outside contributor. * Improving Readme.me (#103) * Update README * Local push notifications (#99) * Update LocationService + Add Local Push Noticications * Remove key * Update binaries * Add Button resource from react-native * Change optOut * Remove Additional Stop Location Recording (#117) * Multilingual support (#119) * Installation & Structure ready * Added readme in languages file and created first label * Added labels for intro1 * Hindi support added * Intro 2 content added * Intro 3 content added * Location tracking content added * hindi content for Location tracking page * Import added in Hindi directory * Import screen content added * Export and News screen added * French, Italian, German, and Portuguese support added Co-authored-by: Harsh Vitra * Location Issues fix FROM #109 (#127) * remove motiontracker requirement; adjust location params; backfill stationary points * Remove Additional Stop Location Recording Co-authored-by: Safe Path * Updated iOS location permission description text (#128) * Refine message in README (#126) Add more detail about the effort to apply Private Kit to COVID * Version 0.5.3 (#130) * Update README * RNFS.DownloadDirectoryPath is not defined on iOS. Figure out a way to access the Downloads folder. * Version 0.5.1 * Testing iOS Action * adding homebrew * Adding node and java * Installing Android Studio, SDK and Accepting licenses * Fixing java * Using cast for Android SDK * Proper way to accept licenses * Correct Android path * Build tools 28.0.3 * New Buildtools command * Fixing Parallelism and License Accept. * Fixing YAML indentation * Trying to see what the error code when accepting the license * Trying to get this licenses signed. * Removing license acceptance. * Fixing Node JS bug * Yet another tentative to get Android Tools signed. * Don't need to install NodeJS * Making sure we don't change this line. * Adding build step. * Moving from cocoa pods action to our own install. * Adding Android's assembleRelease step * Separating update pods. * Bundle is the right option * Changing bundleRelease (needs signature) to build. * Testing to see if react bundle is necessary * Adding react native bundle * Installing Android Support Library, google services and other images * Moving SDK update up top * New Android dependencies. * Fixing Command Line tools * Adding updates and platform tools * Fixing installation by accepting licenses at the moment of the download * Testing the need for Support libraries via cradle. * Reverting Library support * Adding MIT team for the release * Removing SDK Manager update * Adding a gradlew check before build. * Solving merge conflict. * Changing the name of the builder action * Adding working dir. * Keeping things that are working. * Only creates the directory if the directory does not exist. * Setting up Android's back button to go back to the main screen instead of leaving the app. * Version 0.5.2 New UI (#81, #90) * Adding preview UI * Adding logo, Apple Store URL and badge to GitHub Actions * Adding Preview UI * Removing old descriptions * Version 0.5.3: - Multilingual Support - Local Push Notifications - Improved Requests for App Permissions Co-authored-by: David Biga * Added Linking in imports (#116) Co-authored-by: Harsh Vitra * Minor Typo Fix (#132) * fixed typo Co-authored-by: Bikram Khastgir * Update README.md (#138) Adding a note for developers - not sure if it is meaningful but I hit my head for hours on this! * Create dev Code of Conduct (#139) This is from the default community code of conduct template on Github. * Add modal menu for licenses to main screen Co-authored-by: David Biga Co-authored-by: David Biga Co-authored-by: Vitor Pamplona Co-authored-by: Steve Penrod Co-authored-by: Steve Penrod Co-authored-by: Abhishek Singh Co-authored-by: Andy Nuzzo <36167533+andreanuzzo@users.noreply.github.com> Co-authored-by: philrouge Co-authored-by: Harsh Vitra Co-authored-by: Harsh Vitra Co-authored-by: Safe Path Co-authored-by: Rich Paret <623643+rparet@users.noreply.github.com> Co-authored-by: bikramkhastgir <7278304+bikramkhastgir@users.noreply.github.com> Co-authored-by: Bikram Khastgir Co-authored-by: Enrico Santus --- .prettierrc.js | 2 +- App.js | 12 +- app/Entry.js | 14 +- app/assets/images/kebabIcon.png | Bin 0 -> 914 bytes app/locales/en/index.js | 14 +- app/locales/en/licensesscreen.json | 3 + app/views/Licenses.js | 160 ++++++++ app/views/LocationTracking.js | 612 +++++++++++++++++------------ dev_setup.sh | 0 package.json | 1 + yarn.lock | 64 +++ 11 files changed, 613 insertions(+), 269 deletions(-) create mode 100644 app/assets/images/kebabIcon.png create mode 100644 app/locales/en/licensesscreen.json create mode 100644 app/views/Licenses.js mode change 100644 => 100755 dev_setup.sh diff --git a/.prettierrc.js b/.prettierrc.js index 5c4de1a4f6..355e7d1e4b 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,5 +1,5 @@ module.exports = { - bracketSpacing: false, + bracketSpacing: true, jsxBracketSameLine: true, singleQuote: true, trailingComma: 'all', diff --git a/App.js b/App.js index 1f5e6f53fe..4721698b1d 100644 --- a/App.js +++ b/App.js @@ -7,17 +7,15 @@ */ import React from 'react'; -import { - StatusBar -} from 'react-native'; - +import { StatusBar } from 'react-native'; +import { MenuProvider } from 'react-native-popup-menu'; import Entry from './app/Entry'; const App: () => React$Node = () => { return ( - <> - - + + + ); }; diff --git a/app/Entry.js b/app/Entry.js index 91ea6564aa..723eb64c3d 100644 --- a/app/Entry.js +++ b/app/Entry.js @@ -8,6 +8,7 @@ import Welcome from './views/Welcome'; import NewsScreen from './views/News'; import ExportScreen from './views/Export'; import ImportScreen from './views/Import'; +import LicencesScreen from './views/Licenses'; import Slider from './views/welcomeScreens/Slider'; import {GetStoreData, SetStoreData} from './helpers/General'; @@ -50,18 +51,16 @@ class Entry extends Component { options={{headerShown:false}} /> )} - - - + /> + /> + diff --git a/app/assets/images/kebabIcon.png b/app/assets/images/kebabIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..8b3d663aa5990185d3183b47cc1896259c23cf8f GIT binary patch literal 914 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H0wgodS2_SGmUKs7M+SzC{oH>NS%G|oWRDy)vIg-4nJ@ErkR#;MwT(m+A>5>H=O_9x6@47yq!PD1m5ni4!+978H@y`63EADk%R&d(RL zMM!+Il(?bh>;>|UZogMXm?)l6QQIW7zacLvCdF{$u~?oXM?IeyiL}37;Irkz@8>(; z=N6x{wm@+>yLb4y&$gO9?wwA2x2+JBSQtNdHWnH79nO2Eg!wEgFFrWrW vkPX54X(i=}MX3zs<>h*rdD+Fui3O>8`9 { + this.props.navigation.navigate('LocationTrackingScreen', {}); + return true; + }; + + componentDidMount() { + BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); + } + + componentWillUnmount() { + BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); + } + + render() { + return ( + + + this.backToMain()}> + + + Licenses + + + + + {/* This screen is a placeholder for complete license content, or a link */} + {languages.t('label.license_placeholder')} + + + + ); + } +} + +const styles = StyleSheet.create({ + // Container covers the entire screen + container: { + flex: 1, + flexDirection: 'column', + color: colors.PRIMARY_TEXT, + backgroundColor: colors.WHITE, + }, + headerTitle: { + textAlign: 'center', + fontWeight: 'bold', + fontSize: 38, + padding: 0, + }, + subHeaderTitle: { + textAlign: 'center', + fontWeight: 'bold', + fontSize: 22, + padding: 5, + }, + main: { + flex: 1, + flexDirection: 'column', + textAlignVertical: 'top', + // alignItems: 'center', + padding: 20, + width: '96%', + alignSelf: 'center', + }, + buttonTouchable: { + borderRadius: 12, + backgroundColor: '#665eff', + height: 52, + alignSelf: 'center', + width: width * 0.7866, + marginTop: 30, + justifyContent: 'center', + }, + buttonText: { + fontFamily: 'OpenSans-Bold', + fontSize: 14, + lineHeight: 19, + letterSpacing: 0, + textAlign: 'center', + color: '#ffffff', + }, + mainText: { + fontSize: 18, + lineHeight: 24, + fontWeight: '400', + textAlignVertical: 'center', + padding: 20, + }, + smallText: { + fontSize: 10, + lineHeight: 24, + fontWeight: '400', + textAlignVertical: 'center', + padding: 20, + }, + + headerContainer: { + flexDirection: 'row', + height: 60, + borderBottomWidth: 1, + borderBottomColor: 'rgba(189, 195, 199,0.6)', + alignItems: 'center', + }, + backArrowTouchable: { + width: 60, + height: 60, + paddingTop: 21, + paddingLeft: 20, + }, + backArrow: { + height: 18, + width: 18.48, + }, + sectionDescription: { + fontSize: 16, + lineHeight: 24, + marginTop: 12, + fontFamily: 'OpenSans-Regular', + }, +}); + +export default LicensesScreen; diff --git a/app/views/LocationTracking.js b/app/views/LocationTracking.js index ac66986c4b..e09eade4c6 100644 --- a/app/views/LocationTracking.js +++ b/app/views/LocationTracking.js @@ -1,287 +1,399 @@ -import React, { - Component -} from 'react'; +import React, { Component } from 'react'; import { - SafeAreaView, - StyleSheet, - Linking, - View, - Text, - TouchableOpacity, - Dimensions, - Image, - ScrollView, - BackHandler, - Button + SafeAreaView, + StyleSheet, + Linking, + View, + Text, + TouchableOpacity, + Dimensions, + Image, + ScrollView, + BackHandler, } from 'react-native'; -import colors from "../constants/colors"; +import { + Menu, + MenuOptions, + MenuOption, + MenuTrigger, +} from 'react-native-popup-menu'; +import colors from '../constants/colors'; import LocationServices from '../services/LocationService'; import BackgroundGeolocation from '@mauron85/react-native-background-geolocation'; import exportImage from './../assets/images/export.png'; import news from './../assets/images/newspaper.png'; - +import kebabIcon from './../assets/images/kebabIcon.png'; import pkLogo from './../assets/images/PKLogo.png'; -import {GetStoreData, SetStoreData} from '../helpers/General'; -import languages from './../locales/languages' +import { GetStoreData, SetStoreData } from '../helpers/General'; +import languages from './../locales/languages'; const width = Dimensions.get('window').width; class LocationTracking extends Component { - constructor(props) { - super(props); - - this.state = { - isLogging:'' - } - } + constructor(props) { + super(props); - componentDidMount() { - BackHandler.addEventListener("hardwareBackPress", this.handleBackPress); - GetStoreData('PARTICIPATE') - .then(isParticipating => { - console.log(isParticipating); - - if(isParticipating === 'true'){ - this.setState({ - isLogging:true - }) - this.willParticipate() - } - else{ - this.setState({ - isLogging:false - }) - } - }) - .catch(error => console.log(error)) - } - componentWillUnmount() { BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress); } + this.state = { + isLogging: '', + }; + } - handleBackPress = () => { - BackHandler.exitApp(); // works best when the goBack is async - return true; - }; - export() { - this.props.navigation.navigate('ExportScreen', {}) - } + componentDidMount() { + BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); + GetStoreData('PARTICIPATE') + .then(isParticipating => { + console.log(isParticipating); - import() { - this.props.navigation.navigate('ImportScreen', {}) - } + if (isParticipating === 'true') { + this.setState({ + isLogging: true, + }); + this.willParticipate(); + } else { + this.setState({ + isLogging: false, + }); + } + }) + .catch(error => console.log(error)); + } + componentWillUnmount() { + BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); + } - news() { - this.props.navigation.navigate('NewsScreen', {}) - } + handleBackPress = () => { + BackHandler.exitApp(); // works best when the goBack is async + return true; + }; + export() { + this.props.navigation.navigate('ExportScreen', {}); + } - willParticipate =()=> { - SetStoreData('PARTICIPATE', 'true').then(() => - LocationServices.start() - ); + import() { + this.props.navigation.navigate('ImportScreen', {}); + } - // Check and see if they actually authorized in the system dialog. - // If not, stop services and set the state to !isLogging - // Fixes tripleblindmarket/private-kit#129 - BackgroundGeolocation.checkStatus(({ authorization }) => { - if (authorization === BackgroundGeolocation.AUTHORIZED) { - this.setState({ - isLogging:true - }) - } else if (authorization === BackgroundGeolocation.NOT_AUTHORIZED) { - LocationServices.stop(this.props.navigation) - this.setState({ - isLogging:false - }) - } - }); - } + willParticipate = () => { + SetStoreData('PARTICIPATE', 'true').then(() => LocationServices.start()); - setOptOut =()=>{ - LocationServices.stop(this.props.navigation) + // Check and see if they actually authorized in the system dialog. + // If not, stop services and set the state to !isLogging + // Fixes tripleblindmarket/private-kit#129 + BackgroundGeolocation.checkStatus(({ authorization }) => { + if (authorization === BackgroundGeolocation.AUTHORIZED) { this.setState({ - isLogging:false - }) - } + isLogging: true, + }); + } else if (authorization === BackgroundGeolocation.NOT_AUTHORIZED) { + LocationServices.stop(this.props.navigation); + this.setState({ + isLogging: false, + }); + } + }); + }; + + news() { + this.props.navigation.navigate('NewsScreen', {}); + } - render() { - return ( - + licenses() { + this.props.navigation.navigate('LicensesScreen', {}); + } - - - + willParticipate = () => { + SetStoreData('PARTICIPATE', 'true').then(() => LocationServices.start()); + this.setState({ + isLogging: true, + }); + }; - {languages.t('label.private_kit')} + setOptOut = () => { + LocationServices.stop(this.props.navigation); + this.setState({ + isLogging: false, + }); + }; - { - this.state.isLogging ? ( - <> - + render() { + return ( + + + + {/* A modal menu. Currently only used for license info */} + + + + + + { + this.licenses(); + }}> + Licenses + + + + + + {languages.t('label.private_kit')} + - this.setOptOut()} style={styles.stopLoggingButtonTouchable} > - {languages.t('label.stop_logging')} - - - ) : ( - <> - - this.willParticipate()} style={styles.startLoggingButtonTouchable} > - {languages.t('label.start_logging')} - - ) - } + {this.state.isLogging ? ( + <> + - - {this.state.isLogging ? - {languages.t('label.logging_message')} : - {languages.t('label.not_logging_message')} } - + this.setOptOut()} + style={styles.stopLoggingButtonTouchable}> + + {languages.t('label.stop_logging')} + + + + ) : ( + <> + + this.willParticipate()} + style={styles.startLoggingButtonTouchable}> + + {languages.t('label.start_logging')} + + + + )} - - + {this.state.isLogging ? ( + + {languages.t('label.logging_message')} + + ) : ( + + {languages.t('label.not_logging_message')} + + )} + + - - this.import()} style={styles.actionButtonsTouchable}> - - {languages.t('label.import')} - + + this.import()} + style={styles.actionButtonsTouchable}> + + + {languages.t('label.import')} + + - this.export()} style={styles.actionButtonsTouchable}> - - {languages.t('label.export')} - + this.export()} + style={styles.actionButtonsTouchable}> + + + {languages.t('label.export')} + + - this.news()} style={styles.actionButtonsTouchable}> - - {languages.t('label.news')} - - - + this.news()} + style={styles.actionButtonsTouchable}> + + + {languages.t('label.news')} + + + + - - {languages.t('label.url_info')} - Linking.openURL('https://privatekit.mit.edu')}>{languages.t('label.private_kit_url')} - - - ) - } + + + {languages.t('label.url_info')}{' '} + + Linking.openURL('https://privatekit.mit.edu')}> + {languages.t('label.private_kit_url')} + + + + ); + } } const styles = StyleSheet.create({ - // Container covers the entire screen - container: { - flex: 1, - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - color: colors.PRIMARY_TEXT, - backgroundColor: colors.WHITE, - }, - headerTitle: { - textAlign: 'center', - fontSize: 38, - padding: 0, - fontFamily:'OpenSans-Bold' - }, - subHeaderTitle: { - textAlign: 'center', - fontWeight: "bold", - fontSize: 22, - padding: 5 - }, - main: { - flex: 1, - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - width: "80%" - }, - block: { - margin: 20, - width: "100%" - }, - footer: { - textAlign: 'center', - fontSize: 12, - fontWeight: '600', - padding: 4, - paddingBottom: 10 - }, - intro: { - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'stretch', - }, - sectionDescription: { - fontSize: 12, - lineHeight: 24, - fontFamily:'OpenSans-Regular', - marginTop: 20, - marginLeft: 10, - marginRight: 10 - }, - startLoggingButtonTouchable:{ - borderRadius: 12, - backgroundColor: "#665eff", - height:52, - alignSelf:'center', - width:width*.7866, - marginTop:30, - justifyContent:'center' - }, - startLoggingButtonText:{ - fontFamily: "OpenSans-Bold", - fontSize: 14, - lineHeight: 19, - letterSpacing: 0, - textAlign: "center", - color: "#ffffff" - }, - stopLoggingButtonTouchable:{ - borderRadius: 12, - backgroundColor: "#fd4a4a", - height:52, - alignSelf:'center', - width:width*.7866, - marginTop:30, - justifyContent:'center', - }, - stopLoggingButtonText:{ - fontFamily: "OpenSans-Bold", - fontSize: 14, - lineHeight: 19, - letterSpacing: 0, - textAlign: "center", - color: "#ffffff" - }, - actionButtonsView:{ - width:width*.7866, - flexDirection:'row', - justifyContent:'space-between', - marginTop:64 - }, - actionButtonsTouchable:{ - height: 76, - borderRadius: 8, - backgroundColor: "#454f63", - width:width*.23, - justifyContent:'center', - alignItems:'center' - }, - actionButtonImage:{ - height:21.6, - width:32.2 - }, - actionButtonText:{ - opacity: 0.56, - fontFamily: "OpenSans-Bold", - fontSize: 12, - lineHeight: 17, - letterSpacing: 0, - textAlign: "center", - color: "#ffffff", - marginTop:6 - } + // Container covers the entire screen + container: { + flex: 1, + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + color: colors.PRIMARY_TEXT, + backgroundColor: colors.WHITE, + }, + headerTitle: { + textAlign: 'center', + fontSize: 38, + padding: 0, + fontFamily: 'OpenSans-Bold', + }, + subHeaderTitle: { + textAlign: 'center', + fontWeight: 'bold', + fontSize: 22, + padding: 5, + }, + main: { + flex: 1, + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + width: '80%', + }, + block: { + margin: 20, + width: '100%', + }, + footer: { + textAlign: 'center', + fontSize: 12, + fontWeight: '600', + padding: 4, + paddingBottom: 10, + }, + intro: { + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'stretch', + }, + sectionDescription: { + fontSize: 12, + lineHeight: 24, + fontFamily: 'OpenSans-Regular', + marginTop: 20, + marginLeft: 10, + marginRight: 10, + }, + startLoggingButtonTouchable: { + borderRadius: 12, + backgroundColor: '#665eff', + height: 52, + alignSelf: 'center', + width: width * 0.7866, + marginTop: 30, + justifyContent: 'center', + }, + startLoggingButtonText: { + fontFamily: 'OpenSans-Bold', + fontSize: 14, + lineHeight: 19, + letterSpacing: 0, + textAlign: 'center', + color: '#ffffff', + }, + stopLoggingButtonTouchable: { + borderRadius: 12, + backgroundColor: '#fd4a4a', + height: 52, + alignSelf: 'center', + width: width * 0.7866, + marginTop: 30, + justifyContent: 'center', + }, + stopLoggingButtonText: { + fontFamily: 'OpenSans-Bold', + fontSize: 14, + lineHeight: 19, + letterSpacing: 0, + textAlign: 'center', + color: '#ffffff', + }, + actionButtonsView: { + width: width * 0.7866, + flexDirection: 'row', + justifyContent: 'space-between', + marginTop: 64, + }, + actionButtonsTouchable: { + height: 76, + borderRadius: 8, + backgroundColor: '#454f63', + width: width * 0.23, + justifyContent: 'center', + alignItems: 'center', + }, + actionButtonImage: { + height: 21.6, + width: 32.2, + }, + actionButtonText: { + opacity: 0.56, + fontFamily: 'OpenSans-Bold', + fontSize: 12, + lineHeight: 17, + letterSpacing: 0, + textAlign: 'center', + color: '#ffffff', + marginTop: 6, + }, + menuOptionText: { + fontFamily: 'OpenSans-Regular', + fontSize: 14, + padding: 10, + }, }); export default LocationTracking; diff --git a/dev_setup.sh b/dev_setup.sh old mode 100644 new mode 100755 diff --git a/package.json b/package.json index 1aeac2a3c4..c28896897f 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "react-native-fs": "^2.16.6", "react-native-gesture-handler": "~1.5.0", "react-native-i18n": "^2.0.15", + "react-native-popup-menu": "^0.15.7", "react-native-push-notification": "^3.1.9", "react-native-safe-area-context": "0.6.0", "react-native-screens": "2.0.0-alpha.12", diff --git a/yarn.lock b/yarn.lock index 252a04061a..0c17a4914e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -631,6 +631,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.3.1": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.0.0", "@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" @@ -1074,6 +1081,11 @@ dependencies: invariant "^2.2.4" +"@react-native-community/viewpager@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@react-native-community/viewpager/-/viewpager-3.3.0.tgz#e613747a43a31a6f3278f817ba96fdaaa7941f23" + integrity sha512-tyzh79l4t/hxiyS9QD3LRmWMs8KVkZzjrkQ8U8+8To1wmvVCBtp8BenvNsDLTBO7CpO/YmiThpmIdEZMr1WuVw== + "@react-navigation/core@^5.2.1": version "5.2.1" resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-5.2.1.tgz#8fae1b40b3fbaeb70c6182e00899a2e4d281a12f" @@ -2175,6 +2187,11 @@ cross-spawn@^7.0.0: shebang-command "^2.0.0" which "^2.0.1" +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + integrity sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA= + cssom@^0.4.1: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" @@ -3304,6 +3321,18 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +i18n-js@3.0.11: + version "3.0.11" + resolved "https://registry.yarnpkg.com/i18n-js/-/i18n-js-3.0.11.tgz#f9e96bdb641c5b9d6be12759d7c422089987ef02" + integrity sha512-v7dG3kYJTQTyox3NqDabPDE/ZotWntyMI9kh4cYi+XlCSnsIR+KBTS2opPyObL8WndnklcLzbNU92FP/mLge3Q== + +i18next@^19.3.3: + version "19.3.3" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.3.3.tgz#04bd79b315e5fe2c87ab8f411e5d55eda0a17bd8" + integrity sha512-CnuPqep5/JsltkGvQqzYN4d79eCe0TreCBRF3a8qHHi8x4SON1qqZ/pvR2X7BfNkNqpA5HXIqw0E731H+VsgSg== + dependencies: + "@babel/runtime" "^7.3.1" + iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -5102,6 +5131,11 @@ object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +object-resolve-path@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-resolve-path/-/object-resolve-path-1.1.1.tgz#a7f8f93e8a20af80e44217ba7db54316d9d12232" + integrity sha1-p/j5Poogr4DkQhe6fbVDFtnRIjI= + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -5623,6 +5657,19 @@ react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" integrity sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA== +react-native-app-intro-slider@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-native-app-intro-slider/-/react-native-app-intro-slider-3.0.0.tgz#c3620b967503ce410b3d767252392bb6fb2edf97" + integrity sha512-2XXUYnSeMYZTLhdRYHSwv8mhoyuEaYxmQfXrWQInH1QvjsnJtKgvORI3bJuJN+tNPg3aut6JYYCNOFsI5of32A== + +react-native-extended-stylesheet@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/react-native-extended-stylesheet/-/react-native-extended-stylesheet-0.12.0.tgz#ebacf22d78a8e2173bdef2a08cbf1acba4dc051f" + integrity sha512-y4MEI+a9F8qtAKEjxKbwqotJg1FqKfl6vaiF25ULZ/VGkWI4GNTnsFunU9x6B3XJ6ly1E8O9fybO63u6UazL/A== + dependencies: + css-mediaquery "^0.1.2" + object-resolve-path "^1.1.0" + react-native-fs@^2.16.6: version "2.16.6" resolved "https://registry.yarnpkg.com/react-native-fs/-/react-native-fs-2.16.6.tgz#2901789a43210a35a0ef0a098019bbef3af395fd" @@ -5642,11 +5689,23 @@ react-native-gesture-handler@~1.5.0: invariant "^2.2.4" prop-types "^15.7.2" +react-native-i18n@^2.0.15: + version "2.0.15" + resolved "https://registry.yarnpkg.com/react-native-i18n/-/react-native-i18n-2.0.15.tgz#09b5a9836116fa7dbd0054c46e2d1014c1ef3c65" + integrity sha512-V8VwUP0TLda3oJvgt5tdnFaOV7WXPhTjCTLO7sXI3C2SHggSbD4bCUryMzNJhesimJidH21V2Owvj4zAylHoQQ== + dependencies: + i18n-js "3.0.11" + react-native-iphone-x-helper@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.2.1.tgz#645e2ffbbb49e80844bb4cbbe34a126fda1e6772" integrity sha512-/VbpIEp8tSNNHIvstuA3Swx610whci1Zpc9mqNkqn14DkMbw+ORviln2u0XyHG1kPvvwTNGZY6QpeFwxYaSdbQ== +react-native-popup-menu@^0.15.7: + version "0.15.7" + resolved "https://registry.yarnpkg.com/react-native-popup-menu/-/react-native-popup-menu-0.15.7.tgz#ddffa8aa6e5d7d11533947921e9bdf94cd7fc7d0" + integrity sha512-TgPVGQdsHPgynn+mMpTX51QKKhavDXI3tA879zylRUBMrxfNiR3gAWNanI1Sd5X4Sv0tZ1/A33k/gNTwciMDDg== + react-native-push-notification@^3.1.9: version "3.1.9" resolved "https://registry.yarnpkg.com/react-native-push-notification/-/react-native-push-notification-3.1.9.tgz#760ee06e743fef74fc9fcb672dac40794fdc4c47" @@ -5797,6 +5856,11 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" From 1390f9e74a5cbe745e0564568137067df5dcaff2 Mon Sep 17 00:00:00 2001 From: Sam Stowers Date: Sun, 22 Mar 2020 13:10:34 -0500 Subject: [PATCH 08/24] Formatted all JS files with Prettier (#147) --- app/Entry.js | 93 +-- app/components/Button.js | 27 +- app/constants/colors.js | 26 +- app/helpers/General.js | 44 +- app/helpers/GoogleData.js | 85 +-- app/helpers/GoogleTakeOutAutoImport.js | 126 ++-- app/helpers/convertPointsToString.js | 89 +-- app/locales/de/index.js | 12 +- app/locales/fr/index.js | 12 +- app/locales/hi/index.js | 12 +- app/locales/it/index.js | 12 +- app/locales/languages.js | 39 +- app/locales/pt/index.js | 12 +- app/services/LocationService.js | 559 +++++++++--------- app/views/Export.js | 362 ++++++------ app/views/Import.js | 245 ++++---- app/views/Licenses.js | 21 +- app/views/News.js | 217 ++++--- app/views/Welcome.js | 230 +++---- app/views/welcomeScreens/Intro1.js | 220 ++++--- app/views/welcomeScreens/Intro2.js | 279 +++++---- app/views/welcomeScreens/Intro3.js | 283 +++++---- app/views/welcomeScreens/ReactNativeSwiper.js | 79 ++- app/views/welcomeScreens/Slider.js | 24 +- index.js | 4 +- 25 files changed, 1633 insertions(+), 1479 deletions(-) diff --git a/app/Entry.js b/app/Entry.js index 723eb64c3d..744b869859 100644 --- a/app/Entry.js +++ b/app/Entry.js @@ -1,8 +1,8 @@ -import React, {Component } from 'react'; +import React, { Component } from 'react'; -import {NavigationContainer} from '@react-navigation/native'; -import {createStackNavigator} from '@react-navigation/stack'; -import {SafeAreaView} from 'react-native'; +import { NavigationContainer } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; +import { SafeAreaView } from 'react-native'; import LocationTracking from './views/LocationTracking'; import Welcome from './views/Welcome'; import NewsScreen from './views/News'; @@ -10,87 +10,92 @@ import ExportScreen from './views/Export'; import ImportScreen from './views/Import'; import LicencesScreen from './views/Licenses'; import Slider from './views/welcomeScreens/Slider'; -import {GetStoreData, SetStoreData} from './helpers/General'; +import { GetStoreData, SetStoreData } from './helpers/General'; const Stack = createStackNavigator(); class Entry extends Component { - constructor(props) { - super(props); - this.state={ - initialRouteName:'' - } - } + constructor(props) { + super(props); + this.state = { + initialRouteName: '', + }; + } - componentDidMount(){ - GetStoreData('PARTICIPATE') + componentDidMount() { + GetStoreData('PARTICIPATE') .then(isParticipating => { - console.log(isParticipating); - this.setState({ - initialRouteName:isParticipating - }) + console.log(isParticipating); + this.setState({ + initialRouteName: isParticipating, + }); }) - .catch(error => console.log(error)) - } + .catch(error => console.log(error)); + } - render() { - return ( - - - + render() { + return ( + + + {this.state.initialRouteName === 'true' ? ( - ):( + name="InitialScreen" + component={LocationTracking} + options={{ headerShown: false }} + /> + ) : ( + name="InitialScreen" + component={Slider} + options={{ headerShown: false }} + /> )} + - - - ) - } + + + ); + } } export default Entry; diff --git a/app/components/Button.js b/app/components/Button.js index 6835648f2c..137ee48a45 100644 --- a/app/components/Button.js +++ b/app/components/Button.js @@ -1,6 +1,6 @@ -import * as React from "react"; -import { StyleSheet, Text, TouchableOpacity } from "react-native"; -import colors from "../constants/colors"; +import * as React from 'react'; +import { StyleSheet, Text, TouchableOpacity } from 'react-native'; +import colors from '../constants/colors'; interface Props { label: string; @@ -12,7 +12,12 @@ class Button extends React.Component { render() { const { title, onPress, bgColor } = this.props; return ( - + {title} ); @@ -21,21 +26,21 @@ class Button extends React.Component { const styles = StyleSheet.create({ container: { - width: "100%", - alignItems: "center", - justifyContent: "center", + width: '100%', + alignItems: 'center', + justifyContent: 'center', paddingVertical: 12, borderRadius: 4, borderWidth: StyleSheet.hairlineWidth, - borderColor: "rgba(255,255,255,0.7)" + borderColor: 'rgba(255,255,255,0.7)', }, text: { color: colors.WHITE, - textAlign: "center", + textAlign: 'center', height: 28, fontSize: 20, fontWeight: '600', - } + }, }); -export default Button; \ No newline at end of file +export default Button; diff --git a/app/constants/colors.js b/app/constants/colors.js index 292c4fdb88..0e54e2230d 100644 --- a/app/constants/colors.js +++ b/app/constants/colors.js @@ -1,19 +1,19 @@ const colors = { - BLACK: "#000", - WHITE: "#FFF", - DODGER_BLUE: "#428AF8", - SILVER: "#BEBEBE", - TORCH_RED: "#F8262F", - MISCHKA: "#E5E4E6", + BLACK: '#000', + WHITE: '#FFF', + DODGER_BLUE: '#428AF8', + SILVER: '#BEBEBE', + TORCH_RED: '#F8262F', + MISCHKA: '#E5E4E6', APP_BACKGROUND: '#FFF8ED', - PRIMARY_TEXT: "#000", - GREEN: "#32A852", - VIOLET: "#6C3794", + PRIMARY_TEXT: '#000', + GREEN: '#32A852', + VIOLET: '#6C3794', - REG_BUTTON: "#428AF8", - POS_BUTTON: "#32A852", - NEG_BUTTON: "#F8262F", - SENS_BUTTON: "#6C3794" + REG_BUTTON: '#428AF8', + POS_BUTTON: '#32A852', + NEG_BUTTON: '#F8262F', + SENS_BUTTON: '#6C3794', }; export default colors; diff --git a/app/helpers/General.js b/app/helpers/General.js index 6f0805edd4..bb874bcf0f 100644 --- a/app/helpers/General.js +++ b/app/helpers/General.js @@ -9,18 +9,18 @@ import _ from 'lodash'; * @param {boolean} isString */ export async function GetStoreData(key, isString = true) { - try { - let data = await AsyncStorage.getItem(key); + try { + let data = await AsyncStorage.getItem(key); - if (isString) { - return data; - } + if (isString) { + return data; + } - return JSON.parse(data); - } catch (error) { - console.log(error.message); - } - return false; + return JSON.parse(data); + } catch (error) { + console.log(error.message); + } + return false; } /** @@ -30,16 +30,16 @@ export async function GetStoreData(key, isString = true) { * @param {string} key * @param {object} item */ -export async function SetStoreData (key, item) { - try { - //we want to wait for the Promise returned by AsyncStorage.setItem() - //to be resolved to the actual value before returning the value - if (typeof item !== 'string') { - item = JSON.stringify(item); - } +export async function SetStoreData(key, item) { + try { + //we want to wait for the Promise returned by AsyncStorage.setItem() + //to be resolved to the actual value before returning the value + if (typeof item !== 'string') { + item = JSON.stringify(item); + } - return await AsyncStorage.setItem(key, item); - } catch (error) { - console.log(error.message); - } -} \ No newline at end of file + return await AsyncStorage.setItem(key, item); + } catch (error) { + console.log(error.message); + } +} diff --git a/app/helpers/GoogleData.js b/app/helpers/GoogleData.js index ebe8f37569..dfffb261da 100644 --- a/app/helpers/GoogleData.js +++ b/app/helpers/GoogleData.js @@ -1,65 +1,66 @@ /** - * Import a Google JSon into the Database. + * Import a Google JSon into the Database. */ import { GetStoreData, SetStoreData } from '../helpers/General'; function BuildLocalFormat(placeVisit) { - return loc = { - latitude: (placeVisit.location.latitudeE7 * (10 ** -7)), - longitude: (placeVisit.location.longitudeE7 * (10 ** -7)), - time: placeVisit.duration.startTimestampMs - }; + return (loc = { + latitude: placeVisit.location.latitudeE7 * 10 ** -7, + longitude: placeVisit.location.longitudeE7 * 10 ** -7, + time: placeVisit.duration.startTimestampMs, + }); } function LocationExists(localDataJSON, loc) { - var wasImportedBefore = false; + var wasImportedBefore = false; - for (var index = 0; index < localDataJSON.length; ++index) { - var storedLoc = localDataJSON[index]; - if (storedLoc.latitude == loc.latitude && - storedLoc.longitude == loc.longitude && - storedLoc.time == loc.time) { - wasImportedBefore = true; - break; - } + for (var index = 0; index < localDataJSON.length; ++index) { + var storedLoc = localDataJSON[index]; + if ( + storedLoc.latitude == loc.latitude && + storedLoc.longitude == loc.longitude && + storedLoc.time == loc.time + ) { + wasImportedBefore = true; + break; } + } - return wasImportedBefore; + return wasImportedBefore; } function InsertIfNew(localDataJSON, loc) { - if (!LocationExists(localDataJSON, loc)) { - console.log("Importing", loc); - localDataJSON.push(loc); - } else { - console.log("Existing", loc, localDataJSON.indexOf(loc)); - } + if (!LocationExists(localDataJSON, loc)) { + console.log('Importing', loc); + localDataJSON.push(loc); + } else { + console.log('Existing', loc, localDataJSON.indexOf(loc)); + } } function Merge(localDataJSON, googleDataJSON) { - googleDataJSON.timelineObjects.map(function (data, index) { - // Only import visited places, not paths for now - if (data.placeVisit) { - var loc = BuildLocalFormat(data.placeVisit); - InsertIfNew(localDataJSON, loc); - } - }); + googleDataJSON.timelineObjects.map(function(data, index) { + // Only import visited places, not paths for now + if (data.placeVisit) { + var loc = BuildLocalFormat(data.placeVisit); + InsertIfNew(localDataJSON, loc); + } + }); } export async function MergeJSONWithLocalData(googleDataJSON) { - GetStoreData('LOCATION_DATA') - .then(locationArray => { - var locationData; + GetStoreData('LOCATION_DATA').then(locationArray => { + var locationData; - if (locationArray !== null) { - locationData = JSON.parse(locationArray); - } else { - locationData = []; - } + if (locationArray !== null) { + locationData = JSON.parse(locationArray); + } else { + locationData = []; + } - Merge(locationData, googleDataJSON); + Merge(locationData, googleDataJSON); - console.log("Saving on array"); - SetStoreData('LOCATION_DATA', locationData); - }); -} \ No newline at end of file + console.log('Saving on array'); + SetStoreData('LOCATION_DATA', locationData); + }); +} diff --git a/app/helpers/GoogleTakeOutAutoImport.js b/app/helpers/GoogleTakeOutAutoImport.js index 276e524cfc..f7c6b3ca50 100644 --- a/app/helpers/GoogleTakeOutAutoImport.js +++ b/app/helpers/GoogleTakeOutAutoImport.js @@ -1,75 +1,99 @@ /** * Checks the download folder, unzips and imports all data from Google TakeOut */ -import { zip, unzip, unzipAssets, subscribe } from 'react-native-zip-archive' -import {MergeJSONWithLocalData} from '../helpers/GoogleData'; +import { zip, unzip, unzipAssets, subscribe } from 'react-native-zip-archive'; +import { MergeJSONWithLocalData } from '../helpers/GoogleData'; // require the module var RNFS = require('react-native-fs'); -// unzipping progress component. +// unzipping progress component. var progress; -// Google Takout File Format. +// Google Takout File Format. var takeoutZip = /^takeout[\w,\s-]+\.zip$/gm; -// Gets Path of the location file for the current month. +// Gets Path of the location file for the current month. function GetFileName() { - let monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + let monthNames = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; - var year = new Date().getFullYear(); - var month = monthNames[new Date().getMonth()].toUpperCase(); - return RNFS.DownloadDirectoryPath + "/Takeout/Location History/Semantic Location History/"+year+"/"+year+"_MARCH.json"; + var year = new Date().getFullYear(); + var month = monthNames[new Date().getMonth()].toUpperCase(); + return ( + RNFS.DownloadDirectoryPath + + '/Takeout/Location History/Semantic Location History/' + + year + + '/' + + year + + '_MARCH.json' + ); } export async function SearchAndImport(googleLocationJSON) { - console.log('Auto-import start'); + console.log('Auto-import start'); - // UnZip Progress Bar Log. - progress = subscribe(({ progress, filePath }) => { + // UnZip Progress Bar Log. + progress = subscribe(({ progress, filePath }) => { if (Math.trunc(progress * 100) % 10 === 0) - console.log('Unzipping', Math.trunc(progress * 100), '%'); - }); + console.log('Unzipping', Math.trunc(progress * 100), '%'); + }); + + // TODO: RNFS.DownloadDirectoryPath is not defined on iOS. + // Find out how to access Downloads folder. + if (!RNFS.DownloadDirectoryPath) { + return; + } - // TODO: RNFS.DownloadDirectoryPath is not defined on iOS. - // Find out how to access Downloads folder. - if (!RNFS.DownloadDirectoryPath) { - return; - } + RNFS.readDir(RNFS.DownloadDirectoryPath) + .then(result => { + console.log('Checking Downloads Folder'); - RNFS.readDir(RNFS.DownloadDirectoryPath) - .then((result) => { - console.log('Checking Downloads Folder'); - - // Looking for takeout*.zip files and unzipping them. - result.map(function(file, index){ - if (takeoutZip.test(file.name)) { - console.log(`Found Google Takeout {file.name} at {file.path}`, file.name); + // Looking for takeout*.zip files and unzipping them. + result.map(function(file, index) { + if (takeoutZip.test(file.name)) { + console.log( + `Found Google Takeout {file.name} at {file.path}`, + file.name, + ); - unzip(file.path, RNFS.DownloadDirectoryPath) - .then((path) => { - console.log(`Unzip Completed for ${path} and ${file.path}`); - - RNFS.readFile(GetFileName()).then((result) => { - console.log("Opened file"); - - MergeJSONWithLocalData(JSON.parse(result)); - progress.remove(); + unzip(file.path, RNFS.DownloadDirectoryPath) + .then(path => { + console.log(`Unzip Completed for ${path} and ${file.path}`); - }).catch((err) => { - console.log(err.message, err.code); - progress.remove(); - }); - }) - .catch((error) => { - console.log(error); - progress.remove(); - }); - } + RNFS.readFile(GetFileName()) + .then(result => { + console.log('Opened file'); + + MergeJSONWithLocalData(JSON.parse(result)); + progress.remove(); + }) + .catch(err => { + console.log(err.message, err.code); + progress.remove(); + }); + }) + .catch(error => { + console.log(error); + progress.remove(); }); - }) - .catch((err) => { - console.log(err.message, err.code); - progress.remove(); - }); + } + }); + }) + .catch(err => { + console.log(err.message, err.code); + progress.remove(); + }); } diff --git a/app/helpers/convertPointsToString.js b/app/helpers/convertPointsToString.js index cdb0ab4fa6..97e653e9de 100644 --- a/app/helpers/convertPointsToString.js +++ b/app/helpers/convertPointsToString.js @@ -1,50 +1,51 @@ -export function convertPointsToString(count){ - - // For testing Manually override count - // count = 3000 +export function convertPointsToString(count) { + // For testing Manually override count + // count = 3000 - // Get minutes - let tot_mins = count * 5; + // Get minutes + let tot_mins = count * 5; - // Calculate days - var days = (tot_mins / 60/ 24); - var rdays = Math.floor(days); + // Calculate days + var days = tot_mins / 60 / 24; + var rdays = Math.floor(days); - // Calculate Hours - var hours = (days - rdays) * 24; - var rhours = Math.floor(hours); + // Calculate Hours + var hours = (days - rdays) * 24; + var rhours = Math.floor(hours); - // Calculate Minutes - var minutes = (hours - rhours) * 60; - var rminutes = Math.round(minutes); + // Calculate Minutes + var minutes = (hours - rhours) * 60; + var rminutes = Math.round(minutes); - if(rdays > 0){ - if(rdays > 1){ - if(rhours > 1){ - return rdays + " days, " + rhours + " hours and " + rminutes + " minutes."; - } - else{ - return rdays + " days, " + rhours + " hour and " + rminutes + " minutes."; - } - } - else{ - if(rhours > 1){ - return rdays + " day, " + rhours + " hours and " + rminutes + " minutes."; - } - else{ - return rdays + " day, " + rhours + " hour and " + rminutes + " minutes."; - } - } - } - else if(rhours > 0 ){ - if(rhours > 1){ - return rhours + " hours and " + rminutes + " minutes."; - } - else{ - return rhours + " hour and " + rminutes + " minutes."; - } - } - else{ - return rminutes + " minutes."; + if (rdays > 0) { + if (rdays > 1) { + if (rhours > 1) { + return ( + rdays + ' days, ' + rhours + ' hours and ' + rminutes + ' minutes.' + ); + } else { + return ( + rdays + ' days, ' + rhours + ' hour and ' + rminutes + ' minutes.' + ); + } + } else { + if (rhours > 1) { + return ( + rdays + ' day, ' + rhours + ' hours and ' + rminutes + ' minutes.' + ); + } else { + return ( + rdays + ' day, ' + rhours + ' hour and ' + rminutes + ' minutes.' + ); + } } - } \ No newline at end of file + } else if (rhours > 0) { + if (rhours > 1) { + return rhours + ' hours and ' + rminutes + ' minutes.'; + } else { + return rhours + ' hour and ' + rminutes + ' minutes.'; + } + } else { + return rminutes + ' minutes.'; + } +} diff --git a/app/locales/de/index.js b/app/locales/de/index.js index 77d79a8a10..c63e419c7e 100644 --- a/app/locales/de/index.js +++ b/app/locales/de/index.js @@ -1,11 +1,11 @@ import intro from './intro.json'; import locationTracking from './locationTracking.json'; -import importFile from './import.json' -import exportFile from './exportscreen.json' +import importFile from './import.json'; +import exportFile from './exportscreen.json'; export default { - ...intro, - ...locationTracking, - ...importFile, - ...exportFile + ...intro, + ...locationTracking, + ...importFile, + ...exportFile, }; diff --git a/app/locales/fr/index.js b/app/locales/fr/index.js index 77d79a8a10..c63e419c7e 100644 --- a/app/locales/fr/index.js +++ b/app/locales/fr/index.js @@ -1,11 +1,11 @@ import intro from './intro.json'; import locationTracking from './locationTracking.json'; -import importFile from './import.json' -import exportFile from './exportscreen.json' +import importFile from './import.json'; +import exportFile from './exportscreen.json'; export default { - ...intro, - ...locationTracking, - ...importFile, - ...exportFile + ...intro, + ...locationTracking, + ...importFile, + ...exportFile, }; diff --git a/app/locales/hi/index.js b/app/locales/hi/index.js index 77d79a8a10..c63e419c7e 100644 --- a/app/locales/hi/index.js +++ b/app/locales/hi/index.js @@ -1,11 +1,11 @@ import intro from './intro.json'; import locationTracking from './locationTracking.json'; -import importFile from './import.json' -import exportFile from './exportscreen.json' +import importFile from './import.json'; +import exportFile from './exportscreen.json'; export default { - ...intro, - ...locationTracking, - ...importFile, - ...exportFile + ...intro, + ...locationTracking, + ...importFile, + ...exportFile, }; diff --git a/app/locales/it/index.js b/app/locales/it/index.js index 77d79a8a10..c63e419c7e 100644 --- a/app/locales/it/index.js +++ b/app/locales/it/index.js @@ -1,11 +1,11 @@ import intro from './intro.json'; import locationTracking from './locationTracking.json'; -import importFile from './import.json' -import exportFile from './exportscreen.json' +import importFile from './import.json'; +import exportFile from './exportscreen.json'; export default { - ...intro, - ...locationTracking, - ...importFile, - ...exportFile + ...intro, + ...locationTracking, + ...importFile, + ...exportFile, }; diff --git a/app/locales/languages.js b/app/locales/languages.js index d126c0b4a3..4488334afa 100644 --- a/app/locales/languages.js +++ b/app/locales/languages.js @@ -3,66 +3,65 @@ import { getLanguages } from 'react-native-i18n'; // Refer this for checking the codes and creating new folders https://developer.chrome.com/webstore/i18n // Step 1 - Create index.js files for each language we want to have, in this file you can import all the json files (Step 4) and export them -// Step 2 - Import them with a unique title +// Step 2 - Import them with a unique title // Step 3 - Add these titles under the resources object in the i18next.init function // Step 4 - Create separate json files for various sections under the language folder ex. en/intro1.json // Step 5 - Add the labels to be used in repective json files. The labels are the key and the content is the value in different language, so make sure for each file the key remains the same // Step 6 - In React Native code import the main languages file and call the translate function - languages.t('label.labelname') -import enlabels from './en'; +import enlabels from './en'; import delabels from './de'; import hilabels from './hi'; import frlabels from './fr'; import itlabels from './it'; import ptlabels from './pt'; - // This will fetch the user's language let userLang = undefined; getLanguages().then(languages => { userLang = languages[0].split('-')[0]; // ['en-US' will become 'en'] - i18next.changeLanguage(userLang); + i18next.changeLanguage(userLang); }); i18next.init({ interpolation: { // React already does escaping - escapeValue: false + escapeValue: false, }, lng: userLang, // 'en' | 'es', - fallbackLng: 'en', // If language detector fails + fallbackLng: 'en', // If language detector fails resources: { en: { translation: { - label: enlabels - } + label: enlabels, + }, }, de: { translation: { - label: delabels - } + label: delabels, + }, }, hi: { translation: { - label: hilabels - } + label: hilabels, + }, }, fr: { translation: { - label: frlabels - } + label: frlabels, + }, }, it: { translation: { - label: itlabels - } + label: itlabels, + }, }, pt: { translation: { - label: ptlabels - } - } - } + label: ptlabels, + }, + }, + }, }); export default i18next; diff --git a/app/locales/pt/index.js b/app/locales/pt/index.js index 77d79a8a10..c63e419c7e 100644 --- a/app/locales/pt/index.js +++ b/app/locales/pt/index.js @@ -1,11 +1,11 @@ import intro from './intro.json'; import locationTracking from './locationTracking.json'; -import importFile from './import.json' -import exportFile from './exportscreen.json' +import importFile from './import.json'; +import exportFile from './exportscreen.json'; export default { - ...intro, - ...locationTracking, - ...importFile, - ...exportFile + ...intro, + ...locationTracking, + ...importFile, + ...exportFile, }; diff --git a/app/services/LocationService.js b/app/services/LocationService.js index eca6c72c8f..df9ab2f6c7 100644 --- a/app/services/LocationService.js +++ b/app/services/LocationService.js @@ -1,116 +1,115 @@ -import { - GetStoreData, - SetStoreData -} from '../helpers/General'; +import { GetStoreData, SetStoreData } from '../helpers/General'; import BackgroundGeolocation from '@mauron85/react-native-background-geolocation'; import { Alert } from 'react-native'; -import PushNotificationIOS from "@react-native-community/push-notification-ios"; +import PushNotificationIOS from '@react-native-community/push-notification-ios'; -import PushNotification from "react-native-push-notification"; +import PushNotification from 'react-native-push-notification'; var instanceCount = 0; var lastPointCount = 0; -var locationInterval = 60000 * 5; // Time (in milliseconds) between location information polls. E.g. 60000*5 = 5 minutes +var locationInterval = 60000 * 5; // Time (in milliseconds) between location information polls. E.g. 60000*5 = 5 minutes // DEBUG: Reduce Time intervall for faster debugging // var locationInterval = 5000; function saveLocation(location) { - // Persist this location data in our local storage of time/lat/lon values - - GetStoreData('LOCATION_DATA') - .then(locationArrayString => { - - var locationArray; - if (locationArrayString !== null) { - locationArray = JSON.parse(locationArrayString); - } else { - locationArray = []; - } - - // Always work in UTC, not the local time in the locationData - var nowUTC = new Date().toISOString(); - var unixtimeUTC = Date.parse(nowUTC); - var unixtimeUTC_28daysAgo = unixtimeUTC - (60 * 60 * 24 * 1000 * 28); - - // Curate the list of points, only keep the last 28 days - var curated = []; - for (var i = 0; i < locationArray.length; i++) { - if (locationArray[i]["time"] > unixtimeUTC_28daysAgo) { - curated.push(locationArray[i]); - } - } - - // Backfill the stationary points, if available - if (curated.length >= 1) { - var lastLocationArray = curated[curated.length - 1]; - var lastTS = lastLocationArray["time"]; - for (; lastTS < unixtimeUTC - locationInterval; lastTS += locationInterval) { - curated.push(JSON.parse(JSON.stringify(lastLocationArray))); - } - } - - // Save the location using the current lat-lon and the - // calculated UTC time (maybe a few milliseconds off from - // when the GPS data was collected, but that's unimportant - // for what we are doing.) - lastPointCount = locationArray.length; - console.log('[GPS] Saving point:', lastPointCount) - var lat_lon_time = { - "latitude": location["latitude"], - "longitude": location["longitude"], - "time": unixtimeUTC - }; - curated.push(lat_lon_time); - - SetStoreData('LOCATION_DATA', curated); - }); -} + // Persist this location data in our local storage of time/lat/lon values + + GetStoreData('LOCATION_DATA').then(locationArrayString => { + var locationArray; + if (locationArrayString !== null) { + locationArray = JSON.parse(locationArrayString); + } else { + locationArray = []; + } + // Always work in UTC, not the local time in the locationData + var nowUTC = new Date().toISOString(); + var unixtimeUTC = Date.parse(nowUTC); + var unixtimeUTC_28daysAgo = unixtimeUTC - 60 * 60 * 24 * 1000 * 28; + + // Curate the list of points, only keep the last 28 days + var curated = []; + for (var i = 0; i < locationArray.length; i++) { + if (locationArray[i]['time'] > unixtimeUTC_28daysAgo) { + curated.push(locationArray[i]); + } + } + + // Backfill the stationary points, if available + if (curated.length >= 1) { + var lastLocationArray = curated[curated.length - 1]; + var lastTS = lastLocationArray['time']; + for ( + ; + lastTS < unixtimeUTC - locationInterval; + lastTS += locationInterval + ) { + curated.push(JSON.parse(JSON.stringify(lastLocationArray))); + } + } + + // Save the location using the current lat-lon and the + // calculated UTC time (maybe a few milliseconds off from + // when the GPS data was collected, but that's unimportant + // for what we are doing.) + lastPointCount = locationArray.length; + console.log('[GPS] Saving point:', lastPointCount); + var lat_lon_time = { + latitude: location['latitude'], + longitude: location['longitude'], + time: unixtimeUTC, + }; + curated.push(lat_lon_time); + + SetStoreData('LOCATION_DATA', curated); + }); +} export default class LocationServices { - static start() { - instanceCount += 1 - if (instanceCount > 1) { - BackgroundGeolocation.start(); - return; - } + static start() { + instanceCount += 1; + if (instanceCount > 1) { + BackgroundGeolocation.start(); + return; + } - PushNotification.configure({ - // (required) Called when a remote or local notification is opened or received - onNotification: function(notification) { - console.log("NOTIFICATION:", notification); - // required on iOS only (see fetchCompletionHandler docs: https://github.com/react-native-community/react-native-push-notification-ios) - notification.finish(PushNotificationIOS.FetchResult.NoData); - }, - requestPermissions: true - }); - - // PushNotificationIOS.requestPermissions(); - BackgroundGeolocation.configure({ - desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY, - stationaryRadius: 5, - distanceFilter: 5, - notificationTitle: 'Private Kit Enabled', - notificationText: 'Private Kit is securely storing your GPS coordinates once every five minutes on this device.', - debug: false, // when true, it beeps every time a loc is read - startOnBoot: true, - stopOnTerminate: false, - locationProvider: BackgroundGeolocation.DISTANCE_FILTER_PROVIDER, - - interval: locationInterval, - fastestInterval: locationInterval, - activitiesInterval: locationInterval, - - activityType: "AutomotiveNavigation", - pauseLocationUpdates: false, - saveBatteryOnBackground: true, - stopOnStillActivity: false, - }); - - BackgroundGeolocation.on('location', (location) => { - // handle your locations here - /* SAMPLE OF LOCATION DATA OBJECT + PushNotification.configure({ + // (required) Called when a remote or local notification is opened or received + onNotification: function(notification) { + console.log('NOTIFICATION:', notification); + // required on iOS only (see fetchCompletionHandler docs: https://github.com/react-native-community/react-native-push-notification-ios) + notification.finish(PushNotificationIOS.FetchResult.NoData); + }, + requestPermissions: true, + }); + + // PushNotificationIOS.requestPermissions(); + BackgroundGeolocation.configure({ + desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY, + stationaryRadius: 5, + distanceFilter: 5, + notificationTitle: 'Private Kit Enabled', + notificationText: + 'Private Kit is securely storing your GPS coordinates once every five minutes on this device.', + debug: false, // when true, it beeps every time a loc is read + startOnBoot: true, + stopOnTerminate: false, + locationProvider: BackgroundGeolocation.DISTANCE_FILTER_PROVIDER, + + interval: locationInterval, + fastestInterval: locationInterval, + activitiesInterval: locationInterval, + + activityType: 'AutomotiveNavigation', + pauseLocationUpdates: false, + saveBatteryOnBackground: true, + stopOnStillActivity: false, + }); + + BackgroundGeolocation.on('location', location => { + // handle your locations here + /* SAMPLE OF LOCATION DATA OBJECT { "accuracy": 20, "altitude": 5, "id": 114, "isFromMockProvider": false, "latitude": 37.4219983, "locationProvider": 1, "longitude": -122.084, @@ -118,174 +117,204 @@ export default class LocationServices { "time": 1583696413000 } */ - // to perform long running operation on iOS - // you need to create background task - BackgroundGeolocation.startTask(taskKey => { - // execute long running task - // eg. ajax post location - // IMPORTANT: task has to be ended by endTask - saveLocation(location); - BackgroundGeolocation.endTask(taskKey); - }); - }); - - if (Platform.OS === 'android') { - // This feature only is present on Android. - BackgroundGeolocation.headlessTask(async (event) => { - // Application was shutdown, but the headless mechanism allows us - // to capture events in the background. (On Android, at least) - if (event.name === 'location' || event.name === 'stationary') { - saveLocation(event.params); - } - }); + // to perform long running operation on iOS + // you need to create background task + BackgroundGeolocation.startTask(taskKey => { + // execute long running task + // eg. ajax post location + // IMPORTANT: task has to be ended by endTask + saveLocation(location); + BackgroundGeolocation.endTask(taskKey); + }); + }); + + if (Platform.OS === 'android') { + // This feature only is present on Android. + BackgroundGeolocation.headlessTask(async event => { + // Application was shutdown, but the headless mechanism allows us + // to capture events in the background. (On Android, at least) + if (event.name === 'location' || event.name === 'stationary') { + saveLocation(event.params); } - - BackgroundGeolocation.on('stationary', (stationaryLocation) => { - // handle stationary locations here - // Actions.sendLocation(stationaryLocation); - BackgroundGeolocation.startTask(taskKey => { - // execute long running task - // eg. ajax post location - // IMPORTANT: task has to be ended by endTask - - // For capturing stationaryLocation. Note that it hasn't been - // tested as I couldn't produce stationaryLocation callback in emulator - // but since the plugin documentation mentions it, no reason to keep - // it empty I believe. - saveLocation(stationaryLocation); - BackgroundGeolocation.endTask(taskKey); - }); - console.log('[INFO] stationaryLocation:', stationaryLocation); - }); - - BackgroundGeolocation.on('error', (error) => { - console.log('[ERROR] BackgroundGeolocation error:', error); - }); - - BackgroundGeolocation.on('start', () => { - console.log('[INFO] BackgroundGeolocation service has been started'); - }); - - BackgroundGeolocation.on('stop', () => { - console.log('[INFO] BackgroundGeolocation service has been stopped'); - }); - - BackgroundGeolocation.on('authorization', (status) => { - console.log('[INFO] BackgroundGeolocation authorization status: ' + status); - - if (status !== BackgroundGeolocation.AUTHORIZED) { - // we need to set delay or otherwise alert may not be shown - setTimeout(() => - Alert.alert('Private Kit requires access to location information', 'Would you like to open app settings?', [{ - text: 'Yes', - onPress: () => BackgroundGeolocation.showAppSettings() - }, - { - text: 'No', - onPress: () => console.log('No Pressed'), - style: 'cancel' - } - ]), 1000); - } - else { - BackgroundGeolocation.start(); //triggers start on start event - - // TODO: We reach this point on Android when location services are toggled off/on. - // When this fires, check if they are off and show a Notification in the tray - } - }); - - BackgroundGeolocation.on('background', () => { - console.log('[INFO] App is in background'); - }); - - BackgroundGeolocation.on('foreground', () => { - console.log('[INFO] App is in foreground'); - }); - - BackgroundGeolocation.on('abort_requested', () => { - console.log('[INFO] Server responded with 285 Updates Not Required'); - // Here we can decide whether we want stop the updates or not. - // If you've configured the server to return 285, then it means the server does not require further update. - // So the normal thing to do here would be to `BackgroundGeolocation.stop()`. - // But you might be counting on it to receive location updates in the UI, so you could just reconfigure and set `url` to null. - }); - - BackgroundGeolocation.on('http_authorization', () => { - console.log('[INFO] App needs to authorize the http requests'); - }); - - BackgroundGeolocation.on('stop', () => { - PushNotification.localNotification({ - title: "Location Tracking Was Disabled", - message: "Private Kit requires location services." - }); - console.log('[INFO] stop'); - }); - - BackgroundGeolocation.on('stationary', () => { - console.log('[INFO] stationary'); - }); - - BackgroundGeolocation.checkStatus(status => { - console.log('[INFO] BackgroundGeolocation service is running', status.isRunning); - console.log('[INFO] BackgroundGeolocation services enabled', status.locationServicesEnabled); - console.log('[INFO] BackgroundGeolocation auth status: ' + status.authorization); - - BackgroundGeolocation.start(); //triggers start on start event - - if (!status.locationServicesEnabled) { - // we need to set delay or otherwise alert may not be shown - setTimeout(() => - Alert.alert('Private Kit requires location services to be enabled', 'Would you like to open location settings?', [{ - text: 'Yes', - onPress: () => BackgroundGeolocation.showLocationSettings() - }, - { - text: 'No', - onPress: () => console.log('No Pressed'), - style: 'cancel' - } - ]), 1000); - } - else if (!status.authorization) { - // we need to set delay or otherwise alert may not be shown - setTimeout(() => - Alert.alert('Private Kit requires access to location information', 'Would you like to open app settings?', [{ - text: 'Yes', - onPress: () => BackgroundGeolocation.showAppSettings() - }, - { - text: 'No', - onPress: () => console.log('No Pressed'), - style: 'cancel' - } - ]), 1000); - } - else if (!status.isRunning) { - } - - }); - - // you can also just start without checking for status - // BackgroundGeolocation.start(); - } - - static getPointCount() { - return lastPointCount; + }); } - static stop(nav) { - // unregister all event listeners - PushNotification.localNotification({ - title: "Location Tracking Was Disabled", - message: "Private Kit requires location services." - }); - BackgroundGeolocation.removeAllListeners(); - BackgroundGeolocation.stop(); - instanceCount -= 1; - SetStoreData('PARTICIPATE', 'false').then(() => - nav.navigate('LocationTrackingScreen', {}) - ) - } + BackgroundGeolocation.on('stationary', stationaryLocation => { + // handle stationary locations here + // Actions.sendLocation(stationaryLocation); + BackgroundGeolocation.startTask(taskKey => { + // execute long running task + // eg. ajax post location + // IMPORTANT: task has to be ended by endTask + + // For capturing stationaryLocation. Note that it hasn't been + // tested as I couldn't produce stationaryLocation callback in emulator + // but since the plugin documentation mentions it, no reason to keep + // it empty I believe. + saveLocation(stationaryLocation); + BackgroundGeolocation.endTask(taskKey); + }); + console.log('[INFO] stationaryLocation:', stationaryLocation); + }); + + BackgroundGeolocation.on('error', error => { + console.log('[ERROR] BackgroundGeolocation error:', error); + }); + + BackgroundGeolocation.on('start', () => { + console.log('[INFO] BackgroundGeolocation service has been started'); + }); + + BackgroundGeolocation.on('stop', () => { + console.log('[INFO] BackgroundGeolocation service has been stopped'); + }); + + BackgroundGeolocation.on('authorization', status => { + console.log( + '[INFO] BackgroundGeolocation authorization status: ' + status, + ); + + if (status !== BackgroundGeolocation.AUTHORIZED) { + // we need to set delay or otherwise alert may not be shown + setTimeout( + () => + Alert.alert( + 'Private Kit requires access to location information', + 'Would you like to open app settings?', + [ + { + text: 'Yes', + onPress: () => BackgroundGeolocation.showAppSettings(), + }, + { + text: 'No', + onPress: () => console.log('No Pressed'), + style: 'cancel', + }, + ], + ), + 1000, + ); + } else { + BackgroundGeolocation.start(); //triggers start on start event + + // TODO: We reach this point on Android when location services are toggled off/on. + // When this fires, check if they are off and show a Notification in the tray + } + }); + + BackgroundGeolocation.on('background', () => { + console.log('[INFO] App is in background'); + }); + + BackgroundGeolocation.on('foreground', () => { + console.log('[INFO] App is in foreground'); + }); + + BackgroundGeolocation.on('abort_requested', () => { + console.log('[INFO] Server responded with 285 Updates Not Required'); + // Here we can decide whether we want stop the updates or not. + // If you've configured the server to return 285, then it means the server does not require further update. + // So the normal thing to do here would be to `BackgroundGeolocation.stop()`. + // But you might be counting on it to receive location updates in the UI, so you could just reconfigure and set `url` to null. + }); + + BackgroundGeolocation.on('http_authorization', () => { + console.log('[INFO] App needs to authorize the http requests'); + }); + + BackgroundGeolocation.on('stop', () => { + PushNotification.localNotification({ + title: 'Location Tracking Was Disabled', + message: 'Private Kit requires location services.', + }); + console.log('[INFO] stop'); + }); + + BackgroundGeolocation.on('stationary', () => { + console.log('[INFO] stationary'); + }); + + BackgroundGeolocation.checkStatus(status => { + console.log( + '[INFO] BackgroundGeolocation service is running', + status.isRunning, + ); + console.log( + '[INFO] BackgroundGeolocation services enabled', + status.locationServicesEnabled, + ); + console.log( + '[INFO] BackgroundGeolocation auth status: ' + status.authorization, + ); + + BackgroundGeolocation.start(); //triggers start on start event + + if (!status.locationServicesEnabled) { + // we need to set delay or otherwise alert may not be shown + setTimeout( + () => + Alert.alert( + 'Private Kit requires location services to be enabled', + 'Would you like to open location settings?', + [ + { + text: 'Yes', + onPress: () => BackgroundGeolocation.showLocationSettings(), + }, + { + text: 'No', + onPress: () => console.log('No Pressed'), + style: 'cancel', + }, + ], + ), + 1000, + ); + } else if (!status.authorization) { + // we need to set delay or otherwise alert may not be shown + setTimeout( + () => + Alert.alert( + 'Private Kit requires access to location information', + 'Would you like to open app settings?', + [ + { + text: 'Yes', + onPress: () => BackgroundGeolocation.showAppSettings(), + }, + { + text: 'No', + onPress: () => console.log('No Pressed'), + style: 'cancel', + }, + ], + ), + 1000, + ); + } else if (!status.isRunning) { + } + }); + + // you can also just start without checking for status + // BackgroundGeolocation.start(); + } + + static getPointCount() { + return lastPointCount; + } + + static stop(nav) { + // unregister all event listeners + PushNotification.localNotification({ + title: 'Location Tracking Was Disabled', + message: 'Private Kit requires location services.', + }); + BackgroundGeolocation.removeAllListeners(); + BackgroundGeolocation.stop(); + instanceCount -= 1; + SetStoreData('PARTICIPATE', 'false').then(() => + nav.navigate('LocationTrackingScreen', {}), + ); + } } diff --git a/app/views/Export.js b/app/views/Export.js index 2362d00765..8721b03216 100644 --- a/app/views/Export.js +++ b/app/views/Export.js @@ -1,204 +1,198 @@ -import React, { - Component -} from 'react'; +import React, { Component } from 'react'; import { - SafeAreaView, - StyleSheet, - ScrollView, - Linking, - View, - Text, - Image, - Dimensions, - TouchableOpacity,BackHandler + SafeAreaView, + StyleSheet, + ScrollView, + Linking, + View, + Text, + Image, + Dimensions, + TouchableOpacity, + BackHandler, } from 'react-native'; -import colors from "../constants/colors"; +import colors from '../constants/colors'; import WebView from 'react-native-webview'; -import Button from "../components/Button"; -import { - GetStoreData -} from '../helpers/General'; -import { - convertPointsToString -} from '../helpers/convertPointsToString'; +import Button from '../components/Button'; +import { GetStoreData } from '../helpers/General'; +import { convertPointsToString } from '../helpers/convertPointsToString'; import Share from 'react-native-share'; import RNFetchBlob from 'rn-fetch-blob'; import LocationServices from '../services/LocationService'; -import backArrow from './../assets/images/backArrow.png' -import languages from './../locales/languages' +import backArrow from './../assets/images/backArrow.png'; +import languages from './../locales/languages'; const width = Dimensions.get('window').width; -const base64 = RNFetchBlob.base64 - +const base64 = RNFetchBlob.base64; //import RNShareFile from 'react-native-file-share'; - class ExportScreen extends Component { - constructor(props) { - super(props); - } - - onShare = async () => { - try { - const locationArray = await GetStoreData('LOCATION_DATA'); - var locationData; - - if (locationArray !== null) { - locationData = JSON.parse(locationArray); - } else { - locationData = []; - } - - b64Data = base64.encode(JSON.stringify(locationData)); - Share.open({ - url: "data:string/txt;base64," + b64Data - }).then(res => { - console.log(res); - }) - .catch(err => { - console.log(err.message, err.code); - }) - } catch (error) { - console.log(error.message); - } - }; - - backToMain() { - this.props.navigation.navigate('LocationTrackingScreen', {}) - } - - handleBackPress = () => { - this.props.navigation.navigate('LocationTrackingScreen', {}); - return true; - }; - - componentDidMount() { - BackHandler.addEventListener("hardwareBackPress", this.handleBackPress); - } - - componentWillUnmount() { - BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress); - } - - render() { - - return ( - - - - this.backToMain()}> - - - {languages.t('label.export')} - - - - {languages.t('label.export_para_1')} - {languages.t('label.export_para_2')} - - {languages.t('label.share')} - - {languages.t('label.data_hint')} {convertPointsToString(LocationServices.getPointCount()) } - - - - ) + constructor(props) { + super(props); + } + + onShare = async () => { + try { + const locationArray = await GetStoreData('LOCATION_DATA'); + var locationData; + + if (locationArray !== null) { + locationData = JSON.parse(locationArray); + } else { + locationData = []; + } + + b64Data = base64.encode(JSON.stringify(locationData)); + Share.open({ + url: 'data:string/txt;base64,' + b64Data, + }) + .then(res => { + console.log(res); + }) + .catch(err => { + console.log(err.message, err.code); + }); + } catch (error) { + console.log(error.message); } + }; + + backToMain() { + this.props.navigation.navigate('LocationTrackingScreen', {}); + } + + handleBackPress = () => { + this.props.navigation.navigate('LocationTrackingScreen', {}); + return true; + }; + + componentDidMount() { + BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); + } + + componentWillUnmount() { + BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); + } + + render() { + return ( + + + this.backToMain()}> + + + {languages.t('label.export')} + + + + + {languages.t('label.export_para_1')} + + + {languages.t('label.export_para_2')} + + + {languages.t('label.share')} + + + {languages.t('label.data_hint')}{' '} + {convertPointsToString(LocationServices.getPointCount())} + + + + ); + } } const styles = StyleSheet.create({ - // Container covers the entire screen - container: { - flex: 1, - flexDirection: 'column', - color: colors.PRIMARY_TEXT, - backgroundColor: colors.WHITE - }, - headerTitle: { - textAlign: 'center', - fontWeight: "bold", - fontSize: 38, - - padding: 0 - }, - subHeaderTitle: { - textAlign: 'center', - fontWeight: "bold", - fontSize: 22, - padding: 5 - }, - main: { - flex: 1, - flexDirection: 'column', - textAlignVertical: 'top', - // alignItems: 'center', - padding:20, - width:'96%', - alignSelf:'center' - }, - buttonTouchable: { - borderRadius: 12, - backgroundColor: "#665eff", - height:52, - alignSelf:'center', - width:width*.7866, - marginTop:30, - justifyContent:'center' - }, - buttonText:{ - - fontFamily: "OpenSans-Bold", - fontSize: 14, - lineHeight: 19, - letterSpacing: 0, - textAlign: "center", - color: "#ffffff" - }, - mainText: { - fontSize: 18, - lineHeight: 24, - fontWeight: '400', - textAlignVertical: 'center', - padding: 20, - }, - smallText: { - fontSize: 10, - lineHeight: 24, - fontWeight: '400', - textAlignVertical: 'center', - padding: 20, - }, - - headerContainer: { - flexDirection: 'row', - height:60, - borderBottomWidth:1, - borderBottomColor:'rgba(189, 195, 199,0.6)', - alignItems:'center' - }, - backArrowTouchable:{ - width:60, - height:60, - paddingTop:21, - paddingLeft:20 - }, - backArrow: { - height: 18, - width: 18.48 - }, - headerTitle:{ - fontSize: 24, - fontFamily:'OpenSans-Bold' - }, - sectionDescription: { - fontSize: 16, - lineHeight: 24, - marginTop:12, - fontFamily:'OpenSans-Regular', - }, + // Container covers the entire screen + container: { + flex: 1, + flexDirection: 'column', + color: colors.PRIMARY_TEXT, + backgroundColor: colors.WHITE, + }, + subHeaderTitle: { + textAlign: 'center', + fontWeight: 'bold', + fontSize: 22, + padding: 5, + }, + main: { + flex: 1, + flexDirection: 'column', + textAlignVertical: 'top', + // alignItems: 'center', + padding: 20, + width: '96%', + alignSelf: 'center', + }, + buttonTouchable: { + borderRadius: 12, + backgroundColor: '#665eff', + height: 52, + alignSelf: 'center', + width: width * 0.7866, + marginTop: 30, + justifyContent: 'center', + }, + buttonText: { + fontFamily: 'OpenSans-Bold', + fontSize: 14, + lineHeight: 19, + letterSpacing: 0, + textAlign: 'center', + color: '#ffffff', + }, + mainText: { + fontSize: 18, + lineHeight: 24, + fontWeight: '400', + textAlignVertical: 'center', + padding: 20, + }, + smallText: { + fontSize: 10, + lineHeight: 24, + fontWeight: '400', + textAlignVertical: 'center', + padding: 20, + }, + + headerContainer: { + flexDirection: 'row', + height: 60, + borderBottomWidth: 1, + borderBottomColor: 'rgba(189, 195, 199,0.6)', + alignItems: 'center', + }, + backArrowTouchable: { + width: 60, + height: 60, + paddingTop: 21, + paddingLeft: 20, + }, + backArrow: { + height: 18, + width: 18.48, + }, + headerTitle: { + fontSize: 24, + fontFamily: 'OpenSans-Bold', + }, + sectionDescription: { + fontSize: 16, + lineHeight: 24, + marginTop: 12, + fontFamily: 'OpenSans-Regular', + }, }); -export default ExportScreen; \ No newline at end of file +export default ExportScreen; diff --git a/app/views/Import.js b/app/views/Import.js index c6200e3bc7..1e31d9e387 100644 --- a/app/views/Import.js +++ b/app/views/Import.js @@ -1,140 +1,141 @@ -import React, { - Component -} from 'react'; +import React, { Component } from 'react'; import { - SafeAreaView, - StyleSheet, - ScrollView, - Linking, - View, - Text, - Image, - TouchableOpacity,BackHandler + SafeAreaView, + StyleSheet, + ScrollView, + Linking, + View, + Text, + Image, + TouchableOpacity, + BackHandler, } from 'react-native'; -import colors from "../constants/colors"; +import colors from '../constants/colors'; import WebView from 'react-native-webview'; -import Button from "../components/Button"; -import backArrow from './../assets/images/backArrow.png' -import { - SearchAndImport -} from '../helpers/GoogleTakeOutAutoImport'; -import languages from './../locales/languages' +import Button from '../components/Button'; +import backArrow from './../assets/images/backArrow.png'; +import { SearchAndImport } from '../helpers/GoogleTakeOutAutoImport'; +import languages from './../locales/languages'; class ImportScreen extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - // Autoimports if user has downloaded - SearchAndImport(); - } + // Autoimports if user has downloaded + SearchAndImport(); + } - backToMain() { - this.props.navigation.navigate('LocationTrackingScreen', {}) - } + backToMain() { + this.props.navigation.navigate('LocationTrackingScreen', {}); + } - handleBackPress = () => { - this.props.navigation.navigate('LocationTrackingScreen', {}); - return true; - }; + handleBackPress = () => { + this.props.navigation.navigate('LocationTrackingScreen', {}); + return true; + }; - componentDidMount() { - BackHandler.addEventListener("hardwareBackPress", this.handleBackPress); - } + componentDidMount() { + BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); + } - componentWillUnmount() { - BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress); - } + componentWillUnmount() { + BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); + } - render() { - return ( - - - this.backToMain()}> - - - {languages.t('label.import_title')} - + render() { + return ( + + + this.backToMain()}> + + + + {languages.t('label.import_title')} + + - - - {languages.t('label.import_step_1')} - {languages.t('label.import_step_2')} - - - - - - - ) - } + + + + {languages.t('label.import_step_1')} + + + {languages.t('label.import_step_2')} + + + + + + + + ); + } } const styles = StyleSheet.create({ - // Container covers the entire screen - container: { - flex: 1, - flexDirection: 'column', - color: colors.PRIMARY_TEXT, - backgroundColor: colors.WHITE, - }, - headerTitle: { - textAlign: 'center', - fontWeight: "bold", - fontSize: 38, - padding: 0 - }, - subHeaderTitle: { - textAlign: 'center', - fontWeight: "bold", - fontSize: 22, - padding: 5 - }, - web: { - flex: 1, - width: "100%" - }, - main: { - flex: 1, - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - paddingLeft: 20, - paddingRight: 20, - width: "100%" - }, - - headerContainer: { - flexDirection: 'row', - height:60, - borderBottomWidth:1, - borderBottomColor:'rgba(189, 195, 199,0.6)', - alignItems:'center' - }, - backArrowTouchable:{ - width:60, - height:60, - paddingTop:21, - paddingLeft:20 - }, - backArrow: { - height: 18, - width: 18.48 - }, - headerTitle:{ - fontSize: 24, - fontFamily:'OpenSans-Bold' - }, - sectionDescription: { - fontSize: 16, - lineHeight: 24, - textAlignVertical: 'center', - marginTop:12, - fontFamily:'OpenSans-Regular' - }, + // Container covers the entire screen + container: { + flex: 1, + flexDirection: 'column', + color: colors.PRIMARY_TEXT, + backgroundColor: colors.WHITE, + }, + subHeaderTitle: { + textAlign: 'center', + fontWeight: 'bold', + fontSize: 22, + padding: 5, + }, + web: { + flex: 1, + width: '100%', + }, + main: { + flex: 1, + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + paddingLeft: 20, + paddingRight: 20, + width: '100%', + }, + headerContainer: { + flexDirection: 'row', + height: 60, + borderBottomWidth: 1, + borderBottomColor: 'rgba(189, 195, 199,0.6)', + alignItems: 'center', + }, + backArrowTouchable: { + width: 60, + height: 60, + paddingTop: 21, + paddingLeft: 20, + }, + backArrow: { + height: 18, + width: 18.48, + }, + headerTitle: { + fontSize: 24, + fontFamily: 'OpenSans-Bold', + }, + sectionDescription: { + fontSize: 16, + lineHeight: 24, + textAlignVertical: 'center', + marginTop: 12, + fontFamily: 'OpenSans-Regular', + }, }); -export default ImportScreen; \ No newline at end of file +export default ImportScreen; diff --git a/app/views/Licenses.js b/app/views/Licenses.js index 4d8b047433..3bb0545206 100644 --- a/app/views/Licenses.js +++ b/app/views/Licenses.js @@ -2,7 +2,6 @@ import React, { Component } from 'react'; import { SafeAreaView, StyleSheet, - ScrollView, View, Text, Image, @@ -12,20 +11,11 @@ import { } from 'react-native'; import colors from '../constants/colors'; -import WebView from 'react-native-webview'; -import Button from '../components/Button'; -import { GetStoreData } from '../helpers/General'; -import { convertPointsToString } from '../helpers/convertPointsToString'; -import Share from 'react-native-share'; -import RNFetchBlob from 'rn-fetch-blob'; -import LocationServices from '../services/LocationService'; import backArrow from './../assets/images/backArrow.png'; import languages from './../locales/languages'; const width = Dimensions.get('window').width; -const base64 = RNFetchBlob.base64; - class LicensesScreen extends Component { constructor(props) { super(props); @@ -79,12 +69,6 @@ const styles = StyleSheet.create({ color: colors.PRIMARY_TEXT, backgroundColor: colors.WHITE, }, - headerTitle: { - textAlign: 'center', - fontWeight: 'bold', - fontSize: 38, - padding: 0, - }, subHeaderTitle: { textAlign: 'center', fontWeight: 'bold', @@ -131,7 +115,10 @@ const styles = StyleSheet.create({ textAlignVertical: 'center', padding: 20, }, - + headerTitle: { + fontSize: 24, + fontFamily: 'OpenSans-Bold', + }, headerContainer: { flexDirection: 'row', height: 60, diff --git a/app/views/News.js b/app/views/News.js index 3752d28f44..ff243de18d 100644 --- a/app/views/News.js +++ b/app/views/News.js @@ -1,124 +1,123 @@ -import React, { - Component -} from 'react'; +import React, { Component } from 'react'; import { - SafeAreaView, - StyleSheet, - ScrollView, - Image, - View, - Text, - TouchableOpacity,BackHandler + SafeAreaView, + StyleSheet, + Image, + View, + Text, + TouchableOpacity, + BackHandler, } from 'react-native'; -import colors from "../constants/colors"; -import { - WebView -} from 'react-native-webview'; -import Button from "../components/Button"; -import backArrow from './../assets/images/backArrow.png' -import languages from './../locales/languages' +import colors from '../constants/colors'; +import { WebView } from 'react-native-webview'; +import Button from '../components/Button'; +import backArrow from './../assets/images/backArrow.png'; +import languages from './../locales/languages'; class NewsScreen extends Component { - constructor(props) { - super(props); - } + constructor(props) { + super(props); + } + + backToMain() { + this.props.navigation.navigate('LocationTrackingScreen', {}); + } - backToMain() { - this.props.navigation.navigate('LocationTrackingScreen', {}) - } + handleBackPress = () => { + this.props.navigation.navigate('LocationTrackingScreen', {}); + return true; + }; - handleBackPress = () => { - this.props.navigation.navigate('LocationTrackingScreen', {}); - return true; - }; + componentDidMount() { + BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); + } - componentDidMount() { - BackHandler.addEventListener("hardwareBackPress", this.handleBackPress); - } + componentWillUnmount() { + BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); + } - componentWillUnmount() { - BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress); - } + render() { + return ( + + + this.backToMain()}> + + + + {languages.t('label.latest_news')} + + - render() { - return ( - - - this.backToMain()}> - - - {languages.t('label.latest_news')} - - - - - ) - } + + + ); + } } const styles = StyleSheet.create({ - // Container covers the entire screen - container: { - flex: 1, - flexDirection: 'column', - color: colors.PRIMARY_TEXT, - backgroundColor: colors.WHITE, - }, - headerContainer: { - flexDirection: 'row', - }, - backArrow: { - fontSize: 60, - lineHeight: 60, - fontWeight: '400', - marginRight: 5, - textAlignVertical: 'center' - }, - sectionDescription: { - fontSize: 24, - lineHeight: 24, - fontWeight: '800', - textAlignVertical: 'center' - }, - web: { - flex: 1, - width: "100%", - margin: 0, - padding: 0 - }, - headerContainer: { - flexDirection: 'row', - height:60, - borderBottomWidth:1, - borderBottomColor:'rgba(189, 195, 199,0.6)', - alignItems:'center' - }, - backArrowTouchable:{ - width:60, - height:60, - paddingTop:21, - paddingLeft:20 - }, - backArrow: { - height: 18, - width: 18.48 - }, - headerTitle:{ - fontSize: 24, - fontFamily:'OpenSans-Bold', - }, - sectionDescription: { - fontSize: 16, - lineHeight: 24, - textAlignVertical: 'center', - marginTop:12, - fontFamily:'OpenSans-Regular' - } - + // Container covers the entire screen + container: { + flex: 1, + flexDirection: 'column', + color: colors.PRIMARY_TEXT, + backgroundColor: colors.WHITE, + }, + headerContainer: { + flexDirection: 'row', + }, + backArrow: { + fontSize: 60, + lineHeight: 60, + fontWeight: '400', + marginRight: 5, + textAlignVertical: 'center', + }, + sectionDescription: { + fontSize: 24, + lineHeight: 24, + fontWeight: '800', + textAlignVertical: 'center', + }, + web: { + flex: 1, + width: '100%', + margin: 0, + padding: 0, + }, + headerContainer: { + flexDirection: 'row', + height: 60, + borderBottomWidth: 1, + borderBottomColor: 'rgba(189, 195, 199,0.6)', + alignItems: 'center', + }, + backArrowTouchable: { + width: 60, + height: 60, + paddingTop: 21, + paddingLeft: 20, + }, + backArrow: { + height: 18, + width: 18.48, + }, + headerTitle: { + fontSize: 24, + fontFamily: 'OpenSans-Bold', + }, + sectionDescription: { + fontSize: 16, + lineHeight: 24, + textAlignVertical: 'center', + marginTop: 12, + fontFamily: 'OpenSans-Regular', + }, }); -export default NewsScreen; \ No newline at end of file +export default NewsScreen; diff --git a/app/views/Welcome.js b/app/views/Welcome.js index c475b9f41c..dce653b0ab 100644 --- a/app/views/Welcome.js +++ b/app/views/Welcome.js @@ -1,125 +1,137 @@ import React, { Component } from 'react'; -import { - SafeAreaView, - StyleSheet, - ScrollView, - Linking, - View, - Text -} from 'react-native'; +import { SafeAreaView, StyleSheet, Linking, View, Text } from 'react-native'; -import colors from "../constants/colors"; -import Button from "../components/Button"; +import colors from '../constants/colors'; +import Button from '../components/Button'; -import {GetStoreData, SetStoreData} from '../helpers/General'; +import { GetStoreData, SetStoreData } from '../helpers/General'; class Welcome extends Component { - constructor(props) { - super(props); - } - componentDidMount() { - GetStoreData('PARTICIPATE') - .then(isParticipating => { - console.log(isParticipating); - if(isParticipating == 'true') { - this.props.navigation.navigate('LocationTrackingScreen', {}) - } - }) - .catch(error => console.log(error)) - } - - componentWillUnmount() { - } - - willParticipate() { - SetStoreData('PARTICIPATE', 'true').then(() => - this.props.navigation.navigate('LocationTrackingScreen', {}) - ); - } + constructor(props) { + super(props); + } + componentDidMount() { + GetStoreData('PARTICIPATE') + .then(isParticipating => { + console.log(isParticipating); + if (isParticipating == 'true') { + this.props.navigation.navigate('LocationTrackingScreen', {}); + } + }) + .catch(error => console.log(error)); + } - render() { - return ( - + componentWillUnmount() {} - - - + willParticipate() { + SetStoreData('PARTICIPATE', 'true').then(() => + this.props.navigation.navigate('LocationTrackingScreen', {}), + ); + } - Private Kit + render() { + return ( + + + + + Private Kit - Private Kit is your personal vault that nobody else can access. - It will allow you to log your location privately every five minutes. Your location information will NOT leave your phone. + + Private Kit is your personal vault that nobody else can access. + + + It will allow you to log your location privately every five + minutes. Your location information will NOT leave your phone. + + + - - + +