<commit_before>// @flow

import type { BaseAction } from 'lib/types/redux-types';
import type { BaseNavInfo } from 'lib/types/nav-types';
import type {
  RawThreadInfo,
  LeaveThreadPayload,
} from 'lib/types/thread-types';
import type {
  NavigationState,
  NavigationScreenProp,
  NavigationAction,
  NavigationRouter,
  NavigationRoute,
  NavigationTransitionProps,
} from 'react-navigation';
import type { AppState } from '../redux-setup';
import type { SetSessionPayload } from 'lib/types/session-types';
import type { NotificationPressPayload } from 'lib/shared/notif-utils';
import type { AndroidNotificationActions } from '../push/android';
import type { UserInfo } from 'lib/types/user-types';

import {
  createBottomTabNavigator,
  createMaterialTopTabNavigator,
  createStackNavigator,
  NavigationActions,
} from 'react-navigation';
import invariant from 'invariant';
import _findIndex from 'lodash/fp/findIndex';
import _includes from 'lodash/fp/includes';
import { Alert, BackHandler, Platform, Keyboard } from 'react-native';
import React from 'react';
import PropTypes from 'prop-types';
import { StackViewTransitionConfigs } from 'react-navigation-stack';

import { infoFromURL } from 'lib/utils/url-utils';
import { fifteenDaysEarlier, fifteenDaysLater } from 'lib/utils/date-utils';
import { setNewSessionActionType } from 'lib/utils/action-utils';
import {
  logOutActionTypes,
  deleteAccountActionTypes,
  logInActionTypes,
  registerActionTypes,
  resetPasswordActionTypes,
} from 'lib/actions/user-actions';
import { pingActionTypes } from 'lib/actions/ping-actions';
import {
  leaveThreadActionTypes,
  deleteThreadActionTypes,
  newThreadActionTypes,
} from 'lib/actions/thread-actions';
import { notificationPressActionType } from 'lib/shared/notif-utils';
import { threadInfoFromRawThreadInfo } from 'lib/shared/thread-utils';
import { connect } from 'lib/utils/redux-utils';

import Calendar from '../calendar/calendar.react';
import Chat from '../chat/chat.react';
import More from '../more/more.react';
import LoggedOutModal from '../account/logged-out-modal.react';
import VerificationModal from '../account/verification-modal.react';
import {
  createIsForegroundSelector,
  appCanRespondToBackButtonSelector,
} from '../selectors/nav-selectors';
import {
  assertNavigationRouteNotLeafNode,
  getThreadIDFromParams,
} from '../utils/navigation-utils';
import {
  AppRouteName,
  ComposeThreadRouteName,
  DeleteThreadRouteName,
  ThreadSettingsRouteName,
  MessageListRouteName,
  VerificationModalRouteName,
  LoggedOutModalRouteName,
  MoreRouteName,
  MoreScreenRouteName,
  ChatRouteName,
  ChatThreadListRouteName,
  CalendarRouteName,
  ThreadPickerModalRouteName,
  AddUsersModalRouteName,
  CustomServerModalRouteName,
  ColorPickerModalRouteName,
  ComposeSubthreadModalRouteName,
} from './route-names';
import {
  handleURLActionType,
  navigateToAppActionType,
} from './action-types';
import ThreadPickerModal from '../calendar/thread-picker-modal.react';
import AddUsersModal from '../chat/settings/add-users-modal.react';
import CustomServerModal from '../more/custom-server-modal.react';
import ColorPickerModal from '../chat/settings/color-picker-modal.react';
import ComposeSubthreadModal from '../chat/settings/compose-subthread-modal.react';

export type NavInfo = {|
  ...$Exact<BaseNavInfo>,
  navigationState: NavigationState,
|};

const uniqueBaseId = `id-${Date.now()}`;
let uuidCount = 0;
function _getUuid() {
  return `${uniqueBaseId}-${uuidCount++}`;
}

export type Action =
  | BaseAction
  | NavigationAction
  | {| type: "HANDLE_URL", payload: string |}
  | {| type: "NAVIGATE_TO_APP", payload: null |}
  | {|
      type: "NOTIFICATION_PRESS",
      payload: NotificationPressPayload,
    |}
  | AndroidNotificationActions
  | {| type: "RECORD_NOTIF_PERMISSION_ALERT", time: number |}
  | {| type: "BACKGROUND" |}
  | {| type: "FOREGROUND" |};

let tabBarOptions;
if (Platform.OS === "android") {
  tabBarOptions = {
    style: {
      backgroundColor: '#445588',
    },
    indicatorStyle: {
      backgroundColor: '#AAFFCC',
    },
  };
} else {
  tabBarOptions = {};
}
const createTabNavigator = Platform.OS === "android"
  ? createMaterialTopTabNavigator
  : createBottomTabNavigator;
const AppNavigator = createTabNavigator(
  {
    [CalendarRouteName]: { screen: Calendar },
    [ChatRouteName]: { screen: Chat },
    [MoreRouteName]: { screen: More },
  },
  {
    initialRouteName: CalendarRouteName,
    lazy: false,
    tabBarOptions,
  },
);
type WrappedAppNavigatorProps = {|
  navigation: NavigationScreenProp<*>,
  isForeground: bool,
  appCanRespondToBackButton: bool,
|};
class WrappedAppNavigator
  extends React.PureComponent<WrappedAppNavigatorProps> {

  static propTypes = {
    navigation: PropTypes.shape({
      goBack: PropTypes.func.isRequired,
    }).isRequired,
    isForeground: PropTypes.bool.isRequired,
    appCanRespondToBackButton: PropTypes.bool.isRequired,
  };

  componentDidMount() {
    if (this.props.isForeground) {
      this.onForeground();
    }
  }

  componentWillUnmount() {
    if (this.props.isForeground) {
      this.onBackground();
    }
  }

  componentWillReceiveProps(nextProps: WrappedAppNavigatorProps) {
    if (!this.props.isForeground && nextProps.isForeground) {
      this.onForeground();
    } else if (this.props.isForeground && !nextProps.isForeground) {
      this.onBackground();
    }
  }

  onForeground() {
    BackHandler.addEventListener('hardwareBackPress', this.hardwareBack);
  }

  onBackground() {
    BackHandler.removeEventListener('hardwareBackPress', this.hardwareBack);
  }

  hardwareBack = () => {
    if (!this.props.appCanRespondToBackButton) {
      return false;
    }
    this.props.navigation.goBack(null);
    return true;
  }

  render() {
    return <AppNavigator navigation={this.props.navigation} />;
  }

}

const isForegroundSelector = createIsForegroundSelector(AppRouteName);
const ReduxWrappedAppNavigator = connect((state: AppState) => ({
  appCanRespondToBackButton: appCanRespondToBackButtonSelector(state),
  isForeground: isForegroundSelector(state),
}))(WrappedAppNavigator);
(ReduxWrappedAppNavigator: Object).router = AppNavigator.router;

