ali322/CNodeRN

View on GitHub
app/component/tabbar.js

Summary

Maintainability
C
1 day
Test Coverage
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
  Animated,
  TouchableWithoutFeedback
} from 'react-native'
import React from 'react'
import preferredThemer from '../theme/'
import { connected } from 'redux-container'

const defaultStyles = StyleSheet.create({
  tabBarContainer: {
    flexDirection: 'row',
    height: 48,
    backgroundColor: '#F7F7F7',
    borderTopColor: '#DDD',
    borderTopWidth: 1
  },
  tabBarTab: {
    marginVertical: 4,
    flex: 1,
    alignItems: 'stretch',
    justifyContent: 'flex-end'
  },
  tabBarItem: {
    marginVertical: 3,
    flex: 1,
    alignItems: 'stretch',
    justifyContent: 'flex-start'
  },
  tabBarIcon: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    alignItems: 'center',
    justifyContent: 'center'
  },
  tabBarLabel: {
    textAlign: 'center',
    fontSize: 10,
    marginBottom: 1.5,
    backgroundColor: 'transparent'
  }
})

const TabBarIcon = ({
  scene,
  navigation,
  navigationState,
  position,
  renderIcon,
  activeTintColor,
  inactiveTintColor,
  styles
}) => {
  const { route, index } = scene
  const { routes } = navigationState
  const inputRange = [-1, ...routes.map((x, i) => i)]
  const activeOpacity = position.interpolate({
    inputRange,
    outputRange: inputRange.map(i => (i === index ? 1 : 0))
  })
  const inactiveOpacity = position.interpolate({
    inputRange,
    outputRange: inputRange.map(i => (i === index ? 0 : 1))
  })
  return (
    <View style={{ flexGrow: 1 }}>
      <Animated.View style={[styles.tabBarIcon, { opacity: activeOpacity }]}>
        {renderIcon({
          route,
          index,
          focused: true,
          tintColor: activeTintColor
        })}
      </Animated.View>
      <Animated.View style={[styles.tabBarIcon, { opacity: inactiveOpacity }]}>
        {renderIcon({
          route,
          index,
          focused: false,
          tintColor: inactiveTintColor
        })}
      </Animated.View>
    </View>
  )
}

@connected(state => ({ ...state.userPrefsReducer, ...state.authReducer }))
@preferredThemer(defaultStyles)
class TabBar extends React.PureComponent {
  static defaultProps = {
    activeTintColor: '#3478f6', // Default active tint color in iOS 10
    activeBackgroundColor: 'transparent',
    inactiveTintColor: '#929292', // Default inactive tint color in iOS 10
    inactiveBackgroundColor: 'transparent',
    showIcon: true,
    showLabel: true
  }
  render() {
    const {
      navigation,
      renderIcon,
      showIcon,
      showLabel,
      getLabel,
      labelStyle,
      activeBackgroundColor,
      inactiveBackgroundColor,
      jumpToIndex,
      position,
      navigationState,
      activeTintColor,
      inactiveTintColor,
      style,
      loginRequired,
      auth
    } = this.props
    const { styles } = this.props
    const { routes } = navigation.state

    function _renderIcon(scene) {
      if (!showIcon) return null
      return (
        <TabBarIcon
          position={position}
          navigation={navigation}
          navigationState={navigationState}
          styles={styles}
          activeTintColor={activeTintColor}
          inactiveTintColor={inactiveTintColor}
          renderIcon={renderIcon}
          scene={scene}
        />
      )
    }

    function _renderLabel(scene) {
      if (!showLabel) return null
      const { index } = scene
      const { routes } = navigationState
      const inputRange = [-1, ...routes.map((x, i) => i)]
      const outputRange = inputRange.map(
        inputIndex =>
          inputIndex === index ? activeTintColor : inactiveTintColor
      )
      const color = position.interpolate({
        inputRange,
        outputRange
      })
      const label = getLabel(scene)
      if (typeof label === 'string') {
        return (
          <Animated.Text style={[styles.tabBarLabel, { color }, labelStyle]}>
            {label}
          </Animated.Text>
        )
      }
      if (typeof label === 'function') {
        return label(scene)
      }
      return label
    }
    function _handleTabClick(route, index) {
      if (
        Array.isArray(loginRequired) &&
        loginRequired.indexOf(route.routeName) > -1 &&
        !auth.isLogined
      ) {
        navigation.navigate('login')
        return
      }
      jumpToIndex(index)
    }
    const inputRange = [-1, ...routes.map((x, i) => i)]
    return (
      <View style={[styles.tabBarContainer, style]}>
        {routes.map((route, index) => {
          const outputRange = inputRange.map(
            inputIndex =>
              inputIndex === index
                ? activeBackgroundColor
                : inactiveBackgroundColor
          )
          const backgroundColor = position.interpolate({
            inputRange,
            outputRange
          })
          const justifyContent = this.props.showIcon ? 'flex-end' : 'center'
          return (
            <TouchableWithoutFeedback
              onPress={() => _handleTabClick(route, index)}
              key={route.routeName}
            >
              <Animated.View
                style={[styles.tabBarTab, { backgroundColor, justifyContent }]}
              >
                {_renderIcon({ route, index })}
                {_renderLabel({ route, index })}
              </Animated.View>
            </TouchableWithoutFeedback>
          )
        })}
      </View>
    )
  }
}

export default TabBar