Merge pull request 'part4' (#3) from part4 into master

Reviewed-on: #3
pull/5/head^2
Antoine PEREDERII 1 year ago
commit 1910234f06

@ -0,0 +1,8 @@
> Why do I have a folder named ".expo" in my project?
The ".expo" folder is created when an Expo project is started using "expo start" command.
> What do the files contain?
- "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
- "settings.json": contains the server configuration that is used to serve the application manifest.
> Should I commit the ".expo" folder?
No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
Upon project creation, the ".expo" folder is already added to your ".gitignore" file.

@ -0,0 +1,3 @@
{
"devices": []
}

@ -0,0 +1 @@
module.exports = $$require_external('node:assert');

@ -0,0 +1 @@
module.exports = $$require_external('node:async_hooks');

@ -0,0 +1 @@
module.exports = $$require_external('node:buffer');

@ -0,0 +1 @@
module.exports = $$require_external('node:child_process');

@ -0,0 +1 @@
module.exports = $$require_external('node:cluster');

@ -0,0 +1 @@
module.exports = $$require_external('node:console');

@ -0,0 +1 @@
module.exports = $$require_external('node:constants');

@ -0,0 +1 @@
module.exports = $$require_external('node:crypto');

@ -0,0 +1 @@
module.exports = $$require_external('node:dgram');

@ -0,0 +1 @@
module.exports = $$require_external('node:diagnostics_channel');

@ -0,0 +1 @@
module.exports = $$require_external('node:dns');

@ -0,0 +1 @@
module.exports = $$require_external('node:domain');

@ -0,0 +1 @@
module.exports = $$require_external('node:events');

@ -0,0 +1 @@
module.exports = $$require_external('node:fs');

@ -0,0 +1 @@
module.exports = $$require_external('node:fs/promises');

@ -0,0 +1 @@
module.exports = $$require_external('node:http');

@ -0,0 +1 @@
module.exports = $$require_external('node:http2');

@ -0,0 +1 @@
module.exports = $$require_external('node:https');

@ -0,0 +1 @@
module.exports = $$require_external('node:inspector');

@ -0,0 +1 @@
module.exports = $$require_external('node:module');

@ -0,0 +1 @@
module.exports = $$require_external('node:net');

@ -0,0 +1 @@
module.exports = $$require_external('node:os');

@ -0,0 +1 @@
module.exports = $$require_external('node:path');

@ -0,0 +1 @@
module.exports = $$require_external('node:perf_hooks');

@ -0,0 +1 @@
module.exports = $$require_external('node:process');

@ -0,0 +1 @@
module.exports = $$require_external('node:punycode');

@ -0,0 +1 @@
module.exports = $$require_external('node:querystring');

@ -0,0 +1 @@
module.exports = $$require_external('node:readline');

@ -0,0 +1 @@
module.exports = $$require_external('node:repl');

@ -0,0 +1 @@
module.exports = $$require_external('node:stream');

@ -0,0 +1 @@
module.exports = $$require_external('node:string_decoder');

@ -0,0 +1 @@
module.exports = $$require_external('node:timers');

@ -0,0 +1 @@
module.exports = $$require_external('node:tls');

@ -0,0 +1 @@
module.exports = $$require_external('node:trace_events');

@ -0,0 +1 @@
module.exports = $$require_external('node:tty');

@ -0,0 +1 @@
module.exports = $$require_external('node:url');

@ -0,0 +1 @@
module.exports = $$require_external('node:util');

@ -0,0 +1 @@
module.exports = $$require_external('node:v8');

@ -0,0 +1 @@
module.exports = $$require_external('node:vm');

@ -0,0 +1 @@
module.exports = $$require_external('node:wasi');

@ -0,0 +1 @@
module.exports = $$require_external('node:worker_threads');

@ -0,0 +1 @@
module.exports = $$require_external('node:zlib');

@ -0,0 +1 @@
global.$$require_external = typeof window === "undefined" ? require : () => null;

@ -0,0 +1 @@
global.$$require_external = (moduleId) => {throw new Error(`Node.js standard library module ${moduleId} is not available in this JavaScript environment`);}

@ -0,0 +1,25 @@
import { SafeAreaView } from 'react-native'
import {StyleSheet} from 'react-native';
import NavigationBar from "./navigation/NavigationBar";
import {indigoColor} from "./assets/Theme";
import store from "./redux/store";
import React from "react";
import {Provider} from "react-redux";
export default function App() {
return (
<Provider store={store}>
<SafeAreaView style={{flex: 0, backgroundColor: 'darksalmon'}}/>
<SafeAreaView style={styles.container}>
<NavigationBar />
</SafeAreaView>
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: indigoColor
},
});

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

@ -0,0 +1,28 @@
import {StyleSheet, Text, View} from 'react-native';
import {SampleJoke} from "../model/SampleJoke";
import {CustomJoke} from "../model/CustomJoke";
import {greyColor} from "../assets/Theme";
type JokeItemProps = {
joke: (CustomJoke | SampleJoke);
};
export default function Categ(prop: JokeItemProps) {
return (
<View style={styles.bottomContainer}>
<Text style={{color:'white'}}>{prop.joke.type}</Text>
</View>
);
}
const styles = StyleSheet.create({
bottomContainer: {
backgroundColor: greyColor,
paddingVertical: 5,
paddingHorizontal: 10,
margin: 10,
borderRadius: 20,
width : 100,
alignItems : 'center'
}
});

@ -0,0 +1,22 @@
import {FlatList} from 'react-native';
import {SampleJoke} from "../model/SampleJoke";
import {CustomJoke} from "../model/CustomJoke";
import Categ from "./Categ";
type JokeListItemProps = {
jokes: (CustomJoke | SampleJoke)[];
};
export default function Categs(props: JokeListItemProps) {
return (
<FlatList showsHorizontalScrollIndicator={false} horizontal={true}
data={props.jokes}
keyExtractor={(item) => item.type.toString()}
renderItem={
({ item }: { item: CustomJoke | SampleJoke }) => (
<Categ joke={item}/>
)
}
/>
);
}

@ -0,0 +1,67 @@
import {StyleSheet, Text, View, Image} from 'react-native';
import {SampleJoke} from "../model/SampleJoke";
import {CustomJoke} from "../model/CustomJoke";
import {darksalmonColor, whiteColor, indigoColor} from "../assets/Theme";
type JokeListItemProps = {
joke: (CustomJoke | SampleJoke);
};
export default function JokeHomeSquare(prop: JokeListItemProps) {
return (
<View style={styles.container}>
<View style={styles.topBackgroundColor}>
<View style={{width: 200, height: 40, backgroundColor: darksalmonColor}}/>
</View>
<View style={styles.bottomBackgroundColor}>
<View style={{width: 200, height: 120, backgroundColor: indigoColor}}/>
</View>
<Image source={{ uri: prop.joke.image }} style={styles.image} />
<Text style={[styles.text, styles.textTitle]}>Résumé de la blague</Text>
<Text style={[styles.text, styles.textSimple]}>{prop.joke.description()}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
marginTop: 10,
marginLeft: 20,
position: "relative",
},
topBackgroundColor: {
borderTopLeftRadius: 5,
borderTopRightRadius: 5,
overflow: 'hidden',
},
bottomBackgroundColor: {
borderBottomLeftRadius: 5,
borderBottomRightRadius: 5,
overflow: 'hidden',
},
image: {
width: 120,
height: 75,
position: "absolute",
top: 5,
left: "50%",
marginLeft: -60
},
text: {
position: 'absolute',
textAlign: "center",
color:whiteColor,
paddingBottom: 7,
paddingTop: 7,
width: "100%"
},
textTitle: {
fontSize: 17,
fontWeight: "bold",
top: 90
},
textSimple: {
fontSize: 15,
top: 115
}
});

@ -1,35 +1,25 @@
import {StyleSheet, Text, View, FlatList, Image} from 'react-native'; import {StyleSheet, Text, View, Image} from 'react-native';
import {SampleJoke} from "../model/SampleJoke"; import {SampleJoke} from "../model/SampleJoke";
import {CustomJoke} from "../model/CustomJoke"; import {CustomJoke} from "../model/CustomJoke";
import {darksalmonColor, whiteColor, greyColor, indigoColor} from "../assets/Theme"; import {darksalmonColor, whiteColor, greyColor, indigoColor} from "../assets/Theme";
import {Colors} from "react-native/Libraries/NewAppScreen"; import Categ from "./Categ";
type JokeListItemProps = { type JokeListItemProps = {
jokes: CustomJoke[] | SampleJoke[]; joke: (CustomJoke | SampleJoke);
}; };
export default function JokeListItem(props: JokeListItemProps) { export default function JokeItem(prop: JokeListItemProps) {
const renderItem = ({ item }: { item: CustomJoke | SampleJoke }) => ( return (
<View style={styles.rowContainer}> <View style={styles.rowContainer}>
<View style={styles.color}/> <View style={styles.color}/>
<Image source={{ uri: item.image }} style={styles.image} /> <Image source={{ uri: prop.joke.image }} style={styles.image} />
<View style={styles.columnContainer}> <View style={styles.columnContainer}>
<Text style={styles.text}>Résumé de la blague</Text> <Text style={styles.text}>Résumé de la blague</Text>
<Text style={styles.text}>{item.description()}</Text> <Text style={styles.text}>{prop.joke.description()}</Text>
<View style={styles.bottomContainer}> <Categ joke={prop.joke}/>
<Text style={{color:'white'}}>{item.type}</Text>
</View>
</View> </View>
</View> </View>
); );
return (
<FlatList
data={props.jokes}
keyExtractor={(item) => item.id.toString()}
renderItem={renderItem}
/>
);
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({

@ -0,0 +1,22 @@
import {FlatList} from 'react-native';
import {SampleJoke} from "../model/SampleJoke";
import {CustomJoke} from "../model/CustomJoke";
import JokeItem from "./JokeItem";
type JokeListItemProps = {
jokes: (CustomJoke | SampleJoke)[];
};
export default function JokeItems(props: JokeListItemProps) {
return (
<FlatList
data={props.jokes}
keyExtractor={(item) => item.id.toString()}
renderItem={
({ item }: { item: CustomJoke | SampleJoke }) => (
<JokeItem joke={item}/>
)
}
/>
);
}

@ -0,0 +1,22 @@
import {FlatList} from 'react-native';
import {SampleJoke} from "../model/SampleJoke";
import {CustomJoke} from "../model/CustomJoke";
import JokeHomeSquare from "./JokeHomeSquare";
type JokeListItemProps = {
jokes: (CustomJoke | SampleJoke)[];
};
export default function JokesHomeSquare(props: JokeListItemProps) {
return (
<FlatList showsHorizontalScrollIndicator={false} horizontal={true}
data={props.jokes}
renderItem={
({ item }: { item: CustomJoke | SampleJoke }) => (
<JokeHomeSquare joke={item}/>
)
}
keyExtractor={(item) => item.id.toString()}
/>
);
}

@ -0,0 +1,13 @@
/**
* @file CustomJokeStub.ts
* @brief Exemple d'utilisation de la classe JokeFactory pour créer des blagues personnalisées.
*/
import { JokeFactory } from '../../model/JokeFactory';
/**
* @brief Stub de blagues personnalisées créées à l'aide de la classe JokeFactory.
* @constant
* @type {CustomJoke[]}
*/
export const customJokeStub = JokeFactory.createCustomJokes('[{"id":"premier", "type":"custom", "setup":"one", "punchline":"y\'en a pas", "image":"https://placekitten.com/200/300"},{"id":"deuxieme", "type":"custom", "setup":"two","punchline":"y\'en a pas", "image":"https://placekitten.com/200/300"},{"id":"troisieme", "type":"Default", "setup":"three","punchline":"y\'en toujours a pas ;)", "image":"https://placekitten.com/200/300"},{"id":"quatrieme", "type":"custom bro", "setup":"four","punchline":"y\'en toujours toujours ap", "image":"https://placekitten.com/200/300"}]');

@ -96,6 +96,9 @@ export abstract class Joke {
* @return {string} Un résumé de la blague. * @return {string} Un résumé de la blague.
*/ */
public summary(): string { public summary(): string {
if(this.punchline.length <= 25){
return this.punchline;
}
return this.punchline.substring(0, 24) + "..."; return this.punchline.substring(0, 24) + "...";
} }
@ -104,6 +107,6 @@ export abstract class Joke {
* @return {string} Une description textuelle de la blague. * @return {string} Une description textuelle de la blague.
*/ */
public description(): string { public description(): string {
return this.type + this.summary(); return this.type + ", " + this.summary();
} }
} }

@ -21,11 +21,12 @@ export class SampleJoke extends Joke {
* @param {string} punchline - La chute de la blague. * @param {string} punchline - La chute de la blague.
* @param {string} image - L'URL de l'image associée à la blague. * @param {string} image - L'URL de l'image associée à la blague.
*/ */
constructor(id: number, type: string, setup: string, punchline: string, image: string) { constructor(id: number, type: string, setup: string, image: string, punchline: string = "") {
super(type, setup, punchline, image); // Assuming Joke class has these properties super(type, setup, punchline, image); // Assuming Joke class has these properties
this._id = id; this._id = id;
} }
/** /**
* @brief Obtient l'identifiant de la blague d'échantillon. * @brief Obtient l'identifiant de la blague d'échantillon.
* @return {number} L'identifiant de la blague d'échantillon. * @return {number} L'identifiant de la blague d'échantillon.

@ -0,0 +1,109 @@
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import {Image, View} from 'react-native';
import HomeScreen from "../screens/HomeScreen";
import Catalogue from "../screens/Catalogue";
import Favorites from "../screens/Favorites";
import Add from "../screens/AddScreen";
import Settings from "../screens/Settings";
import {darksalmonColor, greyColor, indigoColor} from "../assets/Theme";
export default function NavigationBar() {
const BottomTabNavigator = createBottomTabNavigator();
const homeIcon = require("../assets/home_icon.png");
const listIcon = require("../assets/list_icon.png");
const addIcon = require("../assets/add_icon.png");
const favoriteIcon = require("../assets/favorite_icon.png");
const settingsIcon = require("../assets/settings_icon.png");
return (
<NavigationContainer>
<BottomTabNavigator.Navigator initialRouteName="Accueil"
screenOptions={{
headerStyle: {
backgroundColor: indigoColor,
},
headerTitleStyle: {
color:darksalmonColor,
fontSize:24,
textAlign: "center",
paddingBottom:20,
},
headerTitleAlign: 'center',
tabBarShowLabel: false,
tabBarStyle: {
backgroundColor: indigoColor,
}
}}
>
<BottomTabNavigator.Screen name="Accueil" component={HomeScreen}
options={{
tabBarIcon: ({focused}) => (
<Image
source={homeIcon}
style={{
width: 30, height: 30,
tintColor: focused ? darksalmonColor : greyColor,
}}
/>
)
}}/>
<BottomTabNavigator.Screen name="Catalogue" component={Catalogue}
options={{
tabBarIcon: ({focused}) => (
<Image
source={listIcon}
style={{
width: 30, height: 30,
tintColor: focused ? darksalmonColor : greyColor,
}}
/>
)
}}/>
<BottomTabNavigator.Screen name="Ajouter" component={Add}
options={{
tabBarIcon: ({focused}) => (
<View style={{backgroundColor: greyColor, borderRadius: 5, padding: 10}}>
<Image
source={addIcon}
style={{
width: 20, height: 20,
tintColor: focused ? darksalmonColor : "black",
}}
/>
</View>
)
}}/>
<BottomTabNavigator.Screen name="Favoris" component={Favorites}
options={{
tabBarIcon: ({focused}) => (
<Image
source={favoriteIcon}
style={{
width: 30, height: 30,
tintColor: focused ? darksalmonColor : greyColor,
}}
/>
)
}}/>
<BottomTabNavigator.Screen name="Paramètres" component={Settings}
options={{
tabBarIcon: ({focused}) => (
<Image
source={settingsIcon}
style={{
width: 30, height: 30,
tintColor: focused ? darksalmonColor : greyColor,
}}
/>
)
}}/>
</BottomTabNavigator.Navigator>
</NavigationContainer>
)
}

@ -0,0 +1,20 @@
// import {createStackNavigator} from "@react-navigation/stack";
// import Accueil from "../screens/HomeScreen";
// import Catalogue from "../screens/Catalogue";
// import Add from "../screens/AddScreen";
// import Favorites from "../screens/Favorites";
// import Settings from "../screens/Settings";
//
//
// export default function StackNavigation() {
// const Stack = createStackNavigator();
// return (
// <Stack.Navigator initialRouteName="Home">
// <Stack.Screen name="Accueil" component={Accueil}/>
// <Stack.Screen name="Catalogue" component={Catalogue}/>
// <Stack.Screen name="Ajouter" component={Add}/>
// <Stack.Screen name="Favoris" component={Favorites}/>
// <Stack.Screen name="Paramètres" component={Settings}/>
// </Stack.Navigator>
// )
// }

@ -10,12 +10,16 @@
"dependencies": { "dependencies": {
"@react-navigation/bottom-tabs": "^6.5.11", "@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.9", "@react-navigation/native": "^6.1.9",
"@reduxjs/toolkit": "^2.2.1",
"@types/react": "~18.2.45", "@types/react": "~18.2.45",
"expo": "~50.0.3", "expo": "~50.0.3",
"expo-status-bar": "~1.11.1", "expo-status-bar": "~1.11.1",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.73.2", "react-native": "0.73.2",
"react-native-gesture-handler": "^2.14.1", "react-native-gesture-handler": "^2.14.1",
"react-native-safe-area-context": "^4.9.0",
"react-redux": "^9.1.0",
"redux": "^5.0.1",
"typescript": "^5.3.0" "typescript": "^5.3.0"
}, },
"devDependencies": { "devDependencies": {
@ -5958,6 +5962,29 @@
"nanoid": "^3.1.23" "nanoid": "^3.1.23"
} }
}, },
"node_modules/@reduxjs/toolkit": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.1.tgz",
"integrity": "sha512-8CREoqJovQW/5I4yvvijm/emUiCCmcs4Ev4XPWd4mizSO+dD3g5G6w34QK5AGeNrSH7qM8Fl66j4vuV7dpOdkw==",
"dependencies": {
"immer": "^10.0.3",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"reselect": "^5.0.1"
},
"peerDependencies": {
"react": "^16.9.0 || ^17.0.0 || ^18",
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-redux": {
"optional": true
}
}
},
"node_modules/@segment/loosely-validate-event": { "node_modules/@segment/loosely-validate-event": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
@ -6065,6 +6092,11 @@
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="
}, },
"node_modules/@types/use-sync-external-store": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
},
"node_modules/@types/yargs": { "node_modules/@types/yargs": {
"version": "17.0.32", "version": "17.0.32",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
@ -8374,6 +8406,15 @@
"node": ">=16.x" "node": ">=16.x"
} }
}, },
"node_modules/immer": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz",
"integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
}
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
@ -11487,10 +11528,9 @@
} }
}, },
"node_modules/react-native-safe-area-context": { "node_modules/react-native-safe-area-context": {
"version": "4.8.2", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.8.2.tgz", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.9.0.tgz",
"integrity": "sha512-ffUOv8BJQ6RqO3nLml5gxJ6ab3EestPiyWekxdzO/1MQ7NF8fW1Mzh1C5QE9yq573Xefnc7FuzGXjtesZGv7cQ==", "integrity": "sha512-/OJD9Pb8IURyvn+1tWTszWPJqsbZ4hyHBU9P0xhOmk7h5owSuqL0zkfagU0pg7Vh0G2NKQkaPpUKUMMCUMDh/w==",
"peer": true,
"peerDependencies": { "peerDependencies": {
"react": "*", "react": "*",
"react-native": "*" "react-native": "*"
@ -11531,6 +11571,32 @@
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
} }
}, },
"node_modules/react-redux": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.0.tgz",
"integrity": "sha512-6qoDzIO+gbrza8h3hjMA9aq4nwVFCKFtY2iLxCtVT38Swyy2C/dJCGBXHeHLtx6qlg/8qzc2MrhOeduf5K32wQ==",
"dependencies": {
"@types/use-sync-external-store": "^0.0.3",
"use-sync-external-store": "^1.0.0"
},
"peerDependencies": {
"@types/react": "^18.2.25",
"react": "^18.0",
"react-native": ">=0.69",
"redux": "^5.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"react-native": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@ -11592,6 +11658,19 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/redux": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
},
"node_modules/redux-thunk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
"peerDependencies": {
"redux": "^5.0.0"
}
},
"node_modules/regenerate": { "node_modules/regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -11703,6 +11782,11 @@
"path-parse": "^1.0.5" "path-parse": "^1.0.5"
} }
}, },
"node_modules/reselect": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz",
"integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg=="
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.8", "version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@ -12812,6 +12896,14 @@
"react": ">=16.8" "react": ">=16.8"
} }
}, },
"node_modules/use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

@ -12,12 +12,16 @@
"dependencies": { "dependencies": {
"@react-navigation/bottom-tabs": "^6.5.11", "@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.9", "@react-navigation/native": "^6.1.9",
"@reduxjs/toolkit": "^2.2.1",
"@types/react": "~18.2.45", "@types/react": "~18.2.45",
"expo": "~50.0.3", "expo": "~50.0.3",
"expo-status-bar": "~1.11.1", "expo-status-bar": "~1.11.1",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.73.2", "react-native": "0.73.2",
"react-native-gesture-handler": "^2.14.1", "react-native-gesture-handler": "^2.14.1",
"react-native-safe-area-context": "^4.9.0",
"react-redux": "^9.1.0",
"redux": "^5.0.1",
"typescript": "^5.3.0" "typescript": "^5.3.0"
}, },
"devDependencies": { "devDependencies": {

@ -0,0 +1,20 @@
import {CustomJoke} from "../../model/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
export enum ActionType {
FETCH_JOKES = 'FETCH_JOKE',
}
interface actionFetch {
type: ActionType.FETCH_JOKES;
payload: (CustomJoke | SampleJoke)[];
}
export type Action = actionFetch;
export const setJokesList = (jokesList: (CustomJoke | SampleJoke)[]) => {
return {
type: ActionType.FETCH_JOKES,
payload: jokesList,
};
}

@ -0,0 +1,27 @@
import {CustomJoke} from "../../model/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
import {Action} from "redux";
import {ActionType} from "../actions/JokeAction";
interface State {
jokes: (CustomJoke | SampleJoke)[];
favoriteJokes: (CustomJoke | SampleJoke)[],
}
const initialState = {
jokes: [],
favoriteJokes: [],
}
const appReducer = (state: State = initialState, action: Action) => {
switch (action.type) {
case ActionType.FETCH_JOKES:
// @ts-ignore
return {...state, jokes: action.payload};
//case ActionType....
default:
return state;
}
}
export default appReducer;

@ -0,0 +1,18 @@
import {configureStore} from '@reduxjs/toolkit'
import appReducer from './reducers/jokeReducer';
// Reference here all your application reducers
const reducer = {
appReducer: appReducer,
}
// @ts-ignore
const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false
})
},);
export default store;

@ -0,0 +1,23 @@
//Define your action creators that will be responsible for asynchronous operations
import {CustomJoke} from "../../model/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
import {setJokesList} from "../actions/JokeAction";
export const getSampleJokesList = () => {
//In order to use await your callback must be asynchronous using async keyword.
return async dispatch => {
//Then perform your asynchronous operations.
try {
//Have it first fetch data from our starwars url.
const jokesPromise = await fetch('https://iut-weather-api.azurewebsites.net/jokes/samples');
//Then use the json method to get json data from api/
const jokesListJson = await jokesPromise.json();
const jokesList: SampleJoke[] = jokesListJson.map(elt => new SampleJoke(elt["id"], elt["type"], elt["setup"], elt["image"]));
dispatch(setJokesList(jokesList));
} catch (error) {
console.log('Error---------', error);
//You can dispatch to another action if you want to display an error message in the application
//dispatch(fetchDataRejected(error))
}
}
}

@ -0,0 +1,23 @@
//Define your action creators that will be responsible for asynchronous operations
import {CustomJoke} from "../../model/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
import {setJokesList} from "../actions/JokeAction";
export const getLastSampleJokesList = () => {
//In order to use await your callback must be asynchronous using async keyword.
return async dispatch => {
//Then perform your asynchronous operations.
try {
//Have it first fetch data from our starwars url.
const jokesPromise = await fetch('https://iut-weather-api.azurewebsites.net/jokes/lasts');
//Then use the json method to get json data from api/
const jokesListJson = await jokesPromise.json();
const jokesList: SampleJoke[] = jokesListJson.map(elt => new SampleJoke(elt["id"], elt["type"], elt["setup"], elt["image"]));
dispatch(setJokesList(jokesList));
} catch (error) {
console.log('Error---------', error);
//You can dispatch to another action if you want to display an error message in the application
//dispatch(fetchDataRejected(error))
}
}
}

@ -0,0 +1,35 @@
import { customJokeStub } from '../data/stub/CustomJokeStub';
import { sampleJokeStub } from '../data/stub/SampleJokeStub';
import JokeItems from "../components/JokeItems";
import '../types/extension';
import {useDispatch, useSelector} from "react-redux";
import {StyleSheet, View} from "react-native";
import {purpleColor} from "../assets/Theme";
import {getSampleJokesList} from "../redux/thunk/CatalogueSampleJokeThunk";
import {useEffect} from "react";
export default function Catalogue() {
// const allJokes = [...customJokeStub, ...sampleJokeStub];
// @ts-ignore
const allJokes = useSelector(state => state.appReducer.jokes);
const dispatch = useDispatch();
useEffect(() => {
const loadJokes = async () => {
// @ts-ignore
await dispatch(getSampleJokesList());
};
loadJokes();
}, [dispatch]);
return (
<View style={styles.container}>
<JokeItems jokes={allJokes}/>
</View>
)
};
const styles = StyleSheet.create({
container: {
backgroundColor: purpleColor
}
});

@ -0,0 +1,35 @@
import { customJokeStub } from '../data/stub/CustomJokeStub';
import { sampleJokeStub } from '../data/stub/SampleJokeStub';
import JokeItems from "../components/JokeItems";
import '../types/extension';
import {StyleSheet, View} from "react-native";
import {purpleColor} from "../assets/Theme";
import {useDispatch, useSelector} from "react-redux";
import {useEffect} from "react";
import {getSampleJokesList} from "../redux/thunk/CatalogueSampleJokeThunk";
export default function Catalogue() {
// const allJokes = [...customJokeStub, ...sampleJokeStub];
// @ts-ignore
const allJokes = useSelector(state => state.appReducer.jokes);
const dispatch = useDispatch();
useEffect(() => {
const loadJokes = async () => {
// @ts-ignore
await dispatch(getSampleJokesList());
};
loadJokes();
}, [dispatch]);
return (
<View style={styles.container}>
<JokeItems jokes={allJokes}/>
</View>
)
};
const styles = StyleSheet.create({
container: {
backgroundColor: purpleColor
}
});

@ -0,0 +1,21 @@
import { customJokeStub } from '../data/stub/CustomJokeStub';
import { sampleJokeStub } from '../data/stub/SampleJokeStub';
import JokeItems from "../components/JokeItems";
import '../types/extension';
import {StyleSheet, View} from "react-native";
import {purpleColor} from "../assets/Theme";
export default function Catalogue() {
const allJokes = [...customJokeStub, ...sampleJokeStub];
return (
<View style={styles.container}>
<JokeItems jokes={allJokes}/>
</View>
)
};
const styles = StyleSheet.create({
container: {
backgroundColor: purpleColor
}
});

@ -0,0 +1,95 @@
import {Image, StyleSheet, Text, View} from 'react-native';
import '../types/extension';
import {darksalmonColor, purpleColor, whiteColor} from "../assets/Theme";
import JokesHomeSquare from "../components/JokesHomeSquare";
import Categs from "../components/Categs";
import {useDispatch, useSelector} from "react-redux";
import {useEffect} from "react";
import {getLastSampleJokesList} from "../redux/thunk/RecentsJokesThunk";
export default function Catalogue() {
// @ts-ignore
const allJokes = useSelector(state => state.appReducer.jokes);
const dispatch = useDispatch();
useEffect(() => {
const loadJokes = async () => {
// @ts-ignore
await dispatch(getLastSampleJokesList());
};
loadJokes();
}, [dispatch]);
return (
<>
<View style={styles.container}>
<View style={styles.top}>
<Image style={styles.cat} source={require('../assets/logo.png')}/>
<Text style={styles.textAccueil}>Chat C'est Drôle</Text>
</View>
<View style={styles.Jokes}>
<Text style={styles.textLastJokes}>Dernières blagues</Text>
<JokesHomeSquare jokes={allJokes} />
</View>
<View style={styles.bestCateg}>
<View style={styles.horizBestCateg}>
<Text style={styles.textBestCateg}>Top Categories</Text>
<Image source={require("../assets/fire_icon.png")}/>
</View>
<View style={styles.horizChip}>
<Categs jokes={allJokes}/>
</View>
</View>
</View>
</>
)
};
const styles = StyleSheet.create({
container: {
backgroundColor: purpleColor,
flex:1,
},
top: {
alignItems: "center",
},
cat: {
height:160,
width: 160
},
textAccueil: {
fontSize: 25,
color: darksalmonColor,
fontWeight: "bold",
},
Jokes: {
display:"flex",
flexDirection:"column",
marginTop: 50,
marginLeft: 20,
},
scrollList: {
alignItems: "center"
},
textLastJokes: {
color: whiteColor,
fontSize: 20,
fontWeight: "bold",
},
bestCateg: {
marginTop: 30,
marginLeft: 20,
},
horizBestCateg: {
flexDirection: "row",
},
textBestCateg: {
color: whiteColor,
fontSize: 20,
fontWeight: "bold",
},
horizChip: {
flexDirection: "row",
marginTop: 30,
}
});

@ -0,0 +1,21 @@
import { customJokeStub } from '../data/stub/CustomJokeStub';
import { sampleJokeStub } from '../data/stub/SampleJokeStub';
import JokeItems from "../components/JokeItems";
import '../types/extension';
import {StyleSheet, View} from "react-native";
import {purpleColor} from "../assets/Theme";
export default function Catalogue() {
const allJokes = [...customJokeStub, ...sampleJokeStub];
return (
<View style={styles.container}>
<JokeItems jokes={allJokes}/>
</View>
)
};
const styles = StyleSheet.create({
container: {
backgroundColor: purpleColor
}
});

@ -1,35 +0,0 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# dependencies
node_modules/
# Expo
.expo/
dist/
web-build/
# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
# Metro
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo

@ -1,7 +0,0 @@
import HomePage from './screens/HomeScreen';
export default function App() {
return (
<HomePage />
);
}

@ -1,13 +0,0 @@
/**
* @file CustomJokeStub.ts
* @brief Exemple d'utilisation de la classe JokeFactory pour créer des blagues personnalisées.
*/
import { JokeFactory } from '../../model/JokeFactory';
/**
* @brief Stub de blagues personnalisées créées à l'aide de la classe JokeFactory.
* @constant
* @type {CustomJoke[]}
*/
export const customJokeStub = JokeFactory.createCustomJokes('[{"id":"1", "type":"custom", "setup":"one", "punchline":"y\'en a pas", "image":"https://placekitten.com/200/300"},{"id":"2", "type":"custom", "setup":"two","punchline":"y\'en a pas", "image":"https://placekitten.com/200/300"},{"id":"3", "type":"Default", "setup":"three","punchline":"y\'en toujours a pas ;)", "image":"https://placekitten.com/200/300"},{"id":"4", "type":"custom bro", "setup":"four","punchline":"y\'en toujours toujours ap", "image":"https://placekitten.com/200/300"}]');

@ -1,44 +0,0 @@
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { customJokeStub } from '../data/stub/CustomJokeStub';
import { sampleJokeStub } from '../data/stub/SampleJokeStub';
import { SafeAreaView } from 'react-native'
import JokeListItem from "../components/JokeListItem";
import '../types/extension';
import {darksalmonColor, indigoColor, purpleColor} from "../assets/Theme";
export default function HomeScreen() {
const allJokes = [...customJokeStub, ...sampleJokeStub];
return (
<>
<SafeAreaView style={styles.topSafeArea}/>
<SafeAreaView style={styles.container}>
<View style={styles.title}>
<Text style={styles.centered}>Catalogue</Text>
</View>
<StatusBar style="light" />
<JokeListItem jokes={allJokes}/>
</SafeAreaView>
</>
)
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: purpleColor,
},
centered: {
color:darksalmonColor,
fontSize:24,
textAlign: "center",
paddingBottom:20,
},
title: {
backgroundColor: indigoColor
},
topSafeArea: {
flex: 0,
backgroundColor: indigoColor
}
});

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save