Lots of changes
- internationalization - new logo - connection screen improved - always try provisioning IP for connection
This commit is contained in:
parent
03812fe514
commit
4614a28ead
|
@ -9,3 +9,4 @@ npm-debug.*
|
||||||
*.orig.*
|
*.orig.*
|
||||||
web-build/
|
web-build/
|
||||||
web-report/
|
web-report/
|
||||||
|
/dist
|
27
App.js
27
App.js
|
@ -13,6 +13,12 @@ import { persistStore, persistReducer } from 'redux-persist'
|
||||||
import hardSet from 'redux-persist/lib/stateReconciler/hardSet'
|
import hardSet from 'redux-persist/lib/stateReconciler/hardSet'
|
||||||
import { PersistGate } from 'redux-persist/integration/react'
|
import { PersistGate } from 'redux-persist/integration/react'
|
||||||
|
|
||||||
|
// Internationalization
|
||||||
|
import * as Localization from 'expo-localization';
|
||||||
|
import i18n from 'i18n-js';
|
||||||
|
import en from "./locales/en/translations";
|
||||||
|
import de from "./locales/de/translations";
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
|
@ -27,13 +33,23 @@ import WifiSelectionView from './views/WifiSelectionView';
|
||||||
import WifiPasswordView from './views/WifiPasswordView';
|
import WifiPasswordView from './views/WifiPasswordView';
|
||||||
|
|
||||||
|
|
||||||
|
// Set the key-value pairs for the different languages you want to support.
|
||||||
|
i18n.translations = {
|
||||||
|
en: en,
|
||||||
|
de: de,
|
||||||
|
};
|
||||||
|
i18n.locale = "de-DE"; //Localization.locale; // Set the locale once at the beginning of your app.
|
||||||
|
i18n.fallbacks = true; // When a value is missing from a language it'll fallback to another language with the key present.
|
||||||
|
|
||||||
|
console.log("locale", i18n.locale);
|
||||||
|
|
||||||
const persistConfig = {
|
const persistConfig = {
|
||||||
key: 'root',
|
key: 'root',
|
||||||
storage: AsyncStorage,
|
storage: AsyncStorage,
|
||||||
stateReconciler: hardSet,
|
// stateReconciler: hardSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
const persistedReducer = persistReducer(persistConfig, swimtrackerReducer)
|
const persistedReducer = persistReducer(persistConfig, swimtrackerReducer);
|
||||||
const store = createStore(persistedReducer);
|
const store = createStore(persistedReducer);
|
||||||
const persistor = persistStore(store);
|
const persistor = persistStore(store);
|
||||||
const Stack = createStackNavigator();
|
const Stack = createStackNavigator();
|
||||||
|
@ -112,9 +128,9 @@ export default class App extends React.Component {
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Settings"
|
name="Settings"
|
||||||
component={SettingsView}
|
options={screenOptions}>
|
||||||
options={screenOptions}
|
{props => <SettingsView {...props} device={this.device} />}
|
||||||
/>
|
</Stack.Screen>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Training"
|
name="Training"
|
||||||
component={TrainingView}
|
component={TrainingView}
|
||||||
|
@ -129,7 +145,6 @@ export default class App extends React.Component {
|
||||||
);
|
);
|
||||||
|
|
||||||
let activeView;
|
let activeView;
|
||||||
|
|
||||||
if (this.state.disconnected)
|
if (this.state.disconnected)
|
||||||
activeView = disconnectedView;
|
activeView = disconnectedView;
|
||||||
else if (this.state.isProvisioning)
|
else if (this.state.isProvisioning)
|
||||||
|
|
6
app.json
6
app.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"expo": {
|
"expo": {
|
||||||
"name": "swimtrainer-app",
|
"name": "SwimTracker",
|
||||||
"slug": "swimtrainer-app",
|
"slug": "swimtracker",
|
||||||
"privacy": "public",
|
"privacy": "public",
|
||||||
"platforms": [
|
"platforms": [
|
||||||
"ios",
|
"ios",
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
"icon": "./assets/icon.png",
|
"icon": "./assets/icon.png",
|
||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/splash.png",
|
"image": "./assets/splash.png",
|
||||||
"resizeMode": "contain",
|
"resizeMode": "cover",
|
||||||
"backgroundColor": "#ffffff"
|
"backgroundColor": "#ffffff"
|
||||||
},
|
},
|
||||||
"updates": {
|
"updates": {
|
||||||
|
|
BIN
assets/icon.png
BIN
assets/icon.png
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 20 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 814 KiB |
|
@ -32,13 +32,13 @@ function ImageHeader(props) {
|
||||||
const imageHeaderStyles = StyleSheet.create({
|
const imageHeaderStyles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
minHeight: 175,
|
minHeight: 185,
|
||||||
maxHeight: 175,
|
maxHeight: 185,
|
||||||
height: 175,
|
height: 175,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
row: {
|
row: {
|
||||||
paddingTop: 30,
|
paddingTop: 40,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
|
|
|
@ -28,6 +28,7 @@ const OpCodes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const HEARTBEAT_TIMEOUT = 3000;
|
const HEARTBEAT_TIMEOUT = 3000;
|
||||||
|
const PROVISIONING_IP = "192.168.42.1";
|
||||||
|
|
||||||
export default class SwimTrackerWebsocketConnection {
|
export default class SwimTrackerWebsocketConnection {
|
||||||
constructor(swimTrackerHost, onData, onStarted, onStopped, onWifiStateInfo, onConnect, onDisconnect) {
|
constructor(swimTrackerHost, onData, onStarted, onStopped, onWifiStateInfo, onConnect, onDisconnect) {
|
||||||
|
@ -40,11 +41,13 @@ export default class SwimTrackerWebsocketConnection {
|
||||||
this.onConnect = onConnect;
|
this.onConnect = onConnect;
|
||||||
this.onDisconnect = onDisconnect;
|
this.onDisconnect = onDisconnect;
|
||||||
|
|
||||||
const wsOptions = {
|
|
||||||
maxReconnectionDelay: 4000
|
// try configured URL and provisioning URL
|
||||||
};
|
const urls = [`ws://${swimTrackerHost}:81`, `ws://${PROVISIONING_IP}:81`];
|
||||||
|
let urlIndex = 0;
|
||||||
|
const urlProvider = () => urls[urlIndex++ % urls.length]; // round robin url provider
|
||||||
|
|
||||||
this.ws = new ReconnectingWebSocket(`ws://${swimTrackerHost}:81`, [], wsOptions);
|
this.ws = new ReconnectingWebSocket(urlProvider, [], { maxReconnectionDelay: 3000 });
|
||||||
this.ws.onmessage = this._onMessage;
|
this.ws.onmessage = this._onMessage;
|
||||||
this.ws.onopen = this.onConnect;
|
this.ws.onopen = this.onConnect;
|
||||||
this.ws.onclose = this.onDisconnect;
|
this.ws.onclose = this.onDisconnect;
|
||||||
|
@ -67,7 +70,8 @@ export default class SwimTrackerWebsocketConnection {
|
||||||
|
|
||||||
let connection = this;
|
let connection = this;
|
||||||
this.pingTimeout = setTimeout(() => {
|
this.pingTimeout = setTimeout(() => {
|
||||||
connection.ws.reconnect();
|
if(connection.ws !== null)
|
||||||
|
connection.ws.reconnect();
|
||||||
}, HEARTBEAT_TIMEOUT);
|
}, HEARTBEAT_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +94,7 @@ export default class SwimTrackerWebsocketConnection {
|
||||||
this._sendMsg(OpCodes.STOP_SESSION);
|
this._sendMsg(OpCodes.STOP_SESSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendTareCommand() {
|
sendTareCommand = () => {
|
||||||
this._sendMsg(OpCodes.TARE);
|
this._sendMsg(OpCodes.TARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +109,7 @@ export default class SwimTrackerWebsocketConnection {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wifiResetToProvisioning() {
|
sendTareCommand = () => {
|
||||||
this._sendMsg(OpCodes.WIFI_STATE_SET, {
|
this._sendMsg(OpCodes.WIFI_STATE_SET, {
|
||||||
"reset_to_provisioning": true,
|
"reset_to_provisioning": true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
# Based on https://docs.expo.io/distribution/turtle-cli/
|
||||||
|
|
||||||
|
|
||||||
|
npm -g install turtle-cli --legacy-peer-deps
|
||||||
|
|
||||||
|
# Needs jdk 8
|
||||||
|
apt install openjdk-8-jdk-headless
|
||||||
|
export PATH=/usr/lib/jvm/java-8-openjdk-amd64/bin/:$PATH
|
||||||
|
turtle setup:android
|
|
@ -0,0 +1,11 @@
|
||||||
|
export default {
|
||||||
|
connecting: "Verbindung aufbauen",
|
||||||
|
connectSubtext: "Gehe entweder in das WLAN deines SwimTrackers oder in dein eigenes WLAN, falls du den SwimTracker schon eingerichtet hast.",
|
||||||
|
simpleMode: "Weniger Einstellungen",
|
||||||
|
advancedMode: "Mehr Einstellungen",
|
||||||
|
settings: "Einstellungen",
|
||||||
|
help: "Hilfe",
|
||||||
|
mainMenu_lastSessions: "Letzte Sessions",
|
||||||
|
mainMenu_social: "Freunde",
|
||||||
|
mainMenu_swimNow: "Jetzt schwimmen",
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export default {
|
||||||
|
connecting: "Connecting",
|
||||||
|
connectSubtext: "Please connect your phone to the WiFi of your SwimTracker",
|
||||||
|
simpleMode: "Simple Mode",
|
||||||
|
advancedMode: "Advanced Mode",
|
||||||
|
help: "Need help?",
|
||||||
|
settings: "Settings",
|
||||||
|
mainMenu_lastSessions: "Last Sessions",
|
||||||
|
mainMenu_social: "Social",
|
||||||
|
mainMenu_swimNow: "Start training now"
|
||||||
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
"expo-blur": "~9.0.3",
|
"expo-blur": "~9.0.3",
|
||||||
"expo-keep-awake": "~9.1.2",
|
"expo-keep-awake": "~9.1.2",
|
||||||
"expo-linear-gradient": "~9.1.0",
|
"expo-linear-gradient": "~9.1.0",
|
||||||
|
"expo-localization": "~10.1.0",
|
||||||
"immutable": "^4.0.0-rc.12",
|
"immutable": "^4.0.0-rc.12",
|
||||||
"moment": "^2.27.0",
|
"moment": "^2.27.0",
|
||||||
"msgpack-lite": "^0.1.26",
|
"msgpack-lite": "^0.1.26",
|
||||||
|
@ -7709,6 +7710,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-9.1.0.tgz",
|
||||||
"integrity": "sha512-9W4TxaDrZUzmLzd18+Eo2Ef7ONnuLrHKX0PRyHEGY2/rJCtGiPJtJuR6AS5dkX7WB/Pxlx0zK/p/qDHHw09Uxg=="
|
"integrity": "sha512-9W4TxaDrZUzmLzd18+Eo2Ef7ONnuLrHKX0PRyHEGY2/rJCtGiPJtJuR6AS5dkX7WB/Pxlx0zK/p/qDHHw09Uxg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-localization": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-covyQ1YJneUBvjkNp0p8Lp7ej5Plz1OpJiwA2P6O3hZ4yVVqNDOOAb2WADLARPtxNJrDdntSozgI+JSz/yQxmQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"rtl-detect": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-permissions": {
|
"node_modules/expo-permissions": {
|
||||||
"version": "12.0.1",
|
"version": "12.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/expo-permissions/-/expo-permissions-12.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/expo-permissions/-/expo-permissions-12.0.1.tgz",
|
||||||
|
@ -17812,6 +17821,11 @@
|
||||||
"node": "6.* || >= 7.*"
|
"node": "6.* || >= 7.*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rtl-detect": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ=="
|
||||||
|
},
|
||||||
"node_modules/run-async": {
|
"node_modules/run-async": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||||
|
@ -25951,6 +25965,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-9.1.0.tgz",
|
||||||
"integrity": "sha512-9W4TxaDrZUzmLzd18+Eo2Ef7ONnuLrHKX0PRyHEGY2/rJCtGiPJtJuR6AS5dkX7WB/Pxlx0zK/p/qDHHw09Uxg=="
|
"integrity": "sha512-9W4TxaDrZUzmLzd18+Eo2Ef7ONnuLrHKX0PRyHEGY2/rJCtGiPJtJuR6AS5dkX7WB/Pxlx0zK/p/qDHHw09Uxg=="
|
||||||
},
|
},
|
||||||
|
"expo-localization": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-covyQ1YJneUBvjkNp0p8Lp7ej5Plz1OpJiwA2P6O3hZ4yVVqNDOOAb2WADLARPtxNJrDdntSozgI+JSz/yQxmQ==",
|
||||||
|
"requires": {
|
||||||
|
"rtl-detect": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"expo-permissions": {
|
"expo-permissions": {
|
||||||
"version": "12.0.1",
|
"version": "12.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/expo-permissions/-/expo-permissions-12.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/expo-permissions/-/expo-permissions-12.0.1.tgz",
|
||||||
|
@ -33831,6 +33853,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||||
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
|
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
|
||||||
},
|
},
|
||||||
|
"rtl-detect": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ=="
|
||||||
|
},
|
||||||
"run-async": {
|
"run-async": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
"expo-blur": "~9.0.3",
|
"expo-blur": "~9.0.3",
|
||||||
"expo-keep-awake": "~9.1.2",
|
"expo-keep-awake": "~9.1.2",
|
||||||
"expo-linear-gradient": "~9.1.0",
|
"expo-linear-gradient": "~9.1.0",
|
||||||
|
"expo-localization": "~10.1.0",
|
||||||
|
"i18n-js": "^3.8.0",
|
||||||
"immutable": "^4.0.0-rc.12",
|
"immutable": "^4.0.0-rc.12",
|
||||||
"moment": "^2.27.0",
|
"moment": "^2.27.0",
|
||||||
"msgpack-lite": "^0.1.26",
|
"msgpack-lite": "^0.1.26",
|
||||||
|
|
|
@ -30,9 +30,10 @@ export const STOP_SESSION = "STOP_SESSION";
|
||||||
|
|
||||||
export const WIFI_SET_STATE = "WIFI_SET_STATE";
|
export const WIFI_SET_STATE = "WIFI_SET_STATE";
|
||||||
|
|
||||||
export const reportNewWifiState = (newStateStr) => ({
|
export const reportNewWifiState = (newStateStr, newHostname) => ({
|
||||||
type: WIFI_SET_STATE,
|
type: WIFI_SET_STATE,
|
||||||
newStateStr: newStateStr
|
newStateStr: newStateStr,
|
||||||
|
newHostname: newHostname,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const reportSessionStarted = (sessionId) => ({
|
export const reportSessionStarted = (sessionId) => ({
|
||||||
|
@ -83,7 +84,6 @@ export class DeviceReduxCoupling {
|
||||||
const state = this.reduxStore.getState();
|
const state = this.reduxStore.getState();
|
||||||
|
|
||||||
if (this.conn === null || (state.settings.swimTrackerHost != this.conn.swimTrackerHost)) {
|
if (this.conn === null || (state.settings.swimTrackerHost != this.conn.swimTrackerHost)) {
|
||||||
console.log(" ---- starting websocket connection to ", state.settings.swimTrackerHost);
|
|
||||||
if( this.conn !== null) {
|
if( this.conn !== null) {
|
||||||
this.conn.close();
|
this.conn.close();
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ export class DeviceReduxCoupling {
|
||||||
this._onNewData,
|
this._onNewData,
|
||||||
(sessionId) => this.reduxStore.dispatch(reportSessionStarted(sessionId)),
|
(sessionId) => this.reduxStore.dispatch(reportSessionStarted(sessionId)),
|
||||||
() => this.reduxStore.dispatch(reportSessionStopped()),
|
() => this.reduxStore.dispatch(reportSessionStopped()),
|
||||||
(response) => this.reduxStore.dispatch(reportNewWifiState(response["state"])),
|
(response) => this.reduxStore.dispatch(reportNewWifiState(response["state"], response["hostname"])),
|
||||||
() => this.reduxStore.dispatch(reportDeviceConnect()),
|
() => this.reduxStore.dispatch(reportDeviceConnect()),
|
||||||
() => this.reduxStore.dispatch(reportDeviceDisconnect())
|
() => this.reduxStore.dispatch(reportDeviceDisconnect())
|
||||||
);
|
);
|
||||||
|
@ -130,6 +130,7 @@ const INITIAL_DEVICE_STATE = {
|
||||||
sessionId: 0,
|
sessionId: 0,
|
||||||
measurements: List(),
|
measurements: List(),
|
||||||
analysis: INITIAL_ANALYSIS,
|
analysis: INITIAL_ANALYSIS,
|
||||||
|
deviceReportedHostname: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => {
|
export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => {
|
||||||
|
@ -162,7 +163,7 @@ export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => {
|
||||||
if (action.newStateStr === "STATION_MODE") { wifiState = WifiState.STA; }
|
if (action.newStateStr === "STATION_MODE") { wifiState = WifiState.STA; }
|
||||||
else if (action.newStateStr === "AP_PROVISIONING") { wifiState = WifiState.AP_PROVISIONING; }
|
else if (action.newStateStr === "AP_PROVISIONING") { wifiState = WifiState.AP_PROVISIONING; }
|
||||||
else if (action.newStateStr === "AP_SECURE") { wifiState = WifiState.AP_SECURE; }
|
else if (action.newStateStr === "AP_SECURE") { wifiState = WifiState.AP_SECURE; }
|
||||||
return { ...state, wifiState: wifiState };
|
return { ...state, wifiState: wifiState, deviceReportedHostname: action.newHostname };
|
||||||
default:
|
default:
|
||||||
//console.log("Unhandled state in deviceStateReducer", action, action.type, "state", state);
|
//console.log("Unhandled state in deviceStateReducer", action, action.type, "state", state);
|
||||||
return state;
|
return state;
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const changeUsername = newUsername => ({
|
||||||
newUserName: newUsername,
|
newUserName: newUsername,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const changeSwimTrackerHostname = newSwimTrackerHost => ( {
|
export const changeSwimTrackerHostname = newSwimTrackerHost => ({
|
||||||
type: CHANGE_SWIMTRACKER_HOSTNAME,
|
type: CHANGE_SWIMTRACKER_HOSTNAME,
|
||||||
newSwimTrackerHost: newSwimTrackerHost,
|
newSwimTrackerHost: newSwimTrackerHost,
|
||||||
});
|
});
|
||||||
|
@ -34,7 +34,7 @@ const INITIAL_SETTINGS = {
|
||||||
windowSizeInSecs: 5,
|
windowSizeInSecs: 5,
|
||||||
numMeasurementsPerSec: 10,
|
numMeasurementsPerSec: 10,
|
||||||
|
|
||||||
kgFactor: 1.0 / 701.0,
|
kgFactor: 1.0 / 701.0,
|
||||||
|
|
||||||
peakDetector: 'SIMPLE', // either 'SIMPLE' or 'ZSCORE'
|
peakDetector: 'SIMPLE', // either 'SIMPLE' or 'ZSCORE'
|
||||||
peakDetectorSimpleThreshold: 2000,
|
peakDetectorSimpleThreshold: 2000,
|
||||||
|
@ -44,17 +44,17 @@ const INITIAL_SETTINGS = {
|
||||||
peakDetectorZScoreInfluence: 0.1,
|
peakDetectorZScoreInfluence: 0.1,
|
||||||
|
|
||||||
activeTimeThreshold: 700,
|
activeTimeThreshold: 700,
|
||||||
movingAverageWindowSize: 10*3,
|
movingAverageWindowSize: 10 * 3,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const settingsReducer = (state = INITIAL_SETTINGS, action) => {
|
const settingsReducer = (state = INITIAL_SETTINGS, action) => {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case CHANGE_USER_NAME:
|
case CHANGE_USER_NAME:
|
||||||
return { ...state, username: action.newUsername };
|
return { ...state, username: action.newUsername };
|
||||||
case CHANGE_SWIMTRACKER_HOSTNAME:
|
case CHANGE_SWIMTRACKER_HOSTNAME:
|
||||||
return {... state, swimTrackerHost: action.newSwimTrackerHost};
|
return { ...state, swimTrackerHost: action.newSwimTrackerHost };
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
|
@ -8,37 +8,59 @@ import {
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
|
||||||
import SetupView from '../components/SetupView';
|
import SetupView from '../components/SetupView';
|
||||||
import EvilIcon from "react-native-vector-icons/EvilIcons";
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { changeSwimTrackerHostname } from '../state/Reducer';
|
import { changeSwimTrackerHostname } from '../state/Reducer';
|
||||||
|
import i18n from 'i18n-js';
|
||||||
|
|
||||||
|
const validHostnameRegex = /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))|(^\s*((?=.{1,255}$)(?=.*[A-Za-z].*)[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?)*)\s*$)/;
|
||||||
|
|
||||||
|
function isValidHostname(hostname) {
|
||||||
|
return validHostnameRegex.test(hostname);
|
||||||
|
}
|
||||||
|
|
||||||
function ConnectingView(props) {
|
function ConnectingView(props) {
|
||||||
|
|
||||||
|
const [isHostnameValid, setIsHostnameValid] = useState(isValidHostname(props.swimTrackerHost));
|
||||||
|
const [hostnameTextInput, setHostnameTextInput] = useState(props.swimTrackerHost);
|
||||||
|
const [advancedMode, setAdvancedMode] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
let onHostnameChange = newHostName => {
|
let onHostnameChange = newHostName => {
|
||||||
props.dispatch(changeSwimTrackerHostname(newHostName));
|
setHostnameTextInput(newHostName);
|
||||||
|
const newHostnameValid = isValidHostname(newHostName);
|
||||||
|
setIsHostnameValid(newHostnameValid);
|
||||||
|
if (newHostnameValid) {
|
||||||
|
props.dispatch(changeSwimTrackerHostname(newHostName));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hiddenStyle = advancedMode ? {} : {"display": "none"};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SetupView
|
<SetupView
|
||||||
headerText="Connecting..."
|
headerText={i18n.t("connecting") + "..."}
|
||||||
lowerLeftButtonText="Advanced Setup"
|
lowerLeftButtonText={ i18n.t(advancedMode ? 'simpleMode' : 'advancedMode') }
|
||||||
lowerRightButtonText="Need help?"
|
onLowerLeftButtonPress={() => { setAdvancedMode(!advancedMode); }}
|
||||||
|
lowerRightButtonText={i18n.t('help')}
|
||||||
>
|
>
|
||||||
|
<View style={{flexDirection: "row", alignItems: "center"}}>
|
||||||
<ActivityIndicator size="large" color="#ffffff" />
|
<ActivityIndicator size="large" color="#ffffff" />
|
||||||
<Text style={styles.subtext}>
|
<Text style={styles.subtext}>
|
||||||
Please connect your phone to the WiFi of your SwimTracker
|
{i18n.t('connectSubtext')}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={styles.row}>
|
|
||||||
<EvilIcon name="archive" style={styles.hostIcon}></EvilIcon>
|
|
||||||
<TextInput
|
|
||||||
onChangeText={onHostnameChange}
|
|
||||||
value={props.swimTrackerHost}
|
|
||||||
style={styles.hostnameInput}
|
|
||||||
placeholder="Hostname/IP"
|
|
||||||
placeholderTextColor="rgba(255,255,255,0.5)"
|
|
||||||
></TextInput>
|
|
||||||
</View>
|
</View>
|
||||||
|
{true &&
|
||||||
|
<View style={StyleSheet.flatten([styles.row, hiddenStyle])}>
|
||||||
|
<Text style={styles.label}>Host:</Text>
|
||||||
|
<TextInput
|
||||||
|
onChangeText={onHostnameChange}
|
||||||
|
value={hostnameTextInput}
|
||||||
|
style={{ ...styles.hostnameInput, color: isHostnameValid ? "rgb(255, 255, 255)" : "rgb(255, 150, 150)" }}
|
||||||
|
placeholderTextColor="rgba(255,255,255,0.5)"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
</SetupView>
|
</SetupView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -46,32 +68,33 @@ function ConnectingView(props) {
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
subtext: {
|
subtext: {
|
||||||
color: "rgba(255,255,255,1)",
|
color: "rgba(255,255,255,1)",
|
||||||
textAlign: "center",
|
textAlign: "left",
|
||||||
fontSize: 18,
|
fontSize: 16,
|
||||||
lineHeight: 25,
|
lineHeight: 25,
|
||||||
width: "80%",
|
width: "100%",
|
||||||
|
//paddingTop: 50,
|
||||||
|
paddingLeft: 30,
|
||||||
},
|
},
|
||||||
row: {
|
row: {
|
||||||
backgroundColor: "rgba(255,255,255,0.4)",
|
backgroundColor: "rgba(255,255,255,0.4)",
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: "80%",
|
width: "100%",
|
||||||
height: 50,
|
height: 50,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
marginTop: 60,
|
marginTop: 60,
|
||||||
marginBottom: 5,
|
marginBottom: 5,
|
||||||
},
|
},
|
||||||
hostIcon: {
|
|
||||||
fontSize: 25,
|
|
||||||
color: "rgba(255,255,255,1)",
|
|
||||||
marginLeft: 15,
|
|
||||||
marginRight: 15,
|
|
||||||
},
|
|
||||||
hostnameInput: {
|
hostnameInput: {
|
||||||
height: 30,
|
height: 30,
|
||||||
color: "rgba(255,255,255,1)",
|
color: "rgba(255,255,255,1)",
|
||||||
width: "80%",
|
width: "80%",
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
},
|
||||||
|
label : {
|
||||||
|
color: "rgb(80, 80, 80)",
|
||||||
|
marginLeft: 15,
|
||||||
|
marginRight: 10,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -248,7 +248,7 @@ class LastSessionsView extends React.Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<StatusBar hidden={true} />
|
<StatusBar barStyle="light-content" backgroundColor="rgba(0,0,0,0.4)" translucent={true} />
|
||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<ImageHeader
|
<ImageHeader
|
||||||
text="LETZTE SESSIONS"
|
text="LETZTE SESSIONS"
|
||||||
|
|
|
@ -12,10 +12,8 @@ import MaterialIcon from "react-native-vector-icons/MaterialIcons";
|
||||||
import MaterialCommIcon from "react-native-vector-icons/MaterialCommunityIcons";
|
import MaterialCommIcon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
|
|
||||||
import EntypoIcon from "react-native-vector-icons/Entypo";
|
import EntypoIcon from "react-native-vector-icons/Entypo";
|
||||||
import FeatherIcon from "react-native-vector-icons/Feather";
|
|
||||||
|
|
||||||
//import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
||||||
|
|
||||||
|
import i18n from 'i18n-js';
|
||||||
|
|
||||||
import { ConnState, startSession } from '../state/DeviceReduxCoupling';
|
import { ConnState, startSession } from '../state/DeviceReduxCoupling';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
@ -41,7 +39,6 @@ const largeHeaderStyles = StyleSheet.create({
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "flex-end",
|
justifyContent: "flex-end",
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
//alignContent: "space-between"
|
|
||||||
},
|
},
|
||||||
titleText: {
|
titleText: {
|
||||||
color: "rgba(255,255,255,1)",
|
color: "rgba(255,255,255,1)",
|
||||||
|
@ -72,17 +69,18 @@ function ButtonGrid(props) {
|
||||||
activeOpacity={0.6}
|
activeOpacity={0.6}
|
||||||
>
|
>
|
||||||
<MaterialCommIcon name="swim" style={buttonGridStyles.icon}></MaterialCommIcon>
|
<MaterialCommIcon name="swim" style={buttonGridStyles.icon}></MaterialCommIcon>
|
||||||
<Text style={buttonGridStyles.buttonText}>{"LETZTE\nSESSIONS"}</Text>
|
<Text style={buttonGridStyles.buttonText}>{ i18n.t('mainMenu_lastSessions').toUpperCase().split(" ").join("\n") }</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<View style={buttonGridStyles.columnContainer}>
|
<View style={buttonGridStyles.columnContainer}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={props.onSocialPress}
|
onPress={props.onSocialPress}
|
||||||
style={[{ backgroundColor: themeColors["MIDNIGHT BLUE"] }, buttonGridStyles.button]}
|
style={[{ backgroundColor: "#444" }, buttonGridStyles.button]}
|
||||||
activeOpacity={0.6}
|
activeOpacity={0.6}
|
||||||
|
disabled={true}
|
||||||
>
|
>
|
||||||
<MaterialCommIcon name="account-group" style={buttonGridStyles.icon}></MaterialCommIcon>
|
<MaterialCommIcon name="account-group" style={buttonGridStyles.icon}></MaterialCommIcon>
|
||||||
<Text style={buttonGridStyles.buttonText}>SOCIAL</Text>
|
<Text style={buttonGridStyles.buttonText}>{ i18n.t('mainMenu_social').toUpperCase()}</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={props.onSettingsPress}
|
onPress={props.onSettingsPress}
|
||||||
|
@ -90,7 +88,7 @@ function ButtonGrid(props) {
|
||||||
activeOpacity={0.6}
|
activeOpacity={0.6}
|
||||||
>
|
>
|
||||||
<MaterialIcon name="settings" style={buttonGridStyles.icon}></MaterialIcon>
|
<MaterialIcon name="settings" style={buttonGridStyles.icon}></MaterialIcon>
|
||||||
<Text style={buttonGridStyles.buttonText}>EINSTELLUNGEN</Text>
|
<Text style={buttonGridStyles.buttonText}>{ i18n.t('settings').toUpperCase()}</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -193,7 +191,7 @@ const fullWidthButtonStyles = StyleSheet.create({
|
||||||
|
|
||||||
function MainMenuView(props) {
|
function MainMenuView(props) {
|
||||||
const s = props.connState;
|
const s = props.connState;
|
||||||
let startButtonText = "JETZT SCHWIMMEN";
|
let startButtonText = i18n.t('mainMenu_swimNow').toUpperCase();
|
||||||
let startButtonDisabled = false;
|
let startButtonDisabled = false;
|
||||||
if (s === ConnState.DISCONNECTED) {
|
if (s === ConnState.DISCONNECTED) {
|
||||||
startButtonText = "NICHT VERBUNDEN";
|
startButtonText = "NICHT VERBUNDEN";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
|
@ -12,6 +12,9 @@ import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import EntypoIcon from "react-native-vector-icons/Entypo";
|
import EntypoIcon from "react-native-vector-icons/Entypo";
|
||||||
import ImageHeader from "../components/ImageHeader";
|
import ImageHeader from "../components/ImageHeader";
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { TouchableOpacity } from "react-native-gesture-handler";
|
||||||
|
import request from '../utility/PromiseRequest';
|
||||||
|
import i18n from 'i18n-js';
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
@ -51,6 +54,29 @@ function SettingsSwitch(props) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SettingsButton(props) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Text style={settingsGroupStyles.label}>{props.label}</Text>
|
||||||
|
<TouchableOpacity style={settingsGroupStyles.buttonTouchable} onPress={props.onPress}>
|
||||||
|
<Text style={settingsGroupStyles.buttonText}>{props.buttonText}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function SettingsText(props) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Text style={settingsGroupStyles.label}>{props.label}</Text>
|
||||||
|
<Text style={settingsGroupStyles.text}>{props.text}</Text>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function SettingsSlider(props) {
|
function SettingsSlider(props) {
|
||||||
/*
|
/*
|
||||||
<Slider
|
<Slider
|
||||||
|
@ -136,20 +162,65 @@ const settingsGroupStyles = StyleSheet.create({
|
||||||
switch: {
|
switch: {
|
||||||
//minHeight: 50,
|
//minHeight: 50,
|
||||||
//minWidth: 80,
|
//minWidth: 80,
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
color: "rgba(255,255,255,1)",
|
||||||
|
width: "100%",
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
text : {
|
||||||
|
color: "rgba(255,255,255,1)",
|
||||||
|
width: "100%",
|
||||||
|
textAlign: "right",
|
||||||
|
},
|
||||||
|
buttonTouchable: {
|
||||||
|
backgroundColor: themeColors["CARROT"],
|
||||||
|
width: 128,
|
||||||
|
padding: 10,
|
||||||
|
justifyContent: "center",
|
||||||
|
borderRadius: 4,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
async function queryDeviceFirmwareVersion(swimTrackerHost) {
|
||||||
|
const result = await request({ url: "http://" + swimTrackerHost + "/api/status", responseType: "json" });
|
||||||
|
return result["firmware"]["version"];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function queryNewestFirmwareVersion() {
|
||||||
|
const QUERY_URL = "https://swimtracker-update.bauer.tech/VERSION";
|
||||||
|
const result = await request({ url: QUERY_URL, responseType: "text" });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function SettingsView(props) {
|
function SettingsView(props) {
|
||||||
console.log("settings props", props);
|
|
||||||
|
const [deviceFirmwareVersion, setDeviceFirmwareVersion] = useState("");
|
||||||
|
const [newestFirmwareVersion, setNewestFirmwareVersion] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Promise.all([queryDeviceFirmwareVersion(props.settings.swimTrackerHost), queryNewestFirmwareVersion()]).then(
|
||||||
|
(values) => {
|
||||||
|
setDeviceFirmwareVersion(values[0]);
|
||||||
|
setNewestFirmwareVersion(values[1]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const doFirmwareUpdate = () => {
|
||||||
|
request({ url: "http://" + props.settings.swimTrackerHost + "/api/firmwareupdate", responseType: "text"});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<StatusBar hidden={true} />
|
<StatusBar barStyle="light-content" backgroundColor="rgba(0,0,0,0.4)" translucent={true} />
|
||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<ImageHeader
|
<ImageHeader
|
||||||
text="EINSTELLUNGEN"
|
text={i18n.t('settings').toUpperCase()}
|
||||||
navigation={props.navigation}
|
navigation={props.navigation}
|
||||||
image={require("../assets/infinity_pool2.jpg")}
|
image={require("../assets/infinity_pool2.jpg")}
|
||||||
/>
|
/>
|
||||||
|
@ -163,6 +234,11 @@ function SettingsView(props) {
|
||||||
/>
|
/>
|
||||||
<SettingsSwitch label="Start automatically" />
|
<SettingsSwitch label="Start automatically" />
|
||||||
<SettingsSwitch label="Stop automatically" />
|
<SettingsSwitch label="Stop automatically" />
|
||||||
|
<SettingsButton label="Tare" buttonText="GO" onPress={props.device.conn.sendTareCommand} />
|
||||||
|
<SettingsButton label="WiFi config" buttonText="Reset" onPress={props.device.conn.wifiResetToProvisioning} />
|
||||||
|
<SettingsText label="Firmware version" text={deviceFirmwareVersion}></SettingsText>
|
||||||
|
<SettingsText label="Newest Firmware" text={newestFirmwareVersion}></SettingsText>
|
||||||
|
<SettingsButton label="Update Firmware" buttonText="GO" onPress={doFirmwareUpdate}></SettingsButton>
|
||||||
</SettingsGroup>
|
</SettingsGroup>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -9,6 +9,8 @@ import {
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import SetupView from '../components/SetupView';
|
import SetupView from '../components/SetupView';
|
||||||
import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
|
import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { changeSwimTrackerHostname } from '../state/Reducer';
|
||||||
|
|
||||||
|
|
||||||
function WifiListElement(props) {
|
function WifiListElement(props) {
|
||||||
|
@ -129,7 +131,11 @@ class WifiSelectionView extends React.Component {
|
||||||
buttonText: "OK",
|
buttonText: "OK",
|
||||||
subText: "Please enter the password for your home WiFi",
|
subText: "Please enter the password for your home WiFi",
|
||||||
onSubmit: (ssid, pw) => {
|
onSubmit: (ssid, pw) => {
|
||||||
|
console.log("1");
|
||||||
this.props.device.conn.wifiSetModeSTA(ssid, pw);
|
this.props.device.conn.wifiSetModeSTA(ssid, pw);
|
||||||
|
console.log("2", this.props.deviceReportedHostname, changeSwimTrackerHostname, this.props);
|
||||||
|
this.props.dispatch(changeSwimTrackerHostname(this.props.deviceReportedHostname));
|
||||||
|
console.log("3");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
|
@ -181,4 +187,8 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default WifiSelectionView;
|
const mapStateToProps = (state) => {
|
||||||
|
return { deviceReportedHostname: state.deviceState.deviceReportedHostname };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(WifiSelectionView);
|
Loading…
Reference in New Issue