minor improvement
This commit is contained in:
		
							parent
							
								
									d1d749290a
								
							
						
					
					
						commit
						b713911e6b
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -36,7 +36,7 @@ local.properties | ||||
| 
 | ||||
| # vscode | ||||
| .vscode | ||||
| 
 | ||||
| .history | ||||
| # node.js | ||||
| # | ||||
| node_modules/ | ||||
|  | ||||
							
								
								
									
										15
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								package.json
									
									
									
									
									
								
							| @ -10,15 +10,23 @@ | ||||
|     "test": "jest" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@react-native-async-storage/async-storage": "^1.18.1", | ||||
|     "@react-navigation/material-bottom-tabs": "^6.2.15", | ||||
|     "@react-navigation/native": "^6.1.6", | ||||
|     "@react-navigation/native-stack": "^6.9.12", | ||||
|     "@reduxjs/toolkit": "^1.9.3", | ||||
|     "axios": "^1.3.4", | ||||
|     "expo": "^48.0.9", | ||||
|     "expo-cli": "^6.3.2", | ||||
|     "@react-navigation/native": "^6.1.6", | ||||
|     "@react-navigation/native-stack": "^6.9.12", | ||||
|     "react": "18.2.0", | ||||
|     "react-native": "0.71.4", | ||||
|     "react-native-async-storage": "^0.0.1", | ||||
|     "react-native-paper": "^5.6.0", | ||||
|     "react-native-simple-toast": "^2.0.0", | ||||
|     "react-native-vector-icons": "^9.2.0" | ||||
|     "react-native-vector-icons": "^9.2.0", | ||||
|     "react-redux": "^8.0.5", | ||||
|     "redux": "^4.2.1", | ||||
|     "redux-persist": "^6.0.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@babel/core": "^7.20.0", | ||||
| @ -28,6 +36,7 @@ | ||||
|     "@tsconfig/react-native": "^2.0.2", | ||||
|     "@types/jest": "^29.2.1", | ||||
|     "@types/react": "^18.0.24", | ||||
|     "@types/react-native": "^0.71.5", | ||||
|     "@types/react-native-vector-icons": "^6.4.13", | ||||
|     "@types/react-test-renderer": "^18.0.0", | ||||
|     "babel-jest": "^29.2.1", | ||||
|  | ||||
							
								
								
									
										80
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								src/App.tsx
									
									
									
									
									
								
							| @ -5,8 +5,8 @@ | ||||
