This commit is contained in:
parent
e9f70bb9c2
commit
651793bfe2
|
@ -9,11 +9,9 @@ import useCachedResources from './hooks/useCachedResources';
|
|||
import useColorScheme from './hooks/useColorScheme';
|
||||
import Navigation from './navigation';
|
||||
import { Trips } from './GT2';
|
||||
import * as fs from 'fs';
|
||||
|
||||
|
||||
export var debug:boolean = false;
|
||||
var expoGeoState:any;
|
||||
var debug:boolean = false;
|
||||
var expoGeoState:any = null;
|
||||
|
||||
export default function App() {
|
||||
const isLoadingComplete = useCachedResources();
|
||||
|
@ -29,12 +27,11 @@ export default function App() {
|
|||
if (status !== 'granted') {
|
||||
setErrorMsg('Permission to access location was denied');
|
||||
return;
|
||||
}
|
||||
} else Trips.setLocEnabled(true);
|
||||
|
||||
let location = await Location.getCurrentPositionAsync({});
|
||||
setLocation(location);
|
||||
if (!errorMsg && location)
|
||||
Trips.deltaLoc(JSON.stringify(location));
|
||||
Trips.deltaLoc(location);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
import * as React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import * as Location from 'expo-location';
|
||||
import { Coordinate } from "./Coordinate";
|
||||
import { Text, View } from './components/Themed';
|
||||
import { Alert, StyleSheet } from 'react-native';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Button, StyleSheet } from 'react-native';
|
||||
|
||||
var debug:boolean = false;
|
||||
export var endPending:boolean = false;
|
||||
var expoGeoState:any = null;
|
||||
export var locEnabled:boolean = false;
|
||||
|
||||
const heartbeat:number = 500;
|
||||
const displayBeat:number = 3;
|
||||
|
||||
export function getEndPending() { return(endPending) }
|
||||
export function toggleEndPending() { endPending = !endPending;}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tripText: {
|
||||
|
@ -14,68 +25,154 @@ const styles = StyleSheet.create({
|
|||
fontWeight: 'bold',
|
||||
}});
|
||||
|
||||
var lastLoc:any = null;
|
||||
const heartbeat:number = 500;
|
||||
const displayBeat:number = 3;
|
||||
|
||||
class Chronometer {
|
||||
function Monitor() {
|
||||
|
||||
public display:string = "00.00.00";
|
||||
clock:number = 0;
|
||||
intervalID:any = null;
|
||||
const [location, setLocation] = useState(Object);
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let { status } = await Location.requestBackgroundPermissionsAsync();
|
||||
if (status !== 'granted') {
|
||||
setErrorMsg('Permission to monitor location was denied');
|
||||
return;
|
||||
} else Trips.setLocEnabled(true);
|
||||
|
||||
let location = await Location.getCurrentPositionAsync({});
|
||||
setLocation(location);
|
||||
Trips.deltaLoc(location);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
expoGeoState = 'Waiting..';
|
||||
if (errorMsg) {
|
||||
expoGeoState = errorMsg;
|
||||
} else if (location) {
|
||||
expoGeoState = JSON.stringify(location);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Trip {
|
||||
|
||||
public elapsed:string = "00.00.00";
|
||||
ticks:number = 0;
|
||||
interval:any;
|
||||
segments:number = 1;
|
||||
distance:number = 0;
|
||||
ds:number = 0;
|
||||
CO2:number = 0.0;
|
||||
|
||||
loc:Coordinate = new Coordinate(0.0,0.0);
|
||||
startPoint:Coordinate = new Coordinate(0.0,0.0)
|
||||
|
||||
tick() {let hours:number = 0, minutes:number = 0, seconds:number = 0;
|
||||
this.clock++;
|
||||
hours = this.clock < 3600 ? 0 : (this.clock / 3600);
|
||||
minutes = this.clock < 60 ? 0 : (this.clock - (hours * 3600)) / 60;
|
||||
seconds = this.clock % 60;
|
||||
this.display = hours + ":" + minutes + ":" + seconds;
|
||||
this.ticks++;
|
||||
hours = this.ticks < 3600 ? 0 : (this.ticks / 3600);
|
||||
minutes = this.ticks < 60 ? 0 : (this.ticks - (hours * 3600)) / 60;
|
||||
seconds = this.ticks % 60;
|
||||
this.elapsed = hours.toFixed(0) + ":" + minutes.toFixed(0) + ":" + seconds.toFixed(0);
|
||||
}
|
||||
public start() { this.clock = 0;
|
||||
this.intervalID = setInterval(this.tick, heartbeat);
|
||||
}
|
||||
public resume() { this.intervalID = setInterval(this.tick, heartbeat); }
|
||||
public stop() { clearInterval(this.intervalID); }
|
||||
public start() { this.interval = setInterval(() => this.tick(), heartbeat); }
|
||||
public resume() { this.startPoint = new Coordinate(0.0,0.0)
|
||||
this.loc = new Coordinate(0.0, 0.0);
|
||||
this.segments++;
|
||||
this.interval = setInterval(() => this.tick(), heartbeat); }
|
||||
public stop() { this.ds = this.loc.distanceTo(this.startPoint);
|
||||
this.distance += this.ds;
|
||||
clearInterval(this.interval);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface expoGeoObj {
|
||||
coords: [
|
||||
altitude:number,
|
||||
altitudeAccuracy:number,
|
||||
latitude:number,
|
||||
accuracy:number,
|
||||
longitude:number,
|
||||
heading:number,
|
||||
speed:number,
|
||||
timestamp:number
|
||||
]
|
||||
}
|
||||
|
||||
export class GT2 {
|
||||
|
||||
loc:Coordinate = new Coordinate(0,0);
|
||||
clock:Chronometer = new Chronometer();
|
||||
startPoint:Coordinate = new Coordinate(0,0);
|
||||
trip:Trip = new Trip();
|
||||
endPoint:Coordinate = new Coordinate(0.0,0.0);
|
||||
startPoint:Coordinate = new Coordinate(0.0,0.0);
|
||||
|
||||
displayInterval:number = displayBeat * heartbeat;
|
||||
public distance:number = 0.0;
|
||||
co2Rate:number = 0.0;
|
||||
currTime:number = 0;
|
||||
lastTime:number = 0;
|
||||
co2Rate:number = 250.0;
|
||||
z:number = 0.0;
|
||||
public v:number = 0.0;
|
||||
public inProgress:boolean = false;
|
||||
public paused:boolean = false;
|
||||
public elapsed:number = 0.0;
|
||||
segments:number = 0;
|
||||
elevation:number = 0.0;
|
||||
public units:string = "km";
|
||||
public CO2Effect:string = "carbon burden";
|
||||
|
||||
|
||||
nTrips:number = 0;
|
||||
|
||||
parseGeoExpo(key:string, value:any) {}
|
||||
n:number = 0.0;
|
||||
m:number = 0.0;
|
||||
|
||||
|
||||
public deltaLoc(lastFix:any) {
|
||||
|
||||
lastFix = JSON.stringify(lastFix);
|
||||
let expoFix:expoGeoObj = JSON.parse(lastFix);
|
||||
|
||||
this.trip.loc.setLongitude(expoFix.coords['longitude']);
|
||||
this.trip.loc.setLatitude(expoFix.coords['latitude']);
|
||||
|
||||
if (this.trip.startPoint.mLatitude == 0.0) {
|
||||
this.trip.startPoint.mLatitude = this.trip.loc.mLatitude;
|
||||
this.trip.startPoint.mLongitude = this.trip.loc.mLongitude;
|
||||
}
|
||||
|
||||
this.trip.ds = this.trip.loc.distanceTo(this.trip.startPoint);
|
||||
|
||||
}
|
||||
|
||||
public end() {
|
||||
|
||||
this.trip.stop();
|
||||
this.inProgress = false;
|
||||
this.nTrips++;
|
||||
toggleEndPending();
|
||||
|
||||
}
|
||||
|
||||
public setLocEnabled(value:boolean) { locEnabled = value}
|
||||
|
||||
public pause() {
|
||||
|
||||
if (!this.paused) {
|
||||
this.trip.stop();
|
||||
this.paused = true;
|
||||
} else {
|
||||
this.trip.resume();
|
||||
this.paused = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public reset() {
|
||||
|
||||
this.startPoint = new Coordinate(0,0);
|
||||
this.distance = 0.0;
|
||||
this.co2Rate = 0.0;
|
||||
this.currTime = 0;
|
||||
this.lastTime = 0;
|
||||
this.loc = new Coordinate(0,0);
|
||||
this.endPoint = new Coordinate(0,0);
|
||||
this.startPoint = new Coordinate(0,0);
|
||||
this.v = 0;
|
||||
this.inProgress = false;
|
||||
this.paused = false;
|
||||
|
@ -83,42 +180,40 @@ export class GT2 {
|
|||
|
||||
}
|
||||
|
||||
public end() {
|
||||
|
||||
this.clock.stop();
|
||||
this.inProgress = false;
|
||||
this.nTrips++;
|
||||
|
||||
}
|
||||
|
||||
public pause() {
|
||||
|
||||
if (!this.paused) {
|
||||
this.clock.stop();
|
||||
this.paused = true;
|
||||
} else {
|
||||
this.clock.start();
|
||||
this.paused = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public start() {
|
||||
|
||||
this.reset();
|
||||
this.clock.start();
|
||||
this.trip = new Trip();
|
||||
this.trip.start();
|
||||
this.inProgress = true;
|
||||
|
||||
}
|
||||
|
||||
lt:number = 0.0;
|
||||
|
||||
public getTripSummary() : string {
|
||||
|
||||
return (
|
||||
'Elapsed - ' + this.trip.elapsed + '\n' +
|
||||
'Origin: ' + 'lat: ' + this.trip.loc.mLatitude.toFixed(8) +
|
||||
' long: ' + this.trip.loc.mLongitude.toFixed(8) + '\n' +
|
||||
'Destination: ' + 'lat: ' + this.trip.loc.mLatitude.toFixed(8) +
|
||||
' long: ' + this.trip.loc.mLongitude.toFixed(8) + '\n' +
|
||||
'CO2: ' + this.trip.CO2 + ' grams ' + this.CO2Effect );
|
||||
|
||||
}
|
||||
|
||||
public getTripPanel() : string {
|
||||
|
||||
if (this.inProgress)
|
||||
if (this.inProgress) {
|
||||
return (
|
||||
'Elapsed - ' + this.clock.display + '\n' +
|
||||
'Geo: ' + 'lat: ' + this.loc.mLatitude + ' long: ' + this.loc.mLatitude + '\n' +
|
||||
'Vector: ' + 'distance: ' + this.distance + ' velocity: ' + this.v + '\n' +
|
||||
'Elapsed - ' + this.trip.elapsed + '\n' +
|
||||
'Geo: ' + 'lat: ' + this.trip.loc.mLatitude.toFixed(8) +
|
||||
' long: ' + this.trip.loc.mLongitude.toFixed(8) + '\n' +
|
||||
'Vector: ' + 'distance: ' + this.trip.ds + ' velocity: ' + this.v + '\n' +
|
||||
'Altitude: ' + this.elevation + '\n');
|
||||
else return("No trip in progress. " + this.nTrips + " trip(s) completed");
|
||||
}
|
||||
else return("No trip in progress. " + this.nTrips + " trip(s) completed.");
|
||||
|
||||
}
|
||||
|
||||
|
@ -149,12 +244,42 @@ export class TripDisplay extends React.Component {
|
|||
|
||||
render() {
|
||||
|
||||
if (!debug)
|
||||
return(
|
||||
<View>
|
||||
<Text style={styles.tripText}>
|
||||
{Trips.getTripPanel() }
|
||||
</Text>
|
||||
</View> );
|
||||
else;
|
||||
return(
|
||||
<View>
|
||||
<Text style={styles.tripText}>
|
||||
{Trips.getTripPanel() }
|
||||
</Text>
|
||||
<Text>{expoGeoState}</Text>
|
||||
</View> );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class TripSummary extends React.Component {
|
||||
|
||||
constructor(props:any) {
|
||||
super(props);
|
||||
this.state = { slug: null };
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return(
|
||||
<View>
|
||||
<Text style={styles.tripText}>
|
||||
{Trips.getTripSummary() }
|
||||
</Text>
|
||||
</View> );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ function RootNavigator() {
|
|||
<Stack.Screen name="Root" component={BottomTabNavigator} options={{ headerShown: false }} />
|
||||
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
|
||||
<Stack.Group screenOptions={{ presentation: 'modal' }}>
|
||||
<Stack.Screen name="Modal" component={ModalScreen} />
|
||||
</Stack.Group>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
|
@ -51,7 +52,7 @@ function RootNavigator() {
|
|||
* A bottom tab navigator displays tab buttons on the bottom of the display to switch screens.
|
||||
* https://reactnavigation.org/docs/bottom-tab-navigator
|
||||
*/
|
||||
const BottomTab = createBottomTabNavigator<RootTabParamList>();
|
||||
export const BottomTab = createBottomTabNavigator<RootTabParamList>();
|
||||
|
||||
function BottomTabNavigator() {
|
||||
const colorScheme = useColorScheme();
|
||||
|
|
|
@ -5,7 +5,10 @@ import { ScreenInfo3 } from '../components/ScreenInfo';
|
|||
|
||||
const image = { uri: "https://meansofproduction.biz/images/GREENT.jpg" };
|
||||
|
||||
export default function HomeScreen() {
|
||||
export var nav:any = null;
|
||||
|
||||
export default function HomeScreen(navigation:any) {
|
||||
nav = navigation;
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ImageBackground source={image} resizeMode="cover" style={styles.image}>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Text, View } from '../components/Themed';
|
|||
import { useState } from 'react';
|
||||
import ScreenInfo from '../components/ScreenInfo';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { Trips } from '../GT2';
|
||||
|
||||
export default function SettingsScreen() {
|
||||
const [number, onChangeNumber] = React.useState("");
|
||||
|
@ -26,15 +27,27 @@ export default function SettingsScreen() {
|
|||
<View style={styles.controls} >
|
||||
<Button
|
||||
title="Jet"
|
||||
onPress={() => Alert.alert('Jet Fuel Selected \n 285 g / passenger / km')}
|
||||
onPress={() => {
|
||||
Trips.co2Rate = 285.0;
|
||||
Trips.CO2Effect = "carbon burden";
|
||||
Alert.alert('Jet Fuel Selected \n 285 g / passenger / km')}
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
title="Gasoline"
|
||||
onPress={() => Alert.alert('Gasoline Selected \n 255 g for driver \n only passenger / km')}
|
||||
onPress={() => {
|
||||
Trips.co2Rate = 285.0;
|
||||
Trips.CO2Effect = "carbon burden";
|
||||
Alert.alert('Gasoline Selected \n 255 g for driver \n only passenger / km')}
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
title="Food"
|
||||
onPress={() => Alert.alert('Savings vs Gasoline Selected')}
|
||||
onPress={() => {
|
||||
Trips.co2Rate = -285.0;
|
||||
Trips.CO2Effect = "carbon relief";
|
||||
Alert.alert('Savings vs Gasoline Selected')}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<TextInput
|
||||
|
@ -42,7 +55,7 @@ export default function SettingsScreen() {
|
|||
returnKeyType={'done'}
|
||||
onChangeText={onChangeNumber}
|
||||
value={number}
|
||||
placeholder="250"
|
||||
placeholder={Trips.co2Rate.toString()}
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
</View>
|
||||
|
|
|
@ -3,7 +3,8 @@ import { useState } from 'react';
|
|||
import { Alert, Button, StyleSheet } from 'react-native';
|
||||
import { Text, View } from '../components/Themed';
|
||||
import { ScreenInfo2 } from '../components/ScreenInfo';
|
||||
import { TripDisplay, Trips } from '../GT2';
|
||||
import EndScreenInfo from '../components/EndScreenInfo';
|
||||
import { locEnabled, getEndPending, toggleEndPending, TripDisplay, Trips } from '../GT2';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -30,8 +31,12 @@ const styles = StyleSheet.create({
|
|||
|
||||
function startTrip() {
|
||||
|
||||
if (!locEnabled ) {
|
||||
Alert.alert("You must enable both foreground\n and background location tracking.");
|
||||
return;
|
||||
}
|
||||
|
||||
Trips.start();
|
||||
Alert.alert('Trip Started');
|
||||
|
||||
}
|
||||
|
||||
|
@ -48,18 +53,14 @@ function pauseTrip() {
|
|||
|
||||
}
|
||||
|
||||
function endTrip() {
|
||||
function endTrip() { Trips.end(); }
|
||||
|
||||
Trips.end();
|
||||
Alert.alert('Trip Ended');
|
||||
|
||||
}
|
||||
|
||||
export default function TripScreen() {
|
||||
export default function TripScreen( navigation:any ) {
|
||||
|
||||
const [sButtonText, setSButtonText] = useState("Start");
|
||||
const [pButtonText, setPButtonText] = useState("Pause");
|
||||
|
||||
if (!getEndPending())
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Trip Control</Text>
|
||||
|
@ -69,8 +70,8 @@ export default function TripScreen() {
|
|||
<Button
|
||||
title={sButtonText}
|
||||
onPress={() => {
|
||||
if (!Trips.inProgress) {setSButtonText("End");startTrip();}
|
||||
else {setSButtonText('Start');setPButtonText('Pause');endTrip();}}
|
||||
if (!Trips.inProgress) {setSButtonText("End");startTrip();setPButtonText('Pause');}
|
||||
else {setSButtonText('Start');endTrip();}}
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
|
@ -84,5 +85,17 @@ export default function TripScreen() {
|
|||
<TripDisplay></TripDisplay>
|
||||
</View>
|
||||
);
|
||||
else
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Trip Control</Text>
|
||||
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
||||
<EndScreenInfo path="/screens/TripScreen.tsx" />
|
||||
<Button title={'Dismiss'}
|
||||
onPress={() => { toggleEndPending(); if (getEndPending()) Alert.alert("t"); else Alert.alert("f"); }}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
## 2.0.0
|
||||
|
||||
- An Expo version of exactly the same functionality as the original 2011 app slightly enhanced
|
||||
except it's a completed and x-platform app.
|
||||
except it's a completed and x-platform app and the overall trip fuel consumption has been corrected.
|
||||
|
||||
This first replacement on play and first version on app store using an expo build will be maintained
|
||||
but the binaries will be available [here](https://sameboat.live/sb-app) after 2.1 replaces it on the app stores.
|
||||
|
|
Loading…
Reference in New Issue