Clean spot screen and CardComponent 🎨
continuous-integration/drone/push Build is passing
Details
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 729 KiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 892 KiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 1.6 MiB |
After Width: | Height: | Size: 247 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 915 B |
@ -1,6 +1,5 @@
|
||||
const Lotties = {
|
||||
likeAnimation: require('./spotify-like-interaction.json')
|
||||
// riveLike : require('./light_like.riv'),
|
||||
}
|
||||
|
||||
export default Lotties;
|
@ -1,227 +0,0 @@
|
||||
import { View, Image, Dimensions, StyleSheet } from 'react-native'
|
||||
import React from 'react'
|
||||
import Animated, { interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
||||
import normalize from '../components/Normalize';
|
||||
import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
|
||||
|
||||
const SCREEN_WIDTH = Dimensions.get('window').width
|
||||
const SCREEN_HEIGHT = Dimensions.get('window').height
|
||||
|
||||
interface CardProps {
|
||||
title: string;
|
||||
image: any;
|
||||
onSwipe: (direction: "left" | "right" | "down") => void;
|
||||
}
|
||||
type ContextType = {
|
||||
translateX: number;
|
||||
translateY: number;
|
||||
};
|
||||
|
||||
const Card = ({ image, onSwipe }: CardProps) => {
|
||||
|
||||
const translateX = useSharedValue(0);
|
||||
const translateY = useSharedValue(0);
|
||||
const scale = useSharedValue(1);
|
||||
const onGestureEvent = useAnimatedGestureHandler<
|
||||
PanGestureHandlerGestureEvent,
|
||||
ContextType
|
||||
>({
|
||||
onStart: (event, context) => {
|
||||
context.translateX = translateX.value;
|
||||
context.translateY = translateY.value;
|
||||
},
|
||||
onActive: (event, context) => {
|
||||
translateX.value = event.translationX + context.translateX;
|
||||
translateY.value = event.translationY + context.translateY;
|
||||
|
||||
},
|
||||
onEnd: () => {
|
||||
|
||||
if (translateX.value > 160) {
|
||||
console.log("translateX2");
|
||||
runOnJS(onSwipe)("right");
|
||||
} else if (translateX.value < -160) {
|
||||
runOnJS(onSwipe)("left");
|
||||
} else if (translateY.value > 250) {
|
||||
runOnJS(onSwipe)("down");
|
||||
}
|
||||
|
||||
else {
|
||||
translateX.value = withSpring(0);
|
||||
translateY.value = withSpring(0);
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
//better to have 2 listerner => 2 useAnimatedStyle ou faire une ftc qui retourne l'verse de une useAnimatedStyle
|
||||
const opacLStyle = useAnimatedStyle(() => {
|
||||
const opacityl = interpolate
|
||||
(translateX.value,
|
||||
[-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4],
|
||||
[0, 0, 1]);
|
||||
return {
|
||||
opacity: opacityl,
|
||||
};
|
||||
});
|
||||
const opacRStyle = useAnimatedStyle(() => {
|
||||
const opacityl = interpolate
|
||||
(translateX.value,
|
||||
[-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 2],
|
||||
[1, 0, 0]);
|
||||
return {
|
||||
opacity: opacityl,
|
||||
};
|
||||
});
|
||||
|
||||
const opacCStyle = useAnimatedStyle(() => {
|
||||
const opacityl = interpolate
|
||||
(translateX.value,
|
||||
[-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 4],
|
||||
[0.35, 0, 0.35]);
|
||||
|
||||
|
||||
return {
|
||||
opacity: opacityl,
|
||||
};
|
||||
});
|
||||
const opacCStyle2 = useAnimatedStyle(() => {
|
||||
const opacityl = interpolate
|
||||
(translateY.value,
|
||||
[0, SCREEN_HEIGHT / 4],
|
||||
[0, 0.35]);
|
||||
|
||||
|
||||
return {
|
||||
opacity: opacityl,
|
||||
};
|
||||
});
|
||||
|
||||
const opacDStyle = useAnimatedStyle(() => {
|
||||
const opacityl = interpolate
|
||||
(translateY.value,
|
||||
[100, 300],
|
||||
[0, 1]);
|
||||
|
||||
return {
|
||||
opacity: opacityl,
|
||||
};
|
||||
});
|
||||
|
||||
const horizontalThreshold = SCREEN_WIDTH * 0.65;
|
||||
|
||||
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` },
|
||||
]
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<View>
|
||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||
<Animated.View style={[styleCardsNew, styles.container]}>
|
||||
<Animated.View style={[styles.image, {
|
||||
backgroundColor: 'black', elevation: 100,
|
||||
position: "absolute", borderWidth: 8, borderColor: '#FFF',
|
||||
zIndex: 1000,
|
||||
}, opacCStyle]}>
|
||||
</Animated.View>
|
||||
<Animated.View style={[styles.image, {
|
||||
backgroundColor: 'black', elevation: 100,
|
||||
position: "absolute", borderWidth: 8, borderColor: '#FFF',
|
||||
zIndex: 1000,
|
||||
}, opacCStyle2]}>
|
||||
</Animated.View>
|
||||
<Image source={{ uri: image }} style={[styles.image]} />
|
||||
<>
|
||||
<Animated.View
|
||||
style={[{
|
||||
elevation: 100,
|
||||
position: "absolute",
|
||||
zIndex: 1000,
|
||||
}, opacRStyle]}
|
||||
>
|
||||
<Image style={[{ alignSelf: "center" }]}
|
||||
source={require('../assets/images/dislike_icon.png')}
|
||||
/>
|
||||
</Animated.View>
|
||||
<Animated.View
|
||||
style={[{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: "absolute",
|
||||
justifyContent: "center",
|
||||
alignContent: "center",
|
||||
zIndex: 1000,
|
||||
elevation: 100,
|
||||
}, opacLStyle]}
|
||||
>
|
||||
<Image style={[{ alignSelf: "center" }]}
|
||||
source={require('../assets/images/like_icon.png')}
|
||||
|
||||
/>
|
||||
</Animated.View>
|
||||
<Animated.View
|
||||
style={[{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: "absolute",
|
||||
justifyContent: "center",
|
||||
alignContent: "center",
|
||||
elevation: 100,
|
||||
zIndex: 1000,
|
||||
}, opacDStyle]}
|
||||
>
|
||||
<Image style={[{
|
||||
alignSelf: "center", width: 126.27,
|
||||
height: 118.64,
|
||||
}]}
|
||||
source={require('../assets/images/discovery_icon.png')}
|
||||
|
||||
/>
|
||||
</Animated.View>
|
||||
</>
|
||||
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
image: {
|
||||
borderRadius: 24,
|
||||
resizeMode: 'stretch',
|
||||
height: normalize(420),
|
||||
width: normalize(420),
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}
|
||||
})
|
||||
|
||||
export default Card;
|
||||
|
@ -0,0 +1,212 @@
|
||||
import { View, Image, Dimensions, StyleSheet } from 'react-native'
|
||||
import React from 'react'
|
||||
import Animated, { interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
||||
import normalize from './Normalize';
|
||||
import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
|
||||
|
||||
const SCREEN_WIDTH = Dimensions.get('window').width;
|
||||
const SCREEN_HEIGHT = Dimensions.get('window').height;
|
||||
|
||||
interface CardProps {
|
||||
image: any;
|
||||
onSwipe: (direction: "left" | "right" | "down") => void;
|
||||
}
|
||||
|
||||
type ContextType = {
|
||||
translateX: number;
|
||||
translateY: number;
|
||||
};
|
||||
|
||||
export default function CardComponent(props: CardProps) {
|
||||
|
||||
const translateX = useSharedValue(0);
|
||||
const translateY = useSharedValue(0);
|
||||
const scale = useSharedValue(1);
|
||||
const onGestureEvent = useAnimatedGestureHandler<
|
||||
PanGestureHandlerGestureEvent,
|
||||
ContextType
|
||||
>({
|
||||
onStart: (event, context) => {
|
||||
context.translateX = translateX.value;
|
||||
context.translateY = translateY.value;
|
||||
},
|
||||
onActive: (event, context) => {
|
||||
translateX.value = event.translationX + context.translateX;
|
||||
translateY.value = event.translationY + context.translateY;
|
||||
},
|
||||
onEnd: () => {
|
||||
|
||||
if (translateX.value > SCREEN_WIDTH / 2) {
|
||||
runOnJS(props.onSwipe)("right");
|
||||
} else if (translateX.value < -SCREEN_WIDTH / 2) {
|
||||
runOnJS(props.onSwipe)("left");
|
||||
} else if (translateY.value > SCREEN_HEIGHT / 2) {
|
||||
runOnJS(props.onSwipe)("down");
|
||||
} else {
|
||||
translateX.value = withSpring(0);
|
||||
translateY.value = withSpring(0);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const opacityRightIcon = useAnimatedStyle(() => {
|
||||
const horizontal = interpolate
|
||||
(translateX.value,
|
||||
[-SCREEN_WIDTH / 4, 20, SCREEN_WIDTH / 4],
|
||||
[0, 0, 1]);
|
||||
|
||||
const vertical = interpolate
|
||||
(translateY.value,
|
||||
[20, SCREEN_HEIGHT / 4],
|
||||
[1, 0.2]);
|
||||
|
||||
return {
|
||||
opacity: horizontal * vertical,
|
||||
};
|
||||
});
|
||||
|
||||
const opacityLeftIcon = useAnimatedStyle(() => {
|
||||
const horizontal = interpolate
|
||||
(translateX.value,
|
||||
[-SCREEN_WIDTH / 4, -20, SCREEN_WIDTH / 4],
|
||||
[1, 0, 0]);
|
||||
|
||||
const vertical = interpolate
|
||||
(translateY.value,
|
||||
[20, SCREEN_HEIGHT / 4],
|
||||
[1, 0.2]);
|
||||
|
||||
return {
|
||||
opacity: horizontal * vertical,
|
||||
};
|
||||
});
|
||||
|
||||
const opacityDownIcon = useAnimatedStyle(() => {
|
||||
const vertical = interpolate
|
||||
(translateY.value,
|
||||
[20, SCREEN_HEIGHT / 2],
|
||||
[0, 1]);
|
||||
|
||||
const horizontal = interpolate
|
||||
(translateX.value,
|
||||
[-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 4],
|
||||
[0.5, 1, 0.5]);
|
||||
|
||||
return {
|
||||
opacity: vertical * horizontal,
|
||||
};
|
||||
});
|
||||
|
||||
const opacityHorizontalBackground = useAnimatedStyle(() => {
|
||||
const value = interpolate
|
||||
(translateX.value,
|
||||
[-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 4],
|
||||
[0.27, 0, 0.27]);
|
||||
return {
|
||||
opacity: value,
|
||||
};
|
||||
});
|
||||
|
||||
const opacityDownBackground = useAnimatedStyle(() => {
|
||||
const value = interpolate
|
||||
(translateY.value,
|
||||
[0, SCREEN_HEIGHT / 5],
|
||||
[0, 0.28]);
|
||||
return {
|
||||
opacity: value,
|
||||
};
|
||||
});
|
||||
|
||||
const horizontalThreshold = SCREEN_WIDTH * 0.65;
|
||||
|
||||
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` },
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<View>
|
||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||
<Animated.View style={[styleCardsNew, styles.container]}>
|
||||
<Animated.View style={[styles.image, styles.backgroundEffect, opacityHorizontalBackground]} />
|
||||
<Animated.View style={[styles.image, styles.backgroundEffect, opacityDownBackground]} />
|
||||
<Image source={{ uri: props.image }} style={[styles.image]} />
|
||||
<Animated.View style={[styles.iconContainer, opacityLeftIcon]}>
|
||||
<Image style={{ alignSelf: "center" }}
|
||||
source={require('../assets/images/dislike_icon.png')}
|
||||
/>
|
||||
</Animated.View>
|
||||
<Animated.View style={[styles.iconContainer, opacityRightIcon]} >
|
||||
<Image style={{ alignSelf: "center" }}
|
||||
source={require('../assets/images/like_icon.png')}
|
||||
/>
|
||||
</Animated.View>
|
||||
<Animated.View style={[styles.iconContainer, opacityDownIcon]}>
|
||||
<Image style={styles.icon}
|
||||
source={require('../assets/images/discovery_icon.png')}
|
||||
/>
|
||||
</Animated.View>
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
image: {
|
||||
borderRadius: 24,
|
||||
resizeMode: 'stretch',
|
||||
height: normalize(420),
|
||||
width: normalize(420),
|
||||
},
|
||||
backgroundEffect: {
|
||||
backgroundColor: 'black',
|
||||
elevation: 100,
|
||||
position: "absolute",
|
||||
borderWidth: 8,
|
||||
borderColor: '#FFF',
|
||||
zIndex: 1
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
shadowColor: "#000",
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 4,
|
||||
},
|
||||
shadowOpacity: 0.39,
|
||||
shadowRadius: 8.30,
|
||||
},
|
||||
iconContainer: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: "absolute",
|
||||
justifyContent: "center",
|
||||
alignContent: "center",
|
||||
elevation: 100,
|
||||
zIndex: 1
|
||||
},
|
||||
icon: {
|
||||
alignSelf: "center",
|
||||
width: 126.27,
|
||||
height: 118.64,
|
||||
}
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import Music from "../models/Music";
|
||||
import IMusicService from "./musics/interfaces/IMusicService";
|
||||
import Music from "../../models/Music";
|
||||
import IMusicService from "./interfaces/IMusicService";
|
||||
|
||||
export default class EmptyMusicService implements IMusicService {
|
||||
getImageArtistWithId(idArtist: string): Promise<string | null> {
|