<commit_before>// @flow
'use strict';

import React, { Component, PropTypes } from 'react';
import {
  Animated,
  Dimensions,
  PanResponder,
  StyleSheet,
  Text,
  View
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';

class SideMenu extends Component {
  static propTypes = {
    headerComponent: PropTypes.element.isRequired,
    height: PropTypes.number,
    menu: PropTypes.element,
    menuWidth: PropTypes.number.isRequired,
    menuOpenBuffer: PropTypes.number.isRequired,
    openMenu: PropTypes.bool,
    onMenuOpened: PropTypes.func,
    useLinearGradient: PropTypes.bool,
    width: PropTypes.number,
  }
  
  constructor(props) {
    super(props);

    // bindings
    this._menuIsOpenToThreshold = this._menuIsOpenToThreshold.bind(this);
    this._openOrCloseMenu = this._openOrCloseMenu.bind(this);
    this._absoluteXValueOfCurrentSceneDuringPan = this._absoluteXValueOfCurrentSceneDuringPan.bind(this);

    // State not used in render method
    this._isMenuOpen = false;

    this.state = {
      pan: new Animated.ValueXY(),
      panResponder: PanResponder.create({
        onStartShouldSetPanResponder: () => true,
        onMoveShouldSetPanResponder: (evt, gestureState) => {
          return gestureState.dx != 0 && gestureState.dy != 0;
        },
        onPanResponderGrant: this._handlePanResponderGrant.bind(this),
        onPanResponderMove: this._handlePanResponderMove.bind(this),
        onPanResponderRelease: this._handlePanResponderEnd.bind(this),
        onPanResponderTerminate: this._handlePanResponderEnd.bind(this),
      })
    };
  }

  componentWillReceiveProps(nextProps: object) {
    this._openOrCloseMenu(nextProps.openMenu)
  }

  render() {
    const screenWidth = Dimensions.get('window').width;
    const screenHeight = Dimensions.get('window').height;
    let menuStyle = {
      position: 'absolute',
      width: this.props.width ? this.props.width : screenWidth,
      height: this.props.height ? this.props.height : screenHeight,
    };

    return (
      <View>
        <View style={menuStyle}>
          {this.props.menu}
        </View>
        <Animated.View style={[this.state.pan.getLayout(), menuStyle]}>
          <View style={this.props.useLinearGradient ? styles.sceneContainer : [styles.sceneContainer, {marginLeft: 0}]}>
            {this.props.useLinearGradient
              ? <LinearGradient
                  start={[0.0, 0.0]} end={[1.0, 0.0]}
                  colors={['transparent', 'rgba(0, 0, 0, 0.1)']}
                  style={styles.linearGradient}
                />
              : <View />}
            <View style={{flex: 1}}>
              <View {...this.state.panResponder.panHandlers}>
                {this.props.headerComponent}
              </View>
              {this.props.children}
            </View>
          </View>
        </Animated.View>
      </View>
    );
  }

  _handlePanResponderGrant(e: Object, gestureState: Object) {
    // set the offset to be 0 or the menu width, and reset the values to 0 to avoid a jump
    // before the binding with gestureState.dx takes over and resets the x value
    this.state.pan.setOffset({x: this.state.pan.x._value, y: 0});
    this.state.pan.setValue({x: 0, y: 0});
  }

  _handlePanResponderMove(e: Object, gestureState: Object) {
    // update pan.x unless pan goes off left of screen. Then set pan to be the very left 
    if (this._absoluteXValueOfCurrentSceneDuringPan(gestureState.dx) >= 0)
      this.state.pan.setValue({x: gestureState.dx, y: 0});
    else
      this.state.pan.setValue({x: this._isMenuOpen ? -this.props.menuWidth : 0, y: 0});
  }

  _handlePanResponderEnd(e: Object, gestureState: Object) {
    // Set x value to be absolute position because the animation is from an offset of 0,
    // and currently the offset may be the menuWidth
    if (this._isMenuOpen)<commit_msg>Finally get opening menu anywhere on screen and scrolling up and down working<commit_after>// @flow
'use strict';

import React, { Component, PropTypes } from 'react';
import {
  Animated,
  Dimensions,
  PanResponder,
  StyleSheet,
  Text,
  View
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';

class SideMenu extends Component {
  static propTypes = {
    headerComponent: PropTypes.element.isRequired,
    height: PropTypes.number,
    menu: PropTypes.element,
    menuWidth: PropTypes.number.isRequired,
    menuOpenBuffer: PropTypes.number.isRequired,
    openMenu: PropTypes.bool,
    onMenuOpened: PropTypes.func,
    useLinearGradient: PropTypes.bool,
    width: PropTypes.number,
  }
  
  constructor(props) {
    super(props);

    // bindings
    this._menuIsOpenToThreshold = this._menuIsOpenToThreshold.bind(this);
    this._openOrCloseMenu = this._openOrCloseMenu.bind(this);
    this._absoluteXValueOfCurrentSceneDuringPan = this._absoluteXValueOfCurrentSceneDuringPan.bind(this);

    // State not used in render method
    this._isMenuOpen = false;

    this.state = {
      pan: new Animated.ValueXY(),
      panResponder: PanResponder.create({
        onStartShouldSetPanResponder: this._shouldRespondToPan.bind(this),
        onMoveShouldSetPanResponder: this._shouldRespondToPan.bind(this),
        onPanResponderGrant: this._handlePanResponderGrant.bind(this),
        onPanResponderMove: this._handlePanResponderMove.bind(this),
        onPanResponderRelease: this._handlePanResponderEnd.bind(this),
        onPanResponderTerminate: this._handlePanResponderEnd.bind(this),
      })
    };
  }

  componentWillReceiveProps(nextProps: object) {
    this._openOrCloseMenu(nextProps.openMenu)
  }

  render() {
    const screenWidth = Dimensions.get('window').width;
    const screenHeight = Dimensions.get('window').height;
    let menuStyle = {
      position: 'absolute',
      width: this.props.width ? this.props.width : screenWidth,
      height: this.props.height ? this.props.height : screenHeight,
    };

    return (
      <View>
        <View style={menuStyle}>
          {this.props.menu}
        </View>
        <Animated.View
          {...this.state.panResponder.panHandlers}
          style={[this.state.pan.getLayout(), menuStyle]}>
          <View style={this.props.useLinearGradient ? styles.sceneContainer : [styles.sceneContainer, {marginLeft: 0}]}>
            {this.props.useLinearGradient
              ? <LinearGradient
                  start={[0.0, 0.0]} end={[1.0, 0.0]}
                  colors={['transparent', 'rgba(0, 0, 0, 0.1)']}
                  style={styles.linearGradient}
                />
              : <View />}
            <View style={{flex: 1}}>
              <View>
                {this.props.headerComponent}
              </View>
              {this.props.children}
            </View>
          </View>
        </Animated.View>
      </View>
    );
  }

  _shouldRespondToPan(e: Object, gestureState: Object) {
    // is there more left to right movement than up and down?
    return Math.abs(gestureState.dx) > Math.abs(gestureState.dy);
  }

  _handlePanResponderGrant(e: Object, gestureState: Object) {
    // set the offset to be 0 or the menu width, and reset the values to 0 to avoid a jump
    // before the binding with gestureState.dx takes over and resets the x value
    this.state.pan.setOffset({x: this.state.pan.x._value, y: 0});
    this.state.pan.setValue({x: 0, y: 0});
  }

  _handlePanResponderMove(e: Object, gestureState: Object) {
    // update pan.x unless pan goes off left of screen. Then set pan to be the very left 
    if (this._absoluteXValueOfCurrentSceneDuringPan(gestureState.dx) >= 0)
      this.state.pan.setValue({x: gestureState.dx, y: 0});
    else
      this.state.pan.setValue({x: this._isMenuOpen ? -this.props.menuWidth : 0, y: 0});
  }

  _handlePanResponderEnd(e: Object, gestureState: Object) {
    // Set x value to be absolute position because the animation is from an offset of 0,
    // and currently the offset may be the menuWidth
    if (this._isMenuOpen)
{'fraction_non_alphanumeric': 0.11563008384432487, 'fraction_numerical': 0.006507320735827806, 'mean_word_length': 2.812977099236641, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3190373', 'n_tokens_mistral': 2488, 'n_tokens_neox': 2377, 'n_words': 541}