new ui device design
parent
5ae3f9ffde
commit
d96311c3d6
8
App.js
8
App.js
|
@ -15,13 +15,14 @@ import { Suspense, lazy, useContext, useEffect } from "react";
|
|||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import "./i18n";
|
||||
import DeviceScreen from "./src/Screens/Device";
|
||||
import DeviceOldScreen from "./src/Screens/DeviceOld";
|
||||
|
||||
const Drawer = createDrawerNavigator();
|
||||
|
||||
const SettingsScreen = lazy(() => import("./src/Screens/Settings"));
|
||||
const FaqScreen = lazy(() => import("./src/Screens/FAQ"));
|
||||
const FeedbackScreen = lazy(() => import("./src/Screens/Feedback"));
|
||||
|
||||
const Drawer = createDrawerNavigator();
|
||||
|
||||
export function MyApp() {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
|
@ -63,7 +64,7 @@ export function MyApp() {
|
|||
<NavigationContainer>
|
||||
<Drawer.Navigator
|
||||
screenOptions={{
|
||||
// headerShown: false,
|
||||
headerShown: true,
|
||||
headerStyle: {
|
||||
backgroundColor: appContext.appTheme.backgroundColor,
|
||||
},
|
||||
|
@ -75,6 +76,7 @@ export function MyApp() {
|
|||
drawerContent={(props) => <SideBar {...props} />}
|
||||
>
|
||||
<Drawer.Screen name="Turtle" component={DeviceScreen} />
|
||||
<Drawer.Screen name="Old Turtle" component={DeviceOldScreen} />
|
||||
<Drawer.Screen name="FAQ" component={FaqScreen} />
|
||||
<Drawer.Screen name="Feedback" component={FeedbackScreen} />
|
||||
<Drawer.Screen name="Settings" component={SettingsScreen} />
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.3 MiB |
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
|
@ -26,6 +26,7 @@
|
|||
"react-native-safe-area-context": "4.5.0",
|
||||
"react-native-screens": "~3.20.0",
|
||||
"react-native-tab-view": "^3.5.2",
|
||||
"react-native-uuid": "^2.0.1",
|
||||
"reanimated-color-picker": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -5010,34 +5011,6 @@
|
|||
"react-native-screens": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/drawer/node_modules/color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/drawer/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/drawer/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/@react-navigation/elements": {
|
||||
"version": "1.3.18",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.18.tgz",
|
||||
|
@ -6291,6 +6264,18 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
|
@ -6313,6 +6298,22 @@
|
|||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/color/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
|
||||
|
@ -7101,6 +7102,15 @@
|
|||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-asset/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-constants": {
|
||||
"version": "14.2.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-14.2.1.tgz",
|
||||
|
@ -7113,6 +7123,15 @@
|
|||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-constants/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-file-system": {
|
||||
"version": "15.2.2",
|
||||
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-15.2.2.tgz",
|
||||
|
@ -7124,6 +7143,15 @@
|
|||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-file-system/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-font": {
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-11.1.1.tgz",
|
||||
|
@ -7269,6 +7297,15 @@
|
|||
"resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.4.4.tgz",
|
||||
"integrity": "sha512-5DV0hIEWgatSC3UgQuAZBoQeaS9CqeWRZ3vzBR9R/+IUD87Adbi4FGhU10nymRqFXOizGsureButGZIXPs7zEA=="
|
||||
},
|
||||
"node_modules/expo/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/extend-shallow": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
|
||||
|
@ -11931,6 +11968,15 @@
|
|||
"react-native-pager-view": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-uuid": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.1.tgz",
|
||||
"integrity": "sha512-cptnoIbL53GTCrWlb/+jrDC6tvb7ypIyzbXNJcpR3Vab0mkeaaVd5qnB3f0whXYzS+SMoSQLcUUB0gEWqkPC0g==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native/node_modules/promise": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
|
||||
|
@ -13795,15 +13841,6 @@
|
|||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/valid-url": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz",
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"react-native-safe-area-context": "4.5.0",
|
||||
"react-native-screens": "~3.20.0",
|
||||
"react-native-tab-view": "^3.5.2",
|
||||
"react-native-uuid": "^2.0.1",
|
||||
"reanimated-color-picker": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { useContext } from "react";
|
||||
import { Text, TouchableHighlight, View } from "react-native";
|
||||
import { AppContext, AppStyles } from "../../utils";
|
||||
|
||||
export default function MyButton({ title, style, disabled, onPress }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
disabled={disabled}
|
||||
onPress={onPress}
|
||||
style={[{ borderRadius: 6 }, style]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
backgroundColor: appContext.appTheme.colors.primary,
|
||||
borderRadius: 6,
|
||||
padding: 10,
|
||||
},
|
||||
AppStyles.Shadow,
|
||||
disabled && { opacity: 0.6 },
|
||||
]}
|
||||
>
|
||||
<Text style={{ textAlign: "center", color: "#fff" }}>{title}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
|
@ -2,9 +2,14 @@ import { useContext } from "react";
|
|||
import { View } from "react-native";
|
||||
import { AppContext, AppStyles } from "../../utils";
|
||||
|
||||
export default function Card({ children }) {
|
||||
export default function Card({ children, cardBackgroundColor }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const backgroundColor =
|
||||
cardBackgroundColor === undefined
|
||||
? appContext.appTheme.card.backgroundColor
|
||||
: cardBackgroundColor;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
|
@ -18,7 +23,7 @@ export default function Card({ children }) {
|
|||
style={[
|
||||
{
|
||||
borderRadius: 20,
|
||||
backgroundColor: appContext.appTheme.card.backgroundColor,
|
||||
backgroundColor: backgroundColor,
|
||||
padding: 20,
|
||||
},
|
||||
AppStyles.Shadow,
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import { Text, View } from "react-native";
|
||||
import { TouchableOpacity } from "react-native";
|
||||
import { AppContext, IsPlatformIos } from "../../utils";
|
||||
import { useContext } from "react";
|
||||
import MyIcon from "../Icon";
|
||||
|
||||
export default function MyDropdown({ label, onPress, selectedItemLabel }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => onPress()}>
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
//IsPlatformIos() && { marginBottom: 10 },
|
||||
]}
|
||||
>
|
||||
<View>
|
||||
<Text style={{ color: appContext.appTheme.text }}>{label}</Text>
|
||||
<Text style={{ color: appContext.appTheme.colors.primary }}>
|
||||
{selectedItemLabel}
|
||||
</Text>
|
||||
</View>
|
||||
<MyIcon
|
||||
name="chevron-down"
|
||||
size={24}
|
||||
color={appContext.appTheme.icon}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
|
@ -1,5 +1,11 @@
|
|||
import Icon from "@expo/vector-icons/MaterialCommunityIcons";
|
||||
import { useContext } from "react";
|
||||
import { AppContext } from "../../utils";
|
||||
|
||||
export default function MyIcon({ style, name, color, size }) {
|
||||
return <Icon style={style} name={name} color={color} size={size} />;
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const iconColor = color === undefined ? appContext.appTheme.icon : color;
|
||||
|
||||
return <Icon style={style} name={name} color={iconColor} size={size} />;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { AppContext, AppStyles, IsPlatformIos } from "../../utils";
|
|||
import {
|
||||
KeyboardAvoidingView,
|
||||
Modal,
|
||||
Platform,
|
||||
ScrollView,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
|
@ -13,15 +13,134 @@ import { Divider } from "../Divider";
|
|||
import MyIcon from "../Icon";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const modalIosPaddingTop = 10;
|
||||
/*
|
||||
transparent: set this to prevent modal reopening on iOS
|
||||
https://github.com/facebook/react-native/issues/34018
|
||||
*/
|
||||
|
||||
export default function PickerModal({
|
||||
const modalContentStyle = { margin: 10, paddingTop: 10 };
|
||||
|
||||
export default function MyModal({
|
||||
children,
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
items,
|
||||
searchFilter,
|
||||
closeModal,
|
||||
header,
|
||||
content,
|
||||
disableAnimationForIos,
|
||||
scrollView,
|
||||
}) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const getContent = () => {
|
||||
if (scrollView) {
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={modalContentStyle}>{content}</View>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
return <View style={modalContentStyle}>{content}</View>;
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Modal
|
||||
visible={isOpen}
|
||||
animationType={disableAnimationForIos ? "none" : "slide"}
|
||||
onRequestClose={() => closeModal()}
|
||||
transparent
|
||||
>
|
||||
{children}
|
||||
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
flex: 1,
|
||||
backgroundColor: appContext.appTheme.backgroundColor,
|
||||
paddingTop: IsPlatformIos() ? 30 : 15,
|
||||
},
|
||||
,
|
||||
]}
|
||||
>
|
||||
{header}
|
||||
|
||||
{getContent()}
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export function MyPickerDefaultHeader({ title, closeModal }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity onPress={() => closeModal()}>
|
||||
<MyIcon name="chevron-left" size={24} style={{ marginLeft: 20 }} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography16,
|
||||
{ fontWeight: "bold", color: appContext.appTheme.text },
|
||||
]}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
<View style={{ marginRight: 40 }} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export function MyPickerModalListItem({ onPress, itemName, itemSelected }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TouchableOpacity onPress={onPress}>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginLeft: 10,
|
||||
marginRight: 10,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography16,
|
||||
{ color: appContext.appTheme.text },
|
||||
]}
|
||||
>
|
||||
{itemName}
|
||||
</Text>
|
||||
|
||||
{itemSelected && (
|
||||
<MyIcon
|
||||
name="check"
|
||||
size={24}
|
||||
color={appContext.appTheme.colors.primary}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<Divider />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function MyPickerModal({ isOpen, setIsOpen, items, searchFilter }) {
|
||||
const appContext = useContext(AppContext);
|
||||
const { t } = useTranslation();
|
||||
const [providedItems, setProvidedItems] = useState([]);
|
||||
const [searchFilterInput, setSearchFilterInput] = useState("");
|
||||
|
@ -47,7 +166,6 @@ export default function PickerModal({
|
|||
flex: 1,
|
||||
backgroundColor: appContext.appTheme.backgroundColor,
|
||||
},
|
||||
IsPlatformIos() && { paddingTop: modalIosPaddingTop },
|
||||
]}
|
||||
>
|
||||
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
||||
|
@ -193,7 +311,7 @@ export default function PickerModal({
|
|||
);
|
||||
}
|
||||
|
||||
export function TextInputModal({
|
||||
export function MyTextInputModal({
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
onTextInputSave,
|
||||
|
@ -217,7 +335,6 @@ export function TextInputModal({
|
|||
flex: 1,
|
||||
backgroundColor: appContext.appTheme.backgroundColor,
|
||||
},
|
||||
IsPlatformIos() && { paddingTop: modalIosPaddingTop },
|
||||
]}
|
||||
>
|
||||
<View
|
|
@ -122,7 +122,7 @@ export default function Sidebar(props) {
|
|||
{t("sideBar.devicesTitle")}
|
||||
</Text>
|
||||
<DrawerContentScrollView contentContainerStyle={{ paddingTop: 0 }}>
|
||||
{["Turtle"].map((item, i) => (
|
||||
{["Turtle", "Old Turtle"].map((item, i) => (
|
||||
<MyDrawerItem
|
||||
key={i}
|
||||
isDevice
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { lazy, useContext, useState } from "react";
|
||||
import { useContext, useState } from "react";
|
||||
import {
|
||||
Image,
|
||||
ScrollView,
|
||||
|
@ -7,17 +7,12 @@ import {
|
|||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
Dimensions,
|
||||
Platform,
|
||||
ImageBackground,
|
||||
} from "react-native";
|
||||
import LightView from "./light";
|
||||
import { AppContext } from "../../utils";
|
||||
import MyIcon from "../../Components/Icon";
|
||||
|
||||
const MotorView = lazy(() => import("./motor"));
|
||||
const SettingsView = lazy(() => import("./settings"));
|
||||
const ColorScenesView = lazy(() => import("./colorScenes"));
|
||||
import SettingsView from "./settings";
|
||||
import SceneView from "./scene";
|
||||
|
||||
const spaceToSide = 10; // left and right
|
||||
const top = 35;
|
||||
|
@ -27,43 +22,16 @@ const topFirst = top;
|
|||
const topSecond = top + spaceBetweenButtons;
|
||||
const topThird = top + 2 * spaceBetweenButtons;
|
||||
|
||||
const windowDimensions = Dimensions.get("window");
|
||||
|
||||
let data = [];
|
||||
|
||||
const ledLines = 4;
|
||||
const ledsPerLine = 16;
|
||||
|
||||
const deviceLeds = ledLines * ledsPerLine;
|
||||
|
||||
// setting default color for testing
|
||||
for (let i = 0; i < deviceLeds; i++) {
|
||||
data.push("lime");
|
||||
}
|
||||
|
||||
export default function DeviceScreen() {
|
||||
const appContext = useContext(AppContext);
|
||||
const [selectedView, setSelectedView] = useState(0);
|
||||
const [deviceLedsColors, setDeviceLedsColor] = useState(data);
|
||||
const [selectedDeviceLed, setSelectedDeviceLed] = useState(2);
|
||||
|
||||
const SelectedView = () => {
|
||||
switch (selectedView) {
|
||||
case 0:
|
||||
return <LightView />;
|
||||
case 2:
|
||||
return <MotorView />;
|
||||
case 3:
|
||||
return <SettingsView />;
|
||||
case 4:
|
||||
return (
|
||||
<ColorScenesView
|
||||
deviceLedsColors={deviceLedsColors}
|
||||
setDeviceLedsColor={setDeviceLedsColor}
|
||||
selectedDeviceLed={selectedDeviceLed}
|
||||
setSelectedDeviceLed={setSelectedDeviceLed}
|
||||
/>
|
||||
);
|
||||
case 2:
|
||||
return <SceneView />;
|
||||
default:
|
||||
<Text>Not found</Text>;
|
||||
}
|
||||
|
@ -102,59 +70,6 @@ export default function DeviceScreen() {
|
|||
);
|
||||
};
|
||||
|
||||
const DeviceLedsColor = () => {
|
||||
let elements = [];
|
||||
let test = 400;
|
||||
|
||||
for (let l = 0; l < ledLines; l++) {
|
||||
let left = 0;
|
||||
let ledsElements = [];
|
||||
|
||||
for (let p = 0; p < ledsPerLine; p++) {
|
||||
left = left + 1.5;
|
||||
|
||||
const ledId = l > 0 ? l * 16 + p : p;
|
||||
|
||||
const deviceLedColor =
|
||||
l > 0 ? deviceLedsColors[l * 16 + p] : deviceLedsColors[p];
|
||||
|
||||
ledsElements.push(
|
||||
<View
|
||||
key={`${l}-${p}`}
|
||||
style={{
|
||||
width: 0.1 * (test / 16),
|
||||
height: 0.1 * (test / 16),
|
||||
backgroundColor:
|
||||
ledId === selectedDeviceLed ? "red" : deviceLedColor,
|
||||
borderRadius: 0.5,
|
||||
left: left,
|
||||
marginRight:
|
||||
windowDimensions.width > 360
|
||||
? 0.27 * (test / 16)
|
||||
: 0.26 * (test / 16),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
elements.push(
|
||||
<View
|
||||
key={`v-${l}`}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
top: 118.5 + l,
|
||||
right: "8%",
|
||||
}}
|
||||
>
|
||||
{ledsElements}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{elements}</>;
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
|
@ -193,49 +108,27 @@ export default function DeviceScreen() {
|
|||
)}
|
||||
|
||||
<MyButton
|
||||
iconName={"lightbulb-on-outline"}
|
||||
left
|
||||
iconName={"cog-outline"}
|
||||
left={false}
|
||||
selectedViewNumber={0}
|
||||
space={spaceToSide}
|
||||
top={topFirst}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"television-ambient-light"}
|
||||
left
|
||||
iconName={"rotate-3d-variant"}
|
||||
left={false}
|
||||
selectedViewNumber={1}
|
||||
space={spaceToSide}
|
||||
top={topSecond}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"axis-z-rotate-counterclockwise"}
|
||||
left
|
||||
iconName={"group"}
|
||||
left={false}
|
||||
selectedViewNumber={2}
|
||||
space={spaceToSide}
|
||||
top={topThird}
|
||||
/>
|
||||
|
||||
<MyButton
|
||||
iconName={"cog-outline"}
|
||||
left={false}
|
||||
selectedViewNumber={3}
|
||||
space={spaceToSide}
|
||||
top={topFirst}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"palette-outline"}
|
||||
left={false}
|
||||
selectedViewNumber={4}
|
||||
space={spaceToSide}
|
||||
top={topSecond}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"rotate-3d-variant"}
|
||||
left={false}
|
||||
selectedViewNumber={5}
|
||||
space={spaceToSide}
|
||||
top={topThird}
|
||||
/>
|
||||
|
||||
<ScrollView style={{ height: "100%" }}>
|
||||
<SelectedView />
|
||||
</ScrollView>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import { Text } from "react-native";
|
||||
|
||||
export default function LayersActionEditModalContent() {
|
||||
return <Text>Layers</Text>;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
import { useState } from "react";
|
||||
import { Text, TouchableHighlight, View } from "react-native";
|
||||
import MyButton from "../../../../../Components/Button";
|
||||
|
||||
function Layer({ number, selected, onPress }) {
|
||||
return (
|
||||
<TouchableHighlight onPress={onPress} style={{ borderRadius: 10 }}>
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
height: 150,
|
||||
width: 150,
|
||||
backgroundColor: "gray",
|
||||
borderRadius: 10,
|
||||
},
|
||||
selected && { borderColor: "#9b59b6", borderWidth: 6 },
|
||||
]}
|
||||
>
|
||||
<View style={{ alignItems: "flex-end" }}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 6,
|
||||
marginRight: 6,
|
||||
backgroundColor: "#e67e22",
|
||||
paddingLeft: 6,
|
||||
paddingRight: 6,
|
||||
borderRadius: 10,
|
||||
}}
|
||||
>
|
||||
<Text>{number}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
|
||||
export default function LayerSelectionModalContent({
|
||||
openLayersActionEditModal,
|
||||
}) {
|
||||
const [selectedLayer, setSelectedLayer] = useState([]);
|
||||
|
||||
const handleSelectLayerClick = (layerNumber) => {
|
||||
if (selectedLayer.includes(layerNumber)) {
|
||||
setSelectedLayer((sLayer) =>
|
||||
sLayer.filter((item) => item != layerNumber)
|
||||
);
|
||||
} else {
|
||||
setSelectedLayer((sLayer) => [...sLayer, layerNumber]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
gap: 14,
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: 4 }).map((_, i) => (
|
||||
<Layer
|
||||
key={i}
|
||||
number={i + 1}
|
||||
selected={selectedLayer.includes(i + 1)}
|
||||
onPress={() => handleSelectLayerClick(i + 1)}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<View style={{ alignItems: "center" }}>
|
||||
<MyButton
|
||||
title={"Hinzufügen"}
|
||||
style={{ marginTop: 20, width: 180 }}
|
||||
disabled={selectedLayer.length === 0}
|
||||
onPress={() => openLayersActionEditModal()}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
import { useContext } from "react";
|
||||
import { Image, Text, TouchableOpacity, View } from "react-native";
|
||||
import { AppContext, AppStyles } from "../../../../utils";
|
||||
import MyIcon from "../../../../Components/Icon";
|
||||
import { Divider } from "../../../../Components/Divider";
|
||||
|
||||
function Action({ text, iconName, imageSource, onPress }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TouchableOpacity
|
||||
style={{ marginLeft: 10, marginRight: 10 }}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
},
|
||||
imageSource !== undefined && { marginBottom: 4 },
|
||||
]}
|
||||
>
|
||||
<MyIcon name={iconName} size={24} />
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography16,
|
||||
{ color: appContext.appTheme.text, marginLeft: 6 },
|
||||
]}
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
{imageSource !== undefined && (
|
||||
<Image source={imageSource} style={{ height: 150, width: 150 }} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<Divider />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function AddSceneActionModalContent({
|
||||
openLayerSelectionModal,
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<Action
|
||||
text="Ebenen"
|
||||
iconName="lightbulb-on-outline"
|
||||
imageSource={require("../../../../../assets/layers.gif")}
|
||||
onPress={openLayerSelectionModal}
|
||||
/>
|
||||
|
||||
<Action
|
||||
text="Motor"
|
||||
iconName="axis-z-rotate-counterclockwise"
|
||||
imageSource={require("../../../../../assets/motor.gif")}
|
||||
onPress={() => console.log("pressed action")}
|
||||
/>
|
||||
|
||||
<Action
|
||||
text="Ambilight"
|
||||
iconName="television-ambient-light"
|
||||
imageSource={require("../../../../../assets/ambilight.gif")}
|
||||
onPress={() => console.log("pressed action")}
|
||||
/>
|
||||
|
||||
<Action
|
||||
text="Warten"
|
||||
iconName="timer-sand"
|
||||
onPress={() => console.log("pressed action")}
|
||||
/>
|
||||
|
||||
<Action
|
||||
text="Stop"
|
||||
iconName="pause-octagon-outline"
|
||||
onPress={() => console.log("pressed action")}
|
||||
/>
|
||||
|
||||
<Action
|
||||
text="Zeitsteuerung"
|
||||
iconName="timer-cog"
|
||||
onPress={() => console.log("pressed action")}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import { useContext } from "react";
|
||||
import {
|
||||
AppContext,
|
||||
DevDeviceId,
|
||||
NewEmptyDeviceScene,
|
||||
} from "../../../../../utils";
|
||||
import { FlatList, View } from "react-native";
|
||||
import { MyPickerModalListItem } from "../../../../../Components/Modal";
|
||||
|
||||
export default function CreateSceneModalContent({ closeChooseSceneModals }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const options = [
|
||||
{
|
||||
id: 0,
|
||||
name: "Leere Szene erstellen",
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: "Standard Szene erstellen",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Vorhandene Szene kopieren",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
data={options}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={({ item }) => (
|
||||
<MyPickerModalListItem
|
||||
itemName={item.name}
|
||||
onPress={() => {
|
||||
console.log("pressed", item);
|
||||
|
||||
appContext.setDevices((arr) => {
|
||||
const newArr = [...arr];
|
||||
|
||||
newArr[arr.findIndex((d) => d.id === DevDeviceId)].scenes.push(
|
||||
NewEmptyDeviceScene()
|
||||
);
|
||||
|
||||
return newArr;
|
||||
});
|
||||
|
||||
closeChooseSceneModals();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
import { useContext, useState } from "react";
|
||||
import { FlatList, Text, TouchableOpacity } from "react-native";
|
||||
import { AppContext, AppStyles, DevDeviceId } from "../../../../utils";
|
||||
import { Divider } from "../../../../Components/Divider";
|
||||
import { View } from "react-native";
|
||||
import MyIcon from "../../../../Components/Icon";
|
||||
import { MyPickerModalListItem } from "../../../../Components/Modal";
|
||||
|
||||
export default function ChooseSceneModalContent({ openCreateSceneModal }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const device = appContext.devices.find((device) => device.id === DevDeviceId);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FlatList
|
||||
data={device.scenes}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={({ item }) => (
|
||||
<MyPickerModalListItem
|
||||
itemName={item.name}
|
||||
itemSelected={device.selectedScene === item.id}
|
||||
onPress={() => {
|
||||
appContext.setDevices((arr) => {
|
||||
const newArr = [...arr];
|
||||
|
||||
newArr[
|
||||
arr.findIndex((d) => d.id === DevDeviceId)
|
||||
].selectedScene = item.id;
|
||||
|
||||
return newArr;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginTop: 10,
|
||||
}}
|
||||
onPress={openCreateSceneModal}
|
||||
>
|
||||
<MyIcon
|
||||
name="plus-circle-outline"
|
||||
color={appContext.appTheme.textSecondary}
|
||||
size={24}
|
||||
style={{ marginRight: 10 }}
|
||||
/>
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography16,
|
||||
{ color: appContext.appTheme.textSecondary },
|
||||
]}
|
||||
>
|
||||
Neue Szene erstellen
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
import { FlatList, Text, TouchableOpacity, View } from "react-native";
|
||||
import Card from "../../Components/Card";
|
||||
import { AppContext, AppStyles, DevDeviceId } from "../../utils";
|
||||
import { useContext, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MyDropdown from "../../Components/Dropdown";
|
||||
import MyIcon from "../../Components/Icon";
|
||||
import MyModal, { MyPickerDefaultHeader } from "../../Components/Modal";
|
||||
import CreateSceneModalContent from "./modals/ChooseScene/CreateScene";
|
||||
import ChooseSceneModalContent from "./modals/ChooseScene";
|
||||
import AddSceneActionModalContent from "./modals/AddSceneAction";
|
||||
import LayerSelectionModalContent from "./modals/AddSceneAction/LayerSelection";
|
||||
import LayersActionEditModalContent from "./modals/ActionEdits/Layers";
|
||||
|
||||
function NothingSelected({ text }) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
alignItems: "center",
|
||||
marginTop: 40,
|
||||
}}
|
||||
>
|
||||
<MyIcon name="selection-search" size={64} />
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography16,
|
||||
{ color: appContext.appTheme.text, marginTop: 10 },
|
||||
]}
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SceneView() {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const [modalOpenStates, setModalOpenStates] = useState({
|
||||
modalChooseSceneIsOpen: false,
|
||||
modalCreateSceneIsOpen: false,
|
||||
modalAddSceneActionIsOpen: false,
|
||||
modalLayerSectionIsOpen: false,
|
||||
modalLayersActionEditIsOpen: false,
|
||||
});
|
||||
|
||||
const setModalOpen = (modalName, open) => {
|
||||
console.log("setModalOpen", modalName, open);
|
||||
|
||||
setModalOpenStates((prevState) => ({
|
||||
...prevState,
|
||||
[modalName]: open,
|
||||
}));
|
||||
};
|
||||
|
||||
const device = appContext.devices.find((device) => device.id === DevDeviceId);
|
||||
|
||||
const deviceScene = device.scenes.find(
|
||||
(scene) => scene.id === device.selectedScene
|
||||
);
|
||||
|
||||
const closeChooseSceneModals = () => {
|
||||
setModalOpenStates((prevState) => ({
|
||||
...prevState,
|
||||
modalChooseSceneIsOpen: false,
|
||||
modalCreateSceneIsOpen: false,
|
||||
}));
|
||||
};
|
||||
|
||||
const actionColor =
|
||||
deviceScene === undefined || deviceScene.actions.length === 0
|
||||
? appContext.appTheme.colors.primary
|
||||
: appContext.appTheme.textSecondary;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card>
|
||||
<MyDropdown
|
||||
label={"Szene"}
|
||||
onPress={() => {
|
||||
console.log("pressed");
|
||||
setModalOpen("modalChooseSceneIsOpen", true);
|
||||
}}
|
||||
selectedItemLabel={
|
||||
device.selectedScene === 0
|
||||
? "Keine Szene ausgewählt"
|
||||
: device.scenes.find((scene) => scene.id === device.selectedScene)
|
||||
.name
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
{device.selectedScene === 0 ? (
|
||||
<NothingSelected text="Keine Szene ausgewählt" />
|
||||
) : (
|
||||
<View>
|
||||
{deviceScene.actions.length === 0 ? (
|
||||
<NothingSelected text="Keine Aktionen in der Szene vorhanden" />
|
||||
) : (
|
||||
<FlatList
|
||||
scrollEnabled={false}
|
||||
data={deviceScene.actions}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={({ item }) => (
|
||||
<Card cardBackgroundColor={appContext.appTheme.colors.primary}>
|
||||
<Text>{item.name}</Text>
|
||||
</Card>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => setModalOpen("modalAddSceneActionIsOpen", true)}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginTop: 20,
|
||||
}}
|
||||
>
|
||||
<MyIcon
|
||||
name="plus-circle-outline"
|
||||
size={24}
|
||||
style={{
|
||||
marginRight: 10,
|
||||
color: actionColor,
|
||||
}}
|
||||
/>
|
||||
<Text style={{ color: actionColor }}>Aktion hinzufügen</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
<MyModal
|
||||
isOpen={modalOpenStates.modalChooseSceneIsOpen}
|
||||
closeModal={() => setModalOpen("modalChooseSceneIsOpen", false)}
|
||||
header={
|
||||
<MyPickerDefaultHeader
|
||||
title={"Wähle eine Szene aus"}
|
||||
closeModal={() => setModalOpen("modalChooseSceneIsOpen", false)}
|
||||
/>
|
||||
}
|
||||
content={
|
||||
<ChooseSceneModalContent
|
||||
openCreateSceneModal={() =>
|
||||
setModalOpen("modalCreateSceneIsOpen", true)
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<MyModal
|
||||
isOpen={modalOpenStates.modalCreateSceneIsOpen}
|
||||
closeModal={() => setModalOpen("modalCreateSceneIsOpen", false)}
|
||||
header={
|
||||
<MyPickerDefaultHeader
|
||||
title={"Szene erstellen"}
|
||||
closeModal={() => setModalOpen("modalCreateSceneIsOpen", false)}
|
||||
/>
|
||||
}
|
||||
content={
|
||||
<CreateSceneModalContent
|
||||
closeChooseSceneModals={closeChooseSceneModals}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</MyModal>
|
||||
|
||||
<MyModal
|
||||
scrollView
|
||||
isOpen={modalOpenStates.modalAddSceneActionIsOpen}
|
||||
closeModal={() => setModalOpen("modalAddSceneActionIsOpen", false)}
|
||||
header={
|
||||
<MyPickerDefaultHeader
|
||||
title={"Aktion hinzufügen"}
|
||||
closeModal={() => setModalOpen("modalAddSceneActionIsOpen", false)}
|
||||
/>
|
||||
}
|
||||
content={
|
||||
<AddSceneActionModalContent
|
||||
openLayerSelectionModal={() =>
|
||||
setModalOpen("modalLayerSectionIsOpen", true)
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<MyModal
|
||||
scrollView
|
||||
isOpen={modalOpenStates.modalLayerSectionIsOpen}
|
||||
closeModal={() => setModalOpen("modalLayerSectionIsOpen", false)}
|
||||
header={
|
||||
<MyPickerDefaultHeader
|
||||
title={"Layer auswahl"}
|
||||
closeModal={() => setModalOpen("modalLayerSectionIsOpen", false)}
|
||||
/>
|
||||
}
|
||||
content={
|
||||
<LayerSelectionModalContent
|
||||
openLayersActionEditModal={() =>
|
||||
setModalOpen("modalLayersActionEditIsOpen", true)
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<MyModal
|
||||
scrollView
|
||||
isOpen={modalOpenStates.modalLayersActionEditIsOpen}
|
||||
closeModal={() =>
|
||||
setModalOpen("modalLayersActionEditIsOpen", false)
|
||||
}
|
||||
header={
|
||||
<MyPickerDefaultHeader
|
||||
title={"Layer Action bearbeiten"}
|
||||
closeModal={() =>
|
||||
setModalOpen("modalLayersActionEditIsOpen", false)
|
||||
}
|
||||
/>
|
||||
}
|
||||
content={<LayersActionEditModalContent />}
|
||||
/>
|
||||
</MyModal>
|
||||
</MyModal>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -6,7 +6,7 @@ import { Divider } from "../../Components/Divider";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import MySwitch from "../../Components/Switch";
|
||||
import MyIcon from "../../Components/Icon";
|
||||
import { TextInputModal } from "../../Components/PickerModal";
|
||||
import { MyTextInputModal } from "../../Components/Modal";
|
||||
|
||||
export default function SettingsView() {
|
||||
const appContext = useContext(AppContext);
|
||||
|
@ -104,7 +104,7 @@ export default function SettingsView() {
|
|||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<TextInputModal
|
||||
<MyTextInputModal
|
||||
isOpen={modalTextInputVisible}
|
||||
setIsOpen={setModalTextInputVisible}
|
||||
onTextInputSave={() => console.log("save")}
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
import { lazy, useContext, useState } from "react";
|
||||
import {
|
||||
Image,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
Dimensions,
|
||||
Platform,
|
||||
ImageBackground,
|
||||
} from "react-native";
|
||||
import LightView from "./light";
|
||||
import { AppContext } from "../../utils";
|
||||
import MyIcon from "../../Components/Icon";
|
||||
|
||||
const MotorView = lazy(() => import("./motor"));
|
||||
const SettingsView = lazy(() => import("./settings"));
|
||||
const ColorScenesView = lazy(() => import("./colorScenes"));
|
||||
|
||||
const spaceToSide = 10; // left and right
|
||||
const top = 35;
|
||||
const spaceBetweenButtons = 60;
|
||||
|
||||
const topFirst = top;
|
||||
const topSecond = top + spaceBetweenButtons;
|
||||
const topThird = top + 2 * spaceBetweenButtons;
|
||||
|
||||
const windowDimensions = Dimensions.get("window");
|
||||
|
||||
let data = [];
|
||||
|
||||
const ledLines = 4;
|
||||
const ledsPerLine = 16;
|
||||
|
||||
const deviceLeds = ledLines * ledsPerLine;
|
||||
|
||||
// setting default color for testing
|
||||
for (let i = 0; i < deviceLeds; i++) {
|
||||
data.push("lime");
|
||||
}
|
||||
|
||||
export default function DeviceOldScreen() {
|
||||
const appContext = useContext(AppContext);
|
||||
const [selectedView, setSelectedView] = useState(0);
|
||||
const [deviceLedsColors, setDeviceLedsColor] = useState(data);
|
||||
const [selectedDeviceLed, setSelectedDeviceLed] = useState(2);
|
||||
|
||||
const SelectedView = () => {
|
||||
switch (selectedView) {
|
||||
case 0:
|
||||
return <LightView />;
|
||||
case 2:
|
||||
return <MotorView />;
|
||||
case 3:
|
||||
return <SettingsView />;
|
||||
case 4:
|
||||
return (
|
||||
<ColorScenesView
|
||||
deviceLedsColors={deviceLedsColors}
|
||||
setDeviceLedsColor={setDeviceLedsColor}
|
||||
selectedDeviceLed={selectedDeviceLed}
|
||||
setSelectedDeviceLed={setSelectedDeviceLed}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
<Text>Not found</Text>;
|
||||
}
|
||||
};
|
||||
|
||||
const MyButton = ({ selectedViewNumber, top, left, space, iconName }) => {
|
||||
const TouchComponent =
|
||||
appContext.appColorScheme === "dark"
|
||||
? TouchableHighlight
|
||||
: TouchableOpacity;
|
||||
|
||||
return (
|
||||
<TouchComponent
|
||||
onPress={() => setSelectedView(selectedViewNumber)}
|
||||
style={[
|
||||
{
|
||||
position: "absolute",
|
||||
backgroundColor: appContext.appTheme.card.backgroundColor,
|
||||
borderRadius: 10,
|
||||
padding: 8,
|
||||
},
|
||||
{ top: top },
|
||||
left === true ? { left: space } : { right: space },
|
||||
]}
|
||||
>
|
||||
<MyIcon
|
||||
name={iconName}
|
||||
size={30}
|
||||
color={
|
||||
selectedView === selectedViewNumber
|
||||
? appContext.appTheme.colors.primary
|
||||
: appContext.appTheme.icon
|
||||
}
|
||||
/>
|
||||
</TouchComponent>
|
||||
);
|
||||
};
|
||||
|
||||
const DeviceLedsColor = () => {
|
||||
let elements = [];
|
||||
let test = 400;
|
||||
|
||||
for (let l = 0; l < ledLines; l++) {
|
||||
let left = 0;
|
||||
let ledsElements = [];
|
||||
|
||||
for (let p = 0; p < ledsPerLine; p++) {
|
||||
left = left + 1.5;
|
||||
|
||||
const ledId = l > 0 ? l * 16 + p : p;
|
||||
|
||||
const deviceLedColor =
|
||||
l > 0 ? deviceLedsColors[l * 16 + p] : deviceLedsColors[p];
|
||||
|
||||
ledsElements.push(
|
||||
<View
|
||||
key={`${l}-${p}`}
|
||||
style={{
|
||||
width: 0.1 * (test / 16),
|
||||
height: 0.1 * (test / 16),
|
||||
backgroundColor:
|
||||
ledId === selectedDeviceLed ? "red" : deviceLedColor,
|
||||
borderRadius: 0.5,
|
||||
left: left,
|
||||
marginRight:
|
||||
windowDimensions.width > 360
|
||||
? 0.27 * (test / 16)
|
||||
: 0.26 * (test / 16),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
elements.push(
|
||||
<View
|
||||
key={`v-${l}`}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
top: 118.5 + l,
|
||||
right: "8%",
|
||||
}}
|
||||
>
|
||||
{ledsElements}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{elements}</>;
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
height: "100%",
|
||||
backgroundColor: appContext.appTheme.backgroundColor,
|
||||
}}
|
||||
>
|
||||
{selectedView === 4 && (
|
||||
<View>
|
||||
<ImageBackground
|
||||
source={require("../../../assets/image19.png")}
|
||||
resizeMode="contain"
|
||||
style={{ height: 250 }}
|
||||
>
|
||||
<DeviceLedsColor />
|
||||
</ImageBackground>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{appContext.isUserDeveloperModeEnabled ? (
|
||||
<>
|
||||
{selectedView !== 4 && (
|
||||
<Image
|
||||
source={require("../../../assets/device.png")}
|
||||
style={styles.image}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{selectedView !== 4 && (
|
||||
<View style={[styles.image, { backgroundColor: "#ddd" }]} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<MyButton
|
||||
iconName={"lightbulb-on-outline"}
|
||||
left
|
||||
selectedViewNumber={0}
|
||||
space={spaceToSide}
|
||||
top={topFirst}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"television-ambient-light"}
|
||||
left
|
||||
selectedViewNumber={1}
|
||||
space={spaceToSide}
|
||||
top={topSecond}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"axis-z-rotate-counterclockwise"}
|
||||
left
|
||||
selectedViewNumber={2}
|
||||
space={spaceToSide}
|
||||
top={topThird}
|
||||
/>
|
||||
|
||||
<MyButton
|
||||
iconName={"cog-outline"}
|
||||
left={false}
|
||||
selectedViewNumber={3}
|
||||
space={spaceToSide}
|
||||
top={topFirst}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"palette-outline"}
|
||||
left={false}
|
||||
selectedViewNumber={4}
|
||||
space={spaceToSide}
|
||||
top={topSecond}
|
||||
/>
|
||||
<MyButton
|
||||
iconName={"rotate-3d-variant"}
|
||||
left={false}
|
||||
selectedViewNumber={5}
|
||||
space={spaceToSide}
|
||||
top={topThird}
|
||||
/>
|
||||
|
||||
<ScrollView style={{ height: "100%" }}>
|
||||
<SelectedView />
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#2e2e30",
|
||||
},
|
||||
scrollView: {
|
||||
width: "100%",
|
||||
padding: 20,
|
||||
},
|
||||
image: {
|
||||
width: "100%",
|
||||
height: 250,
|
||||
},
|
||||
});
|
|
@ -25,9 +25,9 @@ import { AppContext, AppStyles, IsPlatformIos } from "../../utils";
|
|||
import Card from "../../Components/Card";
|
||||
import MySwitch from "../../Components/Switch";
|
||||
import MyIcon from "../../Components/Icon";
|
||||
import PickerModal from "../../Components/PickerModal";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MySlider from "../../Components/Slider";
|
||||
import MyPickerModal from "../../Components/Modal";
|
||||
|
||||
const colorModePickerOptions = [
|
||||
{ label: "Pulse", value: "pulse" },
|
||||
|
@ -198,7 +198,7 @@ export default function LightView() {
|
|||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<PickerModal
|
||||
<MyPickerModal
|
||||
searchFilter
|
||||
isOpen={modalDeviceColorModeVisible}
|
||||
setIsOpen={setModalDeviceColorModeVisible}
|
|
@ -0,0 +1,174 @@
|
|||
import { Text, TouchableOpacity, View } from "react-native";
|
||||
import Card from "../../Components/Card";
|
||||
import { useContext, useState } from "react";
|
||||
import { AppContext, AppStyles } from "../../utils";
|
||||
import { Divider } from "../../Components/Divider";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MySwitch from "../../Components/Switch";
|
||||
import MyIcon from "../../Components/Icon";
|
||||
import { MyTextInputModal } from "../../Components/Modal";
|
||||
|
||||
export default function SettingsView() {
|
||||
const appContext = useContext(AppContext);
|
||||
const { t } = useTranslation();
|
||||
const [modalTextInputVisible, setModalTextInputVisible] = useState(false);
|
||||
const [switchState, setSwitchState] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card>
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography20,
|
||||
{
|
||||
color: appContext.appTheme.text,
|
||||
marginBottom: 10,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{t("screens.device.settings.settingsTitle")}
|
||||
</Text>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<View style={{ width: "80%" }}>
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography16,
|
||||
{ color: appContext.appTheme.text },
|
||||
]}
|
||||
>
|
||||
{t("screens.device.settings.wifiStandByTitle")}
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography14,
|
||||
{ color: appContext.appTheme.textSecondary },
|
||||
]}
|
||||
>
|
||||
{t("screens.device.settings.wifiStandByDescription")}
|
||||
</Text>
|
||||
</View>
|
||||
<MySwitch
|
||||
value={switchState}
|
||||
onValueChange={(e) => setSwitchState(e)}
|
||||
/>
|
||||
</View>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<Text
|
||||
style={[
|
||||
AppStyles.typography20,
|
||||
{
|
||||
color: appContext.appTheme.text,
|
||||
marginBottom: 10,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{t("screens.device.settings.deviceInformationText")}
|
||||
</Text>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<View>
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography16], { color: appContext.appTheme.text })
|
||||
}
|
||||
>
|
||||
{t("screens.device.settings.deviceNameText")}
|
||||
</Text>
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography14],
|
||||
{ color: appContext.appTheme.textSecondary })
|
||||
}
|
||||
>
|
||||
Turtle
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity onPress={() => setModalTextInputVisible(true)}>
|
||||
<MyIcon name="pencil" size={18} color={appContext.appTheme.icon} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<MyTextInputModal
|
||||
isOpen={modalTextInputVisible}
|
||||
setIsOpen={setModalTextInputVisible}
|
||||
onTextInputSave={() => console.log("save")}
|
||||
modalTitle={t("screens.device.settings.deviceNameText")}
|
||||
inputTitle={t("screens.device.settings.deviceNameText")}
|
||||
inputDescription={t(
|
||||
"screens.device.settings.modalTextInputDeviceNameDescription"
|
||||
)}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography16], { color: appContext.appTheme.text })
|
||||
}
|
||||
>
|
||||
{t("screens.device.settings.deviceModelText")}
|
||||
</Text>
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography14],
|
||||
{ color: appContext.appTheme.textSecondary })
|
||||
}
|
||||
>
|
||||
Shimmex Aurora
|
||||
</Text>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography16], { color: appContext.appTheme.text })
|
||||
}
|
||||
>
|
||||
{t("screens.device.settings.deviceFirmwareVersionText")}
|
||||
</Text>
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography14],
|
||||
{ color: appContext.appTheme.textSecondary })
|
||||
}
|
||||
>
|
||||
1.0.1
|
||||
</Text>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography16], { color: appContext.appTheme.text })
|
||||
}
|
||||
>
|
||||
{t("screens.device.settings.deviceLastUpdatedText")}
|
||||
</Text>
|
||||
<Text
|
||||
style={
|
||||
([AppStyles.typography14],
|
||||
{ color: appContext.appTheme.textSecondary })
|
||||
}
|
||||
>
|
||||
11.07.2023 um 20:33 Uhr
|
||||
</Text>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -3,9 +3,9 @@ import { Text, TouchableOpacity, View } from "react-native";
|
|||
import Card from "../../Components/Card";
|
||||
import { AppContext, AppStyles, Constants } from "../../utils";
|
||||
import { Divider } from "../../Components/Divider";
|
||||
import PickerModal from "../../Components/PickerModal";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MySwitch from "../../Components/Switch";
|
||||
import { MyPickerModal } from "../../Components/Modal";
|
||||
|
||||
export default function SettingsScreen() {
|
||||
const appContext = useContext(AppContext);
|
||||
|
@ -139,7 +139,7 @@ export default function SettingsScreen() {
|
|||
/>
|
||||
</View>
|
||||
|
||||
<PickerModal
|
||||
<MyPickerModal
|
||||
isOpen={modalAppColorSchemeVisible}
|
||||
setIsOpen={setAppColorSchemeModalVisible}
|
||||
items={[
|
||||
|
@ -160,7 +160,7 @@ export default function SettingsScreen() {
|
|||
]}
|
||||
/>
|
||||
|
||||
<PickerModal
|
||||
<MyPickerModal
|
||||
isOpen={modalAppLanguageVisible}
|
||||
setIsOpen={setModalAppLanguageVisible}
|
||||
items={Constants.languages.map((language) => {
|
||||
|
|
56
src/utils.js
56
src/utils.js
|
@ -2,6 +2,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage";
|
|||
import { createContext, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Appearance, Platform, StyleSheet } from "react-native";
|
||||
import uuid from "react-native-uuid";
|
||||
|
||||
export const Constants = {
|
||||
defaultLanguage: "de",
|
||||
|
@ -147,14 +148,66 @@ export function GetDataFromList(list, key) {
|
|||
return list.find((v) => v[0] === key)[1];
|
||||
}
|
||||
|
||||
export function GetUuid() {
|
||||
return uuid.v4();
|
||||
}
|
||||
|
||||
const appContextPreview = {
|
||||
appColorScheme: "",
|
||||
appLanguage: "",
|
||||
isUserExpertModeEnabled: "",
|
||||
isUserDeveloperModeEnabled: "",
|
||||
appTheme: DarkAppTheme,
|
||||
devices: [],
|
||||
};
|
||||
|
||||
export const DevDeviceId = 0;
|
||||
|
||||
const devData = [
|
||||
{
|
||||
id: 0, // deviceId
|
||||
selectedScene: 0,
|
||||
scenes: [
|
||||
{
|
||||
id: 1,
|
||||
name: "Szene 1",
|
||||
actions: [
|
||||
{
|
||||
id: 0,
|
||||
name: "Test",
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: "Test1",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Szene 2",
|
||||
actions: [
|
||||
{
|
||||
id: 0,
|
||||
name: "Haha",
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: "Haha 1",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export function NewEmptyDeviceScene() {
|
||||
return {
|
||||
id: GetUuid(),
|
||||
name: "Leere Szene",
|
||||
actions: [],
|
||||
};
|
||||
}
|
||||
|
||||
export const AppContext = createContext(appContextPreview);
|
||||
|
||||
export function AppProvider({ children }) {
|
||||
|
@ -165,6 +218,7 @@ export function AppProvider({ children }) {
|
|||
// TODO: only while development
|
||||
const [isUserDeveloperModeEnabled, setIsUserDeveloperModeEnabled] =
|
||||
useState(false);
|
||||
const [devices, setDevices] = useState(devData);
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const saveAppColorScheme = async (value) => {
|
||||
|
@ -207,6 +261,8 @@ export function AppProvider({ children }) {
|
|||
setIsUserExpertModeEnabled: saveUserExpertMode,
|
||||
isUserDeveloperModeEnabled: isUserDeveloperModeEnabled,
|
||||
setUserIsDeveloperModeEnabled: saveUserDeveloperMode,
|
||||
devices: devices,
|
||||
setDevices: setDevices,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
Loading…
Reference in New Issue