Compare commits
48 Commits
@ -0,0 +1,22 @@
|
|||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
|
image: hub.codefirst.iut.uca.fr/camille.petitalot/drone-sonarplugin-reactnative:latest
|
||||||
|
commands:
|
||||||
|
- cd JokesApp
|
||||||
|
- npm install
|
||||||
|
|
||||||
|
- name : sonar
|
||||||
|
image : hub.codefirst.iut.uca.fr/camille.petitalot/drone-sonarplugin-reactnative:latest
|
||||||
|
environment:
|
||||||
|
sonar_host: https://codefirst.iut.uca.fr/sonar/
|
||||||
|
sonar_token:
|
||||||
|
from_secret: SECRET_SONAR_LOGIN
|
||||||
|
project_key: JokesAppSonar
|
||||||
|
commands:
|
||||||
|
- cd JokesApp
|
||||||
|
- npm install
|
||||||
|
- npm run test
|
||||||
|
- sonar-scanner -Dsonar.projectKey=$${project_key} -Dsonar.sources=. -Dsonar.host.url=$${sonar_host} -Dsonar.login=$${sonar_token} -Dsonar.javascript.lcov.reportPaths=/lcov.info -Dsonar.exclusions=/coverage//*,/tests/*/
|
@ -0,0 +1,5 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Tp_ReactNative.iml" filepath="$PROJECT_DIR$/.idea/Tp_ReactNative.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -1 +1,75 @@
|
|||||||
export const indigo = "rgba(74, 74, 104, 1)"
|
import {DarkTheme, Theme, useTheme} from "@react-navigation/native";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import DefaultTheme from "@react-navigation/native/src/theming/DefaultTheme";
|
||||||
|
import {useColorScheme} from "react-native";
|
||||||
|
|
||||||
|
export const indigo = "rgba(14, 14, 44, 1)";
|
||||||
|
export const purpleColor = "rgba(74, 74, 104, 1)";
|
||||||
|
export const darksalmonColor = "rgba(233, 150, 122, 1)";
|
||||||
|
export const greyColor = "rgba(140, 140, 161, 1)";
|
||||||
|
export const whiteColor = "rgba(239, 239, 253, 1)";
|
||||||
|
|
||||||
|
export const blackColor = "rgba(0, 0, 0, 1)";
|
||||||
|
|
||||||
|
|
||||||
|
export default function usePersonalTheme() {
|
||||||
|
|
||||||
|
|
||||||
|
useTheme()
|
||||||
|
const theme = React.useContext(ThemeContext);
|
||||||
|
const [isDark, setIsDark] = useState(false);
|
||||||
|
|
||||||
|
if (isDark) {
|
||||||
|
theme.dark = true;
|
||||||
|
theme.colors = MyDarkTheme.colors;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
theme.dark = false;
|
||||||
|
theme.colors = MyLightTheme.colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//const isDark = false;
|
||||||
|
|
||||||
|
|
||||||
|
const MyDarkTheme: Theme = {
|
||||||
|
dark: true,
|
||||||
|
colors: {
|
||||||
|
primary: indigo,
|
||||||
|
background: purpleColor,
|
||||||
|
card: darksalmonColor,
|
||||||
|
text: whiteColor,
|
||||||
|
border: whiteColor,
|
||||||
|
notification: whiteColor,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const MyLightTheme: Theme = {
|
||||||
|
dark: false,
|
||||||
|
colors: {
|
||||||
|
primary: whiteColor,
|
||||||
|
background: greyColor,
|
||||||
|
card: '',
|
||||||
|
text: blackColor,
|
||||||
|
border: blackColor,
|
||||||
|
notification: blackColor,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const ThemeContext = React.createContext<Theme>(MyDarkTheme);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 604 B |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 603 B |
After Width: | Height: | Size: 744 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 502 B |
After Width: | Height: | Size: 705 B |
After Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 805 B |
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,163 @@
|
|||||||
|
import {Button, Image, StyleSheet, Text, TouchableOpacity, View} from "react-native";
|
||||||
|
import {darksalmonColor, greyColor, indigo, purpleColor, whiteColor} from "../Theme";
|
||||||
|
import React, {useState} from "react";
|
||||||
|
import {SampleJoke} from "../model/SampleJoke";
|
||||||
|
import {Joke} from "../model/Joke";
|
||||||
|
import {CustomJoke} from "../model/CustomJoke";
|
||||||
|
import {removeFavoriteJoke, storeFavoriteJoke, useAppDispatch, useAppSelector} from "../redux/store";
|
||||||
|
|
||||||
|
type DetailJokeProps = {
|
||||||
|
item: CustomJoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function DetailJoke(props: DetailJokeProps) {
|
||||||
|
|
||||||
|
const favoriteJokes = useAppSelector(state => state.customReducer.favoriteJokes) as [CustomJoke, SampleJoke];
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const isFav : boolean = favoriteJokes.some(it => it.id == props.item.id )
|
||||||
|
const [isActivated, setIsActivated] = useState(isFav);
|
||||||
|
const [isActivated2, setIsActivated2] = useState(false);
|
||||||
|
|
||||||
|
function toggleActivation() {
|
||||||
|
setIsActivated(!isActivated);
|
||||||
|
if (isActivated) {
|
||||||
|
console.log("Joke retirée des favoris");
|
||||||
|
dispatch(removeFavoriteJoke(props.item));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dispatch(storeFavoriteJoke(props.item));
|
||||||
|
console.log("Joke ajoutée aux favoris");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function toggleActivation2() {
|
||||||
|
setIsActivated2(!isActivated2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.listItem}>
|
||||||
|
<Image style={styles.imageSettings} source={{
|
||||||
|
uri: props.item.image}}/>
|
||||||
|
<View style={styles.chip}>
|
||||||
|
<Text >Type : {props.item.type}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.contentList}>
|
||||||
|
<Text style={styles.contentSummary}>{props.item.description}</Text>
|
||||||
|
</View >
|
||||||
|
<View style={styles.buttons}>
|
||||||
|
<TouchableOpacity style={styles.button1} onPress={toggleActivation}>
|
||||||
|
<Image source={isActivated ? require('../assets/plain_favorite_icon.png') : require('../assets/favorite_icon.png')} style={styles.img1} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity style={styles.button2} onPress={toggleActivation2}>
|
||||||
|
<Image source={isActivated2 ? require('../assets/eye_icon.png') : require('../assets/eye_off_icon.png')} style={styles.img2} />
|
||||||
|
<Text style={styles.bt2text}>LA CHUTE</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
{isActivated2 ? <Text style={styles.contentSummary}>{props.item.punchline}</Text> : null}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
|
||||||
|
titleResume: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 20,
|
||||||
|
color: whiteColor,
|
||||||
|
},
|
||||||
|
listItem: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
margin: 10,
|
||||||
|
height : '80%',
|
||||||
|
borderRadius: 20,
|
||||||
|
borderColor: whiteColor,
|
||||||
|
backgroundColor : indigo,
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
imageSettings: {
|
||||||
|
flex: 1,
|
||||||
|
width: '85%',
|
||||||
|
height: 100,
|
||||||
|
margin :30,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
contentList :{
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
chip: {
|
||||||
|
borderRadius: 16,
|
||||||
|
backgroundColor: whiteColor,
|
||||||
|
padding: 5,
|
||||||
|
margin: 5,
|
||||||
|
marginLeft: 30,
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
},
|
||||||
|
contentSummary: {
|
||||||
|
color: greyColor,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
fontSize: 16,
|
||||||
|
textAlign: 'left',
|
||||||
|
margin: 10,
|
||||||
|
marginLeft: 20,
|
||||||
|
|
||||||
|
},
|
||||||
|
buttons:
|
||||||
|
{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
button1:{
|
||||||
|
marginRight: 20,
|
||||||
|
borderRadius: 10,
|
||||||
|
width: 100,
|
||||||
|
height: 50,
|
||||||
|
alignItems: "center",
|
||||||
|
borderColor: '#ffffff',
|
||||||
|
borderWidth: 1
|
||||||
|
},
|
||||||
|
button2:{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "center",
|
||||||
|
marginRight: 30,
|
||||||
|
borderRadius: 10,
|
||||||
|
width: 140,
|
||||||
|
height: 50,
|
||||||
|
alignItems: "center",
|
||||||
|
borderColor: whiteColor,
|
||||||
|
borderWidth: 1,
|
||||||
|
backgroundColor: darksalmonColor,
|
||||||
|
},
|
||||||
|
|
||||||
|
img1:{
|
||||||
|
justifyContent: "center",
|
||||||
|
tintColor: darksalmonColor,
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
img2: {
|
||||||
|
tintColor: whiteColor,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
alignSelf: "center",
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
bt2text: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: whiteColor,
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,77 @@
|
|||||||
|
import {Image, ImageBackground, StyleSheet, Text, View} from "react-native";
|
||||||
|
import React from "react";
|
||||||
|
import {Joke} from "../model/Joke";
|
||||||
|
import * as url from "url";
|
||||||
|
import {greyColor, indigo, purpleColor} from "../Theme";
|
||||||
|
|
||||||
|
type JokeListItemProps = {
|
||||||
|
item: Joke;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function HorizontalListJokeComponent(props: JokeListItemProps) {
|
||||||
|
return (
|
||||||
|
<View style={styles.listItem}>
|
||||||
|
<View style={styles.rectangle}></View>
|
||||||
|
<Image style={styles.imageSettings} source={{
|
||||||
|
uri: props.item.image}}/>
|
||||||
|
<View style={styles.contentList}>
|
||||||
|
<Text style={styles.titleResume}>Résumé de la blague</Text>
|
||||||
|
<Text style={styles.contentSummary}>{props.item.summary}</Text>
|
||||||
|
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
|
||||||
|
titleResume: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 20,
|
||||||
|
color: "white",
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
listItem: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: indigo,
|
||||||
|
margin: 10,
|
||||||
|
height: 270,
|
||||||
|
width: 250,
|
||||||
|
borderRadius: 5,
|
||||||
|
},
|
||||||
|
imageSettings: {
|
||||||
|
width: '75%',
|
||||||
|
height: 150,
|
||||||
|
position: 'absolute',
|
||||||
|
margin: 5,
|
||||||
|
},
|
||||||
|
contentList :{
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
alignItems: 'center',
|
||||||
|
margin: 30,
|
||||||
|
},
|
||||||
|
chip: {
|
||||||
|
borderRadius: 16,
|
||||||
|
backgroundColor: greyColor,
|
||||||
|
padding: 5,
|
||||||
|
marginTop: 5,
|
||||||
|
alignSelf: 'center',
|
||||||
|
},
|
||||||
|
rectangle: {
|
||||||
|
borderRadius: 4,
|
||||||
|
flexShrink: 0,
|
||||||
|
width: "100%",
|
||||||
|
height: "20%",
|
||||||
|
backgroundColor: 'darksalmon',
|
||||||
|
},
|
||||||
|
contentSummary: {
|
||||||
|
textAlign: 'center',
|
||||||
|
color: "white",
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
import {Joke} from "../model/Joke";
|
||||||
|
import {Image, StyleSheet, Text, View} from "react-native";
|
||||||
|
import React from "react";
|
||||||
|
import {greyColor, indigo} from "../Theme";
|
||||||
|
import {Categorie} from "../model/Categorie";
|
||||||
|
|
||||||
|
type ListAllCategories = {
|
||||||
|
item: Categorie;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function ListAllCategories(props: ListAllCategories) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.listItem}>
|
||||||
|
<View style={styles.chip}>
|
||||||
|
<Text>{props.item.name}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
listItem: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
chip: {
|
||||||
|
borderRadius: 16,
|
||||||
|
backgroundColor: greyColor,
|
||||||
|
padding: 5,
|
||||||
|
marginTop: 5,
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,24 @@
|
|||||||
|
import {Joke} from "./Joke";
|
||||||
|
|
||||||
|
export class Categorie{
|
||||||
|
|
||||||
|
private _name : string;
|
||||||
|
|
||||||
|
private _number : number;
|
||||||
|
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get number(): number {
|
||||||
|
return this._number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(name :string, number :number) {
|
||||||
|
this._name = name;
|
||||||
|
this._number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import {Categorie} from "./Categorie";
|
||||||
|
|
||||||
|
export class CategorieFactory {
|
||||||
|
public static createCategories(jsonArray: string): Categorie[] {
|
||||||
|
let array = [];
|
||||||
|
let json = JSON.parse(jsonArray);
|
||||||
|
json.forEach(function (categorie) {
|
||||||
|
array.push(new Categorie(categorie.name, categorie.number));
|
||||||
|
});
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
import React, {useContext, useEffect, useState} from "react";
|
||||||
|
import {DarkTheme, DefaultTheme, NavigationContainer, Theme, useTheme} from "@react-navigation/native";
|
||||||
|
import {createBottomTabNavigator} from "@react-navigation/bottom-tabs";
|
||||||
|
import {ListJokeScreen} from "../screens/ListJokeScreen";
|
||||||
|
import {Image, StyleSheet, useColorScheme, View} from "react-native";
|
||||||
|
import usePersonalTheme, {darksalmonColor, greyColor, indigo, purpleColor} from "../Theme";
|
||||||
|
import {AccueilScreen} from "../screens/AccueilScreen";
|
||||||
|
import {AddJokeScreen} from "../screens/AddJokeScreen";
|
||||||
|
import {SettingsScreen} from "../screens/SettingsScreen";
|
||||||
|
import {JokeListItems} from "../components/ListeJokeComponent";
|
||||||
|
import {CatalogueScreen, FavoriteScreen} from "./StackNavigation";
|
||||||
|
const homeIcon = require("../assets/home_icon.png");
|
||||||
|
const listIcon = require("../assets/list_icon.png");
|
||||||
|
const addIcon = require("../assets/add_icon.png");
|
||||||
|
const favIcon = require("../assets/favorite_icon.png");
|
||||||
|
const setIcon = require("../assets/settings_icon.png");
|
||||||
|
import store, {getTheme, storeTheme} from "../redux/store";
|
||||||
|
|
||||||
|
|
||||||
|
export function Navigation(){
|
||||||
|
const BottomTabNavigator = createBottomTabNavigator();
|
||||||
|
|
||||||
|
const [themes, setThemes] = useState<Theme>(DefaultTheme);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchTheme = async () => {
|
||||||
|
const theme = await getTheme();
|
||||||
|
setThemes(theme);
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchTheme();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (themes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<NavigationContainer theme={ themes.dark === false ? DefaultTheme : DarkTheme} >
|
||||||
|
<BottomTabNavigator.Navigator initialRouteName="Home" screenOptions={{
|
||||||
|
headerTitleStyle: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: themes.colors.text,
|
||||||
|
},
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: indigo,
|
||||||
|
},
|
||||||
|
tabBarShowLabel: false,
|
||||||
|
tabBarStyle: styles.top,
|
||||||
|
}}>
|
||||||
|
<BottomTabNavigator.Screen name="Accueil" component={AccueilScreen}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused}) => (
|
||||||
|
<Image
|
||||||
|
source={homeIcon}
|
||||||
|
style={{ tintColor: focused ? darksalmonColor : purpleColor }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}}/>
|
||||||
|
<BottomTabNavigator.Screen name="Catalogue" component={CatalogueScreen}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused}) => (
|
||||||
|
<Image source={listIcon}
|
||||||
|
style={{ tintColor: focused ? darksalmonColor : purpleColor }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
headerShown: false,
|
||||||
|
}}/>
|
||||||
|
<BottomTabNavigator.Screen name="Ajouter" component={AddJokeScreen}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused}) => (
|
||||||
|
<View style={styles.addJoke}>
|
||||||
|
<Image source={addIcon}
|
||||||
|
style={{ tintColor: focused ? darksalmonColor : purpleColor }}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
|
||||||
|
}}/>
|
||||||
|
|
||||||
|
<BottomTabNavigator.Screen name="Favoris" component={FavoriteScreen}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused}) => (
|
||||||
|
<Image source={favIcon}
|
||||||
|
style={{ tintColor: focused ? darksalmonColor : purpleColor }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
headerShown: false,
|
||||||
|
}}/>
|
||||||
|
<BottomTabNavigator.Screen name="Paramètres" component={SettingsScreen}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused}) => (
|
||||||
|
<Image source={setIcon}
|
||||||
|
style={{ tintColor: focused ? darksalmonColor : purpleColor }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}}/>
|
||||||
|
</BottomTabNavigator.Navigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
color: 'darksalmon',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
backgroundColor : indigo
|
||||||
|
},
|
||||||
|
addJoke: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: greyColor,
|
||||||
|
width: '70%',
|
||||||
|
height: '100%',
|
||||||
|
borderRadius: 4,
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const stylesDark = StyleSheet.create({
|
||||||
|
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
color: 'darksalmon',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
backgroundColor : indigo
|
||||||
|
},
|
||||||
|
addJoke: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: greyColor,
|
||||||
|
width: '70%',
|
||||||
|
height: '100%',
|
||||||
|
borderRadius: 4,
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,65 @@
|
|||||||
|
import {createStackNavigator} from "@react-navigation/stack";
|
||||||
|
import {NavigationContainer} from "@react-navigation/native";
|
||||||
|
import {AccueilScreen} from "../screens/AccueilScreen";
|
||||||
|
import {JokeListItems} from "../components/ListeJokeComponent";
|
||||||
|
import {DetailJoke} from "../components/DetailJoke";
|
||||||
|
import JokeDetailScreen from "../screens/JokeDetailScreen";
|
||||||
|
import {ListJokeScreen} from "../screens/ListJokeScreen";
|
||||||
|
import {darksalmonColor, indigo, purpleColor} from "../Theme";
|
||||||
|
import {ListFavoriteJokeScreen} from "../screens/ListFavoriteJokeScreen";
|
||||||
|
|
||||||
|
|
||||||
|
export function CatalogueScreen(){
|
||||||
|
const Stack = createStackNavigator();
|
||||||
|
return(
|
||||||
|
<Stack.Navigator initialRouteName="CatalogueStack" screenOptions={
|
||||||
|
{
|
||||||
|
headerTitleStyle: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: darksalmonColor,
|
||||||
|
|
||||||
|
},
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: indigo,
|
||||||
|
|
||||||
|
},
|
||||||
|
headerTitle : "Catalogue",
|
||||||
|
headerBackTitleVisible: false,
|
||||||
|
headerTintColor: darksalmonColor,
|
||||||
|
}
|
||||||
|
|
||||||
|
}>
|
||||||
|
<Stack.Screen name="CatalogueStack" component={ListJokeScreen} options={{ headerTitle: 'Catalogue' }}/>
|
||||||
|
<Stack.Screen name="JokeDetail" component={JokeDetailScreen} options={{ headerTitle: 'Detail d une blague' }
|
||||||
|
} />
|
||||||
|
</Stack.Navigator>
|
||||||
|
)}
|
||||||
|
|
||||||
|
export function FavoriteScreen(){
|
||||||
|
const Stack = createStackNavigator();
|
||||||
|
return(
|
||||||
|
<Stack.Navigator initialRouteName="FavoriteStack" screenOptions={
|
||||||
|
{
|
||||||
|
headerTitleStyle: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: darksalmonColor,
|
||||||
|
|
||||||
|
},
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: indigo,
|
||||||
|
|
||||||
|
},
|
||||||
|
headerTitle : "Favoris",
|
||||||
|
headerBackTitleVisible: false,
|
||||||
|
headerTintColor: darksalmonColor,
|
||||||
|
}
|
||||||
|
|
||||||
|
}>
|
||||||
|
<Stack.Screen name="FavoriteStack" component={ListFavoriteJokeScreen} options={{ headerTitle: 'Favoris' }}/>
|
||||||
|
<Stack.Screen name="JokeDetail" component={JokeDetailScreen} options={{ headerTitle: 'Detail d une blague' }
|
||||||
|
} />
|
||||||
|
</Stack.Navigator>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
import {Categorie} from "../../model/Categorie";
|
||||||
|
import {CategorieFactory} from "../../model/CategorieFactory";
|
||||||
|
|
||||||
|
|
||||||
|
export enum CategoriesActionType {
|
||||||
|
FETCH_CATEGORIES = 'FETCH_CATEGORIES',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoriesAction {
|
||||||
|
type: CategoriesActionType;
|
||||||
|
payload: Categorie[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Action = CategoriesAction;
|
||||||
|
|
||||||
|
export const setCategories = (categories: Categorie[]): CategoriesAction => {
|
||||||
|
return {
|
||||||
|
type: CategoriesActionType.FETCH_CATEGORIES,
|
||||||
|
payload: categories
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCategorie = async() : Promise<Categorie[]> => {
|
||||||
|
try {
|
||||||
|
const categories = await fetch('https://iut-weather-api.azurewebsites.net/jokes/categories/top');
|
||||||
|
const categorieJson = await categories.text();
|
||||||
|
return CategorieFactory.createCategories(categorieJson);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
import {CustomJoke} from "../../model/CustomJoke";
|
||||||
|
import {JokeFactory} from "../../model/JokeFactory";
|
||||||
|
|
||||||
|
export enum CustomActionType {
|
||||||
|
POST_CUSTOM_JOKE = 'POST_CUSTOM_JOKE',
|
||||||
|
FETCH_CUSTOMS_JOKE = 'FETCH_CUSTOMS_JOKE',
|
||||||
|
FETCH_CUSTOMS_JOKE_BY_ID = 'FETCH_CUSTOMS_JOKE_BY_ID',
|
||||||
|
DELETE_CUSTOM_JOKE = 'DELETE_CUSTOM_JOKE',
|
||||||
|
FETCH_FAVORITE_JOKE = 'FETCH_FAVORITE_JOKE'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomAction {
|
||||||
|
type: CustomActionType;
|
||||||
|
payload: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface postCustomAction {
|
||||||
|
type: CustomActionType;
|
||||||
|
payload: CustomJoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomsAction {
|
||||||
|
type: CustomActionType;
|
||||||
|
payload: CustomJoke[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export type Action = CustomAction;
|
||||||
|
|
||||||
|
|
||||||
|
export const setPostJoke = (postJoke: CustomJoke): postCustomAction => {
|
||||||
|
return {
|
||||||
|
type: CustomActionType.POST_CUSTOM_JOKE,
|
||||||
|
payload: postJoke
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setCustomsJoke = (customJokes: CustomJoke[]): CustomsAction => {
|
||||||
|
return {
|
||||||
|
type: CustomActionType.FETCH_CUSTOMS_JOKE,
|
||||||
|
payload: customJokes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setCustomsJokeById = (completCustomJoke: CustomJoke): postCustomAction => {
|
||||||
|
return {
|
||||||
|
type: CustomActionType.FETCH_CUSTOMS_JOKE_BY_ID,
|
||||||
|
payload: completCustomJoke
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setDeleteCustomJoke = (deleteCustomJoke: CustomJoke): postCustomAction => {
|
||||||
|
return {
|
||||||
|
type: CustomActionType.DELETE_CUSTOM_JOKE,
|
||||||
|
payload: deleteCustomJoke
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setFavoriteJoke = (favoriteJokes: CustomJoke[]): CustomsAction => {
|
||||||
|
return {
|
||||||
|
type: CustomActionType.FETCH_FAVORITE_JOKE,
|
||||||
|
payload: favoriteJokes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const postJoke = (type : string, setup : string, punchline : string) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
console.log('type', type, 'setup', setup, 'punchline', punchline);
|
||||||
|
const reponse = await fetch('https://iut-weather-api.azurewebsites.net/jokes/', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
type: type,
|
||||||
|
setup: setup,
|
||||||
|
punchline: punchline
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
const data = await reponse.json();
|
||||||
|
dispatch(setPostJoke(data));
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getJokesCustoms = () => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const custom = await fetch('https://iut-weather-api.azurewebsites.net/jokes/');
|
||||||
|
const customsJson = await custom.text();
|
||||||
|
const customJokes = JokeFactory.createCustomJokes(customsJson);
|
||||||
|
dispatch(setCustomsJoke(customJokes));
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getJokesCustomsById = (id : number) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const custom = await fetch('https://iut-weather-api.azurewebsites.net/jokes/' + id);
|
||||||
|
const customsJson = await custom.text();
|
||||||
|
const customJokes = JokeFactory.createCustomJokeById(customsJson);
|
||||||
|
console.log('customJokes', customJokes);
|
||||||
|
dispatch(setCustomsJokeById(customJokes));
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deleteJoke = (id : number) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const custom = await fetch('https://iut-weather-api.azurewebsites.net/jokes/' + id, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('Suppression');
|
||||||
|
dispatch(setDeleteCustomJoke({} as CustomJoke));
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
import {SampleJoke} from "../../model/SampleJoke";
|
||||||
|
import {JokeFactory} from "../../model/JokeFactory";
|
||||||
|
|
||||||
|
export enum SampleActionType {
|
||||||
|
FETCH_SAMPLE = 'FETCH_SAMPLE',
|
||||||
|
FECTH_LAST_JOKES = 'FECTH_LAST_JOKES',
|
||||||
|
FECTH_COMPLET_JOKE = 'FECTH_COMPLET_JOKE',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SampleAction {
|
||||||
|
type: SampleActionType;
|
||||||
|
payload: SampleJoke[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SampleActionComplet {
|
||||||
|
type: SampleActionType;
|
||||||
|
payload: SampleJoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Action = SampleAction;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const setSample = (sample: SampleJoke[]): SampleAction => {
|
||||||
|
return {
|
||||||
|
type: SampleActionType.FETCH_SAMPLE,
|
||||||
|
payload: sample
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setRecentJokes = (recentJokes: SampleJoke[]): SampleAction => {
|
||||||
|
return {
|
||||||
|
type: SampleActionType.FECTH_LAST_JOKES,
|
||||||
|
payload: recentJokes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setCompletJokes = (completJoke: SampleJoke): SampleActionComplet => {
|
||||||
|
return {
|
||||||
|
type: SampleActionType.FECTH_COMPLET_JOKE,
|
||||||
|
payload: completJoke
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const getSampleJoke = () => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const sample = await fetch('https://iut-weather-api.azurewebsites.net/jokes/samples');
|
||||||
|
const sampleJson = await sample.text();
|
||||||
|
const joke = JokeFactory.createSampleJokes(sampleJson);
|
||||||
|
dispatch(setSample(joke));
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLatestJokes = () => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const sample = await fetch('https://iut-weather-api.azurewebsites.net/jokes/lasts');
|
||||||
|
const sampleJson = await sample.text();
|
||||||
|
const latestJoke = JokeFactory.createSampleJokes(sampleJson);
|
||||||
|
dispatch(setRecentJokes(latestJoke));
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCompletJokes = (id : number) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const sample = await fetch('https://iut-weather-api.azurewebsites.net/jokes/samples/' + id);
|
||||||
|
const sampleJson = await sample.text();
|
||||||
|
const jokeSelect = JokeFactory.createSampleJokeById(sampleJson);
|
||||||
|
dispatch(setCompletJokes(jokeSelect))
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error---------', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import {Action, CategoriesActionType} from "../actions/categoriesAction";
|
||||||
|
import {Categorie} from "../../model/Categorie";
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
categories: Categorie[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// initial state for categories
|
||||||
|
const initialState: State = {
|
||||||
|
categories: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
// app reducer for categories
|
||||||
|
// @ts-ignore
|
||||||
|
export default appReducer = (state = initialState, action: Action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case CategoriesActionType.FETCH_CATEGORIES:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
categories: action.payload
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
import {SampleJoke} from "../../model/SampleJoke";
|
||||||
|
import {CustomJoke} from "../../model/CustomJoke";
|
||||||
|
import {CustomActionType} from "../actions/customAction";
|
||||||
|
|
||||||
|
|
||||||
|
interface state {
|
||||||
|
postJoke: CustomJoke;
|
||||||
|
customJokes: CustomJoke[];
|
||||||
|
completCustomJoke: CustomJoke;
|
||||||
|
deleteCustomJoke: CustomJoke;
|
||||||
|
favoriteJokes: CustomJoke[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial state for sampleJokes
|
||||||
|
const initialState: state = {
|
||||||
|
postJoke: {} as CustomJoke,
|
||||||
|
customJokes: [],
|
||||||
|
completCustomJoke: {} as CustomJoke,
|
||||||
|
deleteCustomJoke: {} as CustomJoke,
|
||||||
|
favoriteJokes: []
|
||||||
|
}
|
||||||
|
|
||||||
|
// app reducer for sampleJokes
|
||||||
|
// @ts-ignore
|
||||||
|
export default appReducer = (state = initialState, action: Action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case CustomActionType.POST_CUSTOM_JOKE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
postJoke: action.payload,
|
||||||
|
}
|
||||||
|
case CustomActionType.FETCH_CUSTOMS_JOKE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
customJokes: action.payload,
|
||||||
|
}
|
||||||
|
case CustomActionType.FETCH_CUSTOMS_JOKE_BY_ID:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
completCustomJoke: action.payload,
|
||||||
|
}
|
||||||
|
case CustomActionType.DELETE_CUSTOM_JOKE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
deleteCustomJoke: action.payload,
|
||||||
|
}
|
||||||
|
case CustomActionType.FETCH_FAVORITE_JOKE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
favoriteJokes: action.payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import {SampleJoke} from "../../model/SampleJoke";
|
||||||
|
import {Action, SampleActionType} from "../actions/sampleAction";
|
||||||
|
import {CustomJoke} from "../../model/CustomJoke";
|
||||||
|
|
||||||
|
|
||||||
|
interface state {
|
||||||
|
sampleJoke: SampleJoke[];
|
||||||
|
recentJokes: SampleJoke[];
|
||||||
|
completJoke: SampleJoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial state for sampleJokes
|
||||||
|
const initialState: state = {
|
||||||
|
completJoke: {} as SampleJoke,
|
||||||
|
sampleJoke: [],
|
||||||
|
recentJokes: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
// app reducer for sampleJokes
|
||||||
|
// @ts-ignore
|
||||||
|
export default appReducer = (state = initialState, action: Action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case SampleActionType.FETCH_SAMPLE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
sampleJoke: action.payload
|
||||||
|
}
|
||||||
|
case SampleActionType.FECTH_LAST_JOKES:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
recentJokes: action.payload
|
||||||
|
}
|
||||||
|
case SampleActionType.FECTH_COMPLET_JOKE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
completJoke: action.payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
import categorieReducer from './reducers/categoryReducer';
|
||||||
|
import sampleReducer from './reducers/sampleJokeReducer';
|
||||||
|
import customReducer from "./reducers/customJokeReducer";
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
import {DefaultTheme, Theme} from "@react-navigation/native";
|
||||||
|
import {CustomJoke} from "../model/CustomJoke";
|
||||||
|
import {setFavoriteJoke} from "./actions/customAction";
|
||||||
|
import {TypedUseSelectorHook, useDispatch, useSelector} from "react-redux";
|
||||||
|
import {SampleJoke} from "../model/SampleJoke";
|
||||||
|
import {Joke} from "../model/Joke";
|
||||||
|
import {JokeFactory} from "../model/JokeFactory";
|
||||||
|
|
||||||
|
const reducer = {
|
||||||
|
categorieReducer: categorieReducer,
|
||||||
|
sampleReducer: sampleReducer,
|
||||||
|
customReducer: customReducer
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const store = configureStore({
|
||||||
|
// @ts-ignore
|
||||||
|
reducer,
|
||||||
|
middleware: (getDefaultMiddleware) =>
|
||||||
|
getDefaultMiddleware({
|
||||||
|
serializableCheck: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const storeTheme = async (theme) => {
|
||||||
|
try {
|
||||||
|
const jsonValue = JSON.stringify(theme)
|
||||||
|
await AsyncStorage.setItem('@theme', jsonValue)
|
||||||
|
console.log("theme stored")
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTheme = async () => {
|
||||||
|
try {
|
||||||
|
const jsonValue = await AsyncStorage.getItem('@theme')
|
||||||
|
return jsonValue != null ? JSON.parse(jsonValue) as Theme : DefaultTheme;
|
||||||
|
} catch(e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const storeFavoriteJoke = (joke : CustomJoke) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const favoriteJokes = await AsyncStorage.getItem('favorites');
|
||||||
|
const favoriteJokesList: CustomJoke[] = favoriteJokes != null ? JokeFactory.createCustomJokes(favoriteJokes) : [];
|
||||||
|
favoriteJokesList.push(joke);
|
||||||
|
await AsyncStorage.setItem('favorites', JSON.stringify(favoriteJokesList.map(j => ({type: j.type, setup: j.setup, punchline: j.punchline, image: j.image, id: j.id}))));
|
||||||
|
dispatch(setFavoriteJoke(favoriteJokesList));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const getFavorite = () => {
|
||||||
|
return async (dispatch) => {
|
||||||
|
try {
|
||||||
|
const favoriteJokes = await AsyncStorage.getItem('favorites');
|
||||||
|
let favoriteJokesList = favoriteJokes != null ? JSON.parse(favoriteJokes) : [];
|
||||||
|
favoriteJokesList = favoriteJokesList.filter(joke => joke.id !== undefined);
|
||||||
|
await AsyncStorage.setItem('favorites', JSON.stringify(favoriteJokesList));
|
||||||
|
const favorites = favoriteJokesList.map(joke => new SampleJoke(joke["type"], joke["setup"], joke["punchline"], joke["image"], joke["id"]))
|
||||||
|
dispatch(setFavoriteJoke(favorites));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const removeFavoriteJoke = (joke : CustomJoke) => {
|
||||||
|
return async dispatch => {
|
||||||
|
try {
|
||||||
|
const favoriteJokes = await AsyncStorage.getItem('favorites');
|
||||||
|
let favoriteJokesList: CustomJoke[] = favoriteJokes != null ? JokeFactory.createCustomJokes(favoriteJokes) : [];
|
||||||
|
const index = favoriteJokesList.findIndex((j) => j.id === joke.id);
|
||||||
|
if (index !== -1) {
|
||||||
|
favoriteJokesList.splice(index, 1);
|
||||||
|
await AsyncStorage.setItem('favorites', JSON.stringify(favoriteJokesList.map(j => ({type: j.type, setup: j.setup, punchline: j.punchline, image: j.image, id: j.id}))));
|
||||||
|
dispatch(setFavoriteJoke(favoriteJokesList));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.log("An error occurred", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export type AppDispatch = typeof store.dispatch;
|
||||||
|
|
||||||
|
export type AppStore = ReturnType<typeof store.getState>;
|
||||||
|
|
||||||
|
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||||
|
export const useAppSelector: TypedUseSelectorHook<AppStore> = useSelector;
|
||||||
|
|
||||||
|
export default store;
|
@ -0,0 +1,99 @@
|
|||||||
|
import {FlatList, Image, SafeAreaView, ScrollView, SectionListComponent, StyleSheet, Text, View} from "react-native";
|
||||||
|
import {indigo, purpleColor} from "../Theme";
|
||||||
|
import {Joke} from "../model/Joke";
|
||||||
|
import React, {useEffect} from "react";
|
||||||
|
import {HorizontalListJokeComponent} from "../components/HorizontalListJokeComponent";
|
||||||
|
import {ListAllCategories} from "../components/ListAllCategories";
|
||||||
|
import {CustomJoke} from "../model/CustomJoke";
|
||||||
|
import {JokeFactory} from "../model/JokeFactory";
|
||||||
|
import {JokeStub} from "../model/JokeStub";
|
||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
import {getLatestJokes, getSampleJoke, setRecentJokes, setSample} from "../redux/actions/sampleAction";
|
||||||
|
import {getCategorie, setCategories} from "../redux/actions/categoriesAction";
|
||||||
|
import {Categorie} from "../model/Categorie";
|
||||||
|
|
||||||
|
|
||||||
|
export function AccueilScreen() {
|
||||||
|
|
||||||
|
const DataGen = useSelector((state: any) => state.sampleReducer.recentJokes);
|
||||||
|
const DataCate = useSelector((state: any) => state.categorieReducer.categories);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
const getJokes = async () => {
|
||||||
|
// @ts-ignore
|
||||||
|
await dispatch(getLatestJokes());
|
||||||
|
};
|
||||||
|
getJokes();
|
||||||
|
|
||||||
|
const getTopCategories = async () => {
|
||||||
|
// @ts-ignore
|
||||||
|
dispatch(setCategories(await getCategorie()));
|
||||||
|
};
|
||||||
|
getTopCategories();
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={styles.container}>
|
||||||
|
|
||||||
|
<View>
|
||||||
|
<Image source={require('../assets/logo.png')} style={styles.imgStyle}/>
|
||||||
|
<Text style={styles.title}>Chat C'est Drôle</Text>
|
||||||
|
<Text style={styles.titleAccueil}>Dernieres Blagues</Text>
|
||||||
|
</View>
|
||||||
|
<FlatList showsHorizontalScrollIndicator={false} horizontal={true}
|
||||||
|
data={DataGen}
|
||||||
|
renderItem={HorizontalListJokeComponent}
|
||||||
|
keyExtractor={(item: CustomJoke) => item.id.toString()}
|
||||||
|
/>
|
||||||
|
<View style={styles.categories}>
|
||||||
|
<Text style={styles.titleAccueil} >Top Categories</Text>
|
||||||
|
<Image source={require("../assets/fire_icon.png")}/>
|
||||||
|
</View>
|
||||||
|
<FlatList showsHorizontalScrollIndicator={false} horizontal={true}
|
||||||
|
data={DataCate}
|
||||||
|
renderItem={ListAllCategories}
|
||||||
|
keyExtractor={(item : Categorie) => item.name}/>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
color: 'darksalmon',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
titleResume: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: purpleColor,
|
||||||
|
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
backgroundColor : indigo,
|
||||||
|
},
|
||||||
|
|
||||||
|
imgStyle: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
margin: 5,
|
||||||
|
},
|
||||||
|
titleAccueil: {
|
||||||
|
fontSize: 20,
|
||||||
|
color: 'white',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
categories: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,169 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Button, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
|
||||||
|
import { darksalmonColor, indigo, purpleColor, whiteColor } from "../Theme";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { postJoke} from "../redux/actions/customAction";
|
||||||
|
|
||||||
|
export function AddJokeScreen() {
|
||||||
|
const [joke, setJoke] = useState("");
|
||||||
|
const [jokeFall, setJokeFall] = useState("");
|
||||||
|
const [category, setCategory] = useState("");
|
||||||
|
const [categoryExceeded, setCategoryExceeded] = useState(false);
|
||||||
|
const [buttonDisabled, setButtonDisabled] = useState(true);
|
||||||
|
const MAX_CATEGORY_LENGTH = 10;
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (joke !== "" && jokeFall !== "" && category !== "") {
|
||||||
|
setButtonDisabled(false);
|
||||||
|
} else {
|
||||||
|
setButtonDisabled(true);
|
||||||
|
}
|
||||||
|
}, [joke, jokeFall, category]);
|
||||||
|
const postjoke = async () => {
|
||||||
|
// @ts-ignore
|
||||||
|
await dispatch(postJoke(joke, jokeFall, category));
|
||||||
|
clearFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFields = () => {
|
||||||
|
setJoke("");
|
||||||
|
setJokeFall("");
|
||||||
|
setCategory("");
|
||||||
|
setCategoryExceeded(false);
|
||||||
|
setButtonDisabled(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCategoryChange = (text) => {
|
||||||
|
if (text.length > MAX_CATEGORY_LENGTH) {
|
||||||
|
setCategoryExceeded(true);
|
||||||
|
} else {
|
||||||
|
setCategoryExceeded(false);
|
||||||
|
setCategory(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.font}>
|
||||||
|
<Text style={styles.titleTextInput}>Blague</Text>
|
||||||
|
<TextInput
|
||||||
|
editable
|
||||||
|
multiline
|
||||||
|
style={styles.textInput}
|
||||||
|
value={joke}
|
||||||
|
onChangeText={(text) => setJoke(text)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text style={styles.titleTextInput}>Chute de la blague</Text>
|
||||||
|
<TextInput
|
||||||
|
editable
|
||||||
|
multiline
|
||||||
|
style={styles.textInput}
|
||||||
|
value={jokeFall}
|
||||||
|
onChangeText={(text) => setJokeFall(text)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text style={styles.titleTextInput}>Catégorie</Text>
|
||||||
|
<TextInput
|
||||||
|
editable
|
||||||
|
multiline
|
||||||
|
style={styles.textInput1}
|
||||||
|
value={category}
|
||||||
|
onChangeText={handleCategoryChange}
|
||||||
|
></TextInput>
|
||||||
|
<View style={styles.characterCountContainer}>
|
||||||
|
<Text style={styles.characterCountText}>
|
||||||
|
{category.length}/{MAX_CATEGORY_LENGTH}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.viewButtonCreate, { opacity: buttonDisabled ? 0.5 : 1 }]}
|
||||||
|
disabled={buttonDisabled} // Désactiver le bouton si buttonDisabled est vrai
|
||||||
|
onPress={postjoke}
|
||||||
|
>
|
||||||
|
<Text style={styles.textButton1}>CRÉER</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity style={styles.viewButtonClear} onPress={clearFields}>
|
||||||
|
<Text style={styles.textButton2}>EFFACER</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
font: {
|
||||||
|
backgroundColor: purpleColor,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
},
|
||||||
|
titleTextInput: {
|
||||||
|
fontSize: 20,
|
||||||
|
color: whiteColor,
|
||||||
|
textAlign: "left",
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginTop: 25,
|
||||||
|
marginVertical: 10,
|
||||||
|
marginLeft: 10,
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
backgroundColor: indigo,
|
||||||
|
height: "13%",
|
||||||
|
color: whiteColor,
|
||||||
|
textAlign: "left",
|
||||||
|
textAlignVertical: "top",
|
||||||
|
margin: 10,
|
||||||
|
padding: 30,
|
||||||
|
paddingTop: 15,
|
||||||
|
},
|
||||||
|
textInput1: {
|
||||||
|
backgroundColor: indigo,
|
||||||
|
height: "9%",
|
||||||
|
color: whiteColor,
|
||||||
|
textAlign: "left",
|
||||||
|
textAlignVertical: "top",
|
||||||
|
margin: 10,
|
||||||
|
padding: 20,
|
||||||
|
paddingTop: 10,
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
viewButtonCreate: {
|
||||||
|
backgroundColor: darksalmonColor,
|
||||||
|
height: "7%",
|
||||||
|
marginLeft: 10,
|
||||||
|
marginRight: 10,
|
||||||
|
marginTop: 20,
|
||||||
|
borderRadius: 10,
|
||||||
|
},
|
||||||
|
viewButtonClear: {
|
||||||
|
backgroundColor: whiteColor,
|
||||||
|
height: "7%",
|
||||||
|
marginLeft: 10,
|
||||||
|
marginRight: 10,
|
||||||
|
marginTop: 20,
|
||||||
|
borderRadius: 10,
|
||||||
|
},
|
||||||
|
textButton1: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: whiteColor,
|
||||||
|
alignSelf: "center",
|
||||||
|
padding: 12,
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
textButton2: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: darksalmonColor,
|
||||||
|
alignSelf: "center",
|
||||||
|
padding: 12,
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
characterCountContainer: {
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
bottom: 10,
|
||||||
|
right: 10,
|
||||||
|
},
|
||||||
|
characterCountText: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: whiteColor,
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,69 @@
|
|||||||
|
import {View, Text, StyleSheet, TouchableOpacity, Image} from "react-native";
|
||||||
|
import {indigo, purpleColor, whiteColor} from "../Theme";
|
||||||
|
import React, {useEffect} from "react";
|
||||||
|
import {CustomJoke} from "../model/CustomJoke";
|
||||||
|
import {DetailJoke} from "../components/DetailJoke";
|
||||||
|
import {Joke} from "../model/Joke";
|
||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
import {getCompletJokes, setCompletJokes, setSample} from "../redux/actions/sampleAction";
|
||||||
|
import {useIsFocused, useNavigation, validatePathConfig} from "@react-navigation/native";
|
||||||
|
import {deleteJoke, getJokesCustomsById} from "../redux/actions/customAction";
|
||||||
|
import {Navigation} from "../navigation/Navigation";
|
||||||
|
export default function JokeDetailScreen({route}) {
|
||||||
|
const navigation = useNavigation();
|
||||||
|
const isFocused = useIsFocused();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const jokeId = route.params.joke;
|
||||||
|
const isFavoris = route.params.isFavoris
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const DataGen = typeof jokeId === "string" ? useSelector((state: any) => state.customReducer.completCustomJoke) : useSelector((state: any) => state.sampleReducer.completJoke);
|
||||||
|
// const DataGen = useSelector((state: any) => state.sampleReducer.completJoke);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getDetails = async () => {
|
||||||
|
// @ts-ignore
|
||||||
|
{ typeof jokeId === "string" ? await dispatch(getJokesCustomsById(jokeId)) : await dispatch(getCompletJokes(jokeId));}
|
||||||
|
|
||||||
|
};
|
||||||
|
getDetails();
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
async function deleteJokes() {
|
||||||
|
// @ts-ignore
|
||||||
|
await dispatch(deleteJoke(jokeId));
|
||||||
|
navigation.goBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.font}>
|
||||||
|
<DetailJoke item={DataGen}/>
|
||||||
|
{typeof jokeId === "string" ? <TouchableOpacity onPress={deleteJokes}>
|
||||||
|
<Image style={styles.img} source={require('../assets/delete-icon.png')} />
|
||||||
|
</TouchableOpacity> : null}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
font: {
|
||||||
|
backgroundColor: purpleColor,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 24,
|
||||||
|
color: 'darksalmon',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
img: {
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
margin: 20,
|
||||||
|
alignSelf: 'center'
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,103 @@
|
|||||||
|
import {useTheme} from "@react-navigation/native";
|
||||||
|
import {darksalmonColor, indigo, whiteColor} from "../Theme";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import {getFavorite} from "../redux/store";
|
||||||
|
import {FlatList, SafeAreaView, StyleSheet, TouchableHighlight, View, Text} from "react-native";
|
||||||
|
import {JokeListItems} from "../components/ListeJokeComponent";
|
||||||
|
import {CustomJoke} from "../model/CustomJoke";
|
||||||
|
import {SampleJoke} from "../model/SampleJoke";
|
||||||
|
import {useAppSelector, useAppDispatch} from "../redux/store";
|
||||||
|
import {useDispatch} from "react-redux";
|
||||||
|
export function ListFavoriteJokeScreen({route, navigation}){
|
||||||
|
|
||||||
|
const favoriteJokes: CustomJoke[] = useAppSelector((state) => state.customReducer.favoriteJokes);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getFavoriteJokes = async () => {
|
||||||
|
// @ts-ignore
|
||||||
|
await dispatch(getFavorite());
|
||||||
|
}
|
||||||
|
getFavoriteJokes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const styles = themeSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={styles.container}>
|
||||||
|
{ favoriteJokes.length ? (
|
||||||
|
<FlatList
|
||||||
|
data = {favoriteJokes}
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<TouchableHighlight onPress={() => navigation.navigate("JokeDetail", {"joke" : item.id})}>
|
||||||
|
<JokeListItems item={item}/>
|
||||||
|
</TouchableHighlight>
|
||||||
|
)}
|
||||||
|
keyExtractor={(item) => item.id.toString()}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Text style={styles.title}>Aucun favoris</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function themeSettings() {
|
||||||
|
const {colors} = useTheme();
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
color: colors.text,
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
titleResume: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: colors.background,
|
||||||
|
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
backgroundColor : indigo,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
margin: 9,
|
||||||
|
},
|
||||||
|
headerText: {
|
||||||
|
fontSize: 18,
|
||||||
|
color: whiteColor,
|
||||||
|
textAlign: 'center',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
img2: {
|
||||||
|
tintColor: whiteColor,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
button2:{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "center",
|
||||||
|
marginRight: 10,
|
||||||
|
borderRadius: 10,
|
||||||
|
alignItems: "center",
|
||||||
|
height: 30,
|
||||||
|
width: 70,
|
||||||
|
|
||||||
|
borderColor: darksalmonColor,
|
||||||
|
borderWidth: 1,
|
||||||
|
backgroundColor: darksalmonColor,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return styles;
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
import React, {useContext, useEffect, useState} from "react";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Appearance,
|
||||||
|
Button,
|
||||||
|
FlatList,
|
||||||
|
Image,
|
||||||
|
SafeAreaView,
|
||||||
|
ScrollView,
|
||||||
|
SectionListComponent,
|
||||||
|
StyleSheet, Switch, SwitchComponent,
|
||||||
|
Text, useColorScheme,
|
||||||
|
View
|
||||||
|
} from "react-native";
|
||||||
|
import usePersonalTheme, {
|
||||||
|
blackColor,
|
||||||
|
darksalmonColor,
|
||||||
|
greyColor,
|
||||||
|
indigo,
|
||||||
|
purpleColor,
|
||||||
|
whiteColor
|
||||||
|
} from "../Theme";
|
||||||
|
import {isEnabled} from "react-native/Libraries/Performance/Systrace";
|
||||||
|
import {DarkTheme, DefaultTheme, useTheme} from "@react-navigation/native";
|
||||||
|
import {storeTheme} from "../redux/store";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function SettingsScreen() {
|
||||||
|
|
||||||
|
const [isEnabled, setIsEnabled] = useState(false);
|
||||||
|
|
||||||
|
const toggleSwitch = () => {
|
||||||
|
setIsEnabled(previousState => {
|
||||||
|
const newIsEnabled = !previousState;
|
||||||
|
const newTheme = newIsEnabled ? DarkTheme : DefaultTheme;
|
||||||
|
console.log("newTheme", newTheme);
|
||||||
|
storeTheme(newTheme);
|
||||||
|
return newIsEnabled;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = themeSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={styles.container}>
|
||||||
|
<Text style={styles.title}>Réglages</Text>
|
||||||
|
<View style={styles.settingsContainer}>
|
||||||
|
<View style={styles.settingRow}>
|
||||||
|
<View style={styles.settingRow}>
|
||||||
|
<Image style={styles.img} source={require('../assets/darkmode_icon.png')}/>
|
||||||
|
<Text style={styles.settingText}>Dark Mode</Text>
|
||||||
|
</View>
|
||||||
|
<Switch style={styles.switch}
|
||||||
|
trackColor={{ false: whiteColor, true: darksalmonColor }}
|
||||||
|
thumbColor={isEnabled ? whiteColor :darksalmonColor}
|
||||||
|
onValueChange={toggleSwitch}
|
||||||
|
value={isEnabled}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export function themeSettings() {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const colors = theme.colors;
|
||||||
|
console.log("themeSettings", colors)
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: colors.background,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
padding: 16,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
headerText: {
|
||||||
|
color: whiteColor,
|
||||||
|
fontSize: 18,
|
||||||
|
},
|
||||||
|
settingsContainer: {
|
||||||
|
backgroundColor: indigo,
|
||||||
|
margin: 16,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: whiteColor,
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginTop: 7,
|
||||||
|
marginLeft: 15,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
settingRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingVertical: 12,
|
||||||
|
|
||||||
|
},
|
||||||
|
settingText: {
|
||||||
|
color: whiteColor,
|
||||||
|
marginLeft: 10,
|
||||||
|
},
|
||||||
|
img: {
|
||||||
|
marginLeft: 10,
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
tintColor: darksalmonColor,
|
||||||
|
},
|
||||||
|
switch: {
|
||||||
|
marginRight: 10,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return styles;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
import {describe,test ,expect, jest, it} from "@jest/globals";
|
||||||
|
import {CustomJoke} from "../../model/CustomJoke";
|
||||||
|
import {
|
||||||
|
CustomActionType,
|
||||||
|
getJokesCustoms,
|
||||||
|
setCustomsJoke,
|
||||||
|
setCustomsJokeById, setDeleteCustomJoke, setFavoriteJoke,
|
||||||
|
setPostJoke
|
||||||
|
} from "../../redux/actions/customAction";
|
||||||
|
|
||||||
|
|
||||||
|
describe('Action tests', () => {
|
||||||
|
it('setPostJoke creates correct action', () => {
|
||||||
|
const postJoke = new CustomJoke('test', 'Why did the chicken...', 'To get to the other side!', 'http://www.jokes.com/joke1', "1");
|
||||||
|
const expectedAction = {
|
||||||
|
type: CustomActionType.POST_CUSTOM_JOKE,
|
||||||
|
payload: postJoke,
|
||||||
|
};
|
||||||
|
expect(setPostJoke(postJoke)).toEqual(expectedAction);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('setCustomsJoke creates correct action', () => {
|
||||||
|
const customJokes = [new CustomJoke('test', 'Why did the chicken...', 'To get to the other side!', 'http://www.jokes.com/joke1', "1")];
|
||||||
|
const expectedAction = {
|
||||||
|
type: CustomActionType.FETCH_CUSTOMS_JOKE,
|
||||||
|
payload: customJokes,
|
||||||
|
};
|
||||||
|
expect(setCustomsJoke(customJokes)).toEqual(expectedAction);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('setCustomsJokeById creates correct action', () => {
|
||||||
|
const completCustomJoke = new CustomJoke('test', 'Why did the chicken...', 'To get to the other side!', 'http://www.jokes.com/joke1', "1");
|
||||||
|
const expectedAction = {
|
||||||
|
type: CustomActionType.FETCH_CUSTOMS_JOKE_BY_ID,
|
||||||
|
payload: completCustomJoke,
|
||||||
|
};
|
||||||
|
expect(setCustomsJokeById(completCustomJoke)).toEqual(expectedAction);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('setDeleteCustomJoke creates correct action', () => {
|
||||||
|
const deleteCustomJoke = new CustomJoke('test', 'Why did the chicken...', 'To get to the other side!', 'http://www.jokes.com/joke1', "1");
|
||||||
|
const expectedAction = {
|
||||||
|
type: CustomActionType.DELETE_CUSTOM_JOKE,
|
||||||
|
payload: deleteCustomJoke,
|
||||||
|
};
|
||||||
|
expect(setDeleteCustomJoke(deleteCustomJoke)).toEqual(expectedAction);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('setFavoriteJoke creates correct action', () => {
|
||||||
|
const favoriteJokes = [new CustomJoke('test', 'Why did the chicken...', 'To get to the other side!', 'http://www.jokes.com/joke1', "1")];
|
||||||
|
const expectedAction = {
|
||||||
|
type: CustomActionType.FETCH_FAVORITE_JOKE,
|
||||||
|
payload: favoriteJokes,
|
||||||
|
};
|
||||||
|
expect(setFavoriteJoke(favoriteJokes)).toEqual(expectedAction);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|