pre-push
continuous-integration/drone/push Build is passing Details

pull/8/head
David D'ALMEIDA 2 years ago
parent 7bef39baf9
commit 0369630fc0

@ -50,6 +50,9 @@ class App {
private initialiseControllers(controllers: Controller[]): void {
controllers.forEach((controller: Controller) => {
this.express.use('/api', controller.router);
this.express.get('/toto', (req, res) => {
res.send('Hello World!');
})
});
}

@ -161,8 +161,9 @@ class UserController implements Controller {
): Promise<Response | void> => {
try {
// the FladId should be created by the Userservice
const { name, email, password,idFlad, idSpotify } = req.body;
const { name, email, password , idFlad, idSpotify } = req.body;
console.log(name, email, password, idFlad, idSpotify);
const token = await this.userService.register(
name,
email,

@ -1,4 +1,4 @@
import { Schema, model } from 'mongoose';
import { Schema, model,Document } from 'mongoose';
const locationSchema = new Schema(

@ -7,7 +7,8 @@ const register = Joi.object({
password: Joi.string().min(6).required(),
// can add an field like confimPassword and cheked that the password is equal to the confirmPassword
idSpotify: Joi.string(),
idFlad : Joi.string(),
});
const login = Joi.object({

@ -39,13 +39,14 @@ class UserService {
email: string,
password: string
): Promise<string | Error> {
try {
// should maybe creat a method base on id and other information for better security
// need to view with Emre
const user = await this.user.findOne({ email });
console.log(user?._id);
// const user = await this.user.findById(idFlad);
if (!user) {
if (user === undefined || user === null) {
console.log("Could")
throw new Error('Unable to find user with that email address');
}
@ -54,9 +55,7 @@ class UserService {
} else {
throw new Error('Wrong credentials given');
}
} catch (error) {
throw new Error('Unable to create user');
}
}
}

@ -2,17 +2,18 @@ import Navigation from './navigation/Navigation';
import { StyleSheet,SafeAreaView } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import StartNavigation from './navigation/StartNavigation';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store from './redux/store';
import { useCallback, useEffect } from 'react';
import * as SplashScreen from 'expo-splash-screen';
import AuthNavigation from './navigation/AuthNavigation';
export default function App() {
return (
<SafeAreaProvider>
<StartNavigation/>
</SafeAreaProvider>
// <SafeAreaView style={styles.mainSafeArea}>
// {/* <Navigation/> */}
// </SafeAreaView>
<Provider store={store}>
<AuthNavigation/>
</Provider>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

@ -1,6 +1,9 @@
const Icons = {
discovery: require('./icon_discovery.png'),
like: require('./icon_like.png'),
dislike: require('./icon_dislike.png'),
// riveLike : require('./light_like.riv'),
}

@ -0,0 +1,6 @@
const Lotties = {
likeAnimation: require('./spotify-like-interaction.json')
// riveLike : require('./light_like.riv'),
}
export default Lotties;

File diff suppressed because one or more lines are too long

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

@ -0,0 +1,82 @@
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 ArtistProps {
artist: Music;
onPress: () => void;
}
export const Artist = ({ artist, onPress }: ArtistProps) => {
const source = typeof artist.image === 'string' ? { uri: artist.image } : artist.image;
//@ts-ignore
const onSingleTapEvent = (event) => {
if (event.nativeEvent.state === State.ACTIVE) {
alert('Hey single tap!');
}
};
const doubleTapRef = useRef(null);
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}>
<Image source={source} style={styles.image} />
{ 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",
}
});

@ -1,6 +1,6 @@
import { View, Text, Image , Dimensions, StyleSheet } from 'react-native'
import React, { useRef, useState } from 'react'
import Animated,{ Extrapolate, interpolate, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
import Animated,{ Extrapolate, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
import * as Haptics from 'expo-haptics';
@ -14,17 +14,18 @@ const SCREEN_WIDTH = Dimensions.get('window').width
interface CardProps {
title: string;
image: any;
onSwipe: (direction: "left" | "right") => void;
}
type ContextType = {
translateX: number;
translateY: number;
};
const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
const Card = ({ title, image, onSwipe } : CardProps) => {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const scale = useSharedValue(1);
const onGestureEvent = useAnimatedGestureHandler<
PanGestureHandlerGestureEvent,
ContextType
@ -34,15 +35,20 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
context.translateY = translateY.value;
},
onActive : (event, context) => {
translateX.value = event.translationX + context.translateX -5;
translateX.value = event.translationX + context.translateX;
translateY.value = event.translationY + context.translateY;
},
onEnd : (event, context) => {
console.log(translateX.value);
// translateX.value = withSpring(0);
// translateY.value = withSpring(snapPoint(translateY.value,velocityY, snapPoints ))
if (translateX.value > 160) {
// onSwipe("right");
console.log("translateX2");
runOnJS(onSwipe)("right");
} else if (translateX.value < -160) {
runOnJS(onSwipe)("left");
// onSwipe("left");
} else {
translateX.value = withSpring(0);
@ -58,7 +64,7 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
const opacityl = interpolate
( translateX.value,
[-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4],
[0, 0, 1]);
[ 0,0, 1]);
return {
opacity : opacityl,
};
@ -77,7 +83,7 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
const opacityl = interpolate
( translateX.value,
[-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4],
[0.75, 1, 0.75]);
[0.35, 0, 0.35]);
return {
opacity : opacityl,
@ -92,6 +98,7 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
opacity : opacityl,
};
});
const horizontalThreshold = SCREEN_WIDTH * 0.65;
const rotateStyle = useAnimatedStyle(() => {
const rot = interpolate
@ -106,7 +113,28 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
};
});
const styleCardsNew = useAnimatedStyle(() => {
const factor = 1;
const rot = interpolate
( translateX.value,
[0, factor * horizontalThreshold],
[0, 15],
);
return {
transform: [
{ scale: scale.value },
{ translateX: translateX.value },
{ translateY: translateY.value },
{ rotateZ: `${rot}deg` },
]
};
});
// Calculate the distance of the card from its starting position
const rStyle = useAnimatedStyle(() => {
return {
@ -124,10 +152,18 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
return (
<View>
<PanGestureHandler onGestureEvent={onGestureEvent}>
<Animated.View style={[ rStyle, styles.card,opacCStyle ]}>
<Animated.View style={[ styleCardsNew, styles.container]}>
<Animated.View style={[ styles.image,{backgroundColor: 'black',elevation: 100,
position: "absolute",
zIndex: 1000,}, opacCStyle]}>
</Animated.View>
<Image source={{uri : image}} style={[styles.image]} />
<>
<Animated.View
style={[{
// transform: [{ rotate: "30deg" }],
elevation: 100,
position: "absolute",
zIndex: 1000,
},opacRStyle]}
@ -138,10 +174,13 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
</Animated.View>
<Animated.View
style={[{
width: '100%',
height: '100%',
position: "absolute",
justifyContent : "center",
alignContent : "center",
zIndex: 1000,
elevation: 100,
},opacLStyle]}
>
<Image style={[{alignSelf : "center"}]}
@ -151,10 +190,12 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
</Animated.View>
<Animated.View
style={[{
width: '100%',
height: '100%',
position: "absolute",
justifyContent : "center",
alignContent : "center",
elevation: 100,
zIndex: 1000,
},opacDStyle]}
>
@ -164,8 +205,9 @@ const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
/>
</Animated.View>
<Image source={{uri : image}} style={[styles.image]} />
</Animated.View>
</>
</Animated.View>
</PanGestureHandler>
</View>
);
@ -176,17 +218,21 @@ const styles = StyleSheet.create({
card : {
justifyContent : 'center',
alignItems : 'center',
},
image : {
borderRadius : 24,
resizeMode: 'cover',
height: 529,
width: 312,
backgroundColor: 'black',
resizeMode: 'stretch',
height: 362,
width: 362,
},
container: {
flex: 1,
width: '100%',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}
})
export default Card;
export default Card;

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

@ -0,0 +1,83 @@
import { useState } from "react";
import { FlatList, ScrollView } from "react-native";
import Music from "../Model/Music";
import { Artist } from "./Artist";
import { StyleSheet } from "react-native";
export const ArtistLayout = () => {
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"),
]
const [artists, setArtists] = useState<Music[]>(MUSIC_LIST);
const [selectedArtists, setSelectedArtists] = useState<typeof MUSIC_LIST> ([]);
return (
<ScrollView contentContainerStyle={styles.container}>
{artists.map((artist, i) => (
<Artist
artist={artist}
key={artist.title}
onPress={() => {
// artists.splice(i, 1);
// // 2 implementation
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);
// if (existingObjIndex === -1) {
// selectedArtists.push(tmppArtist);
// } else {
// selectedArtists.splice(existingObjIndex, 1);
// }
// setSelectedArtists([...selectedArtists]);
// 1 implementation
// setSelectedArtists(selectedArtists.findIndex(obj => obj.title === tmppArtist.title) === -1
// ? [...selectedArtists, tmppArtist]
// : selectedArtists.filter(obj => obj.title !== tmppArtist.title))
// 3 implementations
// use the selectedProps of the Artist Component
// then when we need to finish
// onPress{ () => setSelectedArtists([...selectedArtists,artists.filter(artist => artist.selected)])}
artists.push(tmppArtist);
setArtists([...artists]);
}}
/>
))}
{/* <FlatList
data={artists}
// need to reverse colums oreder
numColumns = {3}
renderItem={({ item }) => (
<Artist
artist={item}
key={item.title}
onPress={() => {
artists.push(new Music("Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png"));
setArtists([...artists]);
}}/>
)}
keyExtractor={(item: Music) => item.title }
// ListEmptyComponent = {}
/> */}
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: "row",
flexWrap: "wrap",
},
});

@ -1,6 +1,6 @@
import React, { useState, useRef } from 'react';
import { View, StyleSheet, Text, FlatList, Animated, TouchableOpacity, ImageBackground, Image } from 'react-native';
import Modal from "react-native-modal";
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';
@ -53,11 +53,11 @@ export default function Onboarding() {
onViewableItemsChanged={viewableItemsChanged}
viewabilityConfig={viewConfig}
ref={slidesRef}
/>
/>
<Paginator data={slides} scrollX={scrollX}/>
<NextButton scrollTo={scrollTo} percentage={(currentIndex + 1) * (100 / slides.length)} />
</View>
<Modal isVisible={isModalVisible}>
<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}>
@ -124,11 +124,10 @@ const styles = StyleSheet.create({
right: 10
},
modalContent: {
position: 'absolute',
top: '7%',
left: '-5%',
right: '-5%',
height: '100%',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalView: {
flex: 1,

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

@ -0,0 +1 @@
export const API_URL = "https://flad-api-production.up.railway.app"

@ -0,0 +1,67 @@
import Navigation from './Navigation';
import { StyleSheet,SafeAreaView } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import StartNavigation from './StartNavigation';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store from '../redux/store';
import { useCallback, useEffect } from 'react';
import * as SplashScreen from 'expo-splash-screen';
import { View } from 'react-native';
import { getRefreshToken } from '../redux/thunk/authThunk';
SplashScreen.preventAutoHideAsync();
export default function AuthNavigation() {
//@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 dispatch = useDispatch();
useEffect(() => {
async function prepare() {
console.log(appIsReady, "1 AuthNav")
//@ts-ignore
await dispatch(getRefreshToken())
await SplashScreen.hideAsync();
}
prepare();
}, [dispatch]);
const onStackRootView = useCallback(async () => {
if (appIsReady) {
await SplashScreen.hideAsync();
}
}, [appIsReady]);
if (appIsReady == false) {
console.log(appIsReady, "T9 AuthNav")
return null;
}
console.log(appIsReady, "k9 AuthNav")
// console.log(userToken, "k9 AuthNav")
return (
<>
{isLogin ? (
/* {userToken != null ? ( */
<SafeAreaView style={styles.mainSafeArea} >
<Navigation/>
</SafeAreaView>
) :
<SafeAreaProvider >
<StartNavigation/>
</SafeAreaProvider>
}
</>
)
}
const styles = StyleSheet.create({
mainSafeArea: {
flex: 1,
backgroundColor: "#141414",
}
});

@ -1,6 +1,7 @@
import React, {Component} from 'react';
import FavoritePage from '../screens/favoritePage';
import { createStackNavigator } from '@react-navigation/stack';
import { ArtistLayout } from '../components/Genre';
export default function MusicNavigation() {
const Stack = createStackNavigator();
@ -11,6 +12,11 @@ export default function MusicNavigation() {
component={FavoritePage}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Genre"
component={ArtistLayout}
options={{ headerShown: false }}
/>
</Stack.Navigator>
)
}

@ -2,8 +2,12 @@ import React, {Component} from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
import FavoriteNavigation from './FavoriteNavigation';
// @ts-ignore
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import SpotNavigation from './SpotNavigation';
import Login from '../screens/login';
import FladLoading from '../components/FladLoadingScreen';
export default function Navigation() {
const BottomTabNavigator = createBottomTabNavigator();
@ -27,22 +31,26 @@ export default function Navigation() {
tabBarLabelStyle: { bottom: 5 }
}}>
<BottomTabNavigator.Screen name="Spots" component={FavoriteNavigation}
<BottomTabNavigator.Screen name="Spots" component={SpotNavigation}
options={{
headerShown: false,
tabBarIcon: ({color}) => <TabBarIcon name="music" color={color}/>,
}}/>
<BottomTabNavigator.Screen name="Favories" component={FavoriteNavigation}
options={{
options={{
// use Selector state redux badgeCount ? badgeCount : undefined
tabBarBadge : 2,
tabBarBadgeStyle : {backgroundColor : 'yellow'},
headerShown: false,
tabBarIcon: ({color}) => <TabBarIcon name="heart" color={color}/>,
}}/>
<BottomTabNavigator.Screen name="Messages" component={FavoriteNavigation}
<BottomTabNavigator.Screen name="Messages" component={Login}
options={{
headerShown: false,
tabBarIcon: ({color}) => <TabBarIcon name="comment" color={color}/>,
}}/>
<BottomTabNavigator.Screen name="Paramètres" component={FavoriteNavigation}
<BottomTabNavigator.Screen name="Paramètres" component={FladLoading}
options={{
headerShown: false,
tabBarIcon: ({color}) => <TabBarIcon name="cog" color={color}/>,

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

@ -1,15 +1,40 @@
import React, {Component} from 'react';
import React, {Component, useCallback, useEffect} from 'react';
import LoginPage from '../screens/loginPage';
import InscriptionPage from '../screens/InscriptionPage';
import Onboarding from '../components/Onboarding';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';
import {useDispatch, useSelector} from 'react-redux';
import * as SplashScreen from 'expo-splash-screen';
import { getRefreshToken } from '../redux/thunk/authThunk';
import { ArtistLayout } from '../components/Genre';
export default function StartNavigation() {
// //@ts-ignore
// const appIsReady : boolean = useSelector(state => state.userReducer.loading);
// const dispatch = useDispatch();
// useEffect(() => {
// async function prepare() {
// //@ts-ignore
// await dispatch(getRefreshToken());
// }
// prepare();
// }, [dispatch]);
// const onStackRootView = useCallback(async () => {
// if (appIsReady) {
// await SplashScreen.hideAsync();
// }
// }, [appIsReady]);
// if (!appIsReady) {
// return null;
// }
const Stack = createStackNavigator();
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Onboarding}

@ -13,18 +13,21 @@
"@react-navigation/native": "^6.1.4",
"@react-navigation/native-stack": "^6.9.8",
"@react-navigation/stack": "^6.3.12",
"@reduxjs/toolkit": "^1.9.2",
"@types/react-redux": "^7.1.25",
"axios": "^1.2.6",
"buffer": "^6.0.3",
"expo": "~47.0.12",
"expo-auth-session": "~3.8.0",
"expo-cli": "^6.3.0",
"@reduxjs/toolkit": "^1.9.2",
"@types/react-redux": "^7.1.25",
"expo-haptics": "~12.0.1",
"expo-linear-gradient": "~12.0.1",
"expo-location": "~15.0.1",
"expo-random": "~13.0.0",
"expo-secure-store": "~12.0.0",
"expo-splash-screen": "~0.17.5",
"expo-status-bar": "~1.4.2",
"lottie-react-native": "5.1.4",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-native": "0.70.5",
@ -33,12 +36,15 @@
"react-native-reanimated": "~2.12.0",
"react-native-safe-area-context": "^4.4.1",
"react-native-screens": "~3.18.0",
"react-native-shared-element": "^0.8.8",
"react-native-svg": "13.4.0",
"react-native-vector-icons": "^9.2.0",
"react-native-web": "~0.18.9",
"react-navigation-shared-element": "^3.1.3",
"react-redux": "^8.0.5",
"redux": "^4.2.1",
"rive-react-native": "^3.0.41"
"rive-react-native": "^3.0.41",
"expo-blur": "~12.0.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",

@ -0,0 +1,6 @@
// export const UserLogin = (username: string, password: string) => {
// return {
// type: userTypes.LOGIN,
// playload : username, password
// };
// }

@ -0,0 +1,8 @@
import {spotTypes} from "../types/spotTypes";
export const setSpotList = (spotList: Spot[]) => {
return {
type: spotTypes.FETCH_SPOT,
payload: spotList,
};
}

@ -0,0 +1,39 @@
import { userTypes } from "../types/userTypes";
export interface Credentials {
email : string,
password : string
}
// export const setLoggedInState = loggedInState => (
// {
// type: types.SET_LOGGED_IN_STATE,
// loggedInState,
// }
// );
export const setLoginState = (cred : Credentials) => {
return {
type: userTypes.LOGIN,
playload : cred
};
}
export const restoreToken = (token : string) => {
return {
type: userTypes.RESTORE_TOKEN,
playload : token
};
}
// export const UserLogin = (username: string, password: string) => {
// return {
// type: userTypes.LOGIN,
// playload : username, password
// };
// }
export const UserLogout = () => {
return {
type: userTypes.USER_LOGOUT,
};
}

@ -0,0 +1,22 @@
const initialState = {
spot: [],
favoriteMusic: [],
}
const appReducer = (state = initialState, action : any) => {
switch (action.type) {
case ADD_FAVORITE_MUSICS:
return {...state, favoriteMusic: state.favoriteMusic.push(action.payload)};
case REMOVE_FAVORITE_MUSICS:
return {...state, favoriteMusic: state.favoriteMusic};
case FETCH_SPOT:
return {...state, spot: action.payload};
case FETCH_DISCOVERIES:
default:
return state;
}
}
export default appReducer

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

@ -0,0 +1,52 @@
import { userTypes } from "../types/userTypes";
const initialState = {
loading: false,
user: {}, // for user object
userFladToken: null, // for storing the JWT
userSpotifyToken : null,
error: null,
isLogedIn: false,
}
const userReducer = (state = initialState, action : any) => {
switch (action.type) {
// just for the navigation and speciafly use
// and
case userTypes.RESTORE_TOKEN:
console.log(state.loading, "((((((((((((((((((((((((((((((((((((userRducer))))))))))))))))))))))))))))))))))))");
console.log(state.userFladToken, "userRducer");
console.log(state.loading, "((((((((((((((((((((((((((((((((((((userRducer))))))))))))))))))))))))))))))))))))");
return {
...state,
userFladToken : action.playload,
loading: true,
// isLogedIn: true,
};
case userTypes.LOGIN:
return {
...state,
user :action.payload,
isLogedIn: true
};
case userTypes.SIGNUP:
return {
...state,
user :action.payload,
isLogedIn: true
};
// case USER_SIGNUP:
// return {...state, nounours: action.payload};
case userTypes.USER_LOGOUT:
return {...state,
user :null,
isLogedIn: false }
default:
return state;
}
}
export default userReducer

@ -0,0 +1,15 @@
import {configureStore} from '@reduxjs/toolkit'
import appReducer from './reducers/appReducer';
import userReducer from './reducers/userReducer';
// Reference here all your application reducers
const reducer = {
// appReducer: appReducer,
userReducer: userReducer
}
const store = configureStore({
reducer : reducer,
},);
export default store;

@ -0,0 +1,127 @@
//Define your action creators that will be responsible for asynchronous operations
import axios from "axios";
import { json } from "express";
import { useEffect } from "react";
import { API_URL } from "../../fladConfig";
import { Credentials, restoreToken, setLoginState } from "../actions/userActions";
import * as SecureStore from 'expo-secure-store';
const key = 'userToken';
export const registerUser = ( resgisterCredential : any) => {
//@ts-ignore
return async dispatch => {
try {
const config = {
headers: {
'Content-Type': 'application/json',
},
}
const resp = await axios.post(
`${API_URL}/api/users/register`,
resgisterCredential,
config
)
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 => {
try {
console.log(loginCredential);
const config = {
headers: {
'Content-Type': 'application/json',
},
}
// const resppp = await axios.get(`${API_URL}/toto`);
// console.log(resppp.data, "sddsd");
const resp = await axios.post(
"https://flad-api-production.up.railway.app/api/users/login",
loginCredential,
config
)
console.log("====================================================================================")
console.log(resp.data)
console.log("====================================================================================")
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(setLoginState(resp.data.user) ); // our action is called here
dispatch(setLoginState(user.data) ); // our action is called here
} else {
console.log('Login Failed', 'Username or Password is incorrect');
}
} catch (error) {
console.log('Error---------', error);
}
}
}
export const getRefreshToken = () => {
//@ts-ignore
return async dispatch => {
try {
let userToken : string | null = await SecureStore.getItemAsync(key);
console.log("==========key ==================");
console.log(userToken);
console.log("==========key ==================");
if (userToken) {
console.log("==========key2 ==================");
console.log(userToken);
console.log("==========key ==================");
dispatch(restoreToken(userToken) );
} else {
console.log("==========OOOOOORRRRRRRRHHHHHHHHHH ==================");
const empty = "";
dispatch(restoreToken(empty) );
console.log("merddee");
}
} catch (e) {
console.log('Error---------', e);
}
}
}
// 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);
}

@ -0,0 +1,29 @@
//Define your action creators that will be responsible for asynchronous operations
import { API_URL } from "../../fladConfig";
export type CreateSpotReqBody = {
id : string;
name : string;
artist : string;
linkCover : string;
user : string;
}
// export const getSpotList = () => {
// return async dispatch => {
// try {
// const spotPromise = await fetch(`${API_URL}/spotify/spot`);
// const spotJson = await spotPromise.json();
// const spotList: Spot[] = spotJson.map(spot => {
// } );
// dispatch(setNounoursList(spotList));
// } catch (error) {
// console.log('Error---------', error);
// }
// }
// }

@ -0,0 +1,3 @@
export const spotTypes = {
FETCH_SPOT : 'FETCH_NOUNOURS',
}

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

@ -1,8 +1,12 @@
import React, {Component, useState } from 'react';
import { View, Image, StyleSheet, Text, ImageBackground, Button, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity } from 'react-native';
import React, {Component, useEffect, useState } from 'react';
import { View, Image, StyleSheet, Text, ImageBackground, Button, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity, Platform } from 'react-native';
import {useNavigation} from "@react-navigation/native";
import normalize from '../components/Normalize';
import * as SecureStore from 'expo-secure-store';
import * as AuthSession from 'expo-auth-session';
import axios from 'axios';
import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';
// @ts-ignore
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
@ -10,6 +14,21 @@ const DismissKeyboard = ({ children }) => (
</TouchableWithoutFeedback>
)
export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey';
WebBrowser.maybeCompleteAuthSession();
// Endpoint
const discovery = {
authorizationEndpoint: 'https://accounts.spotify.com/authorize',
tokenEndpoint: 'https://accounts.spotify.com/api/token',
};
// save the spotifyToken
async function save(key : string, value : string) {
await SecureStore.setItemAsync(key, value);
}
export default function InscriptionPage() {
const [rememberMe, setRememberMe] = useState(false);
const navigation = useNavigation();
@ -17,6 +36,29 @@ export default function InscriptionPage() {
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') {
// Securely store the auth on your device
save(MY_SECURE_AUTH_STATE_KEY, storageValue);
}
}
}, [response]);
return (
<DismissKeyboard>
@ -39,7 +81,9 @@ export default function InscriptionPage() {
<TextInput style={[styles.input, styles.shadow]}/>
<Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} />
</View>
<TouchableOpacity style={[styles.buttonSpotify, styles.shadow]}>
<TouchableOpacity onPress={() => {
promptAsync();
}} style={[styles.buttonSpotify, styles.shadow]}>
<Text style={styles.textIntoButton}>Lier compte</Text>
<Image source={require("../assets/icons/icons/Spotify.png")} style={{width: 30, height: 30}}/>
</TouchableOpacity>
@ -161,4 +205,4 @@ const styles = StyleSheet.create ({
borderRadius: 30,
flexDirection: 'row'
}
})
})

@ -0,0 +1,76 @@
import { SharedElement } from "react-navigation-shared-element";
import { NavigationProp, RouteProp } from "@react-navigation/native";
import { View,Text,Image,StyleSheet, Dimensions, useWindowDimensions } from "react-native";
import Animated, { interpolate, SensorType, useAnimatedSensor, useAnimatedStyle, withSpring, withTiming } from "react-native-reanimated";
import { BlurView } from 'expo-blur';
interface SpotProps {
spot: { name: string, sourceUrl: string, index : number };
}
const halfPi = Math.PI/2;
// const {width : wWidht} = Dimensions.get("window");
//@ts-ignore
const SpotDetailsPage = ({ route }) => {
const {width, height} = useWindowDimensions();
console.log("====================================");
console.log(route);
const spot : { name: string, sourceUrl: string, index : number } = route.params.spot;
console.log(spot);
const sensor = useAnimatedSensor(SensorType.ROTATION);
const styleAniamatedImage = useAnimatedStyle(() => {
const {yaw, pitch, roll} = sensor.sensor.value;
const verticalAxis =interpolate(
pitch,
[-halfPi,halfPi],
[-30, 30]
)
const horizontalAxis =interpolate(
roll,
[-halfPi*2,halfPi*2],
[-30, 30]
)
return {
top : withSpring( verticalAxis),
left : withSpring(horizontalAxis),
};
})
return (
<View style={{ flex: 1, justifyContent : 'flex-start', alignItems : 'center' }}>
{/* <SharedElement id={spot.name} style={{ flex: 1 }}> */}
<Animated.Image
source={{
uri:spot.sourceUrl ,
}}
style={[
{
width: 370,
height: 370,
borderRadius : 24,
resizeMode: 'stretch',
},styleAniamatedImage
]}
/>
{/* <View style={detailRadicalStyle.container}>
<Text style={detailRadicalStyle.radicalText}>{props.character}</Text>
<SvgXml
xml={props.icon
.replace(/fill="#[0-9a-f]{6}"/g, `fill=${detailRadicalStyle.svg.color}`)}
width="30"
height="30"
opacity={0.5}
style={detailRadicalStyle.radicalIcon}
/>
</View> */}
{/* </SharedElement> */}
</View>
);
};
export default SpotDetailsPage;

@ -1,9 +1,13 @@
import React, {Component} from 'react';
import { Animated, StyleSheet, Text, View, FlatList, ScrollView } from 'react-native';
import { Animated, Image,StyleSheet, Text, View, FlatList, ScrollView, TouchableOpacity } from 'react-native';
import CardMusic from '../components/CardMusic';
import normalize from '../components/Normalize';
import Music from '../Model/Music'
import {useNavigation} from "@react-navigation/native";
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")),
@ -32,6 +36,11 @@ export default function favoritePage() {
keyExtractor={(item: Music) => item.title }
/>
</View>
<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>
</View>
);
@ -57,5 +66,29 @@ const styles = StyleSheet.create({
fontSize: 18,
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,
}
});

@ -10,6 +10,7 @@ import { cards as cardArray } from '../data/data'
import FladButton from '../components/button/button';
import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';
import { Buffer } from 'buffer';
const SCREEN_WIDTH = Dimensions.get('window').width
@ -26,6 +27,7 @@ interface Params {
email: string;
id: string;
}
//generate random string
export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey';
@ -36,8 +38,7 @@ const discovery = {
authorizationEndpoint: 'https://accounts.spotify.com/authorize',
tokenEndpoint: 'https://accounts.spotify.com/api/token',
};
// save the spotifyToken
async function save(key : string, value : string) {
await SecureStore.setItemAsync(key, value);
}
@ -45,14 +46,18 @@ async function save(key : string, value : string) {
export default function Login() {
// const [advice, setAdvice] = useState("dd");
// there we use implicit grant flow
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'],
usePKCE: false,
redirectUri: makeRedirectUri({
scheme: 'flad'
}),
scheme: 'https://auth.expo.io/@anonymous/FLAD-7eafd441-fd6b-4fb6-924c-ec2b0ed5ce6d',
useProxy : true
})
},
discovery
);
@ -68,22 +73,78 @@ export default function Login() {
};
React.useEffect(() => {
if (response && response.type === 'success') {
console.log(response);
console.log("========================code=====================");
console.log(response.params.code)
console.log("=============================================");
console.log("========================acess=====================");
console.log(response.params.access_token)
console.log("=============================================");
const auth = response.params.access_token;
const storageValue = JSON.stringify(auth);
if (Platform.OS !== 'web') {
// Securely store the auth on your device
save(MY_SECURE_AUTH_STATE_KEY, storageValue);
// 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);
} catch (err) {
console.error(err)
}
}
const getTokens = async () => {
try {
const authorizationCode = await getAuthorizationCode() //we wrote this function above
const response = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
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`,
});
const responseJson = await response.json();
// 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;
console.log(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={() => {
promptAsync();
getTokens()
// promptAsync();
}}
/>
</View>

@ -2,6 +2,9 @@ import React, {Component, useState } from 'react';
import { View, Image, StyleSheet, Text, ImageBackground, Button, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity } from 'react-native';
import {useNavigation} from "@react-navigation/native";
import normalize from '../components/Normalize';
import { userLogin } from '../redux/thunk/authThunk';
import { useDispatch } from 'react-redux';
import { Credentials } from '../redux/actions/userActions';
// @ts-ignore
const DismissKeyboard = ({ children }) => (
@ -14,6 +17,20 @@ export default function loginPage() {
const [rememberMe, setRememberMe] = useState(false);
const navigation = useNavigation();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const dispatch = useDispatch();
const submitForm = () => {
const credentials: Credentials = {
email: username,
password: password
};
//@ts-ignore
dispatch(userLogin(credentials))
}
const toggleRememberMe = () => {
setRememberMe(!rememberMe);
}
@ -28,18 +45,23 @@ export default function loginPage() {
<Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo}/>
<Text style={styles.text}>SE CONNECTER</Text>
<View>
<TextInput style={[styles.input, styles.shadow]}/>
<TextInput placeholder="Username"
value={username}
onChangeText={setUsername}style={[styles.input, styles.shadow]}/>
<Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} />
</View>
<View>
<TextInput style={[styles.input, styles.shadow]}/>
<TextInput placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry style={[styles.input, styles.shadow]}/>
<Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} />
</View>
<View style={styles.rememberMeContainer}>
<TouchableOpacity style={[styles.checkbox, rememberMe ? styles.checkboxChecked : null]} onPress={toggleRememberMe}></TouchableOpacity>
<Text style={styles.rememberMeText}>SE SOUVENIR DE MOI</Text>
</View>
<TouchableOpacity style={[styles.button, styles.shadow]} onPress={() => console.log("Oui")}>
<TouchableOpacity style={[styles.button, styles.shadow]} onPress={submitForm}>
<Image source={require("../assets/icons/Check.png")} style={styles.buttonImage}/>
</TouchableOpacity>
<View style={styles.inscriptionText}>

@ -1,7 +1,8 @@
import { View, Text, Image, Animated ,PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable } from 'react-native'
import { View, Text, Image ,PanResponder, Dimensions, StyleSheet, ImageBackground, Button, Pressable, TouchableOpacity } from 'react-native'
import React, { useCallback, useEffect, useRef, useState, useTransition } from 'react'
import { LinearGradient } from 'expo-linear-gradient';
import * as Haptics from 'expo-haptics';
import Animated from 'react-native-reanimated';
import Card from '../components/Card';
@ -11,10 +12,15 @@ import axios from 'axios';
import * as SecureStore from 'expo-secure-store';
import { MY_SECURE_AUTH_STATE_KEY } from './login';
import * as AuthSession from 'expo-auth-session';
import * as Location from 'expo-location';
import Icons from '../assets/icons/icons/icon';
import LottieView from 'lottie-react-native'
import Lotties from '../assets/lottie/Lottie';
import FladLoading from '../components/FladLoadingScreen';
import { SharedElement } from 'react-navigation-shared-element';
import { useNavigation } from '@react-navigation/native';
interface SpotProps {
}
@ -94,8 +100,19 @@ export default function Spot() {
}
// update the state of the cards state when it remove thisy
setCards(cards.filter((_, i) => i !== index));
setcurrentCard(cards[index-1]);
};
const likeButtonref = useRef<LottieView>(null);
const dislikeButtonref = useRef<LottieView>(null);
const discoveryButtonref = useRef<LottieView>(null);
const onLike = useCallback( () => {
likeButtonref.current?.reset();
likeButtonref.current?.play(0,55);
}, [])
// const hapti = (() => {
// Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)
// getValueFor(MY_SECURE_AUTH_STATE_KEY)
@ -147,56 +164,106 @@ export default function Spot() {
// };
// setInterval(sendLocationToServer, 30000)
const navigator = useNavigation();
const {width : wWidht} = Dimensions.get("window");
const hapti = (card : any) => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)
navigator.navigate("DetailsSpot", {"spot": card})
// Haptics.NotificationFeedbackType.Success
};
return (
<View style={styles.spot}>
<ImageBackground blurRadius={20}
<View style={{flex: 1,
}}>
{ cards.length > 0 ? (
<>
<ImageBackground blurRadius={7}
style={{
position: 'absolute',
width: "120%",
height: "120%",
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center",
opacity: 0.28
opacity: 0.48
}}
source={{
uri:currentCard.sourceUrl ,
}}
></ImageBackground>
></ImageBackground>
<View style={{flex : 1.65}}>
<LinearGradient colors={['rgba(2, 2, 2, 0.58) 0%','rgba(0, 0, 0, 0) 90.56%']}style={styles.gradient}>
<Text
style={{
fontStyle : 'normal',
left: wWidht/9 ,
top: 65,
color: "#FFFFFF",
fontSize: 20,
fontWeight: "800",
}}>LOST FOREST</Text>
<Text
style={{
fontStyle : 'normal',
left: wWidht/9 ,
top: 65,
color: "#FFFFFF",
fontSize: 18,
fontWeight: "800",
}}>Laylow</Text>
</LinearGradient>
</View>
<View style={{flex : 8.35}}>
{cards.map((card, index) => (
<View style={{flex : 1.83, justifyContent: 'center', alignItems: 'center' }}>
<View key={card.name} style = {{ position:'absolute'
}} >
<Pressable >
<Card
title={card.name}
image={card.sourceUrl}
/>
</Pressable>
{/* <Button
title="Success"
onPress={
() =>
Haptics.notificationAsync(
Haptics.NotificationFeedbackType.Success
)
}
></Button> */}
<FladButton name="discovery"/>
</View>
))}
{cards.map((card, index) => (
<View key={card.name} style = {{ position:'absolute'}} >
<Pressable onLongPress={() => {hapti(card)}} >
{/* <SharedElement id={card.name}> */}
<Card
title={card.name}
image={card.sourceUrl}
onSwipe={(direction) => {onSwipe(index, direction)}}
/>
{/* </SharedElement> */}
</Pressable>
</View>
))
}
</View>
{/* <LinearGradient
// Background Linear Gradient
colors={['rgba(0,0,0,0.8)', 'transparent']}
/> */}
<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} source={Lotties.likeAnimation} style={styles.lottie}/>
</TouchableOpacity>
</Animated.View>
</View>
</View>
</>)
: (<View style={{justifyContent : 'center', alignItems : 'center', flex : 1}}>
<View style={{flex:7}}>
<FladLoading></FladLoading>
</View>
<View style={{flex : 3 , justifyContent: 'flex-start'}}>
<Text style={{color: "grey", fontWeight: "400", textAlign: "center"}}>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>
</View>
</View>)
}
</View>
);
};
@ -205,7 +272,32 @@ export default function Spot() {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
alignContent : 'center',
flexDirection : 'column',
backgroundColor : '#000'
}
},
lottie : {
width : '100%',
},
button : {
setOpacityTo: 0.8,
alignItems : 'center',
borderRadius : 100,
justifyContent : 'center',
width: 61,
height: 61,
backgroundColor: '#24243A',
opacity : 0.8,
shadowRadius : 2,
},
gradient : {
position : "absolute",
top : 0,
left : 0,
right : 0,
height : 209,
},
})

Loading…
Cancel
Save