merge resume
continuous-integration/drone/push Build is passing Details

pull/15/head
David D'ALMEIDA 2 years ago
commit 5228d86392

@ -22,7 +22,7 @@ class SpotifyController implements Controller {
this.router.get(`${this.path}/exchange`,this.login);
this.router.get(`${this.path}/callback`,this.getAccessToken);
// this.router.post(`${this.path}/refresh`,this.getRefreshToken);
this.router.get(`${this.path}/play/:musicId`, this.getMusic);
// this.router.get(`${this.path}/play/:musicId`, this.getMusic);
this.router.get(`${this.path}/spot`, this.getSpot);
}
@ -137,10 +137,6 @@ class SpotifyController implements Controller {
}
public getMusic(){
return null;
}
public getSpot = async (
req: Request,

@ -219,8 +219,9 @@ class UserController implements Controller {
console.log('Impossible de convertir la chaîne en nombre');
}
//}
const currentMusicId = req.body.currentMusicId;
const userId = req.user.idFlad;
const data = await this.locationService.getNearUser(userId,latitude,longitude);
const data = await this.locationService.getNearUser(userId,latitude,longitude, currentMusicId);
console.log(data);
res.status(201).send(data);

@ -18,6 +18,9 @@ const locationSchema = new Schema(
type: Number,
required: true,
},
currentMusicId : {
type: String,
}
},