|  * @format | ||||
|  */ | ||||
| import * as React from 'react'; | ||||
| import { NavigationContainer, StackActions } from '@react-navigation/native'; | ||||
| import type { PropsWithChildren } from 'react'; | ||||
| import {NavigationContainer, StackActions} from '@react-navigation/native'; | ||||
| import type {PropsWithChildren} from 'react'; | ||||
| import { | ||||
|   SafeAreaView, | ||||
|   ScrollView, | ||||
| @ -19,62 +19,82 @@ import { | ||||
| 
 | ||||
| import ClipViewLocal from './clip/ClipViewLocal'; | ||||
| import ClipViewRemote from './clip/ClipViewRemote'; | ||||
| import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs'; | ||||
| import { createNativeStackNavigator } from '@react-navigation/native-stack'; | ||||
| import {createMaterialBottomTabNavigator} from '@react-navigation/material-bottom-tabs'; | ||||
| import {createNativeStackNavigator} from '@react-navigation/native-stack'; | ||||
| import SignIn from './auth/SignIn'; | ||||
| import SignUp from './auth/SignUp'; | ||||
| import { Provider } from 'react-redux'; | ||||
| import { store, persistor } from './redux/store'; | ||||
| import { PersistGate } from 'redux-persist/integration/react'; | ||||
| 
 | ||||
| 
 | ||||
| import {Provider} from 'react-redux'; | ||||
| import {store, persistor} from './redux/store'; | ||||
| import {PersistGate} from 'redux-persist/integration/react'; | ||||
| 
 | ||||
| const Stack = createNativeStackNavigator(); | ||||
| const Tab = createMaterialBottomTabNavigator(); | ||||
| 
 | ||||
| class App extends React.Component<any, any> { | ||||
| 
 | ||||
|   constructor(props: any) { | ||||
|     super(props); | ||||
|     this.state = { | ||||
|             token: "", | ||||
|             username: "" | ||||
|         } | ||||
|       token: '', | ||||
|       username: '', | ||||
|     }; | ||||
|     store.subscribe(() => { | ||||
|             this.setState({ token: store.getState().persistedUserReducer.token }); | ||||
|       this.setState({token: store.getState().persistedUserReducer.token}); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   render(): React.ReactNode { | ||||
|         console.log("render app", store.getState()); | ||||
|         console.log("app state", this.state); | ||||
|         return | ||||
|     console.log('render app', store.getState()); | ||||
|     console.log('app state', this.state); | ||||
|     return ( | ||||
|       <Provider store={store}> | ||||
|             <PersistGate loading={null} persistor={persistor}></PersistGate> | ||||
|         <PersistGate loading={null} persistor={persistor} /> | ||||
|         <NavigationContainer> | ||||
|                 <Tab.Navigator>{ | ||||
|                     this.state.token === "" | ||||
|                         ? | ||||
|           <Tab.Navigator> | ||||
|             { | ||||
|               this.state.token === '' ? ( | ||||
|                 ////////////////////////////////////////////////////////////
 | ||||
|                 <> | ||||
|                             <Tab.Screen children={() => <SignIn store={store} />} name="Login" options={{ title: 'Connexion' }} /> | ||||
|                             <Tab.Screen children={() => <SignUp store={store} />} name="Register" options={{ title: 'Créer un compte' }} /> | ||||
|                   <Tab.Screen | ||||
|                     children={() => <SignIn store={store} />} | ||||
|                     name="Login" | ||||
|                     options={{title: 'Connexion'}} | ||||
|                   /> | ||||
|                   <Tab.Screen | ||||
|                     children={() => <SignUp store={store} />} | ||||
|                     name="Register" | ||||
|                     options={{title: 'Créer un compte'}} | ||||
|                   /> | ||||
|                 </> | ||||
|                         : | ||||
|               ) : ( | ||||
|                 ////////////////////////////////////////////////////////////
 | ||||
|                 <> | ||||
|                             <Tab.Screen name="Local" options={{ title: 'local' }}> | ||||
|                                 {(props) => <ClipViewLocal store={store} navigation={props.navigation} type={"local"} />} | ||||
|                   <Tab.Screen name="Local" options={{title: 'local'}}> | ||||
|                     {props => ( | ||||
|                       <ClipViewLocal | ||||
|                         store={store} | ||||
|                         navigation={props.navigation} | ||||
|                         type={'local'} | ||||
|                       /> | ||||
|                     )} | ||||
|                   </Tab.Screen> | ||||
|                             <Tab.Screen name="Remote" options={{ title: 'distant' }}> | ||||
|                                 {(props) => <ClipViewRemote store={store} navigation={props.navigation} type={"remote"} />} | ||||
|                   <Tab.Screen name="Remote" options={{title: 'distant'}}> | ||||
|                     {props => ( | ||||
|                       <ClipViewRemote | ||||
|                         store={store} | ||||
|                         navigation={props.navigation} | ||||
|                         type={'remote'} | ||||
|                       /> | ||||
|                     )} | ||||
|                   </Tab.Screen> | ||||
|                 </> | ||||
|               ) | ||||
|               ////////////////////////////////////////////////////////////
 | ||||
|                 }</Tab.Navigator> | ||||
|             } | ||||
|           </Tab.Navigator> | ||||
|         </NavigationContainer> | ||||
|       </Provider> | ||||
|     }; | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default App; | ||||
|  | ||||
| @ -1,17 +1,15 @@ | ||||
| import React from 'react'; | ||||
| import { View, Text, Button, TextInput } from 'react-native'; | ||||
| import { accessibilityProps } from 'react-native-paper/lib/typescript/src/components/MaterialCommunityIcon'; | ||||
| import { setUser } from '../redux/actions'; | ||||
| 
 | ||||
| import {View, Text, Button, TextInput} from 'react-native'; | ||||
| import {accessibilityProps} from 'react-native-paper/lib/typescript/src/components/MaterialCommunityIcon'; | ||||
| import {setUser} from '../redux/actions'; | ||||
| 
 | ||||
| export default class SignUp extends React.Component<any, any> { | ||||
| 
 | ||||
|   constructor(props: any) { | ||||
|     super(props); | ||||
|     this.state = { | ||||
|       username: '', | ||||
|             password: '' | ||||
|         } | ||||
|       password: '', | ||||
|     }; | ||||
|     this.signUpFunction = this.signUpFunction.bind(this); | ||||
|     this.updateUsername = this.updateUsername.bind(this); | ||||
|     this.updatePassword = this.updatePassword.bind(this); | ||||
| @ -19,45 +17,59 @@ export default class SignUp extends React.Component<any, any> { | ||||
| 
 | ||||
|   async signUpFunction() { | ||||
|     const data = new FormData(); | ||||
|         data.append("username", this.state.username); | ||||
|         data.append("password", this.state.password); | ||||
|     data.append('username', this.state.username); | ||||
|     data.append('password', this.state.password); | ||||
|     const signUpResponse = await fetch( | ||||
|       'https://notifysync.simailadjalim.fr/user', | ||||
|       { | ||||
|         method: 'PUT', | ||||
|                 body: data | ||||
|             } | ||||
|         body: data, | ||||
|       }, | ||||
|     ); | ||||
|     const signUpJson = await signUpResponse.json(); | ||||
|         if (signUpJson.status === "ok") { | ||||
|     if (signUpJson.status === 'ok') { | ||||
|       const signInResponse = await fetch( | ||||
|         'https://notifysync.simailadjalim.fr/user', | ||||
|         { | ||||
|           method: 'POST', | ||||
|                     body: data | ||||
|                 } | ||||
|           body: data, | ||||
|         }, | ||||
|       ); | ||||
|       const signInJson = await signInResponse.json(); | ||||
|             if (signInJson.status === "ok") { | ||||
|       if (signInJson.status === 'ok') { | ||||
|         this.props.store.dispatch(setUser(signInJson.token)); | ||||
|             } else console.log(signInJson); | ||||
|         } else console.log(signUpJson); | ||||
|       } else { | ||||
|         console.log(signInJson); | ||||
|       } | ||||
|     } else { | ||||
|       console.log(signUpJson); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   updateUsername(username: string) { | ||||
|         this.setState({ username: username }); | ||||
|     this.setState({username: username}); | ||||
|   } | ||||
| 
 | ||||
|   updatePassword(password: any) { | ||||
|         this.setState({ password: password }); | ||||
|     this.setState({password: password}); | ||||
|   } | ||||
| 
 | ||||
|   render(): React.ReactNode { | ||||
|     return ( | ||||
|       <View> | ||||
|                 <Text style={{ fontWeight: 'bold', fontSize: 30, margin: 20 }}>Créer un compte</Text> | ||||
|                 <TextInput placeholder="Nom d'utilisateur" value={this.state.username} onChangeText={this.updateUsername} /> | ||||
|                 <TextInput placeholder="Mot de Passe" value={this.state.password} onChangeText={this.updatePassword} /> | ||||
|         <Text style={{fontWeight: 'bold', fontSize: 30, margin: 20}}> | ||||
|           Créer un compte | ||||
|         </Text> | ||||
|         <TextInput | ||||
|           placeholder="Nom d'utilisateur" | ||||
|           value={this.state.username} | ||||
|           onChangeText={this.updateUsername} | ||||
|         /> | ||||
|         <TextInput | ||||
|           placeholder="Mot de Passe" | ||||
|           value={this.state.password} | ||||
|           onChangeText={this.updatePassword} | ||||
|         /> | ||||
|         <Button title="S'enregistrer" onPress={this.signUpFunction} /> | ||||
|       </View> | ||||
|     ); | ||||
|  | ||||
| @ -1,34 +1,46 @@ | ||||
| import { View, Text, Button } from 'react-native'; | ||||
| import {View, Text, Button} from 'react-native'; | ||||
| import IconVector from 'react-native-vector-icons/FontAwesome5'; | ||||
| import AClipElement from './AClipElement'; | ||||
| import Toast from 'react-native-simple-toast'; | ||||
| 
 | ||||
| export default class ClipElementLocal extends AClipElement { | ||||
| 
 | ||||
|   constructor(props: any) { | ||||
|     super(props); | ||||
|   } | ||||
| 
 | ||||
|   async sendToRemote() { | ||||
|     const data = new FormData(); | ||||
|         data.append("token", this.props.store.getState().persistedUserReducer.token); | ||||
|         data.append("content", this.props.content); | ||||
|         data.append("deviceName", "TODOChangeThisMobileDevice"); | ||||
|     data.append( | ||||
|       'token', | ||||
|       this.props.store.getState().persistedUserReducer.token, | ||||
|     ); | ||||
|     data.append('content', this.props.content); | ||||
|     data.append('deviceName', 'TODOChangeThisMobileDevice'); | ||||
|     const sendToRemoteResponse = await fetch( | ||||
|       'https://notifysync.simailadjalim.fr/clipboard', | ||||
|       { | ||||
|         method: 'PUT', | ||||
|                 body: data | ||||
|             } | ||||
|         body: data, | ||||
|       }, | ||||
|     ); | ||||
|     const response = await sendToRemoteResponse.json(); | ||||
|         console.log(response); | ||||
|     Toast.show(this.props.content + 'was sent to the server', Toast.SHORT); | ||||
|   } | ||||
| 
 | ||||
|   render(): JSX.Element { | ||||
|         return <View style={{ flex: 1, margin: 10, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}> | ||||
|             <Text style={{ fontSize: 20, }}>{this.props.content}</Text> | ||||
|             <Button title="Send to remote" onPress={() => this.sendToRemote()} /> | ||||
|     return ( | ||||
|       <View | ||||
|         style={{ | ||||
|           flex: 1, | ||||
|           margin: 10, | ||||
|           flexDirection: 'row', | ||||
|           justifyContent: 'space-between', | ||||
|           alignItems: 'center', | ||||
|         }}> | ||||
|         <Text style={{fontSize: 20}}>{this.props.content.length >28 ?this.props.content.slice(0,24)+"...":this.props.content }</Text> | ||||
|         <IconVector name="sendTo" size={40} onPress={() => this.sendToRemote()} /> | ||||
|         <IconVector name="clipboard" size={40} onPress={() => this.onCopy()} /> | ||||
|         </View>; | ||||
|       </View> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -9,11 +9,13 @@ export default class ClipElementRemote extends AClipElement { | ||||
|     } | ||||
| 
 | ||||
|     render(): JSX.Element { | ||||
|         const date= new Date(this.props.timestamp*1000); | ||||
|         console.log(this.props.timestamp*1000); | ||||
|         return <View style={{flex:1,margin:10,flexDirection:'row',justifyContent:'space-between',alignItems:'center'}}> | ||||
|             <View style={{flex:1,margin:10,flexDirection:'column'}}> | ||||
|                 <Text style={{fontSize:20,}}>{this.props.content}</Text> | ||||
|                 <Text style={{fontSize:20,}}>{this.props.content.length >28 ?this.props.content.slice(0,24)+"...":this.props.content}</Text> | ||||
|                 <Text style={{fontSize:10,}}>{this.props.deviceName}</Text> | ||||
|                 <Text style={{fontSize:10,}}>{this.props.timestamp}</Text> | ||||
|                 <Text style={{fontSize:10,}}>{date.getHours() + ":" + date.getMinutes() + ", "+ date.toDateString()}</Text> | ||||
|             </View> | ||||
|             <IconVector name="clipboard" size={40} onPress={() => this.onCopy()} /> | ||||
|         </View>; | ||||
|  | ||||
| @ -1,10 +1,9 @@ | ||||
| import React from 'react'; | ||||
| import { ScrollView } from 'react-native'; | ||||
| import {ScrollView} from 'react-native'; | ||||
| import ClipElementLocal from './ClipElementLocal'; | ||||
| import ClipElementRemote from './ClipElementRemote'; | ||||
| 
 | ||||
| export default class ClipList extends React.Component<any, any> { | ||||
| 
 | ||||
|   constructor(props: any) { | ||||
|     super(props); | ||||
|   } | ||||
| @ -13,14 +12,36 @@ export default class ClipList extends React.Component<any, any> { | ||||
|     return <ClipElementLocal store={this.props.store} content={content} />; | ||||
|   } | ||||
| 
 | ||||
|     createClipElementRemote(content: string, deviceName: string, timestamp: number): JSX.Element { | ||||
|         return <ClipElementRemote store={this.props.store} content={content} deviceName={deviceName} timestamp={timestamp} />; | ||||
|   createClipElementRemote( | ||||
|     content: string, | ||||
|     deviceName: string, | ||||
|     timestamp: number, | ||||
|   ): JSX.Element { | ||||
|     return ( | ||||
|       <ClipElementRemote | ||||
|         store={this.props.store} | ||||
|         content={content} | ||||
|         deviceName={deviceName} | ||||
|         timestamp={timestamp} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   render(): JSX.Element { | ||||
|     let clips; | ||||
|         if (this.props.type === "local") clips = this.props.clips.map((entry: any) => this.createClipElementLocal(entry.content)); | ||||
|         else clips = this.props.clips.map((entry: any) => this.createClipElementRemote(entry.content, entry.deviceName, entry.timestamp)); | ||||
|     if (this.props.type === 'local') { | ||||
|       clips = this.props.clips.map((entry: any) => | ||||
|         this.createClipElementLocal(entry.content), | ||||
|       ); | ||||
|     } else { | ||||
|       clips = this.props.clips.map((entry: any) => | ||||
|         this.createClipElementRemote( | ||||
|           entry.content, | ||||
|           entry.deviceName, | ||||
|           entry.timestamp, | ||||
|         ), | ||||
|       ); | ||||
|     } | ||||
|     return <ScrollView>{clips}</ScrollView>; | ||||
|   } | ||||
| } | ||||
| @ -1,48 +1,60 @@ | ||||
| import axios from 'axios'; | ||||
| import React from 'react'; | ||||
| import { ScrollView, Text, Button, Clipboard } from 'react-native'; | ||||
| import {ScrollView, Text, Button, Clipboard} from 'react-native'; | ||||
| import ClipList from './ClipList'; | ||||
| import AClipView from './AClipView'; | ||||
| import { addToLocal as addToLocalStorage } from '../redux/actions'; | ||||
| 
 | ||||
| import {addToLocal as addToLocalStorage} from '../redux/actions'; | ||||
| 
 | ||||
| export default class ClipViewLocal extends AClipView { | ||||
| 
 | ||||
|   constructor(props: any) { | ||||
|     super(props); | ||||
|     this.state = { | ||||
|             localClips : [] | ||||
|       clips: [], | ||||
|     }; | ||||
|     this.getClips(); | ||||
|     this.props.store.subscribe(() => { | ||||
|             this.setState({localClips : this.props.store.getState().persistedUserReducer.clips }); | ||||
|       this.setState({ | ||||
|         clips: this.props.store.getState().persistedUserReducer.clips, | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   getClips() { | ||||
|     const clips = this.props.store.getState().persistedUserReducer.clips; | ||||
|         this.setState({localClips: clips}); | ||||
|     this.setState({clips: clips}); | ||||
|   } | ||||
| 
 | ||||
|     async addToLocal(){ | ||||
|         console.log("should add clip"); | ||||
|   async addToLocal() { | ||||
|     console.log('should add clip'); | ||||
|     this.props.store.dispatch(addToLocalStorage(await Clipboard.getString())); | ||||
|   } | ||||
| 
 | ||||
|   componentDidMount() { | ||||
|         let clips; | ||||
|         clips = this.getClips(); | ||||
|         this.setState({clips: clips}); | ||||
|     this.getClips(); | ||||
|   } | ||||
| 
 | ||||
|   render(): JSX.Element { | ||||
|         let title = "Local Clipboard"; | ||||
|         let notTitle = "Remote Clipboard"; | ||||
|         return <ScrollView> | ||||
|             <Text style={{ fontWeight: 'bold', fontSize: 30, margin: 20 }}>{title}</Text> | ||||
|             <Button title="Coller depuis le presse papier" onPress={() => {this.addToLocal}} /> | ||||
|             <ClipList store={this.props.store} type={this.props.type} clips={this.state.clips} /> | ||||
|     let title = 'Local Clipboard'; | ||||
|     let notTitle = 'Remote Clipboard'; | ||||
|     return ( | ||||
|       <ScrollView> | ||||
|         <Text style={{fontWeight: 'bold', fontSize: 30, margin: 20}}> | ||||
|           {title} | ||||
|         </Text> | ||||
|         <Button | ||||
|           title="Coller depuis le presse papier" | ||||
|           onPress={() => { | ||||
|             this.addToLocal(); | ||||
|           }} | ||||
|         /> | ||||
|         <ClipList | ||||
|           store={this.props.store} | ||||
|           type={this.props.type} | ||||
|           clips={this.state.clips} | ||||
|         /> | ||||
|         {this.getSignOutBtn()} | ||||
|         </ScrollView>; | ||||
|       </ScrollView> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -1,19 +1,19 @@ | ||||
| export function setUser(token: string) { | ||||
|   return { | ||||
|         type: "auth/connect", | ||||
|         payload: { token } | ||||
|     type: 'auth/connect', | ||||
|     payload: {token}, | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function clearUser() { | ||||
|   return { | ||||
|         type: "auth/disconnect" | ||||
|     type: 'auth/disconnect', | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function addToLocal(content: string) { | ||||
|   return { | ||||
|         type: "local/add", | ||||
|         payload: {content} | ||||
|     type: 'local/add', | ||||
|     payload: {content}, | ||||
|   }; | ||||
| } | ||||
| @ -1,11 +1,11 @@ | ||||
| import AsyncStorage from '@react-native-async-storage/async-storage'; | ||||
| import { persistReducer } from 'redux-persist' | ||||
| import storage from 'redux-persist/lib/storage' | ||||
| import { userReducer } from "./reducers"; | ||||
| import {persistReducer} from 'redux-persist'; | ||||
| import storage from 'redux-persist/lib/storage'; | ||||
| import {userReducer} from './reducers'; | ||||
| 
 | ||||
| const persistConfig = { | ||||
|   key: 'root', | ||||
|   storage: AsyncStorage, | ||||
| } | ||||
| }; | ||||
| 
 | ||||
| export const persistedUserReducer = persistReducer(persistConfig, userReducer); | ||||
| @ -1,12 +1,12 @@ | ||||
| import { createStore, combineReducers } from "redux"; | ||||
| import { userReducer } from "./reducers"; | ||||
| import { persistedUserReducer } from "./persistance" | ||||
| import { persistStore } from "redux-persist"; | ||||
| import {createStore, combineReducers} from 'redux'; | ||||
| import {userReducer} from './reducers'; | ||||
| import {persistedUserReducer} from './persistance'; | ||||
| import {persistStore} from 'redux-persist'; | ||||
| 
 | ||||
| export const store = createStore( | ||||
|   combineReducers({ | ||||
|         persistedUserReducer | ||||
|     }) | ||||
|     persistedUserReducer, | ||||
|   }), | ||||
| ); | ||||
| 
 | ||||
| export const persistor = persistStore(store); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user