This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
14 KiB
459 lines
14 KiB
/** |
|
* Freifunk Altdorf |
|
*/ |
|
import MapScreen from './MapScreen'; |
|
import NodeInfo from './NodeInfNavigation'; |
|
import FetchData from './components/fetchData'; |
|
import styles from './style' |
|
import React, { Component } from 'react'; |
|
import { Div, StyleSheet, Text, View, ScrollView, Alert, Button, TouchableHighlight, TouchableOpacity, Image, Collapsile, AppRegistry } from 'react-native'; |
|
import wifi from 'react-native-android-wifi'; |
|
import MapView from 'react-native-maps'; |
|
import { createStackNavigator } from 'react-navigation'; |
|
import { YellowBox } from 'react-native'; |
|
import MapScreenFreifunk from './MapScreenFreifunk'; |
|
import Speedtest from './Speedtest'; |
|
import Information from './Information'; |
|
import SwichExample from './components/SwitchExample'; |
|
import NodeInformation from './components/NodeInformation'; |
|
YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated', 'Module RCTImageLoader']); //Silence Bug in React-Navigation |
|
import SplashScreen from 'react-native-splash-screen'; |
|
import { PermissionsAndroid } from 'react-native'; |
|
import { Icon } from 'react-native-elements'; |
|
import { PricingCard } from 'react-native-elements'; |
|
import { Grid, Col, Row } from 'react-native-elements'; |
|
import email from 'react-native-email'; |
|
|
|
class HomeScreen extends React.Component { |
|
static navigationOptions = { |
|
title: 'Home', |
|
header: null //hide Bar at HomeScreen |
|
}; |
|
constructor(props) { |
|
super(props); |
|
this.state = { |
|
security: null, |
|
security2: null, |
|
ssid: null, |
|
bssid: null, |
|
data: [], |
|
hostName: '', |
|
dataATT: [], |
|
data2: [], |
|
isLoad: false, |
|
mySSID: 'Wadenspanner2', |
|
SSIDJson: [], |
|
bssidShort: null, |
|
ipv6Address: null, |
|
communityData: [], |
|
community: null, |
|
communityContact: null, |
|
|
|
latitude: null, |
|
longitude: null, |
|
error: null, |
|
}; |
|
} |
|
|
|
async requestLocationPermission() { |
|
const chckLocationPermission = PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION); |
|
if (chckLocationPermission === PermissionsAndroid.RESULTS.GRANTED) { |
|
alert("You've access for the location"); |
|
} else { |
|
try { |
|
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, |
|
{ |
|
'title': 'Cool Location App required Location permission', |
|
'message': 'We required Location permission in order to get device location ' + |
|
'Please grant us.' |
|
} |
|
) |
|
if (granted === PermissionsAndroid.RESULTS.GRANTED) { |
|
alert("You've access for the location"); |
|
} else { |
|
alert("You don't have access for the location"); |
|
} |
|
} catch (err) { |
|
alert(err) |
|
} |
|
} |
|
}; |
|
|
|
componentWillUnmount() { |
|
navigator.geolocation.clearWatch(this.watchId); |
|
} |
|
|
|
|
|
async componentDidMount() { |
|
// do stuff while splash screen is shown |
|
// After having done stuff (such as async tasks) hide the splash screen |
|
this.json_funcion(); |
|
this.getGeolocationData(); |
|
SplashScreen.hide(); |
|
} |
|
|
|
getGeolocationData() { |
|
this.watchId = navigator.geolocation.watchPosition( |
|
(position) => { |
|
this.setState({ |
|
latitude: position.coords.latitude, |
|
longitude: position.coords.longitude, |
|
error: null, |
|
}); |
|
}, |
|
(error) => this.setState({ error: error.message }), |
|
{ enableHighAccuracy: false, timeout: 20000, maximumAge: 1000, distanceFilter: 10 }, |
|
); |
|
} |
|
|
|
ShowAlertWithDelay = () => { |
|
setTimeout(function () { |
|
//Put All Your Code Here, Which You Want To Execute After Some Delay Time. |
|
Alert.alert("Alert Shows After 5 Seconds of Delay.") |
|
}, 5000); |
|
} |
|
|
|
json_funcionCommunity = async () => { |
|
|
|
await this.setState({ |
|
communityData: require('./config/FreifunkAltdorfConfig') |
|
}); |
|
await this.setState({ |
|
community: this.state.communityData.community, |
|
jsonAdr: this.state.communityData.jsonAdr, |
|
communityContact: this.state.communityContact |
|
}); |
|
|
|
// return fetch('/config/FreifunkAltdorf.json') |
|
// .then((response) => response.json()) |
|
// .then((responseJson) => { |
|
// this.setState({ |
|
// communityData: responseJson |
|
// }); |
|
// this.setState({ |
|
|
|
// // dataATT: this.state.data.nodes.map(user => user.nodeinfo), |
|
// community: this.state.communityData.community, |
|
// jsonAdr: this.state.communityData.jsonAdr, |
|
// communityContact: this.state.communityContact |
|
// }); |
|
// }) |
|
// .catch((error) => { |
|
// console.error(error); |
|
// }); |
|
} |
|
|
|
//Fetching Data from JSON File |
|
json_funcion = async () => { |
|
await Promise.all([this.json_funcionCommunity()]); |
|
return fetch(this.state.jsonAdr) |
|
.then((response) => response.json()) |
|
.then((responseJson) => { |
|
this.setState({ |
|
data: responseJson |
|
}); |
|
this.setState({ |
|
|
|
// dataATT: this.state.data.nodes.map(user => user.nodeinfo), |
|
dataATT: this.state.data.nodes, |
|
isLoad: true |
|
}); |
|
}) |
|
.catch((error) => { |
|
console.error(error); |
|
}); |
|
} |
|
|
|
json_funcion2 = (addr) => { |
|
console.log("9. checkSecurity was called"); |
|
console.log(addr); |
|
return fetch(String(addr)) |
|
.then((response) => response.json()) |
|
.then((responseJson) => { |
|
this.setState({ |
|
data2: responseJson |
|
}); |
|
// this.setState({ |
|
console.log(this.state.data2.node_id); |
|
// // dataATT: this.state.data.nodes.map(user => user.nodeinfo), |
|
// dataATT: this.state.data.nodes, |
|
// isLoad: true |
|
// }); |
|
}) |
|
.catch((error) => { |
|
console.error(error); |
|
}); |
|
} |
|
|
|
getSSIDOnPress() { |
|
wifi.getSSID((ssid) => { |
|
this.setState({ currentSSID: 'Your SSID is ' + ssid }); |
|
}); |
|
} |
|
|
|
getBSSIDOnPress() { |
|
console.log("2. getBSSID was called"); |
|
wifi.getBSSID((bssid) => { |
|
console.log(bssid); |
|
var res = bssid.substring(0, 16); |
|
this.setState({ currentBSSID: bssid }); |
|
this.setState({ currentBSSIDText: 'Your BSSID is ' + bssid }); |
|
this.setState({ bssidShort: res }); |
|
console.log("3. gleich wird findOutComminity aufgerufen"); |
|
this.findOutCommunity(); |
|
}); |
|
} |
|
|
|
async checkSecurity() { |
|
Promise.all([this.getBSSIDOnPress(), this.getSSIDOnPress()]); |
|
this.setState({ security: 'not reliable' }); |
|
|
|
|
|
//ĀRWYB |
|
} |
|
|
|
displayReliabilty = () => { |
|
if (this.state.security != null || this.state.currentSSID != null) { |
|
return <View> |
|
<Text style={styles.simpleText}>{this.state.currentSSID}</Text> |
|
<Text style={styles.simpleText}>{this.state.currentBSSIDText}</Text> |
|
<Text style={styles.simpleText}>{this.state.hostName}</Text> |
|
<Text style={styles.simpleText}>{'Your connection is ' + this.state.security}</Text> |
|
</View> |
|
} |
|
} |
|
|
|
findOutCommunity = () => { |
|
var data = this.state.dataATT; |
|
var aa1 = String(this.state.bssidShort).toLocaleLowerCase(); |
|
for (var k3 in data) { |
|
if (data.hasOwnProperty(k3)) { |
|
if (String(data[k3].nodeinfo.network.mesh.bat0.interfaces.other).toLowerCase().includes(aa1)) { |
|
this.setState({ hostName: data[k3].nodeinfo.hostname }); |
|
if (String(data[k3].nodeinfo.network.addresses[0]).includes("fdef")) { |
|
this.setState({ ipv6Address: data[k3].nodeinfo.network.addresses[0] }); |
|
} else if (String(data[k3].nodeinfo.network.addresses[1]).includes("fdef")) { |
|
this.setState({ ipv6Address: data[k3].nodeinfo.network.addresses[1] }); |
|
} else { |
|
this.setState({ ipv6Address: data[k3].nodeinfo.network.addresses[2] }); |
|
} |
|
console.log("6. gleich wird compareJSONwithJSON aufgerufen"); |
|
this.compareJSONwithJSON(data[k3].nodeinfo.node_id); |
|
} |
|
} |
|
} |
|
} |
|
|
|
compareJSONwithJSON = async (nodeid) => { |
|
var addr = "http://["; |
|
addr += String(this.state.ipv6Address); |
|
addr += "]/cgi-bin/nodeinfo"; |
|
|
|
await Promise.all([this.json_funcion2(addr)]); |
|
console.log(nodeid); |
|
console.log(this.state.data2.node_id); |
|
if (nodeid == this.state.data2.node_id) { |
|
console.log("found"); |
|
this.setState({ security: 'reliable' }); |
|
} |
|
} |
|
|
|
render() { |
|
//console.log(this.state.dataATT.map(us => us.hostname)) |
|
return ( |
|
<ScrollView style={styles.wholeBackground}> |
|
<View style={styles.header}> |
|
{/* Logo */} |
|
<View style={styles.img}> |
|
<Image |
|
style={{ |
|
width: 102, |
|
height: 85, |
|
}} |
|
source={require('./src/img/Logo.png')} |
|
/> |
|
</View> |
|
</View> |
|
<View style={styles.container}> |
|
<View> |
|
<Text style={styles.headlineText}>Reliability Check</Text> |
|
|
|
<View style={styles.testCenter}> |
|
<TouchableHighlight onPress={this.checkSecurity.bind(this)}> |
|
<Text style={styles.button}>Measure Security</Text> |
|
</TouchableHighlight> |
|
<View style={styles.testCenter}> |
|
{this.displayReliabilty()} |
|
</View> |
|
|
|
</View> |
|
</View> |
|
</View> |
|
|
|
<View style={styles.breakLine}></View> |
|
|
|
<View style={styles.container}> |
|
<View style={styles.testCenter}> |
|
<Text style={styles.headlineText}>Node Information</Text> |
|
<NodeInformation dataATT={this.state.dataATT} /> |
|
|
|
|
|
<TouchableHighlight onPress={() => { |
|
/* 1. Navigate to the Details route with params */ |
|
this.checkSecurity(); |
|
console.log('lets see : ' + this.currentBSSID); // ISSUE currentBSSID is not set as fast as nav gets open |
|
this.props.navigation.navigate('NodeInfoO', { |
|
dataATT: this.state.dataATT, |
|
currentBSSID: this.state.currentBSSID, |
|
hostName: this.state.hostName, |
|
}); |
|
}}> |
|
<Text style={styles.button}>More Node Info</Text> |
|
</TouchableHighlight> |
|
</View> |
|
</View> |
|
|
|
<View style={styles.breakLine}></View> |
|
|
|
<View style={styles.container}> |
|
<View> |
|
<Text style={styles.headlineText}>Speedtest</Text> |
|
<TouchableHighlight onPress={() => { |
|
/* 1. Navigate to the Details route with params */ |
|
this.props.navigation.navigate('SpeedtestO', { |
|
}); |
|
}}> |
|
<Text style={styles.button}>Start Speedtest</Text> |
|
</TouchableHighlight> |
|
</View> |
|
</View> |
|
|
|
<View style={styles.breakLine}></View> |
|
|
|
<View style={styles.container}> |
|
<View> |
|
<Text style={styles.headlineText}>Map Info</Text> |
|
|
|
<View> |
|
<TouchableHighlight onPress={() => { |
|
/* 1. Navigate to the Details route with params */ |
|
this.props.navigation.navigate('MapScreenG', { |
|
dataATT: this.state.dataATT, |
|
latitude: this.state.latitude, |
|
longitude: this.state.longitude, |
|
}); |
|
}}> |
|
<Text style={styles.button}>Maps (Google)</Text> |
|
</TouchableHighlight> |
|
|
|
<TouchableHighlight onPress={() => { |
|
/* 1. Navigate to the Details route with params */ |
|
this.props.navigation.navigate('MapScreenF', { |
|
itemId: 86, |
|
dataATT: this.state.dataATT, |
|
}); |
|
}}> |
|
<Text style={styles.button}>Maps (Freifunk)</Text> |
|
</TouchableHighlight> |
|
</View> |
|
</View> |
|
</View> |
|
|
|
<View style={styles.breakLine}></View> |
|
|
|
<View style={styles.container}> |
|
<View> |
|
<Text style={styles.headlineText}>Info</Text> |
|
{/* Latitude Longitude */} |
|
{/* <Text |
|
onPress={() => this.requestLocationPermission()}> |
|
Request Location Permission |
|
</Text> |
|
<Text>Latitude: {this.state.latitude}</Text> |
|
<Text style={{ paddingBottom: 10 }}>Longitude: {this.state.longitude}</Text> |
|
{this.state.error ? <Text>Error: {this.state.error}</Text> : null} |
|
<Text></Text> */} |
|
<TouchableHighlight onPress={() => { |
|
/* 1. Navigate to the Details route with params */ |
|
this.props.navigation.navigate('InformationO', { |
|
itemId: 86, |
|
dataATT: this.state.dataATT, |
|
}); |
|
}}> |
|
<Text style={styles.button}>Information</Text> |
|
</TouchableHighlight> |
|
</View> |
|
</View> |
|
|
|
<View style={styles.breakLine}></View> |
|
|
|
<View style={styles.container}> |
|
<View style={{ paddingBottom: 10 }}> |
|
<Text style={styles.headlineText}>Report</Text> |
|
<TouchableOpacity |
|
style={styles.button2} |
|
onPress={this.handleEmail} |
|
> |
|
<Text> Send Report </Text> |
|
</TouchableOpacity> |
|
</View> |
|
</View> |
|
</ScrollView> |
|
); |
|
} |
|
|
|
handleEmail = () => { |
|
const to = ['orhan.sari.1993@gmail.com'] // string or array of email addresses |
|
email(to, { |
|
// Optional additional arguments |
|
// cc: ['bazzy@moo.com', 'doooo@daaa.com'], // string or array of email addresses |
|
// bcc: 'mee@mee.com', // string or array of email addresses |
|
subject: 'From Freifunk App', |
|
body: |
|
'Hostname: ' + this.state.hostName + //If not connected with Freifunk then null |
|
'\n SSID: ' + this.state.currentSSID + |
|
'\n BSSID: ' + this.state.currentBSSID + |
|
'\n IPv6 Address: ' + this.state.ipv6Address + //If not connected with Freifunk then null |
|
'\n Latitude: ' + this.state.latitude + |
|
'\n Longitude: ' + this.state.longitude |
|
// TODO: |
|
// + Information returned by Node Information |
|
// e.g. Gateway Hops, Clients, .. |
|
}).catch(console.error) |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const RootStack = createStackNavigator( |
|
{ |
|
Home: { |
|
screen: HomeScreen, |
|
}, |
|
MapScreenG: { |
|
screen: MapScreen, |
|
}, |
|
MapScreenF: { |
|
screen: MapScreenFreifunk, |
|
}, |
|
NodeInfoO: { |
|
screen: NodeInfo, |
|
}, |
|
SpeedtestO: { |
|
screen: Speedtest, |
|
}, |
|
InformationO: { |
|
screen: Information, |
|
} |
|
}, |
|
{ |
|
initialRouteName: 'Home', |
|
} |
|
); |
|
|
|
export default class App extends React.Component { |
|
render() { |
|
return <RootStack />; |
|
} |
|
} |