Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notification UI to show histogram and day wise list of intersections #237

Merged
merged 10 commits into from
Mar 27, 2020
1 change: 1 addition & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
6 changes: 6 additions & 0 deletions app/Entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -87,6 +88,11 @@ class Entry extends Component {
component={LicencesScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name='NotificationScreen'
component={NotificationScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name='OverlapScreen'
component={OverlapScreen}
Expand Down
14 changes: 8 additions & 6 deletions app/locales/en/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
7 changes: 7 additions & 0 deletions app/locales/en/notification.json
Original file line number Diff line number Diff line change
@@ -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",
}
10 changes: 10 additions & 0 deletions app/views/LocationTracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ class LocationTracking extends Component {
this.props.navigation.navigate('LicensesScreen', {});
}

notifications() {
this.props.navigation.navigate('NotificationScreen', {});
}

willParticipate = () => {
SetStoreData('PARTICIPATE', 'true').then(() => {
LocationServices.start();
Expand Down Expand Up @@ -157,6 +161,12 @@ class LocationTracking extends Component {
}}>
<Text style={styles.menuOptionText}>Licenses</Text>
</MenuOption>
<MenuOption
onSelect={() => {
this.notifications();
}}>
<Text style={styles.menuOptionText}>Notifications</Text>
</MenuOption>
</MenuOptions>
</Menu>
<Text style={styles.headerTitle}>
Expand Down
289 changes: 289 additions & 0 deletions app/views/Notification.js
Original file line number Diff line number Diff line change
@@ -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 (
<SafeAreaView style={styles.container}>
<View style={styles.headerContainer}>
<TouchableOpacity
style={styles.backArrowTouchable}
onPress={() => this.backToMain()}>
<Image style={styles.backArrow} source={backArrow} />
</TouchableOpacity>
<Text style={styles.headerTitle}>
{languages.t('label.private_kit')}
</Text>
</View>

<View style={styles.main}>
<Text style={styles.headerTitle}>
{languages.t('label.notification_title')}
</Text>
{this.state.dataAvailable ? (
<>
<VictoryChart height={0.35 * height} dependentAxis={true}>
<VictoryAxis dependentAxis={true} />

<VictoryBar
alignment='start'
style={{
data: {
fill: ({ datum }) => datum.fill,
},
}}
data={this.state.data}
/>
</VictoryChart>
<Text style={styles.mainText}>
{languages.t('label.notification_main_text')}
</Text>
<ScrollView contentContainerStyle={styles.contentContainer}>
{this.state.data.map(data => (
<TouchableOpacity key={data.x} style={styles.buttonTouchable}>
<Text style={styles.buttonText}>
{'Day ' +
data.x +
': Number of Intersections ' +
data.y}
</Text>
</TouchableOpacity>
))}
</ScrollView>
</>
) : (
<>
<Text style={styles.mainText}>
{languages.t('label.notification_data_not_available')}
</Text>
<Text style={styles.mainText}>
{languages.t('label.notification_warning_text')}
</Text>
<TouchableOpacity
style={styles.buttonTouchable}
onPress={() => this.generate_random_intersections()}>
<Text style={styles.buttonText}>
{languages.t('label.notification_random_data_button')}
</Text>
</TouchableOpacity>
</>
)}
</View>
</SafeAreaView>
);
}
}

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;
2 changes: 2 additions & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading