diff --git a/App.js b/App.js
index 3588bce..f4c6ba8 100644
--- a/App.js
+++ b/App.js
@@ -10,11 +10,9 @@ import { DeviceReduxCoupling } from './state/DeviceReduxCoupling';
import { Provider } from 'react-redux';
import ThemedStackNavigation from './components/ThemedStackNavigation';
-
+import NewAppMain from "./components/NewAppMain";
const store = createStore(swimtrackerReducer);
-//const deviceReduxCoupling = new DeviceReduxCoupling(store);
-
export default class App extends React.Component {
constructor(props) {
@@ -38,11 +36,16 @@ export default class App extends React.Component {
if (!this.state.isReady) {
return ;
}
-
+ /*
return (
+ );*/
+ return (
+
+
+
);
}
}
diff --git a/assets/infinity_pool.jpg b/assets/infinity_pool.jpg
new file mode 100644
index 0000000..49bd9ce
Binary files /dev/null and b/assets/infinity_pool.jpg differ
diff --git a/assets/infinity_pool2.jpg b/assets/infinity_pool2.jpg
new file mode 100644
index 0000000..84acf29
Binary files /dev/null and b/assets/infinity_pool2.jpg differ
diff --git a/assets/pool_sky_background_blurred.jpg b/assets/pool_sky_background_blurred.jpg
new file mode 100644
index 0000000..071c614
Binary files /dev/null and b/assets/pool_sky_background_blurred.jpg differ
diff --git a/components/NewAppMain.js b/components/NewAppMain.js
new file mode 100644
index 0000000..218a9a5
--- /dev/null
+++ b/components/NewAppMain.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import { NavigationContainer } from '@react-navigation/native';
+import { createStackNavigator } from '@react-navigation/stack';
+
+// Own views
+import MainMenuView from "../views/MainMenuView";
+import SettingsView from "../views/SettingsView";
+import TrainingView from "../views/TrainingView";
+
+const Stack = createStackNavigator();
+
+function NewAppMain(props) {
+
+ const screenOptions = {
+ headerShown: false,
+ }
+
+ return (
+
+
+
+
+
+
+
+ )
+};
+
+export default NewAppMain;
diff --git a/data_processing/DataAnalysis.js b/data_processing/DataAnalysis.js
index b632ac7..3703fa0 100644
--- a/data_processing/DataAnalysis.js
+++ b/data_processing/DataAnalysis.js
@@ -33,7 +33,6 @@ export default class DataAnalysis {
this.activeMeasurements += newAverages.reduce((n, val) => {
return n + ((val >= analysisParameters.activeTimeThreshold) ? 1 : 0);
}, 0);
- console.log("data", newDataArr, "newAverages", newAverages, "reduction", this.activeMeasurements);
// peaks
const newPeaks = this.peakDetectorSimple.addVector(newDataArr);
@@ -63,7 +62,6 @@ export default class DataAnalysis {
peakMaxWindow: peakMaxWindow,
};
}
-
_resetCache(analysisParameters, sessionId) {
this.movingAverage = analysisParameters ? new MovingAverage(analysisParameters.movingAverageWindowSize) : null;
diff --git a/state/Reducer.js b/state/Reducer.js
index 142804c..63c4edc 100644
--- a/state/Reducer.js
+++ b/state/Reducer.js
@@ -27,6 +27,7 @@ export const stopSession = () => ({
const INITIAL_SETTINGS = {
theme: "hot",
username: "",
+ //swimTrackerHost: "192.168.178.107",
swimTrackerHost: "192.168.178.110",
analysis: {
diff --git a/views/LastSessionView.js b/views/LastSessionView.js
new file mode 100644
index 0000000..e69de29
diff --git a/views/MainMenuView.js b/views/MainMenuView.js
new file mode 100644
index 0000000..9410f7b
--- /dev/null
+++ b/views/MainMenuView.js
@@ -0,0 +1,233 @@
+import React from "react";
+import {
+ StyleSheet,
+ View,
+ StatusBar,
+ ImageBackground,
+ Text,
+ TouchableOpacity,
+} from "react-native";
+import themeColors from './themeColors';
+import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
+import EntypoIcon from "react-native-vector-icons/Entypo";
+
+import { ConnState, startSession } from '../state/DeviceReduxCoupling';
+import { connect } from 'react-redux';
+
+
+// ---------------------------------------------------------------------------------------------
+
+function LargeHeaderView(props) {
+ return (
+
+ swimtracker
+
+ bauer.tech
+
+ );
+}
+
+const largeHeaderStyles = StyleSheet.create({
+ container: {
+ height: 160,
+ maxHeight: 160,
+ flex: 1,
+ alignItems: "center",
+ justifyContent: "flex-end",
+ paddingBottom: 10,
+ //alignContent: "space-between"
+ },
+ titleText: {
+ color: "rgba(255,255,255,1)",
+ fontSize: 48,
+ },
+ subText: {
+ color: "rgba(255,255,255, 0.8)",
+ marginTop: 15,
+ textAlign: "center",
+ },
+ separator: {
+ height: 7,
+ backgroundColor: "rgba(255,255,255,1)",
+ opacity: 0.5,
+ width: 230
+ }
+});
+
+// ---------------------------------------------------------------------------------------------
+
+function ButtonGrid(props) {
+ return (
+
+
+
+
+ {"LETZTE\nSESSIONS"}
+
+
+
+
+
+ SOCIAL
+
+
+
+ EINSTELLUNGEN
+
+
+
+ )
+}
+
+const buttonGridStyles = StyleSheet.create({
+ rowContainer: {
+ flex: 1,
+ flexDirection: "column",
+ justifyContent: "space-around",
+ alignItems: "center",
+ paddingTop: 20,
+ paddingBottom: 50,
+ },
+ columnContainer: {
+ flex: 1,
+ width: "100%",
+ flexDirection: "row",
+ justifyContent: "space-around",
+ alignItems: "center",
+ },
+ button: {
+ flex: 1,
+ margin: 20,
+ padding: 20,
+ width: 120,
+ height: 130,
+ borderRadius: 10,
+ opacity: 0.95,
+ justifyContent: "space-around",
+ alignItems: "center",
+ },
+ buttonText: {
+ color: "rgba(255,255,255,1)",
+ textAlign: "center",
+ fontSize: 16,
+ },
+ icon: {
+ color: "rgba(255,255,255,1)",
+ fontSize: 60,
+ }
+});
+
+// ---------------------------------------------------------------------------------------------
+
+function FullWidthButton(props) {
+ let textStyle = [fullWidthButtonStyles.buttonText];
+ let iconStyle = [fullWidthButtonStyles.icon];
+ if (props.disabled) {
+ textStyle.push(fullWidthButtonStyles.buttonTextDisabled);
+ iconStyle.push(fullWidthButtonStyles.iconDisabled);
+ }
+ return (
+
+
+
+ {props.text}
+
+
+ )
+}
+
+const fullWidthButtonStyles = StyleSheet.create({
+ container: {
+ flex: 1,
+ maxHeight: 70,
+ backgroundColor: themeColors["WET ASPHALT"],
+ flexDirection: "row",
+ alignItems: "center",
+ //paddingBottom: 10,
+ justifyContent: "center",
+ },
+ buttonText: {
+ padding: 10,
+ color: "rgba(255,255,255,1)",
+ fontSize: 25,
+ fontWeight: "600",
+ textAlign: "center",
+ },
+ buttonTextDisabled: {
+ opacity: 0.3,
+ },
+ icon: {
+ fontSize: 40,
+ padding: 10,
+ color: themeColors["GREEN SEA"],
+ },
+ iconDisabled: {
+ color: themeColors["POMEGRANATE"],
+ },
+});
+
+
+// ---------------------------------------------------------------------------------------------
+
+function MainMenuView(props) {
+ const s = props.connState;
+ let startButtonText = "JETZT SCHWIMMEN";
+ let startButtonDisabled = false;
+ if (s === ConnState.DISCONNECTED) {
+ startButtonText = "NICHT VERBUNDEN";
+ startButtonDisabled = true;
+ } else if (s === ConnState.CONNECTED_RUNNING || s === ConnState.CONNECTED_STARTING) {
+ startButtonText = "TRAINING LÄUFT";
+ } else if (s === ConnState.CONNECTED_STOPPING) {
+ startButtonDisabled = true;
+ }
+
+ const onStartButtonPress = () => {
+ if (!props.connState !== ConnState.CONNECTED_RUNNING) {
+ props.dispatch(startSession());
+ }
+ props.navigation.navigate('Training')
+ };
+
+ return (
+
+
+
+
+
+ props.navigation.navigate('Settings')} />
+
+
+
+
+ );
+}
+
+const mapStateToProps = (state) => {
+ return { connState: state.deviceState.connState };
+};
+
+export default connect(mapStateToProps)(MainMenuView);
diff --git a/views/SettingsView.js b/views/SettingsView.js
new file mode 100644
index 0000000..358dde2
--- /dev/null
+++ b/views/SettingsView.js
@@ -0,0 +1,207 @@
+import React, { useState } from "react";
+import {
+ StyleSheet,
+ View,
+ StatusBar,
+ TextInput,
+ ImageBackground,
+ Text,
+ TouchableOpacity,
+ SafeAreaView,
+ Slider,
+ Switch,
+} from "react-native";
+import themeColors from './themeColors';
+import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
+import EntypoIcon from "react-native-vector-icons/Entypo";
+
+
+function ImageHeader(props) {
+ return (
+
+
+
+ props.navigation.goBack()}>
+
+
+ {props.text}
+
+
+
+ )
+}
+
+const imageHeaderStyles = StyleSheet.create({
+ container: {
+ flex: 1,
+ minHeight: 175,
+ maxHeight: 175,
+ height: 175,
+ width: "100%",
+ },
+ row: {
+ paddingTop: 30,
+ flexDirection: "row",
+ },
+ icon: {
+ color: "white",
+ fontSize: 40,
+ paddingRight: 10,
+ paddingLeft: 10,
+ },
+ text: {
+ color: "white",
+ fontSize: 30,
+ },
+});
+
+// ---------------------------------------------------------------------------------------------
+
+function SettingsTextInput(props) {
+ return (
+
+ {props.label}
+
+
+ );
+}
+
+function SettingsSwitch(props) {
+ const [isEnabled, setIsEnabled] = useState(false);
+ const toggleSwitch = () => setIsEnabled(previousState => !previousState);
+
+ return (
+
+ {props.label}
+
+
+ )
+}
+
+function SettingsSlider(props) {
+ return (
+
+ {props.label}
+
+
+ )
+}
+
+function SettingsCombo(props) {
+
+}
+
+
+function SettingsGroup(props) {
+
+ return (
+
+ {props.title}
+
+ {React.Children.map(props.children, (child, idx) =>
+
+ {child}
+
+ )}
+
+
+ );
+};
+
+const settingsGroupStyles = StyleSheet.create({
+ container: {
+ padding: 20,
+ paddingRight: 30,
+ },
+ title: {
+ color: "white",
+ fontSize: 20,
+ fontWeight: "600",
+ },
+ subsettings: {
+ padding: 10,
+ paddingLeft: 30,
+ },
+ row: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ borderTopColor: "rgba(255, 255,255, 0.6)",
+ paddingTop: 5,
+ paddingBottom: 5,
+ borderTopWidth: 0.5,
+ minHeight: 40,
+ },
+ firstRow: {
+ paddingTop: 0,
+ borderTopWidth: 0,
+ },
+ label: {
+ color: "white",
+ fontSize: 17,
+ },
+ textInput: {
+ color: "rgba(255,255,255,1)",
+ marginTop: 8,
+ },
+ slider: {
+ minWidth: 100,
+ width: 150,
+ //minHeight: 50,
+ },
+ switch: {
+ //minHeight: 50,
+ //minWidth: 80,
+ }
+});
+
+// ---------------------------------------------------------------------------------------------
+
+
+function SettingsView(props) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default SettingsView;
\ No newline at end of file
diff --git a/views/TrainingView.js b/views/TrainingView.js
new file mode 100644
index 0000000..ea6f0bc
--- /dev/null
+++ b/views/TrainingView.js
@@ -0,0 +1,132 @@
+import React, { Component } from "react";
+import {
+ StyleSheet,
+ View,
+ StatusBar,
+ Text,
+ TouchableOpacity,
+ SafeAreaView
+} from "react-native";
+import themeColors from './themeColors';
+import EntypoIcon from "react-native-vector-icons/Entypo";
+
+import { connect } from 'react-redux';
+import { useKeepAwake } from 'expo-keep-awake';
+import { stopSession } from '../state/DeviceReduxCoupling';
+import CycleView from '../components/CycleView';
+import IconCard from '../components/IconCard';
+import Graph from '../components/Graph';
+
+
+function SmallHeaderView(props) {
+ return (
+
+
+ props.navigation.goBack()}>
+
+
+ {props.text}
+
+
+
+
+
+ )
+}
+
+const smallHeaderStyles = StyleSheet.create({
+ container: {
+ flex: 1,
+ minHeight: 80,
+ maxHeight: 80,
+ height: 80,
+ width: "100%",
+ backgroundColor: themeColors["WET ASPHALT"],
+ },
+ row: {
+ paddingTop: 30,
+ flexDirection: "row",
+ justifyContent: "space-between",
+ },
+ backIcon: {
+ color: "white",
+ fontSize: 40,
+ },
+ stopIcon: {
+ color: themeColors["ALIZARIN"],
+ fontSize: 40,
+ paddingRight: 10,
+ paddingLeft: 10,
+ },
+ text: {
+ color: "white",
+ fontSize: 30,
+ },
+});
+
+const toTimeStr = seconds => {
+ let minuteStr = String(Math.floor(seconds / 60));
+ if (minuteStr.length < 2)
+ minuteStr = "0" + minuteStr;
+ let secondStr = String(Math.floor(seconds % 60));
+ if (secondStr.length < 2)
+ secondStr = "0" + secondStr;
+ return minuteStr + ":" + secondStr;
+}
+
+// ---------------------------------------------------------------------------------------------
+
+function TrainingView(props) {
+ useKeepAwake();
+
+ const analysis = props.session.analysis;
+ const laps = (analysis.peaks.size / props.peaksPerLap).toFixed(1);
+ const totalMomentum = Math.trunc(analysis.totalMomentum * props.kgFactor / 10 / 60);
+
+ const onStopPressed = () => {
+ props.dispatch(stopSession());
+ props.navigation.navigate('Home');
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+const trainingViewStyles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: themeColors["BELIZE HOLE"],
+ padding: 20,
+ justifyContent: "space-around",
+ }
+});
+
+const mapStateToProps = (state) => {
+ return {
+ session: state.deviceState,
+ peaksPerLap: state.settings.analysis.peaksPerLap,
+ theme: state.settings.theme,
+ kgFactor: state.settings.analysis.kgFactor,
+ };
+};
+export default connect(mapStateToProps)(TrainingView);
diff --git a/views/themeColors.js b/views/themeColors.js
new file mode 100644
index 0000000..5f2854c
--- /dev/null
+++ b/views/themeColors.js
@@ -0,0 +1,26 @@
+// https://flatuicolors.com/palette/defo
+
+const themeColors = {
+ 'TURQUOISE': "rgb(26, 188, 156)",
+ "EMERALD": "rgb(46, 204, 113)",
+ "PETER RIVER" : "rgb(52, 152, 219)",
+ "AMETHYST" : "rgb(155, 89, 182)",
+ "WET ASPHALT" : "rgb(52, 73, 94)",
+ "GREEN SEA" : "rgb(22, 160, 133)",
+ "NEPHRITIS" : "rgb(39, 174, 96)",
+ "BELIZE HOLE" : "rgb(41, 128, 185)",
+ "WISTERIA" : "rgb(142, 68, 173)",
+ "MIDNIGHT BLUE" : "rgb(44, 62, 80)",
+ "SUN FLOWER" : "rgb(241, 196, 15)",
+ "CARROT" : "rgb(230, 126, 34)",
+ "ALIZARIN" : "rgb(231, 76, 60)",
+ "CLOUDS" : "rgb(236, 240, 241)",
+ "CONCRETE" : "rgb(149, 165, 166)",
+ "ORANGE" : "rgb(243, 156, 18)",
+ "PUMPKIN" : "rgb(211, 84, 0)",
+ "POMEGRANATE" : "rgb(192, 57, 43)",
+ "SILVER" : "rgb(189, 195, 199)",
+ "ASBESTOS" : "rgb(127, 140, 141)",
+};
+
+export default themeColors;