-
-
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