const RootNavigator = createStackNavigator(
  {
    [LoggedOutModalRouteName]: { screen: LoggedOutModal },
    [VerificationModalRouteName]: { screen: VerificationModal },
    [AppRouteName]: { screen: ReduxWrappedAppNavigator },
    [ThreadPickerModalRouteName]: { screen: ThreadPickerModal },
    [AddUsersModalRouteName]: { screen: AddUsersModal },
    [CustomServerModalRouteName]: { screen: CustomServerModal },
    [ColorPickerModalRouteName]: { screen: ColorPickerModal },
    [ComposeSubthreadModalRouteName]: { screen: ComposeSubthreadModal },
  },
  {
    headerMode: 'none',
    mode: 'modal',
    transparentCard: true,
    disableKeyboardHandling: true,
    onTransitionStart: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps: ?NavigationTransitionProps,
    ) => {
      const { scene } = transitionProps;
      const { route } = scene;
      const { scene: prevScene } = prevTransitionProps;
      const { route: prevRoute } = prevScene;
      if (
        route.routeName !== AppRouteName ||
        prevRoute.routeName !== ThreadPickerModalRouteName
      ) {
        Keyboard.dismiss();
      }<commit_msg>[native] Type fix for onTransitionStart<commit_after>// @flow

import type { BaseAction } from 'lib/types/redux-types';
import type { BaseNavInfo } from 'lib/types/nav-types';
import type {
  RawThreadInfo,
  LeaveThreadPayload,
} from 'lib/types/thread-types';
import type {
  NavigationState,
  NavigationScreenProp,
  NavigationAction,
  NavigationRouter,
  NavigationRoute,
  NavigationTransitionProps,
} from 'react-navigation';
import type { AppState } from '../redux-setup';
import type { SetSessionPayload } from 'lib/types/session-types';
import type { NotificationPressPayload } from 'lib/shared/notif-utils';
import type { AndroidNotificationActions } from '../push/android';
import type { UserInfo } from 'lib/types/user-types';

import {
  createBottomTabNavigator,
  createMaterialTopTabNavigator,
  createStackNavigator,
  NavigationActions,
} from 'react-navigation';
import invariant from 'invariant';
import _findIndex from 'lodash/fp/findIndex';
import _includes from 'lodash/fp/includes';
import { Alert, BackHandler, Platform, Keyboard } from 'react-native';
import React from 'react';
import PropTypes from 'prop-types';
import { StackViewTransitionConfigs } from 'react-navigation-stack';

import { infoFromURL } from 'lib/utils/url-utils';
import { fifteenDaysEarlier, fifteenDaysLater } from 'lib/utils/date-utils';
import { setNewSessionActionType } from 'lib/utils/action-utils';
import {
  logOutActionTypes,
  deleteAccountActionTypes,
  logInActionTypes,
  registerActionTypes,
  resetPasswordActionTypes,
} from 'lib/actions/user-actions';
import { pingActionTypes } from 'lib/actions/ping-actions';
import {
  leaveThreadActionTypes,
  deleteThreadActionTypes,
  newThreadActionTypes,
} from 'lib/actions/thread-actions';
import { notificationPressActionType } from 'lib/shared/notif-utils';
import { threadInfoFromRawThreadInfo } from 'lib/shared/thread-utils';
import { connect } from 'lib/utils/redux-utils';

import Calendar from '../calendar/calendar.react';
import Chat from '../chat/chat.react';
import More from '../more/more.react';
import LoggedOutModal from '../account/logged-out-modal.react';
import VerificationModal from '../account/verification-modal.react';
import {
  createIsForegroundSelector,
  appCanRespondToBackButtonSelector,
} from '../selectors/nav-selectors';
import {
  assertNavigationRouteNotLeafNode,
  getThreadIDFromParams,
} from '../utils/navigation-utils';
import {
  AppRouteName,
  ComposeThreadRouteName,
  DeleteThreadRouteName,
  ThreadSettingsRouteName,
  MessageListRouteName,
  VerificationModalRouteName,
  LoggedOutModalRouteName,
  MoreRouteName,
  MoreScreenRouteName,
  ChatRouteName,
  ChatThreadListRouteName,
  CalendarRouteName,
  ThreadPickerModalRouteName,
  AddUsersModalRouteName,
  CustomServerModalRouteName,
  ColorPickerModalRouteName,
  ComposeSubthreadModalRouteName,
} from './route-names';
import {
  handleURLActionType,
  navigateToAppActionType,
} from './action-types';
import ThreadPickerModal from '../calendar/thread-picker-modal.react';
import AddUsersModal from '../chat/settings/add-users-modal.react';
import CustomServerModal from '../more/custom-server-modal.react';
import ColorPickerModal from '../chat/settings/color-picker-modal.react';
import ComposeSubthreadModal from '../chat/settings/compose-subthread-modal.react';

export type NavInfo = {|
  ...$Exact<BaseNavInfo>,
  navigationState: NavigationState,
|};

const uniqueBaseId = `id-${Date.now()}`;
let uuidCount = 0;
function _getUuid() {
  return `${uniqueBaseId}-${uuidCount++}`;
}

export type Action =
  | BaseAction
  | NavigationAction
  | {| type: "HANDLE_URL", payload: string |}
  | {| type: "NAVIGATE_TO_APP", payload: null |}
  | {|
      type: "NOTIFICATION_PRESS",
      payload: NotificationPressPayload,
    |}
  | AndroidNotificationActions
  | {| type: "RECORD_NOTIF_PERMISSION_ALERT", time: number |}
  | {| type: "BACKGROUND" |}
  | {| type: "FOREGROUND" |};

let tabBarOptions;
if (Platform.OS === "android") {
  tabBarOptions = {
    style: {
      backgroundColor: '#445588',
    },
    indicatorStyle: {
      backgroundColor: '#AAFFCC',
    },
  };
} else {
  tabBarOptions = {};
}
const createTabNavigator = Platform.OS === "android"
  ? createMaterialTopTabNavigator
  : createBottomTabNavigator;
const AppNavigator = createTabNavigator(
  {
    [CalendarRouteName]: { screen: Calendar },
    [ChatRouteName]: { screen: Chat },
    [MoreRouteName]: { screen: More },
  },
  {
    initialRouteName: CalendarRouteName,
    lazy: false,
    tabBarOptions,
  },
);
type WrappedAppNavigatorProps = {|
  navigation: NavigationScreenProp<*>,
  isForeground: bool,
  appCanRespondToBackButton: bool,
|};
class WrappedAppNavigator
  extends React.PureComponent<WrappedAppNavigatorProps> {

  static propTypes = {
    navigation: PropTypes.shape({
      goBack: PropTypes.func.isRequired,
    }).isRequired,
    isForeground: PropTypes.bool.isRequired,
    appCanRespondToBackButton: PropTypes.bool.isRequired,
  };

  componentDidMount() {
    if (this.props.isForeground) {
      this.onForeground();
    }
  }

  componentWillUnmount() {
    if (this.props.isForeground) {
      this.onBackground();
    }
  }

  componentWillReceiveProps(nextProps: WrappedAppNavigatorProps) {
    if (!this.props.isForeground && nextProps.isForeground) {
      this.onForeground();
    } else if (this.props.isForeground && !nextProps.isForeground) {
      this.onBackground();
    }
  }

  onForeground() {
    BackHandler.addEventListener('hardwareBackPress', this.hardwareBack);
  }

  onBackground() {
    BackHandler.removeEventListener('hardwareBackPress', this.hardwareBack);
  }

  hardwareBack = () => {
    if (!this.props.appCanRespondToBackButton) {
      return false;
    }
    this.props.navigation.goBack(null);
    return true;
  }

  render() {
    return <AppNavigator navigation={this.props.navigation} />;
  }

}

const isForegroundSelector = createIsForegroundSelector(AppRouteName);
const ReduxWrappedAppNavigator = connect((state: AppState) => ({
  appCanRespondToBackButton: appCanRespondToBackButtonSelector(state),
  isForeground: isForegroundSelector(state),
}))(WrappedAppNavigator);
(ReduxWrappedAppNavigator: Object).router = AppNavigator.router;

const RootNavigator = createStackNavigator(
  {
    [LoggedOutModalRouteName]: { screen: LoggedOutModal },
    [VerificationModalRouteName]: { screen: VerificationModal },
    [AppRouteName]: { screen: ReduxWrappedAppNavigator },
    [ThreadPickerModalRouteName]: { screen: ThreadPickerModal },
    [AddUsersModalRouteName]: { screen: AddUsersModal },
    [CustomServerModalRouteName]: { screen: CustomServerModal },
    [ColorPickerModalRouteName]: { screen: ColorPickerModal },
    [ComposeSubthreadModalRouteName]: { screen: ComposeSubthreadModal },
  },
  {
    headerMode: 'none',
    mode: 'modal',
    transparentCard: true,
    disableKeyboardHandling: true,
    onTransitionStart: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps: ?NavigationTransitionProps,
    ) => {
      if (!prevTransitionProps) {
        return;
      }
      const { scene } = transitionProps;
      const { route } = scene;
      const { scene: prevScene } = prevTransitionProps;
      const { route: prevRoute } = prevScene;
      if (
        route.routeName !== AppRouteName ||
        prevRoute.routeName !== ThreadPickerModalRouteName
      ) {
        Keyboard.dismiss();
      }
{'fraction_non_alphanumeric': 0.11899622234214786, 'fraction_numerical': 0.0009444144630329196, 'mean_word_length': 4.556596701649175, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, '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': '4876122', 'n_tokens_mistral': 4473, 'n_tokens_neox': 4404, 'n_words': 853}