parent
a08ac09ccc
commit
b3adc54e22
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 569 KiB |
After Width: | Height: | Size: 489 KiB |
After Width: | Height: | Size: 22 KiB |
@ -0,0 +1,87 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { View, StyleSheet, TouchableOpacity , Animated } from 'react-native';
|
||||
import Svg, { G, Circle } from 'react-native-svg';
|
||||
import { AntDesign } from '@expo/vector-icons';
|
||||
|
||||
export default function NextButton({ percentage, scrollTo }) {
|
||||
const size = 128;
|
||||
const strokeWidth = 2;
|
||||
const center = size / 2;
|
||||
const radius = size / 2 - strokeWidth / 2;
|
||||
const circumFerence = 2 * Math.PI * radius;
|
||||
|
||||
const progressAnimation = useRef(new Animated.Value(0)).current;
|
||||
const progressRef = useRef(null);
|
||||
|
||||
const animation = (toValue) => {
|
||||
return Animated.timing(progressAnimation, {
|
||||
toValue,
|
||||
duration: 250,
|
||||
useNativeDriver: true
|
||||
}).start()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
animation(percentage);
|
||||
}, [percentage]);
|
||||
|
||||
useEffect(() => {
|
||||
progressAnimation.addListener(
|
||||
(value) => {
|
||||
const strokeDashoffset = circumFerence - (circumFerence * value.value) / 100;
|
||||
|
||||
if (progressRef?.current) {
|
||||
progressRef.current.setNativeProps({
|
||||
strokeDashoffset,
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
[percentage]
|
||||
|
||||
);
|
||||
|
||||
return () => {
|
||||
progressAnimation.removeAllListeners();
|
||||
};
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Svg width={size} height={size}>
|
||||
<G rotation="-90" origin={center}>
|
||||
<Circle stroke="#E6E7E8" fill="#141414" cx={center} cy={center} r={radius} strokeWidth={strokeWidth}/>
|
||||
<Circle
|
||||
ref={progressRef}
|
||||
stroke="#3F2F78"
|
||||
fill="#141414"
|
||||
cx={center}
|
||||
cy={center}
|
||||
r={radius}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={circumFerence}
|
||||
/>
|
||||
</G>
|
||||
</Svg>
|
||||
<TouchableOpacity onPress={scrollTo} style={styles.button} activeOpacity={0.6}>
|
||||
<AntDesign name="arrowright" size={32} color="#fff" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: -70
|
||||
},
|
||||
button: {
|
||||
position: 'absolute',
|
||||
backgroundColor: '#3F2F78',
|
||||
borderRadius: 100,
|
||||
padding: 20
|
||||
}
|
||||
})
|
@ -0,0 +1,69 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { View, StyleSheet, Text, FlatList, Animated } from 'react-native';
|
||||
|
||||
import OnboardingItem from './OnboardingItem';
|
||||
import Paginator from './Paginator';
|
||||
import NextButton from './NextButton';
|
||||
import slides from '../data/slides';
|
||||
|
||||
export default function Onboarding() {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const scrollX = useRef(new Animated.Value(0)).current;
|
||||
const slidesRef = useRef(null);
|
||||
|
||||
const viewableItemsChanged = useRef(({ viewableItems }) => {
|
||||
setCurrentIndex(viewableItems[0].index);
|
||||
}).current;
|
||||
|
||||
const viewConfig = useRef({ viewAreaCoveragePercentThreshold: 50 }).current;
|
||||
|
||||
const scrollTo = () => {
|
||||
if(currentIndex < slides.length - 1) {
|
||||
slidesRef.current.scrollToIndex({ index: currentIndex + 1 });
|
||||
} else {
|
||||
console.log('Last item.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={{ flex: 3 }}>
|
||||
<FlatList
|
||||
data={slides}
|
||||
renderItem={({item}) => <OnboardingItem item={item} />}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
pagingEnabled
|
||||
bounces={false}
|
||||
keyExtractor={(item) => item.id}
|
||||
onScroll={Animated.event([{ nativeEvent: { contentOffset: { x: scrollX } } }], {
|
||||
useNativeDriver: false,
|
||||
})}
|
||||
scrollEventThrottle={32}
|
||||
onViewableItemsChanged={viewableItemsChanged}
|
||||
viewabilityConfig={viewConfig}
|
||||
ref={slidesRef}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.balise}>
|
||||
<Paginator data={slides} scrollX={scrollX}/>
|
||||
<NextButton scrollTo={scrollTo} percentage={(currentIndex + 1) * (100 / slides.length)} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#141414'
|
||||
},
|
||||
balise: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: -130
|
||||
}
|
||||
})
|
@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import { View, StyleSheet, Text, Image, useWindowDimensions } from 'react-native';
|
||||
|
||||
import slides from '../data/slides';
|
||||
|
||||
export default function Onboarding({ item }) {
|
||||
const { width } = useWindowDimensions();
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { width }]}>
|
||||
<Image source={item.image} style={[styles.image, { width, resizeMode: 'contain'}]} />
|
||||
|
||||
<View style={{ flex: 0.7 }}>
|
||||
<Text style={styles.title}>{item.title}</Text>
|
||||
<Text style={styles.description}>{item.description}</Text>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-start',
|
||||
marginTop: -60
|
||||
},
|
||||
image: {
|
||||
justifyContent: 'center'
|
||||
},
|
||||
title: {
|
||||
fontWeight: '800',
|
||||
fontSize: 28,
|
||||
marginBottom: 10,
|
||||
color: 'white',
|
||||
textAlign: 'left',
|
||||
paddingRight: 30,
|
||||
paddingLeft: 20,
|
||||
marginTop: -80
|
||||
},
|
||||
description: {
|
||||
fontWeight: '300',
|
||||
color: 'white',
|
||||
textAlign: 'left',
|
||||
paddingRight: 30,
|
||||
paddingLeft: 20
|
||||
}
|
||||
})
|
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { View, StyleSheet, Animated, useWindowDimensions } from 'react-native';
|
||||
|
||||
|
||||
export default function Paginator({ data, scrollX }) {
|
||||
const { width } = useWindowDimensions();
|
||||
|
||||
return (
|
||||
<View style={{flexDirection: 'row', height: 64}}>
|
||||
{data.map((_, i) => {
|
||||
const inputRange = [(i - 1) * width, i * width, (i + 1) * width];
|
||||
|
||||
const dotWidth = scrollX.interpolate({
|
||||
inputRange,
|
||||
outputRange: [10, 20, 10],
|
||||
extrapolate: 'clamp',
|
||||
})
|
||||
|
||||
const opacity = scrollX.interpolate({
|
||||
inputRange,
|
||||
outputRange: [0.3, 1, 0.3],
|
||||
extrapolate: 'clamp'
|
||||
})
|
||||
|
||||
return <Animated.View
|
||||
style={[
|
||||
styles.dot,
|
||||
{
|
||||
width: dotWidth,
|
||||
opacity,
|
||||
}
|
||||
]}
|
||||
key={i.toString()}
|
||||
/>
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
dot: {
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
backgroundColor: "#fff",
|
||||
marginHorizontal: 8
|
||||
}
|
||||
})
|
@ -0,0 +1,20 @@
|
||||
export default [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Bienvenue sur Flad',
|
||||
description: 'L\'application pour découvrir de nouvelle music et vous faires de nouveaux amis',
|
||||
image: require('../assets/images/Board_Image.png')
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Tous les jours de nouvelle music qui peut vous plaire',
|
||||
description: 'L\'application apprend de vous et de vos amis pour vos suggérer des albums et séries',
|
||||
image: require('../assets/images/Board_Image2.png')
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'La music ça se partage',
|
||||
description: 'Faites connaissances avec de nouvelles personnes et partagez vos critiques',
|
||||
image: require('../assets/images/Board_Image3.png')
|
||||
}
|
||||
]
|
@ -0,0 +1,16 @@
|
||||
import React, {Component} from 'react';
|
||||
import FavoritePage from '../screens/favoritePage';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
|
||||
export default function MusicNavigation() {
|
||||
const Stack = createStackNavigator();
|
||||
return (
|
||||
<Stack.Navigator initialRouteName="FavoritePage">
|
||||
<Stack.Screen
|
||||
name="FavoritePage"
|
||||
component={FavoritePage}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
)
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import React, {Component} from 'react';
|
||||
import LoginPage from '../screens/loginPage';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import Navigation from './Navigation';
|
||||
|
||||
export default function LoginNavigation() {
|
||||
const Stack = createStackNavigator();
|
||||
console.log("je suis ici");
|
||||
return (
|
||||
<Stack.Navigator initialRouteName="Login">
|
||||
<Stack.Screen
|
||||
name="Login"
|
||||
component={LoginPage}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Home"
|
||||
component={Navigation}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
)
|
||||
}
|
@ -1,36 +1,35 @@
|
||||
import React, {Component} from 'react';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import Home from '../screens/spot';
|
||||
import FavoritePage from '../screens/favoritePage';
|
||||
import LoginPage from '../screens/loginPage';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import FavoriteNavigation from './FavoriteNavigation';
|
||||
import FontAwesome from 'react-native-vector-icons/FontAwesome';
|
||||
|
||||
export default function StackNavigation() {
|
||||
const Stack = createBottomTabNavigator();
|
||||
return (
|
||||
<NavigationContainer>
|
||||
<Stack.Navigator initialRouteName="Home"
|
||||
screenOptions={{
|
||||
|
||||
}}>
|
||||
<Stack.Screen
|
||||
name="Home"
|
||||
component={FavoritePage}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Favoris"
|
||||
component={LoginPage}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Settings"
|
||||
component={FavoritePage}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
export default function Navigation() {
|
||||
const BottomTabNavigator = createBottomTabNavigator();
|
||||
const MyTheme = {
|
||||
dark: false,
|
||||
colors: {
|
||||
primary: 'rgb(255, 45, 85)',
|
||||
card: 'rgb(35, 33, 35)',
|
||||
border: 'rgb(35, 33, 35)',
|
||||
},
|
||||
};
|
||||
return (
|
||||
<NavigationContainer theme={MyTheme}>
|
||||
<BottomTabNavigator.Navigator initialRouteName="Home">
|
||||
<BottomTabNavigator.Screen name="Home" component={FavoriteNavigation}
|
||||
options={{
|
||||
headerShown: false,
|
||||
tabBarIcon: ({color}) => <TabBarIcon name="music" color={color}/>,
|
||||
}}/>
|
||||
</BottomTabNavigator.Navigator>
|
||||
</NavigationContainer>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function TabBarIcon(props: {
|
||||
name: React.ComponentProps<typeof FontAwesome>['name'];
|
||||
color: string;
|
||||
}) {
|
||||
return <FontAwesome size={30} {...props} />;
|
||||
}
|
Loading…
Reference in new issue