main
alex 2023-07-13 18:05:53 +00:00
parent 1a2f47bf7c
commit 835c97a20f
13 changed files with 422 additions and 180 deletions

26
App.js
View File

@ -1,6 +1,6 @@
import "react-native-gesture-handler"; import "react-native-gesture-handler";
import { StatusBar } from "expo-status-bar"; import { StatusBar } from "expo-status-bar";
import { Appearance, StyleSheet } from "react-native"; import { Appearance, StyleSheet, Text, View } from "react-native";
import { createDrawerNavigator } from "@react-navigation/drawer"; import { createDrawerNavigator } from "@react-navigation/drawer";
import { NavigationContainer } from "@react-navigation/native"; import { NavigationContainer } from "@react-navigation/native";
import SideBar from "./src/Components/SideBar"; import SideBar from "./src/Components/SideBar";
@ -16,8 +16,9 @@ import {
} from "./src/utils"; } from "./src/utils";
import DeviceScreen from "./src/Screens/Device"; import DeviceScreen from "./src/Screens/Device";
import SettingsScreen from "./src/Screens/Settings"; import SettingsScreen from "./src/Screens/Settings";
import { useContext, useEffect } from "react"; import { Suspense, useContext, useEffect } from "react";
import { SafeAreaView } from "react-native-safe-area-context"; import { SafeAreaView } from "react-native-safe-area-context";
import "./i18n";
const Drawer = createDrawerNavigator(); const Drawer = createDrawerNavigator();
@ -42,7 +43,7 @@ export function MyApp() {
appLanguage === null ? Constants.defaultLanguage : appLanguage appLanguage === null ? Constants.defaultLanguage : appLanguage
); );
appContext.setAppColorScheme( appContext.setAppColorScheme(
appColorScheme === null ? Appearance.getColorScheme() : appColorScheme appColorScheme === null ? "auto" : appColorScheme
); );
appContext.setIsUserExpertModeEnabled( appContext.setIsUserExpertModeEnabled(
@ -88,17 +89,18 @@ export function MyApp() {
export default function App() { export default function App() {
return ( return (
<Suspense
fallback={
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<Text>Loading...</Text>
</View>
}
>
<AppProvider> <AppProvider>
<MyApp /> <MyApp />
</AppProvider> </AppProvider>
</Suspense>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});

View File

@ -9,3 +9,7 @@ https://pictogrammers.com/library/mdi/
# RNUILib # RNUILib
https://wix.github.io/react-native-ui-lib/docs/getting-started/setup https://wix.github.io/react-native-ui-lib/docs/getting-started/setup
https://stackoverflow.com/questions/68243384/dark-mode-usecolorscheme-always-returns-light-on-android
https://stackoverflow.com/questions/70493788/i18nextpluralresolver-your-environment-seems-not-to-be-intl-api-compatible-u

View File

@ -5,23 +5,23 @@
"version": "1.0.0", "version": "1.0.0",
"orientation": "portrait", "orientation": "portrait",
"icon": "./assets/icon.png", "icon": "./assets/icon.png",
"userInterfaceStyle": "light", "userInterfaceStyle": "automatic",
"splash": { "splash": {
"image": "./assets/splash.png", "image": "./assets/splash.png",
"resizeMode": "contain", "resizeMode": "contain",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"assetBundlePatterns": [ "assetBundlePatterns": ["**/*"],
"**/*"
],
"ios": { "ios": {
"supportsTablet": true "supportsTablet": true,
"userInterfaceStyle": "automatic"
}, },
"android": { "android": {
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png", "foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
} },
"userInterfaceStyle": "automatic"
}, },
"web": { "web": {
"favicon": "./assets/favicon.png" "favicon": "./assets/favicon.png"

29
i18n.js Normal file
View File

@ -0,0 +1,29 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import de from "./locales/de.json";
import en from "./locales/en.json";
const resources = {
de: {
translation: de,
},
en: {
translation: en,
},
};
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
compatibilityJSON: "v3",
resources,
lng: "en", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
// you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
// if you're using a language detector, do not define the lng option
interpolation: {
escapeValue: false, // react already safes from xss
},
});
export default i18n;

34
locales/de.json Normal file
View File

@ -0,0 +1,34 @@
{
"test": "Einstellungen",
"sideBar": {
"devicesTitle": "Geräte",
"settings": "Einstellungen",
"faq": "FAQ",
"feedback": "Feedback geben"
},
"screens": {
"device": {
"settings": {
"settingsTitle": "Einstellungen",
"wifiStandByTitle": "WLAN im Standby",
"wifiStandByDescription": "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.",
"deviceInformationTitle": "Geräteinformationen",
"deviceModelTitle": "Gerätemodell",
"deviceFirmwareVersionTitle": "Firmware Version",
"deviceLastUpdated": "Letzte Aktualisierung"
}
},
"settings": {
"settingsCardTitle": "Einstellungen",
"languageText": "Sprache",
"appColorSchemeText": "Anzeigemodus",
"appColorSchemePicker": {
"auto": "Systemvoreinstellung",
"dark": "Dunkel",
"light": "Hell"
},
"expertModeTitle": "Experten Modus",
"expertModeDescription": "Durch das Einschalten werden zusätzliche Funktionen in der App freigeschaltet, wie beispielsweise die Möglichkeit, benutzerdefinierte Farbcodes anzugeben."
}
}
}

34
locales/en.json Normal file
View File

@ -0,0 +1,34 @@
{
"test": "Settings",
"sideBar": {
"devicesTitle": "Devices",
"settings": "Settings",
"faq": "FAQ",
"feedback": "Give feedback"
},
"screens": {
"device": {
"settings": {
"settingsTitle": "Settings",
"wifiStandByTitle": "WLAN in standby",
"wifiStandByDescription": "The WLAN connection remains established even if the device is switched off. Please note that this can lead to increased power consumption.",
"deviceInformationTitle": "Device information",
"deviceModelTitle": "Device model",
"deviceFirmwareVersionTitle": "Firmware Version",
"deviceLastUpdated": "Last updated"
}
},
"settings": {
"settingsCardTitle": "Settings",
"languageText": "Language",
"appColorSchemeText": "Appearance",
"appColorSchemePicker": {
"auto": "System default",
"dark": "Dark",
"light": "Light"
},
"expertModeTitle": "Expert mode",
"expertModeDescription": "Turning it on unlocks additional features in the app, such as the ability to specify custom color codes."
}
}
}

70
package-lock.json generated
View File

@ -14,7 +14,10 @@
"@react-navigation/native-stack": "^6.9.13", "@react-navigation/native-stack": "^6.9.13",
"expo": "~48.0.18", "expo": "~48.0.18",
"expo-status-bar": "~1.4.4", "expo-status-bar": "~1.4.4",
"i18next": "^23.2.11",
"i18next-browser-languagedetector": "^7.1.0",
"react": "18.2.0", "react": "18.2.0",
"react-i18next": "^13.0.2",
"react-native": "0.71.8", "react-native": "0.71.8",
"react-native-gesture-handler": "~2.9.0", "react-native-gesture-handler": "~2.9.0",
"react-native-pager-view": "6.1.2", "react-native-pager-view": "6.1.2",
@ -8091,6 +8094,14 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}, },
"node_modules/html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"dependencies": {
"void-elements": "3.1.0"
}
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -8126,6 +8137,36 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/i18next": {
"version": "23.2.11",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.2.11.tgz",
"integrity": "sha512-MA4FsxOjyCaOZtRDB4yuwjCvqYEioD4G4LlXOn7SO3rnQUlxTufyLsOqfL9MKakeLRBkefe8bqcs0D6Z/xFk1w==",
"funding": [
{
"type": "individual",
"url": "https://locize.com"
},
{
"type": "individual",
"url": "https://locize.com/i18next.html"
},
{
"type": "individual",
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
}
],
"dependencies": {
"@babel/runtime": "^7.22.5"
}
},
"node_modules/i18next-browser-languagedetector": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz",
"integrity": "sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==",
"dependencies": {
"@babel/runtime": "^7.19.4"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -12105,6 +12146,27 @@
"react": ">=17.0.0" "react": ">=17.0.0"
} }
}, },
"node_modules/react-i18next": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.0.2.tgz",
"integrity": "sha512-NEVxC32v0oR4egwYM0QM0WE93AiJG5r0NTXTL8mhQfAhsMfDS2fSO6jpluyfsfypP988KzUQrAXncspcJ7+GHA==",
"dependencies": {
"@babel/runtime": "^7.22.5",
"html-parse-stringify": "^3.0.1"
},
"peerDependencies": {
"i18next": ">= 23.2.3",
"react": ">= 16.8.0"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@ -14351,6 +14413,14 @@
"resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz",
"integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="
}, },
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/walker": { "node_modules/walker": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",

View File

@ -15,7 +15,10 @@
"@react-navigation/native-stack": "^6.9.13", "@react-navigation/native-stack": "^6.9.13",
"expo": "~48.0.18", "expo": "~48.0.18",
"expo-status-bar": "~1.4.4", "expo-status-bar": "~1.4.4",
"i18next": "^23.2.11",
"i18next-browser-languagedetector": "^7.1.0",
"react": "18.2.0", "react": "18.2.0",
"react-i18next": "^13.0.2",
"react-native": "0.71.8", "react-native": "0.71.8",
"react-native-gesture-handler": "~2.9.0", "react-native-gesture-handler": "~2.9.0",
"react-native-pager-view": "6.1.2", "react-native-pager-view": "6.1.2",

View File

@ -0,0 +1,90 @@
import { useContext } from "react";
import { AppContext, AppStyles } from "../../utils";
import Icon from "@expo/vector-icons/MaterialCommunityIcons";
import { Modal, Text, TouchableOpacity, View } from "react-native";
import { Divider } from "../Divider";
export default function PickerModal({ isOpen, setIsOpen, items }) {
const appContext = useContext(AppContext);
const closeModal = () => setIsOpen(false);
return (
<Modal
visible={isOpen}
animationType="slide"
onRequestClose={() => closeModal()}
>
<View
style={{
flex: 1,
backgroundColor: appContext.appTheme.backgroundColor,
}}
>
<TouchableOpacity
onPress={() => {
console.log("press");
setIsOpen(false);
}}
>
<Icon
name="window-close"
size={24}
style={{ marginLeft: 10, marginTop: 20, marginBottom: 20 }}
color={appContext.appTheme.icon}
/>
</TouchableOpacity>
{items.map((item, i) => {
return item.selected ? (
<View key={i}>
<TouchableOpacity onPress={() => closeModal()}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
marginLeft: 20,
marginRight: 20,
}}
>
<Text
style={[
AppStyles.typography16,
{ color: appContext.appTheme.text },
]}
>
{item.label}
</Text>
<Icon
name="check"
size={24}
color={appContext.appTheme.colors.primary}
/>
</View>
</TouchableOpacity>
<Divider />
</View>
) : (
<View key={i}>
<TouchableOpacity
onPress={() => {
closeModal();
item.onPress();
}}
>
<Text
style={[
AppStyles.typography16,
{ marginLeft: 20, color: appContext.appTheme.text },
]}
>
{item.label}
</Text>
</TouchableOpacity>
<Divider />
</View>
);
})}
</View>
</Modal>
);
}

View File

@ -4,10 +4,11 @@ import { Image, Text, TouchableOpacity, View } from "react-native";
import { AppContext, AppStyles } from "../../utils"; import { AppContext, AppStyles } from "../../utils";
import { Divider } from "../Divider"; import { Divider } from "../Divider";
import Icon from "@expo/vector-icons/MaterialCommunityIcons"; import Icon from "@expo/vector-icons/MaterialCommunityIcons";
import { useIsFocused } from "@react-navigation/native"; import { useTranslation } from "react-i18next";
export default function Sidebar(props) { export default function Sidebar(props) {
const appContext = useContext(AppContext); const appContext = useContext(AppContext);
const { t } = useTranslation();
const MyDrawerItem = ({ const MyDrawerItem = ({
label, label,
@ -53,7 +54,7 @@ export default function Sidebar(props) {
</View> </View>
<TouchableOpacity <TouchableOpacity
onPress={() => console.log("Pressed")} onPress={() => console.log("Pressed power")}
style={{ right: -30 }} style={{ right: -30 }}
> >
<Icon <Icon
@ -118,7 +119,7 @@ export default function Sidebar(props) {
{ marginLeft: 10, marginTop: 10, color: appContext.appTheme.text }, { marginLeft: 10, marginTop: 10, color: appContext.appTheme.text },
]} ]}
> >
Geräte {t("sideBar.devicesTitle")}
</Text> </Text>
<DrawerContentScrollView contentContainerStyle={{ paddingTop: 0 }}> <DrawerContentScrollView contentContainerStyle={{ paddingTop: 0 }}>
{["Turtle"].map((item, i) => ( {["Turtle"].map((item, i) => (
@ -137,19 +138,19 @@ export default function Sidebar(props) {
<View style={{ justifyContent: "flex-end" }}> <View style={{ justifyContent: "flex-end" }}>
<Divider style={{ marginLeft: 10, marginRight: 10 }} /> <Divider style={{ marginLeft: 10, marginRight: 10 }} />
<MyDrawerItem <MyDrawerItem
label={"FAQ"} label={t("sideBar.faq")}
onPress={() => props.navigation.navigate("FAQ")} onPress={() => props.navigation.navigate("FAQ")}
iconName="frequently-asked-questions" iconName="frequently-asked-questions"
routeName="FAQ" routeName="FAQ"
/> />
<MyDrawerItem <MyDrawerItem
label={"Feedback geben"} label={t("sideBar.feedback")}
onPress={() => props.navigation.navigate("Feedback")} onPress={() => props.navigation.navigate("Feedback")}
iconName="comment-quote" iconName="comment-quote"
routeName="Feedback" routeName="Feedback"
/> />
<MyDrawerItem <MyDrawerItem
label={"Einstellungen"} label={t("sideBar.settings")}
onPress={() => props.navigation.navigate("Settings")} onPress={() => props.navigation.navigate("Settings")}
iconName="cog" iconName="cog"
routeName="Settings" routeName="Settings"

View File

@ -1,11 +1,15 @@
import { Text, View } from "react-native"; import { Text, View } from "react-native";
import Card from "../../Components/Card"; import Card from "../../Components/Card";
import { Incubator, Switch } from "react-native-ui-lib"; import { Incubator, Switch } from "react-native-ui-lib";
import { useState } from "react"; import { useContext, useState } from "react";
import { AppStyles } from "../../utils"; import { AppContext, AppStyles } from "../../utils";
import { Divider } from "../../Components/Divider"; import { Divider } from "../../Components/Divider";
import { useTranslation } from "react-i18next";
export default function SettingsView() { export default function SettingsView() {
const appContext = useContext(AppContext);
const { t } = useTranslation();
const [switchState, setSwitchState] = useState(false); const [switchState, setSwitchState] = useState(false);
const [sliderValue, setSliderValue] = useState(0); const [sliderValue, setSliderValue] = useState(0);
@ -16,12 +20,12 @@ export default function SettingsView() {
style={[ style={[
AppStyles.typography20, AppStyles.typography20,
{ {
color: "#fff", color: appContext.appTheme.text,
marginBottom: 10, marginBottom: 10,
}, },
]} ]}
> >
Einstellungen {t("screens.device.settings.settingsTitle")}
</Text> </Text>
<View <View
@ -33,12 +37,10 @@ export default function SettingsView() {
> >
<View style={{ width: "80%" }}> <View style={{ width: "80%" }}>
<Text style={[AppStyles.typography16, { color: "#fff" }]}> <Text style={[AppStyles.typography16, { color: "#fff" }]}>
WLAN im Standby {t("screens.device.settings.wifiStandByTitle")}
</Text> </Text>
<Text style={[AppStyles.typography14, { color: "#ddd" }]}> <Text style={[AppStyles.typography14, { color: "#ddd" }]}>
Die WLAN-Verbindung bleibt bestehen, auch wenn das Gerät {t("screens.device.settings.wifiStandByDescription")}
ausgeschaltet ist. Bitte beachten Sie, dass dies zu einem erhöhten
Stromverbrauch führen kann.
</Text> </Text>
</View> </View>
<Switch <Switch
@ -58,22 +60,22 @@ export default function SettingsView() {
}, },
]} ]}
> >
Geräteinformationen {t("screens.device.settings.deviceInformationTitle")}
</Text> </Text>
<Text style={([AppStyles.typography16], { color: "#fff" })}> <Text style={([AppStyles.typography16], { color: "#fff" })}>
Gerätemodell {t("screens.device.settings.deviceModelTitle")}
</Text> </Text>
<Text style={([AppStyles.typography14], { color: "#ddd" })}> <Text style={([AppStyles.typography14], { color: "#ddd" })}>
Shimmex Aurora Shimmex Aurora
</Text> </Text>
<Divider /> <Divider />
<Text style={([AppStyles.typography16], { color: "#fff" })}> <Text style={([AppStyles.typography16], { color: "#fff" })}>
Firmware Version {t("screens.device.settings.deviceFirmwareVersionTitle")}
</Text> </Text>
<Text style={([AppStyles.typography14], { color: "#ddd" })}>1.0.1</Text> <Text style={([AppStyles.typography14], { color: "#ddd" })}>1.0.1</Text>
<Divider /> <Divider />
<Text style={([AppStyles.typography16], { color: "#fff" })}> <Text style={([AppStyles.typography16], { color: "#fff" })}>
Letzte Aktualisierung {t("screens.device.settings.deviceLastUpdated")}
</Text> </Text>
<Text style={([AppStyles.typography14], { color: "#ddd" })}> <Text style={([AppStyles.typography14], { color: "#ddd" })}>
11.07.2023 um 20:33 Uhr 11.07.2023 um 20:33 Uhr

View File

@ -2,13 +2,17 @@ import { useContext, useState } from "react";
import { Modal, Text, TouchableOpacity, View } from "react-native"; import { Modal, Text, TouchableOpacity, View } from "react-native";
import { Picker, Switch } from "react-native-ui-lib"; import { Picker, Switch } from "react-native-ui-lib";
import Card from "../../Components/Card"; import Card from "../../Components/Card";
import { AppContext, AppStyles } from "../../utils"; import { AppContext, AppStyles, Constants } from "../../utils";
import { Divider } from "../../Components/Divider"; import { Divider } from "../../Components/Divider";
import Icon from "@expo/vector-icons/MaterialCommunityIcons"; import PickerModal from "../../Components/PickerModal";
import { useTranslation } from "react-i18next";
export default function SettingsScreen() { export default function SettingsScreen() {
const appContext = useContext(AppContext); const appContext = useContext(AppContext);
const [modalVisible, setModalVisible] = useState(false); const { t } = useTranslation();
const [modalAppColorSchemeVisible, setAppColorSchemeModalVisible] =
useState(false);
const [modalAppLanguageVisible, setModalAppLanguageVisible] = useState(false);
return ( return (
<View <View
@ -27,33 +31,64 @@ export default function SettingsScreen() {
}, },
]} ]}
> >
Einstellungen {t("screens.settings.settingsCardTitle")}
</Text> </Text>
<Picker <TouchableOpacity
label="Sprache" onPress={() => setModalAppLanguageVisible(true)}
value={appContext.appLanguage} style={{ marginBottom: 6 }}
onChange={(v) => appContext.setAppLanguage(v)}
fieldType={Picker.fieldTypes.settings}
showSearch
searchPlaceholder="Search a language"
searchStyle={{ color: "#fff", placeholderTextColor: "#fff" }}
> >
<Picker.Item key={1} label="System default" value={"auto"} /> <View
<Picker.Item key={2} label="Deutsch" value={"de"} /> style={{
<Picker.Item key={3} label="English" value={"en"} /> flexDirection: "row",
</Picker> alignItems: "center",
justifyContent: "space-between",
}}
>
<Text
style={[
AppStyles.typography14,
{ color: appContext.appTheme.text },
]}
>
{t("screens.settings.languageText")}
</Text>
<Text style={{ color: appContext.appTheme.colors.primary }}>
{
Constants.languages.find(
(language) => language.name === appContext.appLanguage
).label
}
</Text>
</View>
</TouchableOpacity>
<Picker <TouchableOpacity onPress={() => setAppColorSchemeModalVisible(true)}>
label="Anzeigemodus" <View
value={appContext.appColorScheme} style={{
onChange={(v) => appContext.setAppColorScheme(v)} flexDirection: "row",
fieldType={Picker.fieldTypes.settings} alignItems: "center",
justifyContent: "space-between",
}}
> >
<Picker.Item key={1} label="System default" value={"auto"} /> <Text
<Picker.Item key={2} label="Dark" value={"dark"} /> style={[
<Picker.Item key={3} label="Light" value={"light"} /> AppStyles.typography14,
</Picker> { color: appContext.appTheme.text },
]}
>
{t("screens.settings.appColorSchemeText")}
</Text>
<Text style={{ color: appContext.appTheme.colors.primary }}>
{appContext.appColorScheme === "auto"
? t("screens.settings.appColorSchemePicker.auto")
: appContext.appColorScheme === "dark"
? t("screens.settings.appColorSchemePicker.dark")
: t("screens.settings.appColorSchemePicker.light")}
</Text>
</View>
</TouchableOpacity>
<Divider /> <Divider />
<View <View
style={{ style={{
@ -69,7 +104,7 @@ export default function SettingsScreen() {
{ color: appContext.appTheme.text }, { color: appContext.appTheme.text },
]} ]}
> >
Experten Modus {t("screens.settings.expertModeTitle")}
</Text> </Text>
<Text <Text
style={[ style={[
@ -77,9 +112,7 @@ export default function SettingsScreen() {
{ color: appContext.appTheme.textSecondary }, { color: appContext.appTheme.textSecondary },
]} ]}
> >
Durch das Einschalten werden zusätzliche Funktionen in der App {t("screens.settings.expertModeDescription")}
freigeschaltet, wie beispielsweise die Möglichkeit,
benutzerdefinierte Farbcodes anzugeben.
</Text> </Text>
</View> </View>
<Switch <Switch
@ -106,108 +139,38 @@ export default function SettingsScreen() {
/> />
</View> </View>
<TouchableOpacity onPress={() => setModalVisible(true)}> <PickerModal
<View isOpen={modalAppColorSchemeVisible}
style={{ setIsOpen={setAppColorSchemeModalVisible}
flexDirection: "row", items={[
alignItems: "center", {
justifyContent: "space-between", label: t("screens.settings.appColorSchemePicker.auto"),
}} onPress: () => appContext.setAppColorScheme("auto"),
> },
<Text style={{ color: appContext.appTheme.text }}> {
Anzeigemodus label: t("screens.settings.appColorSchemePicker.dark"),
</Text> onPress: () => appContext.setAppColorScheme("dark"),
<Text style={{ color: appContext.appTheme.colors.primary }}> selected: appContext.appColorScheme === "dark",
{appContext.appColorScheme} },
</Text> {
</View> label: t("screens.settings.appColorSchemePicker.light"),
</TouchableOpacity> onPress: () => appContext.setAppColorScheme("light"),
selected: appContext.appColorScheme === "light",
<Modal },
visible={modalVisible} ]}
animationType="slide"
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<TouchableOpacity onPress={() => setModalVisible(false)}>
<Icon
name="window-close"
size={24}
style={{ marginLeft: 10, marginTop: 20, marginBottom: 20 }}
/> />
</TouchableOpacity>
<Text style={[AppStyles.typography16, { marginLeft: 20 }]}> <PickerModal
System default isOpen={modalAppLanguageVisible}
</Text> setIsOpen={setModalAppLanguageVisible}
items={Constants.languages.map((language) => {
<Divider /> return {
label: language.label,
{appContext.appColorScheme === "dark" ? ( onPress: () => appContext.setAppLanguage(language.name),
<TouchableOpacity onPress={() => setModalVisible(false)}> selected: appContext.appLanguage === language.name,
<View };
style={{ })}
flexDirection: "row",
justifyContent: "space-between",
marginLeft: 20,
marginRight: 20,
}}
>
<Text style={[AppStyles.typography16]}>Dark</Text>
<Icon
name="check"
size={24}
color={appContext.appTheme.colors.primary}
/> />
</View>
</TouchableOpacity>
) : (
<TouchableOpacity
onPress={() => {
setModalVisible(false);
appContext.setAppColorScheme("dark");
}}
>
<Text style={[AppStyles.typography16, { marginLeft: 20 }]}>
Dark
</Text>
</TouchableOpacity>
)}
<Divider />
{appContext.appColorScheme === "light" ? (
<TouchableOpacity onPress={() => setModalVisible(false)}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
marginLeft: 20,
marginRight: 20,
}}
>
<Text style={[AppStyles.typography16]}>Light</Text>
<Icon
name="check"
size={24}
color={appContext.appTheme.colors.primary}
/>
</View>
</TouchableOpacity>
) : (
<TouchableOpacity
onPress={() => {
setModalVisible(false);
appContext.setAppColorScheme("light");
}}
>
<Text style={[AppStyles.typography16, { marginLeft: 20 }]}>
Light
</Text>
</TouchableOpacity>
)}
</Modal>
</Card> </Card>
</View> </View>
); );

View File

@ -1,10 +1,20 @@
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { createContext, useState } from "react"; import { createContext, useState } from "react";
import { StyleSheet } from "react-native"; import { useTranslation } from "react-i18next";
import { Colors } from "react-native-ui-lib"; import { Appearance, StyleSheet } from "react-native";
export const Constants = { export const Constants = {
defaultLanguage: "de", defaultLanguage: "de",
languages: [
{
name: "de",
label: "Deutsch",
},
{
name: "en",
label: "English",
},
],
}; };
export const AppStyles = StyleSheet.create({ export const AppStyles = StyleSheet.create({
@ -45,7 +55,7 @@ const DarkAppTheme = {
}, },
}, },
divider: "#ddd", divider: "#ddd",
icon: "#fff", icon: "#ddd",
}; };
const LightAppTheme = { const LightAppTheme = {
@ -122,23 +132,23 @@ export function AppProvider({ children }) {
// TODO: only while development // TODO: only while development
const [isUserDeveloperModeEnabled, setIsUserDeveloperModeEnabled] = const [isUserDeveloperModeEnabled, setIsUserDeveloperModeEnabled] =
useState(false); useState(false);
const { i18n } = useTranslation();
const saveAppColorScheme = async (value) => { const saveAppColorScheme = async (value) => {
StoreData("appColorScheme", value); StoreData("appColorScheme", value);
setAppColorScheme(value); setAppColorScheme(value);
if (value === "dark") { let colorScheme;
setAppTheme(DarkAppTheme);
console.log("dark"); colorScheme = value === "auto" ? Appearance.getColorScheme() : value;
} else {
setAppTheme(LightAppTheme); setAppTheme(colorScheme === "light" ? LightAppTheme : DarkAppTheme);
console.log("light");
}
}; };
const saveAppLanguage = async (value) => { const saveAppLanguage = async (value) => {
StoreData("appLanguage", value); StoreData("appLanguage", value);
setAppLanguage(value); setAppLanguage(value);
i18n.changeLanguage(value);
}; };
const saveUserExpertMode = async (value) => { const saveUserExpertMode = async (value) => {