diff --git a/App.js b/App.js index adbfb4e..ff138b5 100644 --- a/App.js +++ b/App.js @@ -11,6 +11,7 @@ import { Theme } from "./src/utils"; import DeviceOldScreen from "./src/Screens/DeviceOld"; import DeviceScreen from "./src/Screens/Device"; import { Colors } from "react-native-ui-lib"; +import SettingsScreen from "./src/Screens/Settings"; Colors.loadSchemes({ light: { @@ -51,6 +52,7 @@ export default function App() { + diff --git a/package-lock.json b/package-lock.json index 25edff5..df02491 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "app", "version": "1.0.0", "dependencies": { + "@react-native-async-storage/async-storage": "^1.19.0", "@react-navigation/drawer": "^6.6.3", "@react-navigation/native": "^6.1.7", "@react-navigation/native-stack": "^6.9.13", @@ -3679,6 +3680,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.19.0.tgz", + "integrity": "sha512-xOFkz/FaQctD6yNJDur+WnHdSTigOs3pTz6HmfC8X8PYwcnnN3R9UxuWiwsfK8vvT2WioAxUkQt3lB7GySNA2w==", + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || 0.60 - 0.72 || 1000.0.0" + } + }, "node_modules/@react-native-community/cli": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.2.2.tgz", @@ -8442,6 +8454,14 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -9680,6 +9700,17 @@ "resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz", "integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==" }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", diff --git a/package.json b/package.json index 77164ce..3746cd4 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "web": "expo start --web" }, "dependencies": { + "@react-native-async-storage/async-storage": "^1.19.0", "@react-navigation/drawer": "^6.6.3", "@react-navigation/native": "^6.1.7", "@react-navigation/native-stack": "^6.9.13", diff --git a/src/Components/Card/index.js b/src/Components/Card/index.js new file mode 100644 index 0000000..f4a6348 --- /dev/null +++ b/src/Components/Card/index.js @@ -0,0 +1,25 @@ +import { ScrollView, View } from "react-native"; + +export default function Card({ children }) { + return ( + + + {children} + + + ); +} diff --git a/src/Components/Divider/index.js b/src/Components/Divider/index.js new file mode 100644 index 0000000..6b0f2c8 --- /dev/null +++ b/src/Components/Divider/index.js @@ -0,0 +1,7 @@ +import { View } from "react-native"; + +export function Divider() { + return ( + + ); +} diff --git a/src/Components/SideBar/index.js b/src/Components/SideBar/index.js index 781e179..3007af2 100644 --- a/src/Components/SideBar/index.js +++ b/src/Components/SideBar/index.js @@ -1,14 +1,30 @@ import { DrawerContentScrollView, DrawerItem } from "@react-navigation/drawer"; +import { useEffect, useState } from "react"; import { Image, StyleSheet, View } from "react-native"; import { Divider, Text } from "react-native-paper"; +import { GetData } from "../../utils"; export default function Sidebar(props) { + const [isDeveloperModeEnabled, setIsDeveloperModeEnabled] = useState(false); + + useEffect(() => { + async function getDeveloperMode() { + setIsDeveloperModeEnabled(await GetData("developerMode")); + } + + getDeveloperMode(); + }, []); + return ( <> - + {isDeveloperModeEnabled ? ( + + ) : ( + + )} Geräte @@ -32,6 +48,10 @@ export default function Sidebar(props) { label={"Feedback geben"} onPress={() => props.navigation.navigate("Feedback")} /> + props.navigation.navigate("Settings")} + /> ); diff --git a/src/Screens/Device/index.js b/src/Screens/Device/index.js index b9b0e9a..d91426e 100644 --- a/src/Screens/Device/index.js +++ b/src/Screens/Device/index.js @@ -1,17 +1,11 @@ -import { useState } from "react"; -import { Image, ScrollView, StyleSheet } from "react-native"; -import { Avatar, Card, IconButton } from "react-native-paper"; -import { - Slider, - Picker, - Icon, - Colors, - Text, - View, - Switch, - Incubator, -} from "react-native-ui-lib"; +import { useEffect, useState } from "react"; +import { Image, ScrollView, StyleSheet, View, Text } from "react-native"; +import { IconButton } from "react-native-paper"; +import { Colors } from "react-native-ui-lib"; import LightView from "./light"; +import { GetData } from "../../utils"; +import MotorView from "./motor"; +import SettingsView from "./settings"; const spaceToSide = 10; // left and right const top = 35; @@ -26,22 +20,46 @@ const iconButtonNotActiveColor = "#fff"; export default function DeviceScreen() { const [selectedView, setSelectedView] = useState(0); + const [isDeveloperModeEnabled, setIsDeveloperModeEnabled] = useState(false); + + useEffect(() => { + async function getMode() { + const data = await GetData("developerMode"); + + setIsDeveloperModeEnabled(data); + } + + getMode(); + }, []); const SelectedView = () => { switch (selectedView) { case 0: return ; + case 2: + return ; + case 3: + return ; default: Not found; } }; return ( - - + + {isDeveloperModeEnabled ? ( + + ) : ( + + )} console.log("Pressed")} + onPress={() => setSelectedView(3)} /> - - - + ); diff --git a/src/Screens/Device/light.js b/src/Screens/Device/light.js index 1f2f41c..ef8ff81 100644 --- a/src/Screens/Device/light.js +++ b/src/Screens/Device/light.js @@ -1,47 +1,36 @@ -import { useEffect, useRef, useState } from "react"; -import { StyleSheet, Text, TouchableHighlight } from "react-native"; -import { ScrollView } from "react-native-gesture-handler"; +import { useEffect, useState } from "react"; +import { StyleSheet, Text, View } from "react-native"; import { IconButton, TouchableRipple } from "react-native-paper"; import Animated, { useAnimatedStyle, - useDerivedValue, useSharedValue, - withTiming, } from "react-native-reanimated"; -import { - Icon, - Incubator, - Picker, - Switch, - TouchableOpacity, - View, -} from "react-native-ui-lib"; +import { Icon, Incubator, Picker, Switch } from "react-native-ui-lib"; import ColorPicker, { - Panel3, Swatches, - colorKit, - BrightnessSlider, InputWidget, + HueCircular, + Panel1, } from "reanimated-color-picker"; +import { GetData } from "../../utils"; +import Card from "../../Components/Card"; const dropdown = require("../../../assets/icons/chevronDown.png"); const options = [ - { label: "JavaScript", value: "js" }, - { label: "Java", value: "java" }, - { label: "Python", value: "python" }, - { label: "C++", value: "c++", disabled: true }, - { label: "Perl", value: "perl" }, + { label: "Pulse", value: "pulse" }, + { label: "Random", value: "random" }, + { label: "Rainbow", value: "rainbow" }, ]; -export default function LightView() { - const [pickerValue, setPickerValue] = useState(""); - const [switchState, setSwitchState] = useState(false); - const [sliderValue, setSliderValue] = useState(0); - const [isSwitchOn, setIsSwitchOn] = useState(false); - const [selectedColorPicker, setSelectedColorPicker] = useState("#fff"); +function ColorLayer({ layerNumber, sharedColor, selected, onPress }) { + const backgroundColorStyle = useAnimatedStyle(() => { + return { + backgroundColor: sharedColor.value, + }; + }); - const ColorLayer = ({ layerNumber, color, onPress }) => { + const contrastColor = useAnimatedStyle(() => { const getContrastRatio = (hexColor) => { const hex = hexColor.replace("#", ""); const r = parseInt(hex.substr(0, 2), 16); @@ -51,93 +40,153 @@ export default function LightView() { return luminance > 0.5 ? "#000000" : "#ffffff"; }; - const contrastColor = getContrastRatio(color); + let obj = {}; - return ( - + - - - {layerNumber} - - - - ); - }; + {layerNumber} + + + + ); +} - const onToggleSwitch = () => setIsSwitchOn(!isSwitchOn); +/* +function ColorSwatch({ color, onPress }) { + return ( + + + + ); +} */ - const customSwatches = new Array(12) +export default function LightView() { + const [pickerValue, setPickerValue] = useState(""); + const [switchState, setSwitchState] = useState(false); + const [sliderValue, setSliderValue] = useState(0); + const [selectedGlasLayer, setSelectedGlasLayer] = useState(1); + const [colorSwatchesFavorites, setColorSwatchesFavorites] = useState([]); + const [isExpertModeEnabled, setSwitchExpertModeEnabled] = useState(false); + + /*const customSwatches = new Array(12) .fill("#fff") - .map(() => colorKit.randomRgbColor().hex()); + .map(() => colorKit.randomRgbColor().hex()); */ - const selectedColor = useSharedValue(customSwatches[0]); + const selectedColorPickerColor = useSharedValue("#fff"); + const selectedColorLayer1 = useSharedValue(selectedColorPickerColor.value); + const selectedColorLayer2 = useSharedValue(selectedColorPickerColor.value); + const selectedColorLayer3 = useSharedValue(selectedColorPickerColor.value); + const selectedColorLayer4 = useSharedValue(selectedColorPickerColor.value); + + useEffect(() => { + async function getModes() { + const data = await GetData("expertMode"); + + setSwitchExpertModeEnabled(data); + } + + getModes(); + }, []); const onColorSelect = (color) => { - selectedColor.value = color.hex; + selectedColorPickerColor.value = color.hex; + + switch (selectedGlasLayer) { + case 1: + selectedColorLayer1.value = color.hex; + break; + case 2: + selectedColorLayer2.value = color.hex; + break; + case 3: + selectedColorLayer3.value = color.hex; + break; + case 4: + selectedColorLayer4.value = color.hex; + break; + } }; return ( - + setPickerValue(nativePickerValue)} trailingAccessory={} - // containerStyle={{marginTop: 20}} - // renderPicker={() => { - // return ( - // - // Open Native Picker! - // - // ); - // }} - // topBarProps={{doneLabel: 'YES', cancelLabel: 'NO'}} + //containerStyle={{ marginTop: 20 }} + //renderPicker={() => { + //return ( + // + // Open Native Picker! + // + // ); + //}} + //topBarProps={{ doneLabel: "YES", cancelLabel: "NO" }} > {options.map((option) => ( ))} - + setSwitchState(e)} /> - + - console.log("press star")} - /> - - - console.log("pressed")} - /> - console.log("pressed")} - /> - console.log("pressed")} - /> - console.log("pressed")} - /> - - - + + { + setSelectedGlasLayer(1); + selectedColorPickerColor.value = selectedColorLayer1.value; + }} + /> + { + setSelectedGlasLayer(2); + selectedColorPickerColor.value = selectedColorLayer2.value; + }} + /> + { + setSelectedGlasLayer(3); + selectedColorPickerColor.value = selectedColorLayer3.value; + }} + /> + { + setSelectedGlasLayer(4); + selectedColorPickerColor.value = selectedColorLayer4.value; + }} + /> + - + { + setColorSwatchesFavorites([ + ...colorSwatchesFavorites, + selectedColorPickerColor.value, + ]); + }} + /> + + + + + + - - - + {isExpertModeEnabled && ( + + + + )} - + ); } +/* + + {colorSwatchesFavorites.map((color, i) => ( + { + console.log("press", color, renderKey); + selectedColorPickerColor.value = color; + setRenderKey((prevKey) => prevKey + 1); + }} + /> + ))} + +*/ + +// + const styles = StyleSheet.create({ container: { flex: 1, @@ -245,10 +349,20 @@ const styles = StyleSheet.create({ shadowRadius: 6.27, elevation: 5, }, + hueContainer: { + justifyContent: "center", + backgroundColor: "#3f4042", + }, + panelStyle: { + width: "60%", + height: "60%", + alignSelf: "center", + borderRadius: 16, + }, + /* panelStyle: { margin: 10, marginLeft: 20, - borderRadius: 16, shadowColor: "#000", shadowOffset: { width: 0, @@ -257,7 +371,7 @@ const styles = StyleSheet.create({ shadowOpacity: 0.25, shadowRadius: 3.84, elevation: 5, - }, + },*/ sliderStyle: { borderRadius: 20, marginTop: 20, @@ -276,14 +390,13 @@ const styles = StyleSheet.create({ borderColor: "#bebdbe", marginTop: 20, paddingTop: 20, - alignItems: "center", - //flexWrap: "nowrap", + justifyContent: "center", gap: 10, }, swatchStyle: { borderRadius: 20, - height: 30, - width: 30, + height: 25, + width: 25, margin: 0, marginBottom: 0, marginHorizontal: 0, diff --git a/src/Screens/Device/motor.js b/src/Screens/Device/motor.js new file mode 100644 index 0000000..dc71f66 --- /dev/null +++ b/src/Screens/Device/motor.js @@ -0,0 +1,33 @@ +import { Text, View } from "react-native"; +import Card from "../../Components/Card"; +import { Incubator, Switch } from "react-native-ui-lib"; +import { IconButton } from "react-native-paper"; +import { useState } from "react"; + +export default function MotorView() { + const [switchState, setSwitchState] = useState(false); + const [sliderValue, setSliderValue] = useState(0); + + return ( + + + setSwitchState(e)} /> + + + setSliderValue(v)} + containerStyle={{ + flex: 1, + marginHorizontal: 8, + }} + /> + + + + ); +} diff --git a/src/Screens/Device/settings.js b/src/Screens/Device/settings.js new file mode 100644 index 0000000..f061328 --- /dev/null +++ b/src/Screens/Device/settings.js @@ -0,0 +1,84 @@ +import { Text, View } from "react-native"; +import Card from "../../Components/Card"; +import { Incubator, Switch } from "react-native-ui-lib"; +import { useState } from "react"; +import { AppStyles } from "../../utils"; +import { Divider } from "../../Components/Divider"; + +export default function SettingsView() { + const [switchState, setSwitchState] = useState(false); + const [sliderValue, setSliderValue] = useState(0); + + return ( + <> + + + Einstellungen + + + + + + WLAN im Standby + + + Die WLAN-Verbindung bleibt bestehen, auch wenn das Gerät + ausgeschaltet ist. Bitte beachten Sie, dass dies zu einem erhöhten + Stromverbrauch führen kann. + + + setSwitchState(e)} + /> + + + + + + Geräteinformationen + + + Gerätemodell + + + Shimmex Aurora + + + + Firmware Version + + 1.0.1 + + + Letzte Aktualisierung + + + 11.07.2023 um 20:33 Uhr + + + + ); +} diff --git a/src/Screens/FAQ/index.js b/src/Screens/FAQ/index.js index a3f98c6..e1aba9e 100644 --- a/src/Screens/FAQ/index.js +++ b/src/Screens/FAQ/index.js @@ -1,39 +1,3 @@ -import { useState } from "react"; -import { View, useWindowDimensions } from "react-native"; -import { SceneMap, TabView } from "react-native-tab-view"; - -const FirstRoute = () => ( - -); - -const SecondRoute = () => ( - -); - -const ThirdRoute = () => ; - -const renderScene = SceneMap({ - first: FirstRoute, - second: SecondRoute, - third: ThirdRoute, -}); - export default function FaqScreen() { - const layout = useWindowDimensions(); - - const [index, setIndex] = useState(0); - const [routes] = useState([ - { key: "first", title: "First" }, - { key: "second", title: "Second" }, - { key: "third", title: "Third" }, - ]); - - return ( - - ); + return <>; } diff --git a/src/Screens/Settings/index.js b/src/Screens/Settings/index.js new file mode 100644 index 0000000..7fd2d6b --- /dev/null +++ b/src/Screens/Settings/index.js @@ -0,0 +1,105 @@ +import { useEffect, useState } from "react"; +import { Text, View } from "react-native"; +import { ScrollView } from "react-native-gesture-handler"; +import { Picker, Switch } from "react-native-ui-lib"; +import Card from "../../Components/Card"; +import AsyncStorage from "@react-native-async-storage/async-storage"; +import { AppStyles, GetData, GetMultipleData, StoreData } from "../../utils"; + +export default function SettingsScreen() { + const [switchDeveloperMode, setSwitchDeveloperMode] = useState(false); + const [switchExpertMode, setSwitchExpertMode] = useState(false); + const [selectedColorScheme, setSelectedColorScheme] = useState("auto"); + const [selectedLanguage, setSelectedLanguage] = useState("de"); + + useEffect(() => { + async function getModes() { + const data = await GetMultipleData(["developerMode", "expertMode"]); + + setSwitchDeveloperMode(data[0][1]); + setSwitchExpertMode(data[1][1]); + } + + getModes(); + }, []); + + return ( + + + + Einstellungen + + + setSelectedLanguage(v)} + fieldType={Picker.fieldTypes.settings} + showSearch + searchPlaceholder="Search a language" + searchStyle={{ color: "#fff", placeholderTextColor: "#fff" }} + > + + + + + + setSelectedColorScheme(v)} + fieldType={Picker.fieldTypes.settings} + > + + + + + + + + + Developer Mode + { + setSwitchDeveloperMode(e); + StoreData("developerMode", e); + }} + /> + + + + Expert Mode + { + setSwitchExpertMode(e); + StoreData("expertMode", e); + }} + /> + + + + ); +} diff --git a/src/utils.js b/src/utils.js index b2adb45..649ac16 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,13 +1,27 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; import { StyleSheet } from "react-native"; import { DefaultTheme } from "react-native-paper"; -const Styles = StyleSheet.create({ +export const AppStyles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center", }, + typography20: { + fontSize: 20, + fontWeight: "bold", + lineHeight: 24, + }, + typography16: { + fontSize: 16, + lineHeight: 24, + }, + typography14: { + fontSize: 14, + lineHeight: 20, + }, }); export const Theme = { @@ -56,3 +70,31 @@ export const Theme = { mySegmentedButtonsCheckedColor: "#fff", }, }; + +export async function StoreData(key, value) { + try { + const jsonValue = JSON.stringify(value); + await AsyncStorage.setItem(key, jsonValue); + } catch (e) { + console.log("err", e); + } +} + +export async function GetData(key) { + try { + const jsonValue = await AsyncStorage.getItem(key); + return jsonValue != null ? JSON.parse(jsonValue) : null; + } catch (e) { + console.log("err", e); + } +} + +export async function GetMultipleData(keys) { + try { + const data = await AsyncStorage.multiGet(keys); + const retrievedData = data.map(([key, value]) => [key, JSON.parse(value)]); + return retrievedData; + } catch (e) { + console.log("err", e); + } +}