Skip to content

Instantly share code, notes, and snippets.

@WarrenBuffering
Created June 18, 2024 03:18
Show Gist options
  • Save WarrenBuffering/81bee55e16e69b035a70f6d0fa2bd097 to your computer and use it in GitHub Desktop.
Save WarrenBuffering/81bee55e16e69b035a70f6d0fa2bd097 to your computer and use it in GitHub Desktop.
import React, { Component } from 'react'
import { Animated, Dimensions, Easing, PanResponder, SafeAreaView, StyleSheet, Text, View } from 'react-native'
import { connect } from 'react-redux'
import FastImage from 'react-native-fast-image'
// Actions & Selectors
import { setCurrComp, setNextComp, setPrevComp } from '../actions'
import { getCurrComp, getNextComp, getPrevComp } from '../selectors/comps'
import { getActiveProject } from '../selectors/projects'
import { wait } from '../../../utils'
import slides from '../../../json/workSlides.json'
class WorkComps extends Component {
screenWidth = Dimensions.get('window').width
screenHeight = Dimensions.get('window').height
imageWidth = this.screenWidth * .8
imageHeight = this.imageWidth * 1.4125
slideTransY = new Animated.Value(0)
backgroundOpacity = new Animated.Value(1)
slideOpacity = new Animated.Value(1)
prevSlideZ = new Animated.Value(0)
nextSlideZ = new Animated.Value(0)
_handleSwipeLeft = async () => {
await this.props.setPrevComp(0)
await this.props.setCurrComp(0),
await this.props.setNextComp(1)
this.props.navigation.navigate('WorkProjects')
}
_handleSwipeNotCompleted = () => {
Animated.timing(this.backgroundOpacity, {
toValue: 1,
duration: 200,
easing: Easing.ease
}).start()
Animated.timing(this.slideOpacity, {
toValue: 1,
duration: 100
}).start()
Animated.timing(this.slideTransY, {
toValue: 0,
duration: 200,
easing: Easing.bezier(.72,.35,.24,.97)
}).start()
}
_panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (evt, { dy }) => {
this.slideTransY.setValue((dy) * .1)
this.backgroundOpacity.setValue( 1 - (Math.abs(dy) / this.screenHeight) * .7)
this.slideOpacity.setValue( 1 - ((Math.abs(dy) / this.screenHeight) * 2))
this.prevSlideZ.setValue( dy > 0 ? 99 : 9 )
this.nextSlideZ.setValue( dy > 0 ? 9 : 99 )
},
onPanResponderRelease: (evt, { dx, dy, vx, vy }) => {
const { screenHeight, screenWidth } = this
const { currComp, activeProject } = this.props
const comps = slides[this.props.activeProject].comps
if (Math.abs(dx) >= screenWidth * .4) {
if (dx > 0) {
this._handleSwipeLeft()
}
} else if (currComp === 0 && dy > 0) {
this._handleSwipeNotCompleted()
} else if ( currComp === comps.endOfSlides && dy < 0) {
this._handleSwipeNotCompleted()
} else if (Math.abs(vy) >= .5 || Math.abs(dy) >= 0.2 * screenHeight) {
if (dy > 0) {
this._handleSwipeDownComplete(dy)
} else if (dy < 0) {
this._handleSwipeUpComplete(dy)
}
} else {
this._handleSwipeNotCompleted()
}
},
});
_handleSwipeUpComplete = async () => {
const { activeProject, prevComp, currComp, nextComp, setPrevComp, setCurrComp, setNextComp } = this.props
const comps = slides[this.props.activeProject].comps
const { endOfSlides } = comps
if (currComp < endOfSlides) {
setCurrComp(nextComp)
}
Animated.timing(this.backgroundOpacity, {
toValue: 1,
duration: 300,
}).start()
this.slideOpacity.setValue(0)
this.slideTransY.setValue(50)
Animated.timing(this.slideTransY, {
toValue: 0,
duration: 300,
}).start()
Animated.timing(this.slideOpacity, {
toValue: 1,
duration: 300
}).start()
await wait(300)
let newNextComp
if (nextComp === endOfSlides) {
newNextComp = nextComp
} else {
newNextComp = nextComp + 1
}
setPrevComp(currComp)
setNextComp(newNextComp)
}
_handleSwipeDownComplete = async () => {
const { prevComp, currComp, nextComp, setPrevComp, setCurrComp, setNextComp } = this.props
const comps = slides[this.props.activeProject].comps
setCurrComp(prevComp)
Animated.timing(this.backgroundOpacity, {
toValue: 1,
duration: 300,
}).start()
this.slideOpacity.setValue(0)
this.slideTransY.setValue(-50)
Animated.timing(this.slideTransY, {
toValue: 0,
duration: 300,
}).start()
Animated.timing(this.slideOpacity, {
toValue: 1,
duration: 300
}).start()
await wait(300)
let newPrevComp
if (prevComp === 0) {
newPrevComp = prevComp
} else {
newPrevComp = prevComp - 1
}
setPrevComp(newPrevComp)
setNextComp(currComp)
}
render() {
const { prevComp, currComp, nextComp, activeProject } = this.props
const { backgroundOpacity, imageHeight, imageWidth, slideTransY, nextSlideZ, prevSlideZ, screenHeight, screenWidth, slideOpacity } = this
const themeColor = slides[activeProject].themeColor
const comps = slides[activeProject].comps
return (
<View style={[styles.wrap]}>
<Animated.View
style={{
backgroundColor: themeColor,
opacity: backgroundOpacity,
height: screenHeight,
position: 'absolute',
width: screenWidth,
zIndex: prevSlideZ,
justifyContent: 'flex-end',
alignItems: 'center'
}}>
<View style={{ height: screenHeight * .6 }}>
<FastImage
source={{ uri: comps[prevComp].img }}
style={[
styles.image, {
height: imageHeight,
width: imageWidth
}
]}
/>
</View>
</Animated.View>
<Animated.View
style={{
backgroundColor: themeColor,
opacity: backgroundOpacity,
height: screenHeight,
position: 'absolute',
width: screenWidth,
zIndex: nextSlideZ,
justifyContent: 'flex-end',
alignItems: 'center'
}}>
<View style={{ height: screenHeight * .6 }}>
<FastImage
source={{ uri: comps[nextComp].img }}
style={[
styles.image, {
height: imageHeight,
width: imageWidth
}
]}
/>
</View>
</Animated.View>
<Animated.View
style={{
backgroundColor: themeColor,
opacity: backgroundOpacity,
height: screenHeight,
position: 'absolute',
width: screenWidth,
zIndex: 9999,
justifyContent: 'flex-end',
alignItems: 'center'
}}>
<View style={{ height: screenHeight * .6 }}>
<FastImage
source={{ uri: comps[currComp].img }}
style={[
styles.image, {
height: imageHeight,
width: imageWidth
}
]}
/>
</View>
</Animated.View>
<SafeAreaView style={styles.safeAreaView}>
<Animated.View
style={[
styles.panel, {
transform: [{
translateY: slideTransY
}],
height: screenHeight,
paddingBottom: screenHeight * .65,
opacity: slideOpacity,
width: screenWidth,
}]}
{...this._panResponder.panHandlers}
>
<View>
<Text style={styles.title}>{comps[currComp].title}</Text>
<Text style={styles.subtitle}>{comps[currComp].subtitle}</Text>
</View>
</Animated.View>
</SafeAreaView>
</View>
)
}
}
const styles = StyleSheet.create({
wrap: {
flex: 1,
},
safeAreaView: {
height: '100%',
position: 'absolute',
width: '100%',
zIndex: 99999999999,
},
panel: {
justifyContent: 'flex-end',
position: 'absolute',
zIndex: 99999,
paddingHorizontal: '8%'
},
title: {
color: '#fff',
fontSize: 22,
fontFamily: 'Barlow-Bold',
marginBottom: 14,
textAlign: 'center',
},
subtitle: {
color: '#fff',
fontSize: 14,
fontFamily: 'Barlow-Medium',
lineHeight: 20,
marginBottom: 20,
textAlign: 'center'
},
})
const mapStateToProps = state => ({
activeProject: getActiveProject(state),
currComp: getCurrComp(state),
nextComp: getNextComp(state),
prevComp: getPrevComp(state),
})
const mapDispatchToProps = dispatch => ({
setCurrComp: (index) => dispatch(setCurrComp(index)),
setNextComp: (index) => dispatch(setNextComp(index)),
setPrevComp: (index) => dispatch(setPrevComp(index))
})
export default connect(mapStateToProps, mapDispatchToProps)(WorkComps)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment