From 1d45a6b9340103861f5ff3fadf194d3a68ab3452 Mon Sep 17 00:00:00 2001 From: mathysPaul Date: Tue, 9 Jan 2024 17:18:14 +0100 Subject: [PATCH] [IMP] InteractiveCC: split in InteractiveBase & AnimatedBase --- front/components/UI/AnimatedBase.tsx | 128 +++++++++++++++++ front/components/UI/InteractiveBaseV2.tsx | 34 +++++ front/components/UI/InteractiveCC.tsx | 13 -- front/components/UI/useInteractionState.tsx | 48 +++++++ front/views/MusicView.tsx | 145 +++++++++++++++++++- 5 files changed, 348 insertions(+), 20 deletions(-) create mode 100644 front/components/UI/AnimatedBase.tsx create mode 100644 front/components/UI/InteractiveBaseV2.tsx create mode 100644 front/components/UI/useInteractionState.tsx diff --git a/front/components/UI/AnimatedBase.tsx b/front/components/UI/AnimatedBase.tsx new file mode 100644 index 0000000..0bf885f --- /dev/null +++ b/front/components/UI/AnimatedBase.tsx @@ -0,0 +1,128 @@ +import React, { useRef, useEffect } from 'react'; +import { Animated, StyleProp, StyleSheet, ViewStyle } from 'react-native'; + +type StyleObject = Record; +type InterpolatedStyleObject = Record>; + +interface AnimatedBaseProps { + style?: StyleObject; + defaultStyle: StyleObject; + hoverStyle: StyleObject; + pressStyle: StyleObject; + currentState: number; + duration?: number; + children?: React.ReactNode; + styleContainer?: StyleProp; +} + +const AnimatedBase: React.FC = ({ + style, + defaultStyle, + hoverStyle, + pressStyle, + currentState, + children, + duration = 250, + styleContainer, +}) => { + const animatedValues = useRef>({}).current; + + const extractTransformKeys = (styleObject: StyleObject) => { + return styleObject.transform + ? styleObject.transform.map((t: any) => Object.keys(t)[0]) + : []; + }; + + useEffect(() => { + const allStyleKeys = new Set([ + ...Object.keys(defaultStyle), + ...Object.keys(hoverStyle), + ...Object.keys(pressStyle), + ]); + + allStyleKeys.forEach((key) => { + if (!animatedValues[key]) { + animatedValues[key] = new Animated.Value(0); + console.log('key; ', key); + } + }); + + const allTransformKeys = new Set([ + ...extractTransformKeys(defaultStyle), + ...extractTransformKeys(hoverStyle), + ...extractTransformKeys(pressStyle), + ]); + + allTransformKeys.forEach((key) => { + if (!animatedValues[key]) { + animatedValues[key] = new Animated.Value(0); + console.log('keyxx; ', key); + } + }); + }, [defaultStyle, hoverStyle, pressStyle]); + + useEffect(() => { + animateToState(currentState); + }, [currentState]); + + const getTransformValue = (key: string, style: StyleObject) => { + const transformObject = style.transform?.find((t: any) => t.hasOwnProperty(key)); + return transformObject ? transformObject[key] : 0; + }; + + const interpolateStyle = (stateStyle: StyleObject): InterpolatedStyleObject => { + const interpolatedStyle: InterpolatedStyleObject = {}; + const transform: any = []; + + Object.keys(animatedValues).forEach((key) => { + if (stateStyle.transform?.some((t: any) => t.hasOwnProperty(key))) { + const defaultValue = getTransformValue(key, defaultStyle); + const hoverValue = getTransformValue(key, hoverStyle); + const pressValue = getTransformValue(key, pressStyle); + + const interpolated = animatedValues[key]!.interpolate({ + inputRange: [0, 1, 2], + outputRange: [defaultValue, hoverValue, pressValue], + }); + + transform.push({ [key]: interpolated }); + } else if (stateStyle[key]) { + const defaultValue = defaultStyle[key] || 0; + const hoverValue = hoverStyle[key] !== undefined ? hoverStyle[key] : defaultValue; + const pressValue = pressStyle[key] !== undefined ? pressStyle[key] : defaultValue; + + interpolatedStyle[key] = animatedValues[key]!.interpolate({ + inputRange: [0, 1, 2], + outputRange: [defaultValue, hoverValue, pressValue], + }); + } + }); + + if (transform.length > 0) { + interpolatedStyle.transform = transform; + } + + return interpolatedStyle; + }; + + const animateToState = (stateValue: number) => { + Object.keys(animatedValues).forEach((key) => { + Animated.timing(animatedValues[key]!, { + toValue: stateValue, + duration: duration, + useNativeDriver: false, + }).start(); + }); + }; + + const animatedStyle = StyleSheet.flatten([ + styleContainer, + interpolateStyle(defaultStyle), + interpolateStyle(hoverStyle), + interpolateStyle(pressStyle), + ]); + + return {children && children}; +}; + +export default AnimatedBase; diff --git a/front/components/UI/InteractiveBaseV2.tsx b/front/components/UI/InteractiveBaseV2.tsx new file mode 100644 index 0000000..3ab8d12 --- /dev/null +++ b/front/components/UI/InteractiveBaseV2.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { Pressable } from 'react-native'; + +interface InteractiveBaseProps { + handleHoverIn: () => void; + handleHoverOut: () => void; + handlePressIn: () => void; + handlePressOut: () => void; + children: React.ReactNode; + style?: any; +} + +const InteractiveBase: React.FC = ({ + handleHoverIn, + handleHoverOut, + handlePressIn, + handlePressOut, + children, + style, +}) => { + return ( + + {children} + + ); +}; + +export default InteractiveBase; diff --git a/front/components/UI/InteractiveCC.tsx b/front/components/UI/InteractiveCC.tsx index c792e33..c05b27e 100644 --- a/front/components/UI/InteractiveCC.tsx +++ b/front/components/UI/InteractiveCC.tsx @@ -5,19 +5,6 @@ import { Animated, StyleSheet, Pressable, ViewStyle, StyleProp } from 'react-nat type StyleObject = Record; type InterpolatedStyleObject = Record>; -const TRANSFORM_WHITELIST = { - translateX: true, - translateY: true, - scale: true, - scaleX: true, - scaleY: true, - rotate: true, - rotateX: true, - rotateY: true, - rotateZ: true, - perspective: true, -}; - interface InteractiveCCProps { defaultStyle: StyleObject; hoverStyle: StyleObject; diff --git a/front/components/UI/useInteractionState.tsx b/front/components/UI/useInteractionState.tsx new file mode 100644 index 0000000..56cfcc5 --- /dev/null +++ b/front/components/UI/useInteractionState.tsx @@ -0,0 +1,48 @@ +import { useState, useCallback } from 'react'; + +const InteractionStates = { + NORMAL: 0, + HOVER: 1, + PRESSED: 2, +}; + +interface InteractionStateProps { + onHoverIn?: () => void; + onHoverOut?: () => void; + onPressIn?: () => void; + onPressOut?: () => void; +} + +const useInteractionState = ({ onHoverIn, onHoverOut, onPressIn, onPressOut }: InteractionStateProps = {}) => { + const [state, setState] = useState(InteractionStates.NORMAL); + + const handleHoverIn = useCallback(() => { + setState(InteractionStates.HOVER); + if (onHoverIn) onHoverIn(); + }, [onHoverIn]); + + const handleHoverOut = useCallback(() => { + setState(InteractionStates.NORMAL); + if (onHoverOut) onHoverOut(); + }, [onHoverOut]); + + const handlePressIn = useCallback(() => { + setState(InteractionStates.PRESSED); + if (onPressIn) onPressIn(); + }, [onPressIn]); + + const handlePressOut = useCallback(() => { + setState(InteractionStates.HOVER); + if (onPressOut) onPressOut(); + }, [onPressOut]); + + return { + state, + handleHoverIn, + handleHoverOut, + handlePressIn, + handlePressOut, + }; +}; + +export default useInteractionState; diff --git a/front/views/MusicView.tsx b/front/views/MusicView.tsx index 4ba6d01..4eab9b5 100644 --- a/front/views/MusicView.tsx +++ b/front/views/MusicView.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { useBreakpointValue, useTheme } from 'native-base'; -import { useWindowDimensions } from 'react-native'; +import { View, useBreakpointValue, useTheme, Text } from 'native-base'; +import { StyleProp, ViewStyle, useWindowDimensions } from 'react-native'; import { TabView, SceneMap, @@ -20,6 +20,68 @@ import API from '../API'; import { LoadingView } from '../components/Loading'; import { useLikeSongMutation } from '../utils/likeSongMutation'; import Song from '../models/Song'; +import InteractiveCC from '../components/UI/InteractiveCC'; +import ButtonBase from '../components/UI/ButtonBase'; +import InteractiveBase from '../components/UI/InteractiveBaseV2'; +import AnimatedBase from '../components/UI/AnimatedBase'; +import useInteractionState from '../components/UI/useInteractionState'; + +// import React from 'react'; +// import { Text, View } from 'react-native'; +// import InteractiveBase from './InteractiveBase'; +// import AnimatedBase from './AnimatedBase'; +// import useInteractionState from './useInteractionState'; + +interface LinkBaseProps { + text: string; + style?: StyleProp; + textStyle?: StyleProp; + underlineStyle?: StyleProp; + fontSize?: number; + onPress: () => void; +} + +const AnimatedLink = ({ text, style, textStyle, underlineStyle, fontSize = 14 }: LinkBaseProps) => { + const interaction = useInteractionState({ + onPressOut: () => { console.log("AnimatedLink is activate")} + }); + const { colors } = useTheme(); + + const defaultUnderlineStyle = { height: fontSize / 8, bottom: 0 }; + const hoverUnderlineStyle = { height: fontSize * 1.5, bottom: 0 }; + const pressUnderlineStyle = { height: 0, bottom: fontSize * 1.5 }; + + return ( + + + + + {/* {fontSize: fontSize}, */} + {text} + + + + + + ); +}; + type MusicListCCProps = { data: Song[] | undefined; @@ -58,12 +120,81 @@ const MusicListCC = ({ data, isLoading, refetch }: MusicListCCProps) => { const FavoritesMusic = () => { const likedSongs = useQuery(API.getLikedSongs(['artist', 'SongHistory', 'likedByUsers'])); + const { colors } = useTheme(); + const interaction = useInteractionState(); + return ( - x.song)} - isLoading={likedSongs.isLoading} - refetch={likedSongs.refetch} - /> + <> + + console.log("Je suis le lien !!!")}/> + + + + Text + + + + console.log("A que coucou!")} + > + + Coucou + + + + + x.song)} + isLoading={likedSongs.isLoading} + refetch={likedSongs.refetch} + /> + ); };