theme
parent
dde6178c8f
commit
e455b52085
53
src/App.tsx
53
src/App.tsx
|
@ -1,31 +1,16 @@
|
||||||
import React, {useEffect, Fragment} from 'react';
|
import React, {useEffect} from 'react';
|
||||||
import {NavigationContainer} from '@react-navigation/native';
|
import {NavigationContainer} from '@react-navigation/native';
|
||||||
|
|
||||||
import {Provider, useSelector} from 'react-redux';
|
import {Provider, useSelector} from 'react-redux';
|
||||||
import {RootState, store} from '@redux/store';
|
import {RootState, store} from '@redux/store';
|
||||||
|
|
||||||
import {appStatus} from '@configs/appNonSaveVar';
|
import {appStatus} from '@configs/appNonSaveVar';
|
||||||
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
||||||
import {ThemeMode} from '@configs/colors';
|
import {ThemeMode, ThemeType} from '@configs/colors';
|
||||||
|
|
||||||
import StartHelper from '@pages/appStart/StartHelper';
|
import StartHelper from '@pages/appStart/StartHelper';
|
||||||
|
|
||||||
import {GluestackUIProvider} from '@gluestack-ui/themed';
|
import {GluestackUIProvider} from '@gluestack-ui/themed';
|
||||||
|
import configDarkTheme from '@configs/colors';
|
||||||
import configDarkTheme, {ThemeType} from '@configs/colors';
|
|
||||||
import Navigation from '@navigation/navigation';
|
import Navigation from '@navigation/navigation';
|
||||||
/*
|
import {MyStatusBar} from '@components/MyStatusBar';
|
||||||
function Test() {
|
import {SafeAreaView} from 'react-native';
|
||||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
|
|
||||||
<Text style={{color: '#f00'}}>
|
|
||||||
{lang.account.registration.stepTwo.resendError[401]}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
} */
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -43,29 +28,31 @@ const OtherProviders = () => {
|
||||||
const globalTheme = useSelector(
|
const globalTheme = useSelector(
|
||||||
(state: RootState) => state.appVariables.preferences.theme,
|
(state: RootState) => state.appVariables.preferences.theme,
|
||||||
);
|
);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
const navigationTheme = {
|
const navigationTheme = {
|
||||||
dark: globalTheme !== ThemeMode.Light,
|
dark: globalTheme !== ThemeMode.Light,
|
||||||
colors: {
|
colors: {
|
||||||
primary: '#ff7d4f',
|
// primary: '#ff7d4f',
|
||||||
background: '#222',
|
background: currentTheme.backgroundDark400, // color of deep screen background
|
||||||
card: '#222',
|
//card: '#222',
|
||||||
text: '#fff',
|
text: '#fff', // color of header text
|
||||||
border: '#ff7d4f',
|
//border: '#ff7d4f',
|
||||||
notification: '#fff',
|
//notification: '#fff',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const themeConfig: ThemeType = configDarkTheme;
|
const themeConfig: ThemeType = configDarkTheme;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
appNonSaveVarActions.setThemeColors(themeConfig.tokens.colors);
|
appNonSaveVarActions.setTheme(themeConfig.tokens);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// <NativeBaseProvider theme={theme(globalTheme)}>
|
<NavigationContainer theme={navigationTheme}>
|
||||||
<NavigationContainer theme={navigationTheme} /*linking={linking}*/>
|
<GluestackUIProvider config={configDarkTheme}>
|
||||||
<GluestackUIProvider config={themeConfig}>
|
|
||||||
<MainComponent />
|
<MainComponent />
|
||||||
</GluestackUIProvider>
|
</GluestackUIProvider>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
|
@ -78,11 +65,11 @@ const MainComponent = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<SafeAreaView style={{flex: 1}}>
|
||||||
<StartHelper />
|
<StartHelper />
|
||||||
{/*<StatusBar />*/}
|
<MyStatusBar />
|
||||||
{currentAppStatus === appStatus.APP_RUNNING ? <Navigation /> : null}
|
{currentAppStatus === appStatus.APP_RUNNING ? <Navigation /> : null}
|
||||||
</Fragment>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@ import {
|
||||||
ImageSourcePropType,
|
ImageSourcePropType,
|
||||||
ImageStyle,
|
ImageStyle,
|
||||||
StyleProp,
|
StyleProp,
|
||||||
TouchableOpacity,
|
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import LinearGradient from 'react-native-linear-gradient';
|
import LinearGradient from 'react-native-linear-gradient';
|
||||||
import {MyIcon} from './MyIcon';
|
import {MyIcon} from './MyIcon';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
import {RootState} from '@redux/store';
|
import {RootState} from '@redux/store';
|
||||||
import { Text } from '@gluestack-ui/themed';
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
import {MyTouchableOpacity} from './MyTouchableOpacity';
|
||||||
|
|
||||||
interface MyImageButtonProps {
|
interface MyImageButtonProps {
|
||||||
image: ImageSourcePropType;
|
image: ImageSourcePropType;
|
||||||
|
@ -21,11 +21,11 @@ interface MyImageButtonProps {
|
||||||
|
|
||||||
export function MyImageButton({image, imageStyle, text}: MyImageButtonProps) {
|
export function MyImageButton({image, imageStyle, text}: MyImageButtonProps) {
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<MyTouchableOpacity
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: currentTheme.backgroundDark300,
|
backgroundColor: currentTheme.backgroundDark300,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
@ -35,15 +35,15 @@ export function MyImageButton({image, imageStyle, text}: MyImageButtonProps) {
|
||||||
}}>
|
}}>
|
||||||
<Image source={image} style={imageStyle} />
|
<Image source={image} style={imageStyle} />
|
||||||
<Text
|
<Text
|
||||||
|
bold
|
||||||
|
size="lg"
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
}}>
|
}}>
|
||||||
{text}
|
{text}
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,44 +52,56 @@ interface MyButtonProps {
|
||||||
type: 'primary' | 'secondary';
|
type: 'primary' | 'secondary';
|
||||||
text: string;
|
text: string;
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MyButton({style, type, text, onPress}: MyButtonProps) {
|
export function MyButton({
|
||||||
|
style,
|
||||||
|
type,
|
||||||
|
text,
|
||||||
|
onPress,
|
||||||
|
disabled,
|
||||||
|
}: MyButtonProps) {
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ButtonText = () => (
|
const ButtonText = () => (
|
||||||
<Text style={{color: currentTheme.white, fontSize: 18, fontWeight: 'bold'}}>
|
<Text color={currentTheme.colors.white} bold size="lg">
|
||||||
{text}
|
{text}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<MyTouchableOpacity
|
||||||
style={[
|
style={[
|
||||||
style,
|
style,
|
||||||
{
|
{
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
disabled={disabled}
|
||||||
onPress={onPress}>
|
onPress={onPress}>
|
||||||
{type === 'primary' ? (
|
{type === 'primary' ? (
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
colors={[currentTheme.secondary, currentTheme.primary]}
|
colors={[
|
||||||
|
currentTheme.colors.secondary200,
|
||||||
|
currentTheme.colors.primary400,
|
||||||
|
]}
|
||||||
start={{x: 0, y: 1}}
|
start={{x: 0, y: 1}}
|
||||||
end={{x: 1, y: 0}}
|
end={{x: 1, y: 0}}
|
||||||
style={{
|
style={{
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
|
opacity: disabled ? currentTheme.opacity[60] : 1,
|
||||||
}}>
|
}}>
|
||||||
<ButtonText />
|
<ButtonText />
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
) : (
|
) : (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: currentTheme.backgroundDark200,
|
backgroundColor: currentTheme.colors.backgroundDark200,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
|
@ -97,7 +109,7 @@ export function MyButton({style, type, text, onPress}: MyButtonProps) {
|
||||||
<ButtonText />
|
<ButtonText />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,12 +124,12 @@ interface MyIconButtonProps {
|
||||||
|
|
||||||
export function MyIconButton({onPress, MyIconProps}: MyIconButtonProps) {
|
export function MyIconButton({onPress, MyIconProps}: MyIconButtonProps) {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={onPress}>
|
<MyTouchableOpacity onPress={onPress}>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
name={MyIconProps.name}
|
name={MyIconProps.name}
|
||||||
size={MyIconProps.size}
|
size={MyIconProps.size}
|
||||||
color={MyIconProps.color}
|
color={MyIconProps.color}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import { Text } from '@gluestack-ui/themed';
|
import { Text } from '@gluestack-ui/themed';
|
||||||
import {StyleProp, TextStyle} from 'react-native';
|
import {StyleProp, TextStyle} from 'react-native';
|
||||||
import {TouchableOpacity} from 'react-native';
|
import { MyTouchableOpacity } from './MyTouchableOpacity';
|
||||||
|
|
||||||
interface MyClickableTextProps {
|
interface MyClickableTextProps {
|
||||||
textStyle?: StyleProp<TextStyle>;
|
textStyle?: StyleProp<TextStyle>;
|
||||||
text: string;
|
text: string;
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
|
color?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MyClickableText({textStyle, text, onPress}: MyClickableTextProps) {
|
export function MyClickableText({textStyle, text, onPress, color}: MyClickableTextProps) {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={onPress}>
|
<MyTouchableOpacity onPress={onPress}>
|
||||||
<Text style={textStyle}>{text}</Text>
|
<Text color={color} style={textStyle}>{text}</Text>
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
export function MyDivider() {
|
export function MyDivider() {
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -25,7 +25,7 @@ interface MyDividerWithTextProps {
|
||||||
|
|
||||||
export function MyDividerWithText({text}: MyDividerWithTextProps) {
|
export function MyDividerWithText({text}: MyDividerWithTextProps) {
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -41,7 +41,7 @@ export function MyDividerWithText({text}: MyDividerWithTextProps) {
|
||||||
|
|
||||||
export function MyVerticalDivider() {
|
export function MyVerticalDivider() {
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -2,7 +2,8 @@ import {KeyboardTypeOptions, TextInput, View} from 'react-native';
|
||||||
import {MyIcon} from './MyIcon';
|
import {MyIcon} from './MyIcon';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
import {RootState} from '@redux/store';
|
import {RootState} from '@redux/store';
|
||||||
import { Text } from '@gluestack-ui/themed';
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
import {useRef, useState} from 'react';
|
||||||
|
|
||||||
interface MyIconInputProps {
|
interface MyIconInputProps {
|
||||||
text: string;
|
text: string;
|
||||||
|
@ -24,7 +25,7 @@ export function MyIconInput({
|
||||||
disableContainer,
|
disableContainer,
|
||||||
}: MyIconInputProps) {
|
}: MyIconInputProps) {
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -40,11 +41,11 @@ export function MyIconInput({
|
||||||
},
|
},
|
||||||
]}>
|
]}>
|
||||||
<View style={{marginLeft: 12}}>
|
<View style={{marginLeft: 12}}>
|
||||||
<MyIcon name={iconName} size={32} />
|
<MyIcon name={iconName} size={30} />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={{flex: 1, margin: 12, gap: 2}}>
|
<View style={{flex: 1, margin: 12, gap: 2}}>
|
||||||
<Text>{text}</Text>
|
<Text size='sm' color={currentTheme.textLight200}>{text}</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: currentTheme.backgroundDark400,
|
backgroundColor: currentTheme.backgroundDark400,
|
||||||
|
@ -61,3 +62,65 @@ export function MyIconInput({
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ConfirmationCodeInputProps {}
|
||||||
|
|
||||||
|
export const ConfirmationCodeInput: React.FC<
|
||||||
|
ConfirmationCodeInputProps
|
||||||
|
> = () => {
|
||||||
|
const [confirmationCode, setConfirmationCode] = useState([
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
]);
|
||||||
|
const inputRefs = useRef<TextInput[]>([]);
|
||||||
|
|
||||||
|
const focusInput = (index: number) => {
|
||||||
|
if (inputRefs.current[index]) {
|
||||||
|
inputRefs.current[index].focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTextChange = (text: string, index: number) => {
|
||||||
|
const newConfirmationCode = [...confirmationCode];
|
||||||
|
newConfirmationCode[index] = text;
|
||||||
|
|
||||||
|
// Fokus zum nächsten Input verschieben, wenn der aktuelle Input nicht leer ist
|
||||||
|
if (text !== '' && index < confirmationCode.length - 1) {
|
||||||
|
focusInput(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfirmationCode(newConfirmationCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}>
|
||||||
|
{confirmationCode.map((digit, index) => (
|
||||||
|
<TextInput
|
||||||
|
key={index}
|
||||||
|
ref={ref => (inputRefs.current[index] = ref!)}
|
||||||
|
style={{
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
borderColor: 'gray',
|
||||||
|
borderWidth: 1,
|
||||||
|
textAlign: 'center',
|
||||||
|
margin: 5,
|
||||||
|
borderRadius: 5,
|
||||||
|
}}
|
||||||
|
keyboardType="number-pad"
|
||||||
|
maxLength={1}
|
||||||
|
onChangeText={text => handleTextChange(text, index)}
|
||||||
|
value={digit}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function MyScreenContainer({
|
||||||
scrollView,
|
scrollView,
|
||||||
}: MyScreenContainerProps) {
|
}: MyScreenContainerProps) {
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
const containerStyle = {
|
const containerStyle = {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import {ThemeMode} from '@configs/colors';
|
||||||
|
import {RootState} from '@redux/store';
|
||||||
|
import { StatusBar } from 'react-native';
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
|
export function MyStatusBar() {
|
||||||
|
const globalTheme = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.theme,
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StatusBar
|
||||||
|
backgroundColor={currentTheme.backgroundDark400}
|
||||||
|
barStyle={
|
||||||
|
globalTheme === ThemeMode.Light ? 'dark-content' : 'light-content'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,15 +1,21 @@
|
||||||
import { Text } from "@gluestack-ui/themed";
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
|
||||||
export function MyTitle({text}: {text: string}) {
|
interface MyTitleProps {
|
||||||
return (
|
text: string;
|
||||||
<Text
|
textAlign?: 'left' | 'center' | 'right';
|
||||||
style={{
|
paddingBottom?: number;
|
||||||
fontSize: 24,
|
}
|
||||||
fontWeight: 'bold',
|
|
||||||
textAlign: 'center',
|
export function MyTitle({text, textAlign, paddingBottom}: MyTitleProps) {
|
||||||
padding: 20,
|
return (
|
||||||
}}>
|
<Text
|
||||||
{text}
|
size="2xl"
|
||||||
</Text>
|
bold
|
||||||
);
|
style={{
|
||||||
}
|
textAlign: textAlign ?? 'center',
|
||||||
|
paddingBottom: paddingBottom ?? 20,
|
||||||
|
}}>
|
||||||
|
{text}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import {RootState} from '@redux/store';
|
||||||
|
import {ReactNode} from 'react';
|
||||||
|
import {
|
||||||
|
AccessibilityRole,
|
||||||
|
GestureResponderEvent,
|
||||||
|
StyleProp,
|
||||||
|
TouchableOpacity,
|
||||||
|
ViewStyle,
|
||||||
|
} from 'react-native';
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
|
interface CustomTouchableProps {
|
||||||
|
children?: ReactNode;
|
||||||
|
onPress?: () => void;
|
||||||
|
onLongPress?: ((event: GestureResponderEvent) => void) | undefined;
|
||||||
|
style?: StyleProp<ViewStyle>;
|
||||||
|
disabled?: boolean;
|
||||||
|
accessibilityRole?: AccessibilityRole | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MyTouchableOpacity({
|
||||||
|
children,
|
||||||
|
onPress,
|
||||||
|
onLongPress,
|
||||||
|
style,
|
||||||
|
disabled,
|
||||||
|
accessibilityRole,
|
||||||
|
}: CustomTouchableProps) {
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.opacity,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
disabled={disabled}
|
||||||
|
onPress={onPress}
|
||||||
|
onLongPress={onLongPress}
|
||||||
|
style={style}
|
||||||
|
activeOpacity={currentTheme[80]}
|
||||||
|
accessibilityRole={accessibilityRole}>
|
||||||
|
{children}
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
//these variables should not changed by the user and will not be saved in storage
|
//these variables should not changed by the user and will not be saved in storage
|
||||||
|
|
||||||
import {getVersionByNum, VersionType} from '@helper/version';
|
import {getVersionByNum, VersionType} from '@helper/version';
|
||||||
import configDarkTheme, {ThemeColorsType} from '@configs/colors';
|
import configDarkTheme, {ThemeTokensType} from '@configs/colors';
|
||||||
|
|
||||||
export const APP_VERSION = getVersionByNum(1);
|
export const APP_VERSION = getVersionByNum(1);
|
||||||
export const AppVarMaxBackups: number = 10;
|
export const AppVarMaxBackups: number = 10;
|
||||||
|
@ -22,12 +22,12 @@ export interface NON_SAVE_VARS {
|
||||||
currentAppVersion: VersionType;
|
currentAppVersion: VersionType;
|
||||||
appStatus: appStatus;
|
appStatus: appStatus;
|
||||||
connectionStatus: connectionStatus;
|
connectionStatus: connectionStatus;
|
||||||
themeColors: ThemeColorsType;
|
theme: ThemeTokensType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const non_save_vars: NON_SAVE_VARS = {
|
export const non_save_vars: NON_SAVE_VARS = {
|
||||||
currentAppVersion: APP_VERSION,
|
currentAppVersion: APP_VERSION,
|
||||||
appStatus: appStatus.IS_LOADING,
|
appStatus: appStatus.IS_LOADING,
|
||||||
connectionStatus: connectionStatus.UNKNOWN,
|
connectionStatus: connectionStatus.UNKNOWN,
|
||||||
themeColors: configDarkTheme.tokens.colors,
|
theme: configDarkTheme.tokens,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type {PayloadAction} from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import {appStatus, non_save_vars} from './appNonSaveVar';
|
import {appStatus, non_save_vars} from './appNonSaveVar';
|
||||||
|
|
||||||
import {ThemeColorsType} from '@configs/colors';
|
import {ThemeTokensType} from '@configs/colors';
|
||||||
|
|
||||||
export const appNonSaveVariablesSlice = createSlice({
|
export const appNonSaveVariablesSlice = createSlice({
|
||||||
name: 'non_save_vars',
|
name: 'non_save_vars',
|
||||||
|
@ -12,8 +12,8 @@ export const appNonSaveVariablesSlice = createSlice({
|
||||||
setAppStatus: (state, action: PayloadAction<appStatus>) => {
|
setAppStatus: (state, action: PayloadAction<appStatus>) => {
|
||||||
state.appStatus = action.payload;
|
state.appStatus = action.payload;
|
||||||
},
|
},
|
||||||
setThemeColors: (state, action: PayloadAction<ThemeColorsType>) => {
|
setTheme: (state, action: PayloadAction<ThemeTokensType>) => {
|
||||||
state.themeColors = action.payload;
|
state.theme = action.payload;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import {config} from '@configs/gluestack-ui.config'; // default dark theme
|
import {config} from '@configs/gluestack-ui.config'; // default dark theme
|
||||||
|
|
||||||
type ThemeType = typeof config;
|
type ThemeType = typeof config;
|
||||||
type ThemeColorsType = typeof config.tokens.colors;
|
type ThemeTokensType = typeof config.tokens;
|
||||||
|
|
||||||
export type {ThemeType, ThemeColorsType};
|
export type {ThemeType, ThemeTokensType};
|
||||||
export default config;
|
export default config;
|
||||||
|
|
||||||
export enum ThemeMode {
|
export enum ThemeMode {
|
||||||
|
|
|
@ -311,7 +311,16 @@ export const gluestackUIConfig = createConfig({
|
||||||
light700: '#44403c',
|
light700: '#44403c',
|
||||||
light800: '#292524',
|
light800: '#292524',
|
||||||
light900: '#1c1917',
|
light900: '#1c1917',
|
||||||
primary: '#6030da',
|
primary50: '#b9a0f8',
|
||||||
|
primary100: '#a283f2',
|
||||||
|
primary200: '#8c67ea',
|
||||||
|
primary300: '#774de0',
|
||||||
|
primary400: '#6030da', // primary
|
||||||
|
primary500: '#582bc9',
|
||||||
|
primary600: '#532db1',
|
||||||
|
primary700: '#4d2f9b',
|
||||||
|
primary800: '#472f86',
|
||||||
|
primary900: '#412d72',
|
||||||
/*
|
/*
|
||||||
primary0: '#E5F1FB',
|
primary0: '#E5F1FB',
|
||||||
primary50: '#CCE9FF',
|
primary50: '#CCE9FF',
|
||||||
|
@ -337,10 +346,19 @@ export const gluestackUIConfig = createConfig({
|
||||||
secondary800: '#262626',
|
secondary800: '#262626',
|
||||||
secondary900: '#171717',
|
secondary900: '#171717',
|
||||||
secondary950: '#0C0C0C', */
|
secondary950: '#0C0C0C', */
|
||||||
secondary: '#931278',
|
secondary50: '#f939d0',
|
||||||
|
secondary100: '#f21dc4',
|
||||||
|
secondary200: '#d713ad',
|
||||||
|
secondary300: '#b1168f',
|
||||||
|
secondary400: '#931278', // secondary
|
||||||
|
secondary500: '#7b1364',
|
||||||
|
secondary600: '#651453',
|
||||||
|
secondary700: '#511343',
|
||||||
|
secondary800: '#3d1134',
|
||||||
|
secondary900: '#2b0e25',
|
||||||
textLight0: '#FCFCFC',
|
textLight0: '#FCFCFC',
|
||||||
textLight50: '#F5F5F5',
|
textLight50: '#F5F5F5',
|
||||||
textLight100: '#E5E5E5',
|
textLight100: '#E5E5E5', // secondary text
|
||||||
textLight200: '#DBDBDB',
|
textLight200: '#DBDBDB',
|
||||||
textLight300: '#D4D4D4',
|
textLight300: '#D4D4D4',
|
||||||
textLight400: '#A3A3A3',
|
textLight400: '#A3A3A3',
|
||||||
|
|
|
@ -13,7 +13,7 @@ import ProfileTab, {
|
||||||
ProfileStackNavigatorParamList,
|
ProfileStackNavigatorParamList,
|
||||||
} from './tabs/main/ProfileTab';
|
} from './tabs/main/ProfileTab';
|
||||||
import {FadeInView} from '@helper/animations';
|
import {FadeInView} from '@helper/animations';
|
||||||
import {TouchableOpacity, View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
import LinearGradient from 'react-native-linear-gradient';
|
import LinearGradient from 'react-native-linear-gradient';
|
||||||
import {
|
import {
|
||||||
RegistrationScreenAnim,
|
RegistrationScreenAnim,
|
||||||
|
@ -23,7 +23,8 @@ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||||
import {MyIcon} from '@components/MyIcon';
|
import {MyIcon} from '@components/MyIcon';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
import {RootState, store as reduxStore} from '@redux/store';
|
import {RootState, store as reduxStore} from '@redux/store';
|
||||||
import { Text } from '@gluestack-ui/themed';
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
import {MyTouchableOpacity} from '@components/MyTouchableOpacity';
|
||||||
|
|
||||||
export type RootStackNavigatorParamList = {
|
export type RootStackNavigatorParamList = {
|
||||||
Home: NavigatorScreenParams<HomeStackNavigatorParamList>;
|
Home: NavigatorScreenParams<HomeStackNavigatorParamList>;
|
||||||
|
@ -98,7 +99,7 @@ function CustomTabBar(props: BottomTabBarProps) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.themeColors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
const tabNames = [
|
const tabNames = [
|
||||||
|
@ -139,13 +140,12 @@ function CustomTabBar(props: BottomTabBarProps) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: retrieve colors from theme
|
|
||||||
const gradientColors = isFocused
|
const gradientColors = isFocused
|
||||||
? [currentTheme.secondary, currentTheme.primary]
|
? [currentTheme.secondary200, currentTheme.primary400]
|
||||||
: [currentTheme.backgroundDark300, currentTheme.backgroundDark300];
|
: [currentTheme.backgroundDark300, currentTheme.backgroundDark300];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<MyTouchableOpacity
|
||||||
key={route.key}
|
key={route.key}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
@ -170,14 +170,14 @@ function CustomTabBar(props: BottomTabBarProps) {
|
||||||
}}>
|
}}>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
name={tabBarIcons[index]}
|
name={tabBarIcons[index]}
|
||||||
color={isFocused ? currentTheme.white : '#ccc'}
|
color={
|
||||||
|
isFocused ? currentTheme.white : currentTheme.textLight100
|
||||||
|
}
|
||||||
size={20}
|
size={20}
|
||||||
/>
|
/>
|
||||||
{isFocused && (
|
{isFocused && <Text>{tabNames[index]}</Text>}
|
||||||
<Text>{tabNames[index]}</Text>
|
|
||||||
)}
|
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -6,13 +6,7 @@ import {
|
||||||
createNativeStackNavigator,
|
createNativeStackNavigator,
|
||||||
NativeStackNavigationOptions,
|
NativeStackNavigationOptions,
|
||||||
} from '@react-navigation/native-stack';
|
} from '@react-navigation/native-stack';
|
||||||
import {
|
import {Image, View} from 'react-native';
|
||||||
Image,
|
|
||||||
ScrollView,
|
|
||||||
StyleSheet,
|
|
||||||
TextInput,
|
|
||||||
View,
|
|
||||||
} from 'react-native';
|
|
||||||
|
|
||||||
import GoogleLogo from '@assets/google-logo.png';
|
import GoogleLogo from '@assets/google-logo.png';
|
||||||
import AppleLogo from '@assets/apple-logo.png';
|
import AppleLogo from '@assets/apple-logo.png';
|
||||||
|
@ -23,13 +17,18 @@ import {MyButton, MyImageButton} from '@components/MyButton';
|
||||||
import {MyClickableText} from '@components/MyClickableText';
|
import {MyClickableText} from '@components/MyClickableText';
|
||||||
import {OpenURL} from '@helper/linking';
|
import {OpenURL} from '@helper/linking';
|
||||||
import {Constants} from '@utils/utils';
|
import {Constants} from '@utils/utils';
|
||||||
import {MyIconInput} from '@components/MyInput';
|
|
||||||
import {useRef, useState} from 'react';
|
|
||||||
import {KeyboardAvoidingView} from 'react-native';
|
|
||||||
import {MyTitle} from '@components/MyTitle';
|
import {MyTitle} from '@components/MyTitle';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
import {RootState} from '@redux/store';
|
import {RootState} from '@redux/store';
|
||||||
import { Text } from '@gluestack-ui/themed';
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
import {Login} from '@pages/welcome/login/login';
|
||||||
|
import {
|
||||||
|
SignUpStepAccountName,
|
||||||
|
SignUpStepPassword,
|
||||||
|
SignUpStepPhoneNumber,
|
||||||
|
SignUpStepUsername,
|
||||||
|
SignUpStepVerifyPhoneNumber,
|
||||||
|
} from '@pages/welcome/signUp/signUp';
|
||||||
|
|
||||||
export type RegistrationStackNavigatorParamList = {
|
export type RegistrationStackNavigatorParamList = {
|
||||||
SignUpPreview: undefined;
|
SignUpPreview: undefined;
|
||||||
|
@ -53,14 +52,18 @@ export function RegistrationScreenAnim(props: any) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerStyle: NativeStackNavigationOptions = {
|
|
||||||
headerShown: true,
|
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
|
||||||
headerTitleAlign: 'center',
|
|
||||||
headerTitle: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
export function RegistrationScreen() {
|
export function RegistrationScreen() {
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
|
const headerStyle: NativeStackNavigationOptions = {
|
||||||
|
headerShown: true,
|
||||||
|
headerStyle: {backgroundColor: currentTheme.backgroundDark400},
|
||||||
|
headerTitleAlign: 'center',
|
||||||
|
headerTitle: '',
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RegistrationStack.Navigator screenOptions={{headerShown: false}}>
|
<RegistrationStack.Navigator screenOptions={{headerShown: false}}>
|
||||||
<RegistrationStack.Screen
|
<RegistrationStack.Screen
|
||||||
|
@ -71,11 +74,7 @@ export function RegistrationScreen() {
|
||||||
<RegistrationStack.Screen
|
<RegistrationStack.Screen
|
||||||
name="Login"
|
name="Login"
|
||||||
component={Login}
|
component={Login}
|
||||||
options={{
|
options={{...headerStyle}}
|
||||||
headerShown: true,
|
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
|
||||||
headerTitleAlign: 'center',
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<RegistrationStack.Screen
|
<RegistrationStack.Screen
|
||||||
name="SignUpStepUsername"
|
name="SignUpStepUsername"
|
||||||
|
@ -140,6 +139,9 @@ function RegistrationPreview({type}: {type: 'login' | 'signup'}) {
|
||||||
const lang = useSelector(
|
const lang = useSelector(
|
||||||
(state: RootState) => state.appVariables.lang.registration,
|
(state: RootState) => state.appVariables.lang.registration,
|
||||||
);
|
);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -188,25 +190,31 @@ function RegistrationPreview({type}: {type: 'login' | 'signup'}) {
|
||||||
|
|
||||||
{type === 'signup' && (
|
{type === 'signup' && (
|
||||||
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
|
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
|
||||||
<Text>{`${lang.previewSignup.agreeToTerms} `}</Text>
|
<Text
|
||||||
|
color={
|
||||||
|
currentTheme.textLight100
|
||||||
|
}>{`${lang.previewSignup.agreeToTerms} `}</Text>
|
||||||
<MyClickableText
|
<MyClickableText
|
||||||
text={lang.previewSignup.terms}
|
text={lang.previewSignup.terms}
|
||||||
textStyle={{color: '#6030da'}}
|
textStyle={{color: currentTheme.primary300}}
|
||||||
onPress={() => OpenURL(Constants.REGISTRATION.TERMS_URL)}
|
onPress={() => OpenURL(Constants.REGISTRATION.TERMS_URL)}
|
||||||
/>
|
/>
|
||||||
<Text>, </Text>
|
<Text color={currentTheme.textLight100}>, </Text>
|
||||||
<MyClickableText
|
<MyClickableText
|
||||||
text={lang.previewSignup.privacyPolicy}
|
text={lang.previewSignup.privacyPolicy}
|
||||||
textStyle={{color: '#6030da'}}
|
textStyle={{color: currentTheme.primary300}}
|
||||||
onPress={() => OpenURL(Constants.REGISTRATION.PRIVACY_POLICY_URL)}
|
onPress={() => OpenURL(Constants.REGISTRATION.PRIVACY_POLICY_URL)}
|
||||||
/>
|
/>
|
||||||
<Text>{` ${lang.previewSignup.agreeToTermsAnd} `}</Text>
|
<Text
|
||||||
|
color={
|
||||||
|
currentTheme.textLight100
|
||||||
|
}>{` ${lang.previewSignup.agreeToTermsAnd} `}</Text>
|
||||||
<MyClickableText
|
<MyClickableText
|
||||||
text={lang.previewSignup.cookieUse}
|
text={lang.previewSignup.cookieUse}
|
||||||
textStyle={{color: '#6030da'}}
|
textStyle={{color: currentTheme.primary300}}
|
||||||
onPress={() => OpenURL(Constants.REGISTRATION.COOKIE_USE_URL)}
|
onPress={() => OpenURL(Constants.REGISTRATION.COOKIE_USE_URL)}
|
||||||
/>
|
/>
|
||||||
<Text>.</Text>
|
<Text color={currentTheme.textLight100}>.</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -214,12 +222,18 @@ function RegistrationPreview({type}: {type: 'login' | 'signup'}) {
|
||||||
{type === 'login' ? (
|
{type === 'login' ? (
|
||||||
<Text>{lang.previewLogin.dontHaveAccount}</Text>
|
<Text>{lang.previewLogin.dontHaveAccount}</Text>
|
||||||
) : (
|
) : (
|
||||||
<Text>{lang.previewSignup.alreadyHaveAccount}</Text>
|
<Text color={currentTheme.textLight100}>
|
||||||
|
{lang.previewSignup.alreadyHaveAccount}
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<MyClickableText
|
<MyClickableText
|
||||||
text={type === 'login' ? lang.buttonSignUp : lang.buttonLogin}
|
text={type === 'login' ? lang.buttonSignUp : lang.buttonLogin}
|
||||||
textStyle={{left: 2, color: '#931278', fontWeight: 'bold'}}
|
textStyle={{
|
||||||
|
left: 2,
|
||||||
|
color: currentTheme.secondary300,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigation.navigate(
|
navigation.navigate(
|
||||||
'Registration',
|
'Registration',
|
||||||
|
@ -235,7 +249,7 @@ function RegistrationPreview({type}: {type: 'login' | 'signup'}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ContentContainer({children}: {children: React.ReactNode}) {
|
export function ContentContainer({children}: {children: React.ReactNode}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View style={{flex: 1}} />
|
<View style={{flex: 1}} />
|
||||||
|
@ -244,297 +258,10 @@ function ContentContainer({children}: {children: React.ReactNode}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Login() {
|
export function navigateToHome(navigation: RootScreenNavigationProp) {
|
||||||
const lang = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.lang.registration,
|
|
||||||
);
|
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyScreenContainer
|
|
||||||
style={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
<ContentContainer>
|
|
||||||
<MyTitle text={lang.login.title} />
|
|
||||||
|
|
||||||
<View style={{gap: 12}}>
|
|
||||||
<MyIconInput
|
|
||||||
text={lang.login.inputPhoneNumberOrAccountName}
|
|
||||||
iconName="person"
|
|
||||||
/>
|
|
||||||
<MyIconInput
|
|
||||||
text={lang.login.inputPassword}
|
|
||||||
iconName="lock"
|
|
||||||
secureTextEntry
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MyButton
|
|
||||||
type="secondary"
|
|
||||||
text={lang.buttonLogin}
|
|
||||||
style={{marginBottom: 20}}
|
|
||||||
onPress={() => navigateToHome(navigation)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ContentContainer>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SignUpStepUsername() {
|
|
||||||
const lang = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.lang.registration,
|
|
||||||
);
|
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyScreenContainer
|
|
||||||
style={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
<ContentContainer>
|
|
||||||
<MyTitle text={lang.signUpStepUsername.title} />
|
|
||||||
<Text>{lang.signUpStepUsername.description}</Text>
|
|
||||||
|
|
||||||
<View style={{gap: 12, marginTop: 20}}>
|
|
||||||
<MyIconInput
|
|
||||||
text={lang.signUpStepUsername.inputUsername}
|
|
||||||
iconName="person"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MyButton
|
|
||||||
type="secondary"
|
|
||||||
text={lang.buttonNext}
|
|
||||||
style={{marginBottom: 20}}
|
|
||||||
onPress={() => {
|
|
||||||
navigation.navigate('Registration', {
|
|
||||||
screen: 'SignUpStepPhoneNumber',
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ContentContainer>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SignUpStepPhoneNumber() {
|
|
||||||
const lang = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.lang.registration,
|
|
||||||
);
|
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyScreenContainer
|
|
||||||
style={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
<ContentContainer>
|
|
||||||
<MyTitle text={lang.signUpStepPhoneNumber.title} />
|
|
||||||
|
|
||||||
<View style={{gap: 12, marginTop: 20}}>
|
|
||||||
<MyIconInput
|
|
||||||
text={lang.signUpStepPhoneNumber.inputPhoneNumber}
|
|
||||||
iconName="phone-iphone"
|
|
||||||
keyboardType="phone-pad"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MyButton
|
|
||||||
type="secondary"
|
|
||||||
text={lang.buttonNext}
|
|
||||||
style={{marginBottom: 20}}
|
|
||||||
onPress={() => {
|
|
||||||
navigation.navigate('Registration', {
|
|
||||||
screen: 'SignUpStepVerifyPhoneNumber',
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ContentContainer>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ConfirmationCodeInputProps {}
|
|
||||||
|
|
||||||
const ConfirmationCodeInput: React.FC<ConfirmationCodeInputProps> = () => {
|
|
||||||
const [confirmationCode, setConfirmationCode] = useState([
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
]);
|
|
||||||
const inputRefs = useRef<TextInput[]>([]);
|
|
||||||
|
|
||||||
const focusInput = (index: number) => {
|
|
||||||
if (inputRefs.current[index]) {
|
|
||||||
inputRefs.current[index].focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTextChange = (text: string, index: number) => {
|
|
||||||
const newConfirmationCode = [...confirmationCode];
|
|
||||||
newConfirmationCode[index] = text;
|
|
||||||
|
|
||||||
// Fokus zum nächsten Input verschieben, wenn der aktuelle Input nicht leer ist
|
|
||||||
if (text !== '' && index < confirmationCode.length - 1) {
|
|
||||||
focusInput(index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
setConfirmationCode(newConfirmationCode);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={styles.container}>
|
|
||||||
{confirmationCode.map((digit, index) => (
|
|
||||||
<TextInput
|
|
||||||
key={index}
|
|
||||||
ref={ref => (inputRefs.current[index] = ref!)}
|
|
||||||
style={styles.input}
|
|
||||||
keyboardType="number-pad"
|
|
||||||
maxLength={1}
|
|
||||||
onChangeText={text => handleTextChange(text, index)}
|
|
||||||
value={digit}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
input: {
|
|
||||||
height: 40,
|
|
||||||
width: 40,
|
|
||||||
borderColor: 'gray',
|
|
||||||
borderWidth: 1,
|
|
||||||
textAlign: 'center',
|
|
||||||
margin: 5,
|
|
||||||
borderRadius: 5,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function SignUpStepVerifyPhoneNumber() {
|
|
||||||
const lang = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.lang.registration,
|
|
||||||
);
|
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyScreenContainer
|
|
||||||
style={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
<ContentContainer>
|
|
||||||
<MyTitle text={lang.signUpStepVerifyPhoneNumber.title} />
|
|
||||||
<Text>{`${lang.signUpStepVerifyPhoneNumber.description} +49 15** ******43`}</Text>
|
|
||||||
|
|
||||||
<KeyboardAvoidingView style={{gap: 12, marginTop: 20}}>
|
|
||||||
<ConfirmationCodeInput />
|
|
||||||
|
|
||||||
<MyButton
|
|
||||||
type="secondary"
|
|
||||||
text={lang.buttonNext}
|
|
||||||
style={{marginBottom: 2}}
|
|
||||||
onPress={() => {
|
|
||||||
navigation.navigate('Registration', {
|
|
||||||
screen: 'SignUpStepPassword',
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<View style={{alignItems: 'center'}}>
|
|
||||||
<MyClickableText
|
|
||||||
text={lang.signUpStepVerifyPhoneNumber.clickableTextResendCode}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
</ContentContainer>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SignUpStepPassword() {
|
|
||||||
const lang = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.lang.registration,
|
|
||||||
);
|
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyScreenContainer
|
|
||||||
style={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
<ContentContainer>
|
|
||||||
<MyTitle text={lang.signUpStepPassword.title} />
|
|
||||||
<Text>{lang.signUpStepPassword.description}</Text>
|
|
||||||
|
|
||||||
<View style={{gap: 12, marginTop: 20}}>
|
|
||||||
<MyIconInput
|
|
||||||
text={lang.signUpStepPassword.inputPassword}
|
|
||||||
iconName="lock"
|
|
||||||
secureTextEntry
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MyButton
|
|
||||||
type="secondary"
|
|
||||||
text={lang.buttonNext}
|
|
||||||
style={{marginBottom: 2}}
|
|
||||||
onPress={() =>
|
|
||||||
navigation.navigate('Registration', {
|
|
||||||
screen: 'SignUpStepAccountName',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ContentContainer>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateToHome(navigation: RootScreenNavigationProp) {
|
|
||||||
navigation.navigate('Home', {screen: 'Map', params: {screen: 'Overview'}});
|
navigation.navigate('Home', {screen: 'Map', params: {screen: 'Overview'}});
|
||||||
navigation.reset({
|
navigation.reset({
|
||||||
index: 0,
|
index: 0,
|
||||||
routes: [{name: 'Home'}],
|
routes: [{name: 'Home'}],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function SignUpStepAccountName() {
|
|
||||||
const lang = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.lang.registration,
|
|
||||||
);
|
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyScreenContainer
|
|
||||||
style={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
<ScrollView>
|
|
||||||
<ContentContainer>
|
|
||||||
<MyTitle text={lang.signUpStepAccountName.title} />
|
|
||||||
<Text>{lang.signUpStepAccountName.description}</Text>
|
|
||||||
|
|
||||||
<View style={{gap: 12, marginTop: 20}}>
|
|
||||||
<MyIconInput
|
|
||||||
text={lang.signUpStepAccountName.inputAccountName}
|
|
||||||
iconName="person"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MyButton
|
|
||||||
type="primary"
|
|
||||||
text={lang.signUpStepAccountName.buttonGetStarted}
|
|
||||||
style={{marginBottom: 2}}
|
|
||||||
onPress={() => navigateToHome(navigation)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ContentContainer>
|
|
||||||
</ScrollView>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { MyScreenContainer } from '@components/MyScreenContainer';
|
import { MyScreenContainer } from '@components/MyScreenContainer';
|
||||||
|
import { Text } from '@gluestack-ui/themed';
|
||||||
import {
|
import {
|
||||||
createNativeStackNavigator,
|
createNativeStackNavigator,
|
||||||
NativeStackNavigationProp,
|
NativeStackNavigationProp,
|
||||||
} from '@react-navigation/native-stack';
|
} from '@react-navigation/native-stack';
|
||||||
import {RootState} from '@redux/store';
|
import {RootState} from '@redux/store';
|
||||||
import {Text} from 'react-native';
|
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
export const CalendarTabName = 'Calendar';
|
export const CalendarTabName = 'Calendar';
|
||||||
|
@ -21,6 +21,13 @@ export type CalendarScreenNavigationProp =
|
||||||
|
|
||||||
function CalendarTab() {
|
function CalendarTab() {
|
||||||
const lang = useSelector((state: RootState) => state.appVariables.lang.navigation.home.calendar);
|
const lang = useSelector((state: RootState) => state.appVariables.lang.navigation.home.calendar);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
|
const headerStyle = {
|
||||||
|
backgroundColor: currentTheme.backgroundDark400,
|
||||||
|
};
|
||||||
|
|
||||||
//const navigation = useNavigation<CalendarScreenNavigationProp>();
|
//const navigation = useNavigation<CalendarScreenNavigationProp>();
|
||||||
|
|
||||||
|
@ -31,6 +38,8 @@ function CalendarTab() {
|
||||||
options={{
|
options={{
|
||||||
title: lang.tabName,
|
title: lang.tabName,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
|
headerShadowVisible: false,
|
||||||
|
headerStyle: headerStyle,
|
||||||
}}
|
}}
|
||||||
component={CalendarScreen}
|
component={CalendarScreen}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -23,6 +23,13 @@ function ChatsTab() {
|
||||||
const lang = useSelector(
|
const lang = useSelector(
|
||||||
(state: RootState) => state.appVariables.lang.navigation.home.chats,
|
(state: RootState) => state.appVariables.lang.navigation.home.chats,
|
||||||
);
|
);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
|
const headerStyle = {
|
||||||
|
backgroundColor: currentTheme.backgroundDark400,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChatsStack.Navigator initialRouteName="Overview">
|
<ChatsStack.Navigator initialRouteName="Overview">
|
||||||
|
@ -31,6 +38,8 @@ function ChatsTab() {
|
||||||
options={{
|
options={{
|
||||||
title: lang.tabName,
|
title: lang.tabName,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
|
headerShadowVisible: false,
|
||||||
|
headerStyle: headerStyle,
|
||||||
}}
|
}}
|
||||||
component={ChatsScreen}
|
component={ChatsScreen}
|
||||||
/>
|
/>
|
||||||
|
@ -41,7 +50,7 @@ function ChatsTab() {
|
||||||
function ChatsScreen() {
|
function ChatsScreen() {
|
||||||
return (
|
return (
|
||||||
<MyScreenContainer>
|
<MyScreenContainer>
|
||||||
<Text>Chats</Text>
|
<Text>Part of the next phase</Text>
|
||||||
</MyScreenContainer>
|
</MyScreenContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,13 @@ export type MapScreenNavigationProp =
|
||||||
|
|
||||||
function MapTab() {
|
function MapTab() {
|
||||||
const lang = useSelector((state: RootState) => state.appVariables.lang.navigation.home.map);
|
const lang = useSelector((state: RootState) => state.appVariables.lang.navigation.home.map);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
|
const headerStyle = {
|
||||||
|
backgroundColor: currentTheme.backgroundDark400,
|
||||||
|
};
|
||||||
//const navigation = useNavigation<MapScreenNavigationProp>();
|
//const navigation = useNavigation<MapScreenNavigationProp>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -30,6 +36,8 @@ function MapTab() {
|
||||||
options={{
|
options={{
|
||||||
title: lang.tabName,
|
title: lang.tabName,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
|
headerShadowVisible: false,
|
||||||
|
headerStyle: headerStyle,
|
||||||
}}
|
}}
|
||||||
component={MapScreen}
|
component={MapScreen}
|
||||||
/>
|
/>
|
||||||
|
@ -40,7 +48,7 @@ function MapTab() {
|
||||||
function MapScreen() {
|
function MapScreen() {
|
||||||
return (
|
return (
|
||||||
<MyScreenContainer>
|
<MyScreenContainer>
|
||||||
<Text>Map</Text>
|
<Text>Jan dein Part</Text>
|
||||||
</MyScreenContainer>
|
</MyScreenContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,13 @@ export default function ProfileTab() {
|
||||||
const lang = useSelector(
|
const lang = useSelector(
|
||||||
(state: RootState) => state.appVariables.lang.navigation.home.profile,
|
(state: RootState) => state.appVariables.lang.navigation.home.profile,
|
||||||
);
|
);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
|
const headerStyle = {
|
||||||
|
backgroundColor: currentTheme.backgroundDark400
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProfileStack.Navigator>
|
<ProfileStack.Navigator>
|
||||||
|
@ -48,7 +55,8 @@ export default function ProfileTab() {
|
||||||
animation: 'slide_from_left',
|
animation: 'slide_from_left',
|
||||||
title: lang.overview,
|
title: lang.overview,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
headerStyle: headerStyle,
|
||||||
|
headerShadowVisible: false,
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<MyIconButton
|
<MyIconButton
|
||||||
MyIconProps={{name: 'settings', size: 24}}
|
MyIconProps={{name: 'settings', size: 24}}
|
||||||
|
@ -65,7 +73,8 @@ export default function ProfileTab() {
|
||||||
animation: 'slide_from_right',
|
animation: 'slide_from_right',
|
||||||
title: lang.settings,
|
title: lang.settings,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
headerStyle: headerStyle,
|
||||||
|
headerShadowVisible: false,
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
}}
|
}}
|
||||||
component={ProfileSettings}
|
component={ProfileSettings}
|
||||||
|
@ -77,7 +86,8 @@ export default function ProfileTab() {
|
||||||
animation: 'slide_from_right',
|
animation: 'slide_from_right',
|
||||||
title: lang.updateUsername,
|
title: lang.updateUsername,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
headerStyle: headerStyle,
|
||||||
|
headerShadowVisible: false,
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
}}
|
}}
|
||||||
component={UpdateUsername}
|
component={UpdateUsername}
|
||||||
|
@ -89,7 +99,8 @@ export default function ProfileTab() {
|
||||||
animation: 'slide_from_right',
|
animation: 'slide_from_right',
|
||||||
title: lang.updatePassword,
|
title: lang.updatePassword,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
headerStyle: headerStyle,
|
||||||
|
headerShadowVisible: false,
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
}}
|
}}
|
||||||
component={UpdatePassword}
|
component={UpdatePassword}
|
||||||
|
@ -101,7 +112,8 @@ export default function ProfileTab() {
|
||||||
animation: 'slide_from_right',
|
animation: 'slide_from_right',
|
||||||
title: lang.help,
|
title: lang.help,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
headerStyle: headerStyle,
|
||||||
|
headerShadowVisible: false,
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
}}
|
}}
|
||||||
component={Help}
|
component={Help}
|
||||||
|
@ -113,7 +125,8 @@ export default function ProfileTab() {
|
||||||
animation: 'slide_from_right',
|
animation: 'slide_from_right',
|
||||||
title: lang.about,
|
title: lang.about,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerStyle: {backgroundColor: '#212137'},
|
headerStyle: headerStyle,
|
||||||
|
headerShadowVisible: false,
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
}}
|
}}
|
||||||
component={About}
|
component={About}
|
||||||
|
|
|
@ -38,8 +38,9 @@ function StartHelper() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
const theme = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.preferences.theme,
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [motionProps, api] = useSpring(
|
const [motionProps, api] = useSpring(
|
||||||
|
@ -76,16 +77,14 @@ function StartHelper() {
|
||||||
if (currentAppStatus === appStatus.APP_RUNNING) return null;
|
if (currentAppStatus === appStatus.APP_RUNNING) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={[{flex: 1, backgroundColor: '#26263f'}]}>
|
<SafeAreaView style={[{flex: 1, backgroundColor: currentTheme.backgroundDark400}]}>
|
||||||
<Center height={'100%'}>
|
<Center height={'100%'}>
|
||||||
<AnimationView
|
<AnimationView
|
||||||
style={{
|
style={{
|
||||||
height: 100,
|
height: 100,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
backgroundColor: currentTheme.secondary400,
|
||||||
backgroundColor: '#931278',
|
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
|
|
||||||
width: motionProps.width,
|
width: motionProps.width,
|
||||||
opacity: motionProps.opacity,
|
opacity: motionProps.opacity,
|
||||||
transform: [{translateX: motionProps.translateX}, {translateY: 5}],
|
transform: [{translateX: motionProps.translateX}, {translateY: 5}],
|
||||||
|
@ -94,7 +93,7 @@ function StartHelper() {
|
||||||
<Heading style={{color: '#fff'}}>{lang.appName}</Heading>
|
<Heading style={{color: '#fff'}}>{lang.appName}</Heading>
|
||||||
|
|
||||||
<HStack marginTop={5} justifyContent="center">
|
<HStack marginTop={5} justifyContent="center">
|
||||||
<Spinner color="#931278" size="large" />
|
<Spinner color={currentTheme.secondary400} size="large" />
|
||||||
</HStack>
|
</HStack>
|
||||||
</Center>
|
</Center>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import {MyIcon} from '@components/MyIcon';
|
import {MyIcon} from '@components/MyIcon';
|
||||||
import {MyScreenContainer} from '@components/MyScreenContainer';
|
import {MyScreenContainer} from '@components/MyScreenContainer';
|
||||||
import { RootState } from '@redux/store';
|
import { MyTouchableOpacity } from '@components/MyTouchableOpacity';
|
||||||
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
import {RootState} from '@redux/store';
|
||||||
import {View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
import {Text, TouchableOpacity} from 'react-native';
|
import {useSelector} from 'react-redux';
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
|
|
||||||
export function Help() {
|
export function Help() {
|
||||||
const lang = useSelector(
|
const lang = useSelector(
|
||||||
|
@ -26,12 +27,16 @@ export interface ItemProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Item({icon, title, value, onPress}: ItemProps) {
|
export function Item({icon, title, value, onPress}: ItemProps) {
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<MyTouchableOpacity
|
||||||
style={{
|
style={{
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
backgroundColor: '#26263f',
|
backgroundColor: currentTheme.backgroundDark300,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
padding: 12,
|
padding: 12,
|
||||||
marginTop: 12,
|
marginTop: 12,
|
||||||
|
@ -44,17 +49,13 @@ export function Item({icon, title, value, onPress}: ItemProps) {
|
||||||
{value ? (
|
{value ? (
|
||||||
<>
|
<>
|
||||||
<Text>{title}</Text>
|
<Text>{title}</Text>
|
||||||
<Text style={{color: '#fff', fontWeight: 'bold', fontSize: 16}}>
|
<Text bold>{value}</Text>
|
||||||
{value}
|
|
||||||
</Text>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Text style={{color: '#fff', fontWeight: 'bold', fontSize: 16}}>
|
<Text bold>{title}</Text>
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {MyScreenContainer} from '@components/MyScreenContainer';
|
import {MyScreenContainer} from '@components/MyScreenContainer';
|
||||||
import {Image, ScrollView, TouchableOpacity} from 'react-native';
|
import {Image, ScrollView} from 'react-native';
|
||||||
import {Text, View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
import Avatar from '@assets/profile.png';
|
import Avatar from '@assets/profile.png';
|
||||||
import {MyTitle} from '@components/MyTitle';
|
import {MyTitle} from '@components/MyTitle';
|
||||||
import {MyVerticalDivider} from '@components/MyDivider';
|
import {MyVerticalDivider} from '@components/MyDivider';
|
||||||
|
@ -12,6 +12,8 @@ import {useEffect, useState} from 'react';
|
||||||
import {RootScreenNavigationProp} from '@navigation/navigation';
|
import {RootScreenNavigationProp} from '@navigation/navigation';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
import {RootState} from '@redux/store';
|
import {RootState} from '@redux/store';
|
||||||
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
import {MyTouchableOpacity} from '@components/MyTouchableOpacity';
|
||||||
|
|
||||||
function UserAvatar() {
|
function UserAvatar() {
|
||||||
return (
|
return (
|
||||||
|
@ -56,29 +58,33 @@ interface StatisticProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Statistic({value, title}: StatisticProps) {
|
function Statistic({value, title}: StatisticProps) {
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity>
|
<MyTouchableOpacity>
|
||||||
<View>
|
<View>
|
||||||
<Text
|
<Text
|
||||||
|
size="2xl"
|
||||||
|
bold
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
color: currentTheme.secondary400,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: '#931278',
|
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
}}>
|
}}>
|
||||||
{value}
|
{value}
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
|
bold
|
||||||
|
size="sm"
|
||||||
style={{
|
style={{
|
||||||
fontSize: 14,
|
color: currentTheme.textLight100,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: '#ccc',
|
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
}}>
|
}}>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,14 +167,18 @@ interface SettingsItemContainerProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SettingsItemContainer({children, title}: SettingsItemContainerProps) {
|
function SettingsItemContainer({children, title}: SettingsItemContainerProps) {
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{marginTop: 12}}>
|
<View style={{marginTop: 12}}>
|
||||||
<Text style={{fontSize: 12}}>{title}</Text>
|
<Text size="xs">{title}</Text>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
padding: 12,
|
padding: 12,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
backgroundColor: '#26263f',
|
backgroundColor: currentTheme.backgroundDark300,
|
||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
gap: 16,
|
gap: 16,
|
||||||
}}>
|
}}>
|
||||||
|
@ -187,7 +197,7 @@ interface SettingsItemProps {
|
||||||
|
|
||||||
function SettingsItem({icon, title, value, onPress}: SettingsItemProps) {
|
function SettingsItem({icon, title, value, onPress}: SettingsItemProps) {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<MyTouchableOpacity
|
||||||
style={{
|
style={{
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
@ -195,23 +205,19 @@ function SettingsItem({icon, title, value, onPress}: SettingsItemProps) {
|
||||||
disabled={!onPress}
|
disabled={!onPress}
|
||||||
onPress={onPress}>
|
onPress={onPress}>
|
||||||
<View style={{flexDirection: 'row', gap: 12, alignItems: 'center'}}>
|
<View style={{flexDirection: 'row', gap: 12, alignItems: 'center'}}>
|
||||||
<MyIcon name={icon} size={36} />
|
<MyIcon name={icon} size={32} />
|
||||||
<View>
|
<View>
|
||||||
{value ? (
|
{value ? (
|
||||||
<>
|
<>
|
||||||
<Text style={{fontSize: 14}}>{title}</Text>
|
<Text size="sm">{title}</Text>
|
||||||
<Text style={{color: '#fff', fontWeight: 'bold', fontSize: 16}}>
|
<Text bold>{value}</Text>
|
||||||
{value}
|
|
||||||
</Text>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Text style={{color: '#fff', fontWeight: 'bold', fontSize: 16}}>
|
<Text bold>{title}</Text>
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,6 +225,9 @@ export function UpdateUsername() {
|
||||||
const lang = useSelector(
|
const lang = useSelector(
|
||||||
(state: RootState) => state.appVariables.lang.profile.settings,
|
(state: RootState) => state.appVariables.lang.profile.settings,
|
||||||
);
|
);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
const navigation = useNavigation<ProfileScreenNavigationProp>();
|
const navigation = useNavigation<ProfileScreenNavigationProp>();
|
||||||
|
|
||||||
// TODO: get username from current logged in user
|
// TODO: get username from current logged in user
|
||||||
|
@ -232,9 +241,13 @@ export function UpdateUsername() {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerRight: () =>
|
headerRight: () =>
|
||||||
changed ? (
|
changed ? (
|
||||||
<TouchableOpacity onPress={() => navigation.goBack()}>
|
<MyTouchableOpacity onPress={() => navigation.goBack()}>
|
||||||
<MyIcon name="done" size={24} color={!changed ? '#fff' : '#ccc'} />
|
<MyIcon
|
||||||
</TouchableOpacity>
|
name="done"
|
||||||
|
size={24}
|
||||||
|
color={!changed ? currentTheme.white : currentTheme.textLight100}
|
||||||
|
/>
|
||||||
|
</MyTouchableOpacity>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
),
|
),
|
||||||
|
@ -251,15 +264,19 @@ export function UpdateUsername() {
|
||||||
setNewUsername(text);
|
setNewUsername(text);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Text style={{marginTop: 12}}>{lang.changeUsername.info}</Text>
|
<Text color={currentTheme.textLight100} style={{marginTop: 12}}>{lang.changeUsername.info}</Text>
|
||||||
<Text>{lang.changeUsername.info2}</Text>
|
<Text color={currentTheme.textLight100} >{lang.changeUsername.info2}</Text>
|
||||||
</MyScreenContainer>
|
</MyScreenContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UpdatePassword() {
|
export function UpdatePassword() {
|
||||||
const lang = useSelector(
|
const lang = useSelector(
|
||||||
(state: RootState) => state.appVariables.lang.profile.settings.changePassword,
|
(state: RootState) =>
|
||||||
|
state.appVariables.lang.profile.settings.changePassword,
|
||||||
|
);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
const navigation = useNavigation<RootScreenNavigationProp>();
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
@ -277,12 +294,12 @@ export function UpdatePassword() {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerRight: () =>
|
headerRight: () =>
|
||||||
passwordChanged ? (
|
passwordChanged ? (
|
||||||
<TouchableOpacity
|
<MyTouchableOpacity
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
navigation.navigate('Registration', {screen: 'LoginPreview'})
|
navigation.navigate('Registration', {screen: 'LoginPreview'})
|
||||||
}>
|
}>
|
||||||
<MyIcon name="done" size={24} color="#fff" />
|
<MyIcon name="done" size={24} color={currentTheme.white} />
|
||||||
</TouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
),
|
),
|
||||||
|
@ -294,7 +311,7 @@ export function UpdatePassword() {
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
backgroundColor: '#26263f',
|
backgroundColor: currentTheme.backgroundDark300,
|
||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
}}>
|
}}>
|
||||||
<MyIconInput
|
<MyIconInput
|
||||||
|
@ -323,10 +340,8 @@ export function UpdatePassword() {
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Text style={{marginTop: 12}}>
|
<Text color={currentTheme.textLight100} style={{marginTop: 12}}>{lang.info}</Text>
|
||||||
{lang.info}
|
<Text color={currentTheme.textLight100}>{lang.info2}</Text>
|
||||||
</Text>
|
|
||||||
<Text>{lang.info2}</Text>
|
|
||||||
</MyScreenContainer>
|
</MyScreenContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { MyButton } from "@components/MyButton";
|
||||||
|
import { MyIconInput } from "@components/MyInput";
|
||||||
|
import { MyScreenContainer } from "@components/MyScreenContainer";
|
||||||
|
import { MyTitle } from "@components/MyTitle";
|
||||||
|
import { RootScreenNavigationProp } from "@navigation/navigation";
|
||||||
|
import { ContentContainer, navigateToHome } from "@navigation/registration/registration";
|
||||||
|
import { useNavigation } from "@react-navigation/native";
|
||||||
|
import { RootState } from "@redux/store";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
|
export function Login() {
|
||||||
|
const lang = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.lang.registration,
|
||||||
|
);
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
const [username, setUsername] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
|
||||||
|
const loginEnabled = username.length > 0 && password.length > 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyScreenContainer
|
||||||
|
style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<ContentContainer>
|
||||||
|
<MyTitle text={lang.login.title} />
|
||||||
|
|
||||||
|
<View style={{gap: 12}}>
|
||||||
|
<MyIconInput
|
||||||
|
text={lang.login.inputPhoneNumberOrAccountName}
|
||||||
|
iconName="person"
|
||||||
|
value={username}
|
||||||
|
onChangeText={text => setUsername(text)}
|
||||||
|
/>
|
||||||
|
<MyIconInput
|
||||||
|
text={lang.login.inputPassword}
|
||||||
|
iconName="lock"
|
||||||
|
secureTextEntry
|
||||||
|
value={password}
|
||||||
|
onChangeText={text => setPassword(text)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyButton
|
||||||
|
type="primary"
|
||||||
|
text={lang.buttonLogin}
|
||||||
|
style={{marginBottom: 20}}
|
||||||
|
onPress={() => navigateToHome(navigation)}
|
||||||
|
disabled={!loginEnabled}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</ContentContainer>
|
||||||
|
</MyScreenContainer>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
import {MyButton} from '@components/MyButton';
|
||||||
|
import {MyClickableText} from '@components/MyClickableText';
|
||||||
|
import {ConfirmationCodeInput, MyIconInput} from '@components/MyInput';
|
||||||
|
import {MyScreenContainer} from '@components/MyScreenContainer';
|
||||||
|
import {MyTitle} from '@components/MyTitle';
|
||||||
|
import {RootScreenNavigationProp} from '@navigation/navigation';
|
||||||
|
import {
|
||||||
|
ContentContainer,
|
||||||
|
navigateToHome,
|
||||||
|
} from '@navigation/registration/registration';
|
||||||
|
import {useNavigation} from '@react-navigation/native';
|
||||||
|
import {RootState} from '@redux/store';
|
||||||
|
import {Text} from 'react-native';
|
||||||
|
import {KeyboardAvoidingView, ScrollView, View} from 'react-native';
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
|
function Title({text, description}: {text: string; description?: string}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MyTitle text={text} textAlign="left" paddingBottom={0} />
|
||||||
|
{description && <Text>{description}</Text>}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpStepUsername() {
|
||||||
|
const lang = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.lang.registration,
|
||||||
|
);
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyScreenContainer
|
||||||
|
style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<ContentContainer>
|
||||||
|
<Title
|
||||||
|
text={lang.signUpStepUsername.title}
|
||||||
|
description={lang.signUpStepUsername.description}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={{gap: 12, marginTop: 20}}>
|
||||||
|
<MyIconInput
|
||||||
|
text={lang.signUpStepUsername.inputUsername}
|
||||||
|
iconName="person"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyButton
|
||||||
|
type="secondary"
|
||||||
|
text={lang.buttonNext}
|
||||||
|
style={{marginBottom: 20}}
|
||||||
|
onPress={() => {
|
||||||
|
navigation.navigate('Registration', {
|
||||||
|
screen: 'SignUpStepPhoneNumber',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</ContentContainer>
|
||||||
|
</MyScreenContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpStepPhoneNumber() {
|
||||||
|
const lang = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.lang.registration,
|
||||||
|
);
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyScreenContainer
|
||||||
|
style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<ContentContainer>
|
||||||
|
<Title text={lang.signUpStepPhoneNumber.title} />
|
||||||
|
|
||||||
|
<View style={{gap: 12, marginTop: 20}}>
|
||||||
|
<MyIconInput
|
||||||
|
text={lang.signUpStepPhoneNumber.inputPhoneNumber}
|
||||||
|
iconName="phone-iphone"
|
||||||
|
keyboardType="phone-pad"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyButton
|
||||||
|
type="secondary"
|
||||||
|
text={lang.buttonNext}
|
||||||
|
style={{marginBottom: 20}}
|
||||||
|
onPress={() => {
|
||||||
|
navigation.navigate('Registration', {
|
||||||
|
screen: 'SignUpStepVerifyPhoneNumber',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</ContentContainer>
|
||||||
|
</MyScreenContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpStepVerifyPhoneNumber() {
|
||||||
|
const lang = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.lang.registration,
|
||||||
|
);
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyScreenContainer
|
||||||
|
style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<ContentContainer>
|
||||||
|
<Title
|
||||||
|
text={lang.signUpStepVerifyPhoneNumber.title}
|
||||||
|
description={`${lang.signUpStepVerifyPhoneNumber.description} +49 15** ******43`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<KeyboardAvoidingView style={{gap: 12, marginTop: 20}}>
|
||||||
|
<ConfirmationCodeInput />
|
||||||
|
|
||||||
|
<MyButton
|
||||||
|
type="secondary"
|
||||||
|
text={lang.buttonNext}
|
||||||
|
style={{marginBottom: 2}}
|
||||||
|
onPress={() => {
|
||||||
|
navigation.navigate('Registration', {
|
||||||
|
screen: 'SignUpStepPassword',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<View style={{alignItems: 'center'}}>
|
||||||
|
<MyClickableText
|
||||||
|
text={lang.signUpStepVerifyPhoneNumber.clickableTextResendCode}
|
||||||
|
color={currentTheme.textLight400}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
</ContentContainer>
|
||||||
|
</MyScreenContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpStepPassword() {
|
||||||
|
const lang = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.lang.registration,
|
||||||
|
);
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyScreenContainer
|
||||||
|
style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<ContentContainer>
|
||||||
|
<Title
|
||||||
|
text={lang.signUpStepPassword.title}
|
||||||
|
description={lang.signUpStepPassword.description}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={{gap: 12, marginTop: 20}}>
|
||||||
|
<MyIconInput
|
||||||
|
text={lang.signUpStepPassword.inputPassword}
|
||||||
|
iconName="lock"
|
||||||
|
secureTextEntry
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyButton
|
||||||
|
type="secondary"
|
||||||
|
text={lang.buttonNext}
|
||||||
|
style={{marginBottom: 2}}
|
||||||
|
onPress={() =>
|
||||||
|
navigation.navigate('Registration', {
|
||||||
|
screen: 'SignUpStepAccountName',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</ContentContainer>
|
||||||
|
</MyScreenContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpStepAccountName() {
|
||||||
|
const lang = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.lang.registration,
|
||||||
|
);
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyScreenContainer
|
||||||
|
style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<ScrollView>
|
||||||
|
<ContentContainer>
|
||||||
|
<Title
|
||||||
|
text={lang.signUpStepAccountName.title}
|
||||||
|
description={lang.signUpStepAccountName.description}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={{gap: 12, marginTop: 20}}>
|
||||||
|
<MyIconInput
|
||||||
|
text={lang.signUpStepAccountName.inputAccountName}
|
||||||
|
iconName="person"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyButton
|
||||||
|
type="primary"
|
||||||
|
text={lang.signUpStepAccountName.buttonGetStarted}
|
||||||
|
style={{marginBottom: 2}}
|
||||||
|
onPress={() => navigateToHome(navigation)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</ContentContainer>
|
||||||
|
</ScrollView>
|
||||||
|
</MyScreenContainer>
|
||||||
|
);
|
||||||
|
}
|
Reference in New Issue