-
-
Save furkancelik/168c2c7b0ddce86176eb242d4b416716 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* @flow */ | |
import React, { Component } from 'react'; | |
import { | |
TouchableOpacity, | |
Image, | |
View, | |
Text, | |
StatusBar, | |
ScrollView, | |
Dimensions, | |
CameraRoll, | |
Platform, | |
FlatList, | |
Animated, | |
MaskedViewIOS, | |
InteractionManager, | |
ActivityIndicator, | |
ImageEditor, | |
} from 'react-native'; | |
import { observer, inject } from 'mobx-react/native'; | |
import Icon from 'react-native-vector-icons/Ionicons'; | |
import Svg, { LinearGradient, Stop, Rect } from 'react-native-svg'; | |
import ProfilePictureItem from '../../components/Camera/ProfilePictureItem'; | |
import type { AppStore } from '../../types/stores/AppStore'; | |
import type { RegisterStore } from '../../types/stores/RegisterStore'; | |
const AFlatList: any = Animated.createAnimatedComponent(FlatList); | |
const { width }: { width: number } = Dimensions.get('window'); | |
type State = { | |
page: number, | |
loading: boolean, | |
images: ?Object, | |
selectImage: ?Object, | |
selected: ?Object, | |
randomPhoto: ?string, | |
allImages: ?Array<any>, | |
}; | |
type Props = { | |
navigation: Object, | |
registerStore: RegisterStore, | |
appStore: AppStore, | |
}; | |
@inject('appStore', 'registerStore') | |
@observer | |
export default class Picker extends Component<void, Props, State> { | |
props: Props; | |
state: State; | |
scrollY: Object; | |
cropImage: Object; | |
imageH: number; | |
imageW: number; | |
imageRatio: number; | |
zoomScale: number; | |
static navigationOptions = { | |
header: false, | |
}; | |
constructor(props: Props) { | |
super(props); | |
this.state = { | |
page: 0, | |
loading: false, | |
images: null, | |
selectImage: null, | |
selected: null, | |
randomPhoto: null, | |
allImages: null, | |
}; | |
this.scrollY = new Animated.Value(0); | |
} | |
shouldComponentUpdate(nextProps: Props, nextState: State) { | |
if ( | |
// nextState.selectImage !== this.state.selectImage || | |
this.state.images !== nextState.images || | |
this.state.randomPhoto !== nextState.randomPhoto | |
) { | |
return true; | |
} | |
return false; | |
} | |
componentWillMount() { | |
this.fetch(); | |
} | |
fetch() { | |
const { appStore } = this.props; | |
if (appStore.getProfilePictureLibrary === null) { | |
const fetchParams: { | |
first: number, | |
groupTypes: string, | |
assetType: string, | |
} = { | |
first: 1000, | |
groupTypes: 'SavedPhotos', | |
assetType: 'Photos', | |
}; | |
if (Platform.OS === 'android') { | |
delete fetchParams.groupTypes; | |
} | |
CameraRoll.getPhotos(fetchParams).then( | |
(data: Object) => this.appendImage((data: Object)), | |
(err: ?Object | ?string) => { | |
// console.log(err); | |
}, | |
); | |
} else { | |
const allImages: Array<any> = this.nEveryRow(appStore.getProfilePictureLibrary.edges, 100); | |
appStore.setSelectProfilePicture(appStore.getProfilePictureLibrary.edges[0]); | |
const images: Object = allImages[0]; | |
this.setState({ | |
selected: appStore.getProfilePictureLibrary.edges[0], | |
selectImage: appStore.getProfilePictureLibrary.edges[0], | |
images, | |
allImages, | |
loading: true, | |
}); | |
} | |
} | |
appendImage(data: { edges: Array<any> }) { | |
const { appStore } = this.props; | |
const allImages: Array<any> = this.nEveryRow(data.edges, 100); | |
appStore.setProfilePictureLibrary(data); | |
appStore.setSelectProfilePicture(data.edges[0]); | |
const images: Object = allImages[0]; | |
this.setState({ | |
selected: data.edges[0], | |
selectImage: data.edges[0], | |
images, | |
allImages, | |
loading: true, | |
}); | |
} | |
nEveryRow(data: Array<any>, n: number): Array<any> { | |
const result: Array<any> = []; | |
let temp: Array<any> = []; | |
for (let i = 0; i < data.length; ++i) { | |
if (i > 0 && i % n === 0) { | |
result.push(temp); | |
temp = []; | |
} | |
temp.push(data[i]); | |
} | |
if (temp.length > 0) { | |
result.push(temp); | |
} | |
return result; | |
} | |
setAnimate() { | |
Animated.timing(this.scrollY, { | |
toValue: 0, | |
duration: 300, | |
useNativeDriver: true, | |
}).start(); | |
} | |
selectImage(image: Object) { | |
this.setState({ selectImage: image }, this.setAnimate()); | |
} | |
gridRender(color: string = 'rgba(255,255,255,0.5)', lineSize: number = 0.5) { | |
return ( | |
<View style={{ position: 'absolute', zIndex: 1 }}> | |
<View | |
style={{ | |
position: 'absolute', | |
width, | |
height: lineSize, | |
backgroundColor: color, | |
top: width / 3 * 2, | |
}} | |
/> | |
<View | |
style={{ | |
position: 'absolute', | |
width, | |
height: lineSize, | |
backgroundColor: color, | |
top: width / 3, | |
}} | |
/> | |
<View | |
style={{ | |
position: 'absolute', | |
width: lineSize, | |
height: width, | |
backgroundColor: color, | |
top: 0, | |
left: width / 3, | |
}} | |
/> | |
<View | |
style={{ | |
position: 'absolute', | |
width: lineSize, | |
height: width, | |
backgroundColor: color, | |
top: 0, | |
left: width / 3 * 2, | |
}} | |
/> | |
</View> | |
); | |
} | |
imageRender(image: { width: number, height: number, uri: string }) { | |
let imageHeight: number = width; | |
let imageWidth: number = width; | |
let ratio: number = 1; | |
if (image.width > image.height) { | |
ratio = image.height / width; | |
imageHeight = width; | |
imageWidth = image.width / ratio; | |
} else { | |
ratio = image.width / width; | |
imageHeight = image.height / ratio; | |
imageWidth = width; | |
} | |
return ( | |
<Image | |
ref={(c: Object) => { | |
this.cropImage = c; | |
this.imageH = imageHeight; | |
this.imageW = imageWidth; | |
this.imageRatio = ratio; | |
}} | |
resizeMode={'contain'} | |
source={{ uri: image.uri }} | |
style={{ | |
height: imageHeight, | |
width: imageWidth, | |
}} | |
/> | |
); | |
} | |
render() { | |
const { appStore, registerStore, navigation } = this.props; | |
if (this.state.randomPhoto) { | |
return ( | |
<View style={{ flex: 1, marginTop: 50 }}> | |
<Image | |
source={{ uri: this.state.randomPhoto }} | |
style={{ | |
width, | |
height: width, | |
borderRadius: width / 2, | |
}} | |
/> | |
<TouchableOpacity | |
onPress={() => { | |
this.zoomScale = 1; | |
this.setState({ randomPhoto: null }); | |
}} | |
> | |
<Text>iptal</Text> | |
</TouchableOpacity> | |
</View> | |
); | |
} | |
if (!this.state.loading) { | |
return ( | |
<View | |
style={{ | |
backgroundColor: '#000', | |
justifyContent: 'center', | |
alignItems: 'center', | |
flex: 1, | |
}} | |
> | |
<StatusBar hidden /> | |
<ActivityIndicator | |
animating | |
style={{ alignItems: 'center', justifyContent: 'center', height: 80 }} | |
size="large" | |
/> | |
<Text style={{ color: '#fff', textAlign: 'center', fontSize: 15, fontWeight: '600' }}> | |
Resimleriniz Yükleniyor {'\n'} Lütfen Bekleyiniz | |
</Text> | |
</View> | |
); | |
} | |
if (this.state.images.length < 1) { | |
return ( | |
<View | |
style={{ | |
backgroundColor: '#000', | |
justifyContent: 'center', | |
alignItems: 'center', | |
flex: 1, | |
}} | |
> | |
<StatusBar hidden /> | |
<Text style={{ color: '#fff', textAlign: 'center', fontSize: 15, fontWeight: '600' }}> | |
Galeride Resim Bulunamadı | |
</Text> | |
</View> | |
); | |
} | |
const imageTranslate: Object = this.scrollY.interpolate({ | |
inputRange: [0, width], | |
outputRange: [0, -width], | |
extrapolate: 'clamp', | |
}); | |
return ( | |
<View style={{ flex: 1, backgroundColor: '#000' }}> | |
<StatusBar hidden /> | |
<AFlatList | |
onEndReached={() => { | |
const page: number = this.state.page + 1; | |
if (page < this.state.allImages.length) { | |
const images: Object = [...this.state.images, ...this.state.allImages[page]]; | |
this.setState({ | |
page, | |
images, | |
}); | |
} | |
}} | |
contentContainerStyle={{ | |
marginTop: width + 50, | |
paddingBottom: width + 50, | |
}} | |
numColumns={4} | |
keyExtractor={(item: { node: { image: { uri: string } } }) => item.node.image.uri} | |
data={this.state.images} | |
scrollEventThrottle={1} | |
style={{ flex: 1, backgroundColor: '#000', paddingLeft: 2 }} | |
onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: this.scrollY } } }], { | |
useNativeDriver: true, | |
})} | |
renderItem={({ item }: { item: Object }) => | |
(<ProfilePictureItem | |
selectImage={(image: Object) => { | |
// InteractionManager.runAfterInteractions(() => { | |
appStore.setSelectProfilePicture(image); | |
this.setAnimate(); | |
// }); | |
}} | |
selectImageItem={appStore.getSelectProfilePicture} | |
item={item} | |
/>)} | |
/> | |
<Animated.View | |
style={{ | |
position: 'absolute', | |
top: 0, | |
left: 0, | |
right: 0, | |
backgroundColor: '#000', | |
overflow: 'hidden', | |
transform: [{ translateY: imageTranslate }], | |
}} | |
> | |
<Svg width={width} height="50"> | |
<LinearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%"> | |
<Stop offset="0" stopColor="#7000e3" stopOpacity="1" /> | |
<Stop offset="1" stopColor="#e836a8" stopOpacity="1" /> | |
</LinearGradient> | |
<Rect x="0" y="0" width={width} height="50" fill="url(#grad)" /> | |
<View | |
style={{ | |
flex: 1, | |
alignItems: 'center', | |
justifyContent: 'center', | |
flexDirection: 'row', | |
}} | |
> | |
<View style={{ flex: 0 }}> | |
<TouchableOpacity | |
onPress={() => navigation.goBack()} | |
style={{ paddingTop: 5, paddingLeft: 10, paddingRight: 15 }} | |
> | |
<Icon name="ios-close" size={35} color="#FFF" /> | |
</TouchableOpacity> | |
</View> | |
<View | |
style={{ | |
flex: 1, | |
justifyContent: 'center', | |
alignItems: 'center', | |
}} | |
> | |
<Text | |
style={{ | |
flex: 0, | |
color: '#FFF', | |
fontSize: 17, | |
fontWeight: '500', | |
paddingTop: 5, | |
}} | |
> | |
Foto Galeri | |
</Text> | |
</View> | |
<View style={{ flex: 0 }}> | |
<TouchableOpacity | |
onPress={() => { | |
this.cropImage.measure((x, y, owidth, oheight, pageX, pageY) => { | |
pageY = (pageY - 50) * -1; // offset top header bar heih 50px | |
pageX *= -1; | |
const zoomScale: number = this.zoomScale || 1; | |
const w: number = this.imageW * this.imageRatio; | |
const h: number = this.imageH * this.imageRatio; | |
const _x: number = | |
(width - this.imageW) / 2 * this.imageRatio + pageX * this.imageRatio; | |
const _y: number = | |
(width - this.imageH) / 2 * this.imageRatio + pageY * this.imageRatio; | |
ImageEditor.cropImage( | |
appStore.selectProfilePicture.node.image.uri, | |
{ | |
offset: { | |
x: _x / zoomScale, | |
y: _y / zoomScale, | |
}, | |
size: { | |
width: w / zoomScale, | |
height: h / zoomScale, | |
}, | |
resizeMode: 'cover', | |
}, | |
(uri: string) => { | |
registerStore.setProfilePicture(uri); | |
navigation.goBack(); | |
// back page | |
}, | |
(e: Object) => { | |
// console.log(e) | |
}, | |
); | |
}); | |
}} | |
style={{ paddingTop: 5, paddingLeft: 15, paddingRight: 10 }} | |
> | |
<Icon name="ios-checkmark" size={35} color="#FFF" /> | |
</TouchableOpacity> | |
</View> | |
</View> | |
</Svg> | |
<View | |
onStartShouldSetResponder={(e: Object) => { | |
if (width - 50 <= e.nativeEvent.locationY) { | |
this.setAnimate(); | |
} | |
}} | |
style={{ | |
width, | |
height: width, | |
marginBottom: 4, | |
}} | |
> | |
{this.gridRender()} | |
<MaskedViewIOS | |
style={{ flex: 1 }} | |
maskElement={ | |
<View | |
style={{ | |
flex: 1, | |
backgroundColor: 'rgba(0,0,0,0.4)', | |
alignItems: 'center', | |
justifyContent: 'center', | |
}} | |
> | |
<View | |
style={{ | |
width, | |
height: width, | |
borderRadius: width / 2, | |
backgroundColor: '#FFF', | |
}} | |
/> | |
</View> | |
} | |
> | |
<ScrollView | |
showsHorizontalScrollIndicator={false} | |
showsVerticalScrollIndicator={false} | |
horizontal | |
contentContainerStyle={{ | |
alignItems: 'center', | |
justifyContent: 'center', | |
}} | |
> | |
<ScrollView | |
onScroll={(e: Object) => { | |
this.zoomScale = e.nativeEvent.zoomScale; | |
}} | |
scrollEventThrottle={16} | |
showsHorizontalScrollIndicator={false} | |
showsVerticalScrollIndicator={false} | |
contentContainerStyle={{ | |
alignItems: 'center', | |
justifyContent: 'center', | |
}} | |
maximumZoomScale={3} | |
minimumZoomScale={1} | |
> | |
{this.imageRender(appStore.getSelectProfilePicture.node.image)} | |
</ScrollView> | |
</ScrollView> | |
</MaskedViewIOS> | |
</View> | |
</Animated.View> | |
</View> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment