navigation

alpha
Jan Umbach 2022-12-24 18:54:47 +01:00
parent 7fd1ce9596
commit 10ac84df72
40 changed files with 2121 additions and 318 deletions

View File

@ -1,13 +1,16 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
alias: {
'@caj': './src/caj',
module.exports = function (api) {
api.cache(true);
return {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
alias: {
'@caj': './src/caj',
},
},
},
],
],
],
};
};

1023
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,23 +12,35 @@
"lint": "eslint ."
},
"dependencies": {
"@react-navigation/native": "^6.1.0",
"@react-navigation/native-stack": "^6.9.5",
"@react-navigation/bottom-tabs": "^6.5.2",
"@react-navigation/native": "^6.1.1",
"@react-navigation/native-stack": "^6.9.7",
"@react-spring/native": "^9.6.1",
"@react-spring/web": "^9.6.1",
"@reduxjs/toolkit": "^1.9.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-esnext": "^1.1.3",
"babel-preset-react": "^6.24.1",
"native-base": "^3.4.23",
"react": "^18.1.0",
"react-dom": "18.1.0",
"react-native": "0.70.6",
"react-native-encrypted-storage": "^4.0.3",
"react-native-gesture-handler": "^2.8.0",
"react-native-reanimated": "^2.13.0",
"react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.18.2",
"react-native-web": "^0.18.10"
"react-native-web": "^0.18.10",
"react-redux": "^8.0.5"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/runtime": "^7.12.5",
"@babel/preset-react": "^7.18.6",
"@babel/runtime": "^7.20.6",
"@react-native-community/eslint-config": "^2.0.0",
"@types/node": "^18.11.10",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@types/webpack": "^5.28.0",
"babel-jest": "^26.6.3",
"babel-loader": "^9.1.0",

143
src/App copy.tsx Normal file
View File

@ -0,0 +1,143 @@
import React, {useState, useEffect} from 'react';
import {StyleSheet, Appearance} from 'react-native';
import {
NativeBaseProvider,
Box,
Input,
Text,
Button,
useColorMode,
useColorModeValue,
StatusBar,
VStack,
Center,
Avatar,
} from 'native-base';
import {NavigationContainer} from '@react-navigation/native';
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';
import {theme} from '@caj/configs/colors';
import imgSrc from '@caj/img/maimg.png';
interface User {
name: string;
id: number;
}
const user: User = {
name: 'Hayes',
id: 0,
};
function TestContent() {
const {colorMode, toggleColorMode, setColorMode} = useColorMode();
//var bg = useColorModeValue('dark', 'coolGray.800');
const [curTheme, setTheme] = useState(1);
var bg = '#222';
if (curTheme !== 1) bg = curTheme === 0 ? '#000' : '#fff';
console.log(colorMode);
const toggleSwitch = () => {
console.log('switch');
toggleColorMode();
};
return (
<SafeAreaView style={[styles.container, {backgroundColor: bg}]}>
<VStack space={4} alignItems="center">
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Box>
<Text style={{}}>ma boyy :--)))</Text>
</Box>
<Avatar bg="green.500" size="xl" source={imgSrc}>
EM
</Avatar>
<Box>
<Input w="90%" shadow={10} placeholder="Enter your name" />
</Box>
<Button
w="64"
onPress={() => {
let theme = curTheme + 1;
if (theme > 2) theme = 0;
setTheme(theme);
setColorMode(theme === 0 || theme === 1 ? 'dark' : 'light');
}}
h={10}>
Change theme
</Button>
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
</VStack>
</SafeAreaView>
);
}
const Bar = () => {
const {colorMode, toggleColorMode} = useColorMode();
return (
<StatusBar
barStyle={colorMode === 'dark' ? 'light-content' : 'dark-content'}
backgroundColor="transparent"
translucent={true}
/>
);
};
const App = () => {
useEffect(() => {
// this code will run once
}, [])
return (
<NavigationContainer>
<NativeBaseProvider theme={theme}>
<Bar />
<TestContent />
</NativeBaseProvider>
</NavigationContainer>
);
};
const styles = StyleSheet.create({
container: {
height: '100%',
flex: 1,
},
});
/*
const styles = StyleSheet.create({
baseText: {
fontFamily: 'Cochin',
},
titleText: {
fontSize: 20,
fontWeight: 'bold',
},
image: {
width: 500,
height: 500,
borderWidth: 1,
},
});*/
export default App;

View File

@ -1,143 +1,69 @@
import React, {useState} from 'react';
import React, {useState, useEffect, Fragment} from 'react';
import {StyleSheet, Appearance} from 'react-native';
import {
NativeBaseProvider,
Box,
Input,
Text,
Button,
useColorMode,
useColorModeValue,
StatusBar,
VStack,
Center,
Avatar,
} from 'native-base';
import {NativeBaseProvider} from 'native-base';
import {NavigationContainer} from '@react-navigation/native';
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';
import {theme} from '@caj/configs/colors';
import {getBackgroundColor, theme, ThemeSwitcher} from '@caj/configs/colors';
import imgSrc from '@caj/img/maimg.png';
import StatusBar from './StatusBar';
import Navigation, {linking} from './Navigation';
interface User {
name: string;
id: number;
}
const user: User = {
name: 'Hayes',
id: 0,
};
function TestContent() {
const {colorMode, toggleColorMode, setColorMode} = useColorMode();
//var bg = useColorModeValue('dark', 'coolGray.800');
const [curTheme, setTheme] = useState(1);
var bg = '#222';
if (curTheme !== 1) bg = curTheme === 0 ? '#000' : '#fff';
console.log(colorMode);
const toggleSwitch = () => {
console.log('switch');
toggleColorMode();
};
return (
<SafeAreaView style={[styles.container, {backgroundColor: bg}]}>
<VStack space={4} alignItems="center">
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Box>
<Text style={{}}>ma boyy :--)))</Text>
</Box>
<Avatar bg="green.500" size="xl" source={imgSrc}>
EM
</Avatar>
<Box>
<Input w="90%" shadow={10} placeholder="Enter your name" />
</Box>
<Button
w="64"
onPress={() => {
let theme = curTheme + 1;
if (theme > 2) theme = 0;
setTheme(theme);
setColorMode(theme === 0 || theme === 1 ? 'dark' : 'light');
}}
h={10}>
Change theme
</Button>
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
</VStack>
</SafeAreaView>
);
}
const Bar = () => {
const {colorMode, toggleColorMode} = useColorMode();
return (
<StatusBar
barStyle={colorMode === 'dark' ? 'light-content' : 'dark-content'}
backgroundColor="transparent"
translucent={true}
/>
);
};
import {Provider, useSelector} from 'react-redux';
import {RootState, store} from '@caj/redux/store';
import StartHelper from './appStart/StartHelper';
import {appStatus} from '@caj/configs/appNonSaveVar';
import {ThemeMode} from '@caj/configs/appVar';
const App = () => {
useEffect(() => {
// this code will run once
}, [])
console.log('App opened.');
}, []);
return (
<NavigationContainer>
<Provider store={store}>
<OtherProviders />
</Provider>
);
};
const OtherProviders = () => {
const globalTheme = useSelector(
(state: RootState) => state.appVariables.preferences.theme,
);
const navigationTheme = {
dark: globalTheme !== ThemeMode.Light,
colors: {
primary: '#ff7d4f',
background: getBackgroundColor(globalTheme),
card: '#222',
text: '#fff',
border: '#ff7d4f',
notification: '#fff',
},
};
return (
<NavigationContainer theme={navigationTheme} linking={linking}>
<NativeBaseProvider theme={theme}>
<Bar />
<TestContent />
<MainComponent />
</NativeBaseProvider>
</NavigationContainer>
);
};
const styles = StyleSheet.create({
container: {
height: '100%',
flex: 1,
},
});
/*
const styles = StyleSheet.create({
baseText: {
fontFamily: 'Cochin',
},
titleText: {
fontSize: 20,
fontWeight: 'bold',
},
image: {
width: 500,
height: 500,
borderWidth: 1,
},
});*/
const MainComponent = () => {
const currentAppStatus = useSelector(
(state: RootState) => state.nonSaveVariables.appStatus,
);
return (
<Fragment>
<StartHelper />
<ThemeSwitcher />
<StatusBar />
{currentAppStatus === appStatus.APP_RUNNING ? <Navigation /> : null}
</Fragment>
);
};
export default App;

105
src/Navigation copy.tsx Normal file
View File

@ -0,0 +1,105 @@
import React, {useState, useEffect} from 'react';
import {StyleSheet, Appearance} from 'react-native';
import {Box, Input, Text, Button, VStack, Center, Avatar} from 'native-base';
import {NavigationContainer} from '@react-navigation/native';
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';
import {useSelector, useDispatch} from 'react-redux';
import {RootState} from '@caj/redux/store';
import {appVarActions} from '@caj/configs/appVarReducer';
import imgSrc from '@caj/img/maimg.png';
import {placeholder} from '@caj/lang/default';
import {getBackgroundColor} from '@caj/configs/colors';
import {saveVarChanges} from '@caj/helper/appData';
function CounterNum() {
const lang = useSelector((state: RootState) => state.appVariables.lang);
const version = useSelector(
(state: RootState) => state.appVariables.preferences.version,
);
return <Text>{placeholder(lang.curVersion, {version})}</Text>;
}
export default function Navigation() {
const theme = useSelector(
(state: RootState) => state.appVariables.preferences.theme,
);
const dispatch = useDispatch();
//const {colorMode, toggleColorMode, setColorMode} = useColorMode();
//var bg = useColorModeValue('dark', 'coolGray.800');
//const [curTheme, setTheme] = useState(1);
return (
<SafeAreaView
style={[styles.container, {backgroundColor: getBackgroundColor(theme)}]}>
<VStack space={4} alignItems="center">
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Box>
<CounterNum />
</Box>
<Avatar bg="green.500" size="xl" source={imgSrc}>
EM
</Avatar>
<Box>
<Input w="90%" shadow={10} placeholder="Enter your name" />
</Box>
<Button
w="64"
onPress={() => {
let _theme = theme + 1;
if (_theme > 2) _theme = 0;
dispatch(appVarActions.setTheme(_theme));
saveVarChanges();
}}
h={10}>
Change theme
</Button>
<Button
w="48"
onPress={() => {
//dispatch(appVarActions.setVersion(3));
}}
h={10}>
version +1
</Button>
<Button
w="48"
onPress={() => {
//dispatch(appVarActions.setVersion(2));
}}
h={10}>
version -1
</Button>
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.300" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.500" rounded="md" shadow={3} />
<Center w="64" h="20" bg="indigo.700" rounded="md" shadow={3} />
</VStack>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
height: '100%',
flex: 1,
},
});

139
src/Navigation.tsx Normal file
View File

@ -0,0 +1,139 @@
import React, {useState, useEffect} from 'react';
import {StyleSheet, Appearance} from 'react-native';
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';
import {useSelector, useDispatch} from 'react-redux';
import {RootState} from '@caj/redux/store';
import {appVarActions} from '@caj/configs/appVarReducer';
import imgSrc from '@caj/img/maimg.png';
import {placeholder} from '@caj/lang/default';
import {getBackgroundColor} from '@caj/configs/colors';
import {saveVarChanges} from '@caj/helper/appData';
import {Box, Input, VStack, Center, Avatar, Text, Button} from 'native-base';
import {View} from 'react-native';
import {
LinkingOptions,
NavigationContainer,
useNavigation,
} from '@react-navigation/native';
import {
createNativeStackNavigator,
NativeStackNavigationProp,
} from '@react-navigation/native-stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
const styles = StyleSheet.create({
container: {
height: '100%',
flex: 1,
},
});
export const linking: LinkingOptions<{
Auth: string;
Home: string;
Table: string;
Loading: string;
}> = {
prefixes: ['http://'],
config: {
initialRouteName: 'Loading',
screens: {
Auth: 'auth',
Home: 'home',
Table: 'table',
Loading: 'loading',
},
},
};
export type HomeStackNavigatorParamList = {
Home: undefined;
Maps: undefined;
Chat: undefined;
Test: undefined;
Settings: undefined;
};
export type HomeScreenNavigationProp =
NativeStackNavigationProp<HomeStackNavigatorParamList>;
export default function Navigation() {
const theme = useSelector(
(state: RootState) => state.appVariables.preferences.theme,
);
const dispatch = useDispatch();
return (
<Tab.Navigator screenOptions={{headerShown: false}}>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
<Tab.Screen
name="Chat"
options={{headerShown: true, tabBarStyle: {display: 'none'}}}
component={ChatScreen}
/>
</Tab.Navigator>
);
}
function ChatScreen() {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Chat!</Text>
</View>
);
}
function HomeScreen() {
const navigation = useNavigation<HomeScreenNavigationProp>();
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Home screen</Text>
<Button onPress={() => navigation.navigate('Test')}>Go to Test</Button>
</View>
);
}
function SettingsScreen() {
const navigation = useNavigation<HomeScreenNavigationProp>();
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Settings screen</Text>
<Button onPress={() => navigation.navigate('Chat')}>Go to Chat</Button>
</View>
);
}
const HomeStack = createNativeStackNavigator<HomeStackNavigatorParamList>();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name="Maps"
options={{headerShown: false}}
component={HomeScreen}
/>
<HomeStack.Screen name="Test" component={ChatScreen} />
</HomeStack.Navigator>
);
}
const SettingsStack = createNativeStackNavigator<HomeStackNavigatorParamList>();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Chat" component={ChatScreen} />
</SettingsStack.Navigator>
);
}
const Tab = createBottomTabNavigator();

