Merge Conflict
continuous-integration/drone/push Build is passing Details

pull/15/head
root 2 years ago
commit bd5dce0f2b

@ -97,7 +97,10 @@ Notre environnement de travail se base sur plusieurs outils et langages :👇
--- ---
  ![React Native](https://img.shields.io/badge/React%20Native-000?style=for-the-badge&logo=react&logoColor=white&color=lightblue&textColor=white)   ![Redux](https://img.shields.io/badge/Redux-593D88?style=for-the-badge&logo=redux&logoColor=white)
  ![Docker](https://img.shields.io/badge/Docker-2496ED.svg?style=for-the-badge&logo=Docker&logoColor=white)
  ![React Native](https://img.shields.io/badge/React_Native-20232A?style=for-the-badge&logo=react&logoColor=61DAFB)
  ![Spotify Api](https://img.shields.io/badge/Spotify-1ED760?&style=for-the-badge&logo=spotify&logoColor=white)
  ![TypeScript](https://img.shields.io/badge/TypeScript-000?style=for-the-badge&logo=typescript&logoColor=white&color=blue)   ![TypeScript](https://img.shields.io/badge/TypeScript-000?style=for-the-badge&logo=typescript&logoColor=white&color=blue)
  ![JavaScript](https://img.shields.io/badge/JavaScript-000?style=for-the-badge&logo=javascript&logoColor=white&color=yellow)   ![JavaScript](https://img.shields.io/badge/JavaScript-000?style=for-the-badge&logo=javascript&logoColor=white&color=yellow)
@ -114,10 +117,19 @@ Notre environnement de travail se base sur plusieurs outils et langages :👇
La composition pour le projet se voit réaliser par deux élèves de l'IUT d'Aubière: La composition pour le projet se voit réaliser par deux élèves de l'IUT d'Aubière:
<br> <br>
⚙️ Emre KARTAL : emre.kartal@etu.uca.fr Emre KARTAL : emre.kartal@etu.uca.fr
<br> <br>
⚙️ David D'ALMEIDA : david.d_almeida@etu.uca.fr David D'ALMEIDA : david.d_almeida@etu.uca.fr
<a href = "https://codefirst.iut.uca.fr/git/emre.kartal">
<img src="https://codefirst.iut.uca.fr/git/avatars/402cf312e853192f42c0135a888725c2?size=870" width="50" >
</a>
<a href = "https://codefirst.iut.uca.fr/git/david.d_almeida">
<img src="https://codefirst.iut.uca.fr/git/avatars/0f8eaaad1e26d3de644ca522eccaea7c?size=870" width="50" >
</a>
<div align = center> <div align = center>
© PM2 (Projet inspiré par nos très chers développeurs de la Dafl Team (S.O les Dafl dev)) © PM2 (Projet inspiré par nos très chers développeurs de la Dafl Team (S.O les Dafl dev))
</div> </div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 136 KiB

@ -1,199 +0,0 @@
import React, { useState, useRef } from 'react';
import { Modal, View, StyleSheet, Text, FlatList, Animated, TouchableOpacity, ImageBackground, Image } from 'react-native';
// import Modal from "react-native-modal";
import {useNavigation} from "@react-navigation/native";
import normalize from '../components/Normalize';
import OnboardingItem from './OnboardingItem';
import Paginator from './Paginator';
import NextButton from './NextButton';
import slides from '../data/slides';
export default function Onboarding() {
const [currentIndex, setCurrentIndex] = useState(0);
const scrollX = useRef(new Animated.Value(0)).current;
const slidesRef = useRef(null);
const navigation = useNavigation();
const [isModalVisible, setIsModalVisible] = React.useState(false);
const handleModal = () => setIsModalVisible(() => !isModalVisible);
// @ts-ignore
const viewableItemsChanged = useRef(({ viewableItems }) => {
setCurrentIndex(viewableItems[0].index);
}).current;
const viewConfig = useRef({ viewAreaCoveragePercentThreshold: 50 }).current;
const scrollTo = () => {
if(currentIndex < slides.length - 1) {
// @ts-ignore
slidesRef.current.scrollToIndex({ index: currentIndex + 1 });
} else {
setIsModalVisible(() => !isModalVisible);
}
};
return (
// @ts-ignore
<View style={styles.container}>
<View style={styles.balise}>
<FlatList
data={slides}
renderItem={({item}) => <OnboardingItem item={item} />}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
bounces={false}
keyExtractor={(item) => item.id}
onScroll={Animated.event([{ nativeEvent: { contentOffset: { x: scrollX } } }], {
useNativeDriver: false,
})}
scrollEventThrottle={32}
onViewableItemsChanged={viewableItemsChanged}
viewabilityConfig={viewConfig}
ref={slidesRef}
/>
<Paginator data={slides} scrollX={scrollX}/>
<NextButton scrollTo={scrollTo} percentage={(currentIndex + 1) * (100 / slides.length)} />
</View>
<Modal animationType="slide" visible={isModalVisible} transparent={true} presentationStyle={'pageSheet'}>
<View style={styles.modalContent}>
<ImageBackground source={require("../assets/images/Background_Start_Page.png")} style={styles.backgroundImage}>
<View style={styles.modalView}>
<Text style={styles.versionText}>
v2.0
</Text>
<TouchableOpacity onPress={handleModal} style={styles.closeButtonCircle}>
<View>
<Image source={require("../assets/icons/icons/croix.png")} style={styles.imageButton}/>
</View>
</TouchableOpacity>
<Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo}/>
<TouchableOpacity
style={styles.buttonConnection}
onPress={() => {handleModal();
// @ts-ignore
navigation.navigate('Login');
}}>
<Text style={styles.text}>CONTINUER AVEC SPOTIFY</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.buttonInscription} onPress={() => {handleModal(); navigation.navigate('Register');}}>
<Text style={styles.text}>SINSCRIRE MAINTENANT</Text>
</TouchableOpacity>
<Image source={require("../assets/images/Flady.gif")} style={styles.mascot}/>
<TouchableOpacity style={styles.button2Connection} onPress={() => {handleModal(); navigation.navigate('Login');}}>
<Text style={styles.text}>SE CONNECTER</Text>
</TouchableOpacity>
</View>
</ImageBackground>
</View>
</Modal>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#141414'
},
imageLogo: {
width: normalize(324),
height: normalize(162),
marginBottom: '25%'
},
balise: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginBottom: normalize(110)
},
closeButtonCircle: {
backgroundColor: 'gray',
opacity: 0.4,
width: 40,
height: 40,
borderRadius: 20,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
top: 10,
right: 10
},
modalContent: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
backgroundImage: {
flex: 1,
width: '100%',
height: '100%',
},
imageButton: {
width: 20,
height: 20
},
versionText: {
position: 'absolute',
top: 50,
right: 10,
color: 'gray',
fontWeight: 'bold',
fontSize: normalize(17)
},
buttonConnection: {
width: 262,
height: 57,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#24CF5F',
borderRadius: 11,
borderColor: '#68F097',
borderWidth: 1,
marginBottom: 12
},
buttonInscription: {
width: 262,
height: 57,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#951DDE',
borderRadius: 11,
borderColor: '#C656ED',
borderWidth: 1,
marginBottom: 220
},
text: {
fontWeight: 'bold',
color: 'white',
fontSize: normalize(18)
},
button2Connection: {
width: '100%',
height: normalize(92),
backgroundColor: '#232123',
borderTopColor: '#3C3C3C',
borderTopWidth: 1,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
bottom: normalize(0)
},
mascot: {
width: normalize(130),
height: normalize(130),
position: 'absolute',
bottom: normalize(90),
right: normalize(0)
}
})

@ -1,9 +1,9 @@
export default class Artist { export default class Artist {
private id : string; private id: string;
private name : string; private name: string;
private url : string; // Image.source private url: string; // Image.source
constructor(id : string, name : string, url : string){ constructor(id: string, name: string, url: string) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.url = url; this.url = url;

@ -1,112 +1,112 @@
import { useState } from "react"; import { useState } from "react";
import SpotifyService from "../services/spotify/spotify.service"; import SpotifyService from "../services/spotify/spotify.service";
class Manager{ class Manager {
// injection de dépences // injection de dépences
spotifyService = new SpotifyService(); spotifyService = new SpotifyService();
userService = new userService(); userService = new userService();
private currentUser = useState(null); private currentUser = useState(null);
constructor() { constructor() {
} }
// spotify methods // spotify methods
apiAuthorization(url : string) { apiAuthorization(url: string) {
this.spotifyService.apiAuthorization(url); this.spotifyService.apiAuthorization(url);
} }
getCompleteMusic = async (id : string) :Promise<Music> =>{ getCompleteMusic = async (id: string): Promise<Music> => {
// Map info = await spotifyService.getTrackInfo(id); // Map info = await spotifyService.getTrackInfo(id);
// return Music(id, info['name'], info['artist'], info['cover']); // return Music(id, info['name'], info['artist'], info['cover']);
} }
removeFromPlaylist(id : string) { removeFromPlaylist(id: string) {
this.spotifyService.removeFromPlaylist(id); this.spotifyService.removeFromPlaylist(id);
} }
addToPlaylist(id : string) { addToPlaylist(id: string) {
this.spotifyService.addToPlaylist(id); this.spotifyService.addToPlaylist(id);
} }
playTrack(id : string) { playTrack(id: string) {
this.spotifyService.playTrack(id); this.spotifyService.playTrack(id);
} }
//////////////////////////////////////////// ////////////////////////////////////////////
// private readonly getTaskById: RequestHandler = async ( // private readonly getTaskById: RequestHandler = async (
// req: Request, // req: Request,
// res: Response, // res: Response,
// next: NextFunction // next: NextFunction
// ): Promise<Response | void> => { // ): Promise<Response | void> => {
// try { // try {
// const id = req.params.taskId; // const id = req.params.taskId;
// const userId = req.params.userId; // const userId = req.params.userId;
// const data = await this.Taskservice.getTaskById(id, userId); // const data = await this.Taskservice.getTaskById(id, userId);
// res.status(201).send(data); // res.status(201).send(data);
// } // }
// catch(error){ // catch(error){
// next(new HttpException(400, 'Cannot create post')); // next(new HttpException(400, 'Cannot create post'));
// } // }
// } // }
// private delete = async ( // private delete = async (
// req: Request, // req: Request,
// res: Response, // res: Response,
// next: NextFunction // next: NextFunction
// ): Promise<Response | void> => { // ): Promise<Response | void> => {
// try { // try {
// const id = req.params.taskId; // const id = req.params.taskId;
// const userId = req.params.userId; // const userId = req.params.userId;
// await this.Taskservice.DeleteTask(id, userId); // await this.Taskservice.DeleteTask(id, userId);
// return res.status(200).send({ status: "Success", msg: "Data Removed" }); // return res.status(200).send({ status: "Success", msg: "Data Removed" });
// } catch (error) { // } catch (error) {
// next(new HttpException(400, 'Cannot create post')); // next(new HttpException(400, 'Cannot create post'));
// } // }
// }; // };
// private updateTask = async ( // private updateTask = async (
// req: Request, // req: Request,
// res: Response, // res: Response,
// next: NextFunction // next: NextFunction
// ): Promise<Response | void> => { // ): Promise<Response | void> => {
// try { // try {
// const taskId = req.params.taskId; // const taskId = req.params.taskId;
// const userId = req.params.userId; // const userId = req.params.userId;
// const reqBody:CreateTaskReqBody = Object.assign({}, req.body); // const reqBody:CreateTaskReqBody = Object.assign({}, req.body);
// const updatedTask = await this.Taskservice.UpdateTask( // const updatedTask = await this.Taskservice.UpdateTask(
// // req.auth!.uid, // // req.auth!.uid,
// taskId, // taskId,
// userId, // userId,
// // firebase.auth().currentUser.getIdToken() // // firebase.auth().currentUser.getIdToken()
// reqBody.nom, // reqBody.nom,
// reqBody.description, // reqBody.description,
// reqBody.logo, // reqBody.logo,
// reqBody.duration, // reqBody.duration,
// reqBody.done, // reqBody.done,
// // reqBody.tags, // // reqBody.tags,
// reqBody.repepat, // reqBody.repepat,
// reqBody.deb, // reqBody.deb,
// reqBody.fin // reqBody.fin
// ); // );
// // res.send('Success add'); // // res.send('Success add');
// // res.status(201).json({ task }); // // res.status(201).json({ task });
// res.status(204).send(`Update a new contact: ${updatedTask}`); // res.status(204).send(`Update a new contact: ${updatedTask}`);
// } catch (error) { // } catch (error) {
// console.log(error); // console.log(error);
// next(new HttpException(403, 'Cannot create post')); // next(new HttpException(403, 'Cannot create post'));
// } // }
// }; // };
} }

@ -1,22 +1,22 @@
import Music from "./Music"; import Music from "./Music";
export class Spot { export class Spot {
private _userId : string; private _userId: string;
private _music : Music; private _music: Music;
constructor(userId : string, music : Music){ constructor(userId: string, music: Music) {
this._userId = userId; this._userId = userId;
this._music = music; this._music = music;
} }
get userSpotifyId(): string { get userSpotifyId(): string {
return this._userId; return this._userId;
} }
set userSpotifyId(value: string) { set userSpotifyId(value: string) {
this._userId = value; this._userId = value;
} }
get music(): Music { get music(): Music {
return this._music; return this._music;
} }
set music(value: Music) { set music(value: Music) {
this._music = value; this._music = value;
} }
} }

@ -1,34 +1,34 @@
class TokenSpotify { class TokenSpotify {
String _accessToken; String _accessToken;
final String _refreshToken; final String _refreshToken;
late DateTime _tokenEnd; late DateTime _tokenEnd;
// TokenSpotify(this._accessToken, this._refreshToken, int expiresIn) { // TokenSpotify(this._accessToken, this._refreshToken, int expiresIn) {
// _setTokenEnd(expiresIn); // _setTokenEnd(expiresIn);
// } // }
// _setTokenEnd(int expiresIn) { // _setTokenEnd(int expiresIn) {
// _tokenEnd = DateTime.now().add(Duration(seconds: expiresIn)); // _tokenEnd = DateTime.now().add(Duration(seconds: expiresIn));
// } // }
// Future<String> getAccessToken() async { // Future<String> getAccessToken() async {
// if (DateTime.now().isAfter(_tokenEnd)) { // if (DateTime.now().isAfter(_tokenEnd)) {
// await _actualiseToken(); // await _actualiseToken();
// } // }
// return _accessToken; // return _accessToken;
// } // }
// _actualiseToken() async { // _actualiseToken() async {
// var urlToken = Uri.https('accounts.spotify.com', 'api/token', { // var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
// 'grant_type': 'refresh_token', // 'grant_type': 'refresh_token',
// 'refresh_token': _refreshToken, // 'refresh_token': _refreshToken,
// 'client_id': ApiSpotifyIdentification.clientId // 'client_id': ApiSpotifyIdentification.clientId
// }); // });
// setResponse(await http.post(urlToken, headers: <String, String>{ // setResponse(await http.post(urlToken, headers: <String, String>{
// 'Content-Type': 'application/x-www-form-urlencoded' // 'Content-Type': 'application/x-www-form-urlencoded'
// })); // }));
// var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map; // var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
// _accessToken = decodedResponse['access_token']; // _accessToken = decodedResponse['access_token'];
// _setTokenEnd(decodedResponse['expires_in']); // _setTokenEnd(decodedResponse['expires_in']);
// } // }
} }

@ -1,42 +1,42 @@
export class User { export class User {
//attributes from DAFL //attributes from DAFL
private _idFlad : string; private _idFlad: string;
private _idSpotify : string; private _idSpotify: string;
private _email : string; private _email: string;
private _createdAt : Date; private _createdAt: Date;
private _name : string; private _name: string;
public image : string = require('../assets/images/jul.png'); public image: string = require('../assets/images/jul.png');
//constructors //constructors
constructor(idFlad : string, idSpotify : string, email : string, createdAt : Date, name : string, image : string){ constructor(idFlad: string, idSpotify: string, email: string, createdAt: Date, name: string, image: string) {
this._name = name; this._name = name;
this._idFlad = idFlad; this._idFlad = idFlad;
this._idSpotify = idSpotify; this._idSpotify = idSpotify;
this._createdAt = createdAt; this._createdAt = createdAt;
this._email = email; this._email = email;
this.image = image; this.image = image;
} }
get idFlad(): string {
return this._idFlad;
}
get idSpotify(): string {
return this._idSpotify;
}
get email(): string {
return this._email;
}
get createAt(): Date {
return this._createdAt;
}
get name(): string {
return this._name;
}
static empty() { get idFlad(): string {
return new User('','','',new Date(),'',require('../assets/images/jul.png')); return this._idFlad;
} }
get idSpotify(): string {
return this._idSpotify;
}
get email(): string {
return this._email;
}
get createAt(): Date {
return this._createdAt;
}
get name(): string {
return this._name;
}
toString() { static empty() {
return 'User : ' + this.idFlad + ', ' + this.name + ', ' + this.idSpotify; return new User('', '', '', new Date(), '', require('../assets/images/jul.png'));
} }
toString() {
return 'User : ' + this.idFlad + ', ' + this.name + ', ' + this.idSpotify;
} }
}

@ -0,0 +1,6 @@
export const GraphicalCharterDark = {
"body": "#141414",
"Text": "white",
"Card": "#232123",
"Line": "#403F3F"
}

@ -0,0 +1,6 @@
export const GraphicalCharterLight = {
"body": "#f2f2f6",
"Text": "black",
"Card": "#fff",
"Line": "#e2e2e3"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 KiB

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 KiB

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 KiB

After

Width:  |  Height:  |  Size: 590 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 KiB

Binary file not shown.

@ -0,0 +1,10 @@
import React from 'react';
export default function AdjustSize(Text: String) {
const titleLength = Text.length;
const minFontSize = 23;
const maxFontSize = 48;
const fontRatio = 1.1;
const fontSize = Math.max(minFontSize, maxFontSize - (titleLength * fontRatio));
return fontSize;
}

@ -2,45 +2,45 @@ import { View, useWindowDimensions } from "react-native";
import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, withTiming } from "react-native-reanimated"; import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, withTiming } from "react-native-reanimated";
interface SpotProps { interface SpotProps {
spot: { name: string, sourceUrl: string, index : number }; spot: { name: string, sourceUrl: string, index: number };
} }
const halfPi = Math.PI/2; const halfPi = Math.PI / 2;
const AnimatedParalax = ({}) => { const AnimatedParalax = ({ }) => {
const {width, height} = useWindowDimensions(); const { width, height } = useWindowDimensions();
const sensor = useAnimatedSensor(SensorType.ROTATION); const sensor = useAnimatedSensor(SensorType.ROTATION);
const styleAniamatedImage = useAnimatedStyle(() => { const styleAniamatedImage = useAnimatedStyle(() => {
const {yaw, pitch, roll} = sensor.sensor.value; const { yaw, pitch, roll } = sensor.sensor.value;
const verticalAxis =interpolate( const verticalAxis = interpolate(
pitch, pitch,
[-halfPi,halfPi], [-halfPi, halfPi],
[-25, 25] [-25, 25]
) )
const horizontalAxis =interpolate( const horizontalAxis = interpolate(
roll, roll,
[-halfPi*2,halfPi*2], [-halfPi * 2, halfPi * 2],
[-35, 35] [-35, 35]
) )
return { return {
top : verticalAxis, top: verticalAxis,
left : horizontalAxis, left: horizontalAxis,
}; };
}) })
return ( return (
<View style={{ flex: 1, justifyContent : 'flex-start', alignItems : 'center' }}> <View style={{ flex: 1, justifyContent: 'flex-start', alignItems: 'center' }}>
<Animated.Image <Animated.Image
source={{ source={{
uri:spot.sourceUrl , uri: spot.sourceUrl,
}} }}
style={[ style={[
{ {
width: 370, width: 370,
height: 370, height: 370,
borderRadius : 24, borderRadius: 24,
resizeMode: 'stretch', resizeMode: 'stretch',
},styleAniamatedImage }, styleAniamatedImage
]} ]}
/> />
</View> </View>

@ -1,9 +1,9 @@
import { View, StyleSheet, Dimensions, Image, TouchableOpacity } from "react-native"; import { View, StyleSheet, Dimensions, Image, TouchableOpacity } from "react-native";
import Animated, { import Animated, {
Layout, Layout,
ZoomIn, ZoomIn,
ZoomOut, ZoomOut,
} from "react-native-reanimated"; } from "react-native-reanimated";
const { width } = Dimensions.get("window"); const { width } = Dimensions.get("window");
const SIZE = width / 3; const SIZE = width / 3;
@ -14,25 +14,25 @@ import { useRef, useState } from "react";
interface ArtistProps { interface ArtistProps {
artist: Music; artist: Music;
onPress: () => void; onPress: () => void;
} }
export const Artist = ({ artist, onPress }: ArtistProps) => { export const Artist = ({ artist, onPress }: ArtistProps) => {
const source = typeof artist.image === 'string' ? { uri: artist.image } : artist.image; const source = typeof artist.image === 'string' ? { uri: artist.image } : artist.image;
//@ts-ignore //@ts-ignore
const onSingleTapEvent = (event) => { const onSingleTapEvent = (event) => {
if (event.nativeEvent.state === State.ACTIVE) { if (event.nativeEvent.state === State.ACTIVE) {
alert('Hey single tap!'); alert('Hey single tap!');
} }
}; };
const doubleTapRef = useRef(null); const doubleTapRef = useRef(null);
const [selected,setSeleted] = useState(false); const [selected, setSeleted] = useState(false);
const onS = () => { const onS = () => {
setSeleted(!selected); setSeleted(!selected);
onPress(); onPress();
}; };
return ( return (
<TouchableOpacity onPress={onS}> <TouchableOpacity onPress={onS}>
<Animated.View <Animated.View
style={styles.container} style={styles.container}
entering={ZoomIn} entering={ZoomIn}
@ -41,9 +41,9 @@ export const Artist = ({ artist, onPress }: ArtistProps) => {
> >
<View style={styles.card}> <View style={styles.card}>
<Image source={source} style={styles.image} /> <Image source={source} style={styles.image} />
{ selected && ( {selected && (
<View style={styles.cheked}> <View style={styles.cheked}>
<Icon name="check-circle" color="black" size={24} /> <Icon name="check-circle" color="black" size={24} />
</View> </View>
) )
@ -51,31 +51,31 @@ export const Artist = ({ artist, onPress }: ArtistProps) => {
</View> </View>
</Animated.View> </Animated.View>
</TouchableOpacity> </TouchableOpacity>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
width: SIZE, width: SIZE,
height: SIZE, height: SIZE,
padding: 8, padding: 8,
}, },
card: { card: {
flex: 1, flex: 1,
padding: 8, padding: 8,
alignItems: "flex-end", alignItems: "flex-end",
}, },
image: { image: {
borderRadius: 8, borderRadius: 8,
...StyleSheet.absoluteFillObject, ...StyleSheet.absoluteFillObject,
width: undefined, width: undefined,
height: undefined, height: undefined,
}, },
cheked : { cheked: {
backgroundColor : "white", backgroundColor: "white",
borderRadius : 100, borderRadius: 100,
alignItems : "center", alignItems: "center",
} }
}); });

@ -1,49 +1,49 @@
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { View, StyleSheet ,Text,Image, Pressable, Linking, Alert} from 'react-native' import { View, StyleSheet, Text, Image, Pressable, Linking, Alert } from 'react-native'
interface ArtistChipProps { interface ArtistChipProps {
backgroundColor : string; backgroundColor: string;
artist : Artist; artist: Artist;
} }
const ArtistChip = ({artist} : ArtistChipProps) => { const ArtistChip = ({ artist }: ArtistChipProps) => {
const handlePress = useCallback(async () => { const handlePress = useCallback(async () => {
// Checking if the link is supported for links with custom URL scheme. // Checking if the link is supported for links with custom URL scheme.
const supported = await Linking.canOpenURL(artist.url); const supported = await Linking.canOpenURL(artist.url);
if (supported) { if (supported) {
// Opening the link with some app, if the URL scheme is "http" the web link should be opened // Opening the link with some app, if the URL scheme is "http" the web link should be opened
// by some browser in the mobile // by some browser in the mobile
await Linking.openURL(artist.url); await Linking.openURL(artist.url);
} else { } else {
Alert.alert(`Don't know how to open this URL: ${artist.url}`); Alert.alert(`Don't know how to open this URL: ${artist.url}`);
} }
}, [artist.url]); }, [artist.url]);
return ( return (
<View>
<Pressable onPress={handlePress}>
<View> <View>
<Pressable onPress={handlePress}> <Image
<View> source={{
<Image uri: artist.image,
source={{ }}
uri: artist.image, ></Image>
}} </View>
></Image>
</View>
<View> <View>
<Text>ii</Text> <Text>ii</Text>
</View>
</Pressable>
</View> </View>
); </Pressable>
}; </View>
);
};
const styles = StyleSheet.create({ const styles = StyleSheet.create({
input : { input: {
justifyContent : 'center', justifyContent: 'center',
alignItems : 'center', alignItems: 'center',
placeholder : "placeholde" placeholder: "placeholde"
}, },
}) })

@ -1,7 +1,7 @@
import { View, Image , Dimensions, StyleSheet } from 'react-native' import { View, Image, Dimensions, StyleSheet } from 'react-native'
import React from 'react' import React from 'react'
import Animated,{ Extrapolate, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated'; import Animated, { Extrapolate, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
import normalize from '../components/Normalize';
import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler'; import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
const SCREEN_WIDTH = Dimensions.get('window').width const SCREEN_WIDTH = Dimensions.get('window').width
@ -11,251 +11,257 @@ const SCREEN_HEIGHT = Dimensions.get('window').height
// const height = wWidht * (465/264); // const height = wWidht * (465/264);
// const borderRadius = 24; // const borderRadius = 24;
interface CardProps { interface CardProps {
title: string; title: string;
image: any; image: any;
onSwipe: (direction: "left" | "right" | "down") => void; onSwipe: (direction: "left" | "right" | "down") => void;
} }
type ContextType = { type ContextType = {
translateX: number; translateX: number;
translateY: number; translateY: number;
}; };
const Card = ({ title, image, onSwipe } : CardProps) => { const Card = ({ title, image, onSwipe }: CardProps) => {
const translateX = useSharedValue(0); const translateX = useSharedValue(0);
const translateY = useSharedValue(0); const translateY = useSharedValue(0);
const scale = useSharedValue(1); const scale = useSharedValue(1);
const onGestureEvent = useAnimatedGestureHandler< const onGestureEvent = useAnimatedGestureHandler<
PanGestureHandlerGestureEvent, PanGestureHandlerGestureEvent,
ContextType ContextType
>({ >({
onStart : (event, context) => { onStart: (event, context) => {
context.translateX = translateX.value; context.translateX = translateX.value;
context.translateY = translateY.value; context.translateY = translateY.value;
}, },
onActive : (event, context) => { onActive: (event, context) => {
translateX.value = event.translationX + context.translateX; translateX.value = event.translationX + context.translateX;
translateY.value = event.translationY + context.translateY; translateY.value = event.translationY + context.translateY;
}, },
onEnd : (event, context) => { onEnd: (event, context) => {
console.log(translateX.value - translateY.value); console.log(translateX.value - translateY.value);
// console.log(translateY.value); // console.log(translateY.value);
// translateX.value = withSpring(0); // translateX.value = withSpring(0);
// translateY.value = withSpring(snapPoint(translateY.value,velocityY, snapPoints )) // translateY.value = withSpring(snapPoint(translateY.value,velocityY, snapPoints ))
if (translateX.value > 160) { if (translateX.value > 160) {
console.log("translateX2"); console.log("translateX2");
runOnJS(onSwipe)("right"); runOnJS(onSwipe)("right");
} else if (translateX.value < -160) { } else if (translateX.value < -160) {
runOnJS(onSwipe)("left"); runOnJS(onSwipe)("left");
// onSwipe("left"); // onSwipe("left");
}else if (translateY.value > 250) { } else if (translateY.value > 250) {
runOnJS(onSwipe)("down"); runOnJS(onSwipe)("down");
// onSwipe("left"); // onSwipe("left");
} }
else { else {
translateX.value = withSpring(0); translateX.value = withSpring(0);
translateY.value = withSpring(0); translateY.value = withSpring(0);
} }
}, },
}); });
//better to have 2 listerner => 2 useAnimatedStyle ou faire une ftc qui retourne l'verse de une useAnimatedStyle //better to have 2 listerner => 2 useAnimatedStyle ou faire une ftc qui retourne l'verse de une useAnimatedStyle
const opacLStyle = useAnimatedStyle(() => { const opacLStyle = useAnimatedStyle(() => {
const opacityl = interpolate const opacityl = interpolate
( translateX.value, (translateX.value,
[-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4], [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4],
[ 0,0, 1]); [0, 0, 1]);
return { return {
opacity : opacityl, opacity: opacityl,
}; };
}); });
const opacRStyle = useAnimatedStyle(() => { const opacRStyle = useAnimatedStyle(() => {
const opacityl = interpolate const opacityl = interpolate
( translateX.value, (translateX.value,
[-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 2], [-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 2],
[1, 0, 0]); [1, 0, 0]);
return { return {
opacity : opacityl, opacity: opacityl,
}; };
}); });
const opacCStyle = useAnimatedStyle(() => { const opacCStyle = useAnimatedStyle(() => {
const opacityl = interpolate const opacityl = interpolate
( translateX.value, (translateX.value,
[-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 4], [-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 4],
[0.35, 0, 0.35]); [0.35, 0, 0.35]);
return { return {
opacity : opacityl, opacity: opacityl,
}; };
}); });
const opacCStyle2 = useAnimatedStyle(() => { const opacCStyle2 = useAnimatedStyle(() => {
const opacityl = interpolate const opacityl = interpolate
( translateY.value, (translateY.value,
[0,SCREEN_HEIGHT/4], [0, SCREEN_HEIGHT / 4],
[0,0.35]); [0, 0.35]);
return { return {
opacity : opacityl, opacity: opacityl,
}; };
}); });
const opacDStyle = useAnimatedStyle(() => { const opacDStyle = useAnimatedStyle(() => {
const opacityl = interpolate const opacityl = interpolate
( translateY.value, (translateY.value,
[ 100, 300], [100, 300],
[ 0, 1]); [0, 1]);
return { return {
opacity : opacityl, opacity: opacityl,
}; };
}); });
const horizontalThreshold = SCREEN_WIDTH * 0.65; const horizontalThreshold = SCREEN_WIDTH * 0.65;
const rotateStyle = useAnimatedStyle(() => { const rotateStyle = useAnimatedStyle(() => {
const rot = interpolate const rot = interpolate
( translateX.value, (translateX.value,
[-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2], [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
[30, 0, 30], [30, 0, 30],
Extrapolate.CLAMP); Extrapolate.CLAMP);
return { return {
transform: [{ rotate: `${rot}deg` },{ transform: [{ rotate: `${rot}deg` }, {
translateX: withSpring(translateX.value), translateX: withSpring(translateX.value),
} ], }],
}; };
}); });
const styleCardsNew = useAnimatedStyle(() => { const styleCardsNew = useAnimatedStyle(() => {
const factor = 1; const factor = 1;
const rot = interpolate const rot = interpolate
( translateX.value, (translateX.value,
[0, factor * horizontalThreshold], [0, factor * horizontalThreshold],
[0, 15], [0, 15],
); );
return { return {
transform: [ transform: [
{ scale: scale.value }, { scale: scale.value },
{ translateX: translateX.value }, { translateX: translateX.value },
{ translateY: translateY.value }, { translateY: translateY.value },
{ rotateZ: `${rot}deg` }, { rotateZ: `${rot}deg` },
] ]
}; };
}); });
// Calculate the distance of the card from its starting position // Calculate the distance of the card from its starting position
const rStyle = useAnimatedStyle(() => { const rStyle = useAnimatedStyle(() => {
return { return {
transform: [ transform: [
{ {
translateX: translateX.value, translateX: translateX.value,
}, },
{ {
translateY: translateY.value, translateY: translateY.value,
}, },
], ],
}; };
}); });
console.log('==========================================',SCREEN_WIDTH/4 , "==============================="); console.log('==========================================', SCREEN_WIDTH / 4, "===============================");
return ( return (
<View> <View>
<PanGestureHandler onGestureEvent={onGestureEvent}> <PanGestureHandler onGestureEvent={onGestureEvent}>
<Animated.View style={[ styleCardsNew, styles.container]}> <Animated.View style={[styleCardsNew, styles.container]}>
<Animated.View style={[ styles.image,{backgroundColor: 'black',elevation: 100, <Animated.View style={[styles.image, {
position: "absolute",borderWidth : 8, borderColor : '#FFF', backgroundColor: 'black', elevation: 100,
zIndex: 1000,}, opacCStyle]}> position: "absolute", borderWidth: 8, borderColor: '#FFF',
</Animated.View> zIndex: 1000,
<Animated.View style={[ styles.image,{backgroundColor: 'black',elevation: 100, }, opacCStyle]}>
position: "absolute",borderWidth : 8, borderColor : '#FFF', </Animated.View>
zIndex: 1000,}, opacCStyle2]}> <Animated.View style={[styles.image, {
</Animated.View> backgroundColor: 'black', elevation: 100,
<Image source={{uri : image}} style={[styles.image]} /> position: "absolute", borderWidth: 8, borderColor: '#FFF',
<> zIndex: 1000,
<Animated.View }, opacCStyle2]}>
style={[{ </Animated.View>
// transform: [{ rotate: "30deg" }], <Image source={{ uri: image }} style={[styles.image]} />
<>
elevation: 100, <Animated.View
position: "absolute", style={[{
zIndex: 1000, // transform: [{ rotate: "30deg" }],
},opacRStyle]}
> elevation: 100,
<Image style={[{alignSelf : "center"}]} position: "absolute",
source={require('../assets/icons/icons/icon_dislike.png')} zIndex: 1000,
/> }, opacRStyle]}
>
<Image style={[{ alignSelf: "center" }]}
source={require('../assets/icons/icons/icon_dislike.png')}
/>
</Animated.View> </Animated.View>
<Animated.View <Animated.View
style={[{ style={[{
width: '100%', width: '100%',
height: '100%', height: '100%',
position: "absolute", position: "absolute",
justifyContent : "center", justifyContent: "center",
alignContent : "center", alignContent: "center",
zIndex: 1000, zIndex: 1000,
elevation: 100, elevation: 100,
},opacLStyle]} }, opacLStyle]}
> >
<Image style={[{alignSelf : "center"}]} <Image style={[{ alignSelf: "center" }]}
source={require('../assets/icons/icons/icon_like.png')} source={require('../assets/icons/icons/icon_like.png')}
/> />
</Animated.View> </Animated.View>
<Animated.View <Animated.View
style={[{ style={[{
width: '100%', width: '100%',
height: '100%', height: '100%',
position: "absolute", position: "absolute",
justifyContent : "center", justifyContent: "center",
alignContent : "center", alignContent: "center",
elevation: 100, elevation: 100,
zIndex: 1000, zIndex: 1000,
},opacDStyle]} }, opacDStyle]}
> >
<Image style={[{alignSelf : "center",width: 126.27, <Image style={[{
height: 118.64, }]} alignSelf: "center", width: 126.27,
source={require('../assets/icons/icons/icon_discovery.png')} height: 118.64,
}]}
/> source={require('../assets/icons/icons/icon_discovery.png')}
/>
</Animated.View> </Animated.View>
</> </>
</Animated.View> </Animated.View>
</PanGestureHandler> </PanGestureHandler>
</View> </View>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
card : { card: {
justifyContent : 'center', justifyContent: 'center',
alignItems : 'center', alignItems: 'center',
}, },
image : { image: {
borderRadius : 24, borderRadius: 24,
resizeMode: 'stretch', resizeMode: 'stretch',
height: 362, height: normalize(420),
width: 362, width: normalize(420),
}, },
container: { container: {
flex: 1, flex: 1,
width: '100%', width: '100%',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
} }
}) })
export default Card; export default Card;

@ -1,75 +1,78 @@
import React from 'react'; import React from 'react';
import { StyleSheet, Text, View , Image } from 'react-native'; import { StyleSheet, Text, View, Image } from 'react-native';
import { SharedElement } from 'react-navigation-shared-element'; import { SharedElement } from 'react-navigation-shared-element';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
type CustomCardMusic = { //Props type CustomCardMusic = { //Props
image: string; image: string;
title: string; title: string;
description: string; description: string;
id : string; id: string;
} }
export default function CardMusic(CBP: CustomCardMusic) { export default function CardMusic(CBP: CustomCardMusic) {
const isDark = useSelector(state => state.userReducer.dark);
const currentMusic = useSelector(state => state.appReducer.currentMusic); const style = isDark ? GraphicalCharterLight : GraphicalCharterDark;
const currentMusic = useSelector(state => state.appReducer.currentMusic);
const source = typeof CBP.image === 'string' ? { uri: CBP.image } : CBP.image; const source = typeof CBP.image === 'string' ? { uri: CBP.image } : CBP.image;
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 15
},
imageContainer: {
width: normalize(92),
height: normalize(92),
alignItems: 'center',
justifyContent: 'center',
marginRight: 20,
marginLeft: 20
},
image: {
width: '100%',
height: '100%',
borderRadius: 10
},
textContainer: {
flex: 1,
alignItems: 'flex-start',
justifyContent: 'center',
},
title: {
fontWeight: 'bold',
color: style.Text,
fontSize: normalize(23),
marginBottom: 10
},
description: {
color: style.Text,
fontSize: normalize(18)
},
currentMusic: {
color: 'red'
}
});
return ( return (
<View style={styles.container}> <View style={styles.container}>
<View style={styles.imageContainer}> <View style={styles.imageContainer}>
<Image source={source} style={styles.image}/> <Image source={source} style={styles.image} />
</View> </View>
<View style={styles.textContainer}> <View style={styles.textContainer}>
{/* currentMusic.id === CBP.id && styles.currentMusic */} {/* currentMusic.id === CBP.id && styles.currentMusic */}
<Text style={[styles.title]}>{CBP.title}</Text> <Text style={[styles.title]}>{CBP.title}</Text>
<Text style={[styles.description]}>{CBP.description}</Text> <Text style={[styles.description]}>{CBP.description}</Text>
</View> </View>
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 15
},
imageContainer: {
width: normalize(92),
height: normalize(92),
alignItems: 'center',
justifyContent: 'center',
marginRight: 20,
marginLeft: 20
},
image: {
width: '100%',
height: '100%',
borderRadius: 10
},
textContainer: {
flex: 1,
alignItems: 'flex-start',
justifyContent: 'center',
},
title: {
fontWeight: 'bold',
color: 'white',
fontSize: normalize(23),
marginBottom: 10
},
description: {
color: 'white',
fontSize: normalize(18)
},
currentMusic: {
color: 'red'
}
});

@ -1,75 +1,75 @@
import { useState } from 'react'; import { useState } from 'react';
import { View, Text, Image ,PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, TextInput } from 'react-native' import { View, Text, Image, PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, TextInput } from 'react-native'
import Animated, { interpolate, lessThan, multiply, useAnimatedStyle } from 'react-native-reanimated'; import Animated, { interpolate, lessThan, multiply, useAnimatedStyle } from 'react-native-reanimated';
import HalfCirlce from './HalfCircle'; import HalfCirlce from './HalfCircle';
interface CircularProps { interface CircularProps {
background : string, background: string,
foreground : string, foreground: string,
progress : Animated.Value<number>, progress: Animated.Value<number>,
radius : number; radius: number;
} }
const PI= Math.PI; const PI = Math.PI;
const FladInput = ({background, foreground, progress} : CircularProps) => { const FladInput = ({ background, foreground, progress }: CircularProps) => {
const [focused, setFocused] = useState<boolean>(false); const [focused, setFocused] = useState<boolean>(false);
const theta = multiply(progress,2*PI); const theta = multiply(progress, 2 * PI);
const rotateTop = theta; const rotateTop = theta;
const opacity = lessThan(theta, PI); const opacity = lessThan(theta, PI);
const rotateAnimation = useAnimatedStyle(() => { const rotateAnimation = useAnimatedStyle(() => {
const rotate = interpolate const rotate = interpolate
( theta, (theta,
[PI, 2*PI], [PI, 2 * PI],
[0,PI]); [0, PI]);
return { return {
...StyleSheet.absoluteFillObject, ...StyleSheet.absoluteFillObject,
transform: [ transform: [
{rotate: rotate}, { rotate: rotate },
{translateX: RADUIS/2}, { translateX: RADUIS / 2 },
{translateY: RADUIS/2} { translateY: RADUIS / 2 }
], ],
}; };
}); });
const rotateAnimation2 = useAnimatedStyle(() => { const rotateAnimation2 = useAnimatedStyle(() => {
const rotate = interpolate const rotate = interpolate
( theta, (theta,
[PI, 2*PI], [PI, 2 * PI],
[0,PI]); [0, PI]);
return { return {
...StyleSheet.absoluteFillObject, ...StyleSheet.absoluteFillObject,
transform: [ transform: [
{rotate: theta}, { rotate: theta },
{translateX: RADUIS/2}, { translateX: RADUIS / 2 },
{translateY: RADUIS/2} { translateY: RADUIS / 2 }
], ],
}; };
}); });
return ( return (
<> <>
<View style={{zIndex : 1}}> <View style={{ zIndex: 1 }}>
<HalfCirlce backgroundColor={background}/> <HalfCirlce backgroundColor={background} />
<Animated.View style={{...StyleSheet.absoluteFillObject, transform : [{rotate : '180%'}], opacity}}> <Animated.View style={{ ...StyleSheet.absoluteFillObject, transform: [{ rotate: '180%' }], opacity }}>
<HalfCirlce backgroundColor={background}/> <HalfCirlce backgroundColor={background} />
</Animated.View> </Animated.View>
</View> </View>
<View style={{ transform : [{rotate : '180%'}]}}> <View style={{ transform: [{ rotate: '180%' }] }}>
<HalfCirlce backgroundColor={background}/> <HalfCirlce backgroundColor={background} />
<Animated.View style={{}}> <Animated.View style={{}}>
<HalfCirlce backgroundColor={background}/> <HalfCirlce backgroundColor={background} />
</Animated.View> </View> </Animated.View> </View>
</> </>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
input : { input: {
justifyContent : 'center', justifyContent: 'center',
alignItems : 'center', alignItems: 'center',
placeholder : "placeholde" placeholder: "placeholde"
}, },
}) })

@ -91,7 +91,7 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { StyleSheet, Text, View , Image } from 'react-native'; import { StyleSheet, Text, View, Image } from 'react-native';
import Animated, { useAnimatedStyle, useDerivedValue, useSharedValue, withSpring, withTiming } from 'react-native-reanimated'; import Animated, { useAnimatedStyle, useDerivedValue, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
import { SharedElement } from 'react-navigation-shared-element'; import { SharedElement } from 'react-navigation-shared-element';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
@ -110,6 +110,20 @@ export default function CurrentMusic() {
return ( return (
<View style={{ <View style={{
width: 200,
height: 200,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 25,
// iOS
shadowOpacity: 0.2,
shadowOffset: { width: 0, height: 0 },
shadowRadius: 20,
// Android
elevation: 2,
}}>
<Animated.View style={[{
width: 200, width: 200,
height: 200, height: 200,
backgroundColor: 'white', backgroundColor: 'white',
@ -122,24 +136,10 @@ export default function CurrentMusic() {
shadowRadius: 20, shadowRadius: 20,
// Android // Android
elevation: 2, elevation: 2,
}}> }, { overflow: 'hidden' }]}>
<Animated.View style={[{
width: 200,
height: 200,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 25,
// iOS
shadowOpacity: 0.2,
shadowOffset: { width: 0, height: 0 },
shadowRadius: 20,
// Android
elevation: 2,
}, { overflow: 'hidden' }]}>
<Animated.View style={rStyle} /> <Animated.View style={rStyle} />
</Animated.View> </Animated.View>
</View> </View>
); );
} }

@ -1,113 +1,113 @@
import { View, Text, Image , Dimensions, StyleSheet } from 'react-native' import { View, Text, Image, Dimensions, StyleSheet } from 'react-native'
import React, { useEffect, useRef, useState } from 'react' import React, { useEffect, useRef, useState } from 'react'
import Animated,{ Extrapolate, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withRepeat, withSpring, withTiming } from 'react-native-reanimated'; import Animated, { Extrapolate, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withRepeat, withSpring, withTiming } from 'react-native-reanimated';
import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler'; import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
import * as Haptics from 'expo-haptics'; import * as Haptics from 'expo-haptics';
const {width : wWidht} = Dimensions.get("window"); const { width: wWidht } = Dimensions.get("window");
const SCREEN_HEIGHT = Dimensions.get('window').height const SCREEN_HEIGHT = Dimensions.get('window').height
const SCREEN_WIDTH = Dimensions.get('window').width const SCREEN_WIDTH = Dimensions.get('window').width
// const width = wWidht *0.75; // const width = wWidht *0.75;
// const height = wWidht * (465/264); // const height = wWidht * (465/264);
// const borderRadius = 24; // const borderRadius = 24;
const size= 100 const size = 100
const FladLoading = () => { const FladLoading = () => {
const progresse = useSharedValue(1); const progresse = useSharedValue(1);
useEffect(() => { useEffect(() => {
// withTiming, withSpring // withTiming, withSpring
progresse.value =withRepeat( withTiming(0.01,{duration : 750}), -1,true); progresse.value = withRepeat(withTiming(0.01, { duration: 750 }), -1, true);
}, [progresse]); }, [progresse]);
const breatheStyle = useAnimatedStyle(() => { const breatheStyle = useAnimatedStyle(() => {
const borderRange = interpolate const borderRange = interpolate
( progresse.value, (progresse.value,
[0, 1], [0, 1],
[(0*size) / 2,(1*size)/2], [(0 * size) / 2, (1 * size) / 2],
); );
return { return {
justifyContent : 'center', justifyContent: 'center',
alignItems : 'center', alignItems: 'center',
width : size, width: size,
height : size, height: size,
shadowColor : "#DA1D1D", shadowColor: "#DA1D1D",
shadowOffset : {width : 0, height : 0}, shadowOffset: { width: 0, height: 0 },
shadowOpacity : 1, shadowOpacity: 1,
shadowRadius :borderRange, shadowRadius: borderRange,
}; };
}); });
const breatheStyle2 = useAnimatedStyle(() => { const breatheStyle2 = useAnimatedStyle(() => {
const borderRange = interpolate const borderRange = interpolate
( progresse.value, (progresse.value,
[0, 1], [0, 1],
[(0*size) / 2,(1*size)/2], [(0 * size) / 2, (1 * size) / 2],
); );
return { return {
borderRadius : borderRange, borderRadius: borderRange,
}; };
}); });
const breatheStyleSquare = useAnimatedStyle(() => { const breatheStyleSquare = useAnimatedStyle(() => {
const borderRange = interpolate const borderRange = interpolate
( progresse.value, (progresse.value,
[0, 1], [0, 1],
[(size+20),(size)], [(size + 20), (size)],
); );
return { return {
width : borderRange, width: borderRange,
height : borderRange, height: borderRange,
borderRadius : borderRange/2, borderRadius: borderRange / 2,
borderWidth : size/10, borderWidth: size / 10,
borderColor : "#F80404", borderColor: "#F80404",
shadowColor : "#F40C1C", shadowColor: "#F40C1C",
shadowOffset : {width : 0, height : 0}, shadowOffset: { width: 0, height: 0 },
shadowOpacity : 1, shadowOpacity: 1,
shadowRadius :10, shadowRadius: 10,
}; };
}); });
return ( return (
<View style={{ justifyContent : 'center', alignItems :'center'}}> <View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Animated.View style={[{backgroundColor : '#B40404', justifyContent : 'center', alignItems : 'center'}, breatheStyleSquare]}> <Animated.View style={[{ backgroundColor: '#B40404', justifyContent: 'center', alignItems: 'center' }, breatheStyleSquare]}>
<Animated.Image source={require('../assets/icons/icon.png')} style={[{height: size, width : size, borderColor : '#fff',borderRadius : size/2}]}/> <Animated.Image source={require('../assets/icons/icon.png')} style={[{ height: size, width: size, borderColor: '#fff', borderRadius: size / 2 }]} />
</Animated.View> </Animated.View>
{/* <Animated.View style={[ {backgroundColor : 'green'},breatheStyleSquare]}> {/* <Animated.View style={[ {backgroundColor : 'green'},breatheStyleSquare]}>
</Animated.View> */} </Animated.View> */}
{/* <Image source={require('../assets/icons/Spotify_-_Animation_1.gif')}/> */} {/* <Image source={require('../assets/icons/Spotify_-_Animation_1.gif')}/> */}
</View> </View>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
card : { card: {
justifyContent : 'center', justifyContent: 'center',
alignItems : 'center', alignItems: 'center',
}, },
image : { image: {
borderRadius : 24, borderRadius: 24,
resizeMode: 'stretch', resizeMode: 'stretch',
}, },
container: { container: {
flex: 1, flex: 1,
width: '100%', width: '100%',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
} }
}) })
export default FladLoading; export default FladLoading;

@ -0,0 +1,31 @@
import React from 'react';
import { View, Image, StyleSheet } from 'react-native';
import normalize from './Normalize';
type Flady = {
image: string | object;
};
export default function FladyComponent(monFlady: Flady) {
const source = typeof monFlady.image === 'string' ? { uri: monFlady.image } : monFlady.image;
return (
<View style={styles.container}>
<Image source={source} style={styles.image} />
</View>
)
}
const styles = StyleSheet.create({
container: {
width: normalize(152),
height: normalize(152),
borderRadius: 90,
marginHorizontal: normalize(15),
overflow: 'hidden',
},
image: {
width: normalize(220),
height: normalize(220),
marginLeft: -1
}
})

@ -5,52 +5,52 @@ import { Artist } from "./Artist";
import { StyleSheet } from "react-native"; import { StyleSheet } from "react-native";
export const ArtistLayout = () => { export const ArtistLayout = () => {
const MUSIC_LIST : Music[] = [ const MUSIC_LIST: Music[] = [
new Music("La pharmacie", "Jul",require("../assets/images/jul.png")), new Music("La pharmacie", "Jul", require("../assets/images/jul.png")),
new Music("Deux frères", "PNL", require("../assets/images/pnl.png")), new Music("Deux frères", "PNL", require("../assets/images/pnl.png")),
new Music("Bambina", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png"), new Music("Bambina", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png"),
new Music("Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png"), new Music("Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png"),
new Music("Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg"), new Music("Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg"),
new Music("Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png"), new Music("Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png"),
new Music("Blanka", "PNL", require("../assets/images/pnl.png")), new Music("Blanka", "PNL", require("../assets/images/pnl.png")),
new Music("Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png"), new Music("Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png"),
] ]
const [artists, setArtists] = useState<Music[]>(MUSIC_LIST); const [artists, setArtists] = useState<Music[]>(MUSIC_LIST);
const [selectedArtists, setSelectedArtists] = useState<typeof MUSIC_LIST> ([]); const [selectedArtists, setSelectedArtists] = useState<typeof MUSIC_LIST>([]);
return ( return (
<ScrollView contentContainerStyle={styles.container}> <ScrollView contentContainerStyle={styles.container}>
{artists.map((artist, i) => ( {artists.map((artist, i) => (
<Artist <Artist
artist={artist} artist={artist}
key={artist.title} key={artist.title}
onPress={() => { onPress={() => {
// artists.splice(i, 1); // artists.splice(i, 1);
// // 2 implementation // // 2 implementation
const tmppArtist = new Music("Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png"); const tmppArtist = new Music("Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png");
// const existingObjIndex = selectedArtists.findIndex(obj => obj.title === tmppArtist.title); // const existingObjIndex = selectedArtists.findIndex(obj => obj.title === tmppArtist.title);
// if (existingObjIndex === -1) { // if (existingObjIndex === -1) {
// selectedArtists.push(tmppArtist); // selectedArtists.push(tmppArtist);
// } else { // } else {
// selectedArtists.splice(existingObjIndex, 1); // selectedArtists.splice(existingObjIndex, 1);
// } // }
// setSelectedArtists([...selectedArtists]); // setSelectedArtists([...selectedArtists]);
// 1 implementation // 1 implementation
// setSelectedArtists(selectedArtists.findIndex(obj => obj.title === tmppArtist.title) === -1 // setSelectedArtists(selectedArtists.findIndex(obj => obj.title === tmppArtist.title) === -1
// ? [...selectedArtists, tmppArtist] // ? [...selectedArtists, tmppArtist]
// : selectedArtists.filter(obj => obj.title !== tmppArtist.title)) // : selectedArtists.filter(obj => obj.title !== tmppArtist.title))
// 3 implementations // 3 implementations
// use the selectedProps of the Artist Component // use the selectedProps of the Artist Component
// then when we need to finish // then when we need to finish
// onPress{ () => setSelectedArtists([...selectedArtists,artists.filter(artist => artist.selected)])} // onPress{ () => setSelectedArtists([...selectedArtists,artists.filter(artist => artist.selected)])}
artists.push(tmppArtist); artists.push(tmppArtist);
setArtists([...artists]); setArtists([...artists]);
}} }}
/> />
))} ))}
{/* <FlatList {/* <FlatList
data={artists} data={artists}
// need to reverse colums oreder // need to reverse colums oreder
numColumns = {3} numColumns = {3}
@ -67,16 +67,16 @@ export const ArtistLayout = () => {
// ListEmptyComponent = {} // ListEmptyComponent = {}
/> */} /> */}
</ScrollView> </ScrollView>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flexDirection: "row", flexDirection: "row",
flexWrap: "wrap", flexWrap: "wrap",
}, },
}); });

@ -2,31 +2,31 @@ import { useState } from 'react';
import { View, StyleSheet } from 'react-native' import { View, StyleSheet } from 'react-native'
interface HalfCirlceProps { interface HalfCirlceProps {
backgroundColor : string; backgroundColor: string;
} }
const HalfCirlce = ({backgroundColor} : HalfCirlceProps) => { const HalfCirlce = ({ backgroundColor }: HalfCirlceProps) => {
const [focused, setFocused] = useState<boolean>(false); const [focused, setFocused] = useState<boolean>(false);
return ( return (
<View style={{ <View style={{
width : RADUIS* 2, width: RADUIS * 2,
height : RADUIS* 2, height: RADUIS * 2,
overflow : "hidden", overflow: "hidden",
}}> }}>
<View style={{backgroundColor : backgroundColor, width : RADUIS* 2, height : RADUIS * 2, borderRadius : RADUIS, }}> <View style={{ backgroundColor: backgroundColor, width: RADUIS * 2, height: RADUIS * 2, borderRadius: RADUIS, }}>
</View> </View>
</View> </View>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
input : { input: {
justifyContent : 'center', justifyContent: 'center',
alignItems : 'center', alignItems: 'center',
placeholder : "placeholde" placeholder: "placeholde"
}, },
}) })

@ -1,10 +1,10 @@
import { View, StyleSheet, Dimensions,Text, Image, Pressable, TouchableWithoutFeedback, TouchableOpacity, TouchableHighlight, FlatList } from "react-native"; import { View, StyleSheet, Dimensions, Text, Image, Pressable, TouchableWithoutFeedback, TouchableOpacity, TouchableHighlight, FlatList } from "react-native";
import Animated, { import Animated, {
Layout, Layout,
Transition, Transition,
ZoomIn, ZoomIn,
ZoomOut, ZoomOut,
} from "react-native-reanimated"; } from "react-native-reanimated";
const { width } = Dimensions.get("window"); const { width } = Dimensions.get("window");
const SIZE = width / 3; const SIZE = width / 3;
@ -16,35 +16,35 @@ import { RenderCellProps } from "./littleCard";
interface HorizontalFlatListProps { interface HorizontalFlatListProps {
// React.ReactNode; // React.ReactNode;
children:(props: RenderCellProps) => React.ReactElement children: (props: RenderCellProps) => React.ReactElement
title : string; title: string;
data : any[]; data: any[];
} }
export const HorizontalFlatList = ({ title, data, children : RenderCell }: HorizontalFlatListProps) => { export const HorizontalFlatList = ({ title, data, children: RenderCell }: HorizontalFlatListProps) => {
return ( return (
<View style={styles.similarSection}> <View style={styles.similarSection}>
<Text style={styles.similarTitle} >{title}</Text> <Text style={styles.similarTitle} >{title}</Text>
<FlatList <FlatList
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
data={data} data={data}
horizontal={true} horizontal={true}
keyExtractor={item => item.id} keyExtractor={item => item.id}
renderItem={({ item }) => RenderCell(item)}/></View> renderItem={({ item }) => RenderCell(item)} /></View>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
similarSection: { similarSection: {
paddingTop: 16 paddingTop: 16
}, },
similarTitle: { similarTitle: {
color: "#FFF", color: "#FFF",
paddingLeft: 8, paddingLeft: 8,
fontSize: 24, fontSize: 24,
fontWeight: "600", fontWeight: "600",
paddingBottom: 16 paddingBottom: 16
} }
}); });

@ -1,12 +1,15 @@
import React, { useRef, useEffect } from 'react'; import React, { useRef, useEffect } from 'react';
import { View, StyleSheet, TouchableOpacity , Animated } from 'react-native'; import { View, StyleSheet, TouchableOpacity, Animated, useColorScheme } from 'react-native';
import Svg, { G, Circle } from 'react-native-svg'; import Svg, { G, Circle } from 'react-native-svg';
import { AntDesign } from '@expo/vector-icons'; import { AntDesign } from '@expo/vector-icons';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
// @ts-ignore // @ts-ignore
export default function NextButton({ percentage, scrollTo }) { export default function NextButton({ percentage, scrollTo }) {
const style = useColorScheme() == 'light' ? GraphicalCharterLight : GraphicalCharterDark;
const size = normalize(148); const size = normalize(148);
const strokeWidth = 2; const strokeWidth = 2;
const center = size / 2; const center = size / 2;
@ -56,11 +59,11 @@ export default function NextButton({ percentage, scrollTo }) {
<View style={styles.container}> <View style={styles.container}>
<Svg width={size} height={size}> <Svg width={size} height={size}>
<G rotation="-90" origin={center}> <G rotation="-90" origin={center}>
<Circle stroke="#E6E7E8" fill="#141414" cx={center} cy={center} r={radius} strokeWidth={strokeWidth}/> <Circle stroke={style.Text} cx={center} cy={center} r={radius} strokeWidth={strokeWidth} />
<Circle <Circle
ref={progressRef} ref={progressRef}
stroke="#F80404" stroke="#F80404"
fill="#141414" fill={style.body}
cx={center} cx={center}
cy={center} cy={center}
r={radius} r={radius}

@ -1,15 +1,17 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import { Modal, View, StyleSheet, Text, FlatList, Animated, TouchableOpacity, ImageBackground, Image } from 'react-native'; import { Modal, View, StyleSheet, useColorScheme, Text, FlatList, Animated, TouchableOpacity, ImageBackground, Image } from 'react-native';
// import Modal from "react-native-modal"; // import Modal from "react-native-modal";
import {useNavigation} from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import OnboardingItem from './OnboardingItem'; import OnboardingItem from './OnboardingItem';
import Paginator from './Paginator'; import Paginator from './Paginator';
import NextButton from './NextButton'; import NextButton from './NextButton';
import slides from '../data/slides'; import slides from '../data/slides';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
export default function Onboarding() { export default function Onboarding() {
const style = useColorScheme() == 'light' ? GraphicalCharterLight : GraphicalCharterDark;
const [currentIndex, setCurrentIndex] = useState(0); const [currentIndex, setCurrentIndex] = useState(0);
const scrollX = useRef(new Animated.Value(0)).current; const scrollX = useRef(new Animated.Value(0)).current;
const slidesRef = useRef(null); const slidesRef = useRef(null);
@ -26,7 +28,7 @@ export default function Onboarding() {
const viewConfig = useRef({ viewAreaCoveragePercentThreshold: 50 }).current; const viewConfig = useRef({ viewAreaCoveragePercentThreshold: 50 }).current;
const scrollTo = () => { const scrollTo = () => {
if(currentIndex < slides.length - 1) { if (currentIndex < slides.length - 1) {
// @ts-ignore // @ts-ignore
slidesRef.current.scrollToIndex({ index: currentIndex + 1 }); slidesRef.current.scrollToIndex({ index: currentIndex + 1 });
} else { } else {
@ -34,13 +36,119 @@ export default function Onboarding() {
} }
}; };
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: style.body
},
imageLogo: {
width: normalize(324),
height: normalize(162),
marginBottom: '25%'
},
balise: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginBottom: normalize(110)
},
closeButtonCircle: {
backgroundColor: 'gray',
opacity: 0.4,
width: 40,
height: 40,
borderRadius: 20,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
top: 10,
right: 10
},
modalContent: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
backgroundImage: {
flex: 1,
width: '100%',
height: '100%',
},
imageButton: {
width: 20,
height: 20
},
versionText: {
position: 'absolute',
top: 50,
right: 10,
color: 'gray',
fontWeight: 'bold',
fontSize: normalize(17)
},
buttonConnection: {
width: 262,
height: 57,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#24CF5F',
borderRadius: 11,
borderColor: '#68F097',
borderWidth: 1,
marginBottom: 12
},
buttonInscription: {
width: 262,
height: 57,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#DA1D1D',
borderRadius: 11,
borderColor: '#F40C1C',
borderWidth: 1,
marginBottom: 220
},
text: {
fontWeight: 'bold',
color: 'white',
fontSize: normalize(18)
},
button2Connection: {
width: '100%',
height: normalize(92),
backgroundColor: '#232123',
borderTopColor: '#3C3C3C',
borderTopWidth: 1,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
bottom: normalize(0)
},
mascot: {
width: normalize(130),
height: normalize(130),
position: 'absolute',
bottom: normalize(90),
right: normalize(0)
}
})
return ( return (
// @ts-ignore // @ts-ignore
<View style={styles.container}> <View style={styles.container}>
<View style={styles.balise}> <View style={styles.balise}>
<FlatList <FlatList
data={slides} data={slides}
renderItem={({item}) => <OnboardingItem item={item} />} renderItem={({ item }) => <OnboardingItem item={item} />}
horizontal horizontal
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
pagingEnabled pagingEnabled
@ -54,7 +162,7 @@ export default function Onboarding() {
viewabilityConfig={viewConfig} viewabilityConfig={viewConfig}
ref={slidesRef} ref={slidesRef}
/> />
<Paginator data={slides} scrollX={scrollX}/> <Paginator data={slides} scrollX={scrollX} />
<NextButton scrollTo={scrollTo} percentage={(currentIndex + 1) * (100 / slides.length)} /> <NextButton scrollTo={scrollTo} percentage={(currentIndex + 1) * (100 / slides.length)} />
</View> </View>
<Modal animationType="slide" visible={isModalVisible} transparent={true} presentationStyle={'pageSheet'}> <Modal animationType="slide" visible={isModalVisible} transparent={true} presentationStyle={'pageSheet'}>
@ -66,23 +174,24 @@ export default function Onboarding() {
</Text> </Text>
<TouchableOpacity onPress={handleModal} style={styles.closeButtonCircle}> <TouchableOpacity onPress={handleModal} style={styles.closeButtonCircle}>
<View> <View>
<Image source={require("../assets/icons/icons/croix.png")} style={styles.imageButton}/> <Image source={require("../assets/icons/icons/croix.png")} style={styles.imageButton} />
</View> </View>
</TouchableOpacity> </TouchableOpacity>
<Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo}/> <Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo} />
<TouchableOpacity <TouchableOpacity
style={styles.buttonConnection} style={styles.buttonConnection}
onPress={() => {handleModal(); onPress={() => {
// @ts-ignore handleModal();
navigation.navigate('Login'); // @ts-ignore
}}> navigation.navigate('Login');
}}>
<Text style={styles.text}>CONTINUER AVEC SPOTIFY</Text> <Text style={styles.text}>CONTINUER AVEC SPOTIFY</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.buttonInscription} onPress={() => {handleModal(); navigation.navigate('Register');}}> <TouchableOpacity style={styles.buttonInscription} onPress={() => { handleModal(); navigation.navigate('Register'); }}>
<Text style={styles.text}>SINSCRIRE MAINTENANT</Text> <Text style={styles.text}>SINSCRIRE MAINTENANT</Text>
</TouchableOpacity> </TouchableOpacity>
<Image source={require("../assets/images/Flady.gif")} style={styles.mascot}/> <Image source={require("../assets/images/Flady.gif")} style={styles.mascot} />
<TouchableOpacity style={styles.button2Connection} onPress={() => {handleModal(); navigation.navigate('Login');}}> <TouchableOpacity style={styles.button2Connection} onPress={() => { handleModal(); navigation.navigate('Login'); }}>
<Text style={styles.text}>SE CONNECTER</Text> <Text style={styles.text}>SE CONNECTER</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
@ -92,108 +201,3 @@ export default function Onboarding() {
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#141414'
},
imageLogo: {
width: normalize(324),
height: normalize(162),
marginBottom: '25%'
},
balise: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginBottom: normalize(110)
},
closeButtonCircle: {
backgroundColor: 'gray',
opacity: 0.4,
width: 40,
height: 40,
borderRadius: 20,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
top: 10,
right: 10
},
modalContent: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
backgroundImage: {
flex: 1,
width: '100%',
height: '100%',
},
imageButton: {
width: 20,
height: 20
},
versionText: {
position: 'absolute',
top: 50,
right: 10,
color: 'gray',
fontWeight: 'bold',
fontSize: normalize(17)
},
buttonConnection: {
width: 262,
height: 57,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#24CF5F',
borderRadius: 11,
borderColor: '#68F097',
borderWidth: 1,
marginBottom: 12
},
buttonInscription: {
width: 262,
height: 57,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#DA1D1D',
borderRadius: 11,
borderColor: '#F40C1C',
borderWidth: 1,
marginBottom: 220
},
text: {
fontWeight: 'bold',
color: 'white',
fontSize: normalize(18)
},
button2Connection: {
width: '100%',
height: normalize(92),
backgroundColor: '#232123',
borderTopColor: '#3C3C3C',
borderTopWidth: 1,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
bottom: normalize(0)
},
mascot: {
width: normalize(130),
height: normalize(130),
position: 'absolute',
bottom: normalize(90),
right: normalize(0)
}
})

@ -1,11 +1,43 @@
import React from 'react'; import React from 'react';
import { View, StyleSheet, Text, Image, useWindowDimensions } from 'react-native'; import { View, StyleSheet, Text, Image, useWindowDimensions, useColorScheme } from 'react-native';
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
// @ts-ignore // @ts-ignore
export default function Onboarding({ item }) { export default function Onboarding({ item }) {
const style = useColorScheme() == 'light' ? GraphicalCharterLight : GraphicalCharterDark;
const { width, height } = useWindowDimensions(); const { width, height } = useWindowDimensions();
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: normalize(60),
backgroundColor: style.body
},
image: {
width: '100%',
height: '100%',
justifyContent: 'center'
},
title: {
fontWeight: '800',
fontSize: normalize(32),
marginBottom: 10,
color: style.Text,
textAlign: 'left',
paddingRight: 30,
paddingLeft: 20,
marginTop: normalize(30)
},
description: {
fontWeight: '300',
color: style.Text,
fontSize: normalize(16),
textAlign: 'left',
paddingRight: 30,
paddingLeft: 20
}
})
return ( return (
<View style={[styles.container, { width, height }]}> <View style={[styles.container, { width, height }]}>
<View style={{ overflow: 'hidden', height: height * 0.5 }}> <View style={{ overflow: 'hidden', height: height * 0.5 }}>
@ -17,33 +49,3 @@ export default function Onboarding({ item }) {
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: normalize(60),
backgroundColor: '#141414'
},
image: {
width: '100%',
height: '100%',
justifyContent: 'center'
},
title: {
fontWeight: '800',
fontSize: normalize(32),
marginBottom: 10,
color: 'white',
textAlign: 'left',
paddingRight: 30,
paddingLeft: 20,
marginTop: normalize(30)
},
description: {
fontWeight: '300',
color: 'white',
fontSize: normalize(16),
textAlign: 'left',
paddingRight: 30,
paddingLeft: 20
}
})

@ -7,7 +7,7 @@ export default function Paginator({ data, scrollX }) {
const { width } = useWindowDimensions(); const { width } = useWindowDimensions();
return ( return (
<View style={{flexDirection: 'row', height: 64, marginBottom: normalize(50)}}> <View style={{ flexDirection: 'row', height: 64, marginBottom: normalize(50) }}>
{data.map((_, i) => { {data.map((_, i) => {
const inputRange = [(i - 1) * width, i * width, (i + 1) * width]; const inputRange = [(i - 1) * width, i * width, (i + 1) * width];

@ -1,10 +1,10 @@
import { View, StyleSheet, Dimensions, Image, Pressable, TouchableWithoutFeedback, TouchableOpacity, TouchableHighlight } from "react-native"; import { View, StyleSheet, Dimensions, Image, Pressable, TouchableWithoutFeedback, TouchableOpacity, TouchableHighlight } from "react-native";
import Animated, { import Animated, {
Layout, Layout,
Transition, Transition,
ZoomIn, ZoomIn,
ZoomOut, ZoomOut,
} from "react-native-reanimated"; } from "react-native-reanimated";
const { width } = Dimensions.get("window"); const { width } = Dimensions.get("window");
const SIZE = width / 3; const SIZE = width / 3;
@ -15,60 +15,60 @@ import { useRef, useState } from "react";
interface SelectedCardProps { interface SelectedCardProps {
artist: Music; artist: Music;
onPress: () => void; onPress: () => void;
// cheepPosition: string ;(direction: "left" | "right" | "down") // cheepPosition: string ;(direction: "left" | "right" | "down")
} }
export const SelectedCard = ({ artist, onPress }: SelectedCardProps) => { export const SelectedCard = ({ artist, onPress }: SelectedCardProps) => {
const [selected,setSeleted] = useState(false); const [selected, setSeleted] = useState(false);
const onS = () => { const onS = () => {
setSeleted(!selected); setSeleted(!selected);
onPress(); onPress();
}; };
return ( return (
<TouchableOpacity onPress={onS}> <TouchableOpacity onPress={onS}>
<Animated.View <Animated.View
style={styles.container} style={styles.container}
entering={ZoomIn} entering={ZoomIn}
exiting={ZoomOut} exiting={ZoomOut}
layout={Layout.delay(200)} layout={Layout.delay(200)}
> >
<View style={styles.card}> <View style={styles.card}>
{ selected && ( {selected && (
<View style={styles.cheked}> <View style={styles.cheked}>
<Icon name="check-circle" color="black" size={24} /> <Icon name="check-circle" color="black" size={24} />
</View> </View>
)} )}
</View> </View>
</Animated.View> </Animated.View>
</TouchableOpacity> </TouchableOpacity>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
width: SIZE, width: SIZE,
height: SIZE, height: SIZE,
padding: 8, padding: 8,
}, },
card: { card: {
flex: 1, flex: 1,
padding: 8, padding: 8,
alignItems: "flex-end", alignItems: "flex-end",
}, },
image: { image: {
borderRadius: 8, borderRadius: 8,
...StyleSheet.absoluteFillObject, ...StyleSheet.absoluteFillObject,
width: undefined, width: undefined,
height: undefined, height: undefined,
}, },
cheked : { cheked: {
backgroundColor : "white", backgroundColor: "white",
borderRadius : 100, borderRadius: 100,
alignItems : "center", alignItems: "center",
} }
}); });

@ -1,29 +1,29 @@
import { useState } from 'react'; import { useState } from 'react';
import { View, Text, Image, Animated ,PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, TextInput } from 'react-native' import { View, Text, Image, Animated, PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, TextInput } from 'react-native'
interface InputProps { interface InputProps {
name : string; name: string;
placeholder : string; placeholder: string;
} }
const FladInput = ({name, placeholder} : InputProps) => { const FladInput = ({ name, placeholder }: InputProps) => {
const [focused, setFocused] = useState<boolean>(false); const [focused, setFocused] = useState<boolean>(false);
return ( return (
<View> <View>
<Text></Text> <Text></Text>
<TextInput style={[styles.input]}> <TextInput style={[styles.input]}>
</TextInput> </TextInput>
</View> </View>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
input : { input: {
justifyContent : 'center', justifyContent: 'center',
alignItems : 'center', alignItems: 'center',
placeholder : "placeholde" placeholder: "placeholde"
}, },
}) })

@ -1,17 +1,17 @@
import {TouchableOpacity, ScrollView, View, Text, StyleSheet, Image, SafeAreaView, FlatList, Animated} from 'react-native'; import { TouchableOpacity, ScrollView, View, Text, StyleSheet, Image, SafeAreaView, FlatList, Animated } from 'react-native';
export interface RenderCellProps { export interface RenderCellProps {
image: string; image: string;
title: string; title: string;
} }
export const LittleCard = (props : RenderCellProps)=>{ export const LittleCard = (props: RenderCellProps) => {
console.log('==============='+ props.image + props.title+ '==ok============'); console.log('===============' + props.image + props.title + '==ok============');
return ( return (
<View style={styles.similarContainer}> <View style={styles.similarContainer}>
<Image source={{uri: props.image}} style={styles.similarPoster}></Image> <Image source={{ uri: props.image }} style={styles.similarPoster}></Image>
<Text numberOfLines={2} style={styles.similarTitleFilm}>{props.title} <Text numberOfLines={2} style={styles.similarTitleFilm}>{props.title}
</Text> </Text>
</View> </View>
) )
} }

@ -1,46 +1,46 @@
import Music from "../Model/Music"; import Music from "../Model/Music";
import { Spot } from "../Model/Spot"; import { Spot } from "../Model/Spot";
export const cards= [{ export const cards = [{
name : "blue", name: "blue",
sourceUrl : "https://th.bing.com/th/id/R.dbf87f0d8cbfd078ab6a589a5d921994?rik=1%2f6KliMpOAeh8A&pid=ImgRaw&r=0", sourceUrl: "https://th.bing.com/th/id/R.dbf87f0d8cbfd078ab6a589a5d921994?rik=1%2f6KliMpOAeh8A&pid=ImgRaw&r=0",
index : 4 index: 4
}, },
{ {
musicName : "Breathin", musicName: "Breathin",
name : "Ariana Grande", name: "Ariana Grande",
sourceUrl : "https://i.ebayimg.com/images/g/rY0AAOSw97djEo2C/s-l500.jpg", sourceUrl: "https://i.ebayimg.com/images/g/rY0AAOSw97djEo2C/s-l500.jpg",
index : 9 index: 9
}, },
{ {
musicName : "Zombies", musicName: "Zombies",
name : "gambino", name: "gambino",
sourceUrl : "https://th.bing.com/th/id/R.0b2d1a59bfda9b1a49ecb561e08535a8?rik=Xyc35OZU%2f6VOVw&pid=ImgRaw&r=0", sourceUrl: "https://th.bing.com/th/id/R.0b2d1a59bfda9b1a49ecb561e08535a8?rik=Xyc35OZU%2f6VOVw&pid=ImgRaw&r=0",
index : 3 index: 3
}, },
{ {
musicName : "Bambina", musicName: "Bambina",
name : "PNL", name: "PNL",
sourceUrl : "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png", sourceUrl: "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png",
index : 10 index: 10
}, },
{ {
musicName : "Freeze Raël", musicName: "Freeze Raël",
name : "Freeze Corleone", name: "Freeze Corleone",
sourceUrl : "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png", sourceUrl: "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png",
index : 23 index: 23
}, },
{ {
musicName : "Autobahn", musicName: "Autobahn",
name : "Sch", name: "Sch",
sourceUrl : "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg", sourceUrl: "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg",
index : 44 index: 44
}, },
{ {
musicName : "Lakehouse", musicName: "Lakehouse",
name : "Stratos", name: "Stratos",
sourceUrl : "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png", sourceUrl: "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png",
index : 89 index: 89
}, },
] ]

@ -1,20 +1,20 @@
export default [ export default [
{ {
id: '1', id: '1',
title: 'Bienvenue sur Flad', title: 'Bienvenue sur Flad',
description: 'L\'application pour découvrir de nouvelles musiques et vous faire de nouveaux amis', description: 'L\'application pour découvrir de nouvelles musiques et vous faire de nouveaux amis',
image: require('../assets/images/Board_Image.png') image: require('../assets/images/Board_Image.png')
}, },
{ {
id: '2', id: '2',
title: 'Tous les jours de nouvelles musiques qui peuvent vous plaire', title: 'Tous les jours de nouvelles musiques qui peuvent vous plaire',
description: 'L\'application apprends de vous et de vos amis pour vous suggérer des albums et des musics', description: 'L\'application apprends de vous et de vos amis pour vous suggérer des albums et des musics',
image: require('../assets/images/Board_Image2.png') image: require('../assets/images/Board_Image2.png')
}, },
{ {
id: '3', id: '3',
title: 'La musique ça se partage', title: 'La musique ça se partage',
description: 'Faites connaissances avec de nouvelles personnes et partagez vos critiques', description: 'Faites connaissances avec de nouvelles personnes et partagez vos critiques',
image: require('../assets/images/Board_Image3.png') image: require('../assets/images/Board_Image3.png')
} }
] ]

@ -1,11 +1,11 @@
export default class Music { export default class Music {
private _id : string; private _id: string;
private _title: string; private _title: string;
private _bio: string; private _bio: string;
private _image: string; private _image: string;
private _trackPreviewUrl : string; private _trackPreviewUrl: string;
constructor(id : string,title: string, bio: string, image: string, trackPreviewUrl: string) { constructor(id: string, title: string, bio: string, image: string, trackPreviewUrl: string) {
this._title = title; this._title = title;
this._bio = bio; this._bio = bio;
this._image = image; this._image = image;

@ -1,5 +1,5 @@
import Navigation from './Navigation'; import Navigation from './Navigation';
import { StyleSheet,SafeAreaView } from 'react-native'; import { StyleSheet, SafeAreaView } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context'; import { SafeAreaProvider } from 'react-native-safe-area-context';
import StartNavigation from './StartNavigation'; import StartNavigation from './StartNavigation';
import { Provider, useDispatch, useSelector } from 'react-redux'; import { Provider, useDispatch, useSelector } from 'react-redux';
@ -13,10 +13,12 @@ import * as Location from 'expo-location';
// const LOCATION_TASK_NAME = 'flad-background-location-task'; // const LOCATION_TASK_NAME = 'flad-background-location-task';
export default function AuthNavigation() { export default function AuthNavigation() {
//@ts-ignore
const tokenProcesed : boolean = useSelector(state => state.userReducer.loading);
//@ts-ignore //@ts-ignore
const isLogin : boolean = useSelector(state => state.userReducer.isLogedIn); const tokenProcesed: boolean = useSelector(state => state.userReducer.loading);
// //@ts-ignore
// const appIsReady: boolean = useSelector(state => state.userReducer.loading);
//@ts-ignore
const isLogin: boolean = useSelector(state => state.userReducer.isLogedIn);
// const userToken : string = useSelector(state => state.userReducer.userFladToken); // const userToken : string = useSelector(state => state.userReducer.userFladToken);
const [appIsReady, setAppIsReady] = useState(false); const [appIsReady, setAppIsReady] = useState(false);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -25,18 +27,18 @@ export default function AuthNavigation() {
const [errorMsg, setErrorMsg] = useState(''); const [errorMsg, setErrorMsg] = useState('');
// // seems background task but not optimized // // seems background task but not optimized
// TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => { // TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
// if (error) { // if (error) {
// console.log(error); // console.log(error);
// return; // return;
// } // }
// if (data) { // if (data) {
// const { locations } = data; // const { locations } = data;
// // send location updates to server // // send location updates to server
// console.log(locations); // console.log(locations);
// } // }
// }); // });
// const startLocationUpdates = async () => { // const startLocationUpdates = async () => {
// try { // try {
// await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, { // await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
@ -62,14 +64,14 @@ export default function AuthNavigation() {
useEffect(() => { useEffect(() => {
async function prepare() { async function prepare() {
//@ts-ignore //@ts-ignore
await dispatch(getRefreshToken()) await dispatch(getRefreshToken())
if (tokenProcesed && appIsReady ) { if (tokenProcesed && appIsReady) {
await SplashScreen.hideAsync(); await SplashScreen.hideAsync();
} // await SplashScreen.hideAsync(); } // await SplashScreen.hideAsync();
} }
prepare(); prepare();
}, [appIsReady,tokenProcesed]); }, [appIsReady, tokenProcesed]);
// const onStackRootView = useCallback(async () => { // const onStackRootView = useCallback(async () => {
@ -113,21 +115,16 @@ export default function AuthNavigation() {
} }
// console.log(userToken, "k9 AuthNav") // console.log(userToken, "k9 AuthNav")
return ( return (
<> <SafeAreaProvider onLayout={() => setAppIsReady(true)}>
{isLogin ? ( {isLogin ? (
/* {userToken != null ? ( */ /* {userToken != null ? ( */
// should set the reference to the function in Navigation to realy perform an on ready // should set the reference to the function in Navigation to realy perform an on ready
// test purpose // test purpose
<SafeAreaProvider onLayout={()=>setAppIsReady(true)}> <Navigation />
<Navigation/> ) :
</SafeAreaProvider> <StartNavigation />
}
) : </SafeAreaProvider>
<SafeAreaProvider onLayout={()=>setAppIsReady(true)}> )
<StartNavigation /> }
</SafeAreaProvider>
}
</>
)
}

@ -9,22 +9,22 @@ import CurrentMusic from '../components/CurrentMusic';
const Stack = createSharedElementStackNavigator(); const Stack = createSharedElementStackNavigator();
export default function MusicNavigation() { export default function MusicNavigation() {
return ( return (
<Stack.Navigator initialRouteName="Favorite" screenOptions={{gestureEnabled: true, headerShown: false, cardOverlayEnabled: true, cardStyle: {backgroundColor: "transparent"}}} > <Stack.Navigator initialRouteName="Favorite" screenOptions={{ gestureEnabled: true, headerShown: false, cardOverlayEnabled: true, cardStyle: { backgroundColor: "transparent" } }} >
<Stack.Screen <Stack.Screen
name="Favorite" name="Favorite"
component={Favorite} component={Favorite}
/> />
<Stack.Screen <Stack.Screen
name="MusicDetail" name="MusicDetail"
component={MusicDetail} component={MusicDetail}
sharedElements ={(route)=> {return [route.params.music.id]}} sharedElements={(route) => { return [route.params.music.id] }}
/> />
<Stack.Screen <Stack.Screen
name="Genre" name="Genre"
component={CurrentMusic} component={CurrentMusic}
/> />
</Stack.Navigator> </Stack.Navigator>
) )
} }

@ -13,76 +13,88 @@ import Login from '../screens/login';
import FladLoading from '../components/FladLoadingScreen'; import FladLoading from '../components/FladLoadingScreen';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { getFavoritesMusic } from '../redux/actions/appActions'; import { getFavoritesMusic } from '../redux/actions/appActions';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
import { getCurrentUserMusic } from '../redux/thunk/spotThunk';
import SpotifyService from '../services/spotify/spotify.service';
// import { fetchFavoritesMusic } from '../redux/thunk/spotThunk'; // import { fetchFavoritesMusic } from '../redux/thunk/spotThunk';
export default function Navigation() { export default function Navigation() {
const isDark = useSelector(state => state.userReducer.dark);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark;
const BottomTabNavigator = createBottomTabNavigator(); const BottomTabNavigator = createBottomTabNavigator();
const MyTheme = { const MyTheme = {
dark: false, dark: false,
colors: { colors: {
primary: 'rgb(255, 45, 85)', primary: 'rgb(255, 45, 85)',
card: 'rgb(35, 33, 35)', card: style.Card,
border: 'rgb(35, 33, 35)', border: style.Card,
text: 'rgb(138, 138, 138)', text: 'rgb(138, 138, 138)',
} }
}; };
//@ts-ignore //@ts-ignore
const favoritesMusicLength : number = useSelector(state => state.appReducer.favoriteMusic.length); const favoritesMusicLength: number = useSelector(state => state.appReducer.favoriteMusic.length);
// const dispatch = useDispatch(); const dispatch = useDispatch();
// useEffect(() => { // useEffect(() => {
// const loadFavoritesMusics = async () => { // const loadFavoritesMusics = async () => {
// await dispatch(fetchFavoritesMusic()); // await dispatch(fetchFavoritesMusic());
// }; // };
// loadFavoritesMusics(); // loadFavoritesMusics();
// }, [dispatch]); // }, [dispatch]);
return ( const token = "BQBNdaYRkD3GAOFASk8uc-l72zVwQeQ0sFB4GJnkBGudsJHnuAXd4eIWb78gbFLKZeBoHrWpHxMeSmqvHk75Utg9fsOJp7XyJfm-tAlgGhUQ-xiUM8rXTpa9k3M40BMSnujPDrap_O1ChCyGhBWYVHDd2t67qY0NVDvCJ4Qz7LucJJdgu1BN838qXTScQV90zriO8lp6Rjx6SsWov_fMZTyadzxebYIiQ-VDQDs63gUordThas-jFlAHLgJlqPhVOHJ1WaZt-_oLhgY3fk4bhORkyeAFZVRTnjw38A70b0eZU3ziQkOYW6w7kN__tzgP5gis0Y8mEIiUyTnyuQ"
// @ts-ignore const sheet = async () => {
<NavigationContainer theme={MyTheme}> const service = new SpotifyService(token)
<BottomTabNavigator.Navigator dispatch(getCurrentUserMusic(service))
initialRouteName="Spots" }
screenOptions={{
//tabBarShowLabel: false, //to remove the titles under the icons
tabBarStyle: styles.tabBar,
...(Platform.OS === 'android'
? { tabBarLabelStyle: { bottom: normalize(10) } }
: { tabBarLabelStyle: { bottom: normalize(-22) } }
),
}}> useEffect(() => {
<BottomTabNavigator.Screen name="Spots" component={SpotNavigation} sheet()
options={{ }, []);
headerShown: false, return (
tabBarIcon: ({color}) => <View style={styles.IconContainer}><TabBarIcon name="music" color={color}/></View>, // @ts-ignore
}}/> <NavigationContainer theme={MyTheme}>
<BottomTabNavigator.Screen name="Favorites" component={FavoriteNavigation} <BottomTabNavigator.Navigator
options={{ initialRouteName="Spots"
// use Selector state redux badgeCount ? badgeCount : undefined screenOptions={{
tabBarStyle: styles.tabBar,
...(Platform.OS === 'android'
? { tabBarLabelStyle: { bottom: normalize(10) } }
: { tabBarLabelStyle: { bottom: normalize(-22) } }
),
tabBarBadge : favoritesMusicLength, }}>
tabBarBadgeStyle : {backgroundColor : 'yellow'}, <BottomTabNavigator.Screen name="Spots" component={SpotNavigation}
headerShown: false, options={{
tabBarIcon: ({color}) => <View style={styles.IconContainer}><TabBarIcon name="heart" color={color}/></View>, headerShown: false,
}}/> tabBarIcon: ({ color }) => <View style={styles.IconContainer}><TabBarIcon name="music" color={color} /></View>,
<BottomTabNavigator.Screen name="Messages" component={Login} }} />
options={{ <BottomTabNavigator.Screen name="Favorites" component={FavoriteNavigation}
headerShown: false, options={{
tabBarIcon: ({color}) => <View style={styles.IconContainer}><TabBarIcon name="comment" color={color}/></View>, tabBarBadge: favoritesMusicLength,
}}/> tabBarBadgeStyle: { backgroundColor: 'yellow' },
<BottomTabNavigator.Screen name="Setting" component={SettingNavigation} headerShown: false,
options={{ tabBarIcon: ({ color }) => <View style={styles.IconContainer}><TabBarIcon name="heart" color={color} /></View>,
headerShown: false, }} />
tabBarIcon: ({color}) => <View style={styles.IconContainer}><TabBarIcon name="cog" color={color}/></View>, <BottomTabNavigator.Screen name="Messages" component={Login}
}}/> options={{
</BottomTabNavigator.Navigator> headerShown: false,
</NavigationContainer> tabBarIcon: ({ color }) => <View style={styles.IconContainer}><TabBarIcon name="comment" color={color} /></View>,
}} />
<BottomTabNavigator.Screen name="Setting" component={SettingNavigation}
options={{
headerShown: false,
tabBarIcon: ({ color }) => <View style={styles.IconContainer}><TabBarIcon name="cog" color={color} /></View>,
}} />
</BottomTabNavigator.Navigator>
</NavigationContainer>
) )
} }
function TabBarIcon(props: { function TabBarIcon(props: {
name: React.ComponentProps<typeof FontAwesome>['name']; name: React.ComponentProps<typeof FontAwesome>['name'];
color: string; color: string;
}) { }) {
return <FontAwesome size={30} {...props} />; return <FontAwesome size={30} {...props} />;
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({

@ -4,19 +4,19 @@ import SettingProfil from '../screens/SettingProfil';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
export default function SettingNavigation() { export default function SettingNavigation() {
const Stack = createStackNavigator(); const Stack = createStackNavigator();
return ( return (
<Stack.Navigator initialRouteName="Setting"> <Stack.Navigator initialRouteName="Setting">
<Stack.Screen <Stack.Screen
name="Setting" name="Setting"
component={Setting} component={Setting}
options={{ headerShown: false }} options={{ headerShown: false }}
/> />
<Stack.Screen <Stack.Screen
name="SettingProfil" name="SettingProfil"
component={SettingProfil} component={SettingProfil}
options={{ headerShown: false }} options={{ headerShown: false }}
/> />
</Stack.Navigator> </Stack.Navigator>
) )
} }

@ -1,4 +1,4 @@
import React, {Component} from 'react'; import React, { Component } from 'react';
import FavoritePage from '../screens/favorite'; import FavoritePage from '../screens/favorite';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import SpotPage from '../screens/spot' import SpotPage from '../screens/spot'
@ -8,32 +8,32 @@ import MusicDetail from '../screens/MusicDetail';
export default function SpotNavigation() { export default function SpotNavigation() {
// const Stack = createSharedElementStackNavigator(); // const Stack = createSharedElementStackNavigator();
const Stack = createStackNavigator(); const Stack = createStackNavigator();
return ( return (
<Stack.Navigator screenOptions={{ <Stack.Navigator screenOptions={{
gestureEnabled: false, gestureEnabled: false,
headerShown: false, headerShown: false,
cardOverlayEnabled: true, cardOverlayEnabled: true,
}} }}
> >
<Stack.Screen <Stack.Screen
name="Spots" name="Spots"
component={SpotPage} component={SpotPage}
/> />
<Stack.Screen <Stack.Screen
name="DetailsSpot" name="DetailsSpot"
component={MusicDetail} component={MusicDetail}
/> />
{/* <Stack.Screen {/* <Stack.Screen
name="DetailsSpot" name="DetailsSpot"
component={SpotDetailsPage} component={SpotDetailsPage}
sharedElements={(route) => { sharedElements={(route) => {
return [route.params.spot.name] return [route.params.spot.name]
}} }}
/> */} /> */}
</Stack.Navigator> </Stack.Navigator>
) )
} }

@ -4,7 +4,7 @@ import Register from '../screens/Register';
import Onboarding from '../components/Onboarding'; import Onboarding from '../components/Onboarding';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native'; import { NavigationContainer } from '@react-navigation/native';
import {useDispatch, useSelector} from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import * as SplashScreen from 'expo-splash-screen'; import * as SplashScreen from 'expo-splash-screen';
import { getRefreshToken } from '../redux/thunk/authThunk'; import { getRefreshToken } from '../redux/thunk/authThunk';
import { ArtistLayout } from '../components/Genre'; import { ArtistLayout } from '../components/Genre';
@ -31,27 +31,27 @@ export default function StartNavigation() {
// if (!appIsReady) { // if (!appIsReady) {
// return null; // return null;
// } // }
const Stack = createStackNavigator(); const Stack = createStackNavigator();
return ( return (
<NavigationContainer> <NavigationContainer>
<Stack.Navigator> <Stack.Navigator>
<Stack.Screen <Stack.Screen
name="Home" name="Home"
component={Onboarding} component={Onboarding}
options={{ headerShown: false }} options={{ headerShown: false }}
/> />
<Stack.Screen <Stack.Screen
name="Login" name="Login"
component={Login} component={Login}
options={{ headerShown: false }} options={{ headerShown: false }}
/> />
<Stack.Screen <Stack.Screen
name="Register" name="Register"
component={Register} component={Register}
options={{ headerShown: false }} options={{ headerShown: false }}
/> />
</Stack.Navigator> </Stack.Navigator>
</NavigationContainer> </NavigationContainer>
) )
} }

@ -45,3 +45,8 @@ export const userSignUp = (user : User) => {
}; };
} }
export const userChangeMode = () => {
return {
type: userTypes.CHANGE_MODE,
};
}

@ -5,32 +5,32 @@ import { favoritesTypes } from "../types/favoritesTypes";
import { spotifyTypes } from "../types/spotifyTypes"; import { spotifyTypes } from "../types/spotifyTypes";
import { spotTypes } from "../types/spotTypes"; import { spotTypes } from "../types/spotTypes";
let tmpMusic: Music[] = [ let tmpMusic: Music[] = [
new Music("03o8WSqd2K5rkGvn9IsLy2","Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg","https://p.scdn.co/mp3-preview/c55f95de81b8c3d0df04148da1b03bd38db56e8f?cid=774b29d4f13844c495f206cafdad9c86"), new Music("03o8WSqd2K5rkGvn9IsLy2", "Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg", "https://p.scdn.co/mp3-preview/c55f95de81b8c3d0df04148da1b03bd38db56e8f?cid=774b29d4f13844c495f206cafdad9c86"),
new Music("6DPrYPPGYK218iVIZDix3i","Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png","https://p.scdn.co/mp3-preview/a9f9cb19ac1fe6db0d06b67decf8edbb25895a33?cid=774b29d4f13844c495f206cafdad9c86"), new Music("6DPrYPPGYK218iVIZDix3i", "Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png", "https://p.scdn.co/mp3-preview/a9f9cb19ac1fe6db0d06b67decf8edbb25895a33?cid=774b29d4f13844c495f206cafdad9c86"),
new Music("5GFHFEASZeJF0gyWuDDjGE","Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png","https://p.scdn.co/mp3-preview/9e854f4905c1228482e390169eb76d8520076b8f?cid=774b29d4f13844c495f206cafdad9c86"), new Music("5GFHFEASZeJF0gyWuDDjGE", "Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png", "https://p.scdn.co/mp3-preview/9e854f4905c1228482e390169eb76d8520076b8f?cid=774b29d4f13844c495f206cafdad9c86"),
]; ];
const initialState = { const initialState = {
spot: [] as Spot[], spot: [] as Spot[],
favoriteMusic: tmpMusic, favoriteMusic: tmpMusic,
userCurrentMusic : null userCurrentMusic: null
} }
const appReducer = (state = initialState, action : any) => { const appReducer = (state = initialState, action: any) => {
switch (action.type) { switch (action.type) {
case favoritesTypes.GET_FAVORITE_MUSICS: case favoritesTypes.GET_FAVORITE_MUSICS:
return {...state, favoriteMusic: action.playload}; return { ...state, favoriteMusic: action.playload };
case favoritesTypes.ADD_FAVORITE_MUSICS: case favoritesTypes.ADD_FAVORITE_MUSICS:
return {...state, favoriteMusic: [action.playload, ...state.favoriteMusic]}; return { ...state, favoriteMusic: [action.playload, ...state.favoriteMusic] };
case favoritesTypes.REMOVE_FAVORITE_MUSICS: case favoritesTypes.REMOVE_FAVORITE_MUSICS:
return {...state, favoriteMusic: state.favoriteMusic}; return { ...state, favoriteMusic: state.favoriteMusic };
case spotTypes.FETCH_SPOT: case spotTypes.FETCH_SPOT:
return {...state, spot: action.payload}; return { ...state, spot: action.payload };
case discoveriesTypes.FETCH_DISCOVERIES: case discoveriesTypes.FETCH_DISCOVERIES:
return; return;
case spotifyTypes.GET_USER_CURRENT_MUSIC: case spotifyTypes.GET_USER_CURRENT_MUSIC:
return {...state, userCurrentMusic: action.payload}; return { ...state, userCurrentMusic: action.playload };
default: default:
return state; return state;
} }
} }

@ -1,18 +0,0 @@
Uri getApiUrlAuthorize() => _api.identification.urlAuthorize;
String getApiRedirectUrl() => _api.identification.redirectUri;
String getIdSpotify() => _currentUser.idSpotify;
String getIdFlad() => _currentUser.idFlad;
case getCompleteMusic
playTrack(String id)
case addToPlaylist:
return {...state, spot: action.payload}
case removeFromPlaylist:

@ -4,56 +4,60 @@ const initialState = {
loading: false, loading: false,
user: User, // for user object user: User, // for user object
userFladToken: "", // for storing the JWT userFladToken: "", // for storing the JWT
userSpotifyToken : null, userSpotifyToken: null,
error: null, error: null,
isLogedIn: false, isLogedIn: false,
} dark: false,
}
const userReducer = (state = initialState, action : any) => { const userReducer = (state = initialState, action: any) => {
switch (action.type) { switch (action.type) {
// just for the navigation and speciafly use // just for the navigation and speciafly use
// and // and
case userTypes.RESTORE_TOKEN: case userTypes.RESTORE_TOKEN:
const resp = (action.playload == "" ? false : true) const resp = (action.playload == "" ? false : true)
console.log(resp, "si il ya le tokennen ou passssssssssss") console.log(resp, "si il ya le tokennen ou passssssssssss")
return { return {
...state, ...state,
userFladToken : action.playload, userFladToken: action.playload,
loading: true, loading: true,
isLogedIn: resp, isLogedIn: resp,
}; };
case userTypes.LOGIN: case userTypes.LOGIN:
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
console.log(action.playload, "LOOGGIIINN"); console.log(action.playload, "LOOGGIIINN");
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
return { return {
...state, ...state,
user :action.playload, user: action.playload,
isLogedIn: true isLogedIn: true
}; };
case userTypes.SIGNUP: case userTypes.SIGNUP:
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
console.log(action.playload, "LOOGGIIINN"); console.log(action.playload, "LOOGGIIINN");
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
return { return {
...state, ...state,
user :action.playload, user: action.playload,
isLogedIn: true isLogedIn: true
}; };
case userTypes.USER_LOGOUT: case userTypes.USER_LOGOUT:
return {...state, return {
user :null, ...state,
isLogedIn: false } user: null,
case userTypes.SAVE_SPOTIFY: isLogedIn: false
return { }
...state, case userTypes.SAVE_SPOTIFY:
userSpotifyToken : action.playload, return {
}; ...state,
default: userSpotifyToken: action.playload,
return state; };
} case userTypes.CHANGE_MODE:
return { ...state, dark: !state.dark }
default:
return state;
} }
export default userReducer }
export default userReducer

@ -1,4 +1,4 @@
import {configureStore} from '@reduxjs/toolkit' import { configureStore } from '@reduxjs/toolkit'
import appReducer from './reducers/appReducer'; import appReducer from './reducers/appReducer';
import userReducer from './reducers/userReducer'; import userReducer from './reducers/userReducer';
@ -9,7 +9,7 @@ const reducer = {
} }
const store = configureStore({ const store = configureStore({
reducer : reducer, reducer: reducer,
},); },);
export default store; export default store;

@ -4,7 +4,7 @@ import axios from "axios";
import { json } from "express"; import { json } from "express";
import { useEffect } from "react"; import { useEffect } from "react";
import { API_URL } from "../../fladConfig"; import { API_URL } from "../../fladConfig";
import { Credentials, CredentialsRegister, restoreToken, setLoginState, userSignUp } from "../actions/userActions"; import { Credentials, CredentialsRegister, restoreToken, setLoginState, UserLogout, userChangeMode, userSignUp } from "../actions/userActions";
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
import { User } from "../../Model/User"; import { User } from "../../Model/User";
import { UserFactory } from "../../Model/factory/UserFactory"; import { UserFactory } from "../../Model/factory/UserFactory";
@ -12,137 +12,160 @@ import { UserFactory } from "../../Model/factory/UserFactory";
const key = 'userToken'; const key = 'userToken';
export const registerUser = ( resgisterCredential : CredentialsRegister) => { export const registerUser = ( resgisterCredential : CredentialsRegister) => {
//@ts-ignore //@ts-ignore
return async dispatch => { return async dispatch => {
try { try {
console.log(resgisterCredential); console.log(resgisterCredential);
const config = { const config = {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}
const resp = await axios.post(
`${API_URL}/api/users/register`,
resgisterCredential,
config
)
if (resp.data.token) {
console.log(resp.data.token);
const token = resp.data.token;
// await SecureStore.setItemAsync(key, token);
const headers = {
'Authorization': 'Bearer ' + token};
const user = await axios.get(
"https://flad-api-production.up.railway.app/api/users",
{headers}
)
dispatch(userSignUp( UserFactory.JsonToModel(user.data) )); // our action is called here
// console.log(user.data);
// dispatch(setLoginState(user.data) ); // our action is called here
} else {
console.log('Login Failed', 'Username or Password is incorrect');
}
// if (resp.data.msg === 'success') { // response success checking logic could differ
// await SecureStore.setItemAsync(key, resp.data.token);
// dispatch(setLoginState(resp.data.user) ); // our action is called here
// } else {
// console.log('Login Failed', 'Username or Password is incorrect');
// }
} catch (error) {
console.log('Error---------', error);
} }
const resp = await axios.post(
`${API_URL}/api/users/register`,
resgisterCredential,
config
)
if (resp.data.token) {
console.log(resp.data.token);
const token = resp.data.token;
// await SecureStore.setItemAsync(key, token);
const headers = {
'Authorization': 'Bearer ' + token};
const user = await axios.get(
"https://flad-api-production.up.railway.app/api/users",
{headers}
)
dispatch(userSignUp( UserFactory.JsonToModel(user.data) )); // our action is called here
// console.log(user.data);
// dispatch(setLoginState(user.data) ); // our action is called here
} else {
console.log('Login Failed', 'Username or Password is incorrect');
}
// if (resp.data.msg === 'success') { // response success checking logic could differ
// await SecureStore.setItemAsync(key, resp.data.token);
// dispatch(setLoginState(resp.data.user) ); // our action is called here
// } else {
// console.log('Login Failed', 'Username or Password is incorrect');
// }
} catch (error) {
console.log('Error---------', error);
} }
} }
export const userLogin = ( loginCredential : Credentials) => { }
//@ts-ignore
return async dispatch => { export const userLogin = (loginCredential: Credentials) => {
//@ts-ignore
return async dispatch => {
try { try {
console.log(loginCredential); console.log(loginCredential);
const config = { const config = {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
} }
// const resppp = await axios.get(`${API_URL}/toto`); // const resppp = await axios.get(`${API_URL}/toto`);
// console.log(resppp.data, "sddsd"); // console.log(resppp.data, "sddsd");
const resp = await axios.post( const resp = await axios.post(
"https://flad-api-production.up.railway.app/api/users/login", "https://flad-api-production.up.railway.app/api/users/login",
loginCredential, loginCredential,
config config
) )
console.log("====================================================================================") console.log("====================================================================================")
console.log(resp.data) console.log(resp.data)
console.log("====================================================================================") console.log("====================================================================================")
if (resp.data.token) { if (resp.data.token) {
console.log(resp.data.token); console.log(resp.data.token);
const token = resp.data.token; const token = resp.data.token;
await SecureStore.setItemAsync(key, token); await SecureStore.setItemAsync(key, token);
const headers = { const headers = {
'Authorization': 'Bearer ' + token}; 'Authorization': 'Bearer ' + token
};
const user = await axios.get( const user = await axios.get(
"https://flad-api-production.up.railway.app/api/users", "https://flad-api-production.up.railway.app/api/users",
{headers} { headers }
) )
// dispatch(setLoginState(resp.data.user) ); // our action is called here // dispatch(setLoginState(resp.data.user) ); // our action is called here
console.log(user.data); console.log(user.data);
dispatch(setLoginState(user.data) ); // our action is called here dispatch(setLoginState(user.data)); // our action is called here
} else { } else {
console.log('Login Failed', 'Username or Password is incorrect'); console.log('Login Failed', 'Username or Password is incorrect');
} }
} catch (error) { } catch (error) {
console.log('Error---------', error); console.log('Error---------', error);
} }
} }
} }
export const getRefreshToken = () => { export const getRefreshToken = () => {
//@ts-ignore //@ts-ignore
return async dispatch => { return async dispatch => {
try { try {
let userToken : string | null = await SecureStore.getItemAsync('key'); let userToken: string | null = await SecureStore.getItemAsync(key);
if (userToken) { if (userToken) {
console.log("==========key2 =================="); console.log("==========key2 ==================");
console.log(userToken); console.log(userToken);
console.log("==========key =================="); console.log("==========key ==================");
console.log("==========on devrais être laaaa =================="); console.log("==========on devrais être laaaa ==================");
dispatch(restoreToken(userToken) ); dispatch(restoreToken(userToken));
} else { } else {
console.log("==========OOOOOORRRRRRRRHHHHHHHHHH =================="); console.log("==========OOOOOORRRRRRRRHHHHHHHHHH ==================");
const empty = ""; const empty = "";
dispatch(restoreToken(empty) ); dispatch(restoreToken(empty));
console.log("merddee"); console.log("merddee");
} }
} catch (e) { } catch (e) {
console.log('Error---------', e); console.log('Error---------', e);
} }
}
}
export const DeleteToken = () => {
//@ts-ignore
return async dispatch => {
try {
await SecureStore.deleteItemAsync(key);
dispatch(UserLogout());
} catch (e) {
console.log('Error deleting token', e);
} }
}
} }
// const logIn = (email, password) => { export const ChangeMode = () => {
// const action = (dispatch) => { //@ts-ignore
// if (email === user.email && password === user.password) { return async dispatch => {
// dispatch(setLoggedInState(true)); dispatch(userChangeMode());
// return true; await SecureStore.deleteItemAsync(key);
// }
// dispatch(setLoggedInState(false));
// return false;
// };
// return action;
// };
// better
async function save(key : string, value : string) {
await SecureStore.setItemAsync(key, value);
} }
}
// const logIn = (email, password) => {
// const action = (dispatch) => {
// if (email === user.email && password === user.password) {
// dispatch(setLoggedInState(true));
// return true;
// }
// dispatch(setLoggedInState(false));
// return false;
// };
// return action;
// };
// better
async function save(key: string, value: string) {
await SecureStore.setItemAsync(key, value);
}

@ -91,7 +91,7 @@ export const getCurrentUserMusic = (resuestHandler : SpotifyService)=> {
catch (error) { catch (error) {
console.log('Error---------', error); console.log('Error---------', error);
} }
} }
} }
export const searchMusic = async (resuestHandler : SpotifyService,search: string) => { export const searchMusic = async (resuestHandler : SpotifyService,search: string) => {
// //

@ -1,10 +1,10 @@
export const userTypes = { export const userTypes = {
LOGIN: 'LOGIN', LOGIN: 'LOGIN',
SIGNUP: 'SIGNUP', SIGNUP: 'SIGNUP',
SAVE_SPOTIFY :'SAVE_SPOTIFY', SAVE_SPOTIFY: 'SAVE_SPOTIFY',
UPDATE_USER: 'UPDATE_USER', UPDATE_USER: 'UPDATE_USER',
UPDATE_PROFILE_PICTURE: 'UPDATE_PROFILE_PICTURE', UPDATE_PROFILE_PICTURE: 'UPDATE_PROFILE_PICTURE',
USER_LOGOUT : 'USER_LOGOUT', USER_LOGOUT: 'USER_LOGOUT',
RESTORE_TOKEN : "RESTORE_TOKEN" RESTORE_TOKEN: "RESTORE_TOKEN",
} CHANGE_MODE: "CHANGE_MODE"
}

@ -1,26 +1,38 @@
import React, { useEffect, useState} from 'react'; import React, { useEffect, useState } from 'react';
import { Image,StyleSheet, Text, View, FlatList, ScrollView, TouchableOpacity, TouchableHighlight, SafeAreaView } from 'react-native'; import { Image, StyleSheet, Text, View, FlatList, ScrollView, TouchableOpacity, TouchableHighlight, SafeAreaView } from 'react-native';
import CardMusic from '../components/CardMusic'; import CardMusic from '../components/CardMusic';
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import Music from '../Model/Music' import Music from '../Model/Music'
import {useNavigation} from "@react-navigation/native"; import FladyComponent from '../components/FladyComponent';
import { useNavigation } from "@react-navigation/native";
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { getFavoritesMusic } from '../redux/actions/appActions'; import { getFavoritesMusic } from '../redux/actions/appActions';
import { SharedElement } from 'react-navigation-shared-element'; import { SharedElement } from 'react-navigation-shared-element';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
export default function favoritePage() { export default function favoritePage() {
//Dark Mode
const isDark = useSelector(state => state.userReducer.dark);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark;
const navigation = useNavigation(); const navigation = useNavigation();
//@ts-ignore //@ts-ignore
const favoritesMusic = useSelector(state => state.appReducer.favoriteMusic); const favoritesMusic = useSelector(state => state.appReducer.favoriteMusic);
const dispatch = useDispatch(); const dispatch = useDispatch();
const images = [
const navigueToDetail = (music : any) => { { id: 1, source: require('../assets/images/FLADYLove.png') },
navigation.navigate("MusicDetail", {"music": music}) { id: 2, source: require('../assets/images/FLADYStar.png') },
{ id: 3, source: require('../assets/images/FLADYHate.png') },
{ id: 4, source: require('../assets/images/FLADYCry.png') },
];
const navigueToDetail = (music: any) => {
navigation.navigate("MusicDetail", { "music": music })
}; };
// to do // to do
const [filteredDataSource, setFilteredDataSource] = useState<Music[]>([]); const [filteredDataSource, setFilteredDataSource] = useState<Music[]>([]);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const searchMusic = (text: string) => { const searchMusic = (text: string) => {
if (text) { if (text) {
const newData = favoritesMusic.filter(function (item: Music) { const newData = favoritesMusic.filter(function (item: Music) {
const search = item.title const search = item.title
@ -36,86 +48,90 @@ export default function favoritePage() {
} }
}; };
const styles = StyleSheet.create({
mainSafeArea: {
flex: 1,
backgroundColor: style.body,
},
titleContainer: {
marginTop: 30,
marginLeft: 20,
},
title: {
fontSize: normalize(28),
fontWeight: 'bold',
color: style.Text,
},
description: {
marginTop: 10,
fontSize: normalize(20),
color: '#787878',
marginBottom: 20
},
button: {
marginTop: '10%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'center',
backgroundColor: 'white',
width: normalize(100),
height: normalize(100),
borderRadius: 21
},
buttonImage: {
width: normalize(46),
height: normalize(46),
},
shadow: {
shadowColor: '#000',
shadowOffset: {
width: 2,
height: 3,
},
shadowOpacity: 0.50,
shadowRadius: 3.84,
}
});
return ( return (
<View style={styles.body}> <SafeAreaView style={styles.mainSafeArea}>
<SafeAreaView style={styles.mainSafeArea}>
<View style={styles.titleContainer}> <View style={styles.titleContainer}>
<Text style={styles.title}>Favoris</Text> <Text style={styles.title}>Favoris</Text>
<Text style={styles.description}>Retrouvez ici vos musiques favorites</Text> <Text style={styles.description}>Retrouvez ici vos musiques favorites</Text>
</View> </View>
<ScrollView> <ScrollView>
<View> <View>
<FlatList style={{marginBottom: 80}} <FlatList style={{ marginBottom: 30 }}
data={favoritesMusic} data={favoritesMusic}
renderItem={({ item }) => ( renderItem={({ item }) => (
<TouchableHighlight onPress={() => {navigueToDetail(item)}}> <TouchableHighlight onPress={() => { navigueToDetail(item) }}>
<SharedElement id={item.id}> <SharedElement id={item.id}>
<CardMusic image={item.image} title={item.title} description={item.bio} id={item.id}/> <CardMusic image={item.image} title={item.title} description={item.bio} id={item.id} />
</SharedElement> </SharedElement>
</TouchableHighlight> </TouchableHighlight>
)} )}
keyExtractor={(item: Music) => item.title } keyExtractor={(item: Music) => item.title}
/> />
</View> </View>
<TouchableOpacity style={[styles.button, styles.shadow]} <Text style={[styles.title, { marginLeft: 20 }]}>What's your mood?</Text>
// @ts-ignore <FlatList
onPress={() => navigation.navigate('Genre')}> style={{ marginTop: 10 }}
<Image source={require("../assets/icons/icons/next.png")} style={styles.buttonImage}/> data={images}
</TouchableOpacity> keyExtractor={(item) => item.id.toString()}
</ScrollView> horizontal
</SafeAreaView> showsHorizontalScrollIndicator={false}
</View> renderItem={({ item }) => (
<FladyComponent image={item.source} />
)}
/>
<TouchableOpacity style={[styles.button, styles.shadow]}
// @ts-ignore
onPress={() => navigation.navigate('Genre')}>
<Image source={require("../assets/icons/icons/next.png")} style={styles.buttonImage} />
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
); );
}; };
const styles = StyleSheet.create({
mainSafeArea: {
flex: 1,
backgroundColor: "#141414",
},
body: {
flex: 1,
justifyContent: 'center',
backgroundColor: "#141414",
},
titleContainer: {
marginTop: 30,
marginLeft: 20,
},
title: {
fontSize: normalize(28),
fontWeight: 'bold',
color: 'white',
},
description: {
marginTop: 10,
fontSize: normalize(20),
color: '#787878',
marginBottom: 20
},
button: {
marginTop: '10%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'center',
backgroundColor: 'white',
width: normalize(100),
height: normalize(100),
borderRadius: 21
},
buttonImage: {
width: normalize(46),
height: normalize(46),
},
shadow: {
shadowColor: '#000',
shadowOffset: {
width: 2,
height: 3,
},
shadowOpacity: 0.50,
shadowRadius: 3.84,
}
});

@ -1,9 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { View, Image, StyleSheet, Text, ImageBackground, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity } from 'react-native'; import { View, Image, StyleSheet, Text, ImageBackground, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity } from 'react-native';
import {useNavigation} from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import { userLogin } from '../redux/thunk/authThunk'; import { userLogin } from '../redux/thunk/authThunk';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { Audio } from 'expo-av';
import { Credentials } from '../redux/actions/userActions'; import { Credentials } from '../redux/actions/userActions';
// @ts-ignore // @ts-ignore
@ -14,22 +15,33 @@ const DismissKeyboard = ({ children }) => (
) )
export default function loginPage() { export default function loginPage() {
const [sound, setSound] = useState<Audio.Sound>();
const [rememberMe, setRememberMe] = useState(false); const [rememberMe, setRememberMe] = useState(false);
const navigation = useNavigation(); const navigation = useNavigation();
const [username, setUsername] = useState(''); const [username, setUsername] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
async function playSound() {
console.log('Loading Sound');
const { sound } = await Audio.Sound.createAsync(
require('../assets/sounds/Click.mp3')
);
setSound(sound);
console.log('Playing Sound');
await sound.playAsync();
}
const dispatch = useDispatch(); const dispatch = useDispatch();
const submitForm = () => { const submitForm = () => {
const credentials: Credentials = { const credentials: Credentials = {
email: username, email: username,
password: password password: password
}; };
//@ts-ignore //@ts-ignore
dispatch(userLogin(credentials)) dispatch(userLogin(credentials))
} playSound()
}
const toggleRememberMe = () => { const toggleRememberMe = () => {
setRememberMe(!rememberMe); setRememberMe(!rememberMe);
@ -42,19 +54,19 @@ export default function loginPage() {
<Text style={styles.versionText}> <Text style={styles.versionText}>
v2.0 v2.0
</Text> </Text>
<Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo}/> <Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo} />
<Text style={styles.text}>SE CONNECTER</Text> <Text style={styles.text}>SE CONNECTER</Text>
<View> <View>
<TextInput placeholder="Username" <TextInput placeholder="Username"
value={username} value={username}
onChangeText={setUsername}style={[styles.input, styles.shadow]}/> onChangeText={setUsername} style={[styles.input, styles.shadow]} />
<Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} /> <Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} />
</View> </View>
<View> <View>
<TextInput placeholder="Password" <TextInput placeholder="Password"
value={password} value={password}
onChangeText={setPassword} onChangeText={setPassword}
secureTextEntry style={[styles.input, styles.shadow]}/> secureTextEntry style={[styles.input, styles.shadow]} />
<Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} /> <Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} />
</View> </View>
<View style={styles.rememberMeContainer}> <View style={styles.rememberMeContainer}>
@ -62,15 +74,15 @@ export default function loginPage() {
<Text style={styles.rememberMeText}>SE SOUVENIR DE MOI</Text> <Text style={styles.rememberMeText}>SE SOUVENIR DE MOI</Text>
</View> </View>
<TouchableOpacity style={[styles.button, styles.shadow]} onPress={submitForm}> <TouchableOpacity style={[styles.button, styles.shadow]} onPress={submitForm}>
<Image source={require("../assets/icons/Check.png")} style={styles.buttonImage}/> <Image source={require("../assets/icons/Check.png")} style={styles.buttonImage} />
</TouchableOpacity> </TouchableOpacity>
<View style={styles.inscriptionText}> <View style={styles.inscriptionText}>
<Text style={{fontSize: normalize(18), color: 'white'}}>Tu n'as pas de compte? </Text> <Text style={{ fontSize: normalize(18), color: 'white' }}>Tu n'as pas de compte? </Text>
<TouchableOpacity <TouchableOpacity
// @ts-ignore // @ts-ignore
onPress={() => navigation.navigate('Register')} onPress={() => navigation.navigate('Register')}
> >
<Text style={{fontSize: normalize(18), color: '#406DE1', textDecorationLine: 'underline'}}>S'inscrire</Text> <Text style={{ fontSize: normalize(18), color: '#406DE1', textDecorationLine: 'underline' }}>S'inscrire</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</ImageBackground> </ImageBackground>
@ -81,7 +93,7 @@ export default function loginPage() {
const styles = StyleSheet.create ({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
}, },
@ -110,14 +122,14 @@ const styles = StyleSheet.create ({
width: normalize(46), width: normalize(46),
height: normalize(46), height: normalize(46),
}, },
iconUser : { iconUser: {
position: 'absolute', position: 'absolute',
width: 20, width: 20,
height: 20, height: 20,
left: normalize(80), left: normalize(80),
bottom: '50%' bottom: '50%'
}, },
iconLock : { iconLock: {
position: 'absolute', position: 'absolute',
width: 20, width: 20,
height: 20, height: 20,
@ -145,8 +157,8 @@ const styles = StyleSheet.create ({
shadow: { shadow: {
shadowColor: 'black', shadowColor: 'black',
shadowOffset: { shadowOffset: {
width: 2, width: 2,
height: 3, height: 3,
}, },
shadowOpacity: 0.50, shadowOpacity: 0.50,
shadowRadius: 3.84, shadowRadius: 3.84,

@ -1,5 +1,5 @@
import { NavigationProp, RouteProp, useNavigation } from "@react-navigation/native"; import { NavigationProp, RouteProp, useNavigation } from "@react-navigation/native";
import { View,Text,Image,StyleSheet, Dimensions, useWindowDimensions, Button, TouchableOpacity, ScrollView, Pressable } from "react-native"; import { View, Text, Image, StyleSheet, Dimensions, useWindowDimensions, Button, TouchableOpacity, ScrollView, Pressable } from "react-native";
import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, useDerivedValue, useSharedValue, Value, withSpring, withTiming } from "react-native-reanimated"; import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, useDerivedValue, useSharedValue, Value, withSpring, withTiming } from "react-native-reanimated";
import { BlurView } from 'expo-blur'; import { BlurView } from 'expo-blur';
import qs from "qs"; import qs from "qs";
@ -7,6 +7,7 @@ import axios from "axios";
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
import { Audio } from 'expo-av'; import { Audio } from 'expo-av';
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import normalize from '../components/Normalize';
import { State, TapGestureHandler } from "react-native-gesture-handler"; import { State, TapGestureHandler } from "react-native-gesture-handler";
import { RequestHandler } from "../services/spotify/spotifyRequestHandler/utils"; import { RequestHandler } from "../services/spotify/spotifyRequestHandler/utils";
import { FetchRequest } from "expo-auth-session/build/Fetch"; import { FetchRequest } from "expo-auth-session/build/Fetch";
@ -20,17 +21,16 @@ import FontAwesome from 'react-native-vector-icons/FontAwesome';
import { Feather as Icon } from "@expo/vector-icons"; import { Feather as Icon } from "@expo/vector-icons";
import { HorizontalFlatList } from "../components/HorizontalFlatList"; import { HorizontalFlatList } from "../components/HorizontalFlatList";
import { LittleCard } from "../components/littleCard"; import { LittleCard } from "../components/littleCard";
import normalize from "../components/Normalize";
import { Circle } from "react-native-svg"; import { Circle } from "react-native-svg";
import { AntDesign } from '@expo/vector-icons'; import { AntDesign } from '@expo/vector-icons';
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
const halfPi = Math.PI/2; const halfPi = Math.PI / 2;
//@ts-ignore //@ts-ignore
const MusicDetail = ({ route }) => { const MusicDetail = ({ route }) => {
const music : Music = route.params.music; const music: Music = route.params.music;
const [currentspot, setCurrentSpot] = useState(music); const [currentspot, setCurrentSpot] = useState(music);
const [simularMusic, setSimularMusic] = useState<Music[]>([]); const [simularMusic, setSimularMusic] = useState<Music[]>([]);
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
@ -41,7 +41,7 @@ const MusicDetail = ({ route }) => {
const [testtoken, setTesttoken] = useState('') const [testtoken, setTesttoken] = useState('')
const sheet = async () => { const sheet = async () => {
SecureStore.getItemAsync('MySecureAuthStateKey').then(result => { setTesttoken(result)}); SecureStore.getItemAsync('MySecureAuthStateKey').then(result => { setTesttoken(result) });
} }
@ -58,7 +58,7 @@ const MusicDetail = ({ route }) => {
// setSimularMusic(simularMusic); // setSimularMusic(simularMusic);
// } // }
const getSimilarTrack = async () => { const getSimilarTrack = async () => {
try { try {
const service = new SpotifyService(testtoken); const service = new SpotifyService(testtoken);
const simularMusic = await service.getSimilarTrack(currentspot.id, 5, 'FR'); const simularMusic = await service.getSimilarTrack(currentspot.id, 5, 'FR');
@ -72,61 +72,61 @@ const MusicDetail = ({ route }) => {
const handlePlaySound = async () => { const handlePlaySound = async () => {
if (sound === null) { if (sound === null) {
const { sound: newSound } = await Audio.Sound.createAsync( const { sound: newSound } = await Audio.Sound.createAsync(
{ uri: music.trackPreviewUrl }, { uri: music.trackPreviewUrl },
{ shouldPlay: true } { shouldPlay: true }
); );
setSound(newSound); setSound(newSound);
setIsPlaying(true); setIsPlaying(true);
} else { } else {
setIsPlaying(true); setIsPlaying(true);
//@ts-ignore //@ts-ignore
await sound.playAsync(); await sound.playAsync();
} }
}; };
const handleStopSound = async () => { const handleStopSound = async () => {
if (sound !== null) { if (sound !== null) {
setIsPlaying(false); setIsPlaying(false);
//@ts-ignore //@ts-ignore
await sound.stopAsync(); await sound.stopAsync();
} }
else{ else {
} }
}; };
useEffect(() => { useEffect(() => {
return sound ? () => { return sound ? () => {
console.log('Unloading Sound'); console.log('Unloading Sound');
//@ts-ignore //@ts-ignore
sound.unloadAsync(); sound.unloadAsync();
} }
: undefined; : undefined;
}, [sound]); }, [sound]);
const sensor = useAnimatedSensor(SensorType.ROTATION); const sensor = useAnimatedSensor(SensorType.ROTATION);
const styleAniamatedImage = useAnimatedStyle(() => { const styleAniamatedImage = useAnimatedStyle(() => {
const {yaw, pitch, roll} = sensor.sensor.value; const { yaw, pitch, roll } = sensor.sensor.value;
const verticalAxis =interpolate( const verticalAxis = interpolate(
pitch, pitch,
[-halfPi*2,halfPi*2], [-halfPi * 2, halfPi * 2],
[-45, 45] [-45, 45]
) )
const horizontalAxis =interpolate( const horizontalAxis = interpolate(
roll, roll,
[-halfPi*2,halfPi*2], [-halfPi * 2, halfPi * 2],
[-45, 45] [-45, 45]
) )
return { return {
top : withSpring( verticalAxis), top: withSpring(verticalAxis),
left : withSpring(horizontalAxis), left: withSpring(horizontalAxis),
}; };
}) })
return ( return (
<View style={styles.body}> <View style={styles.body}>
<View style={styles.backgroundSection}> <View style={styles.backgroundSection}>
<Image <Image
blurRadius={133} blurRadius={133}
style={styles.back_drop} style={styles.back_drop}
@ -141,85 +141,89 @@ const MusicDetail = ({ route }) => {
/> */} /> */}
<LinearGradient style={styles.gradientFade} <LinearGradient style={styles.gradientFade}
// Button Linear Gradient // Button Linear Gradient
colors={['rgba(56,56,56,0)', 'rgba(14,14,14,1)']}> colors={['rgba(56,56,56,0)', 'rgba(14,14,14,1)']}>
</LinearGradient> </LinearGradient>
</View> </View>
<View style={styles.background1}> <View style={styles.background1}>
<ScrollView style={styles.list} showsVerticalScrollIndicator={false} scrollEventThrottle={4}> <ScrollView style={styles.list} showsVerticalScrollIndicator={false} scrollEventThrottle={4}>
<View style={styles.section1}> <View style={styles.section1}>
<View style={{ flex: 1,justifyContent : 'flex-start', alignItems : 'center' }}> <View style={{ flex: 1, justifyContent: 'flex-start', alignItems: 'center' }}>
{/* <SharedElement id={spot.name} style={{ flex: 1 }}> */} {/* <SharedElement id={spot.name} style={{ flex: 1 }}> */}
<View> <View>
<Animated.Image <Animated.Image
source={{ source={{
uri:currentspot.image , uri: currentspot.image,
}} }}
style={[ style={[
{ {
// width: 370, // width: 370,
// width: 400, // width: 400,
width: 392, width: normalize(429),
height: 392, height: normalize(429),
borderRadius : 24, borderRadius: 24,
resizeMode: 'stretch', resizeMode: 'stretch',
},styleAniamatedImage }, styleAniamatedImage
]} ]}
/> />
</View> </View>
<View style={{marginTop : 45,flex: 1, flexDirection : 'row', }}> <View style={{ marginTop: 45, flex: 1, flexDirection: 'row', }}>
<View> <View>
</View> </View>
<TouchableOpacity activeOpacity={0.5} style={{ <TouchableOpacity activeOpacity={0.5} style={{
backgroundColor: '#F80404', backgroundColor: '#F80404',
borderRadius: 100, borderRadius: 100,
padding: normalize(23) padding: normalize(23)
}}> }}>
<View style={{flex: 1, justifyContent : 'center', alignContent : 'center'}}> <View style={{ flex: 1, justifyContent: 'center', alignContent: 'center' }}>
<FontAwesome name="play" size={32} color="#FFFF" ></FontAwesome> <FontAwesome name="play" size={32} color="#FFFF" ></FontAwesome>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View>
</View>
<View style ={{flex: 1, flexDirection : 'row', justifyContent :'space-evenly', width : '100%' }}> </View>
<TouchableOpacity activeOpacity={0.6} style={{ flexDirection : 'row', justifyContent : 'space-evenly',alignItems: 'center', width: 180, <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-evenly', width: '100%' }}>
height: 64, borderRadius: 8, opacity: 0.86 ,backgroundColor: '#0B0606', }}>
<FontAwesome name="bookmark" size={24} color="#FFFF" ></FontAwesome> <TouchableOpacity activeOpacity={0.6} style={{
<Text style={{ fontSize: normalize(16), fontWeight:"700", color : '#FFFFFF' }}>Dans ma collection</Text> flexDirection: 'row', justifyContent: 'space-evenly', alignItems: 'center', width: 180,
</TouchableOpacity> height: 64, borderRadius: 8, opacity: 0.86, backgroundColor: '#0B0606',
<TouchableOpacity activeOpacity={0.6} style={{ flexDirection : 'row', justifyContent : 'space-evenly',alignItems: 'center', width: 180, }}>
height: 64, borderRadius: 8, opacity: 0.86 ,backgroundColor: '#0B0606', }}> <FontAwesome name="bookmark" size={24} color="#FFFF" ></FontAwesome>
<Icon name="share" size={24} color="#FFFF"></Icon> <Text style={{ fontSize: normalize(16), fontWeight: "700", color: '#FFFFFF' }}>Dans ma collection</Text>
{/* <FontAwesome name="bookmark" size={24} color="#FF0000" ></FontAwesome> */} </TouchableOpacity>
<Text style={{ fontSize: normalize(16), fontWeight:"700", color : '#FFFFFF' }}>Partagedr cette music</Text> <TouchableOpacity activeOpacity={0.6} style={{
</TouchableOpacity> flexDirection: 'row', justifyContent: 'space-evenly', alignItems: 'center', width: 180,
{/* <Pressable style={{flexDirection : 'row', justifyContent : 'space-between', alignItems: 'center', height: "10%" , borderRadius: 8, opacity: 84 ,backgroundColor: 'rgba(29, 16, 16, 0.84)' }}> height: 64, borderRadius: 8, opacity: 0.86, backgroundColor: '#0B0606',
}}>
<Icon name="share" size={24} color="#FFFF"></Icon>
{/* <FontAwesome name="bookmark" size={24} color="#FF0000" ></FontAwesome> */}
<Text style={{ fontSize: normalize(16), fontWeight: "700", color: '#FFFFFF' }}>Partagedr cette music</Text>
</TouchableOpacity>
{/* <Pressable style={{flexDirection : 'row', justifyContent : 'space-between', alignItems: 'center', height: "10%" , borderRadius: 8, opacity: 84 ,backgroundColor: 'rgba(29, 16, 16, 0.84)' }}>
<FontAwesome name="bookmark" size={16} color="#FF0000" ></FontAwesome> <FontAwesome name="bookmark" size={16} color="#FF0000" ></FontAwesome>
<Text style={{ fontSize: 16, fontWeight:"700",lineHeight:12, color : '#FFFFFF' }}>Dans ma collection 2</Text> <Text style={{ fontSize: 16, fontWeight:"700",lineHeight:12, color : '#FFFFFF' }}>Dans ma collection 2</Text>
</Pressable> */} </Pressable> */}
</View> </View>
{simularMusic.length !== 0 && ( {simularMusic.length !== 0 && (
<HorizontalFlatList title={'Similar'} data={simularMusic}> <HorizontalFlatList title={'Similar'} data={simularMusic}>
{(props) => ( {(props) => (
<Pressable onLongPress={() => { navigator.navigate("MusicDetail", {"music": props}) }} > <Pressable onLongPress={() => { navigator.navigate("MusicDetail", { "music": props }) }} >
<LittleCard image={props.image} title ={props.title}/> <LittleCard image={props.image} title={props.title} />
</Pressable> </Pressable>
)} )}
</HorizontalFlatList> </HorizontalFlatList>
)} )}
</ScrollView> </ScrollView>
</View> </View>
</View> </View>
); );
@ -227,7 +231,7 @@ const MusicDetail = ({ route }) => {
export default MusicDetail; export default MusicDetail;
const styles = StyleSheet.create ({ const styles = StyleSheet.create({
mainSafeArea: { mainSafeArea: {
flex: 1, flex: 1,
backgroundColor: "#141414", backgroundColor: "#141414",

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { View, Image, StyleSheet, Text, ImageBackground, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity, Platform } from 'react-native'; import { View, Image, StyleSheet, Text, ImageBackground, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity, Platform } from 'react-native';
import {useNavigation} from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
import * as AuthSession from 'expo-auth-session'; import * as AuthSession from 'expo-auth-session';
@ -8,15 +8,16 @@ import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri, useAuthRequest } from 'expo-auth-session'; import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';
import { registerUser } from '../redux/thunk/authThunk'; import { registerUser } from '../redux/thunk/authThunk';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { Audio } from 'expo-av';
import { CredentialsRegister } from '../redux/actions/userActions'; import { CredentialsRegister } from '../redux/actions/userActions';
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
import SpotifyService from '../services/spotify/spotify.service'; import SpotifyService from '../services/spotify/spotify.service';
// @ts-ignore // @ts-ignore
const DismissKeyboard = ({ children }) => ( const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}> <TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children} {children}
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
) )
export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey'; export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey';
@ -25,347 +26,359 @@ WebBrowser.maybeCompleteAuthSession();
// Endpoint // Endpoint
const discovery = { const discovery = {
authorizationEndpoint: 'https://accounts.spotify.com/authorize', authorizationEndpoint: 'https://accounts.spotify.com/authorize',
tokenEndpoint: 'https://accounts.spotify.com/api/token', tokenEndpoint: 'https://accounts.spotify.com/api/token',
}; };
// save the spotifyToken // save the spotifyToken
async function save(key : string, value : string) { async function save(key: string, value: string) {
await SecureStore.setItemAsync(key, value); await SecureStore.setItemAsync(key, value);
} }
export default function InscriptionPage() { export default function InscriptionPage() {
const [rememberMe, setRememberMe] = useState(false); const [sound, setSound] = useState<Audio.Sound>();
const navigation = useNavigation(); const [rememberMe, setRememberMe] = useState(false);
const [spotifyToken, setSpotifyToken] = useState(''); const navigation = useNavigation();
const [spotifyID, setSpotifyIds] = useState('') const [spotifyToken, setSpotifyToken] = useState('');
const [spotifyID, setSpotifyIds] = useState('')
async function playSound() {
console.log('Loading Sound');
const { sound } = await Audio.Sound.createAsync(
require('../assets/sounds/Click.mp3')
);
setSound(sound);
const [username, setUsername] = useState(''); console.log('Playing Sound');
const [email, setEmail] = useState(''); await sound.playAsync();
const [password, setPassword] = useState(''); }
const toggleRememberMe = () => {
setRememberMe(!rememberMe);
}
//spotify auth
const [request, response, promptAsync] = useAuthRequest(
{
responseType: AuthSession.ResponseType.Token,
clientId: '1f1e34e4b6ba48b388469dba80202b10',
scopes: ['user-read-private','user-read-email','user-read-playback-state','user-read-currently-playing','user-read-recently-played','playlist-modify-public','ugc-image-upload','user-modify-playback-state'],
redirectUri: makeRedirectUri({
scheme: 'flad'
}),
},
discovery
);
useEffect(() => {
if (response && response.type === 'success') {
const auth = response.params.access_token;
const storageValue = JSON.stringify(auth);
if (Platform.OS !== 'web') { const [username, setUsername] = useState('');
// Securely store the auth on your device const [email, setEmail] = useState('');
save(MY_SECURE_AUTH_STATE_KEY, storageValue); const [password, setPassword] = useState('');
} const toggleRememberMe = () => {
} setRememberMe(!rememberMe);
}, [response]); }
const dispatch = useDispatch(); //spotify auth
const [request, response, promptAsync] = useAuthRequest(
{
responseType: AuthSession.ResponseType.Token,
clientId: '1f1e34e4b6ba48b388469dba80202b10',
scopes: ['user-read-private', 'user-read-email', 'user-read-playback-state', 'user-read-currently-playing', 'user-read-recently-played', 'playlist-modify-public', 'ugc-image-upload', 'user-modify-playback-state'],
redirectUri: makeRedirectUri({
scheme: 'flad'
}),
},
discovery
);
useEffect(() => {
if (response && response.type === 'success') {
const auth = response.params.access_token;
const storageValue = JSON.stringify(auth);
const submitForm = () => { if (Platform.OS !== 'web') {
const credentials: CredentialsRegister = { // Securely store the auth on your device
email: email, save(MY_SECURE_AUTH_STATE_KEY, storageValue);
password: password,
idSpotify : spotifyToken,
name : username,
idFlad : "3030"
};
//@ts-ignore
dispatch(registerUser(credentials))
} }
const scopesArr = ['user-read-private','user-read-email','user-read-playback-state','user-read-currently-playing','user-read-recently-played','playlist-modify-public','ugc-image-upload','user-modify-playback-state']; }
const scopes = scopesArr.join(' '); }, [response]);
//work so use this for my implementation
const getAuthorizationCode = async () => {
try {
const redirectUrl = "https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d"; //this will be something like https://auth.expo.io/@your-username/your-app-slug
const result = await AuthSession.startAsync({
authUrl:
'https://accounts.spotify.com/authorize' +
'?response_type=code' +
'&client_id=' +
"1f1e34e4b6ba48b388469dba80202b10" +
(scopes ? '&scope=' + encodeURIComponent(scopes) : '') +
'&redirect_uri=' +
encodeURIComponent(redirectUrl),
})
console.log("=================grant code ==============<");
console.log(result); const dispatch = useDispatch();
console.log("=================grant code ==============<");
return result.params.code; const submitForm = () => {
} catch (err) { const credentials: CredentialsRegister = {
console.error(err) email: email,
} password: password,
idSpotify: spotifyToken,
name: username,
idFlad: "3030"
};
//@ts-ignore
dispatch(registerUser(credentials))
playSound()
}
const scopesArr = ['user-read-private', 'user-read-email', 'user-read-playback-state', 'user-read-currently-playing', 'user-read-recently-played', 'playlist-modify-public', 'ugc-image-upload', 'user-modify-playback-state'];
const scopes = scopesArr.join(' ');
//work so use this for my implementation
const getAuthorizationCode = async () => {
try {
const redirectUrl = "https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d"; //this will be something like https://auth.expo.io/@your-username/your-app-slug
const result = await AuthSession.startAsync({
authUrl:
'https://accounts.spotify.com/authorize' +
'?response_type=code' +
'&client_id=' +
"1f1e34e4b6ba48b388469dba80202b10" +
(scopes ? '&scope=' + encodeURIComponent(scopes) : '') +
'&redirect_uri=' +
encodeURIComponent(redirectUrl),
})
console.log("=================grant code ==============<");
console.log(result);
console.log("=================grant code ==============<");
return result.params.code;
} catch (err) {
console.error(err)
} }
const getAuthorizationCode2 = async () => { }
try { const getAuthorizationCode2 = async () => {
const result = await AuthSession.startAsync({ try {
authUrl:'https://flad-api-production.up.railway.app/api/spotify/exchange' const result = await AuthSession.startAsync({
}) authUrl: 'https://flad-api-production.up.railway.app/api/spotify/exchange'
console.log("=================grant code ==============<"); })
console.log("=================grant code ==============<");
console.log(result); console.log(result);
console.log("=================grant code ==============<"); console.log("=================grant code ==============<");
return result.params.code; return result.params.code;
} catch (err) { } catch (err) {
console.error(err) console.error(err)
}
} }
const getTokens2 = async () => { }
try { const getTokens2 = async () => {
const authorizationCode = await getAuthorizationCode2() //we wrote this function above try {
console.log(authorizationCode, "shhhhhhhhhhhhhheeeeeeeeeeeeeeeetttttttttttt"); const authorizationCode = await getAuthorizationCode2() //we wrote this function above
const response = await fetch('https://flad-api-production.up.railway.app/api/spotify/callback'); console.log(authorizationCode, "shhhhhhhhhhhhhheeeeeeeeeeeeeeeetttttttttttt");
const responseJson = await response.json(); const response = await fetch('https://flad-api-production.up.railway.app/api/spotify/callback');
console.log(responseJson, "okkkkkkkkkkkkkkk") ; const responseJson = await response.json();
// destructure the response and rename the properties to be in camelCase to satisfy my linter ;) console.log(responseJson, "okkkkkkkkkkkkkkk");
const { // destructure the response and rename the properties to be in camelCase to satisfy my linter ;)
access_token: accessToken, const {
refresh_token: refreshToken, access_token: accessToken,
expires_in: expiresIn, refresh_token: refreshToken,
} = responseJson; expires_in: expiresIn,
} = responseJson;
await setSpotifyToken(accessToken); await setSpotifyToken(accessToken);
console.log(spotifyToken); console.log(spotifyToken);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
}
} }
const getTokens = async () => { }
try { const getTokens = async () => {
const authorizationCode = await getAuthorizationCode() //we wrote this function above try {
console.log(authorizationCode, "shhhhhhhhhhhhhheeeeeeeeeeeeeeeetttttttttttt"); const authorizationCode = await getAuthorizationCode() //we wrote this function above
const response = await fetch('https://accounts.spotify.com/api/token', { console.log(authorizationCode, "shhhhhhhhhhhhhheeeeeeeeeeeeeeeetttttttttttt");
method: 'POST', const response = await fetch('https://accounts.spotify.com/api/token', {
headers: { method: 'POST',
Authorization: 'Basic ' + (Buffer.from('1f1e34e4b6ba48b388469dba80202b10' + ':' + '779371c6d4994a68b8dd6e84b0873c82').toString('base64')), headers: {
'Content-Type': 'application/x-www-form-urlencoded', Authorization: 'Basic ' + (Buffer.from('1f1e34e4b6ba48b388469dba80202b10' + ':' + '779371c6d4994a68b8dd6e84b0873c82').toString('base64')),
}, 'Content-Type': 'application/x-www-form-urlencoded',
body: `grant_type=authorization_code&code=${authorizationCode}&redirect_uri=https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d`, },
}); body: `grant_type=authorization_code&code=${authorizationCode}&redirect_uri=https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d`,
const responseJson = await response.json(); });
console.log(responseJson, "okkkkkkkkkkkkkkk") ; const responseJson = await response.json();
// destructure the response and rename the properties to be in camelCase to satisfy my linter ;) console.log(responseJson, "okkkkkkkkkkkkkkk");
const { // destructure the response and rename the properties to be in camelCase to satisfy my linter ;)
access_token: accessToken, const {
refresh_token: refreshToken, access_token: accessToken,
expires_in: expiresIn, refresh_token: refreshToken,
} = responseJson; expires_in: expiresIn,
await setSpotifyToken(accessToken); } = responseJson;
save(MY_SECURE_AUTH_STATE_KEY, accessToken); await setSpotifyToken(accessToken);
testService(accessToken); save(MY_SECURE_AUTH_STATE_KEY, accessToken);
console.log(spotifyToken); testService(accessToken);
} catch (err) { console.log(spotifyToken);
console.error(err); } catch (err) {
} console.error(err);
} }
}
const testService = async (token : string) =>{ const testService = async (token: string) => {
try { try {
const serviceTest = new SpotifyService(token); const serviceTest = new SpotifyService(token);
console.log("==============Test Service 1 ============"); console.log("==============Test Service 1 ============");
const respSearch = await serviceTest.searchMusic("Parapluie Tiakola"); const respSearch = await serviceTest.searchMusic("Parapluie Tiakola");
console.log("===================repoonce========================="); console.log("===================repoonce=========================");
console.log(respSearch); console.log(respSearch);
console.log("============================================"); console.log("============================================");
console.log("==============Test Service 2 ============"); console.log("==============Test Service 2 ============");
const respFull = await serviceTest.getMusicById(respSearch[0].id); const respFull = await serviceTest.getMusicById(respSearch[0].id);
console.log("===================repoonce========================="); console.log("===================repoonce=========================");
console.log(respFull); console.log(respFull);
console.log("============================================"); console.log("============================================");
console.log("==============Test Service 3 ============"); console.log("==============Test Service 3 ============");
const respSimilar = await serviceTest.getSimilarTrack(respSearch[0].id); const respSimilar = await serviceTest.getSimilarTrack(respSearch[0].id);
console.log("===================repoonce========================="); console.log("===================repoonce=========================");
console.log(respSimilar); console.log(respSimilar);
console.log("============================================"); console.log("============================================");
console.log("==============Test Service 4 ============"); console.log("==============Test Service 4 ============");
const respCurrent= await serviceTest.getUserCurrentMusic(); const respCurrent = await serviceTest.getUserCurrentMusic();
console.log("===================repoonce========================="); console.log("===================repoonce=========================");
console.log(respCurrent); console.log(respCurrent);
console.log("============================================"); console.log("============================================");
console.log("==============Test Service 5 ============"); console.log("==============Test Service 5 ============");
const respRecently= await serviceTest.getUserRecentlyPlayedMusic(); const respRecently = await serviceTest.getUserRecentlyPlayedMusic();
console.log("===================repoonce========================="); console.log("===================repoonce=========================");
console.log(respRecently); console.log(respRecently);
console.log("============================================"); console.log("============================================");
} catch (error) {
console.log("==============Test Service Error============");
console.error(error);
console.log("============================================");
} } catch (error) {
console.log("==============Test Service Error============");
console.error(error);
console.log("============================================");
} }
}
return ( return (
<DismissKeyboard> <DismissKeyboard>
<View style={styles.container}> <View style={styles.container}>
<ImageBackground source={require("../assets/images/Background.png")} resizeMode="cover" style={styles.image}> <ImageBackground source={require("../assets/images/Background.png")} resizeMode="cover" style={styles.image}>
<Text style={styles.versionText}> <Text style={styles.versionText}>
v2.0 v2.0
</Text> </Text>
<Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo}/> <Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo} />
<Text style={styles.text}>S'INSCRIRE</Text> <Text style={styles.text}>S'INSCRIRE</Text>
<View> <View>
<TextInput style={[styles.input, styles.shadow]} placeholder="Username" <TextInput style={[styles.input, styles.shadow]} placeholder="Username"
value={username} value={username}
onChangeText={setUsername}/> onChangeText={setUsername} />
<Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} /> <Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} />
</View> </View>
<View> <View>
<TextInput style={[styles.input, styles.shadow]} placeholder="Email" <TextInput style={[styles.input, styles.shadow]} placeholder="Email"
value={email} value={email}
onChangeText={setEmail}/> onChangeText={setEmail} />
<Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} /> <Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} />
</View> </View>
<View> <View>
<TextInput style={[styles.input, styles.shadow]} placeholder="Password" <TextInput style={[styles.input, styles.shadow]} placeholder="Password"
value={password} secureTextEntry={true} value={password} secureTextEntry={true}
onChangeText={setPassword}/> onChangeText={setPassword} />
<Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} /> <Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} />
</View> </View>
<TouchableOpacity onPress={async() => { <TouchableOpacity onPress={async () => {
await getTokens(); await getTokens();
}} style={[styles.buttonSpotify, styles.shadow]}> }} style={[styles.buttonSpotify, styles.shadow]}>
<Text style={styles.textIntoButton}>Lier compte</Text> <Text style={styles.textIntoButton}>Lier compte</Text>
<Image source={require("../assets/icons/icons/Spotify.png")} style={{width: normalize(35), height: normalize(35)}}/> <Image source={require("../assets/icons/icons/Spotify.png")} style={{ width: normalize(35), height: normalize(35) }} />
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={[styles.button, styles.shadow]} onPress={() => submitForm()}> <TouchableOpacity style={[styles.button, styles.shadow]} onPress={() => submitForm()}>
<Image source={require("../assets/icons/icons/next.png")} style={styles.buttonImage}/> <Image source={require("../assets/icons/icons/next.png")} style={styles.buttonImage} />
</TouchableOpacity> </TouchableOpacity>
<View style={styles.connectionText}> <View style={styles.connectionText}>
<Text style={{fontSize: normalize(18), color: 'white'}}>Tu as déjà un compte? </Text> <Text style={{ fontSize: normalize(18), color: 'white' }}>Tu as déjà un compte? </Text>
<TouchableOpacity <TouchableOpacity
// @ts-ignore // @ts-ignore
onPress={() => navigation.navigate('Login')} onPress={() => navigation.navigate('Login')}
> >
<Text style={{fontSize: normalize(18), color: '#406DE1', textDecorationLine: 'underline'}}>Se connecter</Text> <Text style={{ fontSize: normalize(18), color: '#406DE1', textDecorationLine: 'underline' }}>Se connecter</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</ImageBackground> </ImageBackground>
</View> </View>
</DismissKeyboard> </DismissKeyboard>
) )
} }
const styles = StyleSheet.create ({ const styles = StyleSheet.create({
container: { container: {
flex: 1 flex: 1
},
image: {
flex: 1,
justifyContent: 'center',
},
imageLogo: {
width: normalize(324),
height: normalize(162),
alignSelf: 'center',
marginBottom: normalize(58),
marginTop: -20
},
button: {
marginTop: '10%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'center',
backgroundColor: 'white',
width: normalize(100),
height: normalize(100),
borderRadius: 21
},
buttonImage: {
width: normalize(46),
height: normalize(46),
},
versionText: {
position: 'absolute',
top: 40,
right: 20,
color: 'gray',
fontWeight: 'bold',
fontSize: normalize(17)
},
text: {
fontWeight: 'bold',
fontSize: normalize(29),
alignSelf: 'center',
color: 'white',
marginBottom: 15
},
textIntoButton: {
fontWeight: 'bold',
fontSize: normalize(17),
color: 'white',
marginRight: 10
},
shadow: {
shadowColor: '#000',
shadowOffset: {
width: 2,
height: 3,
}, },
image: { shadowOpacity: 0.50,
flex: 1, shadowRadius: 3.84,
justifyContent: 'center', },
}, input: {
imageLogo: { width: normalize(350),
width: normalize(324), height: normalize(50),
height: normalize(162), borderRadius: 30,
alignSelf: 'center', color: 'black',
marginBottom: normalize(58), backgroundColor: 'white',
marginTop: -20 alignSelf: 'center',
}, marginBottom: 20,
button: { paddingLeft: 50,
marginTop: '10%', paddingRight: 20
flexDirection: 'row', },
alignItems: 'center', iconUser: {
justifyContent: 'center', position: 'absolute',
alignSelf: 'center', width: 20,
backgroundColor: 'white', height: 20,
width: normalize(100), left: normalize(80),
height: normalize(100), bottom: '50%'
borderRadius: 21 },
}, iconLock: {
buttonImage: { position: 'absolute',
width: normalize(46), width: 20,
height: normalize(46), height: 20,
}, left: normalize(80),
versionText: { bottom: '50%'
position: 'absolute', },
top: 40, connectionText: {
right: 20, flexDirection: 'row',
color: 'gray', alignSelf: 'center',
fontWeight: 'bold', bottom: normalize(-98)
fontSize: normalize(17) },
}, buttonSpotify: {
text: { width: normalize(350),
fontWeight: 'bold', height: normalize(50),
fontSize: normalize(29), backgroundColor: '#24CF5F',
alignSelf: 'center', justifyContent: 'center',
color: 'white', alignItems: 'center',
marginBottom: 15 alignSelf: 'center',
}, borderRadius: 30,
textIntoButton: { flexDirection: 'row'
fontWeight: 'bold', }
fontSize: normalize(17),
color: 'white',
marginRight: 10
},
shadow: {
shadowColor: '#000',
shadowOffset: {
width: 2,
height: 3,
},
shadowOpacity: 0.50,
shadowRadius: 3.84,
},
input: {
width: normalize(350),
height: normalize(50),
borderRadius: 30,
color: 'black',
backgroundColor: 'white',
alignSelf: 'center',
marginBottom: 20,
paddingLeft: 50,
paddingRight: 20
},
iconUser : {
position: 'absolute',
width: 20,
height: 20,
left: normalize(80),
bottom: '50%'
},
iconLock : {
position: 'absolute',
width: 20,
height: 20,
left: normalize(80),
bottom: '50%'
},
connectionText: {
flexDirection: 'row',
alignSelf: 'center',
bottom: normalize(-98)
},
buttonSpotify: {
width: normalize(350),
height: normalize(50),
backgroundColor: '#24CF5F',
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'center',
borderRadius: 30,
flexDirection: 'row'
}
}) })

@ -1,11 +1,17 @@
import React, { useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { View, StyleSheet, Text, Image, TouchableWithoutFeedback, Keyboard, TouchableOpacity, SafeAreaView } from 'react-native'; import { View, StyleSheet, Text, Image, TouchableWithoutFeedback, Keyboard, TouchableOpacity, SafeAreaView } from 'react-native';
import { Svg, Path } from 'react-native-svg'; import { Svg, Path } from 'react-native-svg';
import {useNavigation} from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { useDispatch } from 'react-redux';
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import { ScrollView, Switch, TextInput } from 'react-native-gesture-handler'; import { ScrollView, Switch, TextInput } from 'react-native-gesture-handler';
import CardMusic from '../components/CardMusic'; import CardMusic from '../components/CardMusic';
import { ChangeMode, DeleteToken } from '../redux/thunk/authThunk';
import { useSelector } from 'react-redux';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
import SpotifyService from '../services/spotify/spotify.service';
import { getCurrentUserMusic } from '../redux/thunk/spotThunk';
// @ts-ignore // @ts-ignore
const DismissKeyboard = ({ children }) => ( const DismissKeyboard = ({ children }) => (
@ -16,31 +22,222 @@ const DismissKeyboard = ({ children }) => (
export default function Setting() { export default function Setting() {
const textInputRef = useRef(null); const textInputRef = useRef(null);
const dispatch = useDispatch();
const navigation = useNavigation(); const navigation = useNavigation();
const handleSvgPress = () => { const handleSvgPress = () => {
//@ts-ignore //@ts-ignore
textInputRef.current?.focus(); textInputRef.current?.focus();
}; };
//Dark Mode const currentMusic = useSelector(state => state.appReducer.userCurrentMusic);
const[isCheckedDarkMode, setIsCheckedDarkMode] = useState(false);
const toggleDarkMode = //Dark Mode
() => setIsCheckedDarkMode(value => !value); const isDark = useSelector(state => state.userReducer.dark);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark;
const ChangeDarkMode = () => {
dispatch(ChangeMode())
}
//Notification //Notification
const[isCheckedNotif, setIsCheckedNotif] = useState(false); const [isCheckedNotif, setIsCheckedNotif] = useState(false);
const toggleNotif = const toggleNotif =
() => setIsCheckedNotif(value => !value); () => setIsCheckedNotif(value => !value);
//Deconnection
const Deconnection = () => {
//@ts-ignore
dispatch(DeleteToken())
}
//Localisation //Localisation
const[isCheckedLocalisation, setIsCheckedLocalisation] = useState(false); const [isCheckedLocalisation, setIsCheckedLocalisation] = useState(false);
const toggleLocalisation = const toggleLocalisation =
() => setIsCheckedLocalisation(value => !value); () => setIsCheckedLocalisation(value => !value);
//Style
const styles = StyleSheet.create({
mainSafeArea: {
flex: 1,
backgroundColor: style.body,
},
container: {
marginTop: 30,
marginHorizontal: normalize(25),
paddingBottom: normalize(400),
flex: 1,
backgroundColor: style.body,
},
title: {
fontSize: normalize(30),
fontWeight: 'bold',
color: style.Text,
alignItems: 'center',
},
search: {
paddingVertical: 9,
backgroundColor: style.Card,
borderRadius: 13,
flexDirection: 'row',
marginTop: 9,
marginBottom: 22
},
inputSearch: {
placeholderTextColor: 'red',
color: 'white',
width: normalize(350),
},
profil: {
paddingVertical: 9,
backgroundColor: style.Card,
borderRadius: 13,
flexDirection: 'row',
alignItems: 'center',
marginBottom: normalize(45)
},
imageProfil: {
marginLeft: 15,
marginRight: 7,
width: 50,
height: 50
},
NameProfil: {
fontWeight: 'bold',
color: style.Text,
fontSize: normalize(22)
},
description: {
color: style.Text,
fontSize: normalize(15)
},
profilContainer: {
flex: 1,
marginLeft: 9,
alignItems: 'flex-start',
justifyContent: 'center',
},
buttonSetting: {
width: normalize(17),
height: normalize(17),
marginRight: 22
},
body: {
paddingTop: normalize(10),
backgroundColor: style.Card,
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45),
paddingLeft: normalize(10),
},
view: {
backgroundColor: '#fe9500',
padding: 5,
borderRadius: 10,
marginLeft: 15,
marginBottom: normalize(11)
},
Option: {
flexDirection: 'row',
alignItems: 'center',
},
secondOption: {
marginTop: normalize(11),
flexDirection: 'row',
alignItems: 'center',
},
textOption: {
fontSize: normalize(18),
color: style.Text,
fontWeight: 'bold',
marginBottom: normalize(8)
},
firstOptionView: {
flex: 1,
marginLeft: 15,
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: style.Line
},
deconnectedOption: {
paddingVertical: 9,
paddingLeft: 5,
backgroundColor: style.Card,
borderRadius: 13,
flexDirection: 'row',
alignItems: 'center',
},
buttonDeconectedOption: {
backgroundColor: '#DF0404',
padding: 5,
borderRadius: 10,
marginLeft: 15
},
textDeconnectionOption: {
fontSize: normalize(18),
color: '#F80404',
fontWeight: 'bold',
marginLeft: 12
},
notification: {
backgroundColor: '#fe3c30',
padding: 5,
borderRadius: 10,
marginLeft: 15,
marginBottom: normalize(11)
},
secondOptionView: {
flex: 1,
marginLeft: 15,
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: style.Line
},
lastOptionView: {
flex: 1,
marginLeft: 15,
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center'
},
localisation: {
backgroundColor: '#0835A7',
padding: 5,
borderRadius: 10,
marginLeft: 15,
marginBottom: normalize(11)
},
lastOption: {
marginTop: normalize(11),
flexDirection: 'row',
alignItems: 'center',
},
musicActually: {
paddingTop: normalize(17),
backgroundColor: style.Card,
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45)
},
titleMusic: {
flexDirection: 'row',
marginBottom: 5
},
mascot: {
width: normalize(90),
height: normalize(90),
position: 'absolute',
right: normalize(0),
top: normalize(10)
}
})
return ( return (
<DismissKeyboard> <DismissKeyboard>
<SafeAreaView style={styles.mainSafeArea}> <SafeAreaView style={styles.mainSafeArea}>
@ -49,24 +246,24 @@ export default function Setting() {
<Text style={styles.title}>Réglages</Text> <Text style={styles.title}>Réglages</Text>
<View style={styles.search}> <View style={styles.search}>
<TouchableOpacity onPress={handleSvgPress}> <TouchableOpacity onPress={handleSvgPress}>
<Svg width="21" height="21" style={{marginHorizontal: normalize(10)}} viewBox="0 0 21 21" fill="none"> <Svg width="21" height="21" style={{ marginHorizontal: normalize(10) }} viewBox="0 0 21 21" fill="none">
<Path d="M13.5625 12.25H12.8713L12.6263 12.0137C13.4838 11.0162 14 9.72125 14 8.3125C14 5.17125 11.4537 2.625 8.3125 2.625C5.17125 2.625 2.625 5.17125 2.625 8.3125C2.625 11.4537 5.17125 14 8.3125 14C9.72125 14 11.0162 13.4838 12.0137 12.6263L12.25 12.8713V13.5625L16.625 17.9287L17.9287 16.625L13.5625 12.25ZM8.3125 12.25C6.13375 12.25 4.375 10.4913 4.375 8.3125C4.375 6.13375 6.13375 4.375 8.3125 4.375C10.4913 4.375 12.25 6.13375 12.25 8.3125C12.25 10.4913 10.4913 12.25 8.3125 12.25Z" fill="#828288"/> <Path d="M13.5625 12.25H12.8713L12.6263 12.0137C13.4838 11.0162 14 9.72125 14 8.3125C14 5.17125 11.4537 2.625 8.3125 2.625C5.17125 2.625 2.625 5.17125 2.625 8.3125C2.625 11.4537 5.17125 14 8.3125 14C9.72125 14 11.0162 13.4838 12.0137 12.6263L12.25 12.8713V13.5625L16.625 17.9287L17.9287 16.625L13.5625 12.25ZM8.3125 12.25C6.13375 12.25 4.375 10.4913 4.375 8.3125C4.375 6.13375 6.13375 4.375 8.3125 4.375C10.4913 4.375 12.25 6.13375 12.25 8.3125C12.25 10.4913 10.4913 12.25 8.3125 12.25Z" fill="#828288" />
</Svg> </Svg>
</TouchableOpacity> </TouchableOpacity>
<TextInput placeholderTextColor="#828288" ref={textInputRef} placeholder='Recherche' style={styles.inputSearch}></TextInput> <TextInput placeholderTextColor="#828288" ref={textInputRef} placeholder='Recherche' style={styles.inputSearch}></TextInput>
<Svg width="19" height="19" viewBox="0 0 19 19" fill="none"> <Svg width="19" height="19" viewBox="0 0 19 19" fill="none">
<Path d="M13.6563 8.3125V10.0938C13.6563 11.1961 13.2184 12.2532 12.4389 13.0327C11.6595 13.8121 10.6023 14.25 9.5 14.25C8.39769 14.25 7.34054 13.8121 6.56109 13.0327C5.78164 12.2532 5.34375 11.1961 5.34375 10.0938V8.3125H4.15625V10.0938C4.15687 11.4078 4.64161 12.6755 5.51785 13.6547C6.39409 14.6339 7.60038 15.2559 8.90625 15.4019V16.625H6.53125V17.8125H12.4688V16.625H10.0938V15.4019C11.3996 15.2559 12.6059 14.6339 13.4822 13.6547C14.3584 12.6755 14.8431 11.4078 14.8438 10.0938V8.3125H13.6563Z" fill="#828288"/> <Path d="M13.6563 8.3125V10.0938C13.6563 11.1961 13.2184 12.2532 12.4389 13.0327C11.6595 13.8121 10.6023 14.25 9.5 14.25C8.39769 14.25 7.34054 13.8121 6.56109 13.0327C5.78164 12.2532 5.34375 11.1961 5.34375 10.0938V8.3125H4.15625V10.0938C4.15687 11.4078 4.64161 12.6755 5.51785 13.6547C6.39409 14.6339 7.60038 15.2559 8.90625 15.4019V16.625H6.53125V17.8125H12.4688V16.625H10.0938V15.4019C11.3996 15.2559 12.6059 14.6339 13.4822 13.6547C14.3584 12.6755 14.8431 11.4078 14.8438 10.0938V8.3125H13.6563Z" fill="#828288" />
<Path d="M9.5 13.0625C10.2874 13.0625 11.0425 12.7497 11.5992 12.193C12.156 11.6362 12.4688 10.8811 12.4688 10.0938V4.15625C12.4688 3.36889 12.156 2.61378 11.5992 2.05703C11.0425 1.50028 10.2874 1.1875 9.5 1.1875C8.71264 1.1875 7.95753 1.50028 7.40078 2.05703C6.84403 2.61378 6.53125 3.36889 6.53125 4.15625V10.0938C6.53125 10.8811 6.84403 11.6362 7.40078 12.193C7.95753 12.7497 8.71264 13.0625 9.5 13.0625Z" fill="#828288"/> <Path d="M9.5 13.0625C10.2874 13.0625 11.0425 12.7497 11.5992 12.193C12.156 11.6362 12.4688 10.8811 12.4688 10.0938V4.15625C12.4688 3.36889 12.156 2.61378 11.5992 2.05703C11.0425 1.50028 10.2874 1.1875 9.5 1.1875C8.71264 1.1875 7.95753 1.50028 7.40078 2.05703C6.84403 2.61378 6.53125 3.36889 6.53125 4.15625V10.0938C6.53125 10.8811 6.84403 11.6362 7.40078 12.193C7.95753 12.7497 8.71264 13.0625 9.5 13.0625Z" fill="#828288" />
</Svg> </Svg>
</View> </View>
<TouchableOpacity onPress={() => navigation.navigate('SettingProfil')}> <TouchableOpacity onPress={() => navigation.navigate('SettingProfil')}>
<View style={styles.profil}> <View style={styles.profil}>
<Image source={require('../assets/icons/icons/IconProfil.png')} style={styles.imageProfil}/> <Image source={require('../assets/icons/icons/IconProfil.png')} style={styles.imageProfil} />
<View style={styles.profilContainer}> <View style={styles.profilContainer}>
<Text style={styles.NameProfil}>Emre KARTAL</Text> <Text style={styles.NameProfil}>Emre KARTAL</Text>
<Text style={styles.description}>id. Spotify, mail et mot de passe</Text> <Text style={styles.description}>id. Spotify, mail et mot de passe</Text>
</View> </View>
<Image style={styles.buttonSetting} source={require('../assets/icons/icons/buttonProfil.png')}/> <Image style={styles.buttonSetting} source={require('../assets/icons/icons/buttonProfil.png')} />
</View> </View>
</TouchableOpacity> </TouchableOpacity>
@ -74,66 +271,66 @@ export default function Setting() {
<View style={styles.Option}> <View style={styles.Option}>
<View style={styles.view}> <View style={styles.view}>
<Svg width="23" height="22" viewBox="0 0 23 18" fill="none"> <Svg width="23" height="22" viewBox="0 0 23 18" fill="none">
<Path d="M1 8.63636C1 8.63636 4.81818 1 11.5 1C18.1818 1 22 8.63636 22 8.63636" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M1 8.63636C1 8.63636 4.81818 1 11.5 1C18.1818 1 22 8.63636 22 8.63636" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<Path d="M1 8.63635C1 8.63635 4.81818 16.2727 11.5 16.2727C18.1818 16.2727 22 8.63635 22 8.63635" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M1 8.63635C1 8.63635 4.81818 16.2727 11.5 16.2727C18.1818 16.2727 22 8.63635 22 8.63635" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<Path d="M11.4997 11.5C13.0813 11.5 14.3634 10.2179 14.3634 8.63634C14.3634 7.0548 13.0813 5.77271 11.4997 5.77271C9.9182 5.77271 8.63611 7.0548 8.63611 8.63634C8.63611 10.2179 9.9182 11.5 11.4997 11.5Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M11.4997 11.5C13.0813 11.5 14.3634 10.2179 14.3634 8.63634C14.3634 7.0548 13.0813 5.77271 11.4997 5.77271C9.9182 5.77271 8.63611 7.0548 8.63611 8.63634C8.63611 10.2179 9.9182 11.5 11.4997 11.5Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</Svg> </Svg>
</View> </View>
<View style={styles.firstOptionView}> <View style={styles.firstOptionView}>
<Text style={styles.textOption}>Dark Mode</Text> <Text style={styles.textOption}>Dark Mode</Text>
<Switch style={{marginBottom: normalize(10), marginRight: 20}} value={isCheckedDarkMode} onValueChange={toggleDarkMode}/> <Switch style={{ marginBottom: normalize(10), marginRight: 20 }} value={isDark} onValueChange={ChangeDarkMode} />
</View> </View>
</View> </View>
<View style={styles.secondOption}> <View style={styles.secondOption}>
<View style={styles.notification}> <View style={styles.notification}>
<Svg width="23" height="22" viewBox="0 0 1242 1242"> <Svg width="23" height="22" viewBox="0 0 1242 1242">
<Path d="M620.553 1181.81C642.27 1181.31 663.11 1173.14 679.388 1158.76C695.665 1144.37 706.331 1124.69 709.498 1103.2H528.159C531.416 1125.28 542.581 1145.42 559.577 1159.88C576.572 1174.34 598.241 1182.13 620.553 1181.81Z" fill="white"/> <Path d="M620.553 1181.81C642.27 1181.31 663.11 1173.14 679.388 1158.76C695.665 1144.37 706.331 1124.69 709.498 1103.2H528.159C531.416 1125.28 542.581 1145.42 559.577 1159.88C576.572 1174.34 598.241 1182.13 620.553 1181.81Z" fill="white" />
<Path d="M1132.51 969.785L1120.79 959.443C1087.53 929.815 1058.43 895.838 1034.25 858.43C1007.85 806.806 992.03 750.428 987.712 692.605V522.298C987.572 501.611 985.727 480.971 982.196 460.587C923.799 448.585 871.344 416.77 833.712 370.531C796.079 324.292 775.582 266.468 775.69 206.851C775.69 199.611 775.69 192.371 775.69 185.131C739.695 167.417 701.023 155.769 661.233 150.656V107.217C661.233 95.011 656.384 83.3046 647.752 74.6733C639.121 66.0421 627.415 61.1931 615.208 61.1931C603.002 61.1931 591.295 66.0421 582.664 74.6733C574.033 83.3046 569.184 95.011 569.184 107.217V152.38C480.09 164.948 398.552 209.324 339.622 277.315C280.692 345.307 248.349 432.323 248.565 522.298V692.605C244.247 750.428 228.424 806.806 202.024 858.43C178.266 895.745 149.628 929.716 116.87 959.443L105.149 969.785V1067.01H1132.51V969.785Z" fill="white"/> <Path d="M1132.51 969.785L1120.79 959.443C1087.53 929.815 1058.43 895.838 1034.25 858.43C1007.85 806.806 992.03 750.428 987.712 692.605V522.298C987.572 501.611 985.727 480.971 982.196 460.587C923.799 448.585 871.344 416.77 833.712 370.531C796.079 324.292 775.582 266.468 775.69 206.851C775.69 199.611 775.69 192.371 775.69 185.131C739.695 167.417 701.023 155.769 661.233 150.656V107.217C661.233 95.011 656.384 83.3046 647.752 74.6733C639.121 66.0421 627.415 61.1931 615.208 61.1931C603.002 61.1931 591.295 66.0421 582.664 74.6733C574.033 83.3046 569.184 95.011 569.184 107.217V152.38C480.09 164.948 398.552 209.324 339.622 277.315C280.692 345.307 248.349 432.323 248.565 522.298V692.605C244.247 750.428 228.424 806.806 202.024 858.43C178.266 895.745 149.628 929.716 116.87 959.443L105.149 969.785V1067.01H1132.51V969.785Z" fill="white" />
<Path d="M1034.25 379.226C1129.45 379.226 1206.63 302.051 1206.63 206.851C1206.63 111.65 1129.45 34.4751 1034.25 34.4751C939.053 34.4751 861.878 111.65 861.878 206.851C861.878 302.051 939.053 379.226 1034.25 379.226Z" fill="white"/> <Path d="M1034.25 379.226C1129.45 379.226 1206.63 302.051 1206.63 206.851C1206.63 111.65 1129.45 34.4751 1034.25 34.4751C939.053 34.4751 861.878 111.65 861.878 206.851C861.878 302.051 939.053 379.226 1034.25 379.226Z" fill="white" />
</Svg> </Svg>
</View> </View>
<View style={styles.secondOptionView}> <View style={styles.secondOptionView}>
<Text style={styles.textOption}>Notification</Text> <Text style={styles.textOption}>Notification</Text>
<Switch style={{marginBottom: normalize(10), marginRight: 20}} value={isCheckedNotif} onValueChange={toggleNotif}/> <Switch style={{ marginBottom: normalize(10), marginRight: 20 }} value={isCheckedNotif} onValueChange={toggleNotif} />
</View> </View>
</View> </View>
<View style={styles.lastOption}> <View style={styles.lastOption}>
<View style={styles.localisation}> <View style={styles.localisation}>
<Svg width="24" height="23" viewBox="0 0 472 420" fill="none"> <Svg width="24" height="23" viewBox="0 0 472 420" fill="none">
<Path d="M235.735 0C178.774 0 132.601 46.1729 132.601 103.134C132.601 149.184 200.006 233.115 225.83 263.581C231.061 269.752 240.416 269.752 245.639 263.581C271.463 233.115 338.868 149.184 338.868 103.134C338.868 46.1729 292.696 0 235.735 0ZM235.735 137.512C216.745 137.512 201.357 122.124 201.357 103.134C201.357 84.1441 216.745 68.7559 235.735 68.7559C254.724 68.7559 270.112 84.1441 270.112 103.134C270.112 122.124 254.724 137.512 235.735 137.512ZM16.4687 176.76C11.6081 178.704 7.44144 182.06 4.50605 186.394C1.57065 190.729 0.00116411 195.843 0 201.078L0 405.971C0 415.237 9.35571 421.572 17.9584 418.134L130.964 366.698V175.917C123.728 162.837 117.81 150.101 113.57 137.921L16.4687 176.76ZM235.735 294.398C224.218 294.398 213.323 289.34 205.85 280.516C189.758 261.526 172.643 239.901 157.156 217.719V366.69L314.313 419.075V217.727C298.826 239.901 281.719 261.534 265.619 280.524C258.146 289.34 247.251 294.398 235.735 294.398ZM453.511 131.913L340.505 183.349V419.084L455 373.287C459.862 371.344 464.029 367.989 466.964 363.654C469.9 359.319 471.469 354.204 471.469 348.969V144.076C471.469 134.811 462.113 128.475 453.511 131.913Z" fill="white"/> <Path d="M235.735 0C178.774 0 132.601 46.1729 132.601 103.134C132.601 149.184 200.006 233.115 225.83 263.581C231.061 269.752 240.416 269.752 245.639 263.581C271.463 233.115 338.868 149.184 338.868 103.134C338.868 46.1729 292.696 0 235.735 0ZM235.735 137.512C216.745 137.512 201.357 122.124 201.357 103.134C201.357 84.1441 216.745 68.7559 235.735 68.7559C254.724 68.7559 270.112 84.1441 270.112 103.134C270.112 122.124 254.724 137.512 235.735 137.512ZM16.4687 176.76C11.6081 178.704 7.44144 182.06 4.50605 186.394C1.57065 190.729 0.00116411 195.843 0 201.078L0 405.971C0 415.237 9.35571 421.572 17.9584 418.134L130.964 366.698V175.917C123.728 162.837 117.81 150.101 113.57 137.921L16.4687 176.76ZM235.735 294.398C224.218 294.398 213.323 289.34 205.85 280.516C189.758 261.526 172.643 239.901 157.156 217.719V366.69L314.313 419.075V217.727C298.826 239.901 281.719 261.534 265.619 280.524C258.146 289.34 247.251 294.398 235.735 294.398ZM453.511 131.913L340.505 183.349V419.084L455 373.287C459.862 371.344 464.029 367.989 466.964 363.654C469.9 359.319 471.469 354.204 471.469 348.969V144.076C471.469 134.811 462.113 128.475 453.511 131.913Z" fill="white" />
</Svg> </Svg>
</View> </View>
<View style={styles.lastOptionView}> <View style={styles.lastOptionView}>
<Text style={styles.textOption}>Localisation</Text> <Text style={styles.textOption}>Localisation</Text>
<Switch style={{marginBottom: normalize(10), marginRight: 20}} value={isCheckedLocalisation} onValueChange={toggleLocalisation}/> <Switch style={{ marginBottom: normalize(10), marginRight: 20 }} value={isCheckedLocalisation} onValueChange={toggleLocalisation} />
</View> </View>
</View> </View>
</View> </View>
<View style={styles.titleMusic}> <View style={styles.titleMusic}>
<Svg width="32" height="23" viewBox="0 0 28 21"> <Svg width="32" height="23" viewBox="0 0 28 21">
<Path d="M5.84463 0.36924C5.37582 -0.0995746 4.59968 -0.13966 4.10723 0.35111C1.57056 2.8792 0 6.37809 0 10.243C0 14.2583 1.69511 17.8783 4.40753 20.4254C4.90303 20.8906 5.65829 20.8413 6.11707 20.3826C6.65205 19.8476 6.58697 18.9969 6.07118 18.5038C3.89425 16.4228 2.53916 13.4914 2.53916 10.243C2.53916 7.11727 3.79368 4.28541 5.82764 2.22202C6.3189 1.72366 6.36867 0.893273 5.84463 0.36924Z" fill="white"/> <Path d="M5.84463 0.36924C5.37582 -0.0995746 4.59968 -0.13966 4.10723 0.35111C1.57056 2.8792 0 6.37809 0 10.243C0 14.2583 1.69511 17.8783 4.40753 20.4254C4.90303 20.8906 5.65829 20.8413 6.11707 20.3826C6.65205 19.8476 6.58697 18.9969 6.07118 18.5038C3.89425 16.4228 2.53916 13.4914 2.53916 10.243C2.53916 7.11727 3.79368 4.28541 5.82764 2.22202C6.3189 1.72366 6.36867 0.893273 5.84463 0.36924Z" fill={style.Text} />
<Path d="M8.82679 3.35124C8.37113 2.89557 7.6097 2.83865 7.11937 3.32383C5.33696 5.08757 4.23193 7.53654 4.23193 10.2428C4.23193 13.1062 5.46885 15.6811 7.43617 17.4616C7.92997 17.9085 8.65988 17.8396 9.10066 17.3988C9.65615 16.8434 9.55157 15.969 9.03099 15.4783C7.63907 14.1659 6.7711 12.306 6.7711 10.2428C6.7711 8.29502 7.5446 6.52876 8.80209 5.23299C9.28672 4.73363 9.3654 3.88984 8.82679 3.35124Z" fill="white"/> <Path d="M8.82679 3.35124C8.37113 2.89557 7.6097 2.83865 7.11937 3.32383C5.33696 5.08757 4.23193 7.53654 4.23193 10.2428C4.23193 13.1062 5.46885 15.6811 7.43617 17.4616C7.92997 17.9085 8.65988 17.8396 9.10066 17.3988C9.65615 16.8434 9.55157 15.969 9.03099 15.4783C7.63907 14.1659 6.7711 12.306 6.7711 10.2428C6.7711 8.29502 7.5446 6.52876 8.80209 5.23299C9.28672 4.73363 9.3654 3.88984 8.82679 3.35124Z" fill={style.Text} />
<Path d="M18.2575 3.35124C18.7132 2.89557 19.4746 2.83865 19.965 3.32383C21.7473 5.08757 22.8524 7.53654 22.8524 10.2428C22.8524 13.1062 21.6154 15.6811 19.6481 17.4616C19.1543 17.9085 18.4244 17.8396 17.9836 17.3988C17.4282 16.8434 17.5326 15.969 18.0533 15.4783C19.4453 14.1659 20.3132 12.306 20.3132 10.2428C20.3132 8.29502 19.5398 6.52876 18.2822 5.23299C17.7976 4.73363 17.7188 3.88984 18.2575 3.35124Z" fill="white"/> <Path d="M18.2575 3.35124C18.7132 2.89557 19.4746 2.83865 19.965 3.32383C21.7473 5.08757 22.8524 7.53654 22.8524 10.2428C22.8524 13.1062 21.6154 15.6811 19.6481 17.4616C19.1543 17.9085 18.4244 17.8396 17.9836 17.3988C17.4282 16.8434 17.5326 15.969 18.0533 15.4783C19.4453 14.1659 20.3132 12.306 20.3132 10.2428C20.3132 8.29502 19.5398 6.52876 18.2822 5.23299C17.7976 4.73363 17.7188 3.88984 18.2575 3.35124Z" fill={style.Text} />
<Path d="M21.2398 0.36924C21.7087 -0.0995746 22.4849 -0.13966 22.9773 0.35111C25.5139 2.8792 27.0845 6.37809 27.0845 10.243C27.0845 14.2583 25.3893 17.8783 22.677 20.4254C22.1815 20.8906 21.4262 20.8413 20.9675 20.3826C20.4324 19.8476 20.4975 18.9969 21.0133 18.5038C23.1902 16.4228 24.5453 13.4914 24.5453 10.243C24.5453 7.11727 23.2908 4.28541 21.2567 2.22202C20.7655 1.72366 20.7157 0.893273 21.2398 0.36924Z" fill="white"/> <Path d="M21.2398 0.36924C21.7087 -0.0995746 22.4849 -0.13966 22.9773 0.35111C25.5139 2.8792 27.0845 6.37809 27.0845 10.243C27.0845 14.2583 25.3893 17.8783 22.677 20.4254C22.1815 20.8906 21.4262 20.8413 20.9675 20.3826C20.4324 19.8476 20.4975 18.9969 21.0133 18.5038C23.1902 16.4228 24.5453 13.4914 24.5453 10.243C24.5453 7.11727 23.2908 4.28541 21.2567 2.22202C20.7655 1.72366 20.7157 0.893273 21.2398 0.36924Z" fill={style.Text} />
<Path d="M13.5422 7.70361C12.1399 7.70361 11.0031 8.84043 11.0031 10.2428C11.0031 11.6451 12.1399 12.7819 13.5422 12.7819C14.9445 12.7819 16.0814 11.6451 16.0814 10.2428C16.0814 8.84043 14.9445 7.70361 13.5422 7.70361Z" fill="white"/> <Path d="M13.5422 7.70361C12.1399 7.70361 11.0031 8.84043 11.0031 10.2428C11.0031 11.6451 12.1399 12.7819 13.5422 12.7819C14.9445 12.7819 16.0814 11.6451 16.0814 10.2428C16.0814 8.84043 14.9445 7.70361 13.5422 7.70361Z" fill={style.Text} />
</Svg> </Svg>
<Text style={[styles.textOption, {marginLeft: 10}]}>En cours découte...</Text> <Text style={[styles.textOption, { marginLeft: 10 }]}>En cours découte...</Text>
</View> </View>
<View style={styles.musicActually}> <View style={styles.musicActually}>
<CardMusic image="https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png" title='Bambina' description="PNL"/> <CardMusic image={currentMusic.image} title={currentMusic.title} description="PNL" />
<Image source={require("../assets/images/FladyShadow.png")} style={styles.mascot}/> <Image source={require("../assets/images/FladyShadow.png")} style={styles.mascot} />
</View> </View>
<View style={styles.deconnectedOption}> <View style={styles.deconnectedOption}>
<View style={styles.buttonDeconectedOption}> <View style={styles.buttonDeconectedOption}>
<Svg width="23" height="24" viewBox="0 0 23 24"> <Svg width="23" height="24" viewBox="0 0 23 24">
<Path d="M4.36916 23.102C4.03419 23.102 3.71379 22.9855 3.43707 22.7671L0.5243 20.3349C0.360787 20.2004 0.229004 20.0315 0.138369 19.8401C0.0477338 19.6488 0.000485206 19.4398 0 19.2281L0 3.87773C0 3.44081 0.18933 3.03302 0.5243 2.75631L3.43707 0.324142C3.87399 -0.0253914 4.47111 -0.0982107 4.98085 0.134811C5.23365 0.251805 5.44759 0.438845 5.59731 0.673748C5.74703 0.908652 5.82624 1.18157 5.82555 1.46012V21.6602C5.82624 21.9388 5.74703 22.2117 5.59731 22.4466C5.44759 22.6815 5.23365 22.8685 4.98085 22.9855C4.79152 23.0583 4.57306 23.102 4.36916 23.102ZM17.4767 15.9221V7.18373C17.4767 6.52835 18.2631 6.20795 18.7146 6.67399L22.574 10.5334C23.142 11.1014 23.142 12.0189 22.574 12.5869L18.7146 16.4463C18.6119 16.547 18.4817 16.615 18.3405 16.6418C18.1992 16.6686 18.0532 16.6529 17.9208 16.5969C17.7885 16.5408 17.6756 16.4468 17.5966 16.3267C17.5175 16.2066 17.4758 16.0658 17.4767 15.9221Z" fill="white"/> <Path d="M4.36916 23.102C4.03419 23.102 3.71379 22.9855 3.43707 22.7671L0.5243 20.3349C0.360787 20.2004 0.229004 20.0315 0.138369 19.8401C0.0477338 19.6488 0.000485206 19.4398 0 19.2281L0 3.87773C0 3.44081 0.18933 3.03302 0.5243 2.75631L3.43707 0.324142C3.87399 -0.0253914 4.47111 -0.0982107 4.98085 0.134811C5.23365 0.251805 5.44759 0.438845 5.59731 0.673748C5.74703 0.908652 5.82624 1.18157 5.82555 1.46012V21.6602C5.82624 21.9388 5.74703 22.2117 5.59731 22.4466C5.44759 22.6815 5.23365 22.8685 4.98085 22.9855C4.79152 23.0583 4.57306 23.102 4.36916 23.102ZM17.4767 15.9221V7.18373C17.4767 6.52835 18.2631 6.20795 18.7146 6.67399L22.574 10.5334C23.142 11.1014 23.142 12.0189 22.574 12.5869L18.7146 16.4463C18.6119 16.547 18.4817 16.615 18.3405 16.6418C18.1992 16.6686 18.0532 16.6529 17.9208 16.5969C17.7885 16.5408 17.6756 16.4468 17.5966 16.3267C17.5175 16.2066 17.4758 16.0658 17.4767 15.9221Z" fill="white" />
<Path d="M5.09735 3.54297H13.1075C13.5153 3.54297 13.8357 3.86337 13.8357 4.27116V7.91213M5.09735 19.5632H13.1075C13.5153 19.5632 13.8357 19.2428 13.8357 18.835V15.1941M21.8458 11.5531H10.1947" stroke="white" stroke-linecap="round"/> <Path d="M5.09735 3.54297H13.1075C13.5153 3.54297 13.8357 3.86337 13.8357 4.27116V7.91213M5.09735 19.5632H13.1075C13.5153 19.5632 13.8357 19.2428 13.8357 18.835V15.1941M21.8458 11.5531H10.1947" stroke="white" stroke-linecap="round" />
</Svg> </Svg>
</View> </View>
<TouchableOpacity onPress={() => console.log("Tkt t deconnecter")}> <TouchableOpacity onPress={() => Deconnection()}>
<Text style={styles.textDeconnectionOption}>Se deconnecter</Text> <Text style={styles.textDeconnectionOption}>Se deconnecter</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
@ -143,182 +340,3 @@ export default function Setting() {
</DismissKeyboard> </DismissKeyboard>
); );
}; };
const styles = StyleSheet.create({
mainSafeArea: {
flex: 1,
backgroundColor: "#141414",
},
container: {
marginTop: 30,
marginHorizontal: normalize(25),
flex: 1,
backgroundColor: '#141414',
},
title: {
fontSize: normalize(30),
fontWeight: 'bold',
color: 'white',
alignItems: 'center',
},
search: {
paddingVertical: 9,
backgroundColor: "#232123",
borderRadius: 13,
flexDirection: 'row',
marginTop: 9,
marginBottom: 22
},
inputSearch: {
placeholderTextColor:'red',
color: 'white',
width: normalize(350),
},
profil: {
paddingVertical: 9,
backgroundColor: "#232123",
borderRadius: 13,
flexDirection: 'row',
alignItems: 'center',
marginBottom: normalize(45)
},
imageProfil: {
marginLeft: 15,
marginRight: 7,
width: 50,
height: 50
},
NameProfil: {
fontWeight: 'bold',
color: 'white',
fontSize: normalize(22)
},
description: {
color: 'white',
fontSize: normalize(15)
},
profilContainer: {
flex: 1,
marginLeft: 9,
alignItems: 'flex-start',
justifyContent: 'center',
},
buttonSetting: {
width: normalize(17),
height: normalize(17),
marginRight: 22
},
body: {
paddingTop: normalize(10),
backgroundColor: "#232123",
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45),
paddingLeft: normalize(10),
},
view: {
backgroundColor: '#fe9500',
padding: 5,
borderRadius: 10,
marginLeft: 15,
marginBottom: normalize(11)
},
Option: {
flexDirection: 'row',
alignItems: 'center',
},
secondOption: {
marginTop: normalize(11),
flexDirection: 'row',
alignItems: 'center',
},
textOption: {
fontSize: normalize(18),
color: 'white',
fontWeight: 'bold',
marginBottom: normalize(8)
},
firstOptionView: {
flex: 1,
marginLeft: 15,
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: '#403F3F'
},
deconnectedOption: {
paddingVertical: 9,
paddingLeft: 5,
backgroundColor: "#232123",
borderRadius: 13,
flexDirection: 'row',
alignItems: 'center',
},
buttonDeconectedOption: {
backgroundColor: '#DF0404',
padding: 5,
borderRadius: 10,
marginLeft: 15
},
textDeconnectionOption: {
fontSize: normalize(18),
color: '#F80404',
fontWeight: 'bold',
marginLeft: 12
},
notification: {
backgroundColor: '#fe3c30',
padding: 5,
borderRadius: 10,
marginLeft: 15,
marginBottom: normalize(11)
},
secondOptionView: {
flex: 1,
marginLeft: 15,
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: '#403F3F'
},
lastOptionView: {
flex: 1,
marginLeft: 15,
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center'
},
localisation: {
backgroundColor: '#0835A7',
padding: 5,
borderRadius: 10,
marginLeft: 15,
marginBottom: normalize(11)
},
lastOption: {
marginTop: normalize(11),
flexDirection: 'row',
alignItems: 'center',
},
musicActually: {
paddingTop: normalize(17),
backgroundColor: "#232123",
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45)
},
titleMusic: {
flexDirection: 'row',
marginBottom: 5
},
mascot: {
width: normalize(90),
height: normalize(90),
position: 'absolute',
right: normalize(0),
top: normalize(10)
}
})

@ -1,13 +1,16 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import { View, Text, StyleSheet, TouchableWithoutFeedback, Keyboard, ScrollView, Image } from 'react-native'; import { View, Text, StyleSheet, TouchableWithoutFeedback, Keyboard, ScrollView, Image } from 'react-native';
import { TextInput, TouchableOpacity } from 'react-native-gesture-handler'; import { TextInput, TouchableOpacity } from 'react-native-gesture-handler';
import { Svg, Path } from 'react-native-svg'; import { Svg, Path } from 'react-native-svg';
import Modal from "react-native-modal"; import Modal from "react-native-modal";
import {useNavigation} from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { useSelector } from 'react-redux';
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import * as ImagePicker from 'expo-image-picker'; import * as ImagePicker from 'expo-image-picker';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
// @ts-ignore // @ts-ignore
const DismissKeyboard = ({ children }) => ( const DismissKeyboard = ({ children }) => (
@ -18,6 +21,10 @@ const DismissKeyboard = ({ children }) => (
export default function SettingProfil() { export default function SettingProfil() {
//Dark Mode
const isDark = useSelector(state => state.userReducer.dark);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark;
const [image, setImage] = useState(null); const [image, setImage] = useState(null);
const navigation = useNavigation(); const navigation = useNavigation();
const [currentIndex, setCurrentIndex] = useState(0); const [currentIndex, setCurrentIndex] = useState(0);
@ -32,19 +39,231 @@ export default function SettingProfil() {
const pickImage = async () => { const pickImage = async () => {
// No permissions request is necessary for launching the image library // No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({ let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All, mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true, allowsEditing: true,
aspect: [4, 3], aspect: [4, 3],
quality: 1, quality: 1,
}); });
console.log(result); console.log(result);
if (!result.canceled) { if (!result.canceled) {
setImage(result.assets[0].uri); setImage(result.assets[0].uri);
} }
}; };
const styles = StyleSheet.create({
mainSafeArea: {
flex: 1,
backgroundColor: style.body,
},
container: {
marginTop: 20,
marginHorizontal: normalize(25),
flex: 1,
backgroundColor: style.body,
},
buttonSetting: {
width: normalize(17),
height: normalize(17),
marginRight: 5
},
modalContent: {
position: 'absolute',
top: '5%',
left: '-5%',
right: '-5%',
height: '100%',
backgroundColor: style.body,
borderRadius: 12
},
modalView: {
flexDirection: 'row',
marginTop: 20,
marginLeft: 30,
marginBottom: normalize(45)
},
exit: {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center'
},
textExit: {
fontSize: normalize(20),
color: '#454545',
fontWeight: 'bold'
},
profilHead: {
alignItems: 'center',
},
title: {
fontSize: normalize(30),
fontWeight: 'bold',
color: style.Text,
},
imageWrapper: {
width: 126,
height: 126,
borderRadius: 63,
borderWidth: 3,
borderColor: style.Text,
overflow: 'hidden',
marginVertical: 20,
alignItems: 'center',
justifyContent: 'center',
},
imageProfil: {
width: 120,
height: 120,
},
editButton: {
width: 50,
height: 50,
borderRadius: 25,
backgroundColor: '#7C7C7C',
alignItems: 'center',
justifyContent: 'center'
},
body: {
paddingVertical: 9,
paddingLeft: normalize(10),
backgroundColor: style.Card,
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45)
},
textOption: {
fontSize: normalize(18),
color: style.Text,
fontWeight: 'bold',
marginLeft: 12
},
deleteOption: {
paddingVertical: 9,
paddingLeft: 5,
backgroundColor: style.Card,
borderRadius: 13,
flexDirection: 'row',
alignItems: 'center',
},
textOptionPassword: {
fontSize: normalize(18),
color: '#1c77fb',
marginLeft: 12
},
buttonDeleteOption: {
backgroundColor: '#DF0404',
padding: 5,
borderRadius: 10,
marginLeft: 15
},
textDeleteOption: {
fontSize: normalize(18),
color: '#F80404',
marginLeft: 12
},
optionId: {
flexDirection: 'row',
marginBottom: 20,
},
optionMail: {
flexDirection: 'row',
},
textInputId: {
marginLeft: 50,
width: '57%',
color: 'white',
fontSize: normalize(18),
},
textInputMail: {
marginLeft: 100,
color: 'white',
width: '57%',
fontSize: normalize(18)
},
passwordOption: {
paddingVertical: 9,
paddingLeft: normalize(10),
backgroundColor: style.Card,
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45)
},
passwordIcon: {
backgroundColor: '#8e8d92',
padding: 5,
paddingHorizontal: 8,
borderRadius: 10,
marginLeft: 10
},
optionView: {
flexDirection: 'row',
marginTop: 5
},
cancelText: {
fontSize: normalize(20),
color: '#1c77fb'
},
updateText: {
marginLeft: 60,
fontSize: normalize(20),
color: '#404040'
},
titlePassword: {
fontSize: normalize(22),
color: style.Text,
marginLeft: 50
},
warning: {
color: '#98989f',
fontSize: normalize(15)
},
warningView: {
marginTop: 10,
paddingHorizontal: 40
},
bodyModal: {
paddingVertical: 12,
paddingLeft: 30,
marginHorizontal: normalize(25),
backgroundColor: style.Card,
borderRadius: 13,
alignItems: 'flex-start'
},
optionModalWithUnderline: {
flexDirection: 'row',
borderBottomWidth: 1,
borderColor: style.Line,
paddingBottom: 10,
marginBottom: 10
},
optionModal: {
flexDirection: 'row'
},
textOptionModal: {
fontSize: normalize(18),
color: style.Text,
fontWeight: 'bold',
},
textInputNewModal: {
marginLeft: 40,
color: style.Text,
width: '67.5%',
fontSize: normalize(18)
},
textInputConfirmModal: {
marginLeft: 30,
color: style.Text,
fontSize: normalize(18)
},
textInputOldModal: {
marginLeft: 55,
color: style.Text,
width: '67.5%',
fontSize: normalize(18)
}
})
return ( return (
<DismissKeyboard> <DismissKeyboard>
<SafeAreaView style={styles.mainSafeArea}> <SafeAreaView style={styles.mainSafeArea}>
@ -52,7 +271,7 @@ export default function SettingProfil() {
<View style={styles.container}> <View style={styles.container}>
<TouchableOpacity onPress={() => navigation.navigate('Setting')}> <TouchableOpacity onPress={() => navigation.navigate('Setting')}>
<View style={styles.exit}> <View style={styles.exit}>
<Image style={styles.buttonSetting} source={require('../assets/icons/icons/buttonProfil_Inverse.png')}/> <Image style={styles.buttonSetting} source={require('../assets/icons/icons/buttonProfil_Inverse.png')} />
<Text style={styles.textExit}>Exit</Text> <Text style={styles.textExit}>Exit</Text>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
@ -64,27 +283,27 @@ export default function SettingProfil() {
<View style={styles.editButton}> <View style={styles.editButton}>
<TouchableOpacity onPress={pickImage} > <TouchableOpacity onPress={pickImage} >
<Image <Image
source={require('../assets/icons/icons/edit.png')} style={{resizeMode: "stretch", height: '85%', aspectRatio: 1}} source={require('../assets/icons/icons/edit.png')} style={{ resizeMode: "stretch", height: '85%', aspectRatio: 1 }}
/> />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View>
<View style={styles.body}> <View style={styles.body}>
<View style={styles.optionId}> <View style={styles.optionId}>
<Text style={styles.textOption}>Identifiant</Text> <Text style={styles.textOption}>Identifiant</Text>
<TextInput placeholderTextColor='#828288' placeholder='Flady' style={styles.textInputId}/> <TextInput placeholderTextColor='#828288' placeholder='Flady' style={styles.textInputId} />
</View> </View>
<View style={styles.optionMail}> <View style={styles.optionMail}>
<Text style={styles.textOption}>Mail</Text> <Text style={styles.textOption}>Mail</Text>
<TextInput placeholderTextColor='#828288' placeholder='emre.kartal@etu.uca.fr' style={styles.textInputMail}/> <TextInput placeholderTextColor='#828288' placeholder='emre.kartal@etu.uca.fr' style={styles.textInputMail} />
</View> </View>
</View> </View>
<View style={styles.passwordOption}> <View style={styles.passwordOption}>
<TouchableOpacity style={{flexDirection: 'row'}} onPress={handleModal}> <TouchableOpacity style={{ flexDirection: 'row' }} onPress={handleModal}>
<View style={styles.passwordIcon}> <View style={styles.passwordIcon}>
<Svg width="14" height="20" viewBox="0 0 14 26" > <Svg width="14" height="20" viewBox="0 0 14 26" >
<Path fill-rule="evenodd" clip-rule="evenodd" d="M3.27129 1.75541C4.23026 1.10258 5.34904 0.723459 6.50733 0.658814C7.66563 0.594169 8.81964 0.846441 9.84531 1.38851C10.7879 1.8833 11.593 2.6042 12.1889 3.48739C12.9939 4.70913 13.3604 6.16796 13.2283 7.62511C13.0962 9.08225 12.4733 10.4514 11.4617 11.5084C11.031 11.9508 10.5387 12.3292 9.99839 12.6274L10.1591 14.3578L9.96312 14.9126L9.00438 15.8973L10.5193 17.3723L10.5326 18.3689L9.05762 19.8838L10.5725 21.3588L10.5858 22.3554L7.63588 25.3852L6.63925 25.3985L4.30933 23.13L4.09638 22.6355L3.96398 12.721C3.36598 12.4165 2.82055 12.0182 2.34835 11.5414C1.68473 10.8774 1.17578 10.0751 0.857766 9.19177C0.539757 8.30846 0.420525 7.36587 0.508571 6.4312C0.596616 5.49652 0.88977 4.59278 1.36714 3.78439C1.8445 2.976 2.49533 2.28386 3.27129 1.75541ZM11.8389 7.50421C11.9428 6.36957 11.6584 5.23325 11.0323 4.28134L11.0412 4.28222C10.5801 3.58952 9.95326 3.02302 9.21756 2.63419C8.48185 2.24536 7.66065 2.04653 6.82857 2.05576C5.99649 2.06499 5.1799 2.28199 4.453 2.68704C3.72611 3.0921 3.11195 3.67236 2.66632 4.37512C2.07477 5.33215 1.8204 6.45957 1.94372 7.57788C2.06704 8.69619 2.56095 9.7411 3.34682 10.5462C3.79752 11.0047 4.33268 11.3684 4.92505 11.6127L5.36528 12.2577L5.5017 22.3236L7.1176 23.8969L9.08424 21.8771L7.56933 20.4021L7.55602 19.4055L9.031 17.8905L7.5161 16.4156L7.50279 15.4189L8.72702 14.1616L8.56231 12.2778L8.97256 11.5736C9.52979 11.3206 10.0346 10.9652 10.4608 10.526C11.249 9.70384 11.7349 8.63846 11.8389 7.50421ZM8.25568 5.66411C8.22318 5.47735 8.15334 5.29906 8.05034 5.13991C7.94734 4.98077 7.8133 4.84403 7.65623 4.73789C7.49916 4.63174 7.3223 4.55837 7.13622 4.52216C6.95014 4.48596 6.75867 4.48765 6.57326 4.52716C6.38785 4.56666 6.21232 4.64315 6.05716 4.75206C5.902 4.86098 5.7704 5.00007 5.67024 5.16101C5.57007 5.32196 5.50341 5.50146 5.47422 5.68877C5.44503 5.87608 5.45393 6.06735 5.50038 6.25114C5.58972 6.60469 5.81261 6.90986 6.12222 7.10253C6.43182 7.29521 6.80405 7.3604 7.16071 7.28441C7.51737 7.20843 7.8307 6.99717 8.03488 6.69503C8.23906 6.39289 8.31821 6.02337 8.25568 5.66411Z" fill="white"/> <Path fill-rule="evenodd" clip-rule="evenodd" d="M3.27129 1.75541C4.23026 1.10258 5.34904 0.723459 6.50733 0.658814C7.66563 0.594169 8.81964 0.846441 9.84531 1.38851C10.7879 1.8833 11.593 2.6042 12.1889 3.48739C12.9939 4.70913 13.3604 6.16796 13.2283 7.62511C13.0962 9.08225 12.4733 10.4514 11.4617 11.5084C11.031 11.9508 10.5387 12.3292 9.99839 12.6274L10.1591 14.3578L9.96312 14.9126L9.00438 15.8973L10.5193 17.3723L10.5326 18.3689L9.05762 19.8838L10.5725 21.3588L10.5858 22.3554L7.63588 25.3852L6.63925 25.3985L4.30933 23.13L4.09638 22.6355L3.96398 12.721C3.36598 12.4165 2.82055 12.0182 2.34835 11.5414C1.68473 10.8774 1.17578 10.0751 0.857766 9.19177C0.539757 8.30846 0.420525 7.36587 0.508571 6.4312C0.596616 5.49652 0.88977 4.59278 1.36714 3.78439C1.8445 2.976 2.49533 2.28386 3.27129 1.75541ZM11.8389 7.50421C11.9428 6.36957 11.6584 5.23325 11.0323 4.28134L11.0412 4.28222C10.5801 3.58952 9.95326 3.02302 9.21756 2.63419C8.48185 2.24536 7.66065 2.04653 6.82857 2.05576C5.99649 2.06499 5.1799 2.28199 4.453 2.68704C3.72611 3.0921 3.11195 3.67236 2.66632 4.37512C2.07477 5.33215 1.8204 6.45957 1.94372 7.57788C2.06704 8.69619 2.56095 9.7411 3.34682 10.5462C3.79752 11.0047 4.33268 11.3684 4.92505 11.6127L5.36528 12.2577L5.5017 22.3236L7.1176 23.8969L9.08424 21.8771L7.56933 20.4021L7.55602 19.4055L9.031 17.8905L7.5161 16.4156L7.50279 15.4189L8.72702 14.1616L8.56231 12.2778L8.97256 11.5736C9.52979 11.3206 10.0346 10.9652 10.4608 10.526C11.249 9.70384 11.7349 8.63846 11.8389 7.50421ZM8.25568 5.66411C8.22318 5.47735 8.15334 5.29906 8.05034 5.13991C7.94734 4.98077 7.8133 4.84403 7.65623 4.73789C7.49916 4.63174 7.3223 4.55837 7.13622 4.52216C6.95014 4.48596 6.75867 4.48765 6.57326 4.52716C6.38785 4.56666 6.21232 4.64315 6.05716 4.75206C5.902 4.86098 5.7704 5.00007 5.67024 5.16101C5.57007 5.32196 5.50341 5.50146 5.47422 5.68877C5.44503 5.87608 5.45393 6.06735 5.50038 6.25114C5.58972 6.60469 5.81261 6.90986 6.12222 7.10253C6.43182 7.29521 6.80405 7.3604 7.16071 7.28441C7.51737 7.20843 7.8307 6.99717 8.03488 6.69503C8.23906 6.39289 8.31821 6.02337 8.25568 5.66411Z" fill="white" />
</Svg> </Svg>
</View> </View>
<View style={styles.optionView}> <View style={styles.optionView}>
@ -96,12 +315,12 @@ export default function SettingProfil() {
<View style={styles.deleteOption}> <View style={styles.deleteOption}>
<View style={styles.buttonDeleteOption}> <View style={styles.buttonDeleteOption}>
<Svg width="20" height="22" viewBox="0 0 25 31"> <Svg width="20" height="22" viewBox="0 0 25 31">
<Path d="M21.4265 16.0194V21.7371V28.4078L19.8044 29.8373H10.6125L21.4265 16.0194Z" fill="#686868"/> <Path d="M21.4265 16.0194V21.7371V28.4078L19.8044 29.8373H10.6125L21.4265 16.0194Z" fill="#686868" />
<Path d="M9.41089 3.4031V1H15.4186V3.4031" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M9.41089 3.4031V1H15.4186V3.4031" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" />
<Path d="M21.4264 8.81006V27.4341C21.4264 28.7613 20.3504 29.8372 19.0233 29.8372H5.80618C4.47901 29.8372 3.40308 28.7613 3.40308 27.4341V8.81006" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M21.4264 8.81006V27.4341C21.4264 28.7613 20.3504 29.8372 19.0233 29.8372H5.80618C4.47901 29.8372 3.40308 28.7613 3.40308 27.4341V8.81006" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" />
<Path d="M1 3.40308H23.8295V5.80618H1V3.40308Z" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M1 3.40308H23.8295V5.80618H1V3.40308Z" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" />
<Path d="M15.4185 10.7626V26.8333" stroke="white" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M15.4185 10.7626V26.8333" stroke="white" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" />
<Path d="M9.41089 10.7626V26.8333" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/> <Path d="M9.41089 10.7626V26.8333" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" />
</Svg> </Svg>
</View> </View>
<TouchableOpacity onPress={() => console.log("Tkt t deconnecter")}> <TouchableOpacity onPress={() => console.log("Tkt t deconnecter")}>
@ -126,15 +345,15 @@ export default function SettingProfil() {
<View style={styles.bodyModal}> <View style={styles.bodyModal}>
<View style={styles.optionModalWithUnderline}> <View style={styles.optionModalWithUnderline}>
<Text style={styles.textOptionModal}>Ancien</Text> <Text style={styles.textOptionModal}>Ancien</Text>
<TextInput placeholderTextColor='#828288' placeholder="saisir l'ancien mot de passe" style={styles.textInputOldModal}/> <TextInput placeholderTextColor='#828288' placeholder="saisir l'ancien mot de passe" style={styles.textInputOldModal} />
</View> </View>
<View style={styles.optionModalWithUnderline}> <View style={styles.optionModalWithUnderline}>
<Text style={styles.textOptionModal}>Nouveau</Text> <Text style={styles.textOptionModal}>Nouveau</Text>
<TextInput placeholderTextColor='#828288' placeholder='saisir le mot de passe' style={styles.textInputNewModal}/> <TextInput placeholderTextColor='#828288' placeholder='saisir le mot de passe' style={styles.textInputNewModal} />
</View> </View>
<View style={styles.optionModal}> <View style={styles.optionModal}>
<Text style={styles.textOptionModal}>Confirmer</Text> <Text style={styles.textOptionModal}>Confirmer</Text>
<TextInput placeholderTextColor='#828288' placeholder='mot de passe' style={styles.textInputConfirmModal}/> <TextInput placeholderTextColor='#828288' placeholder='mot de passe' style={styles.textInputConfirmModal} />
</View> </View>
</View> </View>
<View style={styles.warningView}> <View style={styles.warningView}>
@ -148,215 +367,3 @@ export default function SettingProfil() {
</DismissKeyboard> </DismissKeyboard>
); );
}; };
const styles = StyleSheet.create({
mainSafeArea: {
flex: 1,
backgroundColor: "#141414",
},
container: {
marginTop: 20,
marginHorizontal: normalize(25),
flex: 1,
backgroundColor: '#141414',
},
buttonSetting: {
width: normalize(17),
height: normalize(17),
marginRight: 5
},
modalContent: {
position: 'absolute',
top: '5%',
left: '-5%',
right: '-5%',
height: '100%',
backgroundColor: '#141414',
borderRadius: 12
},
modalView: {
flexDirection: 'row',
marginTop: 20,
marginLeft: 30,
marginBottom: normalize(45)
},
exit: {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center'
},
textExit: {
fontSize: normalize(20),
color: '#454545',
fontWeight: 'bold'
},
profilHead: {
alignItems: 'center',
},
title: {
fontSize: normalize(30),
fontWeight: 'bold',
color: 'white',
},
imageWrapper: {
width: 126,
height: 126,
borderRadius: 63,
borderWidth: 3,
borderColor: 'white',
overflow: 'hidden',
marginVertical: 20,
alignItems: 'center',
justifyContent: 'center',
},
imageProfil: {
width: 120,
height: 120,
},
editButton: {
width: 50,
height: 50,
borderRadius: 25,
backgroundColor: '#7C7C7C',
alignItems: 'center',
justifyContent: 'center'
},
body: {
paddingVertical: 9,
paddingLeft: normalize(10),
backgroundColor: "#232123",
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45)
},
textOption: {
fontSize: normalize(18),
color: 'white',
fontWeight: 'bold',
marginLeft: 12
},
deleteOption: {
paddingVertical: 9,
paddingLeft: 5,
backgroundColor: "#232123",
borderRadius: 13,
flexDirection: 'row',
alignItems: 'center',
},
textOptionPassword: {
fontSize: normalize(18),
color: '#1c77fb',
marginLeft: 12
},
buttonDeleteOption: {
backgroundColor: '#DF0404',
padding: 5,
borderRadius: 10,
marginLeft: 15
},
textDeleteOption: {
fontSize: normalize(18),
color: '#F80404',
marginLeft: 12
},
optionId: {
flexDirection:'row',
marginBottom: 20,
},
optionMail: {
flexDirection:'row',
},
textInputId: {
marginLeft: 50,
width: '57%',
color: 'white',
fontSize: normalize(18),
},
textInputMail: {
marginLeft: 100,
color: 'white',
width: '57%',
fontSize: normalize(18)
},
passwordOption: {
paddingVertical: 9,
paddingLeft: normalize(10),
backgroundColor: "#232123",
borderRadius: 13,
alignItems: 'flex-start',
marginBottom: normalize(45)
},
passwordIcon: {
backgroundColor: '#8e8d92',
padding: 5,
paddingHorizontal: 8,
borderRadius: 10,
marginLeft: 10
},
optionView: {
flexDirection: 'row',
marginTop: 5
},
cancelText: {
fontSize: normalize(20),
color: '#1c77fb'
},
updateText: {
marginLeft: 60,
fontSize: normalize(20),
color: '#404040'
},
titlePassword: {
fontSize: normalize(22),
color: 'white',
marginLeft: 50
},
warning: {
color: '#98989f',
fontSize: normalize(15)
},
warningView: {
marginTop: 10,
paddingHorizontal: 40
},
bodyModal: {
paddingVertical: 12,
paddingLeft: 30,
marginHorizontal: normalize(25),
backgroundColor: "#232123",
borderRadius: 13,
alignItems: 'flex-start'
},
optionModalWithUnderline: {
flexDirection: 'row',
borderBottomWidth: 1,
borderColor: '#403F3F',
paddingBottom: 10,
marginBottom: 10
},
optionModal: {
flexDirection: 'row'
},
textOptionModal: {
fontSize: normalize(18),
color: 'white',
fontWeight: 'bold',
},
textInputNewModal: {
marginLeft: 40,
color: 'white',
width: '67.5%',
fontSize: normalize(18)
},
textInputConfirmModal: {
marginLeft: 30,
color: 'white',
fontSize: normalize(18)
},
textInputOldModal: {
marginLeft: 55,
color: 'white',
width: '67.5%',
fontSize: normalize(18)
}
})

@ -1,6 +1,6 @@
import { SharedElement } from "react-navigation-shared-element"; import { SharedElement } from "react-navigation-shared-element";
import { NavigationProp, RouteProp } from "@react-navigation/native"; import { NavigationProp, RouteProp } from "@react-navigation/native";
import { View,Text,Image,StyleSheet, Dimensions, useWindowDimensions, Button, TouchableOpacity, SafeAreaView } from "react-native"; import { View, Text, Image, StyleSheet, Dimensions, useWindowDimensions, Button, TouchableOpacity, SafeAreaView } from "react-native";
import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, useDerivedValue, useSharedValue, Value, withSpring, withTiming } from "react-native-reanimated"; import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, useDerivedValue, useSharedValue, Value, withSpring, withTiming } from "react-native-reanimated";
import { BlurView } from 'expo-blur'; import { BlurView } from 'expo-blur';
import qs from "qs"; import qs from "qs";
@ -13,70 +13,70 @@ import { RequestHandler } from "../services/spotify/spotifyRequestHandler/utils"
import { FetchRequest } from "expo-auth-session/build/Fetch"; import { FetchRequest } from "expo-auth-session/build/Fetch";
interface SpotProps { interface SpotProps {
spot: { name: string, sourceUrl: string, index : number }; spot: { name: string, sourceUrl: string, index: number };
} }
const halfPi = Math.PI/2; const halfPi = Math.PI / 2;
// const {width : wWidht} = Dimensions.get("window"); // const {width : wWidht} = Dimensions.get("window");
//@ts-ignore //@ts-ignore
const SpotDetailsPage = ({ route }) => { const SpotDetailsPage = ({ route }) => {
const {width, height} = useWindowDimensions(); const { width, height } = useWindowDimensions();
console.log(route); console.log(route);
const spot : { name: string, sourceUrl: string, index : number } = route.params.spot; const spot: { name: string, sourceUrl: string, index: number } = route.params.spot;
const [currentspot, setCurrentspot] = useState(spot); const [currentspot, setCurrentspot] = useState(spot);
const [sound, setSound] = useState(null); const [sound, setSound] = useState(null);
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
const loader = useSharedValue(0); const loader = useSharedValue(0);
useEffect(() => { useEffect(() => {
loader.value = isPlaying ? 1 : 0 loader.value = isPlaying ? 1 : 0
}, [isPlaying,loader ]); }, [isPlaying, loader]);
const transition = useDerivedValue(()=>{ const transition = useDerivedValue(() => {
return withTiming(loader.value, {duration : 1000}) return withTiming(loader.value, { duration: 1000 })
} }
) )
// const styleAniamatedButton = useAnimatedStyle(() => { // const styleAniamatedButton = useAnimatedStyle(() => {
// const verticalAxis =interpolate( // const verticalAxis =interpolate(
// transition.value, // transition.value,
// [0,1], // [0,1],
// [circumference, 0] // [circumference, 0]
// ) // )
// return { // return {
// top : withSpring( verticalAxis), // top : withSpring( verticalAxis),
// left : withSpring(horizontalAxis), // left : withSpring(horizontalAxis),
// }; // };
// }) // })
const trackPreviewUrl = 'https://p.scdn.co/mp3-preview/08ef3b9d6dbd6bab233f5e9ca564091902767f71?cid=774b29d4f13844c495f206cafdad9c86'; const trackPreviewUrl = 'https://p.scdn.co/mp3-preview/08ef3b9d6dbd6bab233f5e9ca564091902767f71?cid=774b29d4f13844c495f206cafdad9c86';
const playTrackPreview = async () => { const playTrackPreview = async () => {
console.log("==============================================================================================================="); console.log("===============================================================================================================");
console.log('get in Sound'); console.log('get in Sound');
const { sound } = await Audio.Sound.createAsync({uri :trackPreviewUrl}); const { sound } = await Audio.Sound.createAsync({ uri: trackPreviewUrl });
//@ts-ignore //@ts-ignore
setSound(sound); setSound(sound);
console.log('Playing Sound'); console.log('Playing Sound');
await sound.playAsync(); await sound.playAsync();
setIsPlaying(true); setIsPlaying(true);
// const soundObject = new Audio.Sound(); // const soundObject = new Audio.Sound();
// try { // try {
// await soundObject.loadAsync({ uri: trackPreviewUrl }); // await soundObject.loadAsync({ uri: trackPreviewUrl });
// await soundObject.playAsync(); // await soundObject.playAsync();
// setIsPlaying(true); // setIsPlaying(true);
// } catch (error) { // } catch (error) {
// console.log('Error loading sound:', error); // console.log('Error loading sound:', error);
// } // }
}; };
const handlePlaySound = async () => { const handlePlaySound = async () => {
if (sound === null) { if (sound === null) {
@ -87,191 +87,192 @@ const SpotDetailsPage = ({ route }) => {
setSound(newSound); setSound(newSound);
} else { } else {
//@ts-ignore //@ts-ignore
await sound.playAsync(); await sound.playAsync();
} }
}; };
const handleStopSound = async () => { const handleStopSound = async () => {
if (sound !== null) { if (sound !== null) {
//@ts-ignore //@ts-ignore
await sound.stopAsync(); await sound.stopAsync();
} }
else{ else {
setIsPlaying(true); setIsPlaying(true);
} }
}; };
useEffect(() => { useEffect(() => {
return sound ? () => { return sound ? () => {
console.log('Unloading Sound'); console.log('Unloading Sound');
//@ts-ignore //@ts-ignore
sound.unloadAsync(); sound.unloadAsync();
} }
: undefined; : undefined;
}, [sound]); }, [sound]);
// useEffect(() => { // useEffect(() => {
// if(isPlaying){ // if(isPlaying){
// } // }
// }) // })
console.log(spot); console.log(spot);
const sensor = useAnimatedSensor(SensorType.ROTATION); const sensor = useAnimatedSensor(SensorType.ROTATION);
const styleAniamatedImage = useAnimatedStyle(() => { const styleAniamatedImage = useAnimatedStyle(() => {
const {yaw, pitch, roll} = sensor.sensor.value; const { yaw, pitch, roll } = sensor.sensor.value;
const verticalAxis =interpolate( const verticalAxis = interpolate(
pitch, pitch,
[-halfPi,halfPi], [-halfPi, halfPi],
[-45, 45] [-45, 45]
) )
const horizontalAxis =interpolate( const horizontalAxis = interpolate(
roll, roll,
[-halfPi*2,halfPi*2], [-halfPi * 2, halfPi * 2],
[-45, 45] [-45, 45]
) )
return { return {
top : withSpring( verticalAxis), top: withSpring(verticalAxis),
left : withSpring(horizontalAxis), left: withSpring(horizontalAxis),
}; };
}) })
const CLIENT_ID = "1f1e34e4b6ba48b388469dba80202b10"; const CLIENT_ID = "1f1e34e4b6ba48b388469dba80202b10";
const CLIENT_SECRET = "779371c6d4994a68b8dd6e84b0873c82"; const CLIENT_SECRET = "779371c6d4994a68b8dd6e84b0873c82";
const spotify = "BQA2IAFZ-7ta4-_4_Uqdcdrqi_peE6Hlf1jwxFqjXTbwes0z8xgVGx0rE3zv4cQlusd1ILJhRwkxzPsL1YakzSvCxaTI1P7kOzBrrMqlkDgk4vlFvzLjScB0hBLULbpZyn3ylgx4RyZBEWfmc24wZPQOsrJU58AYCveA52UxYVSIc_Frr7LZyRmwjzGB68MPZeBD" const spotify = "BQA2IAFZ-7ta4-_4_Uqdcdrqi_peE6Hlf1jwxFqjXTbwes0z8xgVGx0rE3zv4cQlusd1ILJhRwkxzPsL1YakzSvCxaTI1P7kOzBrrMqlkDgk4vlFvzLjScB0hBLULbpZyn3ylgx4RyZBEWfmc24wZPQOsrJU58AYCveA52UxYVSIc_Frr7LZyRmwjzGB68MPZeBD"
var authOptions = { var authOptions = {
method: 'GET', method: 'GET',
url: 'https://api.spotify.com/v1/me/player/currently-playing', url: 'https://api.spotify.com/v1/me/player/currently-playing',
headers: { headers: {
'Authorization': 'Bearer ' + spotify, 'Authorization': 'Bearer ' + spotify,
'Content-Type' : 'application/json', 'Content-Type': 'application/json',
'market' : 'FR', 'market': 'FR',
}, },
json: true json: true
}; };
var id = '0cFS3AMF9Lhj3CNoFvwjvY' var id = '0cFS3AMF9Lhj3CNoFvwjvY'
const requestor = new RequestHandler() const requestor = new RequestHandler()
const getCurrentTrack = async () => { const getCurrentTrack = async () => {
try { try {
const opt : FetchRequest ={headers : Record} const opt: FetchRequest = { headers: Record }
requestor.spotifyFetch(`tracks${id}`,) requestor.spotifyFetch(`tracks${id}`,)
// var GetTrackOptions = { // var GetTrackOptions = {
// method: 'GET', // method: 'GET',
// url: 'https://api.spotify.com/v1/tracks/'+id, // url: 'https://api.spotify.com/v1/tracks/'+id,
// headers: { // headers: {
// 'Authorization': 'Bearer ' + spotify, // 'Authorization': 'Bearer ' + spotify,
// 'Content-Type' : 'application/json', // 'Content-Type' : 'application/json',
// 'market' : 'FR', // 'market' : 'FR',
// }, // },
// json: true // json: true
// }; // };
// const resp = await axios(GetTrackOptions) // const resp = await axios(GetTrackOptions)
// console.log("============"); // console.log("============");
// console.log(resp.data.href); // console.log(resp.data.href);
// console.log("================================"+resp.data.album.images[0].url+ "================================"); // console.log("================================"+resp.data.album.images[0].url+ "================================");
// var tmp = currentspot; // var tmp = currentspot;
// tmp.sourceUrl = resp.data.album.images[0].url; // tmp.sourceUrl = resp.data.album.images[0].url;
// setCurrentspot(tmp); // setCurrentspot(tmp);
// await axios(authOptions).then(async (response) =>{ // await axios(authOptions).then(async (response) =>{
// console.log(response.data.item.preview_url); // console.log(response.data.item.preview_url);
// const id = response.data.item.id; // const id = response.data.item.id;
// var GetTrackOptions = { // var GetTrackOptions = {
// method: 'GET', // method: 'GET',
// url: 'https://api.spotify.com/v1/tracks/'+id, // url: 'https://api.spotify.com/v1/tracks/'+id,
// headers: { // headers: {
// 'Authorization': 'Bearer ' + spotify, // 'Authorization': 'Bearer ' + spotify,
// 'Content-Type' : 'application/json', // 'Content-Type' : 'application/json',
// 'market' : 'FR', // 'market' : 'FR',
// }, // },
// json: true // json: true
// }; // };
// console.log("============"); // console.log("============");
// const music = await axios(GetTrackOptions); // const music = await axios(GetTrackOptions);
// console.log("================================"+music.data+ "================================"); // console.log("================================"+music.data+ "================================");
// currentspot.sourceUrl = music.data.images[0]; // currentspot.sourceUrl = music.data.images[0];
// setCurrentspot(currentspot); // setCurrentspot(currentspot);
// }) // })
// const response = await fetch('https://api.spotify.com/v1/me', { // const response = await fetch('https://api.spotify.com/v1/me', {
// method: 'GET', // method: 'GET',
// headers: { // headers: {
// Authorization: 'Bearer ' + spotify, // Authorization: 'Bearer ' + spotify,
// 'Content-Type': 'application/json', // 'Content-Type': 'application/json',
// }, // },
// }); // });
// response.json() // response.json()
// destructure the response and rename the properties to be in camelCase to satisfy my linter ;) // destructure the response and rename the properties to be in camelCase to satisfy my linter ;)
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
} }
const animationState = new Value(State.UNDETERMINED); const animationState = new Value(State.UNDETERMINED);
return ( return (
<SafeAreaView style={styles.mainSafeArea}> <SafeAreaView style={styles.mainSafeArea}>
<View style={{ flex: 1, justifyContent : 'flex-start', alignItems : 'center' }}> <View style={{ flex: 1, justifyContent: 'flex-start', alignItems: 'center' }}>
{/* <SharedElement id={spot.name} style={{ flex: 1 }}> */} {/* <SharedElement id={spot.name} style={{ flex: 1 }}> */}
<View style={{borderWidth : 1, borderColor : 'red'}}> <View style={{ borderWidth: 1, borderColor: 'red' }}>
<Animated.Image <Animated.Image
source={{ source={{
uri:currentspot.sourceUrl , uri: currentspot.sourceUrl,
}} }}
style={[ style={[
{ {
width: 370, width: 370,
height: 370, height: 370,
borderRadius : 24, borderRadius: 24,
resizeMode: 'stretch', resizeMode: 'stretch',
},styleAniamatedImage }, styleAniamatedImage
]} ]}
/> />
<Button title="Current Track" <Button title="Current Track"
onPress={() => { onPress={() => {
getCurrentTrack() getCurrentTrack()
// promptAsync(); // promptAsync();
}} }}
/> />
</View> </View>
{/* Button */} {/* Button */}
{/* <TapGestureHandler {...gestureHandler}> */} {/* <TapGestureHandler {...gestureHandler}> */}
<Animated.View> <Animated.View>
<TouchableOpacity style={{ <TouchableOpacity style={{
backgroundColor: '#1DB954', backgroundColor: '#1DB954',
paddingVertical: 12, paddingVertical: 12,
paddingHorizontal: 24, paddingHorizontal: 24,
borderRadius: 24, borderRadius: 24,
}} onPressIn={handlePlaySound} }} onPressIn={handlePlaySound}
onPressOut={handleStopSound} onPressOut={handleStopSound}
onLongPress={handlePlaySound} onLongPress={handlePlaySound}
delayLongPress={1000}> delayLongPress={1000}>
<Text style={ { <Text style={{
color: '#fff', color: '#fff',
fontSize: 16, fontSize: 16,
fontWeight: 'bold',}}> fontWeight: 'bold',
{isPlaying ? 'Playing...' : 'Play'} }}>
</Text> {isPlaying ? 'Playing...' : 'Play'}
</TouchableOpacity> </Text>
</Animated.View> </TouchableOpacity>
</Animated.View>
{/* </TapGestureHandler> */}
{/* </TapGestureHandler> */}
{/* Button */}
{/* Button */}
{/* <View style={detailRadicalStyle.container}> {/* <View style={detailRadicalStyle.container}>
@ -287,15 +288,15 @@ const SpotDetailsPage = ({ route }) => {
/> />
</View> */} </View> */}
{/* </SharedElement> */} {/* </SharedElement> */}
</View> </View>
</SafeAreaView> </SafeAreaView>
); );
}; };
export default SpotDetailsPage; export default SpotDetailsPage;
const styles = StyleSheet.create ({ const styles = StyleSheet.create({
mainSafeArea: { mainSafeArea: {
flex: 1, flex: 1,
backgroundColor: "#141414", backgroundColor: "#141414",

@ -1,4 +1,4 @@
import { View, Text, Image, Animated ,PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, Touchable, TouchableOpacity, Modal, SafeAreaView, TextInput, Platform } from 'react-native' import { View, Text, Image, Animated, PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, Touchable, TouchableOpacity, Modal, SafeAreaView, TextInput, Platform } from 'react-native'
import React, { useCallback, useEffect, useRef, useState, useTransition } from 'react' import React, { useCallback, useEffect, useRef, useState, useTransition } from 'react'
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import * as Haptics from 'expo-haptics'; import * as Haptics from 'expo-haptics';
@ -19,19 +19,19 @@ import * as SecureStore from 'expo-secure-store';
interface LoginProps { interface LoginProps {
} }
interface Params { interface Params {
[key: string]: string; [key: string]: string;
} }
interface Profile { interface Profile {
display_name: string; display_name: string;
email: string; email: string;
id: string; id: string;
} }
//generate random string //generate random string
export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey'; export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey';
WebBrowser.maybeCompleteAuthSession(); WebBrowser.maybeCompleteAuthSession();
// Endpoint // Endpoint
const discovery = { const discovery = {
@ -39,162 +39,163 @@ const discovery = {
tokenEndpoint: 'https://accounts.spotify.com/api/token', tokenEndpoint: 'https://accounts.spotify.com/api/token',
}; };
// save the spotifyToken // save the spotifyToken
async function save(key : string, value : string) { async function save(key: string, value: string) {
await SecureStore.setItemAsync(key, value); await SecureStore.setItemAsync(key, value);
} }
export default function Login() { export default function Login() {
// const [advice, setAdvice] = useState("dd"); // const [advice, setAdvice] = useState("dd");
// there we use implicit grant flow // there we use implicit grant flow
const [request, response, promptAsync] = useAuthRequest( const [request, response, promptAsync] = useAuthRequest(
{ {
responseType: AuthSession.ResponseType.Token, responseType: AuthSession.ResponseType.Token,
clientId: '1f1e34e4b6ba48b388469dba80202b10', clientId: '1f1e34e4b6ba48b388469dba80202b10',
scopes: ['user-read-private','user-read-email','user-read-playback-state','user-read-currently-playing','user-read-recently-played','playlist-modify-public','ugc-image-upload','user-modify-playback-state'], scopes: ['user-read-private', 'user-read-email', 'user-read-playback-state', 'user-read-currently-playing', 'user-read-recently-played', 'playlist-modify-public', 'ugc-image-upload', 'user-modify-playback-state'],
usePKCE: false, usePKCE: false,
redirectUri: makeRedirectUri({ redirectUri: makeRedirectUri({
scheme: 'https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d', scheme: 'https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d',
useProxy : true useProxy: true
}) })
}, },
discovery discovery
); );
const getAdvice = async () => { axios.get("http://localhost:8080/api/spotify/exchange") const getAdvice = async () => {
.then(response => { axios.get("http://localhost:8080/api/spotify/exchange")
console.log(response.data.message); .then(response => {
console.log(response.data.message);
// setAdvice(response.data.message);
}).catch(function (error) { // setAdvice(response.data.message);
console.log(error); }).catch(function (error) {
}); console.log(error);
}; });
React.useEffect(() => { };
if (response && response.type === 'success') { React.useEffect(() => {
console.log(response); if (response && response.type === 'success') {
console.log("========================code====================="); console.log(response);
console.log("========================code=====================");
console.log(response.params.code)
console.log("============================================="); console.log(response.params.code)
console.log("=============================================");
console.log("========================acess=====================");
console.log(response.params.access_token) console.log("========================acess=====================");
console.log("============================================="); console.log(response.params.access_token)
console.log("=============================================");
const auth = response.params.access_token;
const storageValue = JSON.stringify(auth); const auth = response.params.access_token;
const storageValue = JSON.stringify(auth);
if (Platform.OS !== 'web') {
// Securely store the auth on your device if (Platform.OS !== 'web') {
// save(MY_SECURE_AUTH_STATE_KEY, storageValue); // Securely store the auth on your device
} // save(MY_SECURE_AUTH_STATE_KEY, storageValue);
}
}, [response]);
const scopesArr = ['user-read-private','user-read-email','user-read-playback-state','user-read-currently-playing','user-read-recently-played','playlist-modify-public','ugc-image-upload','user-modify-playback-state'];
const scopes = scopesArr.join(' ');
//work so use this for my implementation
const getAuthorizationCode = async () => {
try {
const redirectUrl = "https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d"; //this will be something like https://auth.expo.io/@your-username/your-app-slug
const result = await AuthSession.startAsync({
authUrl:
'https://accounts.spotify.com/authorize' +
'?response_type=code' +
'&client_id=' +
"1f1e34e4b6ba48b388469dba80202b10" +
(scopes ? '&scope=' + encodeURIComponent(scopes) : '') +
'&redirect_uri=' +
encodeURIComponent(redirectUrl),
})
console.log(result);
return result.params.code;
} catch (err) {
console.error(err)
} }
} }
const getTokens = async () => { }, [response]);
try {
const authorizationCode = await getAuthorizationCode() //we wrote this function above const scopesArr = ['user-read-private', 'user-read-email', 'user-read-playback-state', 'user-read-currently-playing', 'user-read-recently-played', 'playlist-modify-public', 'ugc-image-upload', 'user-modify-playback-state'];
console.log(authorizationCode, "shhhhhhhhhhhhhheeeeeeeeeeeeeeeetttttttttttt"); const scopes = scopesArr.join(' ');
const response = await fetch('https://accounts.spotify.com/api/token', { //work so use this for my implementation
method: 'POST', const getAuthorizationCode = async () => {
headers: { try {
Authorization: 'Basic ' + (Buffer.from('1f1e34e4b6ba48b388469dba80202b10' + ':' + '779371c6d4994a68b8dd6e84b0873c82').toString('base64')), const redirectUrl = "https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d"; //this will be something like https://auth.expo.io/@your-username/your-app-slug
'Content-Type': 'application/x-www-form-urlencoded', const result = await AuthSession.startAsync({
}, authUrl:
body: `grant_type=authorization_code&code=${authorizationCode}&redirect_uri=https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d`, 'https://accounts.spotify.com/authorize' +
}); '?response_type=code' +
const responseJson = await response.json(); '&client_id=' +
console.log(responseJson.access_token, "okkkkkkkkkkkkkkk") ; "1f1e34e4b6ba48b388469dba80202b10" +
// destructure the response and rename the properties to be in camelCase to satisfy my linter ;) (scopes ? '&scope=' + encodeURIComponent(scopes) : '') +
const { '&redirect_uri=' +
access_token: accessToken, encodeURIComponent(redirectUrl),
refresh_token: refreshToken, })
expires_in: expiresIn, console.log(result);
} = responseJson; return result.params.code;
} catch (err) {
} catch (err) { console.error(err)
console.error(err);
}
} }
return ( }
<View style={styles.centeredView}> const getTokens = async () => {
<Text style={styles.textStyle}>Hello flad test logIn</Text> try {
<Button disabled={!request} title="Login" const authorizationCode = await getAuthorizationCode() //we wrote this function above
onPress={() => { console.log(authorizationCode, "shhhhhhhhhhhhhheeeeeeeeeeeeeeeetttttttttttt");
getTokens() const response = await fetch('https://accounts.spotify.com/api/token', {
// promptAsync(); method: 'POST',
}} headers: {
/> Authorization: 'Basic ' + (Buffer.from('1f1e34e4b6ba48b388469dba80202b10' + ':' + '779371c6d4994a68b8dd6e84b0873c82').toString('base64')),
</View> 'Content-Type': 'application/x-www-form-urlencoded',
); },
body: `grant_type=authorization_code&code=${authorizationCode}&redirect_uri=https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d`,
});
const responseJson = await response.json();
console.log(responseJson.access_token, "okkkkkkkkkkkkkkk");
// destructure the response and rename the properties to be in camelCase to satisfy my linter ;)
const {
access_token: accessToken,
refresh_token: refreshToken,
expires_in: expiresIn,
} = responseJson;
} catch (err) {
console.error(err);
}
}
return (
<View style={styles.centeredView}>
<Text style={styles.textStyle}>Hello flad test logIn</Text>
<Button disabled={!request} title="Login"
onPress={() => {
getTokens()
// promptAsync();
}}
/>
</View>
);
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
centeredView: { centeredView: {
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
marginTop: 22, marginTop: 22,
}, },
modalView: { modalView: {
margin: 20, margin: 20,
backgroundColor: 'white', backgroundColor: 'white',
borderRadius: 20, borderRadius: 20,
padding: 35, padding: 35,
alignItems: 'center', alignItems: 'center',
shadowColor: '#000', shadowColor: '#000',
shadowOffset: { shadowOffset: {
width: 0, width: 0,
height: 2, height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 4,
},
header :{
alignItems : 'flex-end',
justifyContent: 'center',
}, },
button: { shadowOpacity: 0.25,
borderRadius: 20, shadowRadius: 4,
padding: 10, },
elevation: 2, header: {
}, alignItems: 'flex-end',
buttonOpen: { justifyContent: 'center',
backgroundColor: '#F194FF', },
}, button: {
textStyle: { borderRadius: 20,
color: 'white', padding: 10,
fontWeight: 'bold', elevation: 2,
textAlign: 'center', },
}, buttonOpen: {
close :{ backgroundColor: '#F194FF',
alignSelf : 'flex-end', },
backgroundColor : 'red', textStyle: {
justifyContent : 'center' color: 'white',
} fontWeight: 'bold',
textAlign: 'center',
},
close: {
alignSelf: 'flex-end',
backgroundColor: 'red',
justifyContent: 'center'
}
}) })

@ -1,4 +1,4 @@
import { View, Text, Image ,PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, TouchableOpacity, SafeAreaView } from 'react-native' import { View, Text, Image, PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, TouchableOpacity, SafeAreaView } from 'react-native'
import React, { useCallback, useEffect, useRef, useState, useTransition } from 'react' import React, { useCallback, useEffect, useRef, useState, useTransition } from 'react'
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import * as Haptics from 'expo-haptics'; import * as Haptics from 'expo-haptics';
@ -9,11 +9,11 @@ import Card from '../components/Card';
import { cards as cardArray, spotArray2 } from '../data/data' import { cards as cardArray, spotArray2 } from '../data/data'
import FladButton from '../components/button/button'; import FladButton from '../components/button/button';
import axios from 'axios'; import axios from 'axios';
import AdjustSize from '../components/AdjustSize';
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
import { MY_SECURE_AUTH_STATE_KEY } from './login'; import { MY_SECURE_AUTH_STATE_KEY } from './login';
import * as AuthSession from 'expo-auth-session'; import * as AuthSession from 'expo-auth-session';
import normalize from '../components/Normalize';
import * as Location from 'expo-location'; import * as Location from 'expo-location';
import Icons from '../assets/icons/icons/icon'; import Icons from '../assets/icons/icons/icon';
import LottieView from 'lottie-react-native' import LottieView from 'lottie-react-native'
@ -39,25 +39,25 @@ interface NearbyUser {
longitude: number; longitude: number;
} }
async function getUserData(accessToken : string) { async function getUserData(accessToken: string) {
axios.get("https://api.spotify.com/v1/me", axios.get("https://api.spotify.com/v1/me",
{ {
headers: { headers: {
'Authorization': 'Bearer ' + accessToken, 'Authorization': 'Bearer ' + accessToken,
"Content-Type" : "application/json" "Content-Type": "application/json"
}}) }
.then(response => })
{ .then(response => {
if (response && response.statusText === 'success') { if (response && response.statusText === 'success') {
console.log(response.data.message); console.log(response.data.message);
const userData = JSON.stringify(response.data); const userData = JSON.stringify(response.data);
const userId = response.data.id; const userId = response.data.id;
return {userId, userData} return { userId, userData }
} }
}) })
.catch(function (error) { .catch(function (error) {
console.log(error); console.log(error);
}); });
}; };
// async function sendUserLoc(accessToken : string) { // async function sendUserLoc(accessToken : string) {
@ -80,7 +80,7 @@ async function getUserData(accessToken : string) {
// }); // });
// }; // };
async function getValueFor(key:string) :Promise<string | null> { async function getValueFor(key: string): Promise<string | null> {
let result = await SecureStore.getItemAsync(key); let result = await SecureStore.getItemAsync(key);
if (result) { if (result) {
alert("🔐 Here's your value 🔐 \n" + result); alert("🔐 Here's your value 🔐 \n" + result);
@ -98,7 +98,7 @@ export default function SpotPage() {
if (direction === 'right') { if (direction === 'right') {
// Swiped right // Swiped right
console.log("====2==="+currentCard.music.title+"======2========="); console.log("====2===" + currentCard.music.title + "======2=========");
addLike(currentCard.music); addLike(currentCard.music);
console.log('Swiped right'); console.log('Swiped right');
} else if (direction === 'left') { } else if (direction === 'left') {
@ -122,16 +122,16 @@ export default function SpotPage() {
const dislikeButtonref = useRef<LottieView>(null); const dislikeButtonref = useRef<LottieView>(null);
const discoveryButtonref = useRef<LottieView>(null); const discoveryButtonref = useRef<LottieView>(null);
const onLike = useCallback( () => { const onLike = useCallback(() => {
likeButtonref.current?.reset(); likeButtonref.current?.reset();
likeButtonref.current?.play(0,55); likeButtonref.current?.play(0, 55);
likeButtonref.current?.play(55,0); likeButtonref.current?.play(55, 0);
}, []) }, [])
const dispatch = useDispatch(); const dispatch = useDispatch();
function addLike(music: Music) { function addLike(music: Music) {
onLike(); onLike();
console.log("====3==="+currentCard.music.title+"======3========="); console.log("====3===" + currentCard.music.title + "======3=========");
dispatch(addFavoritesMusic(music)) dispatch(addFavoritesMusic(music))
// dispatch(addFavoriteMusic(props)); // dispatch(addFavoriteMusic(props));
@ -139,7 +139,7 @@ export default function SpotPage() {
// setdisplayIndex(0); // setdisplayIndex(0);
// swiper.swipeLeft(); // swiper.swipeLeft();
// } // }
} }
@ -150,7 +150,7 @@ export default function SpotPage() {
// // Haptics.NotificationFeedbackType.Success // // Haptics.NotificationFeedbackType.Success
// }); // });
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// const [locationData, setLocationData] = useState<LocationData>(); // const [locationData, setLocationData] = useState<LocationData>();
// const [prevLocationData, setPrevLocationData] = useState<LocationData>(); // const [prevLocationData, setPrevLocationData] = useState<LocationData>();
// const [nearbyUsers, setNearbyUsers] = useState<NearbyUser[]>([]); // const [nearbyUsers, setNearbyUsers] = useState<NearbyUser[]>([]);
@ -196,136 +196,137 @@ export default function SpotPage() {
// setInterval(sendLocationToServer, 30000) // setInterval(sendLocationToServer, 30000)
const navigator = useNavigation(); const navigator = useNavigation();
const {width : wWidht} = Dimensions.get("window"); const { width: wWidht } = Dimensions.get("window");
const hapti = (card : Spot) => { const hapti = (card: Spot) => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy) Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)
navigator.navigate("DetailsSpot", {"music": card.music}) navigator.navigate("DetailsSpot", { "music": card.music })
// Haptics.NotificationFeedbackType.Success // Haptics.NotificationFeedbackType.Success
}; };
return ( return (
<View style={{flex: 1, <View style={{
flex: 1,
}}> }}>
{ cards.length > 0 ? ( {cards.length > 0 ? (
<> <>
<ImageBackground blurRadius={7} <ImageBackground blurRadius={7}
style={{ style={{
position: 'absolute', position: 'absolute',
width: "100%", width: "100%",
height: "100%", height: "100%",
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
}} }}
source={{ source={{
uri:currentCard.music.image , uri: currentCard.music.image,
}} }}
></ImageBackground> ></ImageBackground>
<SafeAreaView style={styles.mainSafeArea}> <SafeAreaView style={styles.mainSafeArea}>
<LinearGradient colors={['rgba(2, 2, 2, 0.58) 0%','rgba(0, 0, 0, 0) 100.56%']}style={styles.gradient}> <LinearGradient colors={['rgba(2, 2, 2, 0.58) 0%', 'rgba(0, 0, 0, 0) 100.56%']} style={styles.gradient}>
<Text <Text
style={{ style={{
fontStyle : 'normal', fontStyle: 'normal',
left: wWidht/9 , left: wWidht / 9,
top: 75, top: normalize(87),
color: "#FFFFFF", color: "#FFFFFF",
fontSize: 30, fontSize: normalize(AdjustSize(currentCard.music.title)),
fontWeight: "800", fontWeight: "800",
}}>{currentCard.music.title}</Text> }}>{currentCard.music.title}</Text>
<Text <Text
style={{ style={{
fontStyle : 'normal', fontStyle: 'normal',
left: wWidht/9 , left: wWidht / 9,
top: 75, top: normalize(87),
color: "#FFFFFF", color: "#FFFFFF",
fontSize: 18, fontSize: normalize(20),
}}>{currentCard.music.bio}</Text> }}>{currentCard.music.bio}</Text>
</LinearGradient> </LinearGradient>
</SafeAreaView> </SafeAreaView>
<View style={{flex : 8.35}}> <View style={{ flex: 8.35 }}>
<View style={{flex : 1.83, justifyContent: 'center', alignItems: 'center' }}> <View style={{ flex: 1.83, justifyContent: 'center', alignItems: 'center' }}>
{cards.map((card, index) => ( {cards.map((card, index) => (
<View key={card.userSpotifyId} style = {{ position:'absolute'}} > <View key={card.userSpotifyId} style={{ position: 'absolute' }} >
<Pressable onLongPress={() => {hapti(card)}} > <Pressable onLongPress={() => { hapti(card) }} >
{/* <SharedElement id={card.name}> */} {/* <SharedElement id={card.name}> */}
<Card <Card
title={card.music.title} title={card.music.title}
image={card.music.image} image={card.music.image}
onSwipe={(direction) => {onSwipe(index, direction)}} onSwipe={(direction) => { onSwipe(index, direction) }}
/> />
{/* </SharedElement> */} {/* </SharedElement> */}
</Pressable> </Pressable>
</View>
))
}
</View>
<View style={{ flex: 1, flexDirection: 'row', alignItems: "flex-start", justifyContent: 'center' }}>
<Animated.View style={{ flexDirection: 'row', width: '92%', alignItems: "center", justifyContent: 'space-evenly' }}>
<TouchableOpacity style={styles.button} onPress={onLike}>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} source={Lotties.likeAnimation} style={styles.lottie} />
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={onLike}>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} source={Lotties.likeAnimation} style={styles.lottie} />
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={onLike}>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} speed={2} source={Lotties.likeAnimation} style={styles.lottie} />
</TouchableOpacity>
</Animated.View>
</View>
</View> </View>
)) </>
}
</View>
<View style={{flex : 1,flexDirection : 'row', alignItems: "flex-start", justifyContent : 'center'}}>
<Animated.View style={{flexDirection : 'row', width : '92%', alignItems: "center", justifyContent : 'space-evenly'}}>
<TouchableOpacity style={styles.button} onPress={onLike}>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} source={Lotties.likeAnimation} style={styles.lottie}/>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={onLike}>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} source={Lotties.likeAnimation} style={styles.lottie}/>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={onLike}>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} speed={2} source={Lotties.likeAnimation} style={styles.lottie}/>
</TouchableOpacity>
</Animated.View>
</View>
</View>
</>
) )
: (<View style={{justifyContent : 'center', alignItems : 'center', flex : 1, backgroundColor: "#141414"}}> : (<View style={{ justifyContent: 'center', alignItems: 'center', flex: 1, backgroundColor: "#141414" }}>
<View style={{position: "absolute"}}> <View style={{ position: "absolute" }}>
<FladLoading/> <FladLoading />
</View> </View>
<Text style={{color: "grey", fontWeight: "400", textAlign: "center", top: 100}}>Vous avez explorer toutes les spot autour de vous. <Text style={{ color: "grey", fontWeight: "400", textAlign: "center", top: 100 }}>Vous avez explorer toutes les spot autour de vous.
{"\n"}Continuer dans discoverie pour découvrir de nouvelles music basées dur vos gouts musicaux.</Text> {"\n"}Continuer dans discoverie pour découvrir de nouvelles music basées dur vos gouts musicaux.</Text>
</View>) </View>)
} }
</View> </View>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
mainSafeArea: { mainSafeArea: {
flex: 1, flex: 1,
}, },
spot : { spot: {
flex: 1, flex: 1,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
alignContent : 'center', alignContent: 'center',
flexDirection : 'column', flexDirection: 'column',
backgroundColor : '#000' backgroundColor: '#000'
}, },
lottie : { lottie: {
width : '100%', width: '100%',
}, },
button : { button: {
setOpacityTo: 0.8, setOpacityTo: 0.8,
alignItems : 'center', alignItems: 'center',
borderRadius : 100, borderRadius: 100,
justifyContent : 'center', justifyContent: 'center',
width: 61, width: 61,
height: 61, height: 61,
backgroundColor: '#24243A', backgroundColor: '#24243A',
opacity : 0.8, opacity: 0.8,
shadowRadius : 2, shadowRadius: 2,
}, },
gradient : { gradient: {
position : "absolute", position: "absolute",
top : 0, top: 0,
left : 0, left: 0,
right : 0, right: 0,
height : 209, height: 209,
}, },
}) })

@ -1,9 +1,9 @@
import * as React from 'react'; import * as React from 'react';
import {TouchableOpacity, ScrollView, View, Text, StyleSheet, Image, SafeAreaView, FlatList, Animated} from 'react-native'; import { TouchableOpacity, ScrollView, View, Text, StyleSheet, Image, SafeAreaView, FlatList, Animated } from 'react-native';
import {useSafeAreaInsets} from "react-native-safe-area-context"; import { useSafeAreaInsets } from "react-native-safe-area-context";
import {LinearGradient} from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import {useEffect, useState} from "react"; import { useEffect, useState } from "react";
import Ionicons from "@expo/vector-icons/Ionicons"; import Ionicons from "@expo/vector-icons/Ionicons";
import { SharedElement } from "react-navigation-shared-element"; import { SharedElement } from "react-navigation-shared-element";
import { NavigationProp, RouteProp, useNavigation } from "@react-navigation/native"; import { NavigationProp, RouteProp, useNavigation } from "@react-navigation/native";
@ -21,13 +21,13 @@ import SpotifyService from "../services/spotify/spotify.service";
import Music from '../Model/Music'; import Music from '../Model/Music';
import { HorizontalFlatList } from '../components/HorizontalFlatList'; import { HorizontalFlatList } from '../components/HorizontalFlatList';
import { LittleCard } from '../components/littleCard'; import { LittleCard } from '../components/littleCard';
const halfPi = Math.PI/2; const halfPi = Math.PI / 2;
// InfoScreen.sharedElement = (navigation : ReturnType<typeof useNavigation>)=>{ // InfoScreen.sharedElement = (navigation : ReturnType<typeof useNavigation>)=>{
// const music = navigation.getParam('music'); // const music = navigation.getParam('music');
// return [music.id]; // return [music.id];
// } // }
// @ts-ignore // @ts-ignore
export default function InfoScreen({route, navigation}) { export default function InfoScreen({ route, navigation }) {
const item: Music = route.params.music; const item: Music = route.params.music;
@ -35,9 +35,9 @@ export default function InfoScreen({route, navigation}) {
const [similarMusics, setSimilarMusics] = useState<Music[]>([]); const [similarMusics, setSimilarMusics] = useState<Music[]>([]);
// parralax // parralax
// parralax // parralax
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -241,13 +241,13 @@ export default function InfoScreen({route, navigation}) {
const tmpMusic: Music[] = [ const tmpMusic: Music[] = [
// new Music("La pharmacie", "Jul",require("../assets/images/jul.png")), // new Music("La pharmacie", "Jul",require("../assets/images/jul.png")),
// new Music("Deux frères", "PNL", require("../assets/images/pnl.png")), // new Music("Deux frères", "PNL", require("../assets/images/pnl.png")),
new Music("6npyDB4mn8MO1A1h666FTk","Bambina", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png","https://p.scdn.co/mp3-preview/d38052978a79adced2187cd8b6497bb10bedc452?cid=774b29d4f13844c495f206cafdad9c86"), new Music("6npyDB4mn8MO1A1h666FTk", "Bambina", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png", "https://p.scdn.co/mp3-preview/d38052978a79adced2187cd8b6497bb10bedc452?cid=774b29d4f13844c495f206cafdad9c86"),
// new Music("0qwxx9ouUc5kGmMWHglDpq","Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png",""), // new Music("0qwxx9ouUc5kGmMWHglDpq","Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png",""),
new Music("03o8WSqd2K5rkGvn9IsLy2","Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg","https://p.scdn.co/mp3-preview/c55f95de81b8c3d0df04148da1b03bd38db56e8f?cid=774b29d4f13844c495f206cafdad9c86"), new Music("03o8WSqd2K5rkGvn9IsLy2", "Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg", "https://p.scdn.co/mp3-preview/c55f95de81b8c3d0df04148da1b03bd38db56e8f?cid=774b29d4f13844c495f206cafdad9c86"),
new Music("6DPrYPPGYK218iVIZDix3i","Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png","https://p.scdn.co/mp3-preview/a9f9cb19ac1fe6db0d06b67decf8edbb25895a33?cid=774b29d4f13844c495f206cafdad9c86"), new Music("6DPrYPPGYK218iVIZDix3i", "Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png", "https://p.scdn.co/mp3-preview/a9f9cb19ac1fe6db0d06b67decf8edbb25895a33?cid=774b29d4f13844c495f206cafdad9c86"),
// new Music("Blanka", "PNL", require("../assets/images/pnl.png")), // new Music("Blanka", "PNL", require("../assets/images/pnl.png")),
new Music("5GFHFEASZeJF0gyWuDDjGE","Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png","https://p.scdn.co/mp3-preview/9e854f4905c1228482e390169eb76d8520076b8f?cid=774b29d4f13844c495f206cafdad9c86"), new Music("5GFHFEASZeJF0gyWuDDjGE", "Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png", "https://p.scdn.co/mp3-preview/9e854f4905c1228482e390169eb76d8520076b8f?cid=774b29d4f13844c495f206cafdad9c86"),
] ; ];
setSimilarMusics(tmpMusic); setSimilarMusics(tmpMusic);
} }
@ -256,137 +256,137 @@ export default function InfoScreen({route, navigation}) {
getSimilarMusics(); getSimilarMusics();
}, []); }, []);
//////////////////////////////////////////////// ////////////////////////////////////////////////
const {width, height} = useWindowDimensions(); const { width, height } = useWindowDimensions();
const [currentspot, setCurrentspot] = useState(item); const [currentspot, setCurrentspot] = useState(item);
const [sound, setSound] = useState(null); const [sound, setSound] = useState(null);
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
const loader = useSharedValue(0); const loader = useSharedValue(0);
useEffect(() => { useEffect(() => {
loader.value = isPlaying ? 1 : 0 loader.value = isPlaying ? 1 : 0
}, [isPlaying,loader ]); }, [isPlaying, loader]);
const transition = useDerivedValue(()=>{
return withTiming(loader.value, {duration : 1000})
}
)
const transition = useDerivedValue(() => {
return withTiming(loader.value, { duration: 1000 })
}
)
// const styleAniamatedButton = useAnimatedStyle(() => {
// const verticalAxis =interpolate(
// transition.value,
// [0,1],
// [circumference, 0]
// )
// return { // const styleAniamatedButton = useAnimatedStyle(() => {
// top : withSpring( verticalAxis), // const verticalAxis =interpolate(
// left : withSpring(horizontalAxis), // transition.value,
// }; // [0,1],
// [circumference, 0]
// )
// }) // return {
// top : withSpring( verticalAxis),
// left : withSpring(horizontalAxis),
// };
// })
const trackPreviewUrl = 'https://p.scdn.co/mp3-preview/08ef3b9d6dbd6bab233f5e9ca564091902767f71?cid=774b29d4f13844c495f206cafdad9c86';
const playTrackPreview = async () => {
console.log("===============================================================================================================");
console.log('get in Sound'); const trackPreviewUrl = 'https://p.scdn.co/mp3-preview/08ef3b9d6dbd6bab233f5e9ca564091902767f71?cid=774b29d4f13844c495f206cafdad9c86';
const playTrackPreview = async () => {
console.log("===============================================================================================================");
const { sound } = await Audio.Sound.createAsync({uri :item.trackPreviewUrl}); console.log('get in Sound');
//@ts-ignore
setSound(sound);
console.log('Playing Sound');
await sound.playAsync();
setIsPlaying(true);
// const soundObject = new Audio.Sound();
// try {
// await soundObject.loadAsync({ uri: trackPreviewUrl });
// await soundObject.playAsync();
// setIsPlaying(true);
// } catch (error) {
// console.log('Error loading sound:', error);
// }
};
const handlePlaySound = async () => {
if (sound === null) {
const { sound: newSound } = await Audio.Sound.createAsync(
{ uri: item.trackPreviewUrl },
{ shouldPlay: true }
);
setSound(newSound);
} else {
//@ts-ignore
await sound.playAsync();
}
};
const handleStopSound = async () => { const { sound } = await Audio.Sound.createAsync({ uri: item.trackPreviewUrl });
if (sound !== null) {
//@ts-ignore
await sound.stopAsync();
}
else{
setIsPlaying(true);
}
};
useEffect(() => {
return sound ? () => {
console.log('Unloading Sound');
//@ts-ignore //@ts-ignore
sound.unloadAsync(); setSound(sound);
} console.log('Playing Sound');
: undefined; await sound.playAsync();
}, [sound]); setIsPlaying(true);
// const soundObject = new Audio.Sound();
// try {
// await soundObject.loadAsync({ uri: trackPreviewUrl });
// await soundObject.playAsync();
// setIsPlaying(true);
// } catch (error) {
// console.log('Error loading sound:', error);
// }
};
const handlePlaySound = async () => {
if (sound === null) {
const { sound: newSound } = await Audio.Sound.createAsync(
{ uri: item.trackPreviewUrl },
{ shouldPlay: true }
);
setSound(newSound);
const sensor = useAnimatedSensor(SensorType.ROTATION); } else {
const styleAniamatedImage = useAnimatedStyle(() => { //@ts-ignore
const {yaw, pitch, roll} = sensor.sensor.value; await sound.playAsync();
const verticalAxis =interpolate( }
pitch,
[-halfPi*2,halfPi*2],
[-45, 45]
)
const horizontalAxis =interpolate(
roll,
[-halfPi*2,halfPi*2],
[-45, 45]
)
return {
top : withSpring( verticalAxis),
left : withSpring(horizontalAxis),
}; };
}) const handleStopSound = async () => {
if (sound !== null) {
const animationState = new Value(State.UNDETERMINED); //@ts-ignore
const playMusic = async (id: string) => { await sound.stopAsync();
try { }
const service = new SpotifyService("BQC4k_OPQXENwmm2S8qLm9whlJT9IjeKsuG6kJNyVCSd88b0L-zOY84VqwvQxFsc9G3GvtPyUMezwxi8BBBloitzbhWX5tmTKTaLsJosGTnb7xivwNhRv0-LnNYbZWB24ZGAg0xPmDLn0yYmYlo7M_SMK5cCZdYQcZNXAuMYaI18GVXKoICBaKfCn4GcqBiRRgXyCVQnNGU4") ; else {
console.log("=====================================================)))))))))))))))"+id+"================================") setIsPlaying(true);
await service.playMusic(id); }
}catch(error){} };
useEffect(() => {
return sound ? () => {
console.log('Unloading Sound');
//@ts-ignore
sound.unloadAsync();
}
: undefined;
}, [sound]);
const sensor = useAnimatedSensor(SensorType.ROTATION);
const styleAniamatedImage = useAnimatedStyle(() => {
const { yaw, pitch, roll } = sensor.sensor.value;
const verticalAxis = interpolate(
pitch,
[-halfPi * 2, halfPi * 2],
[-45, 45]
)
const horizontalAxis = interpolate(
roll,
[-halfPi * 2, halfPi * 2],
[-45, 45]
)
return {
top: withSpring(verticalAxis),
left: withSpring(horizontalAxis),
};
})
const animationState = new Value(State.UNDETERMINED);
const playMusic = async (id: string) => {
try {
const service = new SpotifyService("BQC4k_OPQXENwmm2S8qLm9whlJT9IjeKsuG6kJNyVCSd88b0L-zOY84VqwvQxFsc9G3GvtPyUMezwxi8BBBloitzbhWX5tmTKTaLsJosGTnb7xivwNhRv0-LnNYbZWB24ZGAg0xPmDLn0yYmYlo7M_SMK5cCZdYQcZNXAuMYaI18GVXKoICBaKfCn4GcqBiRRgXyCVQnNGU4");
console.log("=====================================================)))))))))))))))" + id + "================================")
await service.playMusic(id);
} catch (error) { }
} }
const tmpMusic2: Music[] = [ const tmpMusic2: Music[] = [
// new Music("La pharmacie", "Jul",require("../assets/images/jul.png")), // new Music("La pharmacie", "Jul",require("../assets/images/jul.png")),
// new Music("Deux frères", "PNL", require("../assets/images/pnl.png")), // new Music("Deux frères", "PNL", require("../assets/images/pnl.png")),
new Music("6npyDB4mn8MO1A1h666FTk","Bambina", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png","https://p.scdn.co/mp3-preview/d38052978a79adced2187cd8b6497bb10bedc452?cid=774b29d4f13844c495f206cafdad9c86"), new Music("6npyDB4mn8MO1A1h666FTk", "Bambina", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png", "https://p.scdn.co/mp3-preview/d38052978a79adced2187cd8b6497bb10bedc452?cid=774b29d4f13844c495f206cafdad9c86"),
// new Music("0qwxx9ouUc5kGmMWHglDpq","Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png",""), // new Music("0qwxx9ouUc5kGmMWHglDpq","Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png",""),
new Music("03o8WSqd2K5rkGvn9IsLy2","Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg","https://p.scdn.co/mp3-preview/c55f95de81b8c3d0df04148da1b03bd38db56e8f?cid=774b29d4f13844c495f206cafdad9c86"), new Music("03o8WSqd2K5rkGvn9IsLy2", "Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg", "https://p.scdn.co/mp3-preview/c55f95de81b8c3d0df04148da1b03bd38db56e8f?cid=774b29d4f13844c495f206cafdad9c86"),
new Music("6DPrYPPGYK218iVIZDix3i","Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png","https://p.scdn.co/mp3-preview/a9f9cb19ac1fe6db0d06b67decf8edbb25895a33?cid=774b29d4f13844c495f206cafdad9c86"), new Music("6DPrYPPGYK218iVIZDix3i", "Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png", "https://p.scdn.co/mp3-preview/a9f9cb19ac1fe6db0d06b67decf8edbb25895a33?cid=774b29d4f13844c495f206cafdad9c86"),
// new Music("Blanka", "PNL", require("../assets/images/pnl.png")), // new Music("Blanka", "PNL", require("../assets/images/pnl.png")),
new Music("5GFHFEASZeJF0gyWuDDjGE","Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png","https://p.scdn.co/mp3-preview/9e854f4905c1228482e390169eb76d8520076b8f?cid=774b29d4f13844c495f206cafdad9c86"), new Music("5GFHFEASZeJF0gyWuDDjGE", "Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png", "https://p.scdn.co/mp3-preview/9e854f4905c1228482e390169eb76d8520076b8f?cid=774b29d4f13844c495f206cafdad9c86"),
] ; ];
return ( return (
<View style={styles.body}> <View style={styles.body}>
<View style={styles.backgroundSection}> <View style={styles.backgroundSection}>
@ -403,83 +403,84 @@ const styleAniamatedImage = useAnimatedStyle(() => {
/> />
<LinearGradient style={styles.gradientFade} <LinearGradient style={styles.gradientFade}
// Button Linear Gradient // Button Linear Gradient
colors={['rgba(14,14,14,0)', 'rgba(14,14,14,0.7)', 'rgba(14,14,14,1)', 'rgba(14,14,14,1)']}> colors={['rgba(14,14,14,0)', 'rgba(14,14,14,0.7)', 'rgba(14,14,14,1)', 'rgba(14,14,14,1)']}>
</LinearGradient> </LinearGradient>
</View> </View>
<View style={styles.background1}> <View style={styles.background1}>
<TouchableOpacity onPress={() => navigation.goBack()} style={{zIndex: 100}}> <TouchableOpacity onPress={() => navigation.goBack()} style={{ zIndex: 100 }}>
<Ionicons name="ios-arrow-back" size={30} color="white" style={styles.backButton}/> <Ionicons name="ios-arrow-back" size={30} color="white" style={styles.backButton} />
</TouchableOpacity> </TouchableOpacity>
<ScrollView style={styles.list} showsVerticalScrollIndicator={false} scrollEventThrottle={4} <ScrollView style={styles.list} showsVerticalScrollIndicator={false} scrollEventThrottle={4}
> >
<View style={styles.section1}> <View style={styles.section1}>
<View style={{ flex: 1, justifyContent : 'flex-start', alignItems : 'center' }}> <View style={{ flex: 1, justifyContent: 'flex-start', alignItems: 'center' }}>
{/* <SharedElement id={spot.name} style={{ flex: 1 }}> */} {/* <SharedElement id={spot.name} style={{ flex: 1 }}> */}
<View> <View>
<SharedElement id ={item.id}> <SharedElement id={item.id}>
<Animated.Image <Animated.Image
source={{ source={{
uri:currentspot.image , uri: currentspot.image,
}} }}
style={[ style={[
{ {
width: 370, width: 370,
height: 370, height: 370,
borderRadius : 24, borderRadius: 24,
resizeMode: 'stretch', resizeMode: 'stretch',
},styleAniamatedImage }, styleAniamatedImage
]} ]}
/> />
</SharedElement> </SharedElement>
<Button title="Play Track On Device" <Button title="Play Track On Device"
onPress={() => { onPress={() => {
playMusic(currentspot.id) playMusic(currentspot.id)
// promptAsync(); // promptAsync();
}} }}
/> />
</View> </View>
{/* Button */} {/* Button */}
{/* <TapGestureHandler {...gestureHandler}> */} {/* <TapGestureHandler {...gestureHandler}> */}
<Animated.View> <Animated.View>
<TouchableOpacity style={{ <TouchableOpacity style={{
backgroundColor: '#1DB954', backgroundColor: '#1DB954',
paddingVertical: 12, paddingVertical: 12,
paddingHorizontal: 24, paddingHorizontal: 24,
borderRadius: 24, borderRadius: 24,
}} onPressIn={handlePlaySound} }} onPressIn={handlePlaySound}
onPressOut={handleStopSound} onPressOut={handleStopSound}
onLongPress={handlePlaySound} onLongPress={handlePlaySound}
delayLongPress={1000}> delayLongPress={1000}>
<Text style={ { <Text style={{
color: '#fff', color: '#fff',
fontSize: 16, fontSize: 16,
fontWeight: 'bold',}}> fontWeight: 'bold',
}}>
{isPlaying ? 'Playing...' : 'Play'} {isPlaying ? 'Playing...' : 'Play'}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</Animated.View> </Animated.View>
</View> </View>
</View> </View>
{similarMusics.length !== 0 && ( {similarMusics.length !== 0 && (
// <HorizontalFlatList renderCell={littleCard} title={'Simillar Music'} data={similarMusics}> // <HorizontalFlatList renderCell={littleCard} title={'Simillar Music'} data={similarMusics}>
// </HorizontalFlatList> // </HorizontalFlatList>
<HorizontalFlatList title={'Simillar Music'} data={tmpMusic2}> <HorizontalFlatList title={'Simillar Music'} data={tmpMusic2}>
{(props) => ( {(props) => (
<LittleCard image={props.image} title ={props.title}/> <LittleCard image={props.image} title={props.title} />
)} )}
</HorizontalFlatList> </HorizontalFlatList>
)} )}

@ -1,16 +1,16 @@
export class AuthentificationService { export class AuthentificationService {
constructor(private auth: Auth, private http: HttpClient) { } constructor(private auth: Auth, private http: HttpClient) { }
name = "toto"; name = "toto";
async register({ email, password }) { async register({ email, password }) {
try { try {
const user = await createUserWithEmailAndPassword(this.auth, email, password); const user = await createUserWithEmailAndPassword(this.auth, email, password);
return user; return user;
} catch (e) { } catch (e) {
return null; return null;
} }
} }
async login({ email, password }) { async login({ email, password }) {
// should for all method use a cloud function to creata user // should for all method use a cloud function to creata user
try { try {

@ -2,73 +2,73 @@ import axios from "axios";
import MusicFactory from "../../Model/factory/MusicFactory"; import MusicFactory from "../../Model/factory/MusicFactory";
import Music from "../../Model/Music"; import Music from "../../Model/Music";
import { FetchOptions, RequestHandler } from "./spotifyRequestHandler/utils"; import { FetchOptions, RequestHandler } from "./spotifyRequestHandler/utils";
export class MusicMinimal { export class MusicMinimal {
public id : string; public id: string;
public title: string; public title: string;
public image: string; public image: string;
constructor(id : string,title: string, bio: string, image: string, trackPreviewUrl: string) { constructor(id: string, title: string, bio: string, image: string, trackPreviewUrl: string) {
this.title = title; this.title = title;
this.image = image; this.image = image;
this.id = id; this.id = id;
} }
} }
export default class SpotifyService implements IspotifyService { export default class SpotifyService implements IspotifyService {
private readonly API_URL = "https://flad-api-production.up.railway.app/api/"; private readonly API_URL = "https://flad-api-production.up.railway.app/api/";
private spotifyRequestHandler = new RequestHandler(); private spotifyRequestHandler = new RequestHandler();
private readonly token : string; private readonly token: string;
constructor(token : string) { constructor(token: string) {
this.token = token; this.token = token;
} }
// get id(){ // get id(){
// return this.identification; // return this.identification;
// } // }
// async apiAuth(url : string) { // async apiAuth(url : string) {
// await this.identification.setCode(url); // await this.identification.setCode(url);
// // this.request = ApiSpotifyRequests(await this.identification.createToken()); // // this.request = ApiSpotifyRequests(await this.identification.createToken());
// } // }
public async getMusicById(idMusic : string): Promise<Music>{ public async getMusicById(idMusic: string): Promise<Music> {
var requestData :string = '/tracks/' + idMusic; var requestData: string = '/tracks/' + idMusic;
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined, this.token);
if (respMusic.status != 200) { if (respMusic.status != 200) {
} }
return MusicFactory.mapFromSpotifyTrack(respMusic.data); return MusicFactory.mapFromSpotifyTrack(respMusic.data);
} }
public async getUserCurrentMusic(): Promise<string | null>{ public async getUserCurrentMusic(): Promise<string | null> {
var requestData :string = '/me/player/currently-playing'; var requestData: string = '/me/player/currently-playing';
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined, this.token);
if (respMusic.status != 200) { if (respMusic.status != 200) {
return null; return null;
} }
console.log(respMusic.data.items.track.id)
return respMusic.data.items.track.id; return respMusic.data.items.track.id;
} }
public async getUserRecentlyPlayedMusic(): Promise<string | null>{ public async getUserRecentlyPlayedMusic(): Promise<string | null> {
var requestData :string = '/me/player/recently-played'; var requestData: string = '/me/player/recently-played';
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined, this.token);
if (respMusic.status != 200) { if (respMusic.status != 200) {
} }
if (respMusic.data.items.length <= 0) { if (respMusic.data.items.length <= 0) {
return null; return null;
} }
return respMusic.data.items[0].track.id; return respMusic.data.items[0].track.id;
} }
public async playMusic(idMusic : string): Promise<void>{ public async playMusic(idMusic: string): Promise<void> {
var requestData :string = '/me/player/play'; var requestData: string = '/me/player/play';
const fetchOptions: FetchOptions = { const fetchOptions: FetchOptions = {
method: 'PUT', method: 'PUT',
body: { body: {
uris: [`spotify:track:${idMusic}`], uris: [`spotify:track:${idMusic}`],
position_ms: 0 position_ms: 0
} }
}; };
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions, this.token);
console.log(respMusic.data);
// need to handle when // need to handle when
// if (respMusic.status != 200) { // if (respMusic.status != 200) {
// if (respMusic.status == 400 && respMusic.data.message =='need to use Spotify premium'){ // if (respMusic.status == 400 && respMusic.data.message =='need to use Spotify premium'){
@ -80,18 +80,18 @@ export default class SpotifyService implements IspotifyService {
// console.log(respMusic.data); // console.log(respMusic.data);
// } // }
return ; return;
} }
public async searchMusic(text : string): Promise<Music[]>{ public async searchMusic(text: string): Promise<Music[]> {
var requestData :string = '/search'; var requestData: string = '/search';
const fetchOptions: FetchOptions = { const fetchOptions: FetchOptions = {
params: { params: {
q: text, q: text,
type: 'track' type: 'track'
} }
}; };
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions, this.token);
if (respMusic.status != 200) { if (respMusic.status != 200) {
} }
@ -105,31 +105,31 @@ export default class SpotifyService implements IspotifyService {
// const artistNames = artists.map((artist: any) => artist.name).join(', '); // const artistNames = artists.map((artist: any) => artist.name).join(', ');
// const linkCover = album?.images[0]?.url || ''; // const linkCover = album?.images[0]?.url || '';
// return new Music(id, name, artistNames, linkCover); // return new Music(id, name, artistNames, linkCover);
}); });
return tracks; return tracks;
} }
// tempo version // tempo version
public async getMusicMoreDetails(idMusic : string): Promise<string>{ public async getMusicMoreDetails(idMusic: string): Promise<string> {
var requestData :string = '/audio-features/' + idMusic; var requestData: string = '/audio-features/' + idMusic;
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined, this.token);
if (respMusic.status != 200) { if (respMusic.status != 200) {
} }
return respMusic.data.audio_features.tempo; return respMusic.data.audio_features.tempo;
} }
public async getRelatedArtist(idArtist : string): Promise<string>{ public async getRelatedArtist(idArtist: string): Promise<string> {
var requestData :string = '/artists/' + idArtist + '/related-artists'; var requestData: string = '/artists/' + idArtist + '/related-artists';
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined, this.token);
if (respMusic.status != 200) { if (respMusic.status != 200) {
} }
return respMusic.data.audio_features.tempo; return respMusic.data.audio_features.tempo;
} }
public async getArtistTopTracks(idArtist : string): Promise<string>{ public async getArtistTopTracks(idArtist: string): Promise<string> {
var requestData :string = '/artists/' + idArtist + '/top-tracks'; var requestData: string = '/artists/' + idArtist + '/top-tracks';
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined, this.token);
if (respMusic.status != 200) { if (respMusic.status != 200) {
} }
@ -137,21 +137,21 @@ export default class SpotifyService implements IspotifyService {
} }
public async addItemToPlayList(playlistId : string, idMusic : string): Promise<void>{ public async addItemToPlayList(playlistId: string, idMusic: string): Promise<void> {
var requestData :string = '/playlists/' + playlistId + '/tracks'; var requestData: string = '/playlists/' + playlistId + '/tracks';
const fetchOptions: FetchOptions = { const fetchOptions: FetchOptions = {
method: 'POST', method: 'POST',
body: { body: {
uris: [`spotify:track:${idMusic}`] uris: [`spotify:track:${idMusic}`]
} }
}; };
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions, this.token);
console.log(respMusic.data); console.log(respMusic.data);
return ; return;
} }
public async createPlayList(userId : string,name? : string,description? : string): Promise<void>{ public async createPlayList(userId: string, name?: string, description?: string): Promise<void> {
var requestData :string = '/users/' + encodeURIComponent(userId) + '/playlists'; var requestData: string = '/users/' + encodeURIComponent(userId) + '/playlists';
const fetchOptions: FetchOptions = { const fetchOptions: FetchOptions = {
method: 'POST', method: 'POST',
@ -160,10 +160,10 @@ export default class SpotifyService implements IspotifyService {
"name": name || "New Flad Playlist", "name": name || "New Flad Playlist",
"description": description || "New Flad Playlist", "description": description || "New Flad Playlist",
} }
}; };
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token); const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions, this.token);
console.log(respMusic.data); console.log(respMusic.data);
return ; return;
} }
// public async getSimilarTrack(musicId : string,limit : number =1,market? : string): Promise<Music[]>{ // public async getSimilarTrack(musicId : string,limit : number =1,market? : string): Promise<Music[]>{
@ -205,43 +205,43 @@ export default class SpotifyService implements IspotifyService {
// } // }
public async getSimilarTrack(musicId: string, limit: number = 1, market?: string): Promise<Music[]> { public async getSimilarTrack(musicId: string, limit: number = 1, market?: string): Promise<Music[]> {
const requestData: string = '/recommendations/' + const requestData: string = '/recommendations/' +
'?limit=' + limit + '?limit=' + limit +
'&market=FR' + '&market=FR' +
'&seed_tracks=' + musicId; '&seed_tracks=' + musicId;
console.log(musicId, "=============ouioui=================") console.log(musicId, "=============ouioui=================")
var respSimilarMusic; var respSimilarMusic;
try { try {
console.log( "=======================1=========",requestData,this.token ) console.log("=======================1=========", requestData, this.token)
respSimilarMusic= await this.spotifyRequestHandler.spotifyFetch(requestData, {}, this.token); respSimilarMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, {}, this.token);
} catch (error) { } catch (error) {
console.log(error, "===================================spot Service"); console.log(error, "===================================spot Service");
} }
if (!respSimilarMusic || !respSimilarMusic.data.tracks) { if (!respSimilarMusic || !respSimilarMusic.data.tracks) {
return []; return [];
} }
const similars: Music[] = await Promise.all( const similars: Music[] = await Promise.all(
respSimilarMusic.data.tracks.map(async (trackData: any) => { respSimilarMusic.data.tracks.map(async (trackData: any) => {
if (trackData.id !=undefined) { if (trackData.id != undefined) {
const data = await this.getMusicById(trackData.id); const data = await this.getMusicById(trackData.id);
return data; return data;
} }
}) })
) )
return similars.filter((music: Music | undefined) => !!music) as Music[]; return similars.filter((music: Music | undefined) => !!music) as Music[];
// return similars; // return similars;
} }
async getSpotifyCredentials() { async getSpotifyCredentials() {
const res = await axios.get(this.API_URL) const res = await axios.get(this.API_URL)
// then verify error // then verify error
const spotifyCredentials = res.data; const spotifyCredentials = res.data;
return spotifyCredentials return spotifyCredentials
} }
} }

@ -13,14 +13,14 @@ export interface FetchOptions {
body?: Record<string, string | boolean | number | (string | boolean | number)[]>; body?: Record<string, string | boolean | number | (string | boolean | number)[]>;
} }
export class RequestHandler{ export class RequestHandler {
private _version: `v${number}` = 'v1'; private _version: `v${number}` = 'v1';
get version(): string { get version(): string {
return this._version; return this._version;
} }
public async spotifyFetch(url: string, options: FetchOptions = {}, token: string) : Promise<AxiosResponse<any,any>> { public async spotifyFetch(url: string, options: FetchOptions = {}, token: string): Promise<AxiosResponse<any, any>> {
console.log(options+ "sds============="); console.log(options + "sds=============");
const resp = await axios({ const resp = await axios({
url: `https://api.spotify.com/${this.version}${url}`, url: `https://api.spotify.com/${this.version}${url}`,
method: options.method || 'GET', method: options.method || 'GET',
@ -32,7 +32,7 @@ export class RequestHandler{
}, },
data: options.body data: options.body
}); });
console.log(")))))))))))))))))))",resp.request, "(((((((((((((((((((("); console.log(")))))))))))))))))))", resp.request, "((((((((((((((((((((");
// console.log(resp, "frfrfrfr"); // console.log(resp, "frfrfrfr");
return resp; return resp;
// if ( // if (

Loading…
Cancel
Save