settings und login verschönert

This commit is contained in:
2024-09-19 10:41:30 +02:00
parent 113face8bf
commit abac871af7
4 changed files with 124 additions and 212 deletions

View File

@@ -94,6 +94,7 @@ export const ThemeTextInput = ({ style, value, disabled, onValueChange, secureTe
paddingRight: 14,
paddingLeft: 8,
paddingVertical: 1,
marginVertical: 5,
borderColor: disabled ? colors.textDisabled : colors.text,
borderWidth: 1,
},

View File

@@ -4,7 +4,6 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
import { ToastType, useToast } from "./ToastProvider";
const fadeDuration = 300;
const tabBarHeight = 60;
export const Toast: React.FC = () => {
const insets = useSafeAreaInsets();
@@ -60,7 +59,7 @@ export const Toast: React.FC = () => {
<Animated.View
style={[
styles.container,
{ bottom: insets.bottom + tabBarHeight, opacity },
{ top: insets.top + 20, opacity }, // Positioning at the top
]}
>
<View style={[styles.toast, { backgroundColor }]}>
@@ -86,4 +85,4 @@ const styles = StyleSheet.create({
textAlign: "center",
color: '#fff',
},
});
});

View File

@@ -1,12 +1,11 @@
import React, { useState, useEffect, useContext, useRef } from 'react';
import { View, Text, ScrollView, Button, StyleSheet, TouchableOpacity, ActivityIndicator, Alert, Animated, Image } from 'react-native';
import React, { useState, useEffect, useContext } from 'react';
import { View, ScrollView, Button, StyleSheet, Image, ActivityIndicator, Alert } from 'react-native';
import { SettingsContext } from '../SettingsProvider';
import { useColors } from '../common/colors';
import ErrorBoundary from 'react-native-error-boundary';
import { ThemeSwitch, ThemeText, ThemeTextInput } from '../common/ThemeTypes';
import { ThemeText, ThemeTextInput } from '../common/ThemeTypes';
import Credits from '../common/Credits';
import FontAwesome5 from '@expo/vector-icons/FontAwesome5';
import { ServerSettings } from './Settings';
import { AdvancedSettings } from './Settings';
const Login = () => {
const colors = useColors();
@@ -15,23 +14,14 @@ const Login = () => {
const [url, setUrl] = useState('');
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [isSystemTheme, setIsSystemTheme] = useState(settings.systemTheme);
const [isDarkMode, setIsDarkMode] = useState(settings.darkTheme);
const [requireAuth, setRequireAuth] = useState(settings.requireAuth);
const [isSaving, setIsSaving] = useState(false);
const [showAdvanced, setShowAdvanced] = useState(false);
const [rotateAnim] = useState(new Animated.Value(0)); // Animation state for the arrow
const [advancedHeightAnim] = useState(new Animated.Value(0)); // Animation state for the advanced settings height
const advancedSectionRef = useRef(null);
useEffect(() => {
if (settings) {
setUrl(settings.url || '');
setUsername(settings.username || '');
setPassword(settings.password || '');
setIsSystemTheme(settings.systemTheme);
setIsDarkMode(settings.darkTheme);
setRequireAuth(settings.requireAuth);
}
}, [settings]);
@@ -42,11 +32,10 @@ const Login = () => {
try {
setIsSaving(true);
await updateSettings({
...settings,
url,
username,
password,
systemTheme: isSystemTheme,
darkTheme: isDarkMode,
requireAuth,
});
} catch (error) {
@@ -61,30 +50,6 @@ const Login = () => {
setter(value);
};
const toggleAdvancedSettings = () => {
setShowAdvanced(!showAdvanced);
// Rotate the arrow
Animated.timing(rotateAnim, {
toValue: showAdvanced ? 0 : 1,
duration: 200,
useNativeDriver: true,
}).start();
// Animate the height of the advanced settings
const targetHeight = showAdvanced ? 0 : 150; // You can adjust this height
Animated.timing(advancedHeightAnim, {
toValue: targetHeight,
duration: 300,
useNativeDriver: false,
}).start();
};
const arrowRotation = rotateAnim.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '90deg'],
});
const styles = StyleSheet.create({
container: {
flex: 1,
@@ -98,32 +63,11 @@ const Login = () => {
section: {
marginBottom: 40,
},
switchContainer: {
marginTop: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
activityindicator: {
position: 'absolute',
width: '100%',
height: '100%',
},
arrowContainer: {
display: 'flex',
justifyContent: 'center',
marginTop: 20,
flexDirection: 'row',
alignItems: 'center',
},
advancedButtonText: {
marginLeft: 8,
fontSize: 16,
color: colors.text,
},
advancedSection: {
overflow: 'hidden',
},
logo: {
width: 100,
height: 100,
@@ -141,7 +85,37 @@ const Login = () => {
<View style={[styles.section, styles.logoContainer]}>
<Image style={styles.logo} source={require('../assets/favicon.png')} />
</View>
<ServerSettings />
<View style={styles.section}>
<ThemeText style={styles.label}>Benutzername</ThemeText>
<ThemeTextInput
value={username}
onValueChange={handleChange(setUsername)}
placeholder="Benutzername"
disabled={!requireAuth}
/>
<ThemeText style={styles.label}>Passwort</ThemeText>
<ThemeTextInput
value={password}
onValueChange={handleChange(setPassword)}
secureTextEntry
placeholder="Passwort"
disabled={!requireAuth}
/>
</View>
<View style={styles.section}>
<Button title={isSaving ? "" : "Einloggen"} onPress={handleSave} disabled={isSaving} />
{isSaving && <ActivityIndicator size="small" color={colors.primary} style={styles.activityindicator} />}
</View>
<AdvancedSettings
url={url}
requireAuth={requireAuth}
onUrlChange={setUrl}
onRequireAuthChange={setRequireAuth}
/>
<Credits />
</ScrollView>
</ErrorBoundary>

View File

@@ -109,23 +109,8 @@ const Settings = () => {
return (
<ErrorBoundary>
<ScrollView style={[styles.container, { backgroundColor: colors.backPrimary }]}>
<ServerSettings />
<View style={styles.section}>
<ThemeText style={styles.title}>Server</ThemeText>
<ThemeText style={styles.label}>URL</ThemeText>
<ThemeTextInput
value={url}
onValueChange={handleChange(setUrl)}
placeholder="URL"
/>
<View style={styles.switchContainer}>
<ThemeText>Authentifizierung</ThemeText>
<ThemeSwitch
value={requireAuth}
onValueChange={handleChange(setRequireAuth)}
/>
</View>
<ThemeText style={styles.title}>Login</ThemeText>
<ThemeText style={styles.label}>Benutzername</ThemeText>
<ThemeTextInput
value={username}
@@ -162,6 +147,15 @@ const Settings = () => {
</View>
</View>
<View style={styles.section}>
<AdvancedSettings
url={url}
requireAuth={requireAuth}
onUrlChange={setUrl}
onRequireAuthChange={setRequireAuth}
/>
</View>
<View style={styles.section}>
<Button title={isSaving ? "" : "Speichern"} onPress={handleSave} disabled={isSaving} />
{isSaving && <ActivityIndicator size="small" color={colors.primary} style={styles.activityindicator} />}
@@ -176,58 +170,47 @@ const Settings = () => {
export default Settings;
export const ServerSettings = () => {
const colors = useColors();
const { settings, updateSettings } = useContext(SettingsContext);
const [url, setUrl] = useState('');
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [isSystemTheme, setIsSystemTheme] = useState(settings.systemTheme);
const [isDarkMode, setIsDarkMode] = useState(settings.darkTheme);
const [requireAuth, setRequireAuth] = useState(settings.requireAuth);
const [isSaving, setIsSaving] = useState(false);
export const CredentialsInput = ({ username, password, onUsernameChange, onPasswordChange, requireAuth }) => {
const styles = StyleSheet.create({
section: {
marginBottom: 40,
},
label: {
fontWeight: 'bold',
marginTop: 8,
marginBottom: 6,
},
});
return (
<View style={styles.section}>
<ThemeText style={styles.label}>Benutzername</ThemeText>
<ThemeTextInput
value={username}
onValueChange={onUsernameChange}
placeholder="Benutzername"
disabled={!requireAuth}
/>
<ThemeText style={styles.label}>Passwort</ThemeText>
<ThemeTextInput
value={password}
onValueChange={onPasswordChange}
secureTextEntry
placeholder="Passwort"
disabled={!requireAuth}
/>
</View>
);
};
export const AdvancedSettings = ({ url, requireAuth, onUrlChange, onRequireAuthChange }) => {
const [showAdvanced, setShowAdvanced] = useState(false);
const [rotateAnim] = useState(new Animated.Value(0)); // Animation state for the arrow
const [advancedHeightAnim] = useState(new Animated.Value(0)); // Animation state for the advanced settings height
const advancedSectionRef = useRef(null);
useEffect(() => {
if (settings) {
setUrl(settings.url || '');
setUsername(settings.username || '');
setPassword(settings.password || '');
setIsSystemTheme(settings.systemTheme);
setIsDarkMode(settings.darkTheme);
setRequireAuth(settings.requireAuth);
}
}, [settings]);
const handleSave = async () => {
if (isSaving) return;
try {
setIsSaving(true);
await updateSettings({
url,
username,
password,
systemTheme: isSystemTheme,
darkTheme: isDarkMode,
requireAuth,
});
} catch (error) {
console.error('Error updating settings:', error);
Alert.alert('Error', 'Failed to save settings.');
} finally {
setIsSaving(false);
}
};
const handleChange = (setter) => (value) => {
setter(value);
};
const colors = useColors();
const toggleAdvancedSettings = () => {
setShowAdvanced(!showAdvanced);
@@ -254,33 +237,10 @@ export const ServerSettings = () => {
});
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
label: {
fontWeight: 'bold',
marginTop: 8,
marginBottom: 6,
},
section: {
marginBottom: 40,
},
switchContainer: {
marginTop: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
activityindicator: {
position: 'absolute',
width: '100%',
height: '100%',
},
arrowContainer: {
display: 'flex',
justifyContent: 'center',
marginTop: 20,
marginVertical: 20,
flexDirection: 'row',
alignItems: 'center',
},
@@ -292,71 +252,49 @@ export const ServerSettings = () => {
advancedSection: {
overflow: 'hidden',
},
logo: {
width: 100,
height: 100,
label: {
fontWeight: 'bold',
marginTop: 8,
marginBottom: 6,
},
logoContainer: {
marginTop: 10,
display: 'flex',
switchContainer: {
marginTop: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
});
return (
<ErrorBoundary>
<ScrollView style={[styles.container, { backgroundColor: colors.backPrimary }]}>
<View style={styles.section}>
<ThemeText style={styles.label}>Benutzername</ThemeText>
<ThemeTextInput
value={username}
onValueChange={handleChange(setUsername)}
placeholder="Benutzername"
disabled={!requireAuth}
/>
<ThemeText style={styles.label}>Passwort</ThemeText>
<ThemeTextInput
value={password}
onValueChange={handleChange(setPassword)}
secureTextEntry
placeholder="Passwort"
disabled={!requireAuth}
/>
</View>
<View style={styles.section}>
<Button title={isSaving ? "" : "Einloggen"} onPress={handleSave} disabled={isSaving} />
{isSaving && <ActivityIndicator size="small" color={colors.primary} style={styles.activityindicator} />}
</View>
<TouchableOpacity style={styles.arrowContainer} onPress={toggleAdvancedSettings}>
<Animated.View style={{ transform: [{ rotate: arrowRotation }] }}>
<FontAwesome5 name="angle-right" size={24} color={colors.textAccent} />
</Animated.View>
<Text style={styles.advancedButtonText}>
{showAdvanced ? 'Erweiterte Einstellungen verbergen' : 'Erweiterte Einstellungen anzeigen'}
</Text>
</TouchableOpacity>
{/* Animated section for advanced settings */}
<Animated.View style={[styles.advancedSection, { height: advancedHeightAnim }]}>
<View ref={advancedSectionRef}>
<ThemeText style={styles.label}>URL</ThemeText>
<ThemeTextInput
value={url}
onValueChange={handleChange(setUrl)}
placeholder="URL"
/>
<View style={styles.switchContainer}>
<ThemeText>Authentifizierung</ThemeText>
<ThemeSwitch
value={requireAuth}
onValueChange={handleChange(setRequireAuth)}
/>
</View>
</View>
<>
{/* Toggle button */}
<TouchableOpacity style={styles.arrowContainer} onPress={toggleAdvancedSettings}>
<Animated.View style={{ transform: [{ rotate: arrowRotation }] }}>
<FontAwesome5 name="angle-right" size={24} color={colors.textAccent} />
</Animated.View>
</ScrollView>
</ErrorBoundary>
);
};
<Text style={styles.advancedButtonText}>
{showAdvanced ? 'Erweiterte Einstellungen verbergen' : 'Erweiterte Einstellungen anzeigen'}
</Text>
</TouchableOpacity>
{/* Animated section for advanced settings */}
<Animated.View style={[styles.advancedSection, { height: advancedHeightAnim }]}>
<View ref={advancedSectionRef}>
<ThemeText style={styles.label}>URL</ThemeText>
<ThemeTextInput
value={url}
onValueChange={onUrlChange}
placeholder="URL"
/>
<View style={styles.switchContainer}>
<ThemeText>Authentifizierung</ThemeText>
<ThemeSwitch
value={requireAuth}
onValueChange={onRequireAuthChange}
/>
</View>
</View>
</Animated.View>
</>
);
};