minor improvement

This commit is contained in:
Djalim Simaila 2023-04-10 01:30:59 +02:00
parent d1d749290a
commit b713911e6b
11 changed files with 316 additions and 228 deletions

2
.gitignore vendored
View File

@ -36,7 +36,7 @@ local.properties
# vscode
.vscode
.history
# node.js
#
node_modules/

View File

@ -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",

View File

@ -5,76 +5,96 @@
* @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,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
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: ""
}
store.subscribe(() => {
this.setState({ token: store.getState().persistedUserReducer.token });
});
}
render(): React.ReactNode {
console.log("render app", store.getState());
console.log("app state", this.state);
return
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}></PersistGate>
<NavigationContainer>
<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 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>
</>
////////////////////////////////////////////////////////////
}</Tab.Navigator>
</NavigationContainer>
</Provider>
constructor(props: any) {
super(props);
this.state = {
token: '',
username: '',
};
store.subscribe(() => {
this.setState({token: store.getState().persistedUserReducer.token});
});
}
render(): React.ReactNode {
console.log('render app', store.getState());
console.log('app state', this.state);
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor} />
<NavigationContainer>
<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 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>
</>
)
////////////////////////////////////////////////////////////
}
</Tab.Navigator>
</NavigationContainer>
</Provider>
);
}
}
export default App;

View File

@ -1,65 +1,77 @@
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: '',
};
this.signUpFunction = this.signUpFunction.bind(this);
this.updateUsername = this.updateUsername.bind(this);
this.updatePassword = this.updatePassword.bind(this);
}
constructor(props: any) {
super(props);
this.state = {
username: '',
password: ''
}
this.signUpFunction = this.signUpFunction.bind(this);
this.updateUsername = this.updateUsername.bind(this);
this.updatePassword = this.updatePassword.bind(this);
async signUpFunction() {
const data = new FormData();
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,
},
);
const signUpJson = await signUpResponse.json();
if (signUpJson.status === 'ok') {
const signInResponse = await fetch(
'https://notifysync.simailadjalim.fr/user',
{
method: 'POST',
body: data,
},
);
const signInJson = await signInResponse.json();
if (signInJson.status === 'ok') {
this.props.store.dispatch(setUser(signInJson.token));
} else {
console.log(signInJson);
}
} else {
console.log(signUpJson);
}
}
async signUpFunction() {
const data = new FormData();
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
}
);
const signUpJson = await signUpResponse.json();
if (signUpJson.status === "ok") {
const signInResponse = await fetch(
'https://notifysync.simailadjalim.fr/user',
{
method: 'POST',
body: data
}
);
const signInJson = await signInResponse.json();
if (signInJson.status === "ok") {
this.props.store.dispatch(setUser(signInJson.token));
} else console.log(signInJson);
} else console.log(signUpJson);
}
updateUsername(username: string) {
this.setState({username: username});
}
updateUsername(username: string) {
this.setState({ username: username });
}
updatePassword(password: any) {
this.setState({password: password});
}
updatePassword(password: any) {
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} />
<Button title="S'enregistrer" onPress={this.signUpFunction} />
</View>
);
}
}
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}
/>
<Button title="S'enregistrer" onPress={this.signUpFunction} />
</View>
);
}
}

View File

@ -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);
}
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');
const sendToRemoteResponse = await fetch(
'https://notifysync.simailadjalim.fr/clipboard',
{
method: 'PUT',
body: data,
},
);
const response = await sendToRemoteResponse.json();
Toast.show(this.props.content + 'was sent to the server', Toast.SHORT);
}
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");
const sendToRemoteResponse = await fetch(
'https://notifysync.simailadjalim.fr/clipboard',
{
method: 'PUT',
body: data
}
);
const response = await sendToRemoteResponse.json();
console.log(response);
}
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()} />
<IconVector name="clipboard" size={40} onPress={() => this.onCopy()} />
</View>;
}
}
render(): JSX.Element {
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 File

@ -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>;

View File

@ -1,26 +1,47 @@
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);
}
constructor(props: any) {
super(props);
}
createClipElementLocal(content: string): JSX.Element {
return <ClipElementLocal store={this.props.store} content={content} />;
}
createClipElementLocal(content: string): JSX.Element {
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,
),
);
}
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));
return <ScrollView>{clips}</ScrollView>;
}
}
return <ScrollView>{clips}</ScrollView>;
}
}

View File

@ -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 : []
};
this.getClips();
this.props.store.subscribe(() => {
this.setState({localClips : this.props.store.getState().persistedUserReducer.clips });
});
}
constructor(props: any) {
super(props);
this.state = {
clips: [],
};
this.getClips();
this.props.store.subscribe(() => {
this.setState({
clips: this.props.store.getState().persistedUserReducer.clips,
});
});
}
getClips() {
const clips = this.props.store.getState().persistedUserReducer.clips;
this.setState({localClips: clips});
}
getClips() {
const clips = this.props.store.getState().persistedUserReducer.clips;
this.setState({clips: clips});
}
async addToLocal(){
console.log("should add clip");
this.props.store.dispatch(addToLocalStorage(await Clipboard.getString()));
}
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});
}
componentDidMount() {
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} />
{this.getSignOutBtn()}
</ScrollView>;
}
}
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}
/>
{this.getSignOutBtn()}
</ScrollView>
);
}
}

View File

@ -1,19 +1,19 @@
export function setUser(token: string) {
return {
type: "auth/connect",
payload: { token }
};
return {
type: 'auth/connect',
payload: {token},
};
}
export function clearUser() {
return {
type: "auth/disconnect"
};
return {
type: 'auth/disconnect',
};
}
export function addToLocal(content: string) {
return {
type: "local/add",
payload: {content}
};
}
return {
type: 'local/add',
payload: {content},
};
}

View File

@ -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,
}
key: 'root',
storage: AsyncStorage,
};
export const persistedUserReducer = persistReducer(persistConfig, userReducer);
export const persistedUserReducer = persistReducer(persistConfig, userReducer);

View File

@ -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
})
combineReducers({
persistedUserReducer,
}),
);
export const persistor = persistStore(store);