@ -32,10 +32,12 @@ export class UserLocation {
uuid: string;
latitude : number;
longitude: number;
constructor(uuid: string, latitude: number, longitude: number){
currentMusicId : string;
constructor(uuid: string, latitude: number, longitude: number, currentMusicId : string) {
this.uuid = uuid;
this.latitude = latitude;
this.longitude = longitude;
this.currentMusicId = currentMusicId;
}
}

@ -6,11 +6,11 @@ import LocationSchema from "../database/schema/LocationSchema";
class LocationService {
private locationCollection = LocationSchema;
// private API_KEY : string = "AIzaSyBFCEAtmhZ8jvw84UTQvX3Aqpr66GVqB_A";
public async getNearUser(idFlad : string, latitude : number, longitude : number)
public async getNearUser(idFlad : string, latitude : number, longitude : number, currentMusicId: string)
{
await this.locationCollection.findOneAndUpdate(
{ idFlad },
{ idFlad, latitude, longitude },
{ idFlad, latitude, longitude, currentMusicId },
{ upsert: true }
);
@ -22,18 +22,18 @@ class LocationService {
let dbUsersList:UserLocation[] = [];
snapshot.forEach(doc => {
dbUsersList.push(new UserLocation(doc.idFlad,doc.latitude,doc.longitude));
dbUsersList.push(new UserLocation(doc.idFlad,doc.latitude,doc.longitude, doc.currentMusicId));
console.log(doc.idFlad, '=>', doc);
});
// missing the curent music
let listUser: string[] = [];
let listUser: {userid: string, music : string}[] = [];
dbUsersList.forEach(user => {
console.log(user);
const dist = this.distanceBetween(latitude , longitude , user.latitude, user.longitude);
console.log(user.uuid,dist);
if (dist <= 100) {
listUser.push(user.uuid);
listUser.push({userid : user.uuid, music : user.currentMusicId});
}
});

@ -1,14 +1,14 @@
export default class Music {
private id : string;
private name : string;
private artist : string;
private linkCover : string; // Image.source
// export default class Music {
// private id : string;
// private name : string;
// private artist : string;
// private linkCover : string; // Image.source
constructor(id : string, name : string, artist : string, linkCover : string){
this.id = id;
this.name = name;
this.artist = artist;
this.linkCover = linkCover;
}
// constructor(id : string, name : string, artist : string, linkCover : string){
// this.id = id;
// this.name = name;
// this.artist = artist;
// this.linkCover = linkCover;
// }
}
// }

@ -2,7 +2,7 @@ import Music from "./Music";
export class Spot {
private _userId : string;
public _music : Music;
private _music : Music;
constructor(userId : string, music : Music){
this._userId = userId;
this._music = music;
@ -10,8 +10,13 @@ export class Spot {
get userSpotifyId(): string {
return this._userId;
}
get idSpotify(): Music {
return this._music;
}
set userSpotifyId(value: string) {
this._userId = value;
}
get music(): Music {
return this._music;
}
set music(value: Music) {
this._music = value;
}
}

@ -5,7 +5,9 @@ export default class MusicFactory {
const music = new Music(
jsonMusic.id,
jsonMusic.name,
jsonMusic.album.images[0].url
"",
jsonMusic.album.images[0].url,
jsonMusic.preview_url
);
return music;
}

@ -7,7 +7,7 @@
"icon": "./assets/icons/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/images/RedFlady.png",
"image": "./assets/icons/splash.png",
"resizeMode": "contain",
"backgroundColor": "#1d2129"
},

@ -11,7 +11,7 @@ const SCREEN_WIDTH = Dimensions.get('window').width
interface CardProps {
title: string;
image: any;
onSwipe: (direction: "left" | "right") => void;
onSwipe: (direction: "left" | "right" | "down") => void;
}
type ContextType = {
translateX: number;
@ -47,7 +47,12 @@ const Card = ({ title, image, onSwipe } : CardProps) => {
} else if (translateX.value < -160) {
runOnJS(onSwipe)("left");
// onSwipe("left");
} else {
}else if (translateY.value > 250) {
runOnJS(onSwipe)("down");
// onSwipe("left");
}
else {
translateX.value = withSpring(0);
translateY.value = withSpring(0);
}

@ -1,24 +1,33 @@
import React from 'react';
import { StyleSheet, Text, View , Image } from 'react-native';
import { SharedElement } from 'react-navigation-shared-element';
import { useSelector } from 'react-redux';
import normalize from '../components/Normalize';
type CustomCardMusic = { //Props
image: ImageSource;
image: string;
title: string;
description: string;
id : string;
}
export default function CardMusic(CBP: CustomCardMusic) {
const currentMusic = useSelector(state => state.appReducer.currentMusic);
const source = typeof CBP.image === 'string' ? { uri: CBP.image } : CBP.image;
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<Image source={source} style={styles.image}/>
</View>
<View style={styles.textContainer}>
<Text style={styles.title}>{CBP.title}</Text>
<Text style={styles.description}>{CBP.description}</Text>
{/* currentMusic.id === CBP.id && styles.currentMusic */}
<Text style={[styles.title]}>{CBP.title}</Text>
<Text style={[styles.description]}>{CBP.description}</Text>
</View>
</View>
);
@ -59,5 +68,8 @@ const styles = StyleSheet.create({
description: {
color: 'white',
fontSize: normalize(18)
},
currentMusic: {
color: 'red'
}
});

@ -0,0 +1,145 @@
// import React, { useEffect, useRef } from 'react';
// import { StyleSheet, Text, View , Image } from 'react-native';
// import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
// import { SharedElement } from 'react-navigation-shared-element';
// import { useSelector } from 'react-redux';
// import normalize from '../components/Normalize';
// import SpotifyService from '../services/spotify/spotify.service';
// export default function CurrentMusic() {
// const animatedStyle = useAnimatedStyle(() => {
// return {
// transform: [
// { scale: withTiming(139.929, { duration: 1000 }) }
// ]
// }
// });
// const centerX = useSharedValue(0);
// const centerY = useSharedValue(0);
// const scale = useSharedValue(0);
// const width = useSharedValue(0);
// const height = useSharedValue(0);
// const rippleOpacity = useSharedValue(1);
// const rStyle = useAnimatedStyle(() => {
// const circleRadius = Math.sqrt(width.value ** 2 + height.value ** 2);
// const translateX = centerX.value - circleRadius;
// const translateY = centerY.value - circleRadius;
// return {
// width: circleRadius * 2,
// height: circleRadius * 2,
// borderRadius: circleRadius,
// opacity: rippleOpacity.value,
// backgroundColor: 'rgba(0,0,0,0.2)',
// position: 'absolute',
// top: 0,
// left: 0,
// transform: [
// { translateX },
// { translateY },
// {
// scale: scale.value,
// },
// ],
// };
// });
// useEffect(() => {
// // withTiming, withSpring
// rippleOpacity.value = 1;
// scale.value = withTiming(1, { duration: 1000 });
// }, [rippleOpacity,scale]);
// return (
// <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,
// 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>
// </View>
// );
// }
import React, { useEffect, useRef } from 'react';
import { StyleSheet, Text, View , Image } from 'react-native';
import Animated, { useAnimatedStyle, useDerivedValue, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
import { SharedElement } from 'react-navigation-shared-element';
import { useSelector } from 'react-redux';
import normalize from '../components/Normalize';
import SpotifyService from '../services/spotify/spotify.service';
export default function CurrentMusic() {
const transition = useDerivedValue(() => {
return withSpring(value.value);
});
return (
<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,
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>
</View>
);
}

@ -0,0 +1,52 @@
import { View, StyleSheet, Dimensions,Text, Image, Pressable, TouchableWithoutFeedback, TouchableOpacity, TouchableHighlight, FlatList } from "react-native";
import Animated, {
Layout,
Transition,
ZoomIn,
ZoomOut,
} from "react-native-reanimated";
const { width } = Dimensions.get("window");
const SIZE = width / 3;
import { Feather as Icon } from "@expo/vector-icons";
import Music from "../Model/Music";
import { State, TapGestureHandler } from "react-native-gesture-handler";
import { useRef, useState } from "react";
interface HorizontalFlatListProps {
// React.ReactNode;
renderCell: (image: string, titre : string) => React.ReactElement
title : string;
data : any[];
}
export const HorizontalFlatList = ({ title, data, renderCell}: HorizontalFlatListProps) => {
return (
<View style={styles.similarSection}>
<Text style={styles.similarTitle} >{title}</Text>
<FlatList
showsHorizontalScrollIndicator={false}
data={data}
horizontal={true}
keyExtractor={item => item.id}
renderItem={({item}) =>{
return renderCell(item.image, image.titre);
}}
/></View>
);
};
const styles = StyleSheet.create({
similarSection: {
paddingTop: 30
},
similarTitle: {
color: "#2998FD",
paddingLeft: 35,
fontSize: 17,
fontWeight: "600",
paddingBottom: 20
}
});

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

@ -0,0 +1,29 @@
import {TouchableOpacity, ScrollView, View, Text, StyleSheet, Image, SafeAreaView, FlatList, Animated} from 'react-native';
export default function littleCard ({image,titre}){
return (
<View style={styles.similarContainer}>
<Image source={{uri: image}} style={styles.similarPoster}></Image>
<Text numberOfLines={2} style={styles.similarTitleFilm}>{titre}
</Text>
</View>
)
}
const styles = StyleSheet.create({
similarContainer: {
width: 90,
marginHorizontal: 7
},
similarTitleFilm: {
color: "#DADADA",
paddingTop: 5,
fontWeight: "300"
},
similarPoster: {
height: 130,
width: 90,
borderRadius: 8
}
})

@ -1,6 +1,8 @@
export const cards = [{
musicName : "Je bibi",
name : "Kaaris",
import Music from "../Model/Music";
import { Spot } from "../Model/Spot";
export const cards= [{
name : "blue",
sourceUrl : "https://th.bing.com/th/id/R.dbf87f0d8cbfd078ab6a589a5d921994?rik=1%2f6KliMpOAeh8A&pid=ImgRaw&r=0",
index : 4
},
@ -42,3 +44,43 @@ export const cards = [{
},
]
const spotArray: Spot[] = [
new Spot("1", new Music("1", "Title 1", "Bio 1", "Image 1", "TrackPreviewUrl 1")),
new Spot("2", new Music("2", "Title 2", "Bio 2", "Image 2", "TrackPreviewUrl 2")),
new Spot("3", new Music("3", "Title 3", "Bio 3", "Image 3", "TrackPreviewUrl 3")),
new Spot("4", new Music("4", "Title 4", "Bio 4", "Image 4", "TrackPreviewUrl 4")),
new Spot("5", new Music("5", "Title 5", "Bio 5", "Image 5", "TrackPreviewUrl 5")),
];
export const spotArray2: Spot[] = [
new Spot("1", new Music("6KNw3UKRp3QRsO7Cf4ASVE",
"MOLLY - A COLORS SHOW",
"Tame Impala",
"https://i.scdn.co/image/ab67616d0000b2734299eb40408fc73ce8bf490a",
"https://p.scdn.co/mp3-preview/4faf99856f15e03a09d50b91006efd3205606866?cid=774b29d4f13844c495f206cafdad9c86")
),
new Spot("2", new Music("5yHoANSze7sGzhn9MUarH3",
"Passat",
"Silk Sonic, Bruno Mars, Anderson .Paak",
"https://i.scdn.co/image/ab67616d0000b273e9df9b5a7df491536c51c922",
"https://p.scdn.co/mp3-preview/0bb7472026a00790950fc231fe61963ef7cc867b?cid=774b29d4f13844c495f206cafdad9c86")
),
new Spot("3", new Music("7suNqxRED5CrwyZSzYC0nT",
"Extendo",
"Kali Uchis",
"https://i.scdn.co/image/ab67616d0000b273b856464c40a062d1723a21f2",
"https://p.scdn.co/mp3-preview/5398121f6295965e3c7cad8a6dca5667ba7f4713?cid=774b29d4f13844c495f206cafdad9c86")
),
new Spot("4", new Music("07JqNLmPUJSlcouGQoJlzq",
"Addiction",
"Harry Styles",
"https://i.scdn.co/image/ab67616d0000b2739297f238f237431d56c67460",
"https://p.scdn.co/mp3-preview/33d12e9e5a3dd3394b1649d515912260b01579dd?cid=774b29d4f13844c495f206cafdad9c86")
),
new Spot("5", new Music("5Ylp75kdffyJSwISRPqEiL",
"La Vidéo",
"Harry Styles",
"https://i.scdn.co/image/ab67616d0000b2738900d48677696015bf325b8b",
"https://p.scdn.co/mp3-preview/4fff3f8d76a422f42cea39f001836a3d54937fc4?cid=774b29d4f13844c495f206cafdad9c86")
)
];

@ -1,12 +1,16 @@
export default class Music {
private _id : string;
private _title: string;
private _bio: string;
private _image: ImageSource;
private _image: string;
private _trackPreviewUrl : string;
constructor(title: string, bio: string, image: ImageSource) {
constructor(id : string,title: string, bio: string, image: string, trackPreviewUrl: string) {
this._title = title;
this._bio = bio;
this._image = image;
this._id = id;
this._trackPreviewUrl = trackPreviewUrl;
}
get title(): string {
@ -25,11 +29,27 @@ export default class Music {
this._bio = value;
}
get image(): ImageSource {
get image(): string {
return this._image;
}
set image(value: ImageSource) {
set image(value: string) {
this._image = value;
}
get id(): string {
return this._id;
}
set id(value: string) {
this._id = value;
}
get trackPreviewUrl(): string {
return this._trackPreviewUrl;
}
set trackPreviewUrl(value: string) {
this._trackPreviewUrl = value;
}
}

@ -2,20 +2,28 @@ import React from 'react';
import Favorite from '../screens/Favorite';
import { createStackNavigator } from '@react-navigation/stack';
import { ArtistLayout } from '../components/Genre';
import MusicDetail from '../screens/MusicDetail';
import InfoScreen from '../screens/testPage';
import { createSharedElementStackNavigator } from 'react-navigation-shared-element';
import CurrentMusic from '../components/CurrentMusic';
const Stack = createSharedElementStackNavigator();
export default function MusicNavigation() {
const Stack = createStackNavigator();
return (
<Stack.Navigator initialRouteName="Favorite">
<Stack.Navigator initialRouteName="Favorite" screenOptions={{gestureEnabled: true, headerShown: false, cardOverlayEnabled: true, cardStyle: {backgroundColor: "transparent"}}} >
<Stack.Screen
name="Favorite"
component={Favorite}
options={{ headerShown: false }}
/>
<Stack.Screen
name="MusicDetail"
component={InfoScreen}
sharedElements ={(route)=> {return [route.params.music.id]}}
/>
<Stack.Screen
name="Genre"
component={ArtistLayout}
options={{ headerShown: false }}
component={CurrentMusic}
/>
</Stack.Navigator>
)

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import { View, StyleSheet, Platform } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
@ -11,6 +11,9 @@ import FontAwesome from 'react-native-vector-icons/FontAwesome';
import SpotNavigation from './SpotNavigation';
import Login from '../screens/login';
import FladLoading from '../components/FladLoadingScreen';
import { useDispatch, useSelector } from 'react-redux';
import { getFavoritesMusic } from '../redux/actions/appActions';
// import { fetchFavoritesMusic } from '../redux/thunk/spotThunk';
export default function Navigation() {
const BottomTabNavigator = createBottomTabNavigator();
@ -23,6 +26,15 @@ export default function Navigation() {
text: 'rgb(138, 138, 138)',
}
};
//@ts-ignore
const favoritesMusicLength : number = useSelector(state => state.appReducer.favoriteMusic.length);
// const dispatch = useDispatch();
// useEffect(() => {
// const loadFavoritesMusics = async () => {
// await dispatch(fetchFavoritesMusic());
// };
// loadFavoritesMusics();
// }, [dispatch]);
return (
// @ts-ignore
<NavigationContainer theme={MyTheme}>
@ -45,8 +57,8 @@ export default function Navigation() {
<BottomTabNavigator.Screen name="Favorites" component={FavoriteNavigation}
options={{
// use Selector state redux badgeCount ? badgeCount : undefined
tabBarBadge : 2,
tabBarBadge : favoritesMusicLength,
tabBarBadgeStyle : {backgroundColor : 'yellow'},
headerShown: false,
tabBarIcon: ({color}) => <View style={styles.IconContainer}><TabBarIcon name="heart" color={color}/></View>,

@ -1,5 +1,5 @@
import React, {Component} from 'react';
import FavoritePage from '../screens/favoritePage';
import FavoritePage from '../screens/favorite';
import { createStackNavigator } from '@react-navigation/stack';
import Spot from '../screens/spot'
import { createSharedElementStackNavigator } from "react-navigation-shared-element";
@ -22,10 +22,10 @@ export default function SpotNavigation() {
name="Spots"
component={Spot}
/>
<Stack.Screen
{/* <Stack.Screen
name="DetailsSpot"
component={SpotDetailsPage}
/>
/> */}
{/* <Stack.Screen
name="DetailsSpot"
component={SpotDetailsPage}

@ -0,0 +1,17 @@
import Music from "../../Model/Music";
import { Spot } from "../../Model/Spot";
import { favoritesTypes } from "../types/favoritesTypes";
import {spotTypes} from "../types/spotTypes";
export const getFavoritesMusic = (favoritesMusic: Music[]) => {
return {
type: favoritesTypes.GET_FAVORITE_MUSICS,
playload: favoritesMusic,
};
}
export const addFavoritesMusic = (favoritesMusic: Music) => {
return {
type: favoritesTypes.ADD_FAVORITE_MUSICS ,
playload: favoritesMusic,
};
}

@ -4,18 +4,30 @@ import { discoveriesTypes } from "../types/discoverieTypes";
import { favoritesTypes } from "../types/favoritesTypes";
import { spotifyTypes } from "../types/spotifyTypes";
import { spotTypes } from "../types/spotTypes";
let tmpMusic: Music[] = [
// new Music("La pharmacie", "Jul",require("../assets/images/jul.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("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("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("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 = {
spot: [] as Spot[],
favoriteMusic: [] as Music [],
favoriteMusic: tmpMusic,
userCurrentMusic : null
}
const appReducer = (state = initialState, action : any) => {
switch (action.type) {
case favoritesTypes.GET_FAVORITE_MUSICS:
return {...state, favoriteMusic: action.playload};
case favoritesTypes.ADD_FAVORITE_MUSICS:
return {...state, favoriteMusic: state.favoriteMusic.push(action.payload)};
case favoritesTypes.REMOVE_FAVORITE_MUSICS:
return {...state, favoriteMusic: [action.playload, ...state.favoriteMusic]};
case favoritesTypes.REMOVE_FAVORITE_MUSICS:
return {...state, favoriteMusic: state.favoriteMusic};
case spotTypes.FETCH_SPOT:
return {...state, spot: action.payload};

@ -4,7 +4,7 @@ import userReducer from './reducers/userReducer';
// Reference here all your application reducers
const reducer = {
// appReducer: appReducer,
appReducer: appReducer,
userReducer: userReducer
}

@ -8,6 +8,8 @@ import { Spot } from "../../Model/Spot";
import SpotifyService from "../../services/spotify/spotify.service";
import * as Location from 'expo-location';
import { setSpotList, setUserCurrentMusic } from "../actions/spotActions";
import Music from "../../Model/Music";
import { getFavoritesMusic } from "../actions/appActions";
const key = 'userToken';
export type CreateSpotReqBody = {
@ -91,6 +93,46 @@ export const getCurrentUserMusic = (resuestHandler : SpotifyService)=> {
}
}
}
export const searchMusic = async (resuestHandler : SpotifyService,search: string) => {
//
return async (dispatch) => {
// const fetchAll = async () => {
// const data = await fetch(`https://kanjialive-api.p.rapidapi.com/api/public/search/${search}`, options)
// .then(response => response.json());
// const fetchPromises = data.map(it =>
// fetch(`https://kanjialive-api.p.rapidapi.com/api/public/kanji/${it.kanji.character}`, options)
// .then(detail => detail.json())
// );
// const kanjis = await Promise.all(fetchPromises)
// .then(details => details.map(detail_data => KanjiMapper.ApiJsonToKanji(detail_data)));
// return kanjis;
// };
return resuestHandler.searchMusic(search).then(musics => dispatch((musics))).catch(err => console.log("something goes wrong while searching : " + err));
};
}
// export const fetchFavoritesMusic = () => {
// //@ts-ignore
// return async dispatch => {
// const MovieList: Music[] = [
// // new Music("La pharmacie", "Jul",require("../assets/images/jul.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("Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png"),
// 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("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"),
// ] ;
// dispatch(getFavoritesMusic(MovieList));
// }
// }
// export const getSpotList = () => {
// return async dispatch => {
// try {

@ -1,6 +1,7 @@
export const favoritesTypes = {
GET_FAVORITE_MUSICS : 'GET_FAVORITE_MUSICS',
ADD_FAVORITE_MUSICS : 'ADD_FAVORITE_MUSICS',
REMOVE_FAVORITE_MUSICS : 'REMOVE_FAVORITE_MUSICS',
}

@ -1,29 +1,28 @@
import React, { useState} from 'react';
import { Image,StyleSheet, Text, View, FlatList, ScrollView, TouchableOpacity, SafeAreaView } from 'react-native';
import React, { useEffect, useState} from 'react';
import { Image,StyleSheet, Text, View, FlatList, ScrollView, TouchableOpacity, TouchableHighlight } from 'react-native';
import CardMusic from '../components/CardMusic';
import normalize from '../components/Normalize';
import Music from '../Model/Music'
import {useNavigation} from "@react-navigation/native";
import { useDispatch, useSelector } from 'react-redux';
import { getFavoritesMusic } from '../redux/actions/appActions';
import { SharedElement } from 'react-navigation-shared-element';
export default function favoritePage() {
const navigation = useNavigation();
const MUSIC_LIST : Music[] = [
new Music("La pharmacie", "Jul",require("../assets/images/jul.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("Stratos", "Kekra", "https://images.genius.com/ddc9cadedd1d4cef0860aaa85af9cd46.705x705x1.png"),
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("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"),
]
//@ts-ignore
const favoritesMusic = useSelector(state => state.appReducer.favoriteMusic);
const dispatch = useDispatch();
const navigueToDetail = (music : any) => {
navigation.navigate("MusicDetail", {"music": music})
};
// to do
const [filteredDataSource, setFilteredDataSource] = useState<Music[]>([]);
const [search, setSearch] = useState('');
const searchMusic = (text: string) => {
if (text) {
const newData = MUSIC_LIST.filter(function (item: Music) {
const newData = favoritesMusic.filter(function (item: Music) {
const search = item.title
? item.title.toUpperCase() : ''.toUpperCase();
const textsearch = text.toUpperCase();
@ -40,9 +39,24 @@ export default function favoritePage() {
return (
<View style={styles.body}>
<SafeAreaView style={styles.mainSafeArea}>
<View style={styles.titleContainer}>
<Text style={styles.title}>Favoris</Text>
<Text style={styles.description}>Retrouvez ici vos musiques favorites</Text>
<View style={styles.titleContainer}>
<Text style={styles.title}>Favoris</Text>
<Text style={styles.description}>Retrouvez ici vos musiques favorites</Text>
</View>
<ScrollView>
<View>
<FlatList style={{marginBottom: 80}}
data={favoritesMusic}
renderItem={({ item }) => (
<TouchableHighlight onPress={() => {navigueToDetail(item)}}>
<SharedElement id={item.id}>
<CardMusic image={item.image} title={item.title} description={item.bio} id={item.id}/>
</SharedElement>
</TouchableHighlight>
)}
keyExtractor={(item: Music) => item.title }
/>
</View>
<ScrollView>
<View>

@ -0,0 +1,283 @@
import { NavigationProp, RouteProp } from "@react-navigation/native";
import { View,Text,Image,StyleSheet, Dimensions, useWindowDimensions, Button, TouchableOpacity } from "react-native";
import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, useDerivedValue, useSharedValue, Value, withSpring, withTiming } from "react-native-reanimated";
import { BlurView } from 'expo-blur';
import qs from "qs";
import axios from "axios";
import { Buffer } from 'buffer';
import { Audio } from 'expo-av';
import { useEffect, useState } from "react";
import { State, TapGestureHandler } from "react-native-gesture-handler";
import { RequestHandler } from "../services/spotify/spotifyRequestHandler/utils";
import { FetchRequest } from "expo-auth-session/build/Fetch";
import Music from "../Model/Music";
import SpotifyService from "../services/spotify/spotify.service";
import { SharedElement } from "react-navigation-shared-element";
const halfPi = Math.PI/2;
//@ts-ignore
const MusicDetail = ({ route }) => {
const music : Music = route.params.music;
const [currentspot, setCurrentspot] = useState(music);
const [sound, setSound] = useState(null);
const [isPlaying, setIsPlaying] = useState(false);
const loader = useSharedValue(0);
useEffect(() => {
loader.value = isPlaying ? 1 : 0
}, [isPlaying,loader ]);
const transition = useDerivedValue(()=>{
return withTiming(loader.value, {duration : 1000})
}
)
// const styleAniamatedButton = useAnimatedStyle(() => {
// const verticalAxis =interpolate(
// transition.value,
// [0,1],
// [circumference, 0]
// )
// return {
// top : withSpring( verticalAxis),
// left : withSpring(horizontalAxis),
// };
// })
const playTrackPreview = async () => {
console.log("===============================================================================================================");
console.log('get in Sound');
const { sound } = await Audio.Sound.createAsync({uri :music.trackPreviewUrl});
//@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: music.trackPreviewUrl },
{ shouldPlay: true }
);
setSound(newSound);
setIsPlaying(true);
} else {
setIsPlaying(true);
//@ts-ignore
await sound.playAsync();
}
};
const handleStopSound = async () => {
if (sound !== null) {
setIsPlaying(false);
//@ts-ignore
await sound.stopAsync();
}
else{
}
};
useEffect(() => {
return sound ? () => {
console.log('Unloading Sound');
//@ts-ignore
sound.unloadAsync();
}
: undefined;
}, [sound]);
// useEffect(() => {
// if(isPlaying){
// }
// })
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 CLIENT_ID = "1f1e34e4b6ba48b388469dba80202b10";
// const CLIENT_SECRET = "779371c6d4994a68b8dd6e84b0873c82";
// const spotify = "BQA2IAFZ-7ta4-_4_Uqdcdrqi_peE6Hlf1jwxFqjXTbwes0z8xgVGx0rE3zv4cQlusd1ILJhRwkxzPsL1YakzSvCxaTI1P7kOzBrrMqlkDgk4vlFvzLjScB0hBLULbpZyn3ylgx4RyZBEWfmc24wZPQOsrJU58AYCveA52UxYVSIc_Frr7LZyRmwjzGB68MPZeBD"
// var authOptions = {
// method: 'GET',
// url: 'https://api.spotify.com/v1/me/player/currently-playing',
// headers: {
// 'Authorization': 'Bearer ' + spotify,
// 'Content-Type' : 'application/json',
// 'market' : 'FR',
// },
// json: true
// };
// var id = '0cFS3AMF9Lhj3CNoFvwjvY'
// const requestor = new RequestHandler()
// const getCurrentTrack = async () => {
// try {
// const opt : FetchRequest ={headers : Record}
// requestor.spotifyFetch(`tracks${id}`,)
// // var GetTrackOptions = {
// // method: 'GET',
// // url: 'https://api.spotify.com/v1/tracks/'+id,
// // headers: {
// // 'Authorization': 'Bearer ' + spotify,
// // 'Content-Type' : 'application/json',
// // 'market' : 'FR',
// // },
// // json: true
// // };
// // const resp = await axios(GetTrackOptions)
// // console.log("============");
// // console.log(resp.data.href);
// // console.log("================================"+resp.data.album.images[0].url+ "================================");
// // var tmp = currentspot;
// // tmp.sourceUrl = resp.data.album.images[0].url;
// // setCurrentspot(tmp);
// // await axios(authOptions).then(async (response) =>{
// // console.log(response.data.item.preview_url);
// // const id = response.data.item.id;
// // var GetTrackOptions = {
// // method: 'GET',
// // url: 'https://api.spotify.com/v1/tracks/'+id,
// // headers: {
// // 'Authorization': 'Bearer ' + spotify,
// // 'Content-Type' : 'application/json',
// // 'market' : 'FR',
// // },
// // json: true
// // };
// // console.log("============");
// // const music = await axios(GetTrackOptions);
// // console.log("================================"+music.data+ "================================");
// // currentspot.sourceUrl = music.data.images[0];
// // setCurrentspot(currentspot);
// // })
// // const response = await fetch('https://api.spotify.com/v1/me', {
// // method: 'GET',
// // headers: {
// // Authorization: 'Bearer ' + spotify,
// // 'Content-Type': 'application/json',
// // },
// // });
// // response.json()
// // destructure the response and rename the properties to be in camelCase to satisfy my linter ;)
// } catch (err) {
// console.error(err);
// }
// }
const animationState = new Value(State.UNDETERMINED);
const playMusic = async (id: string) => {
try {
const service = new SpotifyService("BQDWJTPvSloZPYDqLc1YWri2LEcognvqoM5bdoCWMuHR9In2FhaKq5tW3-VC5JET9dD9K-W4Rmm0IiyhtX-fSL3Tb8RTHMJUc5GKFq2jxWlH7QXxsiYZV8Fhw2qU1eCpSof1qkPsBd1R36GOgcBaXq2N6kLTP5UcfP-gzjz65x_fVRSxoP6znK2dkvL6saQ6WwzoEFopqpqo") ;
console.log("=====================================================)))))))))))))))"+id+"================================")
await service.playMusic(id);
}catch(error){}
}
return (
<View style={{ flex: 1, justifyContent : 'flex-start', alignItems : 'center' }}>
{/* <SharedElement id={spot.name} style={{ flex: 1 }}> */}
<View style={{borderWidth : 1, borderColor : 'red'}}>
<Animated.Image
source={{
uri:currentspot.image ,
}}
style={[
{
width: 370,
height: 370,
borderRadius : 24,
resizeMode: 'stretch',
},styleAniamatedImage
]}
/>
<Button title="Play Track On Device"
onPress={() => {
playMusic(currentspot.id)
// promptAsync();
}}
/>
</View>
{/* Button */}
{/* <TapGestureHandler {...gestureHandler}> */}
<Animated.View>
<TouchableOpacity style={{
backgroundColor: '#1DB954',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 24,
}}
onPressOut={handleStopSound}
onLongPress={handlePlaySound}
delayLongPress={1000}>
<Text style={ {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',}}>
{isPlaying ? 'Playing...' : 'Play'}
</Text>
</TouchableOpacity>
</Animated.View>
{/* </TapGestureHandler> */}
{/* Button */}
{/* </SharedElement> */}
</View>
);
};
export default MusicDetail;

@ -6,7 +6,7 @@ import Animated from 'react-native-reanimated';
import Card from '../components/Card';
import { cards as cardArray } from '../data/data'
import { cards as cardArray, spotArray2 } from '../data/data'
import FladButton from '../components/button/button';
import axios from 'axios';
@ -21,6 +21,9 @@ import Lotties from '../assets/lottie/Lottie';
import FladLoading from '../components/FladLoadingScreen';
import { SharedElement } from 'react-navigation-shared-element';
import { useNavigation } from '@react-navigation/native';
import Music from '../Model/Music';
import { addFavoritesMusic } from '../redux/actions/appActions';
import { useDispatch } from 'react-redux';
interface SpotProps {
}
@ -90,17 +93,30 @@ async function getValueFor(key:string) :Promise<string | null> {
}
export default function Spot() {
const [cards, setCards] = useState(cardArray);
const [cards, setCards] = useState(spotArray2);
const [currentCard, setcurrentCard] = useState(cards[cards.length - 1]);
const onSwipe = (index: number, direction: 'left' | 'right') => {
const onSwipe = (index: number, direction: 'left' | 'right' | 'down') => {
if (direction === 'right') {
// Swiped right
console.log("====2==="+currentCard.music.title+"======2=========");
addLike(currentCard.music);
console.log('Swiped right');
} else if (direction === 'left') {
// Swiped left
console.log('Swiped left');
}
else if (direction === 'down') {
// Swiped down
console.log('Swiped down');
}
// update the state of the cards state when it remove thisy
setCards(cards.filter((_, i) => i !== index));
setcurrentCard(cards[index-1]);
// update the state of the cards state when it remove this
setTimeout(() => {
setCards(cards.filter((_, i) => i !== index));
setcurrentCard(cards[index - 1]);
}, 3);
// setCards(cards.filter((_, i) => i !== index));
// setcurrentCard(cards[index-1]);
};
const likeButtonref = useRef<LottieView>(null);
@ -110,26 +126,22 @@ export default function Spot() {
const onLike = useCallback( () => {
likeButtonref.current?.reset();
likeButtonref.current?.play(0,55);
likeButtonref.current?.play(55,0);
}, [])
const dispatch = useDispatch();
function addLike(music: Music) {
onLike();
console.log("====3==="+currentCard.music.title+"======3=========");
// function addWatchLater(props: Movie) {
// dispatch(addMovieToWatchLater(props));
// dispatch(removeMovieTrending(props));
// if (displayIndex == trendingMovies.length - 1) {
// setdisplayIndex(0);
// swiper.swipeLeft();
// }
// }
dispatch(addFavoritesMusic(music))
// dispatch(addFavoriteMusic(props));
// if (displayIndex == trendingMovies.length - 1) {
// setdisplayIndex(0);
// swiper.swipeLeft();
// }
}
// function addFavourite(props: Movie) {
// dispatch(addMovieToFavourite(props));
// dispatch(removeMovieTrending(props));
// if (displayIndex == trendingMovies.length - 1) {
// setdisplayIndex(0);
// swiper.swipeLeft();
// }
// }
// const hapti = (() => {
@ -206,7 +218,7 @@ export default function Spot() {
alignItems: "center",
}}
source={{
uri:currentCard.sourceUrl ,
uri:currentCard.music.image ,
}}
></ImageBackground>
<SafeAreaView style={styles.mainSafeArea}>
@ -235,13 +247,13 @@ export default function Spot() {
<View style={{flex : 1.83, justifyContent: 'center', alignItems: 'center' }}>
{cards.map((card, index) => (
<View key={card.name} style = {{ position:'absolute'}} >
<View key={card.userSpotifyId} style = {{ position:'absolute'}} >
<Pressable onLongPress={() => {hapti(card)}} >
{/* <SharedElement id={card.name}> */}
<Card
title={card.name}
image={card.sourceUrl}
title={card.music.title}
image={card.music.image}
onSwipe={(direction) => {onSwipe(index, direction)}}
/>
{/* </SharedElement> */}
@ -260,7 +272,7 @@ export default function Spot() {
<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}/>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} speed={2} source={Lotties.likeAnimation} style={styles.lottie}/>
</TouchableOpacity>
</Animated.View>

@ -0,0 +1,479 @@
import * as React from 'react';
import {TouchableOpacity, ScrollView, View, Text, StyleSheet, Image, SafeAreaView, FlatList, Animated} from 'react-native';
import {useSafeAreaInsets} from "react-native-safe-area-context";
import {LinearGradient} from 'expo-linear-gradient';
import {useEffect, useState} from "react";
import Ionicons from "@expo/vector-icons/Ionicons";
import { SharedElement } from "react-navigation-shared-element";
import { NavigationProp, RouteProp, useNavigation } from "@react-navigation/native";
import { Dimensions, useWindowDimensions, Button } from "react-native";
import { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, useDerivedValue, useSharedValue, Value, withSpring, withTiming } from "react-native-reanimated";
import { BlurView } from 'expo-blur';
import qs from "qs";
import axios from "axios";
import { Buffer } from 'buffer';
import { Audio } from 'expo-av';
import { State, TapGestureHandler } from "react-native-gesture-handler";
import { RequestHandler } from "../services/spotify/spotifyRequestHandler/utils";
import { FetchRequest } from "expo-auth-session/build/Fetch";
import SpotifyService from "../services/spotify/spotify.service";
import Music from '../Model/Music';
import { HorizontalFlatList } from '../components/HorizontalFlatList';
import littleCard from '../components/littleCard';
const halfPi = Math.PI/2;
// InfoScreen.sharedElement = (navigation : ReturnType<typeof useNavigation>)=>{
// const music = navigation.getParam('music');
// return [music.id];
// }
// @ts-ignore
export default function InfoScreen({route, navigation}) {
const item: Music = route.params.music;
const insets = useSafeAreaInsets();
const [similarMusics, setSimilarMusics] = useState<Music[]>([]);
// parralax
// parralax
const styles = StyleSheet.create({
background1: {
height: '100%',
width: '100%',
paddingTop: insets.top,
},
body: {
backgroundColor: "#0E0E0E"
},
backgroundSection: {
height: "100%",
width: "100%",
position: "absolute"
},
back_drop: {
height: "45%",
width: '100%',
position: "absolute",
},
gradientFade: {
height: "30%",
top: "25%"
},
backButton: {
position: "absolute",
top: 10,
left: 5
},
list: {
height: "100%"
},
section1: {
paddingHorizontal: 35
},
title: {
color: "white",
fontSize: 43,
fontWeight: "bold",
paddingBottom: 10,
paddingTop: "45%"
},
characteristics: {
flexDirection: "row",
width: "100%",
justifyContent: "flex-start"
},
stars: {
flexDirection: "row",
width: "100%",
justifyContent: "flex-start",
alignItems: "center",
paddingBottom: 30
},
starsLabel: {
color: "#FFC42D",
fontWeight: "bold",
paddingLeft: 10,
fontSize: 16
},
player: {
borderRadius: 10,
overflow: "hidden"
},
resume: {
color: "#B3B3B3",
paddingTop: 30,
fontSize: 17
},
creditSection: {
paddingTop: 30
},
creditTitle: {
color: "#2998FD",
paddingBottom: 20,
paddingLeft: 35,
fontSize: 17,
fontWeight: "600"
},
similarSection: {
paddingTop: 30
},
similarTitle: {
color: "#2998FD",
paddingLeft: 35,
fontSize: 17,
fontWeight: "600",
paddingBottom: 20
},
similarContainer: {
width: 90,
marginHorizontal: 7
},
similarPoster: {
height: 130,
width: 90,
borderRadius: 8
},
similarTitleFilm: {
color: "#DADADA",
paddingTop: 5,
fontWeight: "300"
},
reviewSection: {
paddingTop: 30
},
reviewTitle: {
color: "#2998FD",
paddingLeft: 35,
fontSize: 17,
fontWeight: "600",
paddingBottom: 10
},
reviewContainer: {
marginHorizontal: 7,
width: 300,
padding: 20,
backgroundColor: "#09090F",
marginVertical: 10,
borderRadius: 14,
borderWidth: 0.8,
borderColor: "rgba(223,223,223,0.14)"
},
reviewInfo: {
flexDirection: "row",
paddingBottom: 20
},
imageProfile: {
height: 50,
width: 50,
borderRadius: 100
},
infoContainer: {
paddingLeft: 10,
flexDirection: "row",
justifyContent: "space-between",
width: "80%",
alignItems: "center"
},
pseudo: {
color: "white",
paddingTop: 5,
fontWeight: "700",
fontSize: 16
},
date: {
color: "grey",
paddingTop: 5,
fontWeight: "500",
fontSize: 14
},
message: {
color: "#B3B3B3",
paddingTop: 5,
fontWeight: "400"
},
creditContainer: {
width: 90,
marginHorizontal: 7,
alignItems: "center"
},
bubble: {
justifyContent: "center"
},
photo: {
height: 90,
width: 90,
borderRadius: 200,
borderWidth: 3,
borderColor: "rgba(255,255,255,0.8)"
},
popularityDot: {
backgroundColor: "white",
borderRadius: 20,
padding: 2,
paddingHorizontal: 5,
justifyContent: "center",
alignItems: "center",
position: "absolute",
bottom: 0,
right: 0,
flexDirection: "row"
},
popularityLabel: {
color: "black",
fontWeight: "500",
paddingRight: 4
},
creditName: {
color: "#DADADA",
paddingTop: 5,
fontWeight: "300"
}
});
const getSimilarMusics = async () => {
const tmpMusic: Music[] = [
// new Music("La pharmacie", "Jul",require("../assets/images/jul.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("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("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("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);
}
useEffect(() => {
getSimilarMusics();
}, []);
////////////////////////////////////////////////
const {width, height} = useWindowDimensions();
const [currentspot, setCurrentspot] = useState(item);
const [sound, setSound] = useState(null);
const [isPlaying, setIsPlaying] = useState(false);
const loader = useSharedValue(0);
useEffect(() => {
loader.value = isPlaying ? 1 : 0
}, [isPlaying,loader ]);
const transition = useDerivedValue(()=>{
return withTiming(loader.value, {duration : 1000})
}
)
// const styleAniamatedButton = useAnimatedStyle(() => {
// const verticalAxis =interpolate(
// 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 { sound } = await Audio.Sound.createAsync({uri :item.trackPreviewUrl});
//@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 () => {
if (sound !== null) {
//@ts-ignore
await sound.stopAsync();
}
else{
setIsPlaying(true);
}
};
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){}
}
return (
<View style={styles.body}>
<View style={styles.backgroundSection}>
<Image
style={styles.back_drop}
source={{
uri: item.image,
}}
></Image>
<LinearGradient
// Background Linear Gradient
colors={['rgba(0,0,0,0.8)', 'transparent']}
/>
<LinearGradient style={styles.gradientFade}
// 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)']}>
</LinearGradient>
</View>
<View style={styles.background1}>
<TouchableOpacity onPress={() => navigation.goBack()} style={{zIndex: 100}}>
<Ionicons name="ios-arrow-back" size={30} color="white" style={styles.backButton}/>
</TouchableOpacity>
<ScrollView style={styles.list} showsVerticalScrollIndicator={false} scrollEventThrottle={4}
>
<View style={styles.section1}>
<View style={{ flex: 1, justifyContent : 'flex-start', alignItems : 'center' }}>
{/* <SharedElement id={spot.name} style={{ flex: 1 }}> */}
<View>
<SharedElement id ={item.id}>
<Animated.Image
source={{
uri:currentspot.image ,
}}
style={[
{
width: 370,
height: 370,
borderRadius : 24,
resizeMode: 'stretch',
},styleAniamatedImage
]}
/>
</SharedElement>
<Button title="Play Track On Device"
onPress={() => {
playMusic(currentspot.id)
// promptAsync();
}}
/>
</View>
{/* Button */}
{/* <TapGestureHandler {...gestureHandler}> */}
<Animated.View>
<TouchableOpacity style={{
backgroundColor: '#1DB954',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 24,
}} onPressIn={handlePlaySound}
onPressOut={handleStopSound}
onLongPress={handlePlaySound}
delayLongPress={1000}>
<Text style={ {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',}}>
{isPlaying ? 'Playing...' : 'Play'}
</Text>
</TouchableOpacity>
</Animated.View>
</View>
</View>
{similarMusics.length !== 0 && (
<HorizontalFlatList renderCell={littleCard} title={'Simillar Music'} data={similarMusics}>
</HorizontalFlatList>
)}
</ScrollView>
</View>
</View>
)
}

@ -1,7 +1,7 @@
import axios from "axios";
import MusicFactory from "../../Model/factory/MusicFactory";
import Music from "../../Model/Music";
import { RequestHandler } from "./spotifyRequestHandler/utils";
import { FetchOptions, RequestHandler } from "./spotifyRequestHandler/utils";
export default class SpotifyService implements IspotifyService {
private readonly API_URL = "https://flad-api-production.up.railway.app/api/";
@ -46,17 +46,116 @@ export default class SpotifyService implements IspotifyService {
return respMusic.data.items[0].track.id;
}
public async playMusic(): Promise<string | null>{
var requestData :string = '/me/player/recently-played';
public async playMusic(idMusic : string): Promise<void>{
var requestData :string = '/me/player/play';
const fetchOptions: FetchOptions = {
method: 'PUT',
body: {
uris: [`spotify:track:${idMusic}`],
position_ms: 0
}
};
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token);
console.log(respMusic.data);
// need to handle when
// if (respMusic.status != 200) {
// if (respMusic.status == 400 && respMusic.data.message =='need to use Spotify premium'){
// }
// }
// if(respMusic){
// console.log(respMusic);
// console.log(respMusic.data);
// }
return ;
}
public async searchMusic(text : string): Promise<Music[]>{
var requestData :string = '/search';
const fetchOptions: FetchOptions = {
params: {
q: text,
type: 'track'
}
};
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token);
if (respMusic.status != 200) {
}
const tracksData = respMusic?.data?.tracks?.items;
if (!tracksData || !Array.isArray(tracksData)) {
return [];
}
const tracks = tracksData.map((trackData: any) => {
// const { id, name, artists, album } = trackData;
return MusicFactory.mapFromSpotifyTrack(trackData)
// const artistNames = artists.map((artist: any) => artist.name).join(', ');
// const linkCover = album?.images[0]?.url || '';
// return new Music(id, name, artistNames, linkCover);
});
return tracks;
}
// tempo version
public async getMusicMoreDetails(idMusic : string): Promise<string>{
var requestData :string = '/audio-features/' + idMusic;
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token);
if (respMusic.status != 200) {
}
if (respMusic.data.items.length <= 0) {
return null;
}
return respMusic.data.items[0].track.id;
return respMusic.data.audio_features.tempo;
}
public async getRelatedArtist(idArtist : string): Promise<string>{
var requestData :string = '/artists/' + idArtist + '/related-artists';
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token);
if (respMusic.status != 200) {
}
return respMusic.data.audio_features.tempo;
}
public async getArtistTopTracks(idArtist : string): Promise<string>{
var requestData :string = '/artists/' + idArtist + '/top-tracks';
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, undefined,this.token);
if (respMusic.status != 200) {
}
return respMusic.data.audio_features.tempo;
}
public async addItemToPlayList(playlistId : string, idMusic : string): Promise<void>{
var requestData :string = '/playlists/' + playlistId + '/tracks';
const fetchOptions: FetchOptions = {
method: 'POST',
body: {
uris: [`spotify:track:${idMusic}`]
}
};
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token);
console.log(respMusic.data);
return ;
}
public async createPlayList(userId : string,name : string,description : string): Promise<void>{
var requestData :string = '/users/' + encodeURIComponent(userId) + '/playlists';
const fetchOptions: FetchOptions = {
method: 'POST',
body: {
"public": false,
"name": name || "New Flad Playlist",
"description": description,
}
};
const respMusic = await this.spotifyRequestHandler.spotifyFetch(requestData, fetchOptions,this.token);
console.log(respMusic.data);
return ;
}
async getSpotifyCredentials() {
const res = await axios.get(this.API_URL)
// then verify error

@ -20,6 +20,7 @@ export class RequestHandler{
}
public async spotifyFetch(url: string, options: FetchOptions = {}, token: string) {
console.log(options+ "sds=============");
const resp = await axios({
url: `https://api.spotify.com/${this.version}${url}`,
method: options.method || 'GET',
@ -31,7 +32,7 @@ export class RequestHandler{
},
data: options.body
});
console.log()
console.log(resp);
return resp;
// if (
// // @ts-ignore

Loading…
Cancel
Save