Merge pull request ' Add first part of theme' (#9) from part7 into master

Reviewed-on: #9
master
Antoine PEREDERII 1 year ago
commit 6bd58278a0

@ -1,5 +1,32 @@
import {Theme} from "@react-navigation/native";
export const indigoColor = "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 whiteColor = "rgba(239, 239, 253, 1)";
export const DefaultTheme: Theme = {
dark: false,
colors: {
primary: 'rgb(0, 122, 255)',
background: "rgba(239, 239, 253, 1)",
card: 'rgb(255, 255, 255)',
text: 'rgb(28, 28, 30)',
border: 'rgb(216, 216, 216)',
notification: 'rgb(255, 59, 48)',
},
};
export const DarkTheme: Theme = {
dark: true,
colors: {
primary: 'rgb(10, 132, 255)',
background: "rgba(140, 140, 161, 1)",
card: 'rgb(18, 18, 18)',
text: 'rgb(229, 229, 231)',
border: 'rgb(39, 39, 41)',
notification: 'rgb(255, 69, 58)',
},
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

@ -1,16 +1,29 @@
import {StyleSheet, Text, View, Image, Button, TouchableOpacity} from 'react-native';
import {SampleJoke} from "../model/SampleJoke";
import {darksalmonColor, whiteColor, greyColor, indigoColor, purpleColor} from "../assets/Theme";
import React, {useState} from "react";
import React, {useEffect, useState} from "react";
import {CustomJoke} from "../model/CustomJoke";
import {useDispatch, useSelector} from "react-redux";
import {getCustomJokeById, getJokeById} from "../redux/thunk/GetByThunk";
import {getCustomJokesList} from "../redux/thunk/GetThunk";
import {deleteCustomJoke} from "../redux/thunk/DeleteThunk";
import {useNavigation} from "@react-navigation/native";
import {AppDispatch} from "../redux/store";
type JokeItemProps = {
joke: SampleJoke | CustomJoke;
};
const eye = require("../assets/eye_icon.png")
const hideEye = require("../assets/eye_off_icon.png")
const heart = require("../assets/favorite_icon.png")
const bin = require("../assets/bin.png")
const heartPlain = require("../assets/plain_favorite_icon.png")
export default function JokeDetail(props: JokeItemProps) {
const [showDescription, setShowDescription] = useState(false); // état local pour contrôler la visibilité de la description
const [showFavorite, setShowFavorite] = useState(false); // état local pour contrôler la visibilité du favori
const [showDescription, setShowDescription] = useState(false);
const [showFavorite, setShowFavorite] = useState(false);
const isCustom = props.joke instanceof CustomJoke;
const dispatch = useDispatch<AppDispatch>();
const navigation = useNavigation();
const toggleDescription = () => {
setShowDescription(!showDescription);
@ -20,10 +33,11 @@ export default function JokeDetail(props: JokeItemProps) {
setShowFavorite(!showFavorite);
};
const eye = require("../assets/eye_icon.png")
const hideEye = require("../assets/eye_off_icon.png")
const heart = require("../assets/favorite_icon.png")
const heartPlain = require("../assets/plain_favorite_icon.png")
const deleteCustomJokes = async () => {
await dispatch(deleteCustomJoke(props.joke.id));
await dispatch(getCustomJokesList());
navigation.goBack();
};
return(
<View style={styles.container}>
@ -33,6 +47,15 @@ export default function JokeDetail(props: JokeItemProps) {
</View>
<Text style={styles.text}>Résumé de la blague</Text>
<View style={styles.row}>
{isCustom && (<TouchableOpacity style={styles.favContainer} onPress={ deleteCustomJokes }>
<View>
<Image
source={bin}
style={styles.imageButton}
/>
</View>
</TouchableOpacity>)
}
<TouchableOpacity style={styles.favContainer} onPress={toggleFavorite}>
<View>
<Image
@ -149,7 +172,7 @@ const styles = StyleSheet.create({
marginLeft: 19,
marginTop: 20,
borderRadius: 20,
width : 120,
width : 150,
alignItems : 'center'
}
})

@ -1,4 +1,4 @@
import { NavigationContainer } from '@react-navigation/native';
import {DarkTheme, DefaultTheme, NavigationContainer, Theme} from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import {Image, View} from 'react-native';
@ -9,6 +9,8 @@ import Settings from "../screens/Settings";
import {darksalmonColor, greyColor, indigoColor} from "../assets/Theme";
import StackNavigation from "./StackNavigation";
import {useEffect, useState} from "react";
import {getTheme} from "../redux/thunk/ThemeThunk";
export default function NavigationBar() {
@ -20,8 +22,23 @@ export default function NavigationBar() {
const favoriteIcon = require("../assets/favorite_icon.png");
const settingsIcon = require("../assets/settings_icon.png");
const [themes, setTheme] = useState<Theme>(DefaultTheme);
useEffect(() => {
const fetchTheme = async () => {
const theme = await getTheme();
setTheme(theme);
};
fetchTheme();
});
if (themes == null) {
return null;
}
return (
<NavigationContainer>
<NavigationContainer theme={ themes.dark === false ? DefaultTheme : DarkTheme}>
<BottomTabNavigator.Navigator initialRouteName="Accueil"
screenOptions={{
headerStyle: {

@ -8,6 +8,7 @@
"name": "tp-react-native",
"version": "1.0.0",
"dependencies": {
"@react-native-async-storage/async-storage": "^1.23.1",
"@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.10",
"@react-navigation/stack": "^6.3.21",
@ -3683,6 +3684,17 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@react-native-async-storage/async-storage": {
"version": "1.23.1",
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.23.1.tgz",
"integrity": "sha512-Qd2kQ3yi6Y3+AcUlrHxSLlnBvpdCEMVGFlVBneVOjaFaPU61g1huc38g339ysXspwY1QZA2aNhrk/KlHGO+ewA==",
"dependencies": {
"merge-options": "^3.0.4"
},
"peerDependencies": {
"react-native": "^0.0.0-0 || >=0.60 <1.0"
}
},
"node_modules/@react-native-community/cli": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.0.tgz",
@ -8667,6 +8679,14 @@
"node": ">=8"
}
},
"node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"engines": {
"node": ">=8"
}
},
"node_modules/is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@ -9860,6 +9880,17 @@
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
"integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA=="
},
"node_modules/merge-options": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
"dependencies": {
"is-plain-obj": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",

@ -10,6 +10,7 @@
"web": "expo start --web"
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.23.1",
"@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.10",
"@react-navigation/stack": "^6.3.21",

@ -4,7 +4,8 @@ import {SampleJoke} from "../../model/SampleJoke";
export enum ActionType {
FETCH_CUSTOM_JOKES = 'FETCH_CUSTOM_JOKES',
POST_CUSTOM_JOKE = "POST_CUSTOM_JOKE",
FETCH_JOKES_BY_ID = "FETCH_JOKES_BY_ID"
FETCH_JOKES_BY_ID = "FETCH_JOKES_BY_ID",
DELETE_CUSTOM_JOKE = "DELETE_CUSTOM_JOKE"
}
type actionPostFetch = {
@ -19,7 +20,12 @@ type actionGetByFetch = {
type: ActionType.FETCH_JOKES_BY_ID;
payload: CustomJoke;
}
export type Action = actionPostFetch | actionGetFetch | actionGetByFetch;
type actionDeleteFetch = {
type: ActionType.DELETE_CUSTOM_JOKE;
payload: string;
}
export type Action = actionPostFetch | actionGetFetch | actionGetByFetch | actionDeleteFetch;
export const setPostJoke = (customJoke: CustomJoke) => {
return {
@ -27,7 +33,6 @@ export const setPostJoke = (customJoke: CustomJoke) => {
payload: customJoke
}
}
export const setCustomJokesList = (customJokesList: CustomJoke[]) => {
return {
type: ActionType.FETCH_CUSTOM_JOKES,
@ -39,4 +44,10 @@ export const setCustomJokeById = (customJoke: CustomJoke) => {
type: ActionType.FETCH_JOKES_BY_ID,
payload: customJoke,
};
}
export const setDeleteJoke = (jokeId: string) => {
return {
type: ActionType.DELETE_CUSTOM_JOKE,
payload: jokeId
}
}

@ -0,0 +1,18 @@
export enum ActionType {
SET_THEME = 'SET_THEME',
}
type actionFetch = {
type: ActionType.SET_THEME;
payload: String;
}
export type Action = actionFetch;
export const setTheme = (theme) => {
return {
type: ActionType.SET_THEME,
payload: theme,
};
}

@ -0,0 +1,28 @@
import {CustomJoke} from "../../model/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
export enum ActionType {
ADD_FAVORITE = 'ADD_CUSTOM_FAVORITE',
REMOVE_FAVORITE = "REMOVE_CUSTOM_FAVORITE"
}
type actionAddFetch = {
type: ActionType.ADD_FAVORITE;
payload: string;
}
type actionRemoveFetch = {
type: ActionType.REMOVE_FAVORITE;
payload: string;
}
export type Action = actionAddFetch | actionRemoveFetch;
export const addFavorite = (joke: CustomJoke | SampleJoke) => ({
type: ActionType.ADD_FAVORITE,
payload: joke,
});
export const removeFavorite = (joke: CustomJoke | SampleJoke) => ({
type: ActionType.REMOVE_FAVORITE,
payload: joke,
});

@ -1,29 +1,28 @@
import {CustomJoke} from "../../model/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
import {Action, ActionType} from "../actions/CustomJoke";
import {Category} from "../../model/Category";
interface State {
customJokes: CustomJoke[];
customJoke: CustomJoke;
customJoke?: CustomJoke;
jokeId: string;
}
const initialState = {
customJokes: [],
customJoke: new CustomJoke('', '', '', '')
customJoke: null,
jokeId: ''
}
const customReducer = (state: State = initialState, action: Action) => {
switch (action.type) {
case ActionType.POST_CUSTOM_JOKE:
// @ts-ignore
return {...state, customJoke: action.payload};
case ActionType.FETCH_CUSTOM_JOKES:
// @ts-ignore
return {...state, customJokes: action.payload};
case ActionType.FETCH_JOKES_BY_ID:
// @ts-ignore
return {...state, customJoke: action.payload};
case ActionType.DELETE_CUSTOM_JOKE:
return {...state, jokeId: action.payload};
default:
return state;
}

@ -0,0 +1,21 @@
import {Action, ActionType} from "../actions/DarkModeAction";
interface State {
theme: String
}
const initialState = {
theme: 'dark'
}
const themeReducer = (state: State = initialState, action: Action) => {
switch (action.type) {
case ActionType.SET_THEME:
// @ts-ignore
return {...state, theme: action.payload};
default:
return state;
}
}
export default themeReducer;

@ -0,0 +1,26 @@
import {Action, ActionType} from "../actions/FavoriteAction";
import {CustomJoke} from "../../model/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
interface State {
joke: CustomJoke | SampleJoke
}
const initialState = {
joke: new CustomJoke('', '', '', '', '')
}
const favoriteReducer = (state: State = initialState, action: Action) => {
switch (action.type) {
case ActionType.ADD_FAVORITE:
// @ts-ignore
return {...state, joke: action.payload};
case ActionType.REMOVE_FAVORITE:
// @ts-ignore
return {...state, joke: action.payload};
default:
return state;
}
}
export default favoriteReducer;

@ -6,13 +6,13 @@ import {Category} from "../../model/Category";
interface State {
jokes: SampleJoke[];
favoriteJokes: SampleJoke[];
joke : SampleJoke;
joke? : SampleJoke;
}
const initialState = {
jokes: [],
favoriteJokes: [],
joke: new SampleJoke(1, "", "", "", ""),
joke:null,
}
const sampleReducer = (state: State = initialState, action: Action) => {

@ -2,12 +2,16 @@ import {configureStore} from '@reduxjs/toolkit'
import sampleReducer from "./reducers/SampleReducer";
import categoryReducer from "./reducers/CategoryReducer";
import customReducer from "./reducers/CustomReducer";
import themeReducer from "./reducers/DarkModeReducer"
import favoriteReducer from "./reducers/FavoriteReducer";
// Reference here all your application reducers
const reducer = {
sampleReducer: sampleReducer,
categoryReducer: categoryReducer,
customReducer: customReducer,
theme: themeReducer,
favorite: favoriteReducer
}
// @ts-ignore
@ -18,5 +22,6 @@ const store = configureStore({
serializableCheck: false
})
},);
export type AppState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export default store;

@ -0,0 +1,28 @@
import { setDeleteJoke } from "../actions/CustomJoke";
export const deleteItem = (id: string) => {
return async dispatch => {
try {
const response = await fetch(`https://iut-weather-api.azurewebsites.net/jokes/${id}`, {
method: 'DELETE',
headers: {
Accept: "application/json",
"Content-Type": 'application/json',
}
});
if (response.ok) {
dispatch(setDeleteJoke(id)); // Supprimer la blague dans le store Redux
console.log('Suppression de la blague réussie');
} else {
console.log('Erreur lors de la requête DELETE');
}
} catch (error) {
console.log('Erreur :', error);
}
};
};
export const deleteCustomJoke = (jokeId) => {
return deleteItem(jokeId)
}

@ -0,0 +1,47 @@
// Fonction pour ajouter une blague aux favoris
import AsyncStorage from "@react-native-async-storage/async-storage";
import {SampleJoke} from "../../model/SampleJoke";
import {CustomJoke} from "../../model/CustomJoke";
const addFavorite = async (joke: SampleJoke | CustomJoke) => {
try {
let favorites: { sampleJokes: SampleJoke[], customJokes: CustomJoke[] } = await AsyncStorage.getItem('@favorites');
if (!favorites) {
favorites = { sampleJokes: [], customJokes: [] };
}
if (joke instanceof SampleJoke) {
favorites.sampleJokes.push(joke);
} else if (joke instanceof CustomJoke) {
favorites.customJokes.push(joke);
}
await AsyncStorage.setItem('@favorites', JSON.stringify(favorites));
} catch (error) {
console.error('Error adding favorite:', error);
}
};
const removeFavorite = async (jokeId: string | number) => {
try {
var favorites: { sampleJokes: SampleJoke[], customJokes: CustomJoke[] } = await AsyncStorage.getItem('@favorites');
if (!favorites) {
return;
}
favorites.sampleJokes = favorites.sampleJokes.filter(joke => joke.id !== jokeId);
favorites.customJokes = favorites.customJokes.filter(joke => joke.id !== jokeId);
await AsyncStorage.setItem('@favorites', JSON.stringify(favorites));
} catch (error) {
console.error('Error removing favorite:', error);
}
};
const getFavorites = async () => {
try {
const favoritesString = await AsyncStorage.getItem('@favorites');
if (favoritesString !== null) {
return JSON.parse(favoritesString);
}
} catch (error) {
console.error('Error getting favorites:', error);
}
return { sampleJokes: [], customJokes: [] };
};

@ -6,19 +6,21 @@ import {setCustomJokeById} from "../actions/CustomJoke";
export const getItem = <TItem>(uri:string, constructor : (json:any) => TItem, setItem: (item: TItem) => any) => {
return async dispatch => {
try {
console.log(";;;;;;;;;;;;;;", uri, ";;;;;;;;;;;;;;;;;;;")
const promise = await fetch(uri);
const Json = await promise.json();
const Item: TItem = constructor(Json);
console.log("===========", Item , "===================");
dispatch(setItem(Item));
} catch (error) {
console.log('Error---------', error);
}
}
}
export const getJokeById = (id) => {
return getItem<SampleJoke>('https://iut-weather-api.azurewebsites.net/jokes/samples/' + id , (elt) => new SampleJoke(elt["id"], elt["type"], elt["setup"], elt["image"]), (item) => setJokeById(item))
export const getJokeById = (id : number) => {
return getItem<SampleJoke>('https://iut-weather-api.azurewebsites.net/jokes/samples/' + id.toString() , (elt) => new SampleJoke(elt["id"], elt["type"], elt["setup"], elt["image"]), (item) => setJokeById(item))
}
export const getCustomJokeById = (id) => {
export const getCustomJokeById = (id: string) => {
return getItem<CustomJoke>('https://iut-weather-api.azurewebsites.net/jokes/' + id , (elt) => new CustomJoke(elt["id"], elt["type"], elt["setup"], elt["image"]), (item) => setCustomJokeById(item))
}

@ -13,7 +13,7 @@ export const getList = <TList>(uri:string, constructor : (json:any) => TList, se
const List: TList[] = listJson.map(elt => constructor(elt));
dispatch(setList(List));
} catch (error) {
console.log('Error---------', error);
console.log(`Error In getList ${uri} ---------`, error);
}
}
}

@ -1,7 +1,4 @@
import {setPostJoke} from "../actions/CustomJoke";
import {SampleJoke} from "../../model/SampleJoke";
import {setJokesList} from "../actions/SampleAction";
import {getList} from "./GetThunk";
export const setItem = <TItem>(
uri: string,

@ -0,0 +1,21 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import {Theme} from "@react-navigation/native";
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 : null;
} catch(e) {
console.log(e);
}
}

@ -5,7 +5,7 @@ import '../types/extension';
import {useDispatch, useSelector} from "react-redux";
import {Image, StyleSheet, Text, TextInput, TouchableOpacity, View} from "react-native";
import {darksalmonColor, greyColor, indigoColor, purpleColor, whiteColor} from "../assets/Theme";
import {getSampleJokesList} from "../redux/thunk/GetThunk";
import {getCustomJokesList, getSampleJokesList} from "../redux/thunk/GetThunk";
import React, {useEffect} from "react";
import {postCustomJoke} from "../redux/thunk/PostThunk";
@ -25,6 +25,9 @@ export default function AddScreen() {
const handleCreate = () => {
// @ts-ignore
dispatch(postCustomJoke(joke, downgrade, category));
// @ts-ignore
dispatch(getCustomJokesList());
clearFields();
};

@ -5,35 +5,40 @@ import {darksalmonColor, purpleColor, whiteColor} from "../assets/Theme";
import {useDispatch, useSelector} from "react-redux";
import React, {useEffect, useState} from "react";
import {getCustomJokesList, getSampleJokesList} from "../redux/thunk/GetThunk";
const eye = require("../assets/eye_icon.png")
const hideEye = require("../assets/eye_off_icon.png")
export default function Catalogue() {
// @ts-ignore
const sampleJokes = useSelector(state => state.sampleReducer.jokes);
// @ts-ignore
const customJokes = useSelector(state => state.customReducer.customJokes);
const [joke, setJoke] = useState([])
const dispatch = useDispatch();
const eye = require("../assets/eye_icon.png")
const hideEye = require("../assets/eye_off_icon.png")
useEffect(() => {
const loadSamplesJokes = async () => {
// @ts-ignore
await dispatch(getSampleJokesList());
};
loadSamplesJokes();
}, [dispatch]);
const loadCustomJokes = async () => {
// @ts-ignore
await dispatch(getCustomJokesList());
};
const [showCustomJoke, setCustomJoke] = useState(false); // état local pour contrôler la visibilité de la description
const [showCustomJoke, setCustomJoke] = useState(false);
const toggleDescription = () => {
setCustomJoke(!showCustomJoke);
loadCustomJokes();
};
useEffect(() => {
if(!showCustomJoke) {
const loadSamplesJokes = async () => {
// @ts-ignore
await dispatch(getSampleJokesList());
};
loadSamplesJokes();
setJoke(sampleJokes)
} else {
const loadCustomJokes = async () => {
// @ts-ignore
await dispatch(getCustomJokesList());
};
loadCustomJokes();
setJoke(customJokes)
}
}, [dispatch, customJokes, sampleJokes]);
return (
<SafeAreaView style={styles.container}>
<View style={styles.columnContainer}>
@ -48,7 +53,7 @@ export default function Catalogue() {
</TouchableOpacity>
</View>
<View style={styles.container}>
<JokeItems jokes={showCustomJoke ? customJokes : sampleJokes}/>
<JokeItems jokes={joke}/>
</View>
</SafeAreaView>
)

@ -1,21 +1,106 @@
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 {Image, SafeAreaView, StyleSheet, Text, TouchableOpacity, View} from "react-native";
import {darksalmonColor, purpleColor, whiteColor} from "../assets/Theme";
import {useDispatch, useSelector} from "react-redux";
import React, {useEffect, useState} from "react";
import {getCustomJokesList, getSampleJokesList} from "../redux/thunk/GetThunk";
export default function Favorites() {
// @ts-ignore
const sampleJokes = useSelector(state => state.sampleReducer.jokes);
// @ts-ignore
const customJokes = useSelector(state => state.customReducer.customJokes);
const [joke, setJoke] = useState([])
const dispatch = useDispatch();
const eye = require("../assets/eye_icon.png")
const hideEye = require("../assets/eye_off_icon.png")
const [showCustomJoke, setCustomJoke] = useState(false); // état local pour contrôler la visibilité de la description
const toggleDescription = () => {
setCustomJoke(!showCustomJoke);
};
useEffect(() => {
if(!showCustomJoke) {
const loadSamplesJokes = async () => {
// @ts-ignore
await dispatch(getSampleJokesList());
};
loadSamplesJokes();
setJoke(sampleJokes)
} else {
const loadCustomJokes = async () => {
// @ts-ignore
await dispatch(getCustomJokesList());
};
loadCustomJokes();
setJoke(customJokes)
}
}, [dispatch, customJokes, sampleJokes]);
export default function Catalogue() {
const allJokes = [...customJokeStub, ...sampleJokeStub];
return (
<View style={styles.container}>
<JokeItems jokes={allJokes}/>
</View>
<SafeAreaView style={styles.container}>
<View style={styles.columnContainer}>
<Text style={styles.TextButton}>Afficher les exemples</Text>
<TouchableOpacity style={styles.Button} onPress={toggleDescription}>
<View style={styles.jokeTypeContainer}>
<Image
source={showCustomJoke ? hideEye : eye}
style={styles.imageButton}
/>
</View>
</TouchableOpacity>
</View>
<View style={styles.container}>
<JokeItems jokes={joke}/>
</View>
</SafeAreaView>
)
};
const styles = StyleSheet.create({
container: {
backgroundColor: purpleColor
backgroundColor: purpleColor,
flex:1,
},
Button:{
borderRadius : 5,
backgroundColor : darksalmonColor,
height:40,
width : 60,
flexDirection : "row"
},
jokeTypeContainer :{
display : "flex",
flex : 1,
flexDirection: "row",
alignItems : "center"
},
imageButton : {
margin : 10,
width: 40,
height:30,
top : 5,
alignSelf : "center",
backgroundColor: "none",
tintColor : whiteColor,
justifyContent: "center",
alignItems: "center",
},
TextButton : {
fontSize: 18,
color: whiteColor,
textAlign: 'center',
fontWeight: 'bold',
margin: 10,
},
columnContainer: {
marginLeft: 20,
marginRight: 20,
width: '90%',
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
}
});

@ -6,8 +6,6 @@ import Categs from "../components/Categs";
import {useDispatch, useSelector} from "react-redux";
import {useEffect} from "react";
import {getCategoriesList, getLastSampleJokesList} from "../redux/thunk/GetThunk";
import SampleReducer from "../redux/reducers/SampleReducer";
import CategoryReducer from "../redux/reducers/CategoryReducer";
export default function Catalogue() {
// @ts-ignore

@ -5,35 +5,37 @@ import {useDispatch, useSelector} from "react-redux";
import React, {useEffect, useState} from "react";
import {getCustomJokeById, getJokeById} from "../redux/thunk/GetByThunk";
import JokeDetail from "../components/JokeDetail";
import {AppDispatch, AppState} from "../redux/store";
import {CustomJoke} from "../model/CustomJoke";
import {SampleJoke} from "../model/SampleJoke";
export default function JokeDetailsScreen({route}) {
const idJokeDetail = route.params.idJoke;
// @ts-ignore
const joke = useSelector(state => state.sampleReducer.jokes);
// @ts-ignore
const customJoke = useSelector(state => state.customReducer.customJoke);
const [isCustomJoke, setCustomJoke] = useState(false); // état local pour contrôler la visibilité de la description
// @ts-ignore
const dispatch = useDispatch();
const joke = useSelector<AppState>(state => state.sampleReducer.joke);
const customJoke = useSelector<AppState>(state => state.customReducer.customJoke);
const [isCustomJoke, setCustomJoke] = useState(false);
const dispatch = useDispatch<AppDispatch>();
useEffect(() => {
if(idJokeDetail instanceof Number) {
if(typeof idJokeDetail == 'number') {
const loadJoke = async () => {
// @ts-ignore
await dispatch(getJokeById(idJokeDetail));
};
loadJoke();
setCustomJoke(!isCustomJoke)
} else {
const loadCustomJoke = async () => {
// @ts-ignore
await dispatch(getCustomJokeById(idJokeDetail));
};
loadCustomJoke();
}
}, [dispatch]);
if(!joke && !customJoke) return null;
return (
<View style={styles.container}>
{/*@ts-ignore}*/}
<JokeDetail joke={isCustomJoke ? joke : customJoke}/>
</View>
)

@ -1,21 +1,99 @@
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 {Image, StyleSheet, Switch, Text, View} from "react-native";
import {darksalmonColor, DefaultTheme, DarkTheme, greyColor, indigoColor, purpleColor, whiteColor} from "../assets/Theme";
import React, {useEffect, useState} from "react";
import {useTheme} from "@react-navigation/native";
import {storeTheme} from "../redux/thunk/ThemeThunk";
export default function Catalogue() {
const allJokes = [...customJokeStub, ...sampleJokeStub];
const light_mode = require("../assets/light_mode.png")
const dark_mode = require("../assets/dark_mode.png")
const [isDark, setDark] = React.useState(false)
const toggleTheme = () => {
setDark(previousState => {
const theme = !previousState;
const newTheme = theme ? DarkTheme : DefaultTheme;
storeTheme(newTheme);
return theme;
});
};
const styles = themeSettings();
return (
<View style={styles.container}>
<JokeItems jokes={allJokes}/>
<View style={styles.topText}>
<Text style={styles.title}>Réglages</Text>
<View style={styles.switchMode}>
<View style={styles.textContainer}>
<Image
source={isDark? dark_mode: light_mode}
style={styles.imageButton} />
<Text style={styles.darkModeText}>Dark Mode</Text>
</View>
<Switch
value={isDark}
onValueChange={toggleTheme}
style={styles.switchMode}
trackColor={{false: darksalmonColor, true: darksalmonColor}}
thumbColor={whiteColor} />
</View>
</View>
</View>
)
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: purpleColor
}
});
export function themeSettings() {
const theme = useTheme();
const colors = theme.colors;
const styles = StyleSheet.create({
container: {
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 10,
paddingRight: 10,
flex: 1,
justifyContent: 'center',
backgroundColor: colors.background,
flexDirection: 'column',
},
topText: {
flex: 1,
},
title: {
padding: 10,
fontSize: 20,
color: whiteColor,
fontWeight: 'bold'
},
imageButton : {
width: 30,
height:30,
alignSelf : "center",
tintColor: darksalmonColor,
},
switchMode: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
backgroundColor: indigoColor,
padding: 20,
margin: 10,
},
darkModeText: {
color: whiteColor,
fontSize: 20,
marginLeft: 10,
paddingTop: 5,
},
textContainer: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}
});
return styles;
}

@ -1707,6 +1707,13 @@
mkdirp "^1.0.4"
rimraf "^3.0.2"
"@react-native-async-storage/async-storage@^1.23.1":
version "1.23.1"
resolved "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.23.1.tgz"
integrity sha512-Qd2kQ3yi6Y3+AcUlrHxSLlnBvpdCEMVGFlVBneVOjaFaPU61g1huc38g339ysXspwY1QZA2aNhrk/KlHGO+ewA==
dependencies:
merge-options "^3.0.4"
"@react-native-community/cli-clean@12.3.0":
version "12.3.0"
resolved "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.0.tgz"
@ -3982,6 +3989,11 @@ is-path-inside@^3.0.2:
resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-obj@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz"
@ -4430,6 +4442,13 @@ memory-cache@~0.2.0:
resolved "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz"
integrity sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==
merge-options@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz"
integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==
dependencies:
is-plain-obj "^2.1.0"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
@ -5368,7 +5387,7 @@ react-native-safe-area-context@^4.9.0, "react-native-safe-area-context@>= 3.0.0"
react-freeze "^1.0.0"
warn-once "^0.1.0"
react-native@*, react-native@>=0.69, react-native@0.73.2:
react-native@*, "react-native@^0.0.0-0 || >=0.60 <1.0", react-native@>=0.69, react-native@0.73.2:
version "0.73.2"
resolved "https://registry.npmjs.org/react-native/-/react-native-0.73.2.tgz"
integrity sha512-7zj9tcUYpJUBdOdXY6cM8RcXYWkyql4kMyGZflW99E5EuFPoC7Ti+ZQSl7LP9ZPzGD0vMfslwyDW0I4tPWUCFw==

Loading…
Cancel
Save