15
src/StatusBar.tsx Normal file
View File

@ -0,0 +1,15 @@
import {useColorMode} from 'native-base';
import {StatusBar as NBStatusBar} from 'native-base';
export default function StatusBar() {
const {colorMode} = useColorMode();
return (
<NBStatusBar
barStyle={colorMode === 'dark' ? 'light-content' : 'dark-content'}
backgroundColor="transparent"
translucent={true}
/>
);
}

View File

@ -0,0 +1,104 @@
import {Platform, StyleSheet, View, ScrollView} from 'react-native';
import {Center, Heading, Text, Spinner, HStack} from 'native-base';
import {animated, useSpring} from '@react-spring/native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {useSelector, useDispatch} from 'react-redux';
import {RootState, store} from '@caj/redux/store';
import imgSrc from '@caj/img/maimg.png';
import {placeholder} from '@caj/lang/default';
import {getBackgroundColor} from '@caj/configs/colors';
import {useEffect} from 'react';
import {initAppData} from '@caj/helper/appData';
import {appStatus} from '@caj/configs/appNonSaveVar';
import {appNonSaveVarActions} from '@caj/configs/appNonSaveVarReducer';
const AnimationView = animated(View);
function onAppStart() {
initAppData().then(() => {
console.log('finish');
setTimeout(() => {
store.dispatch(appNonSaveVarActions.setAppStatus(appStatus.APP_RUNNING));
}, 500);
//store.dispatch(actions.loadPreferences(appVar));
});
}
function StartHelper() {
const currentAppStatus = useSelector(
(state: RootState) => state.nonSaveVariables.appStatus,
);
const lang = useSelector((state: RootState) => state.appVariables.lang);
const theme = useSelector(
(state: RootState) => state.appVariables.preferences.theme,
);
const [motionProps, api] = useSpring(
() => ({
from: {
translateX: -150,
width: 4,
opacity: 1,
},
}),
[],
);
useEffect(() => {
api.start({
to: [
{
translateX: 150,
width: 4,
opacity: 1,
},
{
translateX: -150,
width: 4,
opacity: 1,
},
],
loop: true,
});
}, []);
useEffect(onAppStart, []);
if (currentAppStatus === appStatus.APP_RUNNING) return null;
return (
<SafeAreaView
style={[{flex: 1, backgroundColor: getBackgroundColor(theme)}]}>
<Center height={'100%'}>
<AnimationView
style={{
height: 100,
position: 'absolute',
backgroundColor: '#f22',
borderRadius: 8,
width: motionProps.width,
opacity: motionProps.opacity,
transform: [{translateX: motionProps.translateX}, {translateY: 5}],
}}
/>
<Heading>{lang.appName}</Heading>
<HStack mt="5" space={2} justifyContent="center">
<Spinner color="#ff7d4f" accessibilityLabel="Loading posts" />
<Heading color="#ff7d4f" fontSize="md">
{lang.startHelper1}
</Heading>
</HStack>
</Center>
</SafeAreaView>
);
}
export default StartHelper;

View File

@ -1,5 +0,0 @@
export function initAppData() {
}

View File

@ -0,0 +1,30 @@
//these variables should not changed by the user and will not be saved in storage
import {getVersionByNum, VersionType} from '@caj/helper/version';
export const APP_VERSION = getVersionByNum(2);
export const AppVarMaxBackups: number = 10;
export enum appStatus {
IS_LOADING,
APP_RUNNING,
}
export enum connectionStatus {
UNKNOWN,
OFFLINE,
ONLINE,
RECONNECTING,
}
export interface NON_SAVE_VARS {
currentAppVersion: VersionType;
appStatus: appStatus;
connectionStatus: connectionStatus;
}
export const non_save_vars: NON_SAVE_VARS = {
currentAppVersion: APP_VERSION,
appStatus: appStatus.IS_LOADING,
connectionStatus: connectionStatus.UNKNOWN,
};

View File

@ -0,0 +1,20 @@
import {createSlice} from '@reduxjs/toolkit';
import type {PayloadAction} from '@reduxjs/toolkit';
import {appStatus, non_save_vars} from './appNonSaveVar';
export const appNonSaveVariablesSlice = createSlice({
name: 'non_save_vars',
initialState: non_save_vars,
reducers: {
setAppStatus: (state, action: PayloadAction<appStatus>) => {
state.appStatus = action.payload;
},
},
});
// Action creators are generated for each case reducer function
const {actions} = appNonSaveVariablesSlice;
export const appNonSaveVarActions = actions;
export default appNonSaveVariablesSlice.reducer;

55
src/caj/configs/appVar.ts Normal file
View File

@ -0,0 +1,55 @@
import {VersionType} from '@caj/helper/version';
import {APP_VERSION} from './appNonSaveVar';
export enum ThemeMode {
Darkest = 0,
Dark = 1,
Light = 2,
}
export function applyUpdateChanges(appVar: any): Promise<void> {
return new Promise<void>(function (resolve, reject) {
appVar.version += 1;
console.log(appVar.version);
function finish() {
resolve();
}
switch (appVar.version) {
case 3: {
let appVarF = appVar as PREFERENCES_VARS;
appVar = appVarF;
finish();
break;
}
case 2: {
let appVarF = appVar;
appVar = appVarF;
finish();
break;
}
default: {
finish();
break;
}
}
});
}
//these variables may be changed by the user and will be saved in storage
export interface PREFERENCES_VARS {
version: VersionType;
theme: ThemeMode;
}
export const preferences_vars_default: PREFERENCES_VARS = {
version: APP_VERSION, //version of datatypes in storage
theme: ThemeMode.Dark,
};

View File

@ -0,0 +1,39 @@
import {createSlice} from '@reduxjs/toolkit';
import type {PayloadAction} from '@reduxjs/toolkit';
import {PREFERENCES_VARS, preferences_vars_default, ThemeMode} from './appVar';
import {non_save_vars, NON_SAVE_VARS} from './appNonSaveVar';
import LangFormat from '@caj/lang/default';
import {lang as defaultLang} from '@caj/lang/en';
export interface appVariablesState {
preferences: PREFERENCES_VARS;
lang: LangFormat;
}
const initialState: appVariablesState = {
preferences: preferences_vars_default,
lang: defaultLang,
};
export const appVariablesSlice = createSlice({
name: 'appVariables',
initialState,
reducers: {
setTheme: (state, action: PayloadAction<ThemeMode>) => {
state.preferences.theme = action.payload;
},
setLang: (state, action: PayloadAction<LangFormat>) => {
state.lang = action.payload;
},
loadPreferences: (state, action: PayloadAction<PREFERENCES_VARS>) => {
state.preferences = action.payload;
},
},
});
// Action creators are generated for each case reducer function
const {actions} = appVariablesSlice;
export const appVarActions = actions;
export default appVariablesSlice.reducer;

View File

@ -1,4 +1,10 @@
import { extendTheme } from 'native-base';
import {Platform} from 'react-native';
import {extendTheme, useColorMode} from 'native-base';
import {ThemeMode} from './appVar';
import {useSelector} from 'react-redux';
import {RootState} from '@caj/redux/store';
import {useEffect} from 'react';
export const theme = extendTheme({
config: {
@ -18,23 +24,18 @@ export const theme = extendTheme({
300: '#292929',
800: '#181725',
},
green: {
300: '#53B175',
},
primary: {
50: '#E3F2F9',
100: '#C5E4F3',
200: '#A2D4EC',
300: '#7AC1E4',
400: '#47A9DA',
500: '#0088CC',
600: '#007AB8',
700: '#006BA1',
800: '#005885',
900: '#003F5E',
},
amber: {
400: '#d97706',
50: '#fff4f1',
100: '#ffd6c9',
200: '#ffb9a1',
300: '#ff9b79',
400: '#ff7d50',
500: '#f96e40',
600: '#f26030',
700: '#e95321',
800: '#d54b1d',
900: '#ba4721',
},
},
components: {
@ -76,4 +77,43 @@ export const theme = extendTheme({
},
},
},
});
});
export function getBackgroundColor(tm: ThemeMode): string {
switch (tm) {
case ThemeMode.Light:
return '#fff';
case ThemeMode.Darkest:
return '#000';
default:
return '#282f34';
}
}
export function isThemeDark(tm: ThemeMode): boolean {
return tm <= 1;
}
export function ThemeSwitcher() {
const myTheme = useSelector(
(state: RootState) => state.appVariables.preferences.theme,
);
const {setColorMode} = useColorMode();
useEffect(() => {
if (myTheme === ThemeMode.Darkest || myTheme === ThemeMode.Dark)
setColorMode('dark');
else setColorMode('light');
if (Platform.OS === 'web') {
document.body.setAttribute(
'style',
'background: ' + getBackgroundColor(myTheme) + ';',
);
}
console.log('refreshed');
}, [myTheme]);
return null;
}

View File

@ -1,3 +0,0 @@
export const testt = { data: "hellow :33 liebe diese Android"};

View File

@ -1,3 +0,0 @@
export const testt = { data: "hellow :33 liebe diese ios"};

View File

@ -1,3 +0,0 @@
export const testt = { data: "hellow :33 liebe diese WEB"};

View File

@ -0,0 +1 @@
export {animated, useSpring} from '@react-spring/native';

View File

@ -0,0 +1 @@
export {animated, useSpring} from '@react-spring/web';

198
src/caj/helper/appData.ts Normal file
View File

@ -0,0 +1,198 @@
import {
applyUpdateChanges,
PREFERENCES_VARS,
preferences_vars_default,
} from '@caj/configs/appVar';
import {AppVarMaxBackups, APP_VERSION} from '@caj/configs/appNonSaveVar';
import {appVarActions} from '@caj/configs/appVarReducer';
import {store} from '@caj/redux/store';
import {getData, setData} from './storage/appData';
import {getVersionByType, stepUpVersionCalc} from './version';
const APP_CHANGE_BACKUP = 'appVerChangeBackup';
function setAppVar(appVar: PREFERENCES_VARS) {
store.dispatch(appVarActions.loadPreferences(appVar));
}
function makeBackup(key: string, version: number): Promise<void> {
return new Promise<void>(function (resolve, reject) {
getData('appVar').then(value => {
if (value !== null) {
setData(key + '#' + version, value).then(() => {
resolve();
});
} else {
resolve();
}
});
});
}
function refreshVersion(from: number, to: number): Promise<void> {
return new Promise<void>(function (resolve, reject) {
if (from < to) {
// app upgrade
console.log('app upgrade detected!');
finish();
} else if (from > to) {
// app downgrade
console.log('app downgrade detected!');
finish();
} else {
// app version not changed
finish();
}
function finish() {
setData('appVersion', APP_VERSION.toString()).then(() => {
resolve();
});
}
});
}
export function initAppData(): Promise<void> {
return new Promise<void>(function (resolve, reject) {
let appVer: number = -1;
getData('appVersion').then(_ver => {
appVer = typeof _ver === 'string' ? Number.parseInt(_ver) : -1;
if (appVer === -1) {
// no version found in storage
setData('appVersion', APP_VERSION.toString()).then(() => {
appVer = APP_VERSION;
preferencesPull();
});
return;
} else if (appVer < APP_VERSION) {
// found outdated version: make backup; and upgrade
makeBackup(APP_CHANGE_BACKUP, appVer).then(() => {
refreshVersion(appVer, APP_VERSION).then(() => {
preferencesPull();
});
});
} else if (appVer > APP_VERSION) {
// version is too high: make backup; and "downgrade"
makeBackup(APP_CHANGE_BACKUP, appVer).then(() => {
refreshVersion(appVer, APP_VERSION).then(() => {
preferencesPull();
});
});
}
preferencesPull();
});
function resetPreferences() {
let appVar = preferences_vars_default;
setData('appVar', JSON.stringify(appVar)).then(() => {
setAppVar(appVar);
resolve();
});
}
function tryToApplyPreferences(
appVar: PREFERENCES_VARS,
didUpdate = false,
) {
if (appVar.version < APP_VERSION) {
{
console.log('ver', appVar.version);
console.log('config update needed until', APP_VERSION, appVar);
applyUpdateChanges(appVar).then(() => {
tryToApplyPreferences(appVar, true);
});
return;
}
}
const changed = checkForUndefined(preferences_vars_default, appVar);
if (didUpdate === true || changed === true) {
setData('appVar', JSON.stringify(appVar)).then(() => {
setAppVar(appVar);
resolve();
});
} else {
setAppVar(appVar);
resolve();
}
}
function preferencesPull() {
getData('appVar').then(value => {
if (value === null) {
resetPreferences();
} else {
let appVarRaw = null;
let isNoJSON = false;
try {
appVarRaw = JSON.parse(value);
} catch (error) {
console.error('corrupt appVar! :(');
isNoJSON = true;
}
if (isNoJSON) {
getData('appVarBackupIndex').then(_index => {
let index: number =
typeof _index === 'string'
? Number.parseInt(_index)
: AppVarMaxBackups;
index--;
if (index < 0) index = AppVarMaxBackups - 1;
setData('appVarBackup' + index, value).then(() => {
setData('appVarBackupIndex', index.toString()).then(() => {
resetPreferences();
});
});
});
} else {
let appVar: PREFERENCES_VARS = appVarRaw;
tryToApplyPreferences(appVar);
}
}
});
}
});
}
export function saveVarChanges() {
let appVar = store.getState().appVariables.preferences;
setData('appVar', JSON.stringify(appVar)).then(() => {
console.log('saved!');
});
}
export function checkForUndefined(objDef: any, objReal: any): boolean {
let changed = false;
function checkObj(objDef: any, objReal: any) {
for (const key in objDef) {
const defValue = objDef[key];
let realValue = objReal[key];
if (typeof defValue === 'undefined') continue;
if (typeof realValue === 'undefined' || realValue === null) {
objReal[key] = defValue;
changed = true;
console.log(key);
} else if (
typeof defValue === 'object' &&
typeof realValue === 'object'
) {
checkObj(defValue, realValue);
}
}
}
checkObj(objDef, objReal);
return changed;
}

View File

@ -0,0 +1,9 @@
import EncryptedStorage from 'react-native-encrypted-storage';
export async function getData(key: string): Promise<string | null> {
return EncryptedStorage.getItem(key);
}
export async function setData(key: string, value: string): Promise<void> {
return EncryptedStorage.setItem(key, value);
}

View File

@ -0,0 +1,13 @@
export async function getData(key: string): Promise<string | null> {
return new Promise(resolve => {
const data = localStorage.getItem(key);
resolve(data);
});
}
export async function setData(key: string, value: string): Promise<void> {
return new Promise(resolve => {
localStorage.setItem(key, value);
resolve();
});
}

39
src/caj/helper/version.ts Normal file
View File

@ -0,0 +1,39 @@
export enum VersionType {}
export function getVersionByNum(ver: number): VersionType {
return ver;
}
export function getVersionByType(ver: VersionType): number {
return ver;
}
export function stepUpVersionCalc(
ver: VersionType,
steps: number,
): VersionType {
return ver + steps;
}
/*const VersionFactor = 1;
export function getVersionByNum(ver: number): VersionType {
let verObj: VersionType;
verObj = ver * VersionFactor;
return verObj;
}
export function getVersionByType(ver: VersionType): number {
let verObj: number;
verObj = Math.floor(ver / VersionFactor);
return verObj;
}
export function stepUpVersionCalc(
ver: VersionType,
steps: number,
): VersionType {
return ver + steps * VersionFactor;
}*/

47
src/caj/lang/default.ts Normal file
View File

@ -0,0 +1,47 @@
import {type} from 'os';
interface LangDetails {
langCode: string;
langName: string;
}
export default interface LangFormat {
details: LangDetails;
curVersion: string;
appName: string;
startHelper1: string;
}
interface LangPlaceholderKeys {
version?: number;
appName?: string;
}
export function placeholder(text: string, data: LangPlaceholderKeys): string {
let out = text;
for (const key in data) {
const rawValue = data[key as keyof LangPlaceholderKeys];
let _value: any =
typeof rawValue === 'number' ? rawValue.toString() : rawValue;
if (typeof rawValue === 'undefined') _value = 'undefined';
let value: string = _value;
out = out.replaceAll('${' + key + '}', value);
}
return out;
}
/*
var str = 'Good ${timeOfTheDay}, ${name}. I am from ${city}, ${age} years old';
var parts = str.split(/(\$\{\w+?})/g).map(function(v) {
var replaced = v.replace(/\$\{(\w+?)}/g, '$1');
return content[replaced] || v;
});
console.log(parts.join(''));
*/

12
src/caj/lang/en.ts Normal file
View File

@ -0,0 +1,12 @@
import StartHelper from 'src/appStart/StartHelper';
import LangFormat from './default';
export const lang: LangFormat = {
details: {
langCode: 'en',
langName: 'English',
},
curVersion: 'Your current version is v${version}.',
appName: 'Click And Join',
startHelper1: 'Your data will be loaded :)',
};

16
src/caj/redux/store.ts Normal file
View File

@ -0,0 +1,16 @@
import appNonSaveVarReducer from '@caj/configs/appNonSaveVarReducer';
import {configureStore} from '@reduxjs/toolkit';
import appVariablesReducer from '../configs/appVarReducer';
export const store = configureStore({
reducer: {
appVariables: appVariablesReducer,
nonSaveVariables: appNonSaveVarReducer,
},
});
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;

View File

@ -7,8 +7,8 @@
"target": "ESNext",
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"jsx": "react-native"
"jsx": "react-native",
"strict": true,
},
"include": ["**/*.ts", "**/*.tsx", "./src/caj/img/*.png"],
"exclude": [

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
web/public/fonts/Outfit.ttf Normal file

Binary file not shown.

View File

@ -6,6 +6,74 @@
<meta name="theme-color" content="#222" />
<meta name="description" content="Click and Join Web" />
<title>Click and Join Web</title>
<style>
:root {
--doc--height: 100%;
}
@font-face {
font-family: 'Outfit-Thin';
src: url('/fonts/Outfit.ttf');
font-weight: 100;
}
@font-face {
font-family: 'Outfit-ExtraLight';
src: url('/fonts/Outfit.ttf');
font-weight: 200;
}
@font-face {
font-family: 'Outfit-Light';
src: url('/fonts/Outfit.ttf');
font-weight: 300;
}
@font-face {
font-family: 'Outfit-Regular';
src: url('/fonts/Outfit.ttf');
font-weight: 400;
}
@font-face {
font-family: 'Outfit-Medium';
src: url('/fonts/Outfit.ttf');
font-weight: 500;
}
@font-face {
font-family: 'Outfit-SemiBold';
src: url('/fonts/Outfit.ttf');
font-weight: 600;
}
@font-face {
font-family: 'Outfit-Bold';
src: url('/fonts/Outfit.ttf');
font-weight: 700;
}
@font-face {
font-family: 'Outfit-ExtraBold';
src: url('/fonts/Outfit.ttf');
font-weight: 800;
}
@font-face {
font-family: 'Outfit-Black';
src: url('/fonts/Outfit.ttf');
font-weight: 900;
}
html,
body {
padding: 0;
margin: 0;
background-color: #282f34;
overflow: hidden;
}
#root {
height: 100vh; /* fallback for Js load */
height: var(--doc-height);
display: flex;
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
@ -13,6 +81,13 @@
<script>
var exports = {};
const documentHeight = () => {
const doc = document.documentElement;
doc.style.setProperty('--doc-height', window.innerHeight + 'px');
};
window.addEventListener('resize', documentHeight);
documentHeight();
</script>
<script type="module" src="/bundle.web.js"></script>
</body>

View File

@ -16,10 +16,8 @@ const babelLoaderConfiguration = {
include: [
path.resolve(appDirectory, 'index.web.tsx'),
path.resolve(appDirectory, 'src'),
path.resolve(appDirectory, 'node_modules'),
path.resolve(appDirectory, 'node_modules/react-native-uncompiled'),
path.resolve(appDirectory, 'node_modules/react-native-sdk'),
],
exclude: [path.resolve(appDirectory, 'node_modules')],
use: {
loader: 'babel-loader',
options: {
@ -29,15 +27,15 @@ const babelLoaderConfiguration = {
// presets: ['react-native'],
presets: [require.resolve('babel-preset-react-native')],
// Re-write paths to import only the modules needed by the app
plugins: ['react-native-web',],
plugins: ['react-native-web'],
presets: ['react-native'],
presets: ['module:metro-react-native-babel-preset'],
// plugins: [
// // needed to support async/await
// '@babel/plugin-transform-runtime'
// ]
plugins: [
// needed to support async/await
'@babel/plugin-transform-runtime',
],
},
}
},
};
// This is needed for webpack to import static images in JavaScript files.
@ -46,44 +44,42 @@ const imageLoaderConfiguration = {
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]'
}
}
name: '[name].[ext]',
},
},
};
module.exports = {
mode: 'development',
target: 'web',
entry: [
// load any web API polyfills
// path.resolve(appDirectory, 'polyfills-web.js'),
//'babel-polyfill',
// your web-specific entry file
path.resolve(appDirectory, 'index.web.tsx')
path.resolve(appDirectory, 'index.web.tsx'),
],
// configures where the build ends up
output: {
filename: 'bundle.web.js',
path: path.resolve(appDirectory, 'dist')
path: path.resolve(appDirectory, 'dist'),
},
// ...the rest of your config
module: {
rules: [
babelLoaderConfiguration,
imageLoaderConfiguration
]
rules: [babelLoaderConfiguration, imageLoaderConfiguration],
},
resolve: {
// This will only alias the exact import "react-native"
alias: {
'react-native$': 'react-native-web',
'@caj': path.resolve(appDirectory, 'src/caj')
'@caj': path.resolve(appDirectory, 'src/caj'),
},
// If you're working on a multi-platform React Native app, web-specific
// module implementations should be written in files using the extension
// `.web.js`.
extensions: ['.web.js', '.js','.web.ts', '.ts','.web.tsx', '.tsx']
}
}
extensions: ['.web.js', '.js', '.web.ts', '.ts', '.web.tsx', '.tsx'],
},
};