diff --git a/android/app/build.gradle b/android/app/build.gradle index a8e504e4dd..845ac5a0af 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -192,6 +192,7 @@ android { } dependencies { + implementation project(':react-native-svg') implementation project(':react-native-webview') implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "com.facebook.react:react-native:+" // From node_modules diff --git a/android/app/src/main/java/edu/mit/privatekit/MainApplication.java b/android/app/src/main/java/edu/mit/privatekit/MainApplication.java index 64e6b1d056..2430861f84 100644 --- a/android/app/src/main/java/edu/mit/privatekit/MainApplication.java +++ b/android/app/src/main/java/edu/mit/privatekit/MainApplication.java @@ -4,6 +4,7 @@ import android.content.Context; import com.facebook.react.PackageList; import com.facebook.react.ReactApplication; +import com.horcrux.svg.SvgPackage; import com.reactnativecommunity.webview.RNCWebViewPackage; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; diff --git a/android/settings.gradle b/android/settings.gradle index 5efc6884fa..75f01d285e 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,6 @@ rootProject.name = 'PrivateKit' +include ':react-native-svg' +project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android') include ':react-native-fs' project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android') include ':react-native-zip-archive' diff --git a/app/Entry.js b/app/Entry.js index 818f2ce272..1760e3fd5f 100644 --- a/app/Entry.js +++ b/app/Entry.js @@ -10,6 +10,7 @@ import ExportScreen from './views/Export'; import ImportScreen from './views/Import'; import OverlapScreen from './views/Overlap'; import LicencesScreen from './views/Licenses'; +import NotificationScreen from './views/Notification'; import Slider from './views/welcomeScreens/Slider'; import { GetStoreData } from './helpers/General'; import SettingsScreen from './views/Settings'; @@ -94,7 +95,12 @@ class Entry extends Component { options={{ headerShown: false }} /> + diff --git a/app/locales/en/index.js b/app/locales/en/index.js index 4cba49d83d..8e4028faaf 100644 --- a/app/locales/en/index.js +++ b/app/locales/en/index.js @@ -4,12 +4,14 @@ import importFile from './import.json'; import exportFile from './exportscreen.json'; import licensesFile from './licensesscreen.json'; import overlapFile from './overlap.json'; +import notificationFile from './notification.json'; export default { - ...intro, - ...locationTracking, - ...importFile, - ...exportFile, - ...overlapFile, - ...licensesFile, + ...intro, + ...locationTracking, + ...importFile, + ...exportFile, + ...overlapFile, + ...licensesFile, + ...notificationFile, }; diff --git a/app/locales/en/notification.json b/app/locales/en/notification.json new file mode 100644 index 0000000000..750c061e94 --- /dev/null +++ b/app/locales/en/notification.json @@ -0,0 +1,7 @@ +{ + "notification_main_text": "Check your Intersection day wise", + "notification_title": "Analyze your intersection", + "notification_data_not_available": "\n\nYou do not have any trails downloaded!\n\n", + "notification_warning_text": "You can press the following button to generate random intersections.\nWARNING: These are simulated intersections not real", + "notification_random_data_button": "Press this button to generate random data", +} \ No newline at end of file diff --git a/app/views/Notification.js b/app/views/Notification.js new file mode 100644 index 0000000000..b9008f51f1 --- /dev/null +++ b/app/views/Notification.js @@ -0,0 +1,289 @@ +import React, { Component } from 'react'; +import { + SafeAreaView, + StyleSheet, + View, + Text, + Platform, + Image, + Dimensions, + TouchableOpacity, + BackHandler, + ScrollView, +} from 'react-native'; +import { WebView } from 'react-native-webview'; +import packageJson from '../../package.json'; + +import colors from '../constants/colors'; +import backArrow from './../assets/images/backArrow.png'; +import languages from './../locales/languages'; +import AsyncStorage from '@react-native-community/async-storage'; +import { GetStoreData, SetStoreData } from '../helpers/General'; +import { + VictoryBar, + VictoryAxis, + VictoryChart, + VictoryTooltip, +} from 'victory-native'; + +const width = Dimensions.get('window').width; +const height = Dimensions.get('window').height; +var using_random_intersections = false; + +class NotificationScreen extends Component { + constructor(props) { + super(props); + this.state = { + data: [], + }; + this.getInitialState(); + } + + backToMain() { + this.resetState(); + this.props.navigation.navigate('LocationTrackingScreen', {}); + } + + handleBackPress = () => { + this.resetState(); + this.props.navigation.navigate('LocationTrackingScreen', {}); + return true; + }; + + componentDidMount() { + this.refreshState(); + BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); + } + + componentWillUnmount() { + BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); + } + + refreshState() { + this.getInitialState(); + } + + resetState() { + if (using_random_intersections === true) { + using_random_intersections = false; + AsyncStorage.removeItem('CROSSED_PATHS'); + console.log('deleting random intersection data'); + this.setState({ dataAvailable: false }); + } + } + + generate_random_intersections(length = 28) { + using_random_intersections = true; + var dayBin = []; + for (var i = 0; i < length; i++) { + // Random Integer between 0-99 + const intersections = Math.floor(Math.random() * 100); + dayBin.push(intersections); + } + SetStoreData('CROSSED_PATHS', dayBin); + this.refreshState(); + } + + getInitialState = async () => { + GetStoreData('CROSSED_PATHS').then(dayBin => { + console.log(dayBin); + if (dayBin === null) { + this.setState({ dataAvailable: false }); + console.log("Can't found Crossed Paths"); + } else { + var crossed_path_data = []; + console.log('Found Crossed Paths'); + this.setState({ dataAvailable: true }); + dayBinParsed = JSON.parse(dayBin); + for (var i = 0; i < dayBinParsed.length; i++) { + const val = dayBinParsed[i]; + data = { x: i, y: val, fill: this.colorfill(val) }; + crossed_path_data.push(data); + } + this.setState({ data: crossed_path_data }); + } + }); + }; + + colorfill(data) { + var color = 'green'; + if (data > 20) { + color = 'yellow'; + } + if (data > 50) { + color = 'orange'; + } + if (data > 80) { + color = 'red'; + } + return color; + } + + render() { + return ( + + + this.backToMain()}> + + + + {languages.t('label.private_kit')} + + + + + + {languages.t('label.notification_title')} + + {this.state.dataAvailable ? ( + <> + + + + datum.fill, + }, + }} + data={this.state.data} + /> + + + {languages.t('label.notification_main_text')} + + + {this.state.data.map(data => ( + + + {'Day ' + + data.x + + ': Number of Intersections ' + + data.y} + + + ))} + + + ) : ( + <> + + {languages.t('label.notification_data_not_available')} + + + {languages.t('label.notification_warning_text')} + + this.generate_random_intersections()}> + + {languages.t('label.notification_random_data_button')} + + + + )} + + + ); + } +} + +const styles = StyleSheet.create({ + // Container covers the entire screen + container: { + flex: 1, + flexDirection: 'column', + color: colors.PRIMARY_TEXT, + backgroundColor: colors.WHITE, + }, + main: { + flex: 1, + flexDirection: 'column', + textAlignVertical: 'top', + alignItems: 'center', + padding: 20, + width: '96%', + alignSelf: 'center', + }, + + contentContainer: { + paddingVertical: 20, + }, + row: { + flex: 1, + flexDirection: 'row', + color: colors.PRIMARY_TEXT, + backgroundColor: colors.WHITE, + }, + valueName: { + fontSize: 20, + fontWeight: '800', + }, + value: { + fontSize: 20, + fontWeight: '200', + }, + buttonTouchable: { + borderRadius: 12, + backgroundColor: '#665eff', + height: 52, + alignSelf: 'center', + width: width * 0.7866, + marginTop: 7, + 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', + }, + smallText: { + fontSize: 10, + lineHeight: 24, + fontWeight: '400', + textAlignVertical: 'center', + padding: 20, + }, + headerTitle: { + fontSize: 24, + fontFamily: 'OpenSans-Bold', + }, + 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, + overflow: 'scroll', + fontFamily: 'OpenSans-Regular', + }, +}); + +export default NotificationScreen; diff --git a/ios/Podfile b/ios/Podfile index ffa7c365c8..5389fcb1fb 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -42,6 +42,8 @@ target 'PrivateKit' do pod 'GoogleMaps' pod 'Google-Maps-iOS-Utils' + pod 'RNSVG', :path => '../node_modules/react-native-svg' + target 'PrivateKitTests' do inherit! :search_paths # Pods for testing diff --git a/package.json b/package.json index ee07dc926f..1653402c68 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,10 @@ "test": "jest test" }, "lint-staged": { - "*.js": ["prettier --write", "git add --force"] + "*.js": [ + "prettier --write", + "git add --force" + ] }, "husky": { "hooks": { @@ -53,10 +56,12 @@ "react-native-safe-area-context": "0.6.0", "react-native-screens": "2.0.0-alpha.12", "react-native-share": "^3.1.0", + "react-native-svg": "^12.0.3", "react-native-uuid-generator": "^6.1.1", "react-native-webview": "^8.1.2", "react-native-zip-archive": "^5.0.1", - "rn-fetch-blob": "^0.12.0" + "rn-fetch-blob": "^0.12.0", + "victory-native": "^34.1.0" }, "devDependencies": { "@babel/core": "^7.8.6",