<|start_filename|>app/services/error/error-code.js<|end_filename|>
// @flow

// We need to decide on format for error codes
// there is a convention in HTTP error codes is that all errors
// starting from 4xx are client side errors and 5xx are server side errors
// we also need to have codes in some logical sequence
// Here is the proposal for that sequence of Error codes
// 1xxxx = data validation error
// where first two `xx` denotes the area of code in which error occurred
// and third x denotes which functionality of that particular area
// and last x denotes which parameter failed
// 2xxxx = libindy exceptions
// 3xxxx = something else
// ----------
// There can another proposal where we just write a detailed error message
// and assign any type of sequential number to error codes
// error code are still needed because we need to take different actions
// for different error codes and we need to match codes, we can do string
// comparisons as well, but tracking code will be bit easier
//
// ---------------
// There can be another way of writing error codes
// where we will write error codes with abbreviated feature
// for example if validation error occurs in user onboarding with agency
// we can write error code as UO-100 where UO- stands for user onboarding
// 1 stands for validation error, 0 stands which part of onboarding
// and last 0 stands for which parameter of part of onboarding
//
// There are advantages and disadvantages to all the approaches
//

export const CLAIM_STORAGE_ERROR = (e?: Error) => ({
  code: 'C-20001',
  message: `Failed to store claim ${e ? e.message : ''}`,
})

export const CONNECTION_HISTORY_STORAGE_ERROR = (e?: Error) => ({
  code: 'C-20002',
  message: `Failed to store connection history ${e ? e.message : ''}`,
})


<|start_filename|>app/components/keyboard/styles.js<|end_filename|>
// @flow

import { StyleSheet, Dimensions, Platform } from 'react-native'
import {
  isBiggerThanShortDevice,
  deviceHeight,
  MEDIUM_DEVICE,
} from '../../common/styles/constant'
import { PUSH_NOTIFICATION_PERMISSION } from '../../push-notification/type-push-notification'

const ROW_MARGIN = isBiggerThanShortDevice ? 36 : 15
const FIRST_ROW_MARGIN = isBiggerThanShortDevice ? 24 : 8

const ROW_HEIGHT =
  Platform.OS === 'ios' ? 36 : deviceHeight < MEDIUM_DEVICE ? 27 : 36

const FONT_SIZE = isBiggerThanShortDevice ? 28 : 26
export const INPUT_RANGE = [0, 0.5, 1]
export const OUTPUT_RANGE =
  Platform.OS === 'ios'
    ? isBiggerThanShortDevice ? [28, 29, 30] : [26, 30, 34]
    : deviceHeight < MEDIUM_DEVICE ? [28, 30, 32] : [26, 30, 34]

export const styles = StyleSheet.create({
  container: {
    marginHorizontal: 32, // TODO: update style guide to reflect new constant
    marginBottom: 5,
  },
  firstRow: {
    height: ROW_HEIGHT,
    marginTop: FIRST_ROW_MARGIN,
  },
  row: {
    height: ROW_HEIGHT,
    marginTop: ROW_MARGIN,
  },
  number: {
    fontSize: FONT_SIZE,
    fontWeight: '500', // TODO: update style guide to reflect new constant
  },
})


<|start_filename|>app/invitation/__tests__/invitation.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import ConnectedInvitation, { Invitation } from '../invitation'

import { color } from '../../common/styles'
import { ResponseType } from '../../components/request/type-request'
import { homeRoute } from '../../common'
import { getNavigation, smsToken } from '../../../__mocks__/static-data'
import { Container } from '../../components'

describe('<Invitation />', () => {
  let store
  let dispatch
  let subscribe
  let navigation
  let sendInvitationResponse
  let smsPendingInvitationSeen
  let invitationRejected
  let instance
  let component
  let invitation
  let isSmsInvitationNotSeen
  let props

  const firstInvitation = {
    requestId: 'requestId1',
    senderAgentKeyDelegationProof: {
      agentDID: 'EHNMj5FNjA3xBo8HUKQTZv',
      agentDelegatedKey: '<KEY>',
      signature:
        'OXtzqX9LJJsBY/Mrhjff6b9L79Pdg8U4B7dI/3RR65BJr5jktAGMwpMLe1aQRQT0FlplZfNy8QtUd4KNPd+ZAg==',
    },
    senderDID: 'senderDID1',
    senderEndpoint: 'endpoint',
    senderLogoUrl: 'lu',
    senderName: 'sender1',
    senderVerificationKey: 'sVk',
    targetName: 'target name',
    senderDetail: {
      name: 'default',
      agentKeyDlgProof: {
        agentDID: '<KEY>HUKQTZv',
        agentDelegatedKey: '<KEY>',
        signature:
          '<KEY>QT0FlplZfNy8QtUd4KNPd+ZAg==',
      },
      DID: '3Bb6zCYMoGnMTho97HGDrn',
      logoUrl: 'http://www.sovrin.org',
      verKey: '2BzhMgbLXbECPPYiLtSEd36Boxt1oquuGJeS1ofhPoEr',
    },
    senderAgencyDetail: {
      DID: 'BDSmVkzxRYGE4HKyMKxd1H',
      verKey: '<KEY>',
      endpoint: '172.16.31.10:80/agency/msg',
    },
  }

  const getState = () => ({
    invitation: {
      senderDID1: {
        error: null,
        isFetching: false,
        payload: firstInvitation,
        status: ResponseType.none,
      },
    },
    config: {
      showErrorAlerts: true,
    },
    connections: {
      connectionThemes: {
        default: {
          primary: `rgba(${color.actions.button.primary.rgba})`,
          secondary: `rgba(${color.actions.button.secondary.rgba})`,
        },
      },
    },
    user: {
      avatarName: undefined,
    },
    lock: {
      isTouchIdEnabled: false,
    },
  })

  beforeEach(() => {
    dispatch = jest.fn()
    subscribe = jest.fn()
    store = {
      getState,
      dispatch() {
        return dispatch
      },
      subscribe() {
        return subscribe
      },
    }
    navigation = {
      ...getNavigation({
        senderDID: firstInvitation.senderDID,
        smsToken,
      }),
    }
    const state = getState()
    invitation = state.invitation.senderDID1
    const showErrorAlerts = state.config.showErrorAlerts
    sendInvitationResponse = jest.fn()
    smsPendingInvitationSeen = jest.fn()
    invitationRejected = jest.fn()
    isSmsInvitationNotSeen = false
    props = {
      invitation,
      showErrorAlerts,
      navigation,
      sendInvitationResponse,
      smsPendingInvitationSeen,
      invitationRejected,
      smsToken,
      isSmsInvitationNotSeen,
    }
    component = renderer.create(
      <Provider store={store}>
        <Invitation {...props} />
      </Provider>
    )

    instance = component.root.findByType(Invitation).instance
  })
  afterEach(() => {
    sendInvitationResponse.mockReset()
    sendInvitationResponse.mockRestore()
    invitationRejected.mockReset()
    invitationRejected.mockRestore()
    smsPendingInvitationSeen.mockReset()
    smsPendingInvitationSeen.mockRestore()
    dispatch.mockReset()
    dispatch.mockRestore()
    subscribe.mockReset()
    subscribe.mockRestore()
  })
  it('should match snapshot', () => {
    const tree = renderer
      .create(
        <Provider store={store}>
          <ConnectedInvitation navigation={navigation} />
        </Provider>
      )
      .toJSON()
    expect(tree).toMatchSnapshot()
  })

  it('should dispatch correct action for accepting invitation', () => {
    const response = ResponseType.accepted
    instance.onAction(response)

    expect(sendInvitationResponse).toHaveBeenCalledWith({
      response,
      senderDID: firstInvitation.senderDID,
    })
  })

  it('should reject invitation and redirect user to Home on Deny', () => {
    instance.onAction(ResponseType.rejected)
    expect(invitationRejected).toHaveBeenCalledWith(firstInvitation.senderDID)
    expect(navigation.navigate).toHaveBeenCalled()
    const redirectScreen = navigation.navigate.mock.calls[0][0]
    expect(redirectScreen).toBe(homeRoute)
  })

  it('should call smsPendingInvitationSeen action if isSmsInvitationNotSeen is true', () => {
    const invitationAfterAccept = {
      ...invitation,
      status: ResponseType.accepted,
    }
    component = renderer.create(
      <Provider store={store}>
        <Invitation
          {...props}
          invitation={invitationAfterAccept}
          isSmsInvitationNotSeen={true}
        />
      </Provider>
    )
    expect(smsPendingInvitationSeen).toHaveBeenCalledWith(smsToken)
  })

  it('should not call smsPendingInvitationSeen action if isSmsInvitationNotSeen is false', () => {
    const invitationAfterAccept = {
      ...invitation,
      status: ResponseType.accepted,
    }
    component = renderer.create(
      <Provider store={store}>
        <Invitation {...props} invitation={invitationAfterAccept} />
      </Provider>
    )
    expect(smsPendingInvitationSeen).not.toHaveBeenCalledWith(smsToken)
  })

  xit('should close modal and redirect to Home on Continue', () => {
    instance.onSuccessModalContinue()

    expect(instance.state.isSuccessModalVisible).toBe(false)
    jest.runAllTimers()
    expect(navigation.navigate).toHaveBeenCalled()
    const redirectScreen = navigation.navigate.mock.calls[0][0]
    expect(redirectScreen).toBe(homeRoute)
  })

  it('should return a empty container when invitation is null', () => {
    invitation = null
    navigation = {
      ...getNavigation({
        senderDID: null,
        smsToken: null,
      }),
    }
    const wrapper = renderer.create(
      <Provider store={store}>
        <Invitation
          {...props}
          invitation={invitation}
          navigation={navigation}
        />
      </Provider>
    )
    expect(wrapper.toJSON()).toMatchSnapshot()
    const instance = wrapper.root
    expect(instance.findByType(Container).children.length).toBe(1)
  })
  it('should show "Connecting..." while sending invitation response', () => {
    const whileSendingInvitation = {
      ...invitation,
      error: null,
      isFetching: true,
      status: ResponseType.accepted,
    }
    component.update(
      <Provider store={store}>
        <Invitation {...props} invitation={whileSendingInvitation} />
      </Provider>
    )
    expect(component.toJSON()).toMatchSnapshot()
  })
})


<|start_filename|>app/common/type-common.js<|end_filename|>
// @flow

import type { Element } from 'react'
import type { NavigationScreenProp } from 'react-navigation'

export type CustomError = {
  code: string,
  message: string,
}

export const INITIAL_TEST_ACTION: 'INITIAL_TEST_ACTION' = 'INITIAL_TEST_ACTION'

export type InitialTestAction = {
  type: typeof INITIAL_TEST_ACTION,
}

export const initialTestAction = () => ({
  type: INITIAL_TEST_ACTION,
})

export type NavigationParams = {
  [string]: any,
}

export type ReactNavigation = NavigationScreenProp

export type GenericObject = {
  [string]: any,
}

export type GenericStringObject = {
  [string]: string,
}

export type MessageAnnotation = {
  name: string,
  version: string,
}

export type TopicAnnotation = {
  tid: number,
  mid: number,
}

export type ReactChildren = Element<*>

export const RESET: 'RESET' = 'RESET'
export const REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS: 'REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS' =
  'REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS'

export type ResetAction = {
  type: typeof RESET,
}

export type ImageSource = {
  uri: string,
}

export type NotificationPayload = {
  forDID: string,
  uid: string,
  type: string,
  remotePairwiseDID: string,
  senderLogoUrl?: ?string,
}

export type ImmutableGenericStringObject = {
  +[string]: string,
}

export const STORE_STATUS = {
  IDLE: 'IDLE',
  IN_PROGRESS: 'IN_PROGRESS',
  ERROR: 'ERROR',
  SUCCESS: 'SUCCESS',
}

export type StoreError = { +error: ?CustomError }
export type StoreStatus = { +status: $Keys<typeof STORE_STATUS> }

export type StatusBarStyle = 'default' | 'light-content' | 'dark-content'


<|start_filename|>connectMeUITest/src/test/java/App3InstallTest.java<|end_filename|>

package test.java;

import io.appium.java_client.AppiumDriver;

import org.testng.annotations.*;
import appModules.AppUtlis;
import funcModules.ConnectionModules;
import utility.Setup;

public class App3InstallTest {

	private AppiumDriver driver;
	static boolean Success=false;
	AppUtlis AppUtlisObj=new AppUtlis();
	ConnectionModules ConnectionModulesObj=new ConnectionModules();


	@BeforeMethod

	public void beforeMethod() throws Exception {
        Thread.sleep(10000);
		driver = Setup.ConfigureDriver("Safari");
	}


    @Test (groups = {"Regression"})
	public void AppInstall() throws Exception  {
    	ConnectionModulesObj.InstallApp(driver,"Sandbox");
    		
    }

	@AfterMethod
	public void afterMethod() {

		driver.quit();
		System.out.println("Cleaning up Completed");

	}
}

<|start_filename|>connectMeUITest/src/utility/InMemWalletType.java<|end_filename|>
package utility;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.hyperledger.indy.sdk.ErrorCode;
import org.hyperledger.indy.sdk.wallet.CustomWallet;
import org.hyperledger.indy.sdk.wallet.WalletType;
import org.json.JSONObject;

public class InMemWalletType extends WalletType {

	private Map<Integer, InMemWallet> openWallets = new ConcurrentHashMap<Integer, InMemWallet>();
	private Map<String, InMemWallet> configuredWallets = new ConcurrentHashMap<String, InMemWallet>();
	
    private static AtomicInteger nextWalletHandle = new AtomicInteger();
    
    private int getNextWalletHandle() {
    	return Integer.valueOf(nextWalletHandle.incrementAndGet());
    }
    
    @Override
    protected CustomWallet getWalletByHandle(int handle) {
    	return openWallets.get(handle);
    }    
	
	@Override
	public ErrorCode create(String name, String config, String credentials) {
		
		if (configuredWallets.containsKey(name))
            return ErrorCode.WalletAlreadyExistsError;

        int freshnessDuration = 1000;
        
        if(config != null){
        	
	        JSONObject configObj =  new JSONObject(config);
	        
	        if(configObj != null && !configObj.isNull("freshness_time")) {
	            freshnessDuration = configObj.getInt("freshness_time");
	        }
        }

        configuredWallets.put(name, new InMemWallet(freshnessDuration));
        return ErrorCode.Success;
	}
	
	@Override
	public ErrorCode delete(String name, String config, String credentials) {
		
		if (!configuredWallets.containsKey(name))
            return ErrorCode.CommonInvalidState;

        InMemWallet wallet = configuredWallets.get(name);

        if (wallet.getIsOpen())
            return ErrorCode.CommonInvalidState;

        configuredWallets.remove(name);

        return ErrorCode.Success;
	}
	
	@Override
	public ErrorCode open(String name, String config, String runtimeConfig, String credentials,
			HandleByReference walletHandle) {
		
        if (!configuredWallets.containsKey(name))
            return ErrorCode.CommonInvalidState;

        InMemWallet wallet = configuredWallets.get(name);

        if (wallet.getIsOpen())
            return ErrorCode.WalletAlreadyOpenedError;

        wallet.setIsOpen(true);

        int newHandle = getNextWalletHandle();
        
        walletHandle.setValue(newHandle);
        openWallets.put(newHandle, wallet);

        return ErrorCode.Success;
	}
	
	@Override
	public ErrorCode close(int handle) {
		
		InMemWallet wallet;

        try
        {
            wallet = (InMemWallet)getWalletByHandle(handle);
        }
        catch(Exception e)
        {
            return ErrorCode.WalletInvalidHandle;
        }
        
        wallet.setIsOpen(false);
        openWallets.remove(handle);

        return ErrorCode.Success;
	}
}



<|start_filename|>app/connection-history/__tests__/connection-history.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { ConnectionHistory } from '../connection-history'
import { color } from '../../common/styles'
import {
  getStore,
  getNavigation,
  connection,
  connectionHistory,
  activeConnectionThemePrimary,
  activeConnectionThemeSecondary,
} from '../../../__mocks__/static-data'

describe('<ConnectionHistory />', () => {
  const store = getStore()

  function props() {
    return {
      navigation: getNavigation({
        image: 'https://test.com/image.png',
        senderName: 'Evernym',
      }),
      activeConnectionThemePrimary,
      activeConnectionThemeSecondary,
      connectionHistory,
      connection,
      claimMap: undefined,
      updateStatusBarTheme: () => {},
      deleteConnectionAction: jest.fn(),
      goToUIScreen: jest.fn(),
    }
  }

  it('should ConnectionHistory render properly', () => {
    const component = renderer.create(
      <Provider store={store}>
        <ConnectionHistory {...props()} />
      </Provider>
    )
    expect(component).toMatchSnapshot()
  })
})


<|start_filename|>app/proof/type-proof.js<|end_filename|>
// @flow

import type {
  CustomError,
  InitialTestAction,
  GenericStringObject,
  GenericObject,
  ResetAction,
} from '../common/type-common'
import type {
  ProofRequestData,
  SelfAttestedAttributes,
  IndySelfAttested,
  ProofRequestShowStartAction,
} from '../proof-request/type-proof-request'

export type ProofRevealedDetails = {
  primary_proof: {
    eq_proof: {
      revealed_attrs: GenericStringObject,
      a_prime: string,
      e: string,
      v: string,
      m: GenericObject,
      m1: string,
      m2: string,
    },
    ge_proofs: Array<string>,
  },
  non_revoc_proof: ?GenericObject,
}

export type IndyRequestedProof = {
  revealed_attrs: {
    [string]: Array<string>,
  },
  unrevealed_attrs: GenericObject,
  self_attested_attrs: GenericObject,
  predicates: GenericObject,
}

export type Proof = {
  proofs: {
    [string]: {
      proof: ProofRevealedDetails,
      schema_seq_no: number,
      issuer_did: string,
    },
  },
  aggregated_proof: {
    c_hash: string,
    c_list: Array<Array<number>>,
  },
  requested_proof: IndyRequestedProof,
}

export type RequestedClaimsJson = {
  self_attested_attributes: IndySelfAttested,
  requested_attrs: IndyRequestedAttributes,
  requested_predicates: GenericObject,
}

export type RequestedAttrsJson = {
  +[string]: [string, boolean],
}

export const UPDATE_ATTRIBUTE_CLAIM = 'UPDATE_ATTRIBUTE_CLAIM'
export type UpdateAttributeClaimAction = {
  type: typeof UPDATE_ATTRIBUTE_CLAIM,
  uid: string,
  requestedAttrsJson: RequestedAttrsJson,
}

export const GENERATE_PROOF = 'GENERATE_PROOF'
export type GenerateProofAction = {
  type: typeof GENERATE_PROOF,
  uid: string,
}

export const PROOF_SUCCESS = 'PROOF_SUCCESS'
export type ProofSuccessAction = {
  type: typeof PROOF_SUCCESS,
  proof: Proof,
  uid: string,
}

export const PROOF_FAIL = 'PROOF_FAIL'
export type ProofFailAction = {
  type: typeof PROOF_FAIL,
  uid: string,
  error: CustomError,
}

export const PROOF_REQUEST_SEND_PROOF_HANDLE = 'PROOF_REQUEST_SEND_PROOF_HANDLE'
export type proofRequestDataToStoreAction = {
  type: typeof PROOF_REQUEST_SEND_PROOF_HANDLE,
  uid: string,
  proofHandle: number,
  selfAttestedAttributes: SelfAttestedAttributes,
}

export const RESET_TEMP_PROOF_DATA = 'RESET_TEMP_PROOF_DATA'
export type resetTempProofDataAction = {
  type: typeof RESET_TEMP_PROOF_DATA,
  uid: string,
}

export const ERROR_SEND_PROOF = 'ERROR_SEND_PROOF'
export type errorSendProofFailAction = {
  type: typeof ERROR_SEND_PROOF,
  uid: string,
  error: CustomError,
}

export const CLEAR_ERROR_SEND_PROOF = 'CLEAR_ERROR_SEND_PROOF'
export type clearSendProofFailAction = {
  type: typeof CLEAR_ERROR_SEND_PROOF,
  uid: string,
}

export const ERROR_CODE_MISSING_ATTRIBUTE = 'P000'

export const ERROR_MISSING_ATTRIBUTE_IN_CLAIMS = (
  message: string
): CustomError => ({
  code: ERROR_CODE_MISSING_ATTRIBUTE,
  message,
})

export type IndySelfAttestedAttributes = {
  [attributeKey: string]: string,
}

export const USER_SELF_ATTESTED_ATTRIBUTES = 'USER_SELF_ATTESTED_ATTRIBUTES'
export type UserSelfAttestedAttributesAction = {
  type: typeof USER_SELF_ATTESTED_ATTRIBUTES,
  selfAttestedAttributes: SelfAttestedAttributes,
  uid: string,
}

export type MatchingCredential = {
  cred_info: {
    referent: string,
    attrs: { [claimAttributeName: string]: string },
    schema_id: string,
    cred_def_id: string,
  },
}

export type IndyPreparedProof = {
  attrs: {
    [attributeName: string]: ?Array<MatchingCredential | null>,
  },
  predicates: {},
  self_attested_attrs?: {},
}

export type IndyRequestedAttributes = {
  [attributeName: string]: [string, boolean, MatchingCredential],
}

export type VcxSelectedCredentials = {
  attrs?: {
    [attributeKey: string]: MatchingCredential,
  },
}

export type ProofAction =
  | GenerateProofAction
  | ProofSuccessAction
  | ProofFailAction
  | UserSelfAttestedAttributesAction
  | ProofRequestShowStartAction
  | InitialTestAction
  | ResetAction
  | proofRequestDataToStoreAction
  | resetTempProofDataAction
  | errorSendProofFailAction
  | clearSendProofFailAction

export type ProofStore = {
  +[string]: {
    proof: Proof,
    error?: CustomError,
    selfAttestedAttributes?: SelfAttestedAttributes,
    proofData?: {
      proofHandle: number,
      selfAttestedAttributes: SelfAttestedAttributes,
      error?: CustomError,
    },
  },
}


<|start_filename|>app/common/route-constants.js<|end_filename|>
// @flow
export const splashScreenRoute = 'SplashScreenHide'
export const homeRoute = 'Home'
export const authenticationRoute = 'Authentication'
export const connectionRoute = 'Connection'
export const settingsRoute = 'Settings'
export const settingsScreen = 'SettingsStack'
export const expiredTokenRoute = 'ExpiredToken'
export const qrCodeScannerRoute = 'QRCodeScanner'
export const lockPinSetupRoute = 'PinSetup'
export const lockTouchIdSetupRoute = 'TouchIdSetup'
export const lockPinSetupHomeRoute = 'PinSetupHome'
export const lockSelectionRoute = 'LockSelection'
export const lockEnterPinRoute = 'LockEnterPin'
export const lockSetupSuccessRoute = 'LockSetupSuccess'
export const lockEnterFingerprintRoute = 'LockEnterFingerprint'
export const claimOfferRoute = 'ClaimOffer'
export const homeTabRoute = 'TabHome'
export const settingsTabRoute = 'TabSettings'
export const qrCodeScannerTabRoute = 'TabQRCodeScanner'
export const proofRequestRoute = 'ProofRequest'
export const invitationRoute = 'InvitationRoute'
export const connectionHistoryRoute = 'ConnectionHistoryRoute'
export const connectionHistoryDetailsRoute = 'ConnectionHistoryDetailsRoute'
export const switchEnvironmentRoute = 'SwitchEnvironment'
export const lockAuthorizationRoute = 'LockAuthorizationRoute'
export const lockAuthorizationHomeRoute = 'LockAuthorizationHomeRoute'
export const waitForInvitationRoute = 'WaitForInvitationRoute'
export const connectionHistoryPendingRoute = 'ConnectionHistoryPendingRoute'
export const walletRoute = 'TokenWallet'
export const walletTabSendDetailsRoute = 'WalletTabSendDetails'
export const receiveTabRoute = 'WalletReceiveTab'
export const sendTabRoute = 'WalletSendTab'
export const historyTabRoute = 'WalletHistoryTab'
export const aboutAppRoute = 'AboutApp'
export const privacyTNCRoute = 'PrivacyTNC'
export const eulaRoute = 'EulaScreen'
export const genRecoveryPhraseRoute = 'GenerateRecoveryPhrase'
export const verifyRecoveryPhraseRoute = 'VerifyRecoveryPhrase'
export const exportBackupFileRoute = 'ExportBackupFile'
export const backupCompleteRoute = 'BackupComplete'
export const restoreRoute = 'RestoreStartScreen'
export const restoreWaitRoute = 'RestoreWaitScreen'
export const restorePassphraseRoute = 'RestorePassphrase'
export const backupErrorRoute = 'BackupErrorScreen'


<|start_filename|>app/components/avatar/badge-avatar.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { Avatar } from './avatar'
import Badge from '../badge'
import type { BadgeAvatarProps } from './type-avatar'

export class BadgeAvatar extends PureComponent<BadgeAvatarProps, void> {
  render() {
    const { count, onPress } = this.props

    return (
      <Avatar
        {...this.props}
        extraNode={
          <Badge
            count={count}
            secondary
            shadow
            badgeStyle={style.topLeft}
            onPress={onPress}
          />
        }
      />
    )
  }
}

const style = StyleSheet.create({
  topLeft: {
    top: 0,
    left: 0,
    position: 'absolute',
  },
})


<|start_filename|>app/services/error/error-handler.js<|end_filename|>
// @flow
import { AlertIOS } from 'react-native'
// import ErrorTracker from './error-tracker'

export const captureError = (error: Error, showAlert: boolean = false) => {
  // ErrorTracker.captureException(error)
  if (showAlert) {
    AlertIOS.alert(JSON.stringify(error))
  }
}


<|start_filename|>__mocks__/data/user-store-mock-data.js<|end_filename|>
// @flow

export const userOneTimeInfo = {
  oneTimeAgencyDid: 'oneTimeAgencyDid',
  oneTimeAgencyVerificationKey: 'oneTimeAgencyVerKey',
  myOneTimeDid: 'myOneTimeDid',
  myOneTimeVerificationKey: 'myOneTimeVerificationKey',
  myOneTimeAgentDid: 'myOneTimeAgentDid',
  myOneTimeAgentVerificationKey: 'myOneTimeAgentVerificationKey',
}


<|start_filename|>e2e/settings.spec.js<|end_filename|>
describe('Settings', () => {
  it('Choose profile photo', async () => {
    // enter Pin Code screen
    // user should redirect to dashboard screen
    // test footer tabs is preset
    // tap on settings
    // user should redirect to settings screen
    // User avatar, user name, pass-code and enable touch-id should be present on settings list
    // tap on user avatar
    // test camera should open
    // tap on home icon in footer
    // user should back to dashboard screen
  })

  it('Setup Pass-code', async () => {
    // tap on settings
    // tap on pass-code
    // pass-code screen should come up
    // tap on home icon in footer
    // user should back to dashboard screen
  })

  it('Enable Touch-Id', async () => {
    // tap on settings
    // tap on Enable Touch-Id
    // touchId enable screen should come up
  })
})


<|start_filename|>app/proof-request/__tests__/proof-request-autofill.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { ProofRequest } from '../proof-request'
import { PROOF_REQUEST_STATUS, PROOF_STATUS } from '../type-proof-request'
import {
  getStore,
  originalProofRequestData,
  proofRequest,
  senderDid1,
  senderName1,
  senderLogoUrl1,
  uid,
  getNavigation,
} from '../../../__mocks__/static-data'

describe('<ProofRequest />', () => {
  const store = getStore()
  let wrapper
  let proofRequestShown
  let acceptProofRequest
  let rejectProofRequest
  let ignoreProofRequest
  let getProof
  let updateAttributeClaim
  let tree
  let navigation
  let componentInstance
  let userSelfAttestedAttributes
  let proofRequestShowStart
  const isValid = true
  let proofStatus = PROOF_STATUS.NONE

  beforeEach(() => {
    proofRequestShown = jest.fn()
    acceptProofRequest = jest.fn()
    rejectProofRequest = jest.fn()
    ignoreProofRequest = jest.fn()
    userSelfAttestedAttributes = jest.fn()
    proofRequestShowStart = jest.fn()

    getProof = jest.fn()
    updateAttributeClaim = jest.fn()
    navigation = getNavigation({ uid })
    wrapper = renderer.create(
      <Provider store={store}>
        <ProofRequest
          data={proofRequest.payload.data}
          proofStatus={proofStatus}
          originalProofRequestData={originalProofRequestData}
          remotePairwiseDID={senderDid1}
          name={senderName1}
          proofRequestShown={proofRequestShown}
          acceptProofRequest={acceptProofRequest}
          ignoreProofRequest={ignoreProofRequest}
          rejectProofRequest={rejectProofRequest}
          getProof={getProof}
          updateAttributeClaim={updateAttributeClaim}
          navigation={navigation}
          uid={navigation.state.params.uid || ''}
          isValid={isValid}
          logoUrl={senderLogoUrl1}
          missingAttributes={{}}
          userSelfAttestedAttributes={userSelfAttestedAttributes}
          userAvatarSource={undefined}
          proofRequestShowStart={proofRequestShowStart}
        />
      </Provider>
    )
    tree = wrapper.toJSON()
    componentInstance = wrapper.root.findByType(ProofRequest).instance
  })

  it('should call proofRequestShown on componentDidMount', () => {
    expect(tree).toMatchSnapshot()
    expect(proofRequestShown).toHaveBeenCalledWith(uid)
  })
})


<|start_filename|>connectMeUITest/src/pageObjects/HomePage.java<|end_filename|>
package pageObjects;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

/**
 * Created by ankurmishra on 6/22/17.
 */
public class HomePage {

	private static WebElement element = null;

	public static WebElement Setting_Button(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("(//XCUIElementTypeOther[@name=' '])[2]/XCUIElementTypeOther[2]"));
			System.out.println("Allow Button is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("Allow Button not is displayed");
    		throw (e);
		}
	}

	public static WebElement Avatar_Photo(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("//XCUIElementTypeImage[@name='tab-active-avatar-icon']"));
			return element;
		} catch (Exception e) {
			
			throw (e);
		}
		

	}

	public static WebElement AddConnection_Button(AppiumDriver driver) throws Exception {
		try {

			element = driver.findElement(By.xpath("//XCUIElementTypeImage[@name='tab-add-connection-icon']"));
			System.out.println("Add connection button is displayed");
			return element;

		} catch (Exception e) {

			System.out.println("Add connection button is not displayed");
			throw (e);

		}
	}


}


<|start_filename|>app/components/request/request.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, Alert } from 'react-native'
import firebase from 'react-native-firebase'
import { bindActionCreators } from 'redux'
import { Container, TouchId } from '../../components'
import { connect } from 'react-redux'
import { TOUCH_ID_MESSAGE, TOUCH_ID_NOT_AVAILABLE, noop } from '../../common'
import RequestDetail from './request-detail'
import FooterActions from '../footer-actions/footer-actions'
import type { RequestProps, RequestState, ResponseTypes } from './type-request'
import { captureError } from '../../services/error/error-handler'
import { lockAuthorizationRoute } from '../../common/route-constants'
import type { Store } from '../../store/type-store'
import { pushNotificationPermissionAction } from '../../push-notification/push-notification-store'
import {
  ERROR_ALREADY_EXIST,
  ERROR_INVITATION_RESPONSE_FAILED,
  ERROR_ALREADY_EXIST_TITLE,
} from '../../api/api-constants'

export class Request extends PureComponent<RequestProps, RequestState> {
  state = {
    disableAccept: false,
  }

  onAccept = () => {
    this.setState({ disableAccept: true })
    // Move these values to enum, we are not doing it now because of TODO in type file
    return this.onAction('accepted')
  }

  onDecline = () => {
    // Move these values to enum, we are not doing it now because of TODO in type file
    return this.onAction('rejected')
  }

  onSuccessfulAuthorization = (response: ResponseTypes) => {
    this.props.onAction(response)
  }

  onDuplicateConnectionError = () => {
    this.onSuccessfulAuthorization('rejected')
  }

  onAvoidAuthorization = () => {
    /**
     * User can choose to avoid entering passcode either by canceling
     * or by pressing back button and choose to ignore passcode
     * then once user comes back, we need to re-enable button
     * so that user can press accept or decline button again
     */
    this.setState({ disableAccept: false })
  }

  onTouchIdFailed = (response: ResponseTypes) =>
    this.props.navigation.navigate(lockAuthorizationRoute, {
      onSuccess: () => this.onSuccessfulAuthorization(response),
      onAvoid: () => this.onAvoidAuthorization(),
    })

  authenticate = (response: ResponseTypes) => {
    return TouchId.isSupported()
      .then(result => TouchId.authenticate(TOUCH_ID_MESSAGE))
      .then(() => this.onSuccessfulAuthorization(response))
      .catch(() => this.onTouchIdFailed(response))
  }

  checkIfTouchIdEnabled(response: ResponseTypes) {
    if (this.props.isTouchIdEnabled) {
      return this.authenticate(response)
    } else {
      this.onTouchIdFailed(response)
    }
  }

  onAction = (response: ResponseTypes) => {
    return firebase
      .messaging()
      .requestPermission()
      .then(() => {
        this.props.pushNotificationPermissionAction(true)
        this.checkIfTouchIdEnabled(response)
      })
      .catch(error => {
        // astute readers will notice that we are calling authenticate
        // in success and fail both, so we can move it outside of promise
        // but we need to authenticate after user take allow/deny action
        // for push notification, after user allows/denies push notification
        // we need to authenticate user either with TouchId or passcode
        // unfortunately React-Native's (ES6's as well) Promise implementation
        // does not have finally block
        this.checkIfTouchIdEnabled(response)
        // TODO: we did not get push token
        // now what should we do?
        captureError(error, this.props.showErrorAlerts)
      })
  }

  componentDidUpdate(prevProps: RequestProps) {
    // When Accept invitation errors out we are re-enabling accept button. Giving user the option to retry.
    if (
      this.props.invitationError !== prevProps.invitationError &&
      this.props.invitationError
    ) {
      const isDuplicateConnection =
        this.props.invitationError.code === ERROR_ALREADY_EXIST.code
      const errorMessage = isDuplicateConnection
        ? `${this.props.invitationError.message}${this.props.senderName}`
        : ERROR_INVITATION_RESPONSE_FAILED
      const okAction = isDuplicateConnection
        ? this.onDuplicateConnectionError
        : noop
      const errorTitle = isDuplicateConnection
        ? ERROR_ALREADY_EXIST_TITLE
        : null

      Alert.alert(
        errorTitle,
        errorMessage,
        [{ text: 'Ok', onPress: okAction }],
        {
          cancelable: false,
        }
      )

      this.setState({
        disableAccept: false,
      })
    }
  }

  render() {
    const { title, message, senderLogoUrl, testID }: RequestProps = this.props

    return (
      <Container>
        <Container fifth>
          <RequestDetail
            title={title}
            message={message}
            senderLogoUrl={senderLogoUrl}
            testID={testID}
          />
        </Container>
        <FooterActions
          disableAccept={this.state.disableAccept}
          disableDeny={this.state.disableAccept}
          onAccept={this.onAccept}
          onDecline={this.onDecline}
          logoUrl={senderLogoUrl}
          testID={testID}
          useColorPicker={true}
        />
      </Container>
    )
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      pushNotificationPermissionAction,
    },
    dispatch
  )

const mapStateToProps = ({ lock }: Store) => {
  return {
    isTouchIdEnabled: lock.isTouchIdEnabled,
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Request)


<|start_filename|>app/components/button.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { Button } from 'react-native-elements'
import { color, font } from '../common/styles/constant'
import debounce from 'lodash.debounce'

const empty = []

const getButtonProps = type => ({
  backgroundColor: color.actions[type],
  color: color.actions.font[type],
  textAlign: 'center',
})

// TODO:KS Add specific prop that are needed and used by Button
export default class CustomButton extends PureComponent<*, void> {
  debounceButtonPress = debounce(
    event => {
      if (this.props.onPress) {
        this.props.onPress(event)
      }
    },
    600,
    { leading: true, trailing: false }
  )

  render() {
    const {
      primary,
      secondary,
      tertiary,
      quaternary,
      fifth,
      dangerous,
      medium,
      customColor = {},
      disabled,
    } = this.props
    const buttonStyles = this.props.style || empty
    const style = [
      medium ? styles.mediumVerticalPadding : null,
      ...buttonStyles,
    ]

    const buttonType = primary
      ? 'sixth'
      : secondary
        ? 'secondary'
        : tertiary
          ? 'tertiary'
          : quaternary
            ? 'quaternary'
            : dangerous ? 'dangerous' : fifth ? 'eighth' : 'fifth'
    const buttonProps = { ...getButtonProps(buttonType), ...customColor }
    // when button is disabled, we want to apply same color that is
    // generated while picking up the color from image
    const disabledStyles = [
      { backgroundColor: customColor.backgroundColor || color.actions.none },
      styles.disabled,
    ]

    return (
      <Button
        {...this.props}
        onPress={this.debounceButtonPress}
        {...buttonProps}
        accessible={true}
        accessibilityLabel={this.props.testID}
        buttonStyle={style}
        containerViewStyle={styles.buttonContainer}
        disabledStyle={disabledStyles}
      />
    )
  }
}

const styles = StyleSheet.create({
  buttonContainer: {
    marginRight: 0,
    marginLeft: 0,
  },
  mediumVerticalPadding: {
    paddingVertical: 17,
  },
  disabled: {
    opacity: 0.4,
  },
  text: {
    fontWeight: '600',
    fontSize: font.size.M,
  },
})


<|start_filename|>connectMeUITest/src/appModules/AppiumUtils.java<|end_filename|>
package appModules;

import org.openqa.selenium.WebElement;

import io.appium.java_client.AppiumDriver;
import pageObjects.InvitationPage;

public class AppiumUtils {
	public AppiumDriver driver;

	
	public static void nClick(int n,WebElement element) throws Exception
	{
		
		for(int i=0; i < n; i++)
		{
			element.click();
		}
	}
	
	
	
	
	

}


<|start_filename|>app/push-notification/push-notification.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View } from 'react-native'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import firebase from 'react-native-firebase'
import type { Notification, NotificationOpen } from 'react-native-firebase'
import {
  pushNotificationPermissionAction,
  updatePushToken,
  fetchAdditionalData,
} from './push-notification-store'
import PushNotificationNavigator from './push-notification-navigator'
import type { PushNotificationProps } from './type-push-notification'
import type { Store } from '../store/type-store'
import type { NotificationPayload } from '../common/type-common'

export class PushNotification extends PureComponent<
  PushNotificationProps,
  void
> {
  notificationListener = null
  initialNotificationListener = null
  refreshTokenListener = null
  notificationDisplayedListener = null
  onNotificationOpenedListener = null

  // Because the type returned from Notification for data is: { [string]: string }, we're parsing it in order to have proper type checks
  notificationParser(notification: Notification) {
    const {
      data: { forDID, uid, type, remotePairwiseDID, senderLogoUrl },
    } = notification

    return {
      forDID,
      uid,
      type,
      remotePairwiseDID,
      senderLogoUrl,
    }
  }

  componentDidMount = async () => {
    // TODO: refactor to run this based off of actions so that we're not creating a new push notification token when user is trying to restore wallet

    // Sets the current badge number on the app icon to zero.
    // iOS only for now.
    firebase.notifications().setBadge(0)
    // Removes all delivered notifications.
    firebase.notifications().removeAllDeliveredNotifications()

    // When a notification is displayed, the listener is invoked with the notification.
    this.notificationDisplayedListener = firebase
      .notifications()
      .onNotificationDisplayed((notification: Notification) => {
        this.onPushNotificationReceived(this.notificationParser(notification))
      })

    // When a notification is received, but not displayed, the listener is invoked with the notification.
    this.notificationListener = firebase
      .notifications()
      .onNotification((notification: Notification) => {
        this.onPushNotificationReceived(this.notificationParser(notification))
      })

    // When a notification is opened, the listener is invoked with the notification and the action that was invoked when it was clicked on.
    this.onNotificationOpenedListener = firebase
      .notifications()
      .onNotificationOpened((notificationOpen: NotificationOpen) => {
        // Get the action triggered by the notification being opened
        const action = notificationOpen.action
        // Get information about the notification that was opened
        const notification: Notification = notificationOpen.notification
        this.onPushNotificationReceived(this.notificationParser(notification))
      })

    try {
      // Due to the delay in the React Native bridge, the onNotification listeners will not be available at startup, so this method can be used to check to see if the application was opened by a notification.
      const notificationOpen: NotificationOpen = await firebase
        .notifications()
        .getInitialNotification()

      // App was opened by a notification
      if (notificationOpen) {
        // Get the action triggered by the notification being opened
        const action = notificationOpen.action
        // Get information about the notification that was opened
        const notification: Notification = notificationOpen.notification
        this.onPushNotificationReceived(this.notificationParser(notification))
      }
    } catch (e) {
      // TODO: handle error better
      console.log(e)
    }
  }

  listenForTokenUpdate() {
    this.refreshTokenListener = firebase.messaging().onTokenRefresh(token => {
      this.saveDeviceToken(token)
    })
  }

  onPushNotificationReceived(notificationPayload: NotificationPayload) {
    if (notificationPayload) {
      this.props.fetchAdditionalData(notificationPayload)
    }
  }

  saveDeviceToken(token: string) {
    if (token) {
      this.props.updatePushToken(token)
    }
  }

  getToken() {
    firebase
      .messaging()
      .getToken()
      .then(token => {
        if (token) {
          // user has a device token
          this.saveDeviceToken(token)
          this.listenForTokenUpdate()
        } else {
          // user doesn't have a device token
        }
      })
  }

  componentDidUpdate(prevProps: PushNotificationProps) {
    if (
      this.props.isAllowed !== prevProps.isAllowed &&
      this.props.isAllowed === true
    ) {
      this.getToken()
    }
  }
  componentWillUnmount() {
    // stop listening for events
    this.notificationListener && this.notificationListener.remove()
    this.refreshTokenListener && this.refreshTokenListener.remove()
    this.notificationDisplayedListener &&
      this.notificationDisplayedListener.remove()
    this.onNotificationOpenedListener &&
      this.onNotificationOpenedListener.remove()
  }
  render() {
    return (
      <PushNotificationNavigator navigateToRoute={this.props.navigateToRoute} />
    )
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      pushNotificationPermissionAction,
      updatePushToken,
      fetchAdditionalData,
    },
    dispatch
  )

const mapStateToProps = (state: Store) => {
  return {
    isAllowed: state.pushNotification.isAllowed,
    pushToken: state.pushNotification.pushToken,
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(PushNotification)


<|start_filename|>app/components/qr-scanner/__tests__/qr-url-validator.spec.js<|end_filename|>
// @flow

import { isValidUrlQrCode } from '../qr-url-validator'

describe('fn:isValidUrlQrCode', () => {
  // creating variables in test, so that our tests break if someone changes
  // scheme and hostname
  const validUrlQrCodeHost = 's3-us-west-2.amazonaws.com'
  const validUrlQrCodeScheme = 'https'

  const validOrigin = `${validUrlQrCodeScheme}://${validUrlQrCodeHost}/vcx-env`

  it('should return url, when url is valid', () => {
    const name = 'dev'
    const urlQrCode = `${validOrigin}/${name}`
    expect(isValidUrlQrCode(urlQrCode)).toEqual({
      url: urlQrCode,
      name,
    })
  })

  it('should return url, when path name is valid', () => {
    const name = 'dev-dev-dev-dev'
    const urlQrCode = `${validOrigin}/${name}`
    expect(isValidUrlQrCode(urlQrCode)).toEqual({
      url: urlQrCode,
      name,
    })
  })

  it('should return false, if we pass an array in pathname', () => {
    const urlQrCode = `${validOrigin}/['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, if we pass comma separated values in path name', () => {
    const urlQrCode = `${validOrigin}/aaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaa`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, if protocol is not https', () => {
    const urlQrCode = `http://${validUrlQrCodeHost}/dev`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, hostname is invalid', () => {
    const urlQrCode = `${validUrlQrCodeScheme}://xyz.com/dev`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, if no path name is supplied', () => {
    const urlQrCode = `https://${validUrlQrCodeHost}/`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, if length of path name is more than expected', () => {
    const urlQrCode = `${validOrigin}/devdevdevdevdevdevdevdevdevdevdevdevdevdevdevdevdev`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, if path name contains unwanted characters', () => {
    const urlQrCode = `${validOrigin}/devdevdevdevdevdevde9.`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, if spaces are added to url path', () => {
    const urlQrCode = `https://${validUrlQrCodeHost}/   `
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })

  it('should return false, if last path name is not specified', () => {
    const urlQrCode = `${validOrigin}/dev/`
    expect(isValidUrlQrCode(urlQrCode)).toBe(false)
  })
})


<|start_filename|>app/store/ledger/ledger-store.js<|end_filename|>
// @flow

import { STORE_STATUS } from '../../common/type-common'
import {
  GET_LEDGER_FEES,
  getLedgerFeesFail,
  ERROR_GET_LEDGER_FEES,
  getLedgerFeesSuccess,
  GET_LEDGER_FEES_SUCCESS,
  GET_LEDGER_FEES_FAIL,
  RESET_LEDGER_FEES,
} from './type-ledger-store'
import type {
  LedgerAction,
  LedgerStore,
  LedgerFeesData,
} from './type-ledger-store'
import { put, take, all, call, select, takeLatest } from 'redux-saga/effects'
import { getLedgerFees } from '../../bridge/react-native-cxs/RNCxs'
import { ensureVcxInitSuccess } from '../config-store'
import { captureError } from '../../services/error/error-handler'

const initialState = {
  fees: {
    data: {
      transfer: '0',
    },
    status: STORE_STATUS.IDLE,
    error: null,
  },
}

export function* getLedgerFeesSaga(): Generator<*, *, *> {
  try {
    const vcxResult = yield* ensureVcxInitSuccess()
    if (vcxResult && vcxResult.fail) {
      throw new Error(JSON.stringify(vcxResult.fail.message))
    }
    const fees: LedgerFeesData = yield call(getLedgerFees)
    yield put(getLedgerFeesSuccess(fees))
  } catch (e) {
    captureError(e)
    yield put(getLedgerFeesFail(ERROR_GET_LEDGER_FEES(e.message)))
  }
}

export function* watchGetLedgerFees(): any {
  yield takeLatest(GET_LEDGER_FEES, getLedgerFeesSaga)
}

export function* watchLedgerStore(): any {
  yield all([watchGetLedgerFees()])
}

export function ledgerStoreReducer(
  state: LedgerStore = initialState,
  action: LedgerAction
): LedgerStore {
  switch (action.type) {
    case GET_LEDGER_FEES:
      return {
        ...state,
        fees: {
          ...state.fees,
          status: STORE_STATUS.IN_PROGRESS,
          error: null,
        },
      }

    case GET_LEDGER_FEES_SUCCESS:
      return {
        ...state,
        fees: {
          ...state.fees,
          status: STORE_STATUS.SUCCESS,
          error: null,
          data: {
            ...action.fees,
          },
        },
      }

    case GET_LEDGER_FEES_FAIL:
      return {
        ...state,
        fees: {
          ...state.fees,
          status: STORE_STATUS.ERROR,
          error: action.error,
        },
      }

    case RESET_LEDGER_FEES:
      return initialState

    default:
      return state
  }
}


<|start_filename|>app/components/layout/custom-list.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View } from 'react-native'
import { Container } from './container'
import { CustomView } from './custom-view'
import styles from './layout-style'
import type { GenericObject } from '../../common/type-common'

const Item = ({ item: { left, right }, itemStyle }) => (
  <Container vCenter row style={[styles.listItem]}>
    {left && <Container left>{left}</Container>}
    {right && <CustomView right>{right}</CustomView>}
  </Container>
)

export default function CustomList(props: CustomListProps) {
  const { data } = props
  const style = props.style || {}
  const itemList = data.map(item => (
    <Item key={item.id} item={item} itemStyle={style.itemStyle} />
  ))

  return <View style={[styles.list, style.listStyle]}>{itemList}</View>
}

type CustomListItem = {
  id: string | number,
  left?: any,
  right?: any,
}

type CustomListProps = {
  data: Array<CustomListItem>,
  style?: GenericObject,
}


<|start_filename|>app/services/error/error-tracker.js<|end_filename|>
// // @flow
// import { Sentry, SentryLog } from 'react-native-sentry'

// // Configure install to add error handler
// const originalSentryInstall = Sentry.install
// Sentry.install = () => {
//   const result = originalSentryInstall()
//   configureSentryErrorHandler()
//   return result
// }

// function configureSentryErrorHandler() {
//   let sentryErrorHandler =
//     // $FlowFixMe ErrorUtils is global variable
//     (ErrorUtils.getGlobalHandler && ErrorUtils.getGlobalHandler()) ||
//     ErrorUtils._globalHandler

//   ErrorUtils.setGlobalHandler((error, isFatal) => {
//     console.log('is fatal, ', isFatal)
//     sentryErrorHandler(error, isFatal)
//   })
// }

// Sentry.config('https://66b7fcd2ca4943c6b7dfcc956ec5e2bf@sentry.io/188725', {
//   logLevel: SentryLog.None,
//   disableNativeIntegration: true,
// }).install()

// export default Sentry


<|start_filename|>app/components/text.js<|end_filename|>
// @flow
import React from 'react'
import { Text, Animated, StyleSheet } from 'react-native'
import empty from '../common/empty'
import { color, font } from '../common/styles/constant'
import debounce from 'lodash.debounce'
import type { GenericObject } from '../common/type-common'

export function formatNumbers(num: string) {
  if (num) {
    let numStr = num.toString().split('.')
    numStr[0] = numStr[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',')
    return numStr.join('.')
  }
  return num
}

//TODO: Default font color should be tertiary and background should also be tertiary.
const CustomText = (props: GenericObject) => {
  const {
    h3,
    h3a,
    h4,
    h4a,
    h5,
    h6,
    h7,
    bold,
    thick,
    semiBold,
    demiBold,
    center,
    bg = 'primary',
    primary,
    secondary,
    tertiary,
    quaternary,
    quinaryText,
    errorText,
    borderColor,
    style = [],
    testID,
    onPress,
    onLongPress,
    transparentBg,
    uppercase,
    heavy,
    numberOfLines,
    formatNumber,
    fullWidth,
    adjustsFontSizeToFit,
    allowFontScaling,
    animated,
    charcoal,
    secondaryColor,
    darkgray,
    medium,
  } = props

  const colorType = quaternary
    ? 'Quaternary'
    : secondary ? 'Secondary' : tertiary ? 'Tertiary' : 'Primary'
  const size = h3
    ? 'h3'
    : h3a ? 'h3a' : h4 ? 'h4' : h4a ? 'h4a' : h6 ? 'h6' : h7 ? 'h7' : 'h5'
  const fontFamily = 'fontLato'
  const textStyles = [
    styles[size],
    styles[fontFamily],
    // $FlowFixMe Flow does not support below syntax for type checking
    styles[`${bg}Bg${colorType}`],
    bold
      ? styles.bold
      : semiBold
        ? styles.semiBold
        : thick
          ? styles.thick
          : demiBold
            ? styles.demiBold
            : heavy ? styles.heavy : medium ? styles.medium : null,
    center ? styles.center : null,
    transparentBg ? styles.transparentBg : null,
    quinaryText ? styles.orangeText : null,
    errorText ? styles.errorText : null,
    borderColor ? styles.borderColor : null,
    primary ? styles.primary : null,
    fullWidth ? styles.fullWidth : null,
    charcoal ? styles.colorCharcoal : null,
    secondaryColor ? styles.greyColor : null,
    darkgray ? styles.darkgray : null,
    ...style,
  ]
  const TextComponent = animated ? Animated.Text : Text

  let filteredProps = {}
  if (typeof onLongPress !== 'undefined') {
    filteredProps.onLongPress = onLongPress
  }
  if (typeof testID !== 'undefined') {
    filteredProps.testID = testID
    filteredProps.accessible = true
    filteredProps.accessibilityLabel = testID
  }
  if (typeof onPress !== 'undefined') {
    filteredProps.onPress = debounce(
      event => {
        onPress(event)
      },
      300,
      { leading: true, trailing: false }
    )
  }
  if (typeof numberOfLines !== 'undefined') {
    filteredProps.numberOfLines = numberOfLines
  }
  let textChild = props.children
  if (uppercase) {
    textChild = props.children.toUpperCase()
  }
  if (formatNumber) {
    textChild = formatNumbers(props.children)
  }
  if (adjustsFontSizeToFit) {
    filteredProps.adjustsFontSizeToFit = adjustsFontSizeToFit
  }
  if (allowFontScaling && animated) {
    filteredProps.allowFontScaling = allowFontScaling
  } else {
    filteredProps.allowFontScaling = false
  }

  return (
    <TextComponent style={textStyles} {...filteredProps}>
      {textChild}
    </TextComponent>
  )
}

export default CustomText
//TODO h should start with h1 to h4
export const styles = StyleSheet.create({
  h3: {
    fontSize: font.size.L,
  },
  h3a: {
    fontSize: font.size.L1,
  },
  h4a: {
    fontSize: font.size.M1,
  },
  h4: {
    fontSize: font.size.ML,
  },
  h5: {
    fontSize: font.size.M,
  },
  h6: {
    fontSize: font.size.S,
  },
  h7: {
    fontSize: font.size.XS,
  },
  medium: {
    fontWeight: '500',
  },
  semiBold: {
    fontWeight: '600',
  },
  demiBold: {
    fontWeight: '600',
  },
  bold: {
    fontWeight: 'bold',
  },
  thick: {
    fontWeight: '800',
  },
  heavy: {
    fontWeight: '900',
  },
  center: {
    textAlign: 'center',
  },
  primaryBgPrimary: {
    color: color.bg.primary.font.primary,
    backgroundColor: color.bg.primary.color,
  },
  primaryBgSecondary: {
    color: color.bg.primary.font.secondary,
    backgroundColor: color.bg.primary.color,
  },
  primaryBgTertiary: {
    color: color.bg.primary.font.tertiary,
    backgroundColor: color.bg.primary.color,
  },
  fifthBgPrimary: {
    color: color.bg.fifth.font.primary,
    backgroundColor: color.bg.fifth.color,
  },
  fifthBgTertiary: {
    color: color.bg.fifth.font.primary,
    backgroundColor: color.bg.tertiary.color,
  },
  tertiaryBgPrimary: {
    color: color.bg.tertiary.font.primary,
    backgroundColor: color.bg.tertiary.color,
  },
  tertiaryBgTertiary: {
    color: color.bg.tertiary.font.tertiary,
    backgroundColor: color.bg.tertiary.color,
  },
  septenaryBgPrimary: {
    color: color.bg.tertiary.font.primary,
    backgroundColor: color.bg.seventh.color,
  },
  transparentBg: {
    backgroundColor: 'transparent',
  },
  orangeText: {
    color: color.bg.eighth.color,
  },
  errorText: {
    color: color.bg.tenth.font.color,
  },
  borderColor: {
    borderWidth: 2,
    borderColor: color.bg.eighth.border.color,
  },
  primary: {
    color: color.bg.primary.color,
  },
  fontLato: {
    fontFamily: font.family,
  },
  fullWidth: {
    width: '100%',
  },
  colorCharcoal: {
    color: color.textColor.charcoal,
  },
  greyColor: {
    color: color.textColor.grey,
  },
  darkgray: {
    color: color.textColor.darkgray,
  },
})


<|start_filename|>__mocks__/camera-mock.js<|end_filename|>
// @flow
import React from 'react'
import { View } from 'react-native'

const constants = {
  Aspect: {},
  BarCodeType: {},
  Type: {},
  CaptureMode: {},
  CaptureTarget: {},
  CaptureQuality: {},
  Orientation: {},
  FlashMode: {},
  TorchMode: {},
}

// We don't need to type check external library
// and we don't need types for mock test stub
class MockCamera extends React.Component<any, void> {
  static constants = constants
  static checkVideoAuthorizationStatus = jest.fn(() => Promise.resolve(true))

  render() {
    return <View>{this.props.children}</View>
  }
}

MockCamera.constants = constants

export default MockCamera


<|start_filename|>connectMeUITest/src/utility/ErrorCodeMatcher.java<|end_filename|>
package utility;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.hyperledger.indy.sdk.ErrorCode;
import org.hyperledger.indy.sdk.IndyException;

public class ErrorCodeMatcher extends TypeSafeMatcher<IndyException> {
	private ErrorCode expectedErrorCode;

	public ErrorCodeMatcher(ErrorCode errorCode) {
		this.expectedErrorCode = errorCode;
	}

	@Override
	protected boolean matchesSafely(IndyException e) {
		return expectedErrorCode.equals(e.getErrorCode());
	}

	@Override
	public void describeTo(Description description) {
		description.appendText("expect ").appendText(expectedErrorCode.name());
	}
}


<|start_filename|>app/connection-history/history-middleware.js<|end_filename|>
// @flow
import type { Middleware, MiddlewareAPI, Dispatch } from 'redux'
import { INVITATION_RECEIVED } from '../invitation/type-invitation'
import { NEW_CONNECTION_SUCCESS } from '../store/connections-store'
import {
  SEND_CLAIM_REQUEST_SUCCESS,
  CLAIM_OFFER_RECEIVED,
} from '../claim-offer/type-claim-offer'
import { CLAIM_STORAGE_SUCCESS } from '../claim/type-claim'
import {
  PROOF_REQUEST_RECEIVED,
  SEND_PROOF_SUCCESS,
} from '../proof-request/type-proof-request'
import {
  RECORD_HISTORY_EVENT,
  HISTORY_EVENT_STORAGE_KEY,
} from './type-connection-history'
import { historyEventOccurred } from './connection-history-store'

const actionToRecord = [
  // removing invitation received from record array
  // because anyway we will not show this event in history view
  // also it uses secure set that is only accessible after vcx_init
  // and we don't want to trigger vxc_init just because invitation
  // is downloaded
  // INVITATION_RECEIVED,
  NEW_CONNECTION_SUCCESS,
  PROOF_REQUEST_RECEIVED,
  CLAIM_OFFER_RECEIVED,
  SEND_CLAIM_REQUEST_SUCCESS,
  CLAIM_STORAGE_SUCCESS,
  SEND_PROOF_SUCCESS,
]

// TODO:KS Fix any type using `redux` provided Generic Types
const history = (store: any) => (next: any) => (action: any) => {
  // pass on the action first to other middleware in line
  const nextState = next(action)

  // now go for our own history recorder
  if (actionToRecord.indexOf(action.type) > -1) {
    // we got an action that needs to be recorded
    // dispatch an action, that starts from beginning of middleware chain
    // we are dispatching a new action here
    store.dispatch(historyEventOccurred(action))
  }

  return nextState
}

export default history


<|start_filename|>app/components/request/type-request.js<|end_filename|>
// @flow
import type { ReactNavigation, CustomError } from '../../common/type-common'

export type noop = () => any

export type RequestDetailTextPropsText = {
  title: string,
  message: string,
  testID: string,
}

export type RequestDetailTextProps = RequestDetailTextPropsText

export type RequestDetailAvatarProps = {
  senderLogoUrl?: ?string,
}

export type RequestDetailProps = RequestDetailTextProps &
  RequestDetailAvatarProps

export const ResponseType = {
  accepted: 'accepted',
  rejected: 'rejected',
  none: 'none',
}

// TODO: Need to move this to one place for each store such as invitation, qr connection, & authentication request
export type ResponseTypes = $Keys<typeof ResponseType>

export type RequestProps = RequestDetailProps & {
  onAction: (response: ResponseTypes) => void,
  showErrorAlerts: boolean,
  isTouchIdEnabled: boolean,
  pushNotificationPermissionAction: boolean => void,
  invitationError?: ?CustomError,
  senderName: string,
} & ReactNavigation

export type RequestState = {
  disableAccept: boolean,
}


<|start_filename|>android/app/src/main/assets/external/connectme/css/styles.css<|end_filename|>
/* ========================================================================
   Component: Base
 ========================================================================== */
/*
 * 1. Set `font-size` to support `rem` units
 *    Not using `font` property because a leading hyphen (e.g. -apple-system) causes the font to break in IE11 and Edge
 * 2. Prevent adjustments of font size after orientation changes in IE and iOS.
 * 3. Style
 */
 html {
  /* 1 */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  font-weight: normal;
  line-height: 1.5;
  /* 2 */
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  /* 3 */
  background: #fff;
  color: #666; }

/*
 * Removes default margin.
 */
body {
  margin: 0; }

/* Links
 ========================================================================== */
/*
 * Remove gaps in links underline in iOS 8+ and Safari 8+.
 */
a {
  -webkit-text-decoration-skip: objects; }

/*
 * Remove the outline on focused links when they are also active or hovered
 */
a:active,
a:hover {
  outline: none; }

/*
 * Style
 */
a,
.uk-link {
  color: #1e87f0;
  text-decoration: none;
  cursor: pointer; }

a:hover,
.uk-link:hover {
  color: #0f6ecd;
  text-decoration: underline; }

/* Text-level semantics
 ========================================================================== */
/*
 * 1. Remove the bottom border in Firefox 39-.
 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 */
abbr[title] {
  border-bottom: none;
  /* 1 */
  text-decoration: underline;
  /* 2 */
  text-decoration: underline dotted;
  /* 2 */ }

/*
 * Add the correct font weight in Chrome, Edge, and Safari.
 */
b,
strong {
  font-weight: bolder; }

/*
 * 1. Correct the odd `em` font sizing in all browsers.
 * 2. Consolas has a better baseline in running text compared to `Courier`
 * 3. Style
 */
:not(pre) > code,
:not(pre) > kbd,
:not(pre) > samp {
  /* 1 */
  font-size: 0.875rem;
  /* 2 */
  font-family: Consolas, monaco, monospace;
  /* 3 */
  color: #f0506e;
  white-space: nowrap; }

/*
 * Emphasize
 */
em {
  color: #f0506e; }

/*
 * Insert
 */
ins {
  background: #ffd;
  color: #666;
  text-decoration: none; }

/*
 * Mark
 */
mark {
  background: #ffd;
  color: #666; }

/*
 * Quote
 */
q {
  font-style: italic; }

/*
 * Add the correct font size in all browsers.
 */
small {
  font-size: 80%; }

/*
 * Prevents `sub` and `sup` affecting `line-height` in all browsers.
 */
sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline; }

sup {
  top: -0.5em; }

sub {
  bottom: -0.25em; }

/* Embedded content
 ========================================================================== */
/*
 * Remove the gap between embedded content and the bottom of their containers.
 */
audio,
canvas,
iframe,
img,
svg,
video {
  vertical-align: middle; }

/*
 * Responsiveness
 * 1. Set a maximum width
 * 2. Auto scale the height. Only needed if `height` attribute is present
 * 2. Corrects `max-width` behavior if padding and border are used
 */
audio,
canvas,
img,
video {
  /* 1 */
  max-width: 100%;
  /* 2 */
  height: auto;
  /* 3 */
  box-sizing: border-box; }

/*
 * Hide the overflow in IE.
 */
svg:not(:root) {
  overflow: hidden; }

/* Block elements
 ========================================================================== */
/*
 * Margins
 */
p,
ul,
ol,
dl,
pre,
address,
fieldset,
figure {
  margin: 0 0 20px 0; }

/* Add margin if adjacent element */
* + p,
* + ul,
* + ol,
* + dl,
* + pre,
* + address,
* + fieldset,
* + figure {
  margin-top: 20px; }

/* Headings
 ========================================================================== */
h1, .uk-h1,
h2, .uk-h2,
h3, .uk-h3,
h4, .uk-h4,
h5, .uk-h5,
h6, .uk-h6 {
  margin: 0 0 20px 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-weight: normal;
  color: #333;
  text-transform: none; }

/* Add margin if adjacent element */
* + h1, * + .uk-h1,
* + h2, * + .uk-h2,
* + h3, * + .uk-h3,
* + h4, * + .uk-h4,
* + h5, * + .uk-h5,
* + h6, * + .uk-h6 {
  margin-top: 40px; }

/*
 * Sizes
 */
h1, .uk-h1 {
  font-size: 2.625rem;
  line-height: 1.2; }

h2, .uk-h2 {
  font-size: 2rem;
  line-height: 1.3; }

h3, .uk-h3 {
  font-size: 1.5rem;
  line-height: 1.4; }

h4, .uk-h4 {
  font-size: 1.25rem;
  line-height: 1.4; }

h5, .uk-h5 {
  font-size: 16px;
  line-height: 1.4; }

h6, .uk-h6 {
  font-size: 0.875rem;
  line-height: 1.4; }

/* Lists
 ========================================================================== */
ul,
ol {
  padding-left: 30px; }

/*
 * Reset margin for nested lists
 */
ul > li > ul,
ul > li > ol,
ol > li > ol,
ol > li > ul {
  margin: 0; }

/* Description lists
 ========================================================================== */
dt {
  font-weight: bold; }

dd {
  margin-left: 0; }

/* Horizontal rules
 ========================================================================== */
/*
 * 1. Add the correct box sizing and height in Firefox.
 * 2. Show the overflow in Edge and IE.
 * 3. Add the correct text-align in Edge and IE.
 * 4. Style
 */
hr, .uk-hr {
  /* 1 */
  box-sizing: content-box;
  height: 0;
  /* 2 */
  overflow: visible;
  /* 3 */
  text-align: inherit;
  /* 4 */
  margin: 0 0 20px 0;
  border: 0;
  border-top: 1px solid #e5e5e5; }

/* Add margin if adjacent element */
* + hr,
* + .uk-hr {
  margin-top: 20px; }

/* Address
 ========================================================================== */
address {
  font-style: normal; }

/* Blockquotes
 ========================================================================== */
blockquote {
  margin: 0 0 20px 0;
  font-size: 1.25rem;
  line-height: 1.5;
  font-style: italic; }

/* Add margin if adjacent element */
* + blockquote {
  margin-top: 20px; }

/*
 * Content
 */
blockquote p:last-of-type {
  margin-bottom: 0; }

blockquote footer {
  margin-top: 10px;
  font-size: 0.875rem;
  line-height: 1.5; }

/* Preformatted text
 ========================================================================== */
/*
 * 1. Contain overflow in all browsers.
 * 2. Override UA
 */
pre {
  font: 0.875rem / 1.5 Consolas, monaco, monospace;
  color: #666;
  -moz-tab-size: 4;
  tab-size: 4;
  /* 1 */
  overflow: auto; }

pre code {
  font-family: Consolas, monaco, monospace; }

/* Selection pseudo-element
 ========================================================================== */
::-moz-selection {
  background: #39f;
  color: #fff;
  text-shadow: none; }

::selection {
  background: #39f;
  color: #fff;
  text-shadow: none; }

/* HTML5 elements
 ========================================================================== */
/*
 * 1. Add the correct display in Edge, IE, and Firefox.
 * 2. Add the correct display in IE.
 */
details,
main {
  /* 2 */
  display: block; }

/*
 * Add the correct display in all browsers.
 */
summary {
  display: list-item; }

/*
 * Add the correct vertical alignment in Chrome, Firefox, and Opera.
 */
progress {
  vertical-align: baseline; }

/*
 * Add the correct display in IE.
 */
template {
  display: none; }

/* Iframe
 ========================================================================== */
iframe {
  border: 0; }

/* Prevent the 300ms delay for touchscreen interactions
 ========================================================================== */
/*
 * Most browsers prevent the 300ms delay automatically for sites that use the `width=device-width` property.
 * For Safari on iOS 9.3+, IE 11 and Edge on desktops and IE 11 on Windows Phone 8.1 it must be applied manually.
 */
a,
area,
button,
input,
label,
select,
summary,
textarea {
  touch-action: manipulation; }

/* Pass media breakpoints to JS
 ========================================================================== */
/*
 * Breakpoints
 */
.var-media-s::before {
  content: "640px"; }

.var-media-m::before {
  content: "960px"; }

.var-media-l::before {
  content: "1200px"; }

.var-media-xl::before {
  content: "1600px"; }

/* ========================================================================
   Component: Animation
 ========================================================================== */
[class*='uk-animation-'] {
  animation-duration: 0.15s;
  animation-timing-function: ease-out;
  animation-fill-mode: both; }

/* Direction modifier
 ========================================================================== */
.uk-animation-reverse {
  animation-direction: reverse;
  animation-timing-function: ease-in; }

/* Animations for scrollspy
 ========================================================================== */
/*
 * Fade
 */
.uk-animation-fade {
  animation-name: uk-fade;
  animation-duration: 0.3s;
  animation-timing-function: linear; }

/*
 * Scale
 */
.uk-animation-scale-up {
  animation-name: uk-fade-scale-02; }

.uk-animation-scale-down {
  animation-name: uk-fade-scale-18; }

/*
 * Slide
 */
.uk-animation-slide-top {
  animation-name: uk-fade-top; }

.uk-animation-slide-bottom {
  animation-name: uk-fade-bottom; }

.uk-animation-slide-left {
  animation-name: uk-fade-left; }

.uk-animation-slide-right {
  animation-name: uk-fade-right; }

/*
 * Slide Small
 */
.uk-animation-slide-top-small {
  animation-name: uk-fade-top-small; }

.uk-animation-slide-bottom-small {
  animation-name: uk-fade-bottom-small; }

.uk-animation-slide-left-small {
  animation-name: uk-fade-left-small; }

.uk-animation-slide-right-small {
  animation-name: uk-fade-right-small; }

/*
 * Slide Medium
 */
.uk-animation-slide-top-medium {
  animation-name: uk-fade-top-medium; }

.uk-animation-slide-bottom-medium {
  animation-name: uk-fade-bottom-medium; }

.uk-animation-slide-left-medium {
  animation-name: uk-fade-left-medium; }

.uk-animation-slide-right-medium {
  animation-name: uk-fade-right-medium; }

/*
 * Kenburns
 */
.uk-animation-kenburns {
  animation-name: uk-scale-kenburns;
  animation-duration: 15s; }

/*
 * Shake
 */
.uk-animation-shake {
  animation-name: uk-shake; }

/* Duration modifier
 ========================================================================== */
.uk-animation-fast {
  animation-duration: 0.1s; }

/* Enable animation only on hover
========================================================================== */
/*
 * Note: Firefox and IE needs this because animations are not triggered when switching between display `none` and `block`
 */
.uk-animation-toggle:not(:hover):not(.uk-hover) [class*='uk-animation-'] {
  animation-name: none; }

/* Keyframes used by animation classes
 ========================================================================== */
/*
 * Fade
 */
@keyframes uk-fade {
  0% {
    opacity: 0; }
  100% {
    opacity: 1; } }

/*
 * Slide Top
 */
@keyframes uk-fade-top {
  0% {
    opacity: 0;
    transform: translateY(-100%); }
  100% {
    opacity: 1;
    transform: translateY(0); } }

/*
 * Slide Bottom
 */
@keyframes uk-fade-bottom {
  0% {
    opacity: 0;
    transform: translateY(100%); }
  100% {
    opacity: 1;
    transform: translateY(0); } }

/*
 * Slide Left
 */
@keyframes uk-fade-left {
  0% {
    opacity: 0;
    transform: translateX(-100%); }
  100% {
    opacity: 1;
    transform: translateX(0); } }

/*
 * Slide Right
 */
@keyframes uk-fade-right {
  0% {
    opacity: 0;
    transform: translateX(100%); }
  100% {
    opacity: 1;
    transform: translateX(0); } }

/*
 * Slide Top Small
 */
@keyframes uk-fade-top-small {
  0% {
    opacity: 0;
    transform: translateY(-10px); }
  100% {
    opacity: 1;
    transform: translateY(0); } }

/*
 * Slide Bottom Small
 */
@keyframes uk-fade-bottom-small {
  0% {
    opacity: 0;
    transform: translateY(10px); }
  100% {
    opacity: 1;
    transform: translateY(0); } }

/*
 * Slide Left Small
 */
@keyframes uk-fade-left-small {
  0% {
    opacity: 0;
    transform: translateX(-10px); }
  100% {
    opacity: 1;
    transform: translateX(0); } }

/*
 * Slide Right Small
 */
@keyframes uk-fade-right-small {
  0% {
    opacity: 0;
    transform: translateX(10px); }
  100% {
    opacity: 1;
    transform: translateX(0); } }

/*
 * Slide Top Medium
 */
@keyframes uk-fade-top-medium {
  0% {
    opacity: 0;
    transform: translateY(-50px); }
  100% {
    opacity: 1;
    transform: translateY(0); } }

/*
 * Slide Bottom Medium
 */
@keyframes uk-fade-bottom-medium {
  0% {
    opacity: 0;
    transform: translateY(50px); }
  100% {
    opacity: 1;
    transform: translateY(0); } }

/*
 * Slide Left Medium
 */
@keyframes uk-fade-left-medium {
  0% {
    opacity: 0;
    transform: translateX(-50px); }
  100% {
    opacity: 1;
    transform: translateX(0); } }

/*
 * Slide Right Medium
 */
@keyframes uk-fade-right-medium {
  0% {
    opacity: 0;
    transform: translateX(50px); }
  100% {
    opacity: 1;
    transform: translateX(0); } }

/*
 * Scale Up
 */
@keyframes uk-fade-scale-02 {
  0% {
    opacity: 0;
    transform: scale(0.2); }
  100% {
    opacity: 1;
    transform: scale(1); } }

/*
 * Scale Down
 */
@keyframes uk-fade-scale-18 {
  0% {
    opacity: 0;
    transform: scale(1.8); }
  100% {
    opacity: 1;
    transform: scale(1); } }

/*
 * Kenburns
 */
@keyframes uk-scale-kenburns {
  0% {
    transform: scale(1); }
  100% {
    transform: scale(1.2); } }

/*
 * Shake
 */
@keyframes uk-shake {
  0%, 100% {
    transform: translateX(0); }
  10% {
    transform: translateX(-9px); }
  20% {
    transform: translateX(8px); }
  30% {
    transform: translateX(-7px); }
  40% {
    transform: translateX(6px); }
  50% {
    transform: translateX(-5px); }
  60% {
    transform: translateX(4px); }
  70% {
    transform: translateX(-3px); }
  80% {
    transform: translateX(2px); }
  90% {
    transform: translateX(-1px); } }

/* ========================================================================
   Component: Transition
 ========================================================================== */
/*
 * Using multiple selectors to exclude `uk-transition-toggle`
 * Note: Transitions don't work with `uk-postion-center-*` classes because they also use `transform`
 *       Just put the transition in an extra `div`
 */
.uk-transition-fade,
[class*='uk-transition-scale'],
[class*='uk-transition-slide'] {
  transition: 0.3s ease-out;
  transition-property: opacity, transform, filter; }

.uk-transition-toggle:focus {
  outline: none; }

/*
 * Fade
 */
.uk-transition-fade {
  opacity: 0; }

/* Show */
.uk-transition-toggle:hover [class*='uk-transition-fade'],
.uk-transition-toggle.uk-hover [class*='uk-transition-fade'],
.uk-transition-toggle:focus [class*='uk-transition-fade'],
.uk-transition-active.uk-active [class*='uk-transition-fade'] {
  opacity: 1; }

/*
 * Scale
 * Note: Using `scale3d` for better image rendering
 */
[class*='uk-transition-scale'] {
  opacity: 0; }

.uk-transition-scale-up {
  transform: scale3d(1, 1, 1); }

.uk-transition-scale-down {
  transform: scale3d(1.1, 1.1, 1); }

/* Show */
.uk-transition-toggle:hover .uk-transition-scale-up,
.uk-transition-toggle.uk-hover .uk-transition-scale-up,
.uk-transition-toggle:focus .uk-transition-scale-up,
.uk-transition-active.uk-active .uk-transition-scale-up {
  opacity: 1;
  transform: scale3d(1.1, 1.1, 1); }

.uk-transition-toggle:hover .uk-transition-scale-down,
.uk-transition-toggle.uk-hover .uk-transition-scale-down,
.uk-transition-toggle:focus .uk-transition-scale-down,
.uk-transition-active.uk-active .uk-transition-scale-down {
  opacity: 1;
  transform: scale3d(1, 1, 1); }

/*
 * Slide
 */
[class*='uk-transition-slide'] {
  opacity: 0; }

.uk-transition-slide-top {
  transform: translateY(-100%); }

.uk-transition-slide-bottom {
  transform: translateY(100%); }

.uk-transition-slide-left {
  transform: translateX(-100%); }

.uk-transition-slide-right {
  transform: translateX(100%); }

.uk-transition-slide-top-small {
  transform: translateY(-10px); }

.uk-transition-slide-bottom-small {
  transform: translateY(10px); }

.uk-transition-slide-left-small {
  transform: translateX(-10px); }

.uk-transition-slide-right-small {
  transform: translateX(10px); }

.uk-transition-slide-top-medium {
  transform: translateY(-50px); }

.uk-transition-slide-bottom-medium {
  transform: translateY(50px); }

.uk-transition-slide-left-medium {
  transform: translateX(-50px); }

.uk-transition-slide-right-medium {
  transform: translateX(50px); }

/* Show */
.uk-transition-toggle:hover [class*='uk-transition-slide'],
.uk-transition-toggle.uk-hover [class*='uk-transition-slide'],
.uk-transition-toggle:focus [class*='uk-transition-slide'],
.uk-transition-active.uk-active [class*='uk-transition-slide'] {
  opacity: 1;
  transform: translateX(0) translateY(0); }

/* Opacity modifier
========================================================================== */
.uk-transition-opaque {
  opacity: 1; }

/* Duration modifiers
========================================================================== */
.uk-transition-slow {
  transition-duration: 0.7s; }

/* ========================================================================
   Component: Visibility
 ========================================================================== */
/*
 * Hidden
 * `hidden` attribute also set here to make it stronger
 */
[hidden],
.uk-hidden {
  display: none !important; }

/* Phone landscape and bigger */
@media (min-width: 640px) {
  .uk-hidden\@s {
    display: none !important; } }

/* Tablet landscape and bigger */
@media (min-width: 960px) {
  .uk-hidden\@m {
    display: none !important; } }

/* Desktop and bigger */
@media (min-width: 1200px) {
  .uk-hidden\@l {
    display: none !important; } }

/* Large screen and bigger */
@media (min-width: 1600px) {
  .uk-hidden\@xl {
    display: none !important; } }

/*
 * Visible
 */
/* Phone portrait and smaller */
@media (max-width: 639px) {
  .uk-visible\@s {
    display: none !important; } }

/* Phone landscape and smaller */
@media (max-width: 959px) {
  .uk-visible\@m {
    display: none !important; } }

/* Tablet landscape and smaller */
@media (max-width: 1199px) {
  .uk-visible\@l {
    display: none !important; } }

/* Desktop and smaller */
@media (max-width: 1599px) {
  .uk-visible\@xl {
    display: none !important; } }

/* Visibility
 ========================================================================== */
.uk-invisible {
  visibility: hidden !important; }

/* Hover
 ========================================================================== */
/*
 * Hidden
 * Can't use `display: hidden` because it's not focusable. This is accessible through keyboard.
 */
.uk-visible-toggle:not(:hover):not(.uk-hover) .uk-hidden-hover:not(:focus) {
  position: absolute !important;
  width: 0 !important;
  height: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  overflow: hidden !important; }

/*
 * Invisible
 * Can't use `visibility: hidden` because it's not focusable. This is accessible through keyboard.
 */
.uk-visible-toggle:not(:hover):not(.uk-hover) .uk-invisible-hover:not(:focus) {
  opacity: 0 !important; }

/* Touch
 ========================================================================== */
/*
 * Hide if primary pointing device has limited accuracy, e.g. a touch screen.
 * Works on mobile browsers: Safari, Chrome and Android browser
 */
@media (pointer: coarse) {
  .uk-hidden-touch {
    display: none !important; } }

/*
 * Hide if primary pointing device is accurate, e.g. mouse.
 * 1. Fallback for IE11 and Firefox, because `pointer` is not supported
 * 2. Reset if supported
 */
/* 1 */
.uk-hidden-notouch {
  display: none !important; }

@media (pointer: coarse) {
  .uk-hidden-notouch {
    display: block !important; } }

/**
 * modified version of eric meyer's reset 2.0
 * http://meyerweb.com/eric/tools/css/reset/
 */
/**
 * basic reset
 */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, main,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline; }

/**
 * HTML5 display-role reset for older browsers
 */
article, aside, details, figcaption, figure,
footer, header, menu, nav, section,
main, summary {
  display: block; }

body {
  line-height: 1; }

ol, ul {
  list-style: none; }

blockquote, q {
  quotes: none; }

blockquote:before, blockquote:after,
q:before, q:after {
  content: '';
  content: none; }

table {
  border-collapse: collapse;
  border-spacing: 0; }

/**
 * modified version of normalize.css 3.0.2
 * http://necolas.github.io/normalize.css/
 */
/**
 * responsive viewport
 */
@viewport {
  width: device-width; }

/**
 * inherit box model
 */
*,
*::before,
*::after {
  box-sizing: inherit; }

/**
 * 1. Set default font family to sans-serif.
 * 2. Prevent iOS text size adjust after orientation change, without disabling
 *    user zoom.
 */
html {
  font-family: sans-serif;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent; }

/**
 * HTML5 display definitions
 * =============================================================================
 */
/**
 * 1. Correct `inline-block` display not defined in IE 8/9.
 * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
 */
audio,
canvas,
progress,
video {
  display: inline-block;
  vertical-align: baseline; }

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */
audio:not([controls]) {
  display: none;
  height: 0; }

/**
 * Address `[hidden]` styling not present in IE 8/9/10.
 * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
 * Hide the `router-outlet` element created by Angular.
 */
[hidden],
template,
router-outlet {
  display: none !important; }

/**
 * Links
 * =============================================================================
 */
/**
 * Remove the gray background color from active links in IE 10.
 */
a {
  background-color: transparent; }

/**
 * Improve readability when focused and also mouse hovered in all browsers.
 */
a:active,
a:hover {
  outline: 0; }

/**
 * Text-level semantics
 * =============================================================================
 */
/**
 * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
 */
abbr[title] {
  border-bottom: 1px dotted;
  cursor: help; }

/**
 * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
 */
b,
strong {
  font-weight: 500; }

/**
 * 1. Address styling not present in Safari and Chrome.
 * 2. Set previously resetted italic font-style
 */
dfn,
i, em {
  font-style: italic; }

/**
 * Address styling not present in IE 8/9.
 */
mark {
  background: #ff0;
  color: #000; }

/**
 * Address inconsistent and variable font size in all browsers.
 */
small {
  font-size: 80%; }

/**
 * Prevent `sub` and `sup` affecting `line-height` in all browsers.
 */
sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative; }

sup {
  top: -0.5em; }

sub {
  bottom: -0.25em; }

/**
 * Embedded content
 * =============================================================================
 */
/**
 * Remove border when inside `a` element in IE 8/9/10.
 */
img {
  border: 0; }

/**
 * Correct overflow not hidden in IE 9/10/11.
 */
svg:not(:root) {
  overflow: hidden; }

/**
 * Grouping content
 * =============================================================================
 */
/**
 * Address differences between Firefox and other browsers.
 */
hr {
  box-sizing: content-box;
  height: 0; }

/**
 * Contain overflow in all browsers.
 */
pre {
  overflow: auto; }

/**
 * Address odd `em`-unit font size rendering in all browsers.
 */
code,
kbd,
pre,
samp {
  font-family: monospace, monospace; }

/**
 * Forms
 * =============================================================================
 */
/**
 * Known limitation: by default, Chrome and Safari on OS X allow very limited
 * styling of `select`, unless a `border` property is set.
 */
/**
 * 1. Correct color not being inherited.
 *    Known issue: affects color of disabled elements.
 * 2. Correct font properties not being inherited.
 * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
 */
button,
input,
optgroup,
select,
textarea {
  color: inherit;
  font: inherit;
  margin: 0; }

/**
 * Avoid 300ms click delay on touch devices that support the `touch-action` CSS property.
 *
 * In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11
 * DON'T remove the click delay when `<meta name="viewport" content="width=device-width">` is present.
 * However, they DO support removing the click delay via `touch-action: manipulation`.
 * See:
 * - http://v4-alpha.getbootstrap.com/content/reboot/#click-delay-optimization-for-touch
 * - http://caniuse.com/#feat=css-touch-action
 * - http://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay
 */
a,
area,
button,
[role="button"],
input,
label,
select,
summary,
textarea {
  touch-action: manipulation; }

/**
 * Address `overflow` set to `hidden` in IE 8/9/10/11.
 */
button {
  overflow: visible; }

/**
 * iOS "clickable elements" fix for role="button"
 *
 * Fixes "clickability" issue (and more generally, the firing of events such as focus as well)
 * for traditionally non-focusable elements with role="button"
 * see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
 */
[role="button"] {
  cursor: pointer; }

/**
 * Address inconsistent `text-transform` inheritance for `button` and `select`.
 * All other form control elements do not inherit `text-transform` values.
 * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
 * Correct `select` style inheritance in Firefox.
 */
button,
select {
  text-transform: none; }

/**
 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
 *    and `video` controls.
 * 2. Correct inability to style clickable `input` types in iOS.
 * 3. Improve usability and consistency of cursor style between image-type
 *    `input` and others.
 */
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button;
  cursor: pointer; }

/**
 * Re-set default cursor for disabled elements.
 */
button[disabled],
html input[disabled] {
  cursor: default; }

/**
 * Remove inner padding and border in Firefox 4+.
 */
button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0; }

/**
 * Address Firefox 4+ setting `line-height` on `input` using `!important` in
 * the UA stylesheet.
 */
input {
  line-height: normal; }

/**
 * It's recommended that you don't attempt to style these elements.
 * Firefox's implementation doesn't respect box-sizing, padding, or width.
 *
 * 1. Address box sizing set to `content-box` in IE 8/9/10.
 * 2. Remove excess padding in IE 8/9/10.
 */
input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box;
  padding: 0; }

/**
 * Fix the cursor style for Chrome's increment/decrement buttons. For certain
 * `font-size` values of the `input`, it causes the cursor style of the
 * decrement button to change from `default` to `text`.
 */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto; }

/**
 * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
 *    (include `-moz` to future-proof).
 */
input[type="search"] {
  -webkit-appearance: none; }

/**
 * Remove inner padding and search cancel button in Safari and Chrome on OS X.
 * Safari (but not Chrome) clips the cancel button when the search input has
 * padding (and `textfield` appearance).
 */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none; }

/**
 * Remove default vertical scrollbar in IE 8/9/10/11.
 */
textarea {
  overflow: auto; }

/**
 * Don't inherit the `font-weight` (applied by a rule above).
 * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
 */
optgroup {
  font-weight: bold; }

button, [type='button'], [type='reset'], [type='submit'],
.btn {
  appearance: none;
  background: #777;
  border: 0;
  border-radius: 5px;
  color: #FFF;
  cursor: pointer;
  display: inline-block;
  font-family: "Lato", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
  font-size: 110%;
  -webkit-font-smoothing: antialiased;
  font-weight: 500;
  line-height: 1;
  padding: .8rem 1.6rem;
  text-align: center;
  text-decoration: none;
  user-select: none;
  vertical-align: middle;
  white-space: nowrap; }
  button:hover, button:focus, [type='button']:hover, [type='button']:focus, [type='reset']:hover, [type='reset']:focus, [type='submit']:hover, [type='submit']:focus,
  .btn:hover,
  .btn:focus {
    color: #FFF;
    text-decoration: none; }
  button:disabled, [type='button']:disabled, [type='reset']:disabled, [type='submit']:disabled,
  .btn:disabled {
    cursor: not-allowed;
    opacity: .5; }
    button:disabled:hover, [type='button']:disabled:hover, [type='reset']:disabled:hover, [type='submit']:disabled:hover,
    .btn:disabled:hover {
      background-color: #FFF; }

.btn-primary {
  border: 2px solid #FFF;
  background-color: #92BC56;
  box-shadow: 0 11px 26px 0 rgba(0, 0, 0, 0.2); }

fieldset {
  background-color: transparent;
  border: 0;
  margin: 0;
  padding: 0; }

legend {
  font-weight: 600;
  margin: 0;
  padding: 0; }

label {
  display: block;
  margin-bottom: .5em;
  text-transform: uppercase; }

select,
textarea,
input[type="text"],
input[type="password"],
input[type="datetime"],
input[type="datetime-local"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="week"],
input[type="number"],
input[type="email"],
input[type="url"],
input[type="search"],
input[type="tel"],
input[type="color"] {
  appearance: none;
  border: 0;
  border-radius: 5px;
  display: inline-block;
  font-size: 19px;
  line-height: 1;
  padding: .5em 1em; }

textarea {
  resize: vertical; }

[type="checkbox"],
[type="radio"] {
  display: inline;
  margin-right: 0.25rem; }

[type="file"] {
  margin-bottom: 0.5rem;
  width: 100%; }

html {
  background: #757575;
  box-sizing: border-box;
  overflow-x: hidden; }

*,
*::before,
*::after {
  box-sizing: inherit; }

body {
  background: #E7E7E7;
  overflow-x: hidden; }
  body:before {
    position: fixed;
    top: 0;
    left: 0;
    background-image: radial-gradient(circle at top left, #FFF, transparent 50%);
    content: '';
    display: block;
    height: 60vh;
    width: 60vw;
    z-index: 0; }
  body:after {
    position: fixed;
    top: 0;
    right: 0;
    background-image: radial-gradient(circle at top right, rgba(0, 0, 0, 0.15), transparent 50%);
    content: '';
    display: block;
    height: 60vh;
    width: 60vw;
    z-index: 0; }

main,
footer {
  position: relative;
  z-index: 1; }

ul,
ol {
  list-style-type: none;
  margin: 0;
  padding: 0; }

dl {
  margin: 0; }

dt {
  font-weight: 600;
  margin: 0; }

dd {
  margin: 0; }

figure {
  margin: 0; }

img,
picture {
  margin: 0;
  max-width: 100%; }

table {
  border-collapse: collapse;
  margin: 0.5rem 0;
  table-layout: fixed;
  width: 100%; }

th {
  border-bottom: 1px solid #999999;
  font-weight: 600;
  padding: 0.5rem 0;
  text-align: left; }

td {
  border-bottom: 1;
  padding: 0.5rem 0; }

tr,
td,
th {
  vertical-align: middle; }

body {
  color: #777;
  font-family: "Lato", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
  font-size: 12px;
  line-height: 1.5; }
  @media (min-width: 1200px) {
    body {
      font-size: 14px; } }
  @media (min-width: 1600px) {
    body {
      font-size: 19px; } }

h1,
h2 {
  color: #414141;
  font-family: "Fjalla One", sans-serif;
  line-height: 1.3;
  margin-bottom: .6em; }

h1 {
  font-size: 3.75em; }

h2 {
  font-size: 2.75em; }

h3 {
  color: #CA2C78;
  font-size: 1.5em;
  font-weight: 700;
  margin-bottom: 1.25em; }

p {
  font-size: 1.15em; }
  @media (min-width: 1200px) {
    p {
      font-size: 1em; } }

.lead {
  font-size: 1.25em;
  font-weight: 700;
  margin-bottom: 1em; }

.grid-main {
  margin: 0 3em; }
  @media (min-width: 640px) {
    .grid-main {
      margin: 0 5em; } }
  @media (min-width: 960px) {
    .grid-main {
      display: grid;
      grid-gap: 5em;
      grid-template-areas: 'nav content';
      grid-template-columns: 14em 1fr; } }
  @media (min-width: 1200px) {
    .grid-main {
      margin: 0 6.5em; } }
  @media (min-width: 1600px) {
    .grid-main {
      margin: 0 auto;
      max-width: 1440px; } }
  .grid-main .grid-main-nav {
    grid-area: nav; }
  .grid-main .grid-main-content {
    grid-area: content; }

.grid-section {
  display: grid;
  grid-template-areas: 'media' 'content'; }
  @media (min-width: 640px) {
    .grid-section {
      grid-gap: 5em;
      grid-template-areas: 'content media';
      grid-template-columns: 1fr 39%; } }
  @media (min-width: 640px) and (orientation: landscape) {
    .grid-section {
      min-height: 100vh; } }
  .grid-section > .media {
    grid-area: media;
    justify-self: center;
    position: relative; }
    @media (min-width: 960px) {
      .grid-section > .media {
        padding-top: 13vh; } }
  .grid-section > .content {
    grid-area: content;
    position: relative; }
    @media (min-width: 960px) {
      .grid-section > .content {
        padding-top: 13vh; } }

.grid-wallet {
  align-items: stretch;
  background: url(../images/img-arrow.png) left center no-repeat;
  background-size: 82%;
  display: grid;
  grid-gap: 1.5rem;
  grid-template-rows: repeat(2, 6rem);
  margin-top: 1.5rem;
  width: 90%; }
  @media (min-width: 1200px) {
    .grid-wallet {
      grid-gap: 4rem;
      margin-top: 4rem; } }
  .grid-wallet .grid-row {
    align-items: center;
    display: grid;
    grid-gap: 1.75em;
    justify-items: center; }
    .grid-wallet .grid-row.row-1 {
      grid-template-columns: 1fr 35% 35%;
      margin: 0 1em 0 3.75em; }
      @media (min-width: 1200px) {
        .grid-wallet .grid-row.row-1 {
          margin: 0 1.5em 0 4.25em; } }
    .grid-wallet .grid-row.row-2 {
      grid-template-columns: 1fr 25% 1fr;
      margin: 0 1.75em 0 3.75em; }
      @media (min-width: 1200px) {
        .grid-wallet .grid-row.row-2 {
          margin: 0 1.75em 0 4.25em; } }
  .grid-wallet .grid-item {
    max-height: 100%; }

.grid-input-group {
  display: grid;
  grid-gap: 1em;
  grid-template-columns: 1fr; }
  @media (min-width: 640px) {
    .grid-input-group {
      grid-template-columns: 1fr auto; } }
  @media (min-width: 1200px) {
    .grid-input-group {
      width: 80%; } }

.grid-main.legal {
  margin: 0 3em; }
  @media (min-width: 640px) {
    .grid-main.legal {
      margin: 0 5em; } }
  @media (min-width: 960px) {
    .grid-main.legal {
      display: grid;
      grid-gap: 5em;
      grid-template-areas: 'nav content';
      grid-template-columns: 1fr; } }
  @media (min-width: 1200px) {
    .grid-main.legal {
      margin: 0 6.5em; } }
  @media (min-width: 1600px) {
    .grid-main.legal {
      margin: 0 auto;
      max-width: 1440px; } }
  .grid-main.legal .grid-main-nav {
    grid-area: nav; }
  .grid-main.legal .grid-main-content {
    grid-area: content; }

.list-colorbar {
  font-size: 1.333em;
  line-height: 1.3; }
  @media (min-width: 640px) {
    .list-colorbar {
      font-size: 1.1em; } }
  @media (min-width: 1200px) {
    .list-colorbar {
      font-size: 1em; } }
  @media (min-width: 1600px) {
    .list-colorbar {
      font-size: .95em;
      line-height: 1.4; } }
  .list-colorbar .list-item {
    background: rgba(255, 255, 255, 0.4);
    border-left: solid 0.333rem #CA2C78;
    margin-bottom: 1.333em;
    padding: .75em;
    padding-left: 1rem;
    padding-right: 1.333rem; }
    .list-colorbar .list-item:nth-of-type(even) {
      border-left: 0;
      border-right: solid 0.333em #92BC56;
      padding-left: 1.333rem;
      padding-right: 1rem; }

.list-icons .list-item {
  display: grid;
  grid-gap: 2em;
  grid-template-columns: 1fr 23%;
  margin-top: 3em; }
  @media (min-width: 640px) {
    .list-icons .list-item {
      grid-gap: 2.25em;
      grid-template-columns: 18% 1fr; } }
  .list-icons .list-item h3 {
    line-height: 1.2;
    margin-bottom: .5em; }
  .list-icons .list-item .media {
    padding-top: .25em;
    order: 2; }
    @media (min-width: 640px) {
      .list-icons .list-item .media {
        order: 1; } }
  .list-icons .list-item .content {
    order: 1; }
    @media (min-width: 640px) {
      .list-icons .list-item .content {
        order: 2; } }
    @media (min-width: 1200px) {
      .list-icons .list-item .content {
        font-weight: 700; } }

.nav {
  display: none; }
  @media (min-width: 960px) {
    .nav {
      display: grid;
      grid-gap: 1.5em;
      grid-template-columns: 1fr;
      grid-row: 1 / -1;
      margin-top: 13vh;
      position: fixed;
      width: 14em; } }
  .nav .logo {
    margin-bottom: 4.2rem;
    outline: 0; }
  .nav .nav-item {
    color: #777;
    font-size: 1.15em;
    font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
    font-weight: 400;
    line-height: 1;
    text-decoration: none;
    text-transform: uppercase;
    outline: 0;
    position: relative; }
    .nav .nav-item:before {
      position: absolute;
      top: 1px;
      bottom: 1px;
      left: -0.9em;
      content: '';
      display: block;
      border-left: solid 0.25em #CA2C78;
      opacity: 0;
      transition: transform 0.1s ease-out;
      transform: translateX(6px) scale(0.5); }
    .nav .nav-item.is-active {
      font-weight: 600; }
      .nav .nav-item.is-active:before {
        opacity: 1;
        transform: translateX(0) scale(1); }

#introduction {
  padding-top: 2.5rem;
  grid-gap: 0;
  grid-template-columns: 1fr; }
  @media (min-width: 640px) {
    #introduction {
      padding-top: 3.5rem; } }
  @media (min-width: 960px) {
    #introduction {
      grid-gap: 5em;
      grid-template-columns: 1fr 1fr;
      padding-top: 0; } }
  #introduction .btn {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 5;
    margin-top: 13vh; }
    @media (min-width: 960px) {
      #introduction .btn {
        margin-top: 6.5vh; } }
  @media (min-width: 960px) {
    #introduction .content {
      padding-top: 13vh; } }
  #introduction .content .logo {
    margin-bottom: 5em;
    max-width: 270px;
    width: 65%; }
  #introduction .media {
    padding-top: 16rem; }

#connectme {
  margin-top: 4rem; }
  @media (min-width: 640px) {
    #connectme {
      grid-template-areas: 'media content';
      grid-template-columns: 1fr 55%; } }
  @media (min-width: 960px) {
    #connectme {
      grid-template-columns: 1fr 65%;
      grid-gap: 4em;
      margin: 0; } }
  @media (min-width: 1200px) {
    #connectme {
      grid-template-columns: 1fr 65%; } }
  @media (min-width: 1600px) {
    #connectme {
      grid-template-columns: 1fr 62%; } }
  #connectme .media {
    padding: 0 1rem 1rem; }
    @media (min-width: 640px) {
      #connectme .media {
        padding: 0; } }
    @media (min-width: 960px) {
      #connectme .media {
        padding-top: 13vh; } }
  #connectme h2 {
    margin-top: 1em;
    margin-bottom: 0.25em; }
    @media (min-width: 640px) {
      #connectme h2 {
        margin-top: 0; } }

.eula,
.privacy {
  padding-top: 6rem;
  padding-bottom: 2rem; }
  .eula h3,
  .privacy h3 {
    color: #333;
    font-size: 1.125rem;
    margin: 0; }
  .eula p,
  .privacy p {
    margin-bottom: 1.5rem; }
    .eula p.uppercase,
    .privacy p.uppercase {
      text-transform: uppercase;
      font-weight: bold; }

span.underline {
  border-bottom: 1px solid #555; }

ol {
  list-style-type: lower-alpha;
  margin-left: 2rem; }

#what {
  margin-top: 4rem; }
  @media (min-width: 640px) {
    #what {
      grid-gap: 0;
      grid-template-columns: 1fr; } }
  @media (min-width: 960px) {
    #what {
      grid-gap: 5rem;
      grid-template-columns: 1fr 40%;
      margin: 0; } }
  #what h2 {
    margin-top: 1em; }
    @media (min-width: 640px) {
      #what h2 {
        margin-top: 0; } }
  #what .media {
    min-height: 24rem;
    position: relative; }
    @media (min-width: 640px) {
      #what .media {
        display: none; } }
    @media (min-width: 960px) {
      #what .media {
        display: block;
        order: 2; } }
    #what .media .img-1 {
      position: relative;
      top: 0;
      left: 5em;
      width: 70%;
      z-index: 3; }
    #what .media .img-2 {
      position: absolute;
      top: 10em;
      left: 0;
      width: 85%;
      z-index: 2; }
      @media (min-width: 960px) {
        #what .media .img-2 {
          top: 31vh; } }
    #what .media .img-3 {
      position: absolute;
      top: 28em;
      left: 0;
      z-index: 1; }
      @media (min-width: 960px) {
        #what .media .img-3 {
          top: 70vh; } }

#trust {
  grid-gap: 0;
  grid-template-columns: 1fr;
  margin-top: 3rem; }
  @media (min-width: 960px) {
    #trust {
      margin: 0; } }
  @media (min-width: 640px) {
    #trust > .content {
      width: 75%; } }
  @media (min-width: 1200px) {
    #trust > .content {
      width: 58%; } }

#beta {
  padding-bottom: 3rem; }
  @media (min-width: 640px) {
    #beta {
      margin-top: 3rem;
      grid-template-columns: 1fr 33%; } }
  @media (min-width: 960px) {
    #beta {
      margin: 0;
      min-height: calc(100vh - 25vh); } }
  @media (min-width: 640px) {
    #beta .beta-form {
      margin-top: 4em; } }
  @media (min-width: 1200px) {
    #beta .beta-form {
      margin-top: 6em; } }
  #beta .beta-form .beta-input {
    border-radius: 0;
    border-bottom: solid 3px #d8d8d8; }
  #beta .media {
    padding: 5em 0 2em 3em; }
    @media (min-width: 640px) {
      #beta .media {
        order: 2;
        padding: 4em 0 0; } }
    @media (min-width: 960px) {
      #beta .media {
        padding-top: 13vh; } }

#footer {
  background: #757575;
  color: rgba(255, 255, 255, 0.9);
  display: flex;
  font-size: .85em;
  font-weight: 300;
  line-height: 1.4;
  min-height: 25vh;
  padding: 2.4rem; }
  @media (min-width: 640px) {
    #footer {
      padding: 2rem 0; } }
  @media (min-width: 960px) {
    #footer {
      padding: 0; } }
  #footer a {
    color: rgba(255, 255, 255, 0.9);
    text-decoration: underline; }
  #footer .container {
    align-content: center;
    display: grid;
    grid-gap: 5rem;
    width: 100%; }
    @media (min-width: 640px) {
      #footer .container {
        grid-template-columns: 1fr auto;
        padding: 0 6em; } }
    @media (min-width: 1600px) {
      #footer .container {
        margin: 0 auto;
        max-width: 1440px;
        padding: 0; } }
    #footer .container .logo-title {
      color: rgba(255, 255, 255, 0.9); }
    #footer .container .logo {
      max-width: 40%; }
      @media (min-width: 640px) {
        #footer .container .logo {
          max-width: 150px; } }
      #footer .container .logo.logo-evernym {
        margin-bottom: 2rem;
        margin-top: 1em; }
      #footer .container .logo.logo-sovrin {
        margin-bottom: 1.5em;
        margin-top: .3em; }
      #footer .container .logo.logo-hyperledger-indy {
        margin-top: .75em; }


<|start_filename|>app/components/custom-date/custom-date.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Text } from 'react-native'
import moment from 'moment'

import { CustomText } from '../index'
import type { CustomDateProps } from './type-custom-date'

export default class CustomDate extends PureComponent<CustomDateProps, void> {
  render() {
    const { format = 'MM/DD/YYYY | h:mm A', children } = this.props
    const customDate = moment(children).format(format)
    return <CustomText {...this.props}>{customDate}</CustomText>
  }
}


<|start_filename|>app/components/AvatarsPair.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Image, StyleSheet, Platform } from 'react-native'
import Modal from 'react-native-modal'
import { Avatar, CustomView, UserAvatar } from '../components'
import { color, OFFSET_1X, OFFSET_2X, isiPhone5 } from '../common/styles'
import avatarStyle from '../components/avatar/avatar-style'
import type { ImageSource } from '../common/type-common'

// TODO:KS Add types and tests for this component
// change the name of the file to match our convention of snake-case
// move this component to it's own folder, add type, tests, etc.
export default class AvatarsPair extends PureComponent<*, void> {
  renderAvatarWithSource = (avatarSource: ImageSource | number) => (
    <Avatar medium src={avatarSource} testID={`avatars-pair-avatars-invitee`} />
  )

  render() {
    const { middleImage, middleImageStyle, avatarRight, testID } = this.props
    return (
      <CustomView
        row
        vCenter
        spaceBetween
        style={[styles.avatarsContainer]}
        testID={`${testID}-text-avatars-container`}
      >
        <UserAvatar>{this.renderAvatarWithSource}</UserAvatar>
        {middleImage && (
          <Image
            style={[styles.checkMark, middleImageStyle && middleImageStyle]}
            source={middleImage}
            testID={`${testID}-check-mark`}
            accessible={true}
            accessibilityLabel={`${testID}-check-mark`}
          />
        )}
        {avatarRight && (
          <Avatar
            medium
            src={avatarRight}
            testID={`${testID}-text-avatars-inviter`}
          />
        )}
      </CustomView>
    )
  }
}

const styles = StyleSheet.create({
  avatarsContainer: {
    marginVertical: OFFSET_1X,
    marginHorizontal: isiPhone5 ? OFFSET_1X : OFFSET_2X,
    ...Platform.select({
      android: {
        paddingVertical: OFFSET_1X / 2,
      },
    }),
  },
  checkMark: {
    width: 30,
    height: 22,
  },
})


<|start_filename|>app/backup/backup-error.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { Image, StyleSheet, Dimensions } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import {
  Container,
  CustomView,
  CustomText,
  CustomButton,
  Icon,
  CustomHeader,
} from '../components'
import {
  isBiggerThanShortDevice,
  grey,
  venetianRed,
  white,
} from '../common/styles/constant'
import { updateStatusBarTheme } from '../store/connections-store'
import { generateBackupFile } from '../backup/backup-store'
import { backupErrorRoute, exportBackupFileRoute } from '../common'
import type { BackupErrorProps } from './type-backup'
import headerStyles from './styles'
import {
  BACKUP_ERROR_BACK_TEST_ID,
  BACKUP_ERROR_CLOSE_TEST_ID,
} from './backup-constants'

const backImage = require('../images/icon_backArrow_white.png')
const closeImage = require('../images/iconClose.png')
export class BackupErrorScreen extends PureComponent<BackupErrorProps, void> {
  static navigationOptions = ({ navigation: { goBack, navigate, state } }) => ({
    header: (
      <CustomHeader backgroundColor={venetianRed} largeHeader flatHeader>
        <CustomView style={[headerStyles.headerSpacer]}>
          <Icon
            medium
            onPress={() => goBack(null)}
            testID={BACKUP_ERROR_BACK_TEST_ID}
            iconStyle={[headerStyles.headerBackIcon]}
            src={backImage}
          />
        </CustomView>

        <CustomView style={[headerStyles.headerSpacer]}>
          <Icon
            medium
            onPress={() => navigate(state.params.initialRoute)}
            testID={BACKUP_ERROR_CLOSE_TEST_ID}
            iconStyle={[headerStyles.headerIcon]}
            src={closeImage}
          />
        </CustomView>
      </CustomHeader>
    ),
    gesturesEnabled: true,
  })

  tryAgain = () => {
    const { initialRoute } = this.props.navigation.state.params
    this.props.generateBackupFile()
    this.props.navigation.navigate(exportBackupFileRoute, {
      initialRoute,
    })
  }

  render() {
    return (
      <Container
        safeArea
        testID={'restore-container'}
        style={[styles.backupErrorContainer]}
      >
        <Image
          source={require('../images/transparentBands2.png')}
          style={[styles.backgroundWaveImage]}
        />
        <Container testID={'restore-innercontainer'}>
          <CustomView center>
            <Image
              source={require('../images/alertRed.png')}
              style={[styles.errorImageContainer]}
            />
          </CustomView>

          <CustomView center pad>
            <CustomText
              transparentBg
              style={[styles.errorText]}
              center
              medium
              h4a
              center
            >
              There was a problem exporting your Connect.Me backup file. Please
              try again.
            </CustomText>
          </CustomView>
        </Container>
        <Container bottom pad>
          <CustomView pad>
            <CustomButton
              large={isBiggerThanShortDevice ? true : false}
              style={[styles.customButton, styles.buttonShadow]}
              title={'Try Again'}
              onPress={this.tryAgain}
              testID={'try-again'}
              customColor={{
                color: venetianRed,
                fontWeight: '600',
              }}
            />
          </CustomView>
        </Container>
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  backupErrorContainer: {
    backgroundColor: venetianRed,
  },
  backgroundWaveImage: {
    position: 'absolute',
    top: isBiggerThanShortDevice ? '30%' : '20%',
    left: 0,
    right: 0,
    resizeMode: 'stretch',
    width: '100%',
  },
  customButton: {
    width: '100%',
    height: isBiggerThanShortDevice ? 57 : 43,
    borderRadius: 5,
    marginTop: 10,
  },
  buttonShadow: {
    shadowColor: grey,
    shadowOffset: {
      width: 0,
      height: 5,
    },
    shadowRadius: 5,
    shadowOpacity: 0.3,
    elevation: 4,
  },
  errorImageContainer: {
    marginTop: '5%',
    zIndex: -1,
  },
  errorText: {
    color: white,
  },
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      updateStatusBarTheme,
      generateBackupFile,
    },
    dispatch
  )

export default createStackNavigator({
  [backupErrorRoute]: {
    screen: connect(null, mapDispatchToProps)(BackupErrorScreen),
  },
})


<|start_filename|>app/components/footer-actions/type-footer-actions.js<|end_filename|>
// @flow
import type { ReactNavigation } from '../../common/type-common'

export type FooterActionsProps = {
  disableAccept?: boolean,
  logoUrl?: ?string,
  onAccept?: () => void,
  onDecline?: () => void,
  denyTitle?: string,
  acceptTitle?: string,
  testID: string,
  hidePrimary?: boolean,
  activeConnectionThemePrimary?: string,
  useColorPicker?: boolean,
  accessible: boolean,
  accessibilityLabel: string,
  disableDeny?: boolean,
} & ReactNavigation


<|start_filename|>index.js<|end_filename|>
// @flow
import './app/app'


<|start_filename|>app/deep-link/index.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import branch from 'react-native-branch'
import { deepLinkData, deepLinkEmpty, deepLinkError } from './deep-link-store'
import type { DeepLinkProps, DeepLinkBundle } from './type-deep-link'

export class DeepLink extends PureComponent<DeepLinkProps, void> {
  onDeepLinkData = (bundle: DeepLinkBundle) => {
    if (bundle.error) {
      this.props.deepLinkError(bundle.error)
    } else if (bundle.params) {
      if (bundle.params['+clicked_branch_link'] === true) {
        // update store with deep link params
        this.props.deepLinkData(bundle.params.t)
      } else {
        // update store that deep link was not clicked
        Object.keys(this.props.tokens).length === 0 &&
          this.props.deepLinkEmpty()
      }
    } else {
      Object.keys(this.props.tokens).length === 0 && this.props.deepLinkEmpty()
    }
  }

  componentDidMount() {
    branch.subscribe(this.onDeepLinkData)
  }

  render() {
    return null
  }
}

const mapStateToProps = state => ({
  tokens: state.deepLink.tokens,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      deepLinkData,
      deepLinkEmpty,
      deepLinkError,
    },
    dispatch
  )

const DeepLinkConnected = connect(mapStateToProps, mapDispatchToProps)(DeepLink)

export default DeepLinkConnected


<|start_filename|>connectMeUITest/src/test/java/App4NegativeTest.java<|end_filename|>

package test.java;

import io.appium.java_client.AppiumDriver;
import org.testng.annotations.*;
import appModules.AppUtlis;
import funcModules.ConnectionModules;
import funcModules.LockModules;
import utility.*;
@Test
public class App4NegativeTest {

	public  AppiumDriver driver;

	AppUtlis AppUtlisObj=new AppUtlis();
	LockModules LockModlesObj=new LockModules();
	ConnectionModules ConnectionModulesObj =new ConnectionModules();


	@BeforeClass //testng 
	public void BeforeClass() throws Exception {
		
    	Thread.sleep(20000);
		driver = Setup.ConfigureDriver("App");

	}
	
	
	
    @Test (groups = {"Regression"})
	public void App1PinCodeInvalidSetup()throws Exception{
		AppUtlisObj.CheckSkip();
		LockModlesObj.InvalidPinCodeSetup(driver);
		AppUtlis.Success=true;		

	   }
    
    @Test (groups = {"Regression"})
	public void App2PinCodevalidSetup()throws Exception{
		
		AppUtlisObj.CheckSkip();
		LockModlesObj.PinCodeSetup(driver);
		AppUtlis.Success=true;		
	
	   }
	

	
    @Test (groups = {"Regression"})
	public void App3ProvisoningDeny()throws Exception{
		
		AppUtlisObj.CheckSkip();
		ConnectionModulesObj.AppProvisioningRequest("Deny",driver);
		AppUtlis.Success=true;		

		
	}
    
    
    @Test (groups = {"Regression"})
	public void App4EnterInvalidPincode()throws Exception{
    	driver.quit();
		driver = Setup.ConfigureDriver("App");
		AppUtlisObj.enterPincodeReverse(driver);
		AppUtlis.Success=true;		

		
	}

    @AfterClass
	public void afterClass() {
		 driver.removeApp("com.evernym.connectme.callcenter");
		 driver.quit();
		 System.out.println("Cleaning up Completed");

	}
}

<|start_filename|>e2e/claim-offer.spec.js<|end_filename|>
describe('Claim Offer', () => {
  it('Received Claim Offer and Accept', async () => {
    // verify Claim Offer popup shows up
    // verify close button, attributes, ignore, and accept button is present
    // tap on Accept
    // verify Continue popup shows up
    // tap on continue
    // verify user is redirected to Dashboard screen
    // tap on Connection bubble from which Claim Offer came
    // verify Connection History popup shows up
    // verify delete connection, close popup, connection logo, and connection history are present
    // verify claim offer "RECEIVED" entry is present
    // tap on "RECEIVED"
    // verify History Details screen shows up
    // verify attributes is present
    // verify back button is present
    // tap on back button
    // user should come back to connection history popup
    // tap close button
    // user should back to dashboard screen
  })

  it('Received Claim Offer and Ignore', async () => {
    // verify Claim Offer popup shows up
    // verify close button, attributes, ignore, and accept button is present
    // tap on Ignore
    // verify user is redirected to Dashboard screen
  })
})


<|start_filename|>app/components/banner/banner-constants.js<|end_filename|>
//  @flow

export const IMAGE_WIDTH = 29
export const IMAGE_HEIGHT = 25
export const BANNER_HEIGHT = 64
export const BACKUP_BANNER_TEST_ID = 'wallet-backup-banner-label'
export const STORAGE_KEY_SHOW_BANNER = 'STORAGE_KEY_SHOW_BANNER'


<|start_filename|>app/authentication/connection-success-modal.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, Image, StyleSheet } from 'react-native'

import { CustomModal, AvatarsPair, CustomText } from '../components'
import { color, OFFSET_1X, OFFSET_2X } from '../common/styles'
import { connectionRoute } from '../common'
import { getConnectionLogo } from '../store/connections-store'

// TODO:KS Move these props to type-* file
// we will move this file as well to components directory
// and create tests, type and component in separate folder
// Trying to avoid as many conflicts as possible
export type ConnectionSuccessModalProps = {
  name: string,
  logoUrl: ?string,
  showConnectionSuccessModal: (boolean, string) => void,
  isModalVisible: boolean,
}

export default class ConnectionSuccessModal extends PureComponent<
  ConnectionSuccessModalProps,
  void
> {
  render() {
    const {
      name = 'Sovrin',
      logoUrl,
      showConnectionSuccessModal,
      isModalVisible,
    } = this.props
    const connectionAvatar = getConnectionLogo(logoUrl)

    return (
      <CustomModal
        onPress={() => showConnectionSuccessModal(false, connectionRoute)}
        buttonText="Continue"
        testID={'invitation'}
        isVisible={isModalVisible}
      >
        <AvatarsPair
          middleImage={require('../images/checkMark.png')}
          avatarRight={connectionAvatar}
          testID={'invitation'}
        />
        <CustomText
          bg="tertiary"
          h5
          tertiary
          demiBold
          center
          style={[styles.message]}
          transparentBg
          testID={`invitation-message`}
        >
          {`You are now connected to ${name}!`}
        </CustomText>
      </CustomModal>
    )
  }
}

const styles = StyleSheet.create({
  message: {
    paddingTop: OFFSET_1X,
    marginBottom: OFFSET_1X,
    marginHorizontal: OFFSET_1X / 2,
  },
})


<|start_filename|>connectMeUITest/src/utility/Setup.java<|end_filename|>
package utility;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.ios.IOSDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.net.URL;
import java.util.concurrent.TimeUnit;

/**
 * Created by ankurmishra on 6/22/17.
 */

public class Setup {

	public static AppiumDriver driver = null;

	public static AppiumDriver ConfigureDriver(String DeviceType) throws Exception {


		try {

			DesiredCapabilities capabilities = new DesiredCapabilities();

			if (DeviceType == "App") {
				capabilities.setCapability("automationName", "XCUITest");
				capabilities.setCapability("platformVersion", "10.3");
				capabilities.setCapability("platformName", "iOS");
				capabilities.setCapability("useNewWDA", "true");
				capabilities.setCapability("bundleId", "com.evernym.connectme.callcenter");
				capabilities.setCapability("deviceName", "Ankur's iPhone");//device name
				capabilities.setCapability("udid", "42d9657d87b56203d1c4c5eb22fde827ca2c0090");//udid of device
				capabilities.setCapability("xcodeOrgId", "ES8QU3D2A4");
				capabilities.setCapability("xcodeSigningId", "iPhone Developer");
				driver = new IOSDriver(new URL("http://172.16.31.10:4723/wd/hub"), capabilities);
				/*driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"),//if some one wants to run locally
			                capabilities);	/*
			                			
			 * We initialize the Appium driver that will connect us to the ios
			 * device with the capabilities that we have just set. The URL we
			 * are providing is telling Appium we
			 * http://172.16.31.10:4723/wd/hub
			 * 
			 * are going to run the test on Real ios Device lets say iphone 6s.
			 */

			driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
			// Setting DefauLt time out to 60 seconds
			System.out.println("Mobile application launched successfully");


		}
			else
			{
				capabilities.setCapability("platformVersion", "10.3");
				capabilities.setCapability("platformName", "iOS");
				capabilities.setCapability("useNewWDA", "true");
				capabilities.setCapability("deviceName", "Ankur's iPhone");//device name
				capabilities.setCapability("udid", "42d9657d87b56203d1c4c5eb22fde827ca2c0090");//udid of device
				capabilities.setCapability("browserName", "Safari");
				driver = new IOSDriver(new URL("http://172.16.31.10:4723/wd/hub"), capabilities);
             	/*driver = new IOSDriver(new URL("http://127.0.0.1:4723/wd/hub"),
			                capabilities);	/*for local test
			 * We initialize the Appium driver that will connect us to the ios
			 * device with the capabilities that we have just set. The URL we
			 * are providing is telling Appium we
			 * http://172.16.31.10:4723/wd/hub
			 * 
			 * are going to run the test on Real ios Device lets say iphone 6s.
			 */

			driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
			// Setting DefauLt time out to 60 seconds
			System.out.println("Safari browser launched successfully");

				
				
			}
		}	

		catch (Exception e)

		{

			System.out.println("Class Setup | Method OpenBrowser | Exception desc : " + e.getMessage());

		}

		return driver;

	}

}


<|start_filename|>app/lock/lock-enter-fingerprint.js<|end_filename|>
//@flow
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { TouchId } from '../components/touch-id/touch-id'
import { Container, CustomText } from '../components'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { captureError } from '../services/error/error-handler'
import { homeRoute, lockEnterPinRoute } from '../common'
import { unlockApp, clearPendingRedirect } from './lock-store'
import type { Store } from '../store/type-store'
import { UNLOCKING_APP_WAIT_MESSAGE } from '../common/message-constants'
import type {
  LockEnterFingerProps,
  LockEnterFingerState,
  PendingRedirection,
} from './type-lock'
import { AllowedFallbackToucheIDErrors } from './type-lock'

export class LockEnterFingerprint extends PureComponent<
  LockEnterFingerProps,
  LockEnterFingerState
> {
  state = {
    authenticationSuccess: false,
  }

  componentWillReceiveProps(nextProps: LockEnterFingerProps) {
    //if fetching Invitation prop has changed and its fetched then only check for authentication
    if (
      this.props.isFetchingInvitation !== nextProps.isFetchingInvitation &&
      nextProps.isFetchingInvitation === false
    ) {
      if (this.state.authenticationSuccess) {
        this.onAuthenticationSuccess(nextProps.pendingRedirection)
      }
    }
  }

  onAuthenticationSuccess = (pendingRedirection: Array<PendingRedirection>) => {
    //this method will be called in fingerprint authentication screen
    //or any where in app if there is a invitation received.
    if (pendingRedirection) {
      pendingRedirection.map(pendingRedirection => {
        this.props.navigation.navigate(
          pendingRedirection.routeName,
          pendingRedirection.params
        )
      })
      this.props.clearPendingRedirect()
    } else if (this.props.isAppLocked === true) {
      // * if app is unlocked and invitation is fetched , with out this condition we are redirecting user to home screen from invitation screen.
      // * this condition will avoid redirecting user to home screen if app is already unlocked
      this.props.navigation.navigate(homeRoute)
    }
    this.props.unlockApp()
  }

  touchIdHandler = () => {
    TouchId.isSupported()
      .then(success => {
        TouchId.authenticate('', this.touchIdHandler)
          .then(success => {
            this.setState({ authenticationSuccess: true })
            if (this.props.isFetchingInvitation === false) {
              this.onAuthenticationSuccess(this.props.pendingRedirection)
            }
          })
          .catch(error => {
            captureError(error)
            if (AllowedFallbackToucheIDErrors.indexOf(error.name) >= 0) {
              this.props.navigation.navigate(lockEnterPinRoute)
            }
          })
      })
      .catch(error => {
        captureError(error)
        if (AllowedFallbackToucheIDErrors.indexOf(error.name) >= 0) {
          this.props.navigation.navigate(lockEnterPinRoute)
        }
      })
  }

  componentDidMount() {
    this.touchIdHandler()
  }

  render() {
    const { isFetchingInvitation } = this.props
    const message =
      isFetchingInvitation && this.state.authenticationSuccess
        ? UNLOCKING_APP_WAIT_MESSAGE
        : ''

    if (isFetchingInvitation) {
      return (
        <Container center>
          <CustomText bg="tertiary" h5 tertiary demiBold center transparentBg>
            {message}
          </CustomText>
        </Container>
      )
    } else {
      return <Container />
    }
  }
}

const mapStateToProps = (state: Store) => ({
  pendingRedirection: state.lock.pendingRedirection,
  pendingRedirectionParams: state.lock.pendingRedirectionParams || {},
  isFetchingInvitation: Object.keys(state.smsPendingInvitation).some(
    smsToken =>
      state.smsPendingInvitation[smsToken] &&
      state.smsPendingInvitation[smsToken].isFetching === true
  ),
  isAppLocked: state.lock.isAppLocked,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      clearPendingRedirect,
      unlockApp,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(
  LockEnterFingerprint
)


<|start_filename|>app/app.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Provider } from 'react-redux'
import {
  AppRegistry,
  StatusBar,
  BackHandler,
  ToastAndroid,
  Platform,
} from 'react-native'
import store from './store'
import { ROUTE_UPDATE } from './store/route-store'
import { getStatusBarTheme } from './store/store-selector'
import { Container } from './components'
import { PushNotification } from './push-notification'
import DeepLink from './deep-link'
import { barStyleDark, whiteSmokeSecondary } from './common/styles/constant'
import ConnectMeAppNavigator from './navigator'
import {
  qrCodeScannerTabRoute,
  homeRoute,
  genRecoveryPhraseRoute,
  backupCompleteRoute,
  lockPinSetupHomeRoute,
  settingsTabRoute,
  settingsRoute,
  lockSetupSuccessRoute,
  invitationRoute,
  lockEnterPinRoute,
  homeTabRoute,
  splashScreenRoute,
  eulaRoute,
  lockSelectionRoute,
  lockAuthorizationHomeRoute,
  restoreRoute,
  restoreWaitRoute,
  expiredTokenRoute,
} from './common'
import { NavigationActions } from 'react-navigation'
import type { AppState } from './type-app'
import { exitAppAndroid } from './bridge/react-native-cxs/RNCxs'
import AppStatus from './app-status/app-status'
import { setupFeedback } from './feedback'
import Offline from './offline/offline'

const backButtonDisableRoutes = [
  lockEnterPinRoute,
  homeTabRoute,
  homeRoute,
  splashScreenRoute,
  settingsRoute,
  qrCodeScannerTabRoute,
  invitationRoute,
  lockSetupSuccessRoute,
  eulaRoute,
  lockSelectionRoute,
  lockPinSetupHomeRoute,
  lockAuthorizationHomeRoute,
  genRecoveryPhraseRoute,
  backupCompleteRoute,
  restoreRoute,
  restoreWaitRoute,
  expiredTokenRoute,
]

const backButtonExitRoutes = [
  homeRoute,
  settingsRoute,
  qrCodeScannerTabRoute,
  eulaRoute,
  lockSelectionRoute,
]

const backButtonConditionalRoutes = [
  lockPinSetupHomeRoute,
  lockAuthorizationHomeRoute,
]

class ConnectMeApp extends PureComponent<void, AppState> {
  currentRouteKey: string = ''
  currentRoute: string = ''
  navigatorRef = null
  currentRouteParams = null
  exitTimeout: number = 0

  componentDidMount() {
    if (Platform.OS === 'android') {
      BackHandler.addEventListener(
        'hardwareBackPress',
        this.handleBackButtonClick
      )
    }
    // components that are mounted inside of the app can also
    // change status bar style and it is getting overridden
    // so we are setting status bar style again after component is mounted
    StatusBar.setBarStyle(barStyleDark, true)
    if (Platform.OS === 'android') {
      StatusBar.setBackgroundColor(whiteSmokeSecondary)
    }
  }

  componentWillUnmount() {
    if (Platform.OS === 'android') {
      BackHandler.removeEventListener(
        'hardwareBackPress',
        this.handleBackButtonClick
      )
    }
  }

  handleBackButtonClick = () => {
    if (this.currentRouteKey !== '' && this.currentRoute !== '') {
      if (backButtonDisableRoutes.indexOf(this.currentRoute) < 0) {
        return false
      }

      if (backButtonConditionalRoutes.indexOf(this.currentRoute) >= 0) {
        let navigateAction = null
        switch (this.currentRoute) {
          case lockPinSetupHomeRoute:
            this.currentRouteParams &&
            this.currentRouteParams.existingPin === true
              ? (navigateAction = NavigationActions.navigate({
                  routeName: settingsTabRoute,
                }))
              : (navigateAction = NavigationActions.navigate({
                  routeName: lockSelectionRoute,
                }))
            this.navigatorRef && this.navigatorRef.dispatch(navigateAction)
            return true
          case lockAuthorizationHomeRoute:
            this.currentRouteParams &&
              this.currentRouteParams.onAvoid &&
              this.currentRouteParams.onAvoid()
            return false
        }
      }

      if (backButtonExitRoutes.indexOf(this.currentRoute) >= 0) {
        this.onBackPressExit()
      }
    }
    return true
  }

  onBackPressExit() {
    if (this.exitTimeout && this.exitTimeout + 2000 >= Date.now()) {
      exitAppAndroid()
    }
    this.exitTimeout = Date.now()
    ToastAndroid.show('Press again to exit!', ToastAndroid.SHORT)
  }

  // gets the current screen from navigation state
  getCurrentRoute = navigationState => {
    const route = navigationState.routes[navigationState.index]
    // dive into nested navigators
    if (route.routes) {
      return this.getCurrentRoute(route)
    }

    return route
  }

  navigationChangeHandler = (previousState, currentState) => {
    if (currentState) {
      const { routeName, key, params } = this.getCurrentRoute(currentState)
      const currentScreen = routeName

      this.currentRoute = routeName
      this.currentRouteKey = key
      this.currentRouteParams = params

      store.dispatch({
        type: ROUTE_UPDATE,
        currentScreen,
      })
    }
  }

  navigateToRoute = (routeName, params = {}) => {
    const navigateAction = NavigationActions.navigate({
      routeName,
      params,
    })
    this.navigatorRef && this.navigatorRef.dispatch(navigateAction)
  }

  render() {
    return (
      <Provider store={store}>
        <Container>
          <StatusBar
            backgroundColor={whiteSmokeSecondary}
            barStyle={barStyleDark}
          />
          <PushNotification navigateToRoute={this.navigateToRoute} />
          <DeepLink />
          <AppStatus />
          <ConnectMeAppNavigator
            ref={navigatorRef => (this.navigatorRef = navigatorRef)}
            onNavigationStateChange={this.navigationChangeHandler}
          />
          <Offline overlay />
        </Container>
      </Provider>
    )
  }
}

AppRegistry.registerComponent('ConnectMe', () => ConnectMeApp)


<|start_filename|>app/authentication/type-splash-screen.js<|end_filename|>
// @flow

import type { ReactNavigation } from '../common/type-common'
import type { ConfigStore } from '../store/type-config-store'
import type { DeepLinkStore } from '../deep-link/type-deep-link'
import type { SMSPendingInvitationStore } from '../sms-pending-invitation/type-sms-pending-invitation'
import type { LockStore, PendingRedirection } from '../lock/type-lock'
import type { EulaStore } from '../eula/type-eula'

export type SplashScreenProps = {
  eula: EulaStore,
  isInitialized: boolean,
  deepLink: DeepLinkStore,
  smsPendingInvitation: SMSPendingInvitationStore,
  lock: LockStore,
  getSmsPendingInvitation: (token: string) => void,
  addPendingRedirection: (
    pendingRedirection: Array<?PendingRedirection>
  ) => void,
  safeToDownloadSmsInvitation: () => void,
  deepLinkProcessed: (data: string) => void,
} & ReactNavigation


<|start_filename|>__mocks__/view-mock.js<|end_filename|>
// @flow
import React from 'react'
import { View } from 'react-native'

class MockView extends React.Component<any, void> {
  render() {
    return <View>{this.props.children}</View>
  }
}

export default MockView


<|start_filename|>connectMeUITest/src/funcModules/AuthRequestModules.java<|end_filename|>
package funcModules;


import appModules.AppUtlis;
import appModules.LibIndy;
import appModules.RestApi;
import io.appium.java_client.AppiumDriver;
import pageObjects.ConnectionDetailPage;

public class AuthRequestModules {
	
	AppUtlis appUtlisObj=new AppUtlis();
	RestApi restApiObj=new RestApi();
	
	public void AuthRequest(AppiumDriver driver,String Env) throws Exception
	{
		
		restApiObj.post("");
		System.out.println("Notification is send on phone");
		appUtlisObj.RequestProvisioning(driver,"Accept");
	    ConnectionDetailPage.Cross_Button(driver).click();
				
		
	}

	public void AppProvisioningDeny(AppiumDriver driver) throws Exception
	{
		appUtlisObj.RequestProvisioning(driver,"Deny");
	    driver.switchTo().alert().accept();
	}

}


<|start_filename|>app/backup/backup-store.js<|end_filename|>
// @flow

import {
  put,
  takeLatest,
  call,
  all,
  select,
  fork,
  take,
  race,
} from 'redux-saga/effects'
import { delay } from 'redux-saga'
import { zip } from 'react-native-zip-archive'
import {
  GENERATE_RECOVERY_PHRASE_SUCCESS,
  GENERATE_BACKUP_FILE_SUCCESS,
  GENERATE_BACKUP_FILE_FAILURE,
  EXPORT_BACKUP_SUCCESS,
  EXPORT_BACKUP_FAILURE,
  BACKUP_COMPLETE,
  BACKUP_STORE_STATUS,
  BACKUP_WALLET_FAIL,
  PROMPT_WALLET_BACKUP_BANNER,
  GENERATE_RECOVERY_PHRASE_FAILURE,
  GENERATE_RECOVERY_PHRASE_LOADING,
  GENERATE_BACKUP_FILE_LOADING,
  PREPARE_BACKUP_LOADING,
  PREPARE_BACKUP_SUCCESS,
  PREPARE_BACKUP_FAILURE,
  EXPORT_BACKUP_LOADING,
  ERROR_EXPORT_BACKUP,
  ERROR_GENERATE_RECOVERY_PHRASE,
  ERROR_GENERATE_BACKUP_FILE,
  ERROR_HYDRATING_BACKUP,
  HYDRATE_BACKUP,
  HYDRATE_BACKUP_FAILURE,
  EXPORT_BACKUP_NO_SHARE,
  WALLET_FILE_NAME,
  PREPARE_BACK_IDLE,
} from './type-backup'
import type {
  PromptBackupBannerAction,
  BackupStore,
  BackupStoreStatus,
  BackupStoreAction,
  Passphrase,
  PrepareBackupLoadingAction,
  ExportBackupLoadingAction,
  GenerateRecoveryPhraseLoadingAction,
  GenerateBackupFileLoadingAction,
  PrepareBackupStatus,
} from './type-backup'
import RNFetchBlob from 'react-native-fetch-blob'
import { Platform } from 'react-native'
import Share from 'react-native-share'
import type { Saga } from 'redux-saga'
import {
  secureSet,
  secureGet,
  secureGetAll,
  secureDelete,
  safeSet,
  safeGet,
  walletSet,
  walletGet,
} from '../services/storage'
import type { AgencyPoolConfig } from '../store/type-config-store'
import type { CustomError } from '../common/type-common'
import {
  LAST_SUCCESSFUL_BACKUP,
  PASSPHRASE_SALT_STORAGE_KEY,
  PASSPHRASE_STORAGE_KEY,
} from '../common/secure-storage-constants'
import { WALLET_KEY } from '../bridge/react-native-cxs/vcx-transformers'
import { encryptWallet } from '../bridge/react-native-cxs/RNCxs'
import {
  getSalt,
  getConfig,
  getBackupPassphrase,
  getBackupWalletPath,
  getVcxInitializationState,
  getPrepareBackupStatus,
} from '../store/store-selector'
import { STORAGE_KEY_SHOW_BANNER } from '../components/banner/banner-constants'
import { getWords } from './secure-passphrase'
import { VCX_INIT_SUCCESS, __uniqueId } from '../store/type-config-store'
import { pinHash as generateKey, generateSalt } from '../lock/pin-hash'
import moment from 'moment'
import { captureError } from '../services/error/error-handler'

const initialState = {
  passphrase: { phrase: '', salt: 's', hash: 'h' },
  status: BACKUP_STORE_STATUS.IDLE,
  error: null,
  showBanner: false,
  lastSuccessfulBackup: '',
  backupWalletPath: '',
  prepareBackupStatus: PREPARE_BACK_IDLE,
}

export function* generateBackupSaga(
  action: GenerateBackupFileLoadingAction
): Generator<*, *, *> {
  // WALLET BACKUP ZIP FLOW
  const recoveryPassphrase: Passphrase = yield select(getBackupPassphrase)
  const { fs } = RNFetchBlob
  try {
    yield put(prepareBackup())

    const documentDirectory: string = fs.dirs.DocumentDir
    const backupTimeStamp = moment().format('YYYY-MM-DD-HH-mm-ss')
    const zipupDirectory: string = `${documentDirectory}/Backup-${backupTimeStamp}`

    // delete zip up directory if it already exists
    const destFileExists = yield call(fs.exists, zipupDirectory)
    if (destFileExists) {
      yield call(fs.unlink, zipupDirectory)
    }

    // create a new zip up directory
    yield call(fs.mkdir, zipupDirectory)
    const destinationZipPath: string = `${documentDirectory}/${WALLET_FILE_NAME}-${backupTimeStamp}.zip`
    const encryptedFileName: string = `${WALLET_FILE_NAME}.wallet`
    const encryptedFileLocation: string = `${zipupDirectory}/${encryptedFileName}`

    // create a file which contains salt needed to decrypt the wallet inside of zip up directory
    const saltValue = yield select(getSalt)
    const saltFileContents = JSON.stringify({ salt: saltValue })
    const saltFileName = `${zipupDirectory}/salt.json`

    const saltFile = yield call(
      fs.createFile,
      saltFileName,
      saltFileContents,
      'utf8'
    )

    // check status for prepare backup, with status of prepare backup
    // we would know whether we have moved all of data inside wallet or not
    // only when we are sure that we have moved data inside of wallet
    // we will go ahead and get a backup of wallet
    const prepareBackupStatus: PrepareBackupStatus = yield select(
      getPrepareBackupStatus
    )
    if (prepareBackupStatus !== PREPARE_BACKUP_SUCCESS) {
      // prepare backup can only be in 3 states, loading, success, failure
      // if it is not success, then we check for failure
      if (prepareBackupStatus === PREPARE_BACKUP_FAILURE) {
        throw new Error('Failed to write data back to wallet')
      }
      // if status is neither success nor failure, then we wait for it to success

      // we will wait for 2 minutes for data to go into wallet
      // and then we will timeout
      const { prepareBackupSuccess, timeout } = yield race({
        prepareBackupSuccess: take(PREPARE_BACKUP_SUCCESS),
        timeout: call(delay, 120000),
      })
      if (timeout) {
        throw new Error('Could not write data back to wallet in 2 minutes')
      }
    }

    // call VCX method to encrypt wallet. Given path to store it, file name, & key to encrypt it
    yield call(encryptWallet, {
      encryptedFileLocation,
      recoveryPassphrase,
    })

    // create zip file of zip up directory contents to be used as backup
    const backupZipFile = yield call(zip, zipupDirectory, destinationZipPath)
    yield put(generateBackupFileSuccess(backupZipFile))
  } catch (e) {
    captureError(e)
    yield put(
      generateBackupFileFail({
        ...ERROR_GENERATE_BACKUP_FILE,
        message: `${ERROR_GENERATE_BACKUP_FILE.message} ${e.message}`,
      })
    )
  }
}

const resolvedPromise = () => Promise.resolve()

export function* prepareBackupSaga(
  action: PrepareBackupLoadingAction
): Generator<*, *, *> {
  const skipItems = [__uniqueId, WALLET_KEY]

  try {
    // get all items saved in secure storage
    const secureStorage = yield call(secureGetAll)
    // for Android secureGetAll returns an object
    // while for ios it returns an array of array
    if (Platform.OS === 'android') {
      yield all(
        Object.keys(secureStorage).map(key => {
          if (skipItems.indexOf(key) === -1) {
            return call(walletSet, key, secureStorage[key])
          }

          return call(resolvedPromise)
        })
      )
    } else {
      if (secureStorage.length > 0) {
        yield all(
          secureStorage[0].map(item => {
            const { key, value } = item
            // check for things we don't want stored in the wallet
            if (skipItems.indexOf(key) === -1) {
              // store items into wallet
              return call(walletSet, key, value)
            }

            return call(resolvedPromise)
          })
        )
      }
    }

    yield put(prepareBackupSuccess())
  } catch (e) {
    yield put(
      prepareBackupFail({
        ...ERROR_GENERATE_BACKUP_FILE,
        message: `${ERROR_GENERATE_BACKUP_FILE.message} ${e.message}`,
      })
    )
  }
}

export function* exportBackupSaga(
  action: ExportBackupLoadingAction
): Generator<*, *, *> {
  try {
    const backupWalletPath: string = yield select(getBackupWalletPath)
    const title: string = `Export ${backupWalletPath.split('/').pop()}`
    Platform.OS === 'android'
      ? yield call(Share.open, {
          title,
          url: `file://${backupWalletPath}`,
          type: 'application/zip',
        })
      : yield call(Share.open, {
          title,
          url: backupWalletPath,
          type: 'application/zip',
        })
    const lastSuccessfulBackup = moment().format()
    yield put(exportBackupSuccess(lastSuccessfulBackup))
    yield put(promptBackupBanner(false))
    yield call(safeSet, LAST_SUCCESSFUL_BACKUP, lastSuccessfulBackup)
  } catch (e) {
    if (e.message === 'User did not share') {
      yield put(exportBackupNoShare())
    } else {
      captureError(new Error(`${ERROR_EXPORT_BACKUP.message} ${e.message}`))
      yield put(
        exportBackupFail({
          ...ERROR_EXPORT_BACKUP,
          message: `${ERROR_EXPORT_BACKUP.message} ${e.message}`,
        })
      )
    }
  }
}

export function* deletePersistedPassphrase(): Generator<*, *, *> {
  yield all([
    call(secureDelete, PASSPHRASE_STORAGE_KEY),
    call(secureDelete, PASSPHRASE_SALT_STORAGE_KEY),
  ])
}

export function* hydratePassphraseFromWallet(): Generator<*, *, *> {
  try {
    const [passphrase, passphraseSalt] = yield all([
      call(walletGet, PASSPHRASE_STORAGE_KEY),
      call(walletGet, PASSPHRASE_SALT_STORAGE_KEY),
    ])
    yield all([
      call(secureSet, PASSPHRASE_STORAGE_KEY, passphrase),
      call(secureSet, PASSPHRASE_SALT_STORAGE_KEY, passphraseSalt),
    ])
  } catch (e) {
    // not sure what to do if we don't get passphrase data
    // user would see new passphrase next time user is generating a backup
  }
}

export function* generateRecoveryPhraseSaga(
  action: GenerateRecoveryPhraseLoadingAction
): Generator<*, *, *> {
  const vcxInitializedState = yield select(getVcxInitializationState)
  if (vcxInitializedState !== VCX_INIT_SUCCESS) {
    yield take(VCX_INIT_SUCCESS)
  }
  // If it failed then we'll retry it a few times
  let retryCount = 0
  let lastInitException = new Error('')
  while (retryCount < 4) {
    try {
      let passphrase = yield call(secureGet, PASSPHRASE_STORAGE_KEY)
      let passphraseSalt = yield call(secureGet, PASSPHRASE_SALT_STORAGE_KEY)
      if (!passphrase) {
        const words: string[] = yield call(getWords, 8, 5)
        passphrase = words.join(' ')
        passphraseSalt = yield call(generateSalt)
      }
      const hashedPassphrase = yield call(
        generateKey,
        passphrase,
        passphraseSalt
      )
      yield call(secureSet, PASSPHRASE_STORAGE_KEY, passphrase)
      yield call(secureSet, PASSPHRASE_SALT_STORAGE_KEY, passphraseSalt)
      yield put(
        generateRecoveryPhraseSuccess({
          phrase: passphrase,
          salt: passphraseSalt,
          hash: hashedPassphrase,
        })
      )
      yield put(generateBackupFile())
      break
    } catch (e) {
      lastInitException = e
      retryCount++
    }
  }
  if (retryCount > 3) {
    captureError(new Error(`${ERROR_GENERATE_RECOVERY_PHRASE.message}`))
    yield put(
      generateRecoveryPhraseFail({
        ...ERROR_GENERATE_RECOVERY_PHRASE,
        message: `${ERROR_GENERATE_RECOVERY_PHRASE.message}`,
      })
    )
  }
}

export const prepareBackupSuccess = () => ({
  type: PREPARE_BACKUP_SUCCESS,
  status: BACKUP_STORE_STATUS.PREPARE_BACKUP_SUCCESS,
})

export const prepareBackupFail = (error: CustomError) => ({
  type: PREPARE_BACKUP_FAILURE,
  status: BACKUP_STORE_STATUS.PREPARE_BACKUP_FAILURE,
  error,
})

export const generateBackupFileSuccess = (backupWalletPath: string) => ({
  type: GENERATE_BACKUP_FILE_SUCCESS,
  status: BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_SUCCESS,
  backupWalletPath,
})

export const generateBackupFileFail = (error: CustomError) => ({
  type: GENERATE_BACKUP_FILE_FAILURE,
  status: BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_FAILURE,
  error,
})

export const hydrateBackupFail = (error: CustomError) => ({
  type: HYDRATE_BACKUP_FAILURE,
  error,
})

export const generateBackupFile = () => ({
  type: GENERATE_BACKUP_FILE_LOADING,
  status: BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_LOADING,
})

function* watchBackupStart(): any {
  yield takeLatest(GENERATE_BACKUP_FILE_LOADING, generateBackupSaga)
}

function* watchPrepareBackup(): any {
  yield takeLatest(PREPARE_BACKUP_LOADING, prepareBackupSaga)
}

function* watchExportBackup(): any {
  yield takeLatest(EXPORT_BACKUP_LOADING, exportBackupSaga)
}

function* watchGenerateRecoveryPhrase(): any {
  yield takeLatest(GENERATE_RECOVERY_PHRASE_LOADING, generateRecoveryPhraseSaga)
}

export function* watchBackup(): any {
  yield all([
    watchBackupStart(),
    watchPrepareBackup(),
    watchGenerateRecoveryPhrase(),
    watchExportBackup(),
    watchBackupBannerPrompt(),
  ])
}

export function* watchBackupBannerPrompt(): any {
  yield takeLatest(PROMPT_WALLET_BACKUP_BANNER, persistBackupBannerStatusSaga)
}

export function* hydrateBackupSaga(): Generator<*, *, *> {
  // We run two hydrations that are needed by this store in single saga
  // we could have merged these two into single hydration and followed
  // one hydration per reducer, for now we are just moving ahead with two
  // Also, these two hydrations runs in parallel, and even if one hydration fails
  // other hydration will continue
  // reason for not using "all" effect of redux-saga is that in all if one saga fails
  // then whole "all" effect is cancelled and other saga are not run to completion
  yield fork(hydrateLastSuccessfulBackupSaga)
  yield fork(hydrateBackupBannerStatusSaga)
}

export function* hydrateLastSuccessfulBackupSaga(): Generator<*, *, *> {
  try {
    let lastSuccessfulBackup = yield call(safeGet, LAST_SUCCESSFUL_BACKUP)
    if (lastSuccessfulBackup != null) {
      yield put(hydrateBackup(lastSuccessfulBackup))
    }
  } catch (e) {
    captureError(e)
    yield put(
      hydrateBackupFail({
        ...ERROR_HYDRATING_BACKUP,
        message: `${ERROR_HYDRATING_BACKUP.message} ${e.message}`,
      })
    )
  }
}

export function* hydrateBackupBannerStatusSaga(): Generator<*, *, *> {
  try {
    const backupBannerStatus = yield call(safeGet, STORAGE_KEY_SHOW_BANNER)
    if (backupBannerStatus) {
      yield put(promptBackupBanner(JSON.parse(backupBannerStatus)))
    }
  } catch (e) {
    captureError(e)
    yield put(
      hydrateBackupFail({
        ...ERROR_HYDRATING_BACKUP,
        message: `${ERROR_HYDRATING_BACKUP.message} ${e.message}`,
      })
    )
  }
}

export function* persistBackupBannerStatusSaga(
  action: PromptBackupBannerAction
): Generator<*, *, *> {
  const { showBanner } = action
  try {
    yield call(safeSet, STORAGE_KEY_SHOW_BANNER, JSON.stringify(showBanner))
  } catch (e) {
    yield put(promptBackupBanner(showBanner))
  }
}

export const hydrateBackup = (lastSuccessfulBackup: string) => ({
  type: HYDRATE_BACKUP,
  lastSuccessfulBackup,
})

export const promptBackupBanner = (
  showBanner: boolean
): PromptBackupBannerAction => ({
  type: PROMPT_WALLET_BACKUP_BANNER,
  showBanner,
})

export const generateRecoveryPhrase = () => ({
  type: GENERATE_RECOVERY_PHRASE_LOADING,
  status: BACKUP_STORE_STATUS.GENERATE_PHRASE_LOADING,
})

export const generateRecoveryPhraseSuccess = (passphrase: Passphrase) => ({
  type: GENERATE_RECOVERY_PHRASE_SUCCESS,
  status: BACKUP_STORE_STATUS.GENERATE_PHRASE_SUCCESS,
  passphrase: <PASSWORD>,
})

export const generateRecoveryPhraseFail = (error: CustomError) => ({
  type: GENERATE_RECOVERY_PHRASE_FAILURE,
  status: BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_FAILURE,
  error,
})

export const prepareBackup = () => ({
  type: PREPARE_BACKUP_LOADING,
  status: BACKUP_STORE_STATUS.PREPARE_BACKUP_LOADING,
})

export const exportBackup = () => ({
  type: EXPORT_BACKUP_LOADING,
  status: BACKUP_STORE_STATUS.EXPORT_BACKUP_LOADING,
})

export const exportBackupFail = (error: CustomError) => ({
  type: EXPORT_BACKUP_FAILURE,
  error,
  status: BACKUP_STORE_STATUS.EXPORT_BACKUP_FAILURE,
})

export const exportBackupSuccess = (lastSuccessfulBackup: string) => ({
  type: EXPORT_BACKUP_SUCCESS,
  status: BACKUP_COMPLETE,
  lastSuccessfulBackup,
})

export const exportBackupNoShare = () => ({
  type: EXPORT_BACKUP_NO_SHARE,
  status: BACKUP_STORE_STATUS.EXPORT_BACKUP_NO_SHARE,
})

export default function backupReducer(
  state: BackupStore = initialState,
  action: BackupStoreAction
) {
  switch (action.type) {
    case GENERATE_RECOVERY_PHRASE_LOADING: {
      return {
        ...state,
        status: action.status,
        error: null,
      }
    }
    case GENERATE_RECOVERY_PHRASE_SUCCESS: {
      return {
        ...state,
        status: action.status,
        error: action.error,
        passphrase: {
          phrase: action.passphrase.phrase,
          salt: action.passphrase.salt,
          hash: action.passphrase.hash,
        },
      }
    }
    case GENERATE_RECOVERY_PHRASE_FAILURE: {
      return {
        ...state,
        status: action.status,
        error: action.error,
      }
    }
    case GENERATE_BACKUP_FILE_LOADING: {
      return {
        ...state,
        status: action.status,
        error: null,
      }
    }
    case GENERATE_BACKUP_FILE_SUCCESS: {
      return {
        ...state,
        status: action.status,
        error: null,
        backupWalletPath: action.backupWalletPath,
      }
    }
    case GENERATE_BACKUP_FILE_FAILURE: {
      return {
        ...state,
        status: action.status,
        error: action.error,
      }
    }
    case EXPORT_BACKUP_LOADING: {
      return {
        ...state,
        status: action.status,
        error: null,
      }
    }
    case EXPORT_BACKUP_NO_SHARE: {
      return {
        ...state,
        status: action.status,
        error: null,
      }
    }
    case EXPORT_BACKUP_SUCCESS: {
      return {
        ...state,
        error: null,
        status: action.status,
        lastSuccessfulBackup: action.lastSuccessfulBackup,
      }
    }
    case EXPORT_BACKUP_FAILURE: {
      return {
        ...state,
        status: action.status,
        error: action.error,
      }
    }
    case PROMPT_WALLET_BACKUP_BANNER: {
      return {
        ...state,
        showBanner: action.showBanner,
      }
    }
    case BACKUP_WALLET_FAIL: {
      return {
        ...state,
        error: action.error,
      }
    }
    case HYDRATE_BACKUP:
      return {
        ...initialState,
        lastSuccessfulBackup: action.lastSuccessfulBackup,
        showBanner: state.showBanner,
      }
    case HYDRATE_BACKUP_FAILURE:
      return {
        ...state,
        error: action.error,
      }
    case PREPARE_BACKUP_LOADING:
    case PREPARE_BACKUP_SUCCESS:
    case PREPARE_BACKUP_FAILURE:
      return {
        ...state,
        prepareBackupStatus: action.status,
      }
    default:
      return state
  }
}


<|start_filename|>app/components/layout/index.js<|end_filename|>
// @flow
import React from 'react'
import { View } from 'react-native'
import { color } from '../../common/styles/constant'

export { Container } from './container'
export { CustomView } from './custom-view'
export { CustomSafeAreaView } from './custom-safeAreaView'
export { default as CustomList } from './custom-list'
export { default as headerStyles } from './header-styles'


<|start_filename|>android/app/src/main/java/me/connect/keystore/WalletKeyHandler.java<|end_filename|>
package me.connect.keystore;

import android.app.KeyguardManager;
import android.content.Context;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyInfo;
import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException;
import android.support.annotation.NonNull;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.ProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.util.Date;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;

public class WalletKeyHandler {
    private static final String wrappingKey = "<KEY>";
    private static final String dummyKey = "<KEY>";
    private static final String walletKeyFilename = "ff7a48ddfe10422cb54b474d04898637";
    private static final String cipherName = "AES/GCM/NoPadding";
    private static final int iv_length = 12;
    private static final int tag_length = 128;
    private static final long thirty_days = 2592000000L;

    public static byte[] getWalletEncryptionKey(Context context) throws UserNotAuthenticatedException, LostKeyException {
        checkKeyguardSecure(context);

        if (systemHasSecureHardware()) {
            String walletFilename = context.getApplicationInfo().dataDir + "/" + walletKeyFilename;
            File walletFile = new File(walletFilename);
            SecretKey key = getWalletKeyWrappingKey();
            try {
                byte[] walletKey;
                if (walletFile.canRead()) {
                    walletKey = tryDecrypt(loadFile(walletFile), key);
                    rotateWrappingKeyIfNeeded(context, walletFile, walletKey, key);
                } else {
                    SecureRandom secureRandom = new SecureRandom();
                    Random random = new Random();
                    int draws = random.nextInt(50) + 10;
                    walletKey = new byte[256];
                    for (int i = 0; i < draws; i++) {
                        //Just in case the random number seed hasn't been initialized well since boot
                        secureRandom.nextBytes(walletKey);
                    }
                    saveWalletEncryptionKey(context, walletKey, key);
                }
                return walletKey;
            } catch (IOException | NoSuchProviderException | NoSuchAlgorithmException |
                     InvalidKeySpecException | KeyStoreException e) {
                throw new RuntimeException(e);
            }
        } else {
            //Key is not in hardware, caller should not be using this method
            throw new RuntimeException("When hardware is not available, do not call this method. Use 'systemHasSecureHardware' first");
        }
    }

    private static void rotateWrappingKeyIfNeeded(Context context, File walletFile, byte[] walletKey, SecretKey key) throws NoSuchAlgorithmException, LostKeyException, NoSuchProviderException, InvalidKeySpecException, KeyStoreException, IOException, UserNotAuthenticatedException {
        if (key == null)
            key = getWalletKeyWrappingKey();
        SecretKeyFactory factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
        KeyInfo keyInfo = (KeyInfo) factory.getKeySpec(key, KeyInfo.class);
        Date keyValidityEnd = new Date(keyInfo.getKeyValidityStart().getTime() + thirty_days);

        if (keyValidityEnd.before(new Date())) {
            //Key should to be rotated.
            walletFile.delete();
            KeyStore keyStore = loadKeyStore();
            keyStore.deleteEntry(wrappingKey);
            saveWalletEncryptionKey(context, walletKey, key);
        }
    }

    public static void setWalletEncryptionKey(Context context, byte[] walletEncryptionKey) throws UserNotAuthenticatedException, LostKeyException, IOException{
        checkKeyguardSecure(context);
        if (systemHasSecureHardware()) {
            saveWalletEncryptionKey(context, walletEncryptionKey, null);
        }
    }

    public static boolean systemHasSecureHardware() {
        try {
            SecretKey key = getKeyStoreKey(dummyKey);
            SecretKeyFactory factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
            KeyInfo keyInfo = (KeyInfo) factory.getKeySpec(key, KeyInfo.class);
            return keyInfo.isInsideSecureHardware();
        } catch (ProviderException e) {
            //The keystore was not automatically created like it would if hardware existed
            return false;
        } catch (LostKeyException e) {
            try {
                KeyStore keyStore = loadKeyStore();
                keyStore.deleteEntry(dummyKey);
            } catch (KeyStoreException ex) {

            }
            return false;
        }
        catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] charsToBytesArray(char[] chars) {
        byte[] b = new byte[chars.length << 1];
        int index = 0;
        for (char c: chars) {
            b[index++] = (byte) (c & 0xFF00 >> 8);
            b[index++] = (byte) (c & 0x00FF);
        }
        return b;
    }

    public static char[] bytesToCharsArray(byte[] bytes) {
        char[] c = new char[bytes.length >> 1];
        int index = 0;
        for (int i = 0; i < bytes.length; i += 2) {
            int temp = bytes[i] << 8 | bytes[i + 1];
            c[index++] = (char) temp;
        }
        return c;
    }

    private static void saveWalletEncryptionKey(Context context, byte[] walletEncryptionKey, SecretKey key) throws IOException, UserNotAuthenticatedException, LostKeyException {
        String walletFilename = context.getApplicationInfo().dataDir + "/" + walletKeyFilename;
        File walletFile = new File(walletFilename);
        saveFile(walletFile, tryEncrypt(walletEncryptionKey, key));
    }

    private static void checkKeyguardSecure(Context context) throws UserNotAuthenticatedException {
        KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);

        if (!keyguardManager.isDeviceSecure()) {
            throw new UserNotAuthenticatedException("Secure lock screen hasn't been set up.\nGo to 'Settings -> Security -> Screen lock' to setup up a lock screen");
        }
    }

    private static byte[] tryEncrypt(byte[] plaintext, SecretKey key) throws UserNotAuthenticatedException, LostKeyException {
        try {
            if (key == null)
                key = getWalletKeyWrappingKey();
            Cipher cipher = Cipher.getInstance(cipherName);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] iv = cipher.getIV();
            byte[] cipherText = cipher.doFinal(plaintext);
            byte[] result = new byte[iv.length + cipherText.length];
            System.arraycopy(iv, 0, result, 0, iv.length);
            System.arraycopy(cipherText, 0, result, iv.length, cipherText.length);
            return result;
        } catch (InvalidKeyException e) {
            if (e instanceof UserNotAuthenticatedException) {
                UserNotAuthenticatedException ex = (UserNotAuthenticatedException) e;
                throw ex;
            } else {
                throw new RuntimeException(e);
            }
        } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException |
                NoSuchPaddingException e) {
            throw new RuntimeException(e);
        }
    }

    private static byte[] tryDecrypt(byte[] cipherText, SecretKey key) throws UserNotAuthenticatedException, LostKeyException {
        try {
            if (key == null)
                key = getWalletKeyWrappingKey();
            Cipher cipher = Cipher.getInstance(cipherName);
            GCMParameterSpec spec = new GCMParameterSpec(tag_length, cipherText, 0, iv_length);
            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            return cipher.doFinal(cipherText, iv_length, cipherText.length - iv_length);
        } catch (InvalidKeyException e) {
            if (e instanceof UserNotAuthenticatedException) {
                UserNotAuthenticatedException ex = (UserNotAuthenticatedException) e;
                throw ex;
            } else {
                throw new RuntimeException(e);
            }
        } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException |
                 NoSuchPaddingException | InvalidAlgorithmParameterException e) {
            throw new RuntimeException(e);
        }
    }

    private static byte[] loadFile(File file) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[(int) Math.min(4096, file.length())];
            int read;
            Log.d("loadFile", "Reading " + file.length() + " bytes");
            try (FileInputStream fileInputStream = new FileInputStream(file)) {
                while ((read = fileInputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, read);
                }
            }
            return outputStream.toByteArray();
        }
    }

    private static void saveFile(File file, byte[] contents) throws IOException {
        Log.d("saveFile", "Wrote " + contents.length + " bytes");
        try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
            fileOutputStream.write(contents);
        }
    }

    private static SecretKey getWalletKeyWrappingKey() throws LostKeyException {
        try {
            SecretKey key = getKeyStoreKey(wrappingKey);
            return key;
        } catch (LostKeyException e) {
            try {
                KeyStore keyStore = loadKeyStore();
                keyStore.deleteEntry(wrappingKey);
            } catch (KeyStoreException ex) {

            }
            throw e;
        }
    }

    @NonNull
    private static SecretKey getKeyStoreKey(String keyId) throws LostKeyException {
        try {
            KeyStore keyStore = loadKeyStore();
            KeyStore.Entry entry = keyStore.getEntry(keyId, null);

            SecretKey key = null;

            if (entry == null) {
                KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
                keyGenerator.init(new KeyGenParameterSpec.Builder(keyId,
                        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                        .setKeySize(256)
                        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                        .setRandomizedEncryptionRequired(true)
                        .setKeyValidityStart(new Date(System.currentTimeMillis() - 5))
                        .setUserAuthenticationValidityDurationSeconds(900)
                        .setUserAuthenticationRequired(true)
                        .build());
                key = keyGenerator.generateKey();
            } else if (entry instanceof KeyStore.SecretKeyEntry) {
                key = ((KeyStore.SecretKeyEntry) entry).getSecretKey();
            }
            return key;
        } catch (UnrecoverableKeyException e) {
            throw new LostKeyException("The lock screen has been disabled or reset. The key is not accessible anymore.");
        }
        catch (KeyStoreException | NoSuchAlgorithmException | NoSuchProviderException |
                 InvalidAlgorithmParameterException | UnrecoverableEntryException e) {
            throw new RuntimeException(e);
        }
    }

    private static KeyStore loadKeyStore() {
        try {
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            keyStore.load(null);
            return keyStore;
        } catch (KeyStoreException | NoSuchAlgorithmException | IOException | CertificateException e) {
            throw new RuntimeException(e);
        }
    }
}


<|start_filename|>app/api/api.js<|end_filename|>
// @flow
import { api, options } from './api-utils'
import type {
  GetInvitationLinkApiData,
  MessageApiData,
  DownloadInvitationApiData,
  SendAuthenticationResponseApiData,
  EnvironmentDetailUrlDownloaded,
} from './type-api'
import { PAYLOAD_TYPE, MESSAGE_TYPE, STATUS_CODE } from './api-constants'

export const getInvitationLink = ({
  agencyUrl,
  smsToken,
}: GetInvitationLinkApiData) =>
  api(`${agencyUrl}/agency/url-mapper/${smsToken}`, options('GET'))

export const invitationDetailsRequest = ({ url }: DownloadInvitationApiData) =>
  api(url, options('GET'))

export const getAdditionalData = ({ agencyUrl, dataBody }: MessageApiData) =>
  api(`${agencyUrl}/agency/route`, options('POST', dataBody))

export const sendAuthenticationRequest = ({
  data: { identifier, dataBody },
  config: { agencyUrl },
}: SendAuthenticationResponseApiData) =>
  api(`${agencyUrl}/agent/${identifier}/auth`, options('PUT', dataBody), true)

export const downloadEnvironmentDetails = (
  url: string
): Promise<EnvironmentDetailUrlDownloaded> => api(url, options())


<|start_filename|>app/lock/__tests__/lock-selection.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { LockSelection } from '../lock-selection'
import { getStore, getNavigation } from '../../../__mocks__/static-data'

function getLockSelectionProps() {
  return {
    switchErrorAlerts: jest.fn(),
    longPressedInLockSelectionScreen: jest.fn(),
    pressedOnOrInLockSelectionScreen: jest.fn(),
    disableDevMode: jest.fn(),
    safeToDownloadSmsInvitation: jest.fn(),
  }
}

const navigation = getNavigation()
const store = getStore()

let componentInstance: LockSelection
let tree
let wrapper
let props

describe('app lock selection page should', () => {
  beforeEach(() => {
    props = getLockSelectionProps()
    wrapper = renderer.create(
      <Provider store={store}>
        <LockSelection {...props} showDevMode={false} navigation={navigation} />
      </Provider>
    )
    tree = wrapper.toJSON()
    componentInstance = wrapper.root.findByType(LockSelection).instance
  })

  it('render properly', () => {
    expect(tree).toMatchSnapshot()
  })

  it('should be able to call longPressedInLockSelectionScreen action', () => {
    componentInstance._onLongPressButton()
    expect(props.longPressedInLockSelectionScreen).toHaveBeenCalled()
  })

  it('should be able to call pressedOnOrInLockSelectionScreen press action', () => {
    componentInstance._onTextPressButton()
    expect(props.pressedOnOrInLockSelectionScreen).toHaveBeenCalled()
  })

  it('call safeToDownloadSmsInvitation if setup touchId', () => {
    componentInstance.goTouchIdSetup()
    expect(props.safeToDownloadSmsInvitation).toHaveBeenCalled()
  })

  it('call safeToDownloadSmsInvitation if setup pass code', () => {
    componentInstance.goPinCodeSetup()
    expect(props.safeToDownloadSmsInvitation).toHaveBeenCalled()
  })
})


<|start_filename|>app/wallet/__tests__/wallet-tab-receive.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { WalletTabReceive } from '../wallet-tab-receive'
import { Clipboard } from 'react-native'
import { walletAddresses, getStore } from '../../../__mocks__/static-data'
import { STORE_STATUS } from '../type-wallet'
import { walletRoute } from '../../common'

describe('<WalletTabReceive />', () => {
  const store = getStore()
  function setup() {
    const component = renderer.create(
      <Provider store={store}>
        <WalletTabReceive
          walletAddresses={walletAddresses.data}
          refreshWalletAddresses={jest.fn()}
          promptBackupBanner={jest.fn()}
          addressStatus={STORE_STATUS.IN_PROGRESS}
          currentScreen={walletRoute}
        />
      </Provider>
    )
    const instance = component.root.findByType(WalletTabReceive).instance
    return { component, instance }
  }
  it('should render properly and match the snapshot', () => {
    const { component } = setup()
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
  it('should call Clipboard.setString', () => {
    const { instance } = setup()
    const copyToClipboard = jest.spyOn(Clipboard, 'setString')
    instance.copyToClipboard()
    expect(copyToClipboard).toHaveBeenCalledWith(walletAddresses.data[0])
    copyToClipboard.mockReset()
    copyToClipboard.mockRestore()
  })
})


<|start_filename|>app/lock/__tests__/lock-setup-success.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { LockSetupSuccess } from '../lock-setup-success'
import { lockSetupSuccessRoute } from '../../common'
import {
  getNavigation,
  pendingRedirection,
} from '../../../__mocks__/static-data'

describe('<LockSetupSuccess />', () => {
  const getProps = (isFetchingInvitation = false) => ({
    isFetchingInvitation,
    navigation: getNavigation(),
    pendingRedirection,
    unlockApp: jest.fn(),
    clearPendingRedirect: jest.fn(),
  })
  const options = {
    createNodeMock: element => {
      return {
        clear: () => {
          cleared = true
        },
      }
    },
  }

  let component
  let props
  let cleared

  it('should render Lock setup success Screen', () => {
    props = getProps(false)
    component = renderer.create(<LockSetupSuccess {...props} />, options)
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should display Loading while fetching the invitation', () => {
    props = getProps(true)
    component = renderer.create(<LockSetupSuccess {...props} />, options)
    expect(component.toJSON()).toMatchSnapshot()
  })
})


<|start_filename|>app/feedback/message-constants.js<|end_filename|>
// @flow
import { Platform } from 'react-native'

export const apptentiveCredentials = Platform.select({
  ios: {
    apptentiveKey: '***REMOVED***',
    apptentiveSignature: '***REMOVED***',
  },
  android: {
    apptentiveKey: '***REMOVED***',
    apptentiveSignature: '***REMOVED***',
  },
})


<|start_filename|>app/components/loader/loading-indicator.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Image, View, StyleSheet, Animated, Easing } from 'react-native'
import type { LoadingIndicatorProps } from './type-loader'
import { DARK } from './type-loader'
import { color } from '../../common/styles/constant'

export default class LoadingIndicator extends PureComponent<
  LoadingIndicatorProps,
  void
> {
  spinValue = new Animated.Value(0)

  static defaultProps = {
    type: DARK,
  }

  spin() {
    this.spinValue.setValue(0)
    Animated.loop(
      Animated.timing(this.spinValue, {
        toValue: 1,
        duration: 1000,
        easing: Easing.linear,
        useNativeDriver: true,
      })
    ).start()
  }

  componentDidMount() {
    this.spin()
  }

  render() {
    const rotate = this.spinValue.interpolate({
      inputRange: [0, 1],
      outputRange: ['0deg', '360deg'],
    })
    const { type, size } = this.props
    const tintColor = type === DARK ? color.actions.sixth : color.actions.none

    return (
      <Animated.Image
        style={[
          {
            tintColor,
            transform: [{ rotate: rotate }],
            width: size,
            height: size,
          },
        ]}
        source={require('../../images/icon_sovrin.png')}
      />
    )
  }
}


<|start_filename|>app/common/index.js<|end_filename|>
// @flow
export * from './button-constants'
export * from './message-constants'
export * from './route-constants'
export * from './secure-storage-constants'
export function noop() {}


<|start_filename|>app/authentication/__tests__/authentication.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { authenticationRoute } from '../../common/'
import { PUSH_NOTIFICATION_SENT_CODE } from '../../api/api-constants'
import AuthenticationScreen from '../authentication'
import { color } from '../../common/styles'

describe('<AuthenticationScreen />', () => {
  let store = {}

  beforeAll(() => {
    store = {
      getState() {
        return {
          connections: {
            connectionThemes: {
              default: {
                primary: `rgba(${color.actions.button.primary.rgba})`,
                secondary: `rgba(${color.actions.button.secondary.rgba})`,
              },
            },
          },
          route: {
            currentScreen: authenticationRoute,
          },
          authentication: {
            data: {
              offerMsgTitle: 'Hi There',
              offerMsgText:
                'Suncoast Credit Union (sandbox) wants to connect with you',
              statusCode: PUSH_NOTIFICATION_SENT_CODE,
              logoUrl: null,
              remoteConnectionId: 'B4Y9fhpeHdGHBKKtSgAYrB',
            },
          },
          config: {
            showErrorAlerts: false,
          },
          lock: {
            isTouchIdEnabled: false,
          },
          user: {
            avatarName: undefined,
          },
        }
      },
      subscribe() {
        return jest.fn()
      },
      dispatch() {
        return jest.fn()
      },
    }
  })

  it('should match snapshot', () => {
    const component = renderer.create(
      <Provider store={store}>
        <AuthenticationScreen showErrorAlerts />
      </Provider>
    )
    let tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/app-status/type-app-status.js<|end_filename|>
// @flow
export type AppStatusState = {
  appState: ?string,
}

export type AppStatusProps = {
  getUnacknowledgedMessages: () => void,
}


<|start_filename|>app/lock/type-lock.js<|end_filename|>
// @flow
import type { CustomError, ReactNavigation } from '../common/type-common'
import { SWITCH_ERROR_ALERTS } from '../store/type-config-store'

export const LOCK_TYPE = {
  FINGERPRINT: 'FINGERPRINT',
  PIN: 'PIN',
}
export type lockType = $Keys<typeof LOCK_TYPE>

export type PendingRedirection = {
  routeName: string,
  params?: ?{ [string]: any },
}

export const PENDING_REDIRECT = 'SET_PENDING_REDIRECT'
export type AddPendingRedirectAction = {
  type: typeof PENDING_REDIRECT,
  pendingRedirection: Array<PendingRedirection>,
}

export const CLEAR_PENDING_REDIRECT = 'CLEAR_PENDING_REDIRECT'
export type ClearPendingRedirectAction = {
  type: typeof CLEAR_PENDING_REDIRECT,
}

export const PIN_HASH = 'PIN_HASH'
export const SALT = 'SALT'
export const PIN_ENABLED_KEY = 'APP_PIN_LOCK_ENABLED'
export const IN_RECOVERY = 'IN_RECOVERY'
export type InRecovery = {
  type: typeof IN_RECOVERY,
  inRecovery: string,
}
export const SET_PIN = 'SET_PIN'
export type SetPinAction = {
  type: typeof SET_PIN,
  pin: string,
}

export const TOUCH_ID_STORAGE_KEY = 'APP_TOUCHID_LOCK'
export const ENABLE_TOUCHID = 'ENABLE_TOUCHID'
export type EnableTouchIdAction = {
  type: typeof ENABLE_TOUCHID,
}
export const DISABLE_TOUCHID = 'DISABLE_TOUCHID'
export type DisableTouchIdAction = {
  type: typeof DISABLE_TOUCHID,
}

export const CHECK_TOUCHID = 'CHECK_TOUCHID'
export type CheckTouchIdAction = {
  type: typeof CHECK_TOUCHID,
  isTouchIdEnabled: boolean,
}

export const LOCK_ENABLE = 'LOCK_ENABLE'
export type LockEnable = {
  type: typeof LOCK_ENABLE,
  isLockEnable: string,
}

export const LOCK_FAIL = 'LOCK_FAIL'
export type LockFail = {
  type: typeof LOCK_FAIL,
  error: CustomError,
}

export const CHECK_PIN = 'CHECK_PIN'
export type CheckPinAction = {
  type: typeof CHECK_PIN,
  pin: string,
}

export const CHECK_PIN_SUCCESS = 'CHECK_PIN_SUCCESS'
export type CheckPinSuccessAction = {
  type: typeof CHECK_PIN_SUCCESS,
}

export const CHECK_PIN_FAIL = 'CHECK_PIN_FAIL'
export type CheckPinFailAction = {
  type: typeof CHECK_PIN_FAIL,
}

export const CHECK_PIN_IDLE = 'CHECK_PIN_IDLE'
export type CheckPinIdleAction = {
  type: typeof CHECK_PIN_IDLE,
}

export const UNLOCK_APP = 'UNLOCK_APP'
export type UnlockAppAction = {
  type: typeof UNLOCK_APP,
}

export const PRESSED_ON_OR_IN_LOCK_SELECTION_SCREEN =
  'PRESSED_ON_OR_IN_LOCK_SELECTION_SCREEN'
export type PressedOnOrInLockSelectionScreen = {
  type: typeof PRESSED_ON_OR_IN_LOCK_SELECTION_SCREEN,
}

export const LONG_PRESSED_IN_LOCK_SELECTION_SCREEN =
  'LONG_PRESSED_IN_LOCK_SELECTION_SCREEN'
export type LongPressedInLockSelectionScreen = {
  type: typeof LONG_PRESSED_IN_LOCK_SELECTION_SCREEN,
}

export const RESET_TOUCH_EVENT_VARIABLES = 'RESET_TOUCH_EVENT_VARIABLES'
export type ResetTouchEventVariables = {
  type: typeof RESET_TOUCH_EVENT_VARIABLES,
}

export type SwitchErrorAlerts = {
  type: typeof SWITCH_ERROR_ALERTS,
}

export type CheckPinStatus =
  | typeof CHECK_PIN_SUCCESS
  | typeof CHECK_PIN_FAIL
  | typeof CHECK_PIN_IDLE

export type LockStore = {
  pendingRedirection: ?Array<PendingRedirection>,
  checkPinStatus: CheckPinStatus,
  isAppLocked: boolean,
  isLockEnabled: string,
  isTouchIdEnabled: boolean,
  showDevMode: boolean,
  inRecovery: string,
  biometricsAvaliable?: string,
}

export type LockSelectionProps = {
  showDevMode: boolean,
  disableDevMode: () => DisableDevMode,
  longPressedInLockSelectionScreen: () => void,
  pressedOnOrInLockSelectionScreen: () => void,
  switchErrorAlerts: () => void,
  safeToDownloadSmsInvitation: () => void,
} & ReactNavigation

export type LockActions =
  | AddPendingRedirectAction
  | ClearPendingRedirectAction
  | SetPinAction
  | EnableTouchIdAction
  | DisableTouchIdAction
  | CheckTouchIdAction
  | CheckPinAction
  | CheckPinSuccessAction
  | CheckPinFailAction
  | SwitchErrorAlerts

export type LockEnterPinProps = {
  pendingRedirection: Array<PendingRedirection>,
  isFetchingInvitation?: boolean,
  clearPendingRedirect: () => void,
  unlockApp: () => void,
  existingPin: boolean,
  isAppLocked: boolean,
  inRecovery: string,
  currentScreen: string,
} & ReactNavigation

export type LockEnterFingerProps = {
  pendingRedirection: Array<PendingRedirection>,
  isFetchingInvitation?: boolean,
  clearPendingRedirect: () => void,
  unlockApp: () => void,
  isAppLocked: boolean,
} & ReactNavigation

export type LockEnterPinState = {
  authenticationSuccess: boolean,
  isKeyboardHidden: boolean,
  showCustomKeyboard: boolean,
}
export type LockEnterFingerState = {
  authenticationSuccess: boolean,
}
export type LockEnterState = {
  interactionsDone: boolean,
}

export const PIN_SETUP_STATE = {
  INITIAL: 'INITIAL',
  REENTER: 'REENTER',
  REENTER_FAIL: 'REENTER_FAIL',
  REENTER_SUCCESS: 'REENTER_SUCCESS',
  ENTER_NEW_PIN: 'ENTER_NEW_PIN',
}

export type LockPinSetupState = {
  pinSetupState: $Keys<typeof PIN_SETUP_STATE>,
  enteredPin: ?string,
  pinReEnterSuccessPin: ?string,
  keyboardHidden: boolean,
  showCustomKeyboard: boolean,
}

export const SHOW_DEV_MODE = 'SHOW_DEV_MODE'
export type EnableDevMode = {
  type: typeof SHOW_DEV_MODE,
}

export const HIDE_DEV_MODE = 'HIDE_DEV_MODE'
export type DisableDevMode = {
  type: typeof HIDE_DEV_MODE,
}

export type LockEnterProps = {
  checkPinAction: (pin: string) => void,
  checkPinStatusIdle: () => void,
  switchErrorAlerts: () => void,
  onSuccess: () => void,
  message?: string,
  checkPinStatus: CheckPinStatus,
  fromRecovery: boolean,
  setupNewPassCode?: () => void,
  enableCustomKeyboard?: boolean,
}

export type LockAuthorizationProps = {
  onSuccess: () => void,
  onFail: () => void,
} & ReactNavigation

export type LockFingerprintSetupProps = {
  touchIdActive: boolean,
  fromSettings: boolean,
  currentScreen: string,
  disableTouchIdAction: () => void,
  enableTouchIdAction: () => void,
} & ReactNavigation

export type LockPinCodeSetupProps = {
  setPinAction: (pin: string) => void,
  enableTouchIdAction: () => void,
  lockEnable: (enableLock: string) => void,
} & ReactNavigation

export type LockSetupSuccessProps = {
  pendingRedirection: Array<PendingRedirection>,
  unlockApp: () => void,
  clearPendingRedirect: () => void,
  isFetchingInvitation: boolean,
} & ReactNavigation

export type LockSetupSuccessState = {
  interactionsDone: boolean,
}

export const LAErrorAuthenticationFailed = 'LAErrorAuthenticationFailed'
export const LAErrorUserCancel = 'LAErrorUserCancel'
export const LAErrorUserFallback = 'LAErrorUserFallback'
export const LAErrorSystemCancel = 'LAErrorSystemCancel'
export const LAErrorPasscodeNotSet = 'LAErrorPasscodeNotSet'
export const LAErrorTouchIDNotAvailable = 'LAErrorTouchIDNotAvailable'
export const LAErrorTouchIDNotEnrolled = 'LAErrorTouchIDNotEnrolled'
export const LAErrorTouchIDUnknownError = 'RCTTouchIDUnknownError'
export const LAErrorTouchIDNotSupported = 'RCTTouchIDNotSupported'
export const TouchIDError = 'Touch ID Error'
export const LAErrorTouchIDTooManyAttempts = 'FINGERPRINT_ERROR_LOCKOUT'

export const AllowedFallbackToucheIDErrors = [
  LAErrorUserCancel,
  LAErrorSystemCancel,
  LAErrorPasscodeNotSet,
  LAErrorTouchIDNotAvailable,
  LAErrorTouchIDNotEnrolled,
  LAErrorTouchIDUnknownError,
  LAErrorAuthenticationFailed,
  LAErrorUserFallback,
  LAErrorTouchIDNotSupported,
  TouchIDError,
]

export const touchIDAlerts = {
  notSupportedBiometrics: `Your phone doesn’t support biometrics.`,
  enableBiometrics:
    'You need to enable biometrics for Connect.Me in your device settings.',
  iOSBiometricsAlert:
    'You need to enable biometrics for Connect.Me or you have exceeded attempts for authentication',
  biometricsExceedAlert:
    'You have exceeded the maximum biometric attempts allowed by your phone. Try again later.',
  usePasscodeAlert: `You'll need to use your passcode to unlock this app from now on`,
}

export const touchIDNotSupportAlertAndroid = [
  'NOT_PRESENT',
  'NOT_AVAILABLE',
  'NOT_SUPPORTED',
]


<|start_filename|>app/authentication/type-authentication.js<|end_filename|>
// @flow
import type { ConfigStore } from '../store/type-config-store'

export type AuthenticationStatus = {
  ACCEPTED: string,
  REJECTED: string,
  NONE: string,
}

export type AuthenticationType = {
  NONE: string,
  AUTHENTICATION_REQUEST: string,
}

export type AuthenticationError = {
  message: string,
  authenticationType: string,
}

type Invitee = {
  +image: string,
}

type Inviter = {
  +image: string,
}

type DataBody = {
  challenge: string,
  signature?: string,
}

export type AuthenticationSuccessData = {
  newStatus: string,
  identifier: string,
  dataBody: DataBody,
  remoteConnectionId: string,
}

export type AuthenticationStore = {
  +inviter: Inviter,
  +invitee: Invitee,
  +data: ?AuthenticationPayload,
  +error: ?AuthenticationError,
  +type: string,
  +status: string,
  +isFetching: boolean,
  +isPristine: boolean,
}

export type AuthenticationPayload =
  | {
      offerMsgTitle: string,
      offerMsgText: string,
      logoUrl: ?string,
      name?: string,
      statusMsg?: string,
      remoteConnectionId: string,
    }
  | AuthenticationSuccessData

export type NewConnection = {
  identifier: string,
  remoteConnectionId: string,
  seed: string,
  remoteDID: string,
}

export type AuthenticationAction =
  | SendUserAuthenticationResponse
  | SendUserAuthenticationResponseSuccess
  | SendUserAuthenticationResponseFailure
  | AuthenticationRequestReceived
  | ResetAuthenticationStatus

const AUTHENTICATION_REQUEST_RECEIVED = 'AUTHENTICATION_REQUEST_RECEIVED'
const SEND_USER_AUTHENTICATION_RESPONSE = 'SEND_USER_AUTHENTICATION_RESPONSE'
const SEND_USER_AUTHENTICATION_RESPONSE_SUCCESS =
  'SEND_USER_AUTHENTICATION_RESPONSE_SUCCESS'
const SEND_USER_AUTHENTICATION_RESPONSE_FAILURE =
  'SEND_USER_AUTHENTICATION_RESPONSE_FAILURE'
const RESET_AUTHENTICATION_STATUS = 'RESET_AUTHENTICATION_STATUS'

export type SendUserAuthenticationResponse = {
  type: typeof SEND_USER_AUTHENTICATION_RESPONSE,
  data: AuthenticationSuccessData,
  config: ConfigStore,
  authenticationType: string,
  token?: string,
  newConnection?: NewConnection,
}

export type SendUserAuthenticationResponseSuccess = {
  type: typeof SEND_USER_AUTHENTICATION_RESPONSE_SUCCESS,
  data: AuthenticationSuccessData,
}

export type SendUserAuthenticationResponseFailure = {
  type: typeof SEND_USER_AUTHENTICATION_RESPONSE_FAILURE,
  error: AuthenticationError,
}

export type AuthenticationRequestReceived = {
  type: typeof AUTHENTICATION_REQUEST_RECEIVED,
  data: AuthenticationPayload,
}

export type ResetAuthenticationStatus = {
  type: typeof RESET_AUTHENTICATION_STATUS,
}


<|start_filename|>app/components/custom-header/custom-header.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, StatusBar, Platform } from 'react-native'
import type { CustomHeaderProps } from './type-custom-header'
import { SafeAreaView } from 'react-navigation'
import { withNavigationFocus } from 'react-navigation'

import style from '../layout/layout-style'
import { Header } from 'react-native-elements'
import Color from 'color'
import { barStyleDark, barStyleLight } from '../../common/styles/constant'
import type { StatusBarStyle } from '../../common/type-common'

export function getStatusBarStyle(backgroundColor: string): StatusBarStyle {
  if (Color(backgroundColor).isLight()) {
    return barStyleDark
  } else {
    return barStyleLight
  }
}

class CustomHeader extends PureComponent<CustomHeaderProps, void> {
  updateStatusBar() {
    if (this.props.isFocused) {
      const { backgroundColor } = this.props
      StatusBar.setBarStyle(getStatusBarStyle(this.props.backgroundColor), true)
      if (Platform.OS === 'android') {
        StatusBar.setBackgroundColor(this.props.backgroundColor)
      }
    }
  }

  componentDidMount() {
    this.updateStatusBar()
  }

  componentDidUpdate() {
    this.updateStatusBar()
  }

  render() {
    const {
      backgroundColor,
      children,
      centerComponent,
      outerContainerStyles,
      leftComponent,
      flatHeader,
      rightComponent,
      largeHeader,
      zeroBottomBorder,
      isFocused,
    } = this.props

    const ContainerStyles = StyleSheet.flatten([
      flatHeader ? style.zeroWidthBottomBorder : null,
    ])
    const borderStyles = StyleSheet.flatten([
      zeroBottomBorder ? style.zeroWidthBottomBorder : null,
    ])
    const barStyle = getStatusBarStyle(backgroundColor)
    const ToggleLargeHeader = largeHeader ? { top: 'always' } : { top: 'never' }

    const animated = true

    return (
      <SafeAreaView style={{ backgroundColor }} forceInset={ToggleLargeHeader}>
        <Header
          statusBarProps={
            isFocused ? { animated: true, barStyle, backgroundColor } : {}
          }
          backgroundColor={backgroundColor}
          outerContainerStyles={[
            outerContainerStyles,
            ContainerStyles,
            borderStyles,
          ]}
          centerComponent={centerComponent}
          leftComponent={leftComponent}
          rightComponent={rightComponent}
        >
          {children}
        </Header>
      </SafeAreaView>
    )
  }
}

export default withNavigationFocus(CustomHeader)


<|start_filename|>app/wallet/wallet-constants.js<|end_filename|>
// @flow

export const RECEIVE_TAB = 'receive'
export const SEND_TAB = 'send'
export const HISTORY_TAB = 'history'
export const RECEIVE_TAB_TEST_ID = 'wallet-tab-receive'
export const SEND_TAB_TEST_ID = 'wallet-tab-send'
export const HISTORY_TAB_TEST_ID = 'wallet-tab-history'
export const SEND_TOKEN_BUTTON = 'wallet-send-token-button'
export const SEND_TOKENS_TO_PAYMENT_ADDRESS = 'wallet-send-tokens-to-address'
export const TO_SEND_DETAILS_TEST_ID = 'to-send-details-test-id'
export const FOR_SEND_DETAILS_TEST_ID = 'for-send-details-test-id'

export const FONT_SIZE_MAPPING = (length: number) => {
  switch (true) {
    case length < 5:
      return 60
    case length < 7:
      return 60
    case length < 10:
      return 50
    case length < 12:
      return 40
    default:
      return 30
  }
}


<|start_filename|>app/components/qr-scanner/qr-url-validator.js<|end_filename|>
// @flow
import urlParse from 'url-parse'
import type { EnvironmentSwitchUrlQrCode } from './type-qr-scanner'

// allow only this domain to be a valid url for a qr code
// if we don't find this as host, then we don't consider it valid
export const validUrlQrCodeHost = 's3-us-west-2.amazonaws.com'

// only trust if scheme is https, http is not allowed
export const validUrlQrCodeScheme = 'https'

// value of path name should not exceed this length
export const validUrlQrCodeUrlPathLength = 50

// maximum length allowed for whole url-qr-code
export const validUrlQrCodeLength = 120

// allow only characters and dash
export const urlQrQueryParamAllowedRegex = /^[a-zA-Z\-]+$/

export function isValidUrlQrCode(
  urlQrCode: string
): EnvironmentSwitchUrlQrCode | boolean {
  if (urlQrCode.length > validUrlQrCodeLength) {
    return false
  }

  const { protocol, hostname, pathname } = urlParse(urlQrCode, {}, true)

  if (protocol !== `${validUrlQrCodeScheme}:`) {
    return false
  }

  if (hostname !== validUrlQrCodeHost) {
    return false
  }

  if (!pathname) {
    return false
  }

  const paths = pathname.split('/')

  // take the last path name and that would be treated as environment name
  const environmentName = paths[paths.length - 1]

  if (!environmentName) {
    return false
  }

  if (environmentName.length > validUrlQrCodeUrlPathLength) {
    return false
  }

  if (urlQrQueryParamAllowedRegex.test(environmentName) === false) {
    return false
  }

  return {
    url: urlQrCode,
    name: environmentName,
  }
}


<|start_filename|>app/app-status/app-status.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { AppState } from 'react-native'
import { getUnacknowledgedMessages } from './../store/config-store'
import { getRestoreStatus } from './../store/store-selector'
import type { Store } from './../store/type-store'
import { RestoreStatus } from '../restore/type-restore'
import type { AppStatusProps, AppStatusState } from './type-app-status'

class AppStatusComponent extends PureComponent<AppStatusProps, AppStatusState> {
  state = {
    appState: AppState.currentState,
  }

  componentDidMount() {
    AppState.addEventListener('change', this._handleAppStateChange)
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange)
  }

  _handleAppStateChange = nextAppState => {
    if (
      this.state.appState &&
      this.state.appState.match(/inactive|background/) &&
      nextAppState === 'active' &&
      (this.props.restoreStatus === RestoreStatus.none ||
        this.props.restoreStatus === RestoreStatus.RESTORE_DATA_STORE_SUCCESS)
    ) {
      this.props.getUnacknowledgedMessages()
    }
    this.setState({ appState: nextAppState })
  }

  render() {
    return null
  }
}

const mapStateToProps = (state: Store) => {
  return {
    restoreStatus: getRestoreStatus(state),
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      getUnacknowledgedMessages,
    },
    dispatch
  )

const AppStatus = connect(mapStateToProps, mapDispatchToProps)(
  AppStatusComponent
)

export default AppStatus


<|start_filename|>app/common/button-constants.js<|end_filename|>
// @flow
export const DENY = 'Deny'
export const CONNECT = 'Connect'


<|start_filename|>app/store/__tests__/hydration-store.spec.js<|end_filename|>
// @flow
import { put } from 'redux-saga/effects'
import { hydrate } from '../hydration-store'
import { hydrated } from '../config-store'

describe('hydration store should update dependant store correctly', () => {
  // TODO Write this test in proper way and check for all generators and values
  it('should raise correct action with correct data', () => {
    const gen = hydrate()

    gen.next()
    gen.next()
    gen.next()
    gen.next()
    gen.next()
    gen.next()

    expect(gen.next().value).toEqual(put(hydrated()))
  })
})


<|start_filename|>app/services/schema-validator.js<|end_filename|>
// @flow
import Ajv from 'ajv'

const ajv = new Ajv()

export default ajv


<|start_filename|>app/authentication/authentication.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, Text, Image } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { connectionRoute, homeRoute } from '../common'
import { getConnection } from '../store/connections-store'
import type { Store } from '../store/type-store'
import { Container, Request } from '../components'
import ConnectionSuccessModal from './connection-success-modal'
import {
  AUTHENTICATION_STATUS,
  resetAuthenticationStatus,
  sendUserAuthenticationResponse,
} from './authentication-store'
import type { Connection } from '../store/type-connection-store'

// TODO:KS Fix type for this screen, we are not using this screen
// as of now, so we will fix this later
class Authentication extends PureComponent<any, any> {
  state = {
    isModalVisible: false,
  }

  _showConnectionSuccessModal = (isModalVisible, route) => {
    this.setState({ isModalVisible })
    if (route) {
      this.props.navigation.navigate(route)
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.authentication.status != this.props.authentication.status) {
      if (
        !nextProps.authentication.isFetching &&
        nextProps.authentication.status === AUTHENTICATION_STATUS.ACCEPTED &&
        !nextProps.authentication.error
      ) {
        this.props.navigation.navigate(connectionRoute)
        this.props.resetAuthenticationStatus()
      } else if (
        !nextProps.authentication.isFetching &&
        (nextProps.authentication.status === AUTHENTICATION_STATUS.REJECTED ||
          nextProps.authentication.error)
      ) {
        this.props.navigation.navigate(homeRoute)
        this.props.resetAuthenticationStatus()
      }
    }
  }

  onUserResponse = (newStatus: string) => {
    let {
      type: authenticationType,
      data: { remoteConnectionId },
    } = this.props.authentication

    const { connections: { data: connectionsData } } = this.props
    // $FlowFixMe
    const connection: Connection[] = getConnection(
      remoteConnectionId,
      connectionsData
    )
    let { identifier } = connection[0]

    const challenge = JSON.stringify({
      newStatus,
    })

    this.props.sendUserAuthenticationResponse(
      {
        newStatus,
        identifier,
        remoteConnectionId,
        dataBody: {
          challenge,
        },
      },
      this.props.config,
      authenticationType
    )
  }

  render() {
    const { data } = this.props.authentication
    let offerMsgTitle = '',
      offerMsgText = '',
      logoUrl = null,
      name = ''

    if (data) {
      offerMsgTitle = data.offerMsgTitle
      offerMsgText = data.offerMsgText
      logoUrl = data.logoUrl
    }

    return (
      <Container>
        <Request
          title={offerMsgTitle}
          message={offerMsgText}
          senderLogoUrl={logoUrl}
          onAction={this.onUserResponse}
          navigation={this.props.navigation}
          showErrorAlerts={this.props.config.showErrorAlerts}
          testID="authentication-request"
          senderName={name}
        />
        <ConnectionSuccessModal
          isModalVisible={this.state.isModalVisible}
          showConnectionSuccessModal={this._showConnectionSuccessModal}
          name={name}
          logoUrl={logoUrl}
        />
      </Container>
    )
  }
}

const mapStateToProps = ({ authentication, connections, config }: Store) => ({
  authentication,
  connections,
  config,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      resetAuthenticationStatus,
      sendUserAuthenticationResponse,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(Authentication)


<|start_filename|>connectMeUITest/src/appModules/AppUtlis.java<|end_filename|>
package appModules;

import io.appium.java_client.AppiumDriver;
import pageObjects.GmailPage;
import pageObjects.HockeyAppPage;
import pageObjects.InvitationPage;
import pageObjects.PincodePage;
import utility.ErrorCodeMatcher;
import utility.InMemWalletType;
import utility.InitHelper;
import utility.StorageUtils;
import java.util.HashSet;
import org.bitcoinj.core.Base58;
import org.hyperledger.indy.sdk.pool.Pool;
import org.hyperledger.indy.sdk.signus.Signus;
import org.hyperledger.indy.sdk.signus.SignusJSONParameters;
import org.hyperledger.indy.sdk.signus.SignusResults.CreateAndStoreMyDidResult;
import org.hyperledger.indy.sdk.wallet.Wallet;
import org.testng.SkipException;
import org.hyperledger.indy.sdk.ErrorCode;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;


public class AppUtlis {
	
	public static boolean Success=false;
	LibIndy libindyObj=new LibIndy();
	RestApi restApiObj=new RestApi();
	public static String pairwiseVerkey,pairwiseDID;

	public  void RequestProvisioning(AppiumDriver driver,String Requestype) throws Exception
	
	{
		AppiumUtils.nClick(4,InvitationPage.Inviation_Text_Container(driver));
		if(Requestype=="Accept")
		{
			InvitationPage.Allow_Button(driver).click();

		}
		else
		{
		   InvitationPage.Deny_Button(driver).click();
		}
	}
	
	public void enterPincode(AppiumDriver driver) throws Exception
	{
		for(int i=0;i<6;i++)
		{
		PincodePage.PinCodeLock_TextBox(driver, i).sendKeys(String.valueOf(i));
		}
		
	}
	public void enterPincodeReverse(AppiumDriver driver) throws Exception
	{
		for(int i=0,j=1;i<6;i++,j++)
		{
		PincodePage.PinCodeLock_TextBox(driver, i).sendKeys(String.valueOf(j));
		}
	}
		
	
	
	public void CheckSkip() throws Exception
	{	if(!AppUtlis.Success)
		{
	    throw new SkipException("Skipping this exception");
		}
	   AppUtlis.Success=false;

		
	}
	
	public String sendSmsRestApi() throws Exception
    {
		
		 String pairwiseVerkey,pairwiseDID;
	     String result[];
	     result=libindyObj.createMyDid();
	     pairwiseVerkey=result[0];
	     pairwiseDID=result[1];
	     restApiObj.createPairwiseKey(pairwiseDID, pairwiseVerkey);
	     restApiObj.setProfileData(pairwiseDID,"<NAME>");
	     restApiObj.sendInvite(pairwiseDID, "D1234", "8327364896");
	     return pairwiseDID;
	}
	
	public void sendClaimofferRestApi(String pairwiseDID) throws Exception
    {
		
		restApiObj.sendClaimOffer(pairwiseDID);
	}
	public void sendClaimRestApi(String pairwiseDID) throws Exception
    {
		
		restApiObj.sendClaim(pairwiseDID);
	}
	
	public void sendProofRequestRestApi(String pairwiseDID) throws Exception
    {
		restApiObj.sendProofReq(pairwiseDID);

    }

}

<|start_filename|>app/home/bubbles.js<|end_filename|>
// @flow
import React, { PureComponent, Component } from 'react'
import {
  Animated,
  InteractionManager,
  Platform,
  Dimensions,
  StyleSheet,
  View,
} from 'react-native'
import { View as AnimationView } from 'react-native-animatable'
import { Avatar, CustomView } from '../components'
import { connectionHistoryRoute } from '../common/route-constants'
import showDID from '../components/show-pairwise-info'
import type {
  BubbleState,
  BubbleProps,
  BubblesProps,
  ConnectionBubblesState,
} from './type-home'
import { Dot as BadgeDot } from '../components/badges-dot'
import { checkIfAnimationToUse } from '../bridge/react-native-cxs/RNCxs'

export class Bubble extends PureComponent<BubbleProps, BubbleState> {
  state = {
    failed: false,
  }

  _onLoad = () => {
    this.setState({ failed: false })
  }

  _onError = () => {
    this.setState({ failed: true })
  }

  goHistoryView = (
    senderName: string,
    image: ?string,
    senderDID: string,
    identifier: string
  ) => {
    this.props.disableTopView()
    if (!this.props.disableTaps) {
      this.props.navigation.navigate(connectionHistoryRoute, {
        senderName,
        image,
        senderDID,
        identifier,
      })
    }
  }
  showHistory = () => {
    const {
      image,

      senderName,
      senderDID,
      identifier,
      allowInteractions,
    } = this.props
    if (allowInteractions) {
      this.goHistoryView(senderName, image, senderDID, identifier)
    }
  }
  render() {
    const {
      image,
      testID,
      senderName,
      senderDID,
      identifier,
      allowInteractions,
    } = this.props
    let source

    if (this.state.failed || Number.isInteger(image) || !image) {
      source = require('../images/logo_sovrin.png')
    }

    if (typeof this.props.image === 'string') {
      source = { uri: image }
    }

    return (
      <CustomView row>
        <View style={[badgeDotStyles.avatarBack]}>
          <Avatar
            radius={this.props.radius}
            src={source}
            onLoad={this._onLoad}
            onError={this._onError}
            testID={testID}
            onLongPress={() => showDID(senderDID, identifier)}
            onPress={this.showHistory}
          />
        </View>
        {/* TODO: the badge has to be put on a condition when there is any unread cred is pending inside this connection */}
        {this.props.showBadge ? (
          <CustomView style={[badgeDotStyles.badge]}>
            <BadgeDot size="medium" />
          </CustomView>
        ) : null}
      </CustomView>
    )
  }
}

const badgeDotStyles = StyleSheet.create({
  badge: {
    marginLeft: -20,
    zIndex: 1,
  },
  avatarBack: {
    zIndex: 0,
  },
})

export default class ConnectionBubbles extends PureComponent<
  BubblesProps,
  ConnectionBubblesState
> {
  state = {
    disableTaps: false,
    interactionsDone: false,
  }
  componentDidMount() {
    InteractionManager.runAfterInteractions(() => {
      this.setState({ interactionsDone: true })
    })
  }
  getBubblePosition = (
    bubbleIndex: number,
    deviceWidth: number,
    deviceHeight: number
  ) => {
    //returns top and left position of the connection bubble
    //based on the bubbleIndex the position is calculated

    //top position for 0th bubble
    let verticalOffset = deviceHeight * 0.58
    //left position for 0th bubble should be somewhere around the mid of the device
    //we are subtracting bubble radius to adjust the bubble width in the offset
    //so that center of bubble comes in mid
    let horizontalOffset = deviceWidth / 2 - deviceHeight / 16

    // we adjust the width and height of bubble just to calculate position
    // we need to adjust width because there will be only 3 bubbles in a row
    // but that row will also contain space between bubbles
    // and will also have margin on both side of screen horizontally
    // so, we assume that each bubble adjusted (margin+spacing+gutter space)
    // will be calculated by dividing device width in 3 columns
    // along with .5 as adjustment for (margin+spacing+gutter space)
    // so, suppose a bubble width is 80, and whole screen width would be 320 (iphone5)
    // then, considering space, margin, bubble width, adjustments would be
    // ~92
    const bubbleAdjustedWidth = deviceWidth / 3.5

    //we need to adjust bubbles in a column with some space in between
    //such that atleast 4 bubbles get adjusted
    //so if deviceHeight is 568 and
    //bubble container is having height 511(90%of deviceHeight)
    //bubbleAdjustedHeight will be 94
    const bubbleAdjustedHeight = deviceHeight / 6

    //add some more vertical offset to the columns on the left and right
    //since their top value is more than the middle column
    const edgeVerticalOffset = 50

    //calculate position of the bubble in its column
    let verticalRowIndex = Math.floor(bubbleIndex / 3)

    if (bubbleIndex % 3 === 2) {
      //calculating offsets for right hand side column
      horizontalOffset = horizontalOffset + bubbleAdjustedWidth
      verticalOffset = verticalOffset + edgeVerticalOffset
    } else if (bubbleIndex % 3 === 1) {
      //calculating offsets for left hand side column
      horizontalOffset = horizontalOffset - bubbleAdjustedWidth
      verticalOffset = verticalOffset + edgeVerticalOffset
    }

    return {
      //note that based on the verticalRowIndex we need to
      //adjust the top of the bubble
      top: Math.floor(verticalOffset - verticalRowIndex * bubbleAdjustedHeight),
      left: Math.floor(horizontalOffset),
    }
  }

  getBubbleContainerHeight = (deviceHeight: number) => {
    return {
      height: 90 * deviceHeight / 100,
    }
  }

  disableViewTaps = () => {
    this.setState({
      disableTaps: true,
    })
    setTimeout(() => {
      this.setState({
        disableTaps: false,
      })
    }, 500)
  }

  render() {
    let { width, height } = Dimensions.get('window')
    //Adjusting height in android due to navigational bar
    height = Platform.OS === 'ios' ? height : height - 44
    let deviceClass = ''

    if (Platform.OS === 'ios') {
      deviceClass =
        width === 320 ? 'Iphone5' : width === 414 ? 'IphonePlus' : 'ios'
    }

    const enterprises = [
      'evernym',
      'ebay',
      'verizon',
      'suncoast',
      'dell',
      'bh',
      'dillard',
      'edcu',
      'agency',
    ]
    const connections = this.props.connections.map((connection, index) => {
      let showBadge =
        this.props.unSeenMessages[connection.senderDID] &&
        this.props.unSeenMessages[connection.senderDID].length > 0
          ? true
          : false
      return {
        ...connection,
        name: enterprises[index] || 'verizon',
        index,
        showBadge,
      }
    })

    return (
      <Animated.View
        style={[
          styles.bubbleContainer,
          this.getBubbleContainerHeight(height),
          { transform: [{ translateY: this.props.height }] },
        ]}
      >
        {connections.map(
          ({
            identifier,
            name,
            logoUrl,
            size,
            senderName,
            senderDID,
            index,
            showBadge,
          }) => (
            <AnimationView
              animation="zoomIn"
              // TODO: SC, need to change to duration={600} delay={200} and for lower end devices have to change the duration accordingly
              duration={checkIfAnimationToUse() ? 20 : 200}
              delay={checkIfAnimationToUse() ? 60 : 600}
              style={[
                styles.avatar,
                this.getBubblePosition(index, width, height),
              ]}
              key={identifier}
            >
              <Bubble
                radius={Math.floor(height / 16)}
                size={size}
                image={logoUrl}
                testID={`bubble-${identifier}`}
                senderName={senderName}
                senderDID={senderDID}
                identifier={identifier}
                navigation={this.props.navigation}
                disableTopView={this.disableViewTaps}
                disableTaps={this.state.disableTaps}
                allowInteractions={this.state.interactionsDone}
                showBadge={showBadge}
              />
            </AnimationView>
          )
        )}
      </Animated.View>
    )
  }
}

const styles = StyleSheet.create({
  bubbleContainer: {
    position: 'absolute',
    top: -70,
    left: 0,
    right: 0,
    overflow: 'hidden',
    zIndex: -1,
  },
  avatar: {
    position: 'absolute',
  },
  avatarImage: {
    resizeMode: 'contain',
  },
})


<|start_filename|>app/components/qr-scanner/type-qr-scanner.js<|end_filename|>
// @flow
import type { InvitationPayload } from '../../invitation/type-invitation'

export const SCAN_STATUS = {
  SCANNING: 'scanning...',
  SUCCESS: 'Success!',
  FAIL: 'QR code format is invalid.',
  DOWNLOADING_INVITATION: 'Downloading invitation...',
  NO_INVITATION_DATA: 'No message found behind this QR code.',
}

export type QrCode = {
  id: string,
  s: {
    n: string,
    dp: {
      d: string,
      k: string,
      s: string,
    },
    d: string,
    l: string,
    v: string,
  },
  sa: {
    d: string,
    v: string,
    e: string,
  },
  t: string,
}

type ValuesType = <V>(v: V) => V

type QR_SCAN_STATUS =
  | typeof SCAN_STATUS.SCANNING
  | typeof SCAN_STATUS.FAIL
  | typeof SCAN_STATUS.SUCCESS
  | typeof SCAN_STATUS.DOWNLOADING_INVITATION
  | typeof SCAN_STATUS.NO_INVITATION_DATA

export type QrScannerState = {
  scanning: boolean,
  scanStatus: QR_SCAN_STATUS,
  cameraActive?: boolean,
}

export type QrScannerProps = {
  onRead: QrCode => void,
  onClose: () => void,
  onEnvironmentSwitchUrl: EnvironmentSwitchUrlQrCode => void,
  onInvitationUrl: InvitationPayload => void,
}

export type CameraMarkerProps = {
  status: QR_SCAN_STATUS,
  onClose: () => void,
}

export const TOP_LEFT = 'topLeft'
export const TOP_RIGHT = 'topRight'
export const BOTTOM_LEFT = 'bottomLeft'
export const BOTTOM_RIGHT = 'bottomRight'

export type CornerBoxProps = {
  status: QR_SCAN_STATUS,
  position:
    | typeof TOP_LEFT
    | typeof TOP_RIGHT
    | typeof BOTTOM_LEFT
    | typeof BOTTOM_RIGHT,
}

export type EnvironmentSwitchUrlQrCode = {
  url: string,
  name: string,
}

export type InvitationUrlQrCode = {
  url: string,
}


<|start_filename|>app/wallet/payment-failure-modal.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Platform } from 'react-native'
import {
  CustomView,
  Icon,
  CustomText,
  CustomButton,
  Container,
} from '../components'
import {
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_6X,
  OFFSET_7X,
  color,
  HAIRLINE_WIDTH,
  whiteSmoke,
} from '../common/styles/constant'
import Modal from 'react-native-modal'

type PaymentFailureModalProps = {
  testID: string,
  onClose: () => void,
  onRetry: (event: any) => void,
  connectionName: string,
}

export default class PaymentFailureModal extends PureComponent<
  PaymentFailureModalProps,
  void
> {
  render() {
    const { testID, onClose } = this.props
    return (
      <CustomView fifth shadow style={[styles.container]}>
        <CustomView spaceBetween style={[styles.innerContainer]}>
          <Icon
            iconStyle={[{ margin: 10 }]}
            src={require('../images/alertInfo.png')}
            extraLarge
            center
            resizeMode="contain"
            testID={`${testID}-modal-header-icon`}
          />
          <CustomText
            h5
            center
            tertiary
            bg="tertiary"
            transparentBg
            style={[styles.message]}
            demiBold
            testID={`${testID}-modal-title`}
          >
            {'Payment Failure'}
          </CustomText>
          <CustomText
            h5
            center
            tertiary
            bg="tertiary"
            transparentBg
            style={[styles.message]}
            demiBold
            testID={`${testID}-modal-content`}
          >
            {`Something went wrong trying to pay ${
              this.props.connectionName
            }. Please try again.`}
          </CustomText>
        </CustomView>
        <CustomView row>
          <Container>
            <CustomButton
              fifth
              onPress={onClose}
              title={'Cancel'}
              testID={`${testID}-modal-cancel`}
              textStyle={{ fontWeight: 'bold' }}
            />
          </Container>
          <Container>
            <CustomButton
              fifth
              onPress={this.props.onRetry}
              title={'Retry'}
              testID={`${testID}-modal-retry`}
              textStyle={{ fontWeight: 'bold' }}
            />
          </Container>
        </CustomView>
      </CustomView>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    marginHorizontal: OFFSET_3X,
  },
  innerContainer: {
    ...Platform.select({
      ios: {
        borderBottomColor: color.bg.fifth.font.tertiary,
        borderBottomWidth: HAIRLINE_WIDTH,
      },
      android: {
        borderBottomColor: color.bg.fifth.font.secondary,
        borderBottomWidth: 1,
      },
    }),
    padding: OFFSET_2X,
  },
  message: {
    marginBottom: OFFSET_1X / 2,
  },
})


<|start_filename|>app/claim-offer/__tests__/claim-request-modal.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { ClaimRequestStatusModal } from '../claim-request-modal'
import { CLAIM_REQUEST_STATUS } from '../type-claim-offer'
import type { ClaimRequestStatusModalProps } from '../type-claim-offer'
import {
  claimOfferPayload,
  senderLogoUrl,
  getStore,
} from '../../../__mocks__/static-data'

describe('<ClaimRequestStatusModal />', () => {
  const store = getStore()

  function getProps(props) {
    return {
      onContinue: jest.fn(),
      payload: claimOfferPayload,
      senderLogoUrl,
      claimRequestStatus: CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_SUCCESS,
      onModalHide: jest.fn(),
      ...props,
    }
  }

  function getWrapper(props) {
    return renderer.create(
      <Provider store={store}>
        <ClaimRequestStatusModal {...props} />
      </Provider>
    )
  }

  function setup(extraProps) {
    const props = getProps(extraProps)
    const wrapper = getWrapper(props)
    const instance = wrapper.root.findByType(ClaimRequestStatusModal).instance

    return { props, wrapper, instance }
  }

  function getPaidClaimProps() {
    return {
      payTokenValue: '1<PASSWORD>',
      message1: 'You paid',
      message3: '',
      message6: 'They will issue it to you shortly.',
    }
  }

  it('should show check mark, you accepted text, if claim request is sent', () => {
    const message = {
      message1: 'You accepted',
      message3: 'from',
      message5: '!',
    }
    const { wrapper } = setup(message)
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should match snapshot when pending popOver', () => {
    const extraProps = {
      message1: 'As soon as ',
      message3: ' signs and issues ',
      message5: ' to you it will appear here',
      isPending: true,
    }
    const { wrapper } = setup(extraProps)
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should show arrow right and only Paying text if paid credential request is being sent', () => {
    const paidClaimProps = getPaidClaimProps()
    const extraProps = {
      claimRequestStatus: CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST,
      isPending: true,
      ...paidClaimProps,
    }
    const { wrapper } = setup(extraProps)
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should show check mark, token amount, if paid credential request is sent', () => {
    const paidClaimProps = getPaidClaimProps()
    const extraProps = {
      claimRequestStatus: CLAIM_REQUEST_STATUS.PAID_CREDENTIAL_REQUEST_SUCCESS,
      ...paidClaimProps,
    }
    const { wrapper } = setup(extraProps)
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should show arrow right and accepting text, if claim request is being sent', () => {
    const extraProps = {
      message1: 'You accepted',
      message3: 'from',
      message6: '',
      claimRequestStatus: CLAIM_REQUEST_STATUS.SENDING_CLAIM_REQUEST,
    }
    const { wrapper } = setup(extraProps)
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should hideModal if continue is clicked', () => {
    const extraProps = {
      message1: 'You accepted ',
      message3: 'from',
      message5: '!',
    }
    const { wrapper, instance } = setup(extraProps)
    instance.onContinue()
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should match paid credential success, if sending state changes to success', () => {
    const paidClaimProps = getPaidClaimProps()
    const extraProps = {
      claimRequestStatus: CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST,
      isPending: true,
      ...paidClaimProps,
    }
    const { wrapper, props } = setup(extraProps)
    // update component so that state changes from sending paid credential
    // to paid credential success
    wrapper.update(
      <Provider store={store}>
        <ClaimRequestStatusModal
          {...{
            ...props,
            isPending: false,
            claimRequestStatus:
              CLAIM_REQUEST_STATUS.PAID_CREDENTIAL_REQUEST_SUCCESS,
          }}
        />
      </Provider>
    )
    expect(wrapper.toJSON()).toMatchSnapshot()
  })
})


<|start_filename|>app/expired-token/expired-token.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, Image, StyleSheet } from 'react-native'
import { Container, CustomView, CustomText, CustomButton } from '../components'
import { isBiggerThanShortDevice, grey, color } from '../common/styles'
import { homeRoute } from '../common'
import type { ReactNavigation } from '../common/type-common'

export default class ExpiredToken extends PureComponent<ReactNavigation, void> {
  okClicked = false

  onOk = () => {
    if (!this.okClicked) {
      this.props.navigation.navigate(homeRoute)
      this.okClicked = true
    }
  }

  render() {
    return (
      <Container fifth>
        <Container center>
          <CustomView vCenter>
            <Image
              style={styles.connectMeLogo}
              source={require('../images/logo_connectme.png')}
              resizeMode="contain"
            />
          </CustomView>
          <CustomView vCenter style={[styles.textContainer]}>
            <CustomText transparentBg primary h1 style={[styles.sorryText]}>
              Sorry!
            </CustomText>
            <CustomText transparentBg primary h3 bold center>
              This invitation has expired!
            </CustomText>
          </CustomView>
        </Container>
        <CustomView safeArea style={[styles.okButtonContainer]}>
          <CustomButton
            testID="expired-token-ok"
            title="Ok"
            primary
            medium
            fontWeight="600"
            large={isBiggerThanShortDevice ? true : false}
            onPress={this.onOk}
            style={[styles.okButton]}
          />
        </CustomView>
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  expiredTokenContainer: {
    paddingTop: 30,
  },
  sovrinLogo: {
    width: 90,
    height: 90,
  },
  connectMeLogo: {
    width: 200,
  },
  textContainer: {
    paddingTop: 30,
  },
  sorryText: {
    paddingBottom: 20,
  },
  okButtonContainer: {
    marginBottom: 15,
    marginLeft: '5%',
    marginRight: '5%',
  },
  okButton: {
    borderRadius: 5,
    height: isBiggerThanShortDevice ? 53 : 43,
  },
})


<|start_filename|>app/backup/backup-complete.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { Image, Dimensions } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import {
  Container,
  CustomView,
  CustomText,
  Icon,
  CustomButton,
  CustomHeader,
} from '../components'
import { backupCompleteRoute } from '../common'
import {
  isBiggerThanVeryShortDevice,
  isBiggerThanShortDevice,
} from '../common/styles'
import { color } from '../common/styles/constant'
import type { BackupCompleteProps, BackupCompleteState } from './type-backup'
import {
  BACKUP_COMPLETE_CLOSE_TEST_ID,
  BACKUP_COMPLETE_SUBMIT_BUTTON,
  BACKUP_COMPLETE_SUBMIT_BUTTON_TITLE,
} from './backup-constants'
import styles from './styles'

const transparentBands = require('../images/transparentBands.png')
const closeImage = require('../images/iconClose.png')
// TODO: use real asset
const successCheck = require('../images/successCheck.png')

export class BackupComplete extends PureComponent<BackupCompleteProps, void> {
  backupComplete = () => {
    const { navigation: { navigate, state, goBack } } = this.props

    return navigate(state.params.initialRoute)
  }

  static navigationOptions = ({ navigation: { navigate, state } }) => ({
    header: (
      <CustomHeader
        backgroundColor={color.bg.fourteenth.color}
        largeHeader
        flatHeader
      >
        <CustomView style={[styles.headerSpacer]} />

        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => navigate(state.params.initialRoute)}
            testID={BACKUP_COMPLETE_CLOSE_TEST_ID}
            iconStyle={[styles.headerIcon]}
            src={closeImage}
          />
        </CustomView>
      </CustomHeader>
    ),
    gesturesEnabled: false,
  })

  render() {
    return (
      <Container style={[styles.backupComplete]} safeArea>
        <Image source={transparentBands} style={[styles.backgroundImage]} />
        <Container style={[styles.wrapper]}>
          <Container>
            <CustomView center>
              <CustomText transparentBg center style={[styles.title]}>
                Backup complete
              </CustomText>
            </CustomView>
            <CustomView center>
              <Image source={successCheck} />
            </CustomView>
            <CustomView horizontalSpace>
              <CustomView
                verticalSpace
                doubleVerticalSpace={isBiggerThanVeryShortDevice ? true : false}
              >
                <CustomText
                  transparentBg
                  center
                  style={styles.backupCompleteText}
                >
                  If you ever have to start with a new installation of
                  Connect.Me you will need to recover from this saved backup
                  file.
                </CustomText>
              </CustomView>
              <CustomView
                doubleVerticalSpace={isBiggerThanVeryShortDevice ? true : false}
              >
                <CustomText
                  transparentBg
                  center
                  style={styles.backupCompleteText}
                >
                  You will be asked to enter your Recovery Phrase during setup
                  of your new Connect.Me application.
                </CustomText>
              </CustomView>
            </CustomView>
          </Container>
          <CustomButton
            large={isBiggerThanShortDevice ? true : false}
            onPress={this.backupComplete}
            testID={BACKUP_COMPLETE_SUBMIT_BUTTON}
            style={[styles.submitButton]}
            customColor={{
              color: color.bg.fourteenth.color,
              fontWeight: '600',
              fontSize: 18,
            }}
            title={BACKUP_COMPLETE_SUBMIT_BUTTON_TITLE}
          />
        </Container>
      </Container>
    )
  }
}

export default createStackNavigator({
  [backupCompleteRoute]: {
    screen: BackupComplete,
  },
})


<|start_filename|>app/components/qr-scanner/__tests__/qr-invitation-url-validator.spec.js<|end_filename|>
// @flow

import { isValidInvitationUrl } from '../qr-invitation-url-validator'

describe('fn:isValidInvitationUrl', () => {
  // creating variables in test, so that our tests break if someone changes
  const validOrigin = `https://some-domain.com/token`

  it('should return url, when url is valid', () => {
    const urlQrCode = `${validOrigin}`
    expect(isValidInvitationUrl(urlQrCode)).toEqual({
      url: urlQrCode,
    })
  })

  it('should return false, if we pass longer url than allowed', () => {
    const urlQrCode = `${validOrigin}/${'x'.repeat(2049)}`
    expect(isValidInvitationUrl(urlQrCode)).toBe(false)
  })

  it('should return correct url, if protocol is http', () => {
    const urlQrCode = `http://some.com/dev`
    expect(isValidInvitationUrl(urlQrCode)).toEqual({
      url: urlQrCode,
    })
  })

  it('should return false, if protocol is neither http or https', () => {
    const urlQrCode = `mail://some.com/dev`
    expect(isValidInvitationUrl(urlQrCode)).toBe(false)
  })
})


<|start_filename|>app/backup/secure-passphrase.js<|end_filename|>
// @flow
import { NativeModules } from 'react-native'
const { RNRandomBytes } = NativeModules
import diceware from './eff.js'
const Buffer = require('buffer/').Buffer

// See : https://www.reddit.com/r/crypto/comments/4xe21s/
//
// skip is to make result in this range:
// 0 ≤ result < n* count < 2^31
// (where n is the largest integer that satisfies this equation)
// This makes result % count evenly distributed.
//
// P.S. if (((count - 1) & count) === 0) {...} is optional and for
// when count is a nice binary number (2n). If this if statement is
// removed then it might have to loop a few times. So it saves a
// couple of micro seconds.
export const secureRandom = async (count: number = 6) => {
  const skip = 0x7fffffff - 0x7fffffff % count
  let result
  const numBytes = 64

  const randomBytes = () => {
    return new Promise(function(resolve, reject) {
      RNRandomBytes.randomBytes(numBytes, (err: any, bytes: string) => {
        if (err) {
          reject(err)
        } else {
          //let decoded = atob(bytes)
          const decoded = Buffer.from(bytes, 'base64')
          //console.log("decoded.byteLength: ", decoded.byteLength)
          resolve(decoded)
        }
      })
    })
  }

  let randIndex = numBytes
  let randVals = []
  do {
    if (randIndex >= numBytes) {
      randVals = await randomBytes()
      randIndex = 0
    }
    const randVal = randVals[randIndex++] //.charCodeAt(0)
    result = randVal & 0x7fffffff
  } while (result >= skip)

  return result % count
}

export const getWords = async (
  numWords: number = 12,
  numRollsPerWord: number = 5
) => {
  //'use strict'

  let i, j, words, rollResults, rollResultsJoined

  words = []

  if (!numWords) {
    numWords = 1
  }
  if (!numRollsPerWord) {
    numRollsPerWord = 5
  }

  for (i = 0; i < numWords; i += 1) {
    rollResults = []

    for (j = 0; j < numRollsPerWord; j += 1) {
      // roll a 6 sided die
      const randVal = await secureRandom(6)
      rollResults.push(randVal + 1)
    }

    rollResultsJoined = rollResults.join('')
    words.push(diceware[rollResultsJoined])
  }

  return words
}


<|start_filename|>app/wallet/__tests__/wallet-tab-send-details.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { WalletTabSendDetails } from '../wallet-tab-send-details'
import { getStore } from '../../../__mocks__/static-data'
import { getNavigation, smsToken } from '../../../__mocks__/static-data'
import { STORE_STATUS } from '../type-wallet'

describe('<WalletTabSendDetails />', () => {
  const store = getStore()
  let navigation = {
    ...getNavigation(),
  }

  function setup() {
    const component = renderer.create(
      <Provider store={store}>
        <WalletTabSendDetails
          tokenAmount="12345"
          tokenSentStatus={STORE_STATUS.SUCCESS}
          navigation={navigation}
          sendTokens={jest.fn()}
        />
      </Provider>
    )
    const instance = component.root.findByType(WalletTabSendDetails).instance
    return { component, instance }
  }

  it('should render properly and match the snapshot', () => {
    const { component, instance } = setup()
    instance.onTextChange('pay:sov:somepaymentaddress', 'paymentTo')
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/home/type-home.js<|end_filename|>
// @flow
import type { ReactNavigation } from '../common/type-common'
import type {
  ConnectionStore,
  Connection,
} from '../store/type-connection-store'

export type BubbleProps = {
  size: number,
  image: ?string,
  testID: string,
  senderName: string,
  senderDID: string,
  radius: number,
  identifier: string,
  disableTaps: boolean,
  disableTopView: () => void,
  allowInteractions: boolean,
  showBadge: boolean,
} & ReactNavigation

export type BubbleState = {
  failed: boolean,
}

export type BubblesProps = {
  connections: Array<Connection>,
  height: number,
  unSeenMessages: {
    [string]: [string],
  },
} & ReactNavigation

export type HomeProps = {
  connections: ConnectionStore,
  unSeenMessages: {
    [string]: [string],
  },
} & ReactNavigation

export type HomeState = {
  // Don't have react-native Animated API type definition
  scrollY: any,
}

export type ConnectionBubblesState = {
  disableTaps: boolean,
  interactionsDone: boolean,
}


<|start_filename|>app/settings/settings-constant.js<|end_filename|>
// @flow
export const EDIT_ICON_DIMENSIONS = 30
export const PASS_CODE_ASTERISK_TOP_OFFSET = 5
export const USERNAME_TEST_ID = 'settings-user-name-label'
export const PASS_CODE_TEST_ID = 'settings-pass-code-label'
export const PASS_CODE_ASTERISK_TEST_ID = 'settings-pass-code-asterisk-label'
export const TOUCH_ID_TEST_ID = 'settings-touch-id-label'
export const CHAT_TEST_ID = 'settings-chat-id-label'
export const USER_AVATAR_TEST_ID = 'settings-user-avatar-label'
export const BACKUP_DATA_WALLET = 'settings-backup-data-wallet'
export const ABOUT_APP_TEST_ID = 'settings-about-app-label'


<|start_filename|>app/connection/connection-info.js<|end_filename|>
// @flow
import React from 'react'
import { View, Text } from 'react-native'
import { CustomView } from '../components'

const labelSuncoastInfo = <Text>SUNCOAST INFO</Text>

// TODO:KS Move it to redux action
const connectionInfo = [
  {
    id: 'info1',
    name: 'SUNCOAST MEMBER NUMBER',
    data: '25269755',
  },
  {
    id: 'info2',
    name: 'MEMBER SINCE',
    data: '2009',
  },
  {
    id: 'info3',
    name: '<NAME>',
    data: '86',
  },
]

export default () => <CustomView />


<|start_filename|>app/navigator.js<|end_filename|>
// @flow
import React from 'react'
import { StyleSheet, Animated, Easing } from 'react-native'
import {
  createStackNavigator,
  TabBarBottom,
  createTabNavigator,
} from 'react-navigation'
import AboutApp from './about-app/about-app'
import AuthenticationScreen from './authentication/authentication'
import HomeScreen from './home/home'
import ConnectionHome from './connection/connection'
import SplashScreenView from './authentication/splash-screen'
import Settings from './settings/settings'
import ExpiredTokenScreen from './expired-token/expired-token'
import QRCodeScanner from './qr-code/qr-code'
import LockSelectionScreen from './lock/lock-selection'
import LockEnterPinScreen from './lock/lock-enter-pin-code'
import LockTouchIdSetupScreen from './lock/lock-fingerprint-setup'
import LockPinCodeSetupScreen from './lock/lock-pin-code-setup'
import LockSetupSuccessScreen from './lock/lock-setup-success'
import LockEnterFingerprintScreen from './lock/lock-enter-fingerprint'
import ClaimOffer from './claim-offer/claim-offer'
import ProofRequestScreen from './proof-request/proof-request'
import InvitationScreen from './invitation/invitation'
import ConnectionHistoryNavigator from './connection-history/connection-history-navigator'
import SwitchEnvironmentScreen from './switch-environment/switch-environment'
import LockAuthorization from './lock/lock-authorization'
import WaitForInvitationScreen from './invitation/wait-for-invitation'
import Wallet from './wallet/wallet'
import GenerateRecoveryPhrase from './backup/generate-phrase'
import VerifyRecoveryPhrase from './backup/verify-phrase'
import ExportBackupFile from './backup/export-backup'
import BackupComplete from './backup/backup-complete'
import BackupErrorScreen from './backup/backup-error'
import WalletTabs from './wallet/wallet-tabs'
import { Icon } from './components'
import {
  splashScreenRoute,
  homeRoute,
  authenticationRoute,
  connectionRoute,
  connectionHistoryRoute,
  expiredTokenRoute,
  lockEnterPinRoute,
  lockSelectionRoute,
  lockPinSetupRoute,
  lockTouchIdSetupRoute,
  lockSetupSuccessRoute,
  lockEnterFingerprintRoute,
  claimOfferRoute,
  homeTabRoute,
  settingsTabRoute,
  qrCodeScannerTabRoute,
  proofRequestRoute,
  invitationRoute,
  switchEnvironmentRoute,
  lockAuthorizationRoute,
  waitForInvitationRoute,
  walletRoute,
  aboutAppRoute,
  walletTabSendDetailsRoute,
  eulaRoute,
  genRecoveryPhraseRoute,
  verifyRecoveryPhraseRoute,
  exportBackupFileRoute,
  backupCompleteRoute,
  restoreRoute,
  restoreWaitRoute,
  restorePassphraseRoute,
  backupErrorRoute,
} from './common/'
import { color } from './common/styles'
import WalletTabSendDetails from './wallet/wallet-tab-send-details'
import EulaScreen from './eula/eula'
import RestoreStartScreen from './restore/restore'
import RestoreWaitScreen from './restore/restore-wait'
import RestorePassphrase from './restore/restore-passphrase'
import { checkIfAnimationToUse } from './bridge/react-native-cxs/RNCxs'

if (__DEV__) {
  require('../tools/reactotron-config')
}

const styles = StyleSheet.create({
  tabBarContainer: {
    backgroundColor: color.bg.tertiary.color,
    borderTopWidth: 0,
  },
})

const Tabs = createTabNavigator(
  {
    [homeTabRoute]: {
      screen: HomeScreen,
      navigationOptions: {
        tabBarTestIDProps: {
          testID: 'tab-bar-home-icon',
          accessible: true,
          accessibleLabel: 'tab-bar-home-icon',
          accessibilityLabel: 'tab-bar-home-icon',
        },
        tabBarIcon: ({ focused }) => {
          return focused ? (
            <Icon src={require('./images/dashboard_large.png')} mediumLarge />
          ) : (
            <Icon src={require('./images/dashboard.png')} medium />
          )
        },
      },
    },
    [settingsTabRoute]: {
      screen: Settings,
      navigationOptions: {
        tabBarTestIDProps: {
          testID: 'tab-bar-settings-icon',
          accessible: true,
          accessibleLabel: 'tab-bar-settings-icon',
          accessibilityLabel: 'tab-bar-settings-icon',
        },
        tabBarIcon: ({ focused }) => {
          return focused ? (
            <Icon src={require('./images/settings_large.png')} mediumLarge />
          ) : (
            <Icon src={require('./images/settings.png')} medium />
          )
        },
      },
    },
    [qrCodeScannerTabRoute]: {
      screen: QRCodeScanner,
      navigationOptions: {
        tabBarTestIDProps: {
          testID: 'tab-bar-qrcode-icon',
          accessible: true,
          accessibleLabel: 'tab-bar-qrcode-icon',
          accessibilityLabel: 'tab-bar-qrcode-icon',
        },
        tabBarVisible: false,
        tabBarIcon: () => {
          return <Icon src={require('./images/addConnection.png')} medium />
        },
      },
    },
  },
  {
    animationEnabled: true,
    swipeEnabled: true,
    lazy: false,
    initialRouteName: homeTabRoute,
    order: [settingsTabRoute, homeTabRoute, qrCodeScannerTabRoute],
    tabBarOptions: {
      showLabel: false,
      style: styles.tabBarContainer,
    },
    tabBarComponent: TabBarBottom,
    tabBarPosition: 'bottom',
  }
)

const CardStack = createStackNavigator(
  {
    [splashScreenRoute]: {
      screen: SplashScreenView,
    },
    [homeRoute]: {
      screen: Tabs,
    },
    [authenticationRoute]: {
      screen: AuthenticationScreen,
    },

    [connectionRoute]: {
      screen: ConnectionHome,
    },
    [expiredTokenRoute]: {
      screen: ExpiredTokenScreen,
    },
    [invitationRoute]: {
      screen: InvitationScreen,
    },
    [lockSelectionRoute]: {
      screen: LockSelectionScreen,
    },
    [lockEnterPinRoute]: {
      screen: LockEnterPinScreen,
    },
    [lockPinSetupRoute]: {
      screen: LockPinCodeSetupScreen,
    },
    [lockTouchIdSetupRoute]: {
      screen: LockTouchIdSetupScreen,
    },
    [lockSetupSuccessRoute]: {
      screen: LockSetupSuccessScreen,
    },
    [lockEnterFingerprintRoute]: {
      screen: LockEnterFingerprintScreen,
    },
    [switchEnvironmentRoute]: {
      screen: SwitchEnvironmentScreen,
    },
    [waitForInvitationRoute]: {
      screen: WaitForInvitationScreen,
    },
    [eulaRoute]: {
      screen: EulaScreen,
    },
    [restoreRoute]: {
      screen: RestoreStartScreen,
    },
    [restorePassphraseRoute]: {
      screen: RestorePassphrase,
    },
    [restoreWaitRoute]: {
      screen: RestoreWaitScreen,
    },
    [backupErrorRoute]: { screen: BackupErrorScreen },
    [genRecoveryPhraseRoute]: { screen: GenerateRecoveryPhrase },
    [verifyRecoveryPhraseRoute]: { screen: VerifyRecoveryPhrase },
    [exportBackupFileRoute]: { screen: ExportBackupFile },
    [backupCompleteRoute]: { screen: BackupComplete },
  },
  {
    headerMode: 'none',
    initialRouteName: splashScreenRoute,
    navigationOptions: {
      gesturesEnabled: false,
    },
  }
)

const transitionConfig = () => {
  return {
    transitionSpec: {
      duration: checkIfAnimationToUse() ? 30 : 300,
      easing: Easing.out(Easing.poly(4)),
      timing: Animated.timing,
      useNativeDriver: true,
    },
    screenInterpolator: sceneProps => {
      const { layout, position, scene } = sceneProps

      const thisSceneIndex = scene.index
      const height = layout.initHeight
      const width = layout.initWidth

      const scale = position.interpolate({
        inputRange: [thisSceneIndex - 1, thisSceneIndex - 0.7, thisSceneIndex],
        outputRange: [0.5, 0.7, 1],
      })

      const opacity = position.interpolate({
        inputRange: [thisSceneIndex - 1, thisSceneIndex - 0.5, thisSceneIndex],
        outputRange: [0, 0.3, 1],
      })

      return {
        opacity,
        transform: [{ scale }],
      }
    },
  }
}

// TODO:KS create a custom navigator to track page changes
// for flows to support deep link, etc.
const ConnectMeAppNavigator = createStackNavigator(
  {
    CardStack: { screen: CardStack },
    [claimOfferRoute]: { screen: ClaimOffer },
    [lockAuthorizationRoute]: { screen: LockAuthorization },
    [proofRequestRoute]: {
      screen: ProofRequestScreen,
    },
    [connectionHistoryRoute]: {
      screen: ConnectionHistoryNavigator,
    },
    [walletRoute]: { screen: Wallet },
    [walletTabSendDetailsRoute]: {
      screen: WalletTabSendDetails,
    },
  },
  {
    mode: 'modal',
    headerMode: 'none',
    transitionConfig,
  }
)

let navigator = ConnectMeAppNavigator

// Temporary disabled
// Reason:
// Ref to ConnectMeAppNavigator on App component was not working as expected

if (__DEV__) {
  // Tried to extend console interface, but it didn't work
  // need to fix, so ignoring error for now
  // `FlowFixMe`
  // navigator = console.tron.overlay(navigator)
}

export default navigator


<|start_filename|>app/components/pin-code/type-pin-code-box.js<|end_filename|>
// @flow
export type PinCodeDigitProps = {
  entered: boolean,
  testID?: ?string,
  onPress: () => void,
}

export type PinCodeBoxProps = {
  onPinComplete: (pin: string) => void,
  enableCustomKeyboard?: boolean,
}

export type PinCodeBoxState = {
  pin: string,
}

export type TextInputRef = {
  clear: () => void,
  isFocused: () => boolean,
  focus: () => void,
  blur: () => void,
}


<|start_filename|>app/components/user-avatar/user-avatar.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Image, TouchableWithoutFeedback, View, Platform } from 'react-native'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import RNFetchBlob from 'react-native-fetch-blob'

import { Icon } from '../index'

import { selectUserAvatar } from '../../store/user/user-store'
import { getUserAvatarSource } from '../../store/store-selector'

import type { UserAvatarProps } from './type-user-avatar'
import type { Store } from '../../store/type-store'

const defaultAvatar = require('../../images/UserAvatar.png')

export class UserAvatar extends PureComponent<UserAvatarProps, void> {
  changeAvatar = () => {
    if (!this.props.userCanChange) {
      return
    }

    this.props.selectUserAvatar()
  }

  render() {
    let avatarSource = this.props.avatarName || defaultAvatar

    if (this.props.children) {
      // if we are using children as render prop
      // then we want user of the component to specify what to render
      return (
        <TouchableWithoutFeedback
          testID={this.props.testID}
          accessible={true}
          accessibilityLabel={this.props.testID}
          onPress={this.changeAvatar}
        >
          <View pointerEvents="box-only">
            {this.props.children(avatarSource)}
          </View>
        </TouchableWithoutFeedback>
      )
    }

    return (
      <Icon
        src={avatarSource}
        onPress={this.changeAvatar}
        extraLarge
        round
        resizeMode="cover"
        testID="user-avatar"
      />
    )
  }
}

const mapStateToProps = (state: Store) => ({
  avatarName: getUserAvatarSource(state.user.avatarName),
})

const mapDispatchToProps = dispatch =>
  bindActionCreators({ selectUserAvatar }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(UserAvatar)


<|start_filename|>app/connection/connection-status.js<|end_filename|>
// @flow
import React from 'react'
import { StyleSheet, Image } from 'react-native'
import { Container, CustomText } from '../components'

const ConnectionStatus = () => (
  <Container center style={[styles.headerContainer]}>
    <Image
      style={[styles.image]}
      source={require('../images/cbSunCoast.png')}
    />
    <CustomText>Currently Talking With</CustomText>
    <CustomText><NAME></CustomText>
    <CustomText>CUSTOMER SERVICE SPECIALIST</CustomText>
  </Container>
)

export default ConnectionStatus

const styles = StyleSheet.create({
  image: {
    marginBottom: 22,
    width: 104,
    height: 104,
  },
  headerContainer: {
    height: 270,
  },
})


<|start_filename|>app/connection-history/connection-history-pending.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { Container } from '../components'
import type { ReactNavigation } from '../common/type-common'
import type { Store } from '../store/type-store'
import { ClaimRequestStatusModal } from '../claim-offer/claim-request-modal'
import { CLAIM_REQUEST_STATUS } from '../claim-offer/type-claim-offer'

type ConnectionHistoryPendingProps = {} & ReactNavigation

export class ConnectionHistoryPending extends PureComponent<
  ConnectionHistoryPendingProps,
  void
> {
  close = () => {
    this.props.navigation.goBack()
  }

  render() {
    const { payload } = this.props.navigation.state
      ? this.props.navigation.state.params
      : {}

    return (
      <Container fifth>
        <ClaimRequestStatusModal
          fromConnectionHistory
          claimRequestStatus={CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_SUCCESS}
          payload={payload}
          onContinue={this.close}
          senderLogoUrl={payload.senderLogoUrl}
          isPending={true}
          message1="As soon as"
          message3="signs and issues the credential"
          message5="to you, it will appear here."
        />
      </Container>
    )
  }
}


<|start_filename|>app/wallet/wallet-balance.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { View, Image } from 'react-native'
import styles from './styles'
import type { WalletBalanceProps } from './type-wallet'
import { getWalletBalance } from '../store/store-selector'
import type { Store } from '../store/type-store'
import { refreshWalletBalance } from './wallet-store'

export class WalletBalance extends PureComponent<WalletBalanceProps, void> {
  componentDidMount() {
    this.props.refreshWalletBalance()
  }

  render() {
    const { walletBalance, render }: WalletBalanceProps = this.props
    return <View>{render(walletBalance)}</View>
  }
}

const mapStateToProps = (state: Store) => {
  return {
    walletBalance: getWalletBalance(state),
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators({ refreshWalletBalance }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(WalletBalance)


<|start_filename|>android/app/src/main/java/me/connect/MainActivity.java<|end_filename|>
package me.connect;

import com.facebook.react.ReactActivity;

import android.os.Bundle;
import android.provider.Settings;
import android.content.pm.PackageManager;
import android.os.Build;    

import org.devio.rn.splashscreen.SplashScreen;
import io.branch.rnbranch.*;
import android.content.Intent;

import android.content.ContextWrapper;
import android.system.Os;

public class MainActivity extends ReactActivity {

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */

    @Override
    protected void onStart() {
        super.onStart();
        try {
          ContextWrapper c = new ContextWrapper(this);
          Os.setenv("EXTERNAL_STORAGE", c.getFilesDir().toString(), true);
          // un-comment to enable logging in vcx, indy & sovtoken libraries
          // Os.setenv("RUST_LOG", "TRACE", true);
        } catch(Exception e){
          e.printStackTrace();
        }
        RNBranchModule.initSession(getIntent().getData(), this);
    }

    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    @Override
    protected String getMainComponentName() {
        return "ConnectMe";
    }

    @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
        SplashScreen.show(this);
   }
}


<|start_filename|>app/store/type-connection-store.js<|end_filename|>
// @flow
import type { InvitationPayload } from '../invitation/type-invitation'
import type { CustomError } from '../common/type-common'

export type MyPairwiseInfo = {
  myPairwiseDid: string,
  myPairwiseVerKey: string,
  myPairwiseAgentDid: string,
  myPairwiseAgentVerKey: string,
  myPairwisePeerVerKey: string,
  senderDID: string,
}

export type Connection = {
  identifier: string,
  logoUrl: string,
  senderEndpoint: string,
  size?: number,
  senderName?: string,
  vcxSerializedConnection: string,
} & MyPairwiseInfo

export const DELETE_CONNECTION = 'DELETE_CONNECTION'

export type DeleteConnectionEventAction = {
  type: typeof DELETE_CONNECTION,
  senderDID: string,
}

export type Connections = { [senderDID: string]: Connection }

export type ConnectionStore = {
  // TODO:PS Add specific keys in connection store
  [string]: any,
  data: ?Connections,
}

export const DELETE_CONNECTION_SUCCESS = 'DELETE_CONNECTION_SUCCESS'

export const DELETE_CONNECTION_FAILURE = 'DELETE_CONNECTION_FAILURE'

export type DeleteConnectionSuccessEventAction = {
  type: typeof DELETE_CONNECTION_SUCCESS,
  filteredConnections: Connections,
}

export type DeleteConnectionFailureEventAction = {
  type: typeof DELETE_CONNECTION_FAILURE,
  connection: Connection,
  error: CustomError,
}

export const NEW_CONNECTION = 'NEW_CONNECTION'

export type NewConnectionAction = {
  type: typeof NEW_CONNECTION,
  connection: {
    identifier: string,
    logoUrl?: ?string,
  } & InvitationPayload,
}

export const STORAGE_KEY_THEMES = 'STORAGE_KEY_THEMES'

export type ConnectionThemes = {
  [string]: {
    primary: string,
    secondary: string,
  },
}

export const HYDRATE_CONNECTION_THEMES = 'HYDRATE_CONNECTION_THEMES'


<|start_filename|>app/connection-history/__tests__/connection-history-store.spec.js<|end_filename|>
// @flow
import {
  all,
  takeLatest,
  takeEvery,
  put,
  call,
  select,
} from 'redux-saga/effects'
import connectionHistoryReducer, {
  loadHistory,
  loadHistorySuccess,
  loadHistoryFail,
  loadHistorySaga,
  recordHistoryEvent,
  historyEventOccurred,
  historyEventOccurredSaga,
  convertInvitationToHistoryEvent,
  convertConnectionSuccessToHistoryEvent,
  convertClaimStorageSuccessToHistoryEvent,
  convertProofRequestToHistoryEvent,
  convertProofSendToHistoryEvent,
  convertSendClaimRequestSuccessToHistoryEvent,
  deleteHistoryEvent,
} from '../connection-history-store'
import { initialTestAction } from '../../common/type-common'
import {
  getTestInvitationPayload,
  successConnectionData,
  claimOffer,
  claimRequest,
  claim,
  claimOfferPayload,
  pendingClaimHistory,
  proofRequest,
  senderDid1,
  fulfilledRequestedAttributes,
  invitationReceivedEvent,
  newConnectionSuccessEvent,
  sendClaimRequestSuccessEvent,
  claimReceivedEvent,
  claimReceivedSuccessEvent,
  proofRequestReceivedEvent,
  proofRequestAutofillEvent,
  proofSharedEvent,
  proofRequestAutofill,
  proof,
  uid,
} from '../../../__mocks__/static-data'
import { invitationRejected } from '../../invitation/invitation-store'
import { saveNewConnection } from '../../store/connections-store'
import {
  claimOfferReceived,
  claimRequestSuccess,
  sendClaimRequestSuccess,
} from '../../claim-offer/claim-offer-store'
import { claimReceived, claimStorageSuccess } from '../../claim/claim-store'
import { CLAIM_STORAGE_SUCCESS } from '../../claim/type-claim'
import {
  proofRequestReceived,
  sendProof,
  proofRequestAutoFill,
  sendProofSuccess,
} from '../../proof-request/proof-request-store'
import {
  HISTORY_EVENT_STORAGE_KEY,
  ERROR_LOADING_HISTORY,
  ERROR_HISTORY_EVENT_OCCURRED,
} from '../type-connection-history'
import {
  getProofRequest,
  getProof,
  getClaimOffer,
  getPendingHistoryEvent,
  getHistoryEvent,
  getPendingHistory,
  getClaimReceivedHistory,
} from '../../store/store-selector'
import { getHydrationItem } from '../../services/storage'
import {
  CLAIM_OFFER_RECEIVED,
  SEND_CLAIM_REQUEST_SUCCESS,
} from './../../claim-offer/type-claim-offer'
import { RESET } from '../../common/type-common'
import { PROOF_REQUEST_RECEIVED } from '../../proof-request/type-proof-request'

jest.mock('../../services/uuid')

function getHistoryData() {
  // generate history data from static data that we have

  const invitationGenerator = getTestInvitationPayload()
  const invitationPayload = invitationGenerator.next().value
  let sender1History = []
  if (invitationPayload) {
    // add history for connection request
    sender1History.push(
      convertInvitationToHistoryEvent(invitationPayload.payload)
    )
  }

  // add history for connection success
  sender1History.push(
    convertConnectionSuccessToHistoryEvent(
      saveNewConnection(successConnectionData)
    )
  )
  sender1History.push(
    convertSendClaimRequestSuccessToHistoryEvent(
      sendClaimRequestSuccess(uid, claimOfferPayload)
    )
  )

  // add history for proof request
  sender1History.push(
    convertProofRequestToHistoryEvent(
      proofRequestReceived(proofRequest.payload, proofRequest.payloadInfo)
    )
  )

  // add history for proof sent
  sender1History.push(
    convertProofSendToHistoryEvent(
      proofSharedEvent,
      proofRequestAutofill,
      proof
    )
  )

  return {
    [senderDid1]: sender1History,
  }
}

describe('Store: ConnectionHistory', () => {
  let initialState
  beforeEach(() => {
    initialState = connectionHistoryReducer(undefined, initialTestAction())
  })

  it('match loadHistory', () => {
    expect(
      connectionHistoryReducer(initialState, loadHistory())
    ).toMatchSnapshot()
  })

  it('match loadHistorySuccess', () => {
    expect(
      connectionHistoryReducer(
        initialState,
        loadHistorySuccess(getHistoryData())
      )
    ).toMatchSnapshot()
  })

  it('match loadHistoryFail', () => {
    expect(
      connectionHistoryReducer(
        initialState,
        loadHistoryFail({
          code: 'TEST 101',
          message: 'Load History failed',
        })
      )
    ).toMatchSnapshot()
  })

  it('match record history event', () => {
    expect(
      connectionHistoryReducer(
        initialState,
        recordHistoryEvent(
          convertSendClaimRequestSuccessToHistoryEvent(
            sendClaimRequestSuccess(uid, claimOfferPayload)
          )
        )
      )
    ).toMatchSnapshot()
  })

  it('historyEventOccurredSaga should raise success for correct invitation received ', () => {
    let historyEvent
    const gen = historyEventOccurredSaga(
      historyEventOccurred(invitationReceivedEvent)
    )
    historyEvent = convertInvitationToHistoryEvent(
      invitationReceivedEvent.data.payload
    )

    expect(gen.next().value).toEqual(put(recordHistoryEvent(historyEvent)))
  })

  it('historyEventOccurredSaga should raise success for correct new connection ', () => {
    let historyEvent
    const gen = historyEventOccurredSaga(
      historyEventOccurred(newConnectionSuccessEvent)
    )
    historyEvent = convertConnectionSuccessToHistoryEvent(
      newConnectionSuccessEvent
    )

    expect(gen.next().value).toEqual(put(recordHistoryEvent(historyEvent)))
  })

  it('historyEventOccurredSaga should raise success for sending claim request ', () => {
    let historyEvent
    const gen = historyEventOccurredSaga(
      historyEventOccurred(sendClaimRequestSuccessEvent)
    )
    historyEvent = convertSendClaimRequestSuccessToHistoryEvent(
      sendClaimRequestSuccessEvent
    )
    expect(gen.next().value).toEqual(
      select(
        getHistoryEvent,
        historyEvent.originalPayload.uid,
        historyEvent.remoteDid,
        CLAIM_OFFER_RECEIVED
      )
    )
    expect(gen.next().value).toEqual(
      select(
        getPendingHistory,
        historyEvent.originalPayload.uid,
        historyEvent.remoteDid,
        SEND_CLAIM_REQUEST_SUCCESS
      )
    )

    expect(gen.next().value).toEqual(put(recordHistoryEvent(historyEvent)))
  })

  it('historyEventOccurredSaga should raise success for claim received ', () => {
    let historyEvent
    const gen = historyEventOccurredSaga(
      historyEventOccurred(claimReceivedSuccessEvent)
    )

    expect(gen.next().value).toEqual(
      select(getClaimOffer, claimReceivedSuccessEvent.messageId)
    )

    historyEvent = convertClaimStorageSuccessToHistoryEvent(
      claimReceivedSuccessEvent,
      claimOfferPayload
    )
    expect(gen.next(claimOfferPayload).value).toEqual(
      select(
        getClaimReceivedHistory,
        historyEvent.originalPayload.messageId,
        historyEvent.remoteDid,
        CLAIM_STORAGE_SUCCESS
      )
    )

    expect(gen.next().value).toEqual(
      select(getPendingHistoryEvent, claimOfferPayload)
    )
    expect(gen.next(pendingClaimHistory).value).toEqual(
      put(deleteHistoryEvent(pendingClaimHistory))
    )
  })

  it('historyEventOccurredSaga should raise success for correct proof request received', () => {
    let historyEvent
    const gen = historyEventOccurredSaga(
      historyEventOccurred(proofRequestReceivedEvent)
    )
    historyEvent = convertProofRequestToHistoryEvent(proofRequestReceivedEvent)
    expect(gen.next().value).toEqual(
      select(
        getHistoryEvent,
        historyEvent.originalPayload.payloadInfo.uid,
        historyEvent.remoteDid,
        PROOF_REQUEST_RECEIVED
      )
    )
    expect(gen.next().value).toEqual(put(recordHistoryEvent(historyEvent)))
  })

  it('historyEventOccurredSaga should raise success for proof shared', () => {
    let historyEvent
    const gen = historyEventOccurredSaga(historyEventOccurred(proofSharedEvent))
    expect(gen.next().value).toEqual(
      select(getProofRequest, proofSharedEvent.uid)
    )
    expect(gen.next(proofRequestAutofill).value).toEqual(
      select(getProof, proofSharedEvent.uid)
    )
    historyEvent = convertProofSendToHistoryEvent(
      proofSharedEvent,
      proofRequestAutofill,
      proof
    )
  })

  it('historyEventOccurredSaga should raise failure in case anything fails', () => {
    const gen = historyEventOccurredSaga(historyEventOccurred(proofSharedEvent))
    expect(gen.next().value).toEqual(
      select(getProofRequest, proofSharedEvent.uid)
    )
    const error = new Error()
    expect(gen.throw(error).value).toEqual(
      put(
        loadHistoryFail({
          ...ERROR_HISTORY_EVENT_OCCURRED,
          message: `${ERROR_HISTORY_EVENT_OCCURRED.message} ${error.message}`,
        })
      )
    )
  })

  it('convertInvitationToHistoryEvent should raise success', () => {
    expect(
      convertInvitationToHistoryEvent(invitationReceivedEvent.data.payload)
    ).toMatchSnapshot()
  })

  it('convertConnectionSuccessToHistoryEvent should raise success', () => {
    expect(
      convertConnectionSuccessToHistoryEvent(newConnectionSuccessEvent)
    ).toMatchSnapshot()
  })

  it('convertSendClaimRequestSuccessToHistoryEvent should raise success', () => {
    expect(
      convertSendClaimRequestSuccessToHistoryEvent(sendClaimRequestSuccessEvent)
    ).toMatchSnapshot()
  })

  it('convertProofRequestToHistoryEvent should raise success', () => {
    expect(
      convertProofRequestToHistoryEvent(proofRequestReceivedEvent)
    ).toMatchSnapshot()
  })

  it('convertProofAutoFillToHistoryEvent should raise success', () => {
    expect(
      convertProofSendToHistoryEvent(
        proofSharedEvent,
        proofRequestAutofill,
        proof
      )
    ).toMatchSnapshot()
  })

  it('should raise failure in case data getHydrationItem fails', () => {
    const gen = loadHistorySaga()
    gen.next()
    expect(gen.next().value).toEqual(
      call(getHydrationItem, HISTORY_EVENT_STORAGE_KEY)
    )
    const error = new Error()
    expect(gen.throw(error).value).toEqual(
      put(
        loadHistoryFail({
          ...ERROR_LOADING_HISTORY,
          message: `${ERROR_LOADING_HISTORY.message} ${error.message}`,
        })
      )
    )
    expect(gen.next().done).toBe(true)
  })

  it('should reset history if RESET action is raised', () => {
    const afterOneHistoryEventState = connectionHistoryReducer(
      initialState,
      recordHistoryEvent(
        convertSendClaimRequestSuccessToHistoryEvent(
          sendClaimRequestSuccess(uid, claimOfferPayload)
        )
      )
    )
    expect(
      connectionHistoryReducer(afterOneHistoryEventState, {
        type: RESET,
      })
    ).toMatchSnapshot()
  })
})


<|start_filename|>app/components/pin-code/__tests__/pin-code-digit.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import PinCodeDigit from '../pin-code-digit'
import type { PinCodeDigitProps } from '../type-pin-code-box'

describe('<PinCodeDigit />', () => {
  let onPress
  beforeEach(() => {
    onPress = jest.fn()
  })

  it('when digit is entered', () => {
    const wrapper = renderer
      .create(<PinCodeDigit entered onPress={onPress} />)
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })

  it('when digit is not entered', () => {
    const wrapper = renderer
      .create(<PinCodeDigit entered={false} onPress={onPress} />)
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>app/wallet/wallet-tab-receive.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { StyleSheet, Clipboard, ScrollView } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import {
  Container,
  CustomView,
  CustomText,
  CustomButton,
  Loader,
} from '../components'
import type {
  WalletTabReceiveProps,
  WalletTabReceiveState,
} from './type-wallet'
import type { Store } from '../store/type-store'
import customStyles from './styles'
import { getWalletAddresses } from '../store/store-selector'
import { refreshWalletAddresses } from './wallet-store'
import { promptBackupBanner } from '../backup/backup-store'
import { STORE_STATUS } from './type-wallet'
import { walletRoute } from '../common'

export class WalletTabReceive extends PureComponent<
  WalletTabReceiveProps,
  WalletTabReceiveState
> {
  state = {
    copyButtonText: 'Copy Address To Clipboard',
  }

  componentDidMount() {
    this.props.refreshWalletAddresses()
  }

  copyToClipboard = () => {
    const { walletAddresses, promptBackupBanner } = this.props
    if (walletAddresses.length) {
      promptBackupBanner(true)
      Clipboard.setString(walletAddresses[0])
      this.setState({
        copyButtonText: 'Copied!',
      })
      setTimeout(() => {
        if (this.props.currentScreen === walletRoute) {
          this.setState({
            copyButtonText: 'Copy Address To Clipboard',
          })
        }
      }, 2000)
    }
  }

  // TODO handle error state
  render() {
    const { walletAddresses, addressStatus } = this.props
    const isLoading =
      addressStatus === STORE_STATUS.IN_PROGRESS && walletAddresses.length === 0
    return (
      <Container>
        <Container>
          <CustomView style={[styles.container]}>
            <ScrollView scrollEnabled={walletAddresses.length > 1}>
              <CustomText
                h6
                bold
                center
                transparentBg
                quinaryText
                style={[styles.heading]}
              >
                {isLoading
                  ? 'Fetching your Sovrin token payment address'
                  : 'Your Sovrin token payment address is:'}
              </CustomText>
              {isLoading && <Loader showMessage={false} />}
              {walletAddresses.map((walletAddress: string) => {
                return (
                  <CustomText
                    center
                    transparentBg
                    borderColor
                    primary
                    key={walletAddress}
                    style={[styles.paymentAddress]}
                  >
                    {walletAddress}
                  </CustomText>
                )
              })}
            </ScrollView>
          </CustomView>
        </Container>
        <CustomView safeArea style={[styles.alignItemsCenter]}>
          {!isLoading && (
            <CustomButton
              onPress={this.copyToClipboard}
              testID="token-copy-to-clipboard-label"
              style={[customStyles.ctaButton]}
              primary
              title={this.state.copyButtonText}
            />
          )}
        </CustomView>
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    marginTop: 38,
  },
  heading: {
    lineHeight: 18,
    letterSpacing: -0.38,
    marginBottom: 20,
    paddingHorizontal: 16,
  },
  paymentAddress: {
    marginTop: 5,
    paddingTop: 16,
    paddingBottom: 16,
    paddingLeft: 13,
    paddingRight: 13,
    marginLeft: 19,
    marginRight: 19,
    fontSize: 18,
    lineHeight: 24,
    letterSpacing: -0.45,
  },
  alignItemsCenter: {
    marginBottom: 6,
    marginLeft: '5%',
    marginRight: '5%',
  },
})

const mapStateToProps = (state: Store) => {
  return {
    walletAddresses: getWalletAddresses(state),
    addressStatus: state.wallet.walletAddresses.status,
    currentScreen: state.route.currentScreen,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators({ promptBackupBanner, refreshWalletAddresses }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(WalletTabReceive)


<|start_filename|>connectMeUITest/src/pageObjects/HockeyAppPage.java<|end_filename|>
package pageObjects;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

/**
 * Created by ankurmishra on 6/22/17.
 */
public class HockeyAppPage {

	private static WebElement element = null;
	
	public static WebElement UserNameText(AppiumDriver driver) throws Exception {

		try {
			WebDriverWait wait = new WebDriverWait(driver, 90);
			element = driver.findElement(By.id("user_email"));

			//element = wait.until(ExpectedConditions.elementToBeClickable(By.id("user_email")));				
			System.out.println("UserNameText is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("UserNameText is not displayed");
			throw (e);
		}
	}
	
    public static WebElement PasswordText(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.id("user_password"));
			
			System.out.println("PasswordText is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("PasswordText not is displayed");
			throw (e);
		}
	}
	
	public static WebElement SigninButton(AppiumDriver driver) throws Exception {

			try {
				element = driver.findElement(By.xpath("//button[@type='submit']"));
				System.out.println("Signin Button is displayed");

				return element;
			    } catch (Exception e) {

				System.out.println("Signin Button is not displayed");
				throw (e);
			}

	}
	
	public static WebElement QAConnectIcon(AppiumDriver driver) throws Exception {

			try {
				
				WebDriverWait wait = new WebDriverWait(driver, 120);
				element = driver.findElement(By.xpath("//img[@title='QA ConnectMe']"));

			//	element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//img[@title='QA ConnectMe']")));				
				System.out.println("QAConnect Icon is displayed");

				return element;
			    } catch (Exception e) {

				System.out.println("QAConnect Icon is not displayed");

				throw (e);
			}
		}
	
	public static WebElement InstallButton(AppiumDriver driver) throws Exception {

			try {
				
				WebDriverWait wait = new WebDriverWait(driver, 90);
				element = driver.findElement(By.xpath("//div[@class='install pull-right']/a"));

			//	element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='install pull-right']/a")));	
				System.out.println("InstallButton is displayed");

				return element;
			    } catch (Exception e) {

			    System.out.println("InstallButton is not displayed");
     			throw (e);
			}
		}
		
		

}


<|start_filename|>app/store/__tests__/connections-store.spec.js<|end_filename|>
// @flow
import renderer from 'react-test-renderer'
import * as matchers from 'redux-saga-test-plan/matchers'
import { expectSaga } from 'redux-saga-test-plan'
import { throwError } from 'redux-saga-test-plan/providers'

import connectionReducer, {
  saveNewConnection,
  saveNewConnectionSuccess,
  saveNewConnectionFailed,
  connectionMapper,
  deleteConnectionSuccess,
  deleteConnectionOccurredSaga,
  deleteConnectionAction,
  persistThemes,
  hydrateThemes,
  removePersistedThemes,
  hydrateConnectionThemes,
} from '../connections-store'
import { bubbleSize } from '../../common/styles'
import {
  successConnectionData,
  connections,
  userOneTimeInfo,
  configStoreNotHydratedInstalledVcxInit,
  getStore,
  connectionThemes,
} from '../../../__mocks__/static-data'
import { safeGet, safeSet, secureSet, secureGet } from '../../services/storage'
import { CONNECTIONS } from '../../common'
import { deleteConnection } from '../../bridge/react-native-cxs/RNCxs'
import { STORAGE_KEY_THEMES } from '../type-connection-store'

describe('Mapper', () => {
  it('connectionMapper should return proper object', () => {
    const connection = {
      identifier: '3nj819kkjywdppuje79',
      logoUrl: 'https://test-agengy.com/logo',
      size: bubbleSize.XL,
      name: 'test',
      senderDID: '123819kkjywdppuj987',
      senderEndpoint: 'https://test-endpoint.com',
      remoteConnectionId: '5iZiu2aLYrQXSdon123456',
    }
    const tree = connectionMapper(connection)
    expect(tree).toMatchSnapshot()
  })
})

describe('connections should update correctly', () => {
  let initialState = {
    data: null,
  }
  const newConnection = {
    identifier: '6789012345678906789012',
    name: 'test',
  }

  beforeAll(() => {
    // get initial state without any action
    initialState = connectionReducer(undefined, { type: 'NO_ACTION' })
  })

  it('should receive new connection request', () => {
    const expectedState = {
      ...initialState,
      isFetching: true,
      isPristine: false,
    }
    const actualState = connectionReducer(
      initialState,
      saveNewConnection(newConnection)
    )
    expect(actualState).toMatchObject(expectedState)
  })

  it('match delete connection success', () => {
    expect(
      connectionReducer(initialState, deleteConnectionSuccess(connections))
    ).toMatchSnapshot()
  })

  it('saga:deleteConnectionOccurredSaga, success', () => {
    const connection = successConnectionData.newConnection
    const stateWithConnection = {
      connections: {
        data: {
          [connection.identifier]: connection,
        },
      },
      user: {
        userOneTimeInfo,
      },
      config: configStoreNotHydratedInstalledVcxInit,
    }

    return expectSaga(
      deleteConnectionOccurredSaga,
      deleteConnectionAction(connection.senderDID)
    )
      .withState(stateWithConnection)
      .provide([
        [matchers.call.like({ fn: deleteConnection }), true],
        [matchers.call.fn(secureSet, CONNECTIONS, '{}'), true],
      ])
      .call.like({ fn: deleteConnection })
      .call(secureSet, CONNECTIONS, '{}')
      .put(deleteConnectionSuccess({}))
      .run()
  })

  it('should update connections and store new connection properly', () => {
    const expectedState = {
      ...initialState,
      isFetching: false,
      data: {
        ...initialState.data,
        [newConnection.identifier]: newConnection,
      },
    }
    const actualState = connectionReducer(
      initialState,
      saveNewConnectionSuccess(newConnection)
    )
    expect(actualState).toMatchObject(expectedState)
  })

  it('should fail if new connection is not stored', () => {
    const error = { code: '1234', message: 'new connection failed' },
      expectedState = {
        ...initialState,
        isFetching: false,
        error,
      }
    const actualState = connectionReducer(
      initialState,
      saveNewConnectionFailed(error)
    )
    expect(actualState).toMatchObject(expectedState)
  })

  it('should reset connection store, if RESET action is raised', () => {
    const afterNewConnection = connectionReducer(
      initialState,
      saveNewConnection(newConnection)
    )
    expect(
      connectionReducer(afterNewConnection, { type: 'RESET' })
    ).toMatchSnapshot()
  })

  it('saga:persistThemes, success', async () => {
    const stateWithThemes = getStore().getState()
    const result = await expectSaga(persistThemes)
      .withState(stateWithThemes)
      .provide([[matchers.call.like({ fn: secureSet }), true]])
      .run()
    expect(result).toMatchSnapshot()
  })

  it('saga:hydrateThemes, success', async () => {
    const result = await expectSaga(hydrateThemes)
      .provide([
        [
          matchers.call.fn(secureGet, STORAGE_KEY_THEMES),
          JSON.stringify(connectionThemes),
        ],
      ])
      .run()
    expect(result).toMatchSnapshot()
  })

  it('saga:removePersistedThemes, success', async () => {
    const result = await expectSaga(removePersistedThemes).run()
    expect(result).toMatchSnapshot()
  })

  it('ACTION:HYDRATE_CONNECTION_THEMES', () => {
    const afterThemeHydrationState = connectionReducer(
      initialState,
      hydrateConnectionThemes(connectionThemes)
    )
    expect(afterThemeHydrationState).toMatchSnapshot()
  })
})


<|start_filename|>app/deep-link/deep-link-store.js<|end_filename|>
// @flow
import {
  DEEP_LINK_DATA,
  DEEP_LINK_EMPTY,
  DEEP_LINK_PROCESSED,
  DEEP_LINK_ERROR,
  DEEP_LINK_STATUS,
} from './type-deep-link'
import type {
  DeepLinkStore,
  DeepLinkAction,
  DeepLinkDataAction,
  DeepLinkProcessedAction,
  DeepLinkEmptyAction,
  DeepLinkErrorAction,
} from './type-deep-link'
import { RESET } from '../common/type-common'

const initialState = {
  tokens: {},
  isLoading: true,
  error: null,
}

// action creators
export const deepLinkData = (data: string): DeepLinkDataAction => ({
  type: DEEP_LINK_DATA,
  data,
})

export const deepLinkEmpty = (): DeepLinkEmptyAction => ({
  type: DEEP_LINK_EMPTY,
})

export const deepLinkError = (error: string): DeepLinkErrorAction => ({
  type: DEEP_LINK_ERROR,
  error,
})

export const deepLinkProcessed = (data: string): DeepLinkProcessedAction => ({
  type: DEEP_LINK_PROCESSED,
  data,
})

export default function deepLinkReducer(
  state: DeepLinkStore = initialState,
  action: DeepLinkAction
) {
  switch (action.type) {
    case DEEP_LINK_DATA:
      return {
        ...state,
        isLoading: false,
        tokens: {
          ...state.tokens,
          [action.data]: {
            token: action.data,
            error: null,
            status: DEEP_LINK_STATUS.NONE,
          },
        },
      }
    case DEEP_LINK_ERROR:
      return {
        ...state,
        isLoading: false,
        error: action.error,
      }
    case DEEP_LINK_PROCESSED:
      return {
        ...state,
        tokens: {
          ...state.tokens,
          [action.data]: {
            ...state.tokens[action.data],
            status: DEEP_LINK_STATUS.PROCESSED,
          },
        },
      }
    case DEEP_LINK_EMPTY:
      return {
        ...state,
        isLoading: false,
        tokens: {},
        error: null,
      }

    case RESET:
      return initialState

    default:
      return state
  }
}


<|start_filename|>app/components/image-color-picker/type-color-picker.js<|end_filename|>
// @flow

export type ConnectionTheme = {
  primary: string,
  secondary: string,
}

export type ImagePickerProps = {
  imageType: string,
  imageUrl: string,
  updateConnectionTheme: (
    logoUrl: string,
    color: string,
    secondaryColor: string
  ) => void,
}

export type ImagePickerStates = {
  imageBlob: string,
}

export type ConnectionThemeProps = {
  logoUrl: string,
  secondary: string,
  connectionTheme: ConnectionTheme,
  children: any, //TODO:PS: import exact react children types
  backgroundColor: string,
  style: any,
  disabled?: boolean,
}


<|start_filename|>android/app/src/main/java/me/connect/rnindy/RNIndyStaticData.java<|end_filename|>
package me.connect.rnindy;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;


public class RNIndyStaticData {
    private int addConnectionCalls = 0;
    private int pairwiseAgentCalls = 0;
    private int getMessageCalls = 0;

    public Map<String, String> oneTimeAddConnection = new HashMap<String, String>(){{
        put("userDID", "3akhf906816kahfadhfas85");
        put("verificationKey", "<KEY>");
    }};

    public Map<String, String> secondTimeAddConnection = new HashMap<String, String>(){{
        put("userDID", "user1Did");
        put("verificationKey", "user1VerificationKey");
    }};

    public Map<String, String> allOtherAddConnection = new HashMap<String, String>(){{
        put("userDID", "user2Did");
        put("verificationKey", "user2VerificationKey");
    }};

    public String addConnection() {
        if (addConnectionCalls == 0) {
            addConnectionCalls += 1;
            return new JSONObject(oneTimeAddConnection).toString();
        }

        if (addConnectionCalls == 1) {
            addConnectionCalls += 1;
            return new JSONObject(secondTimeAddConnection).toString();
        }

        return new JSONObject(allOtherAddConnection).toString();
    }

    public WritableMap connectAgency() {
        WritableMap connectAgency = Arguments.createMap();
        connectAgency.putString("withPairwiseDID", "oneTimeAgencyDid");
        connectAgency.putString("withPairwiseDIDVerKey", "oneTimeAgencyVerKey");

        return connectAgency;
    }

    public WritableMap oneTimeAgent() {
        WritableMap oneTimeAgent = Arguments.createMap();
        oneTimeAgent.putString("withPairwiseDID", "oneTimeAgentDid");
        oneTimeAgent.putString("withPairwiseDIDVerKey", "oneTimeAgentVerKey");

        return oneTimeAgent;
    }

    public WritableMap pairwiseAgent() {
        if (pairwiseAgentCalls == 0) {
            pairwiseAgentCalls += 1;
            WritableMap pairwiseAgent = Arguments.createMap();
            pairwiseAgent.putString("withPairwiseDID", "myPairwiseAgentDID");
            pairwiseAgent.putString("withPairwiseDIDVerKey", "myPairwiseAgentVerKey");

            return pairwiseAgent;
        }

        WritableMap pairwiseAgentSecondTime = Arguments.createMap();
        pairwiseAgentSecondTime.putString("withPairwiseDID", "myPairwiseAgentDID2");
        pairwiseAgentSecondTime.putString("withPairwiseDIDVerKey", "myPairwiseAgentVerKey2");

        return pairwiseAgentSecondTime;
    }

    public WritableMap getMessage() {
        if (getMessageCalls  % 3 == 0) {
            // if called first, fourth, seventh times etc. then return claim offer
            WritableMap claimOffer = Arguments.createMap();
            claimOffer.putString("payload", "{\"msg_type\":\"CLAIM_OFFER\",\"version\":\"0.1\",\"to_did\":\"BnRXf8yDMUwGyZVDkSENeq\",\"from_did\":\"GxtnGN6ypZYgEqcftSQFnC\",\"iid\":\"cCanHnpFAD\",\"mid\":\"\",\"claim\":{\"name\":[\"Alice\"],\"date_of_birth\":[\"2000-05-17\"],\"height\":[\"175\"]},\"schema_seq_no\":12,\"issuer_did\":\"V4SGRU86Z58d6TV7PBUe6f\",\"nonce\":\"351590\",\"claim_name\":\"Profile detail\",\"issuer_name\":\"Test Enterprise\",\"optional_data\":{\"terms_of_service\":\"<Large block of text>\",\"price\":6},\"remoteName\":\"Test remote name\"}");

            return claimOffer;
        }

        if (getMessageCalls  % 3 == 1) {
            // if called second, fifth, eight times etc. then return claim
            WritableMap claim = Arguments.createMap();
            claim.putString("payload", "{\"msg_type\":\"claim\",\"version\":\"0.1\",\"claim_offer_id\":\"7TNw2k5\",\"from_did\":\"3KFuh4jmMC5Agsy5HcCwFB\",\"to_did\":\"5RHwxmBrGxaEskHcBnLKve\",\"claim\":{\"name\":[\"Test\",\"12\"]},\"schema_seq_no\":12,\"issuer_did\":\"V4SGRU86Z58d6TV7PBUe6f\",\"signature\":{\"primary_claim\":{\"m2\":\"m2\",\"a\":\"a\",\"e\":\"e\",\"v\":\"v\"}}}");

            return claim;
        }

        // if called third, sixth, ninth times etc. then return proof request
        WritableMap proofRequest = Arguments.createMap();
        proofRequest.putString("payload", "{\"@type\":{\"name\":\"PROOF_REQUEST\",\"version\":\"1.0\"},\"@topic\":{\"tid\":1,\"mid\":9},\"intended_use\":\"Verify Home Address\",\"proof_request_data\":{\"nonce\":\"123432421212\",\"name\":\"Home Address\",\"version\":\"0.1\",\"requested_attrs\":{\"<attr1_uuid>\":{\"name\":\"your_name\"},\"<attr2_uuid>\":{\"schema_seq_no\":1,\"name\":\"address_1\"},\"<attr3_uuid>\":{\"schema_seq_no\":2,\"issuer_did\":\"ISSUER_DID2\",\"name\":\"address_2\"},\"<attr4_uuid>\":{\"schema_seq_no\":1,\"name\":\"city\"},\"<attr5_uuid>\":{\"schema_seq_no\":1,\"name\":\"state\"},\"<attr6_uuid>\":{\"schema_seq_no\":1,\"name\":\"zip\"}},\"requested_predicates\":{\"predicate1_uuid\":{\"attr_name\":\"age\",\"p_type\":\"GE\",\"value\":18,\"schema_seq_no\":1,\"issuer_did\":\"DID1\"}}},\"remoteName\":\"Evernym\"}");

        return proofRequest;
    }

    public String generateClaimRequest() {
        Map<String, String> claimRequest = new HashMap<String, String>(){{
            put("blinded_ms", "blindedMasterSecret");
            put("schema_seq_no", "1243");
            put("issuer_did", "issuerDID");
        }};

        return new JSONObject(claimRequest).toString();
    }

    public WritableArray getClaim() {
        WritableArray claims = Arguments.createArray();

        WritableMap claim1 = Arguments.createMap();
        claim1.putString("claim_uuid", "claimuuid1");

        WritableMap claim2 = Arguments.createMap();
        claim1.putString("claim_uuid", "claimuuid2");

        claims.pushMap(claim1);
        claims.pushMap(claim2);

        return claims;
    }


}


<|start_filename|>app/about-app/about-app.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Image } from 'react-native'
import { connect } from 'react-redux'
import { createStackNavigator } from 'react-navigation'
import {
  Container,
  CustomText,
  CustomView,
  Icon,
  CustomHeader,
} from '../components'
import {
  color,
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_6X,
  OFFSET_7X,
  dimGray,
  lightGray,
} from '../common/styles'
import { tertiaryHeaderStyles } from '../components/layout/header-styles'
import { aboutAppRoute, privacyTNCRoute } from '../common'
import type { AboutAppProps, AboutAppListItemProps } from './type-about-app'
import VersionNumber from 'react-native-version-number'
import { ListItem } from 'react-native-elements'

import PrivacyTNC from '../privacy-tnc/privacy-tnc-screen'
import type { Store } from '../store/type-store'
import { getEnvironmentName } from '../store/config-store'

const styles = StyleSheet.create({
  headerLeft: {
    width: OFFSET_2X,
  },
  thickLine: {
    height: 2,
    width: 140,
    borderBottomColor: lightGray,
    borderBottomWidth: 2,
  },
  topFloatText: {
    paddingBottom: OFFSET_1X,
  },
  bottomFloatText: {
    paddingBottom: OFFSET_1X / 2,
  },
})

export class AboutAppListItem extends PureComponent<
  AboutAppListItemProps,
  void
> {
  render() {
    return (
      <ListItem
        title={
          <CustomView>
            <CustomText h5 semiBold bg="fifth">
              {this.props.titleValue}
            </CustomText>
          </CustomView>
        }
        onPress={this.props.onPress}
        rightIcon={{
          name: 'chevron-right',
          color: dimGray,
        }}
      />
    )
  }
}

const logoConnectMe = <Image source={require('../images/logo_connectme.png')} />
const logoEvernym = <Image source={require('../images/logo_sovrin.png')} />
const logoSovrin = <Image source={require('../images/logo_sovrin.png')} />
const versionNumber = VersionNumber

export class AboutApp extends PureComponent<AboutAppProps, void> {
  openTermsAndConditions = () => {
    this.props.navigation.navigate(privacyTNCRoute, PrivacyTNC.INFO_TYPE.TNC)
  }

  openPrivacyPolicy = () => {
    this.props.navigation.navigate(
      privacyTNCRoute,
      PrivacyTNC.INFO_TYPE.PRIVACY
    )
  }

  static navigationOptions = ({ navigation }) => ({
    header: (
      <CustomHeader
        backgroundColor={color.bg.tertiary.color}
        outerContainerStyles={{ borderBottomWidth: 0 }}
        leftComponent={
          <Icon
            testID={'back-arrow'}
            iconStyle={[styles.headerLeft]}
            src={require('../images/icon_backArrow.png')}
            resizeMode="contain"
            onPress={() => navigation.goBack()}
            small
          />
        }
        centerComponent={
          <CustomText bg="tertiary" tertiary transparentBg semiBold>
            About this App
          </CustomText>
        }
      />
    ),
    swipeEnabled: false,
  })

  render() {
    return (
      <Container tertiary>
        <CustomView center doubleVerticalSpace>
          {logoConnectMe}
          <CustomView center doubleVerticalSpace>
            <CustomText bg="tertiary" tertiary transparentBg semiBold>
              VERSION # {versionNumber.appVersion}.{versionNumber.buildVersion}
            </CustomText>
          </CustomView>
          <CustomView center verticalSpace>
            <CustomText bg="tertiary" tertiary transparentBg semiBold>
              {this.props.environmentName}
            </CustomText>
          </CustomView>
          <CustomView verticalSpace vCenter style={[styles.thickLine]} />
          <CustomView doubleVerticalSpace>
            <CustomText
              bg="tertiary"
              tertiary
              transparentBg
              h7
              style={[styles.topFloatText]}
            >
              built by
            </CustomText>
            {logoEvernym}
          </CustomView>
          <CustomView verticalSpace>
            <CustomText
              bg="tertiary"
              tertiary
              transparentBg
              h7
              style={[styles.bottomFloatText]}
            >
              powered by
            </CustomText>
            {logoSovrin}
          </CustomView>
        </CustomView>
        <Container>
          {/* TODO: move the below titles also to constants */}
          <AboutAppListItem
            titleValue={'Terms and Conditions'}
            onPress={this.openTermsAndConditions}
          />
          <AboutAppListItem
            titleValue={'Privacy Policy'}
            onPress={this.openPrivacyPolicy}
          />
        </Container>
      </Container>
    )
  }
}

const mapStateToProps = (state: Store) => ({
  environmentName: getEnvironmentName(state.config),
})

export default connect(mapStateToProps)(AboutApp)


<|start_filename|>app/settings/backup-wallet.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { View } from 'react-native'
import { connect } from 'react-redux'
import get from 'lodash.get'
import type { Store } from '../store/type-store'
import type { BackupWalletProps } from '../wallet/type-wallet'
import { genRecoveryPhraseRoute, settingsRoute } from '../common'

class BackupWallet extends PureComponent<BackupWalletProps, void> {
  backupWallet = () => {
    const { navigation: { navigate, state, goBack } } = this.props
    // If no there is no route, then default to Settings
    const initialRoute = get(state, 'routeName', settingsRoute)
    navigate(genRecoveryPhraseRoute, {
      initialRoute,
    })
  }
  render() {
    const { render, backup }: BackupWalletProps = this.props
    return <View>{render(backup.status, this.backupWallet.bind(this))}</View>
  }
}

const mapStateToProps = ({ wallet }: Store) => ({
  backup: wallet.backup,
})

export default connect(mapStateToProps, null)(BackupWallet)


<|start_filename|>app/components/show-pairwise-info.js<|end_filename|>
// @flow
import { Alert } from 'react-native'

const showDID = (senderDID: string, myDID: string) => {
  Alert.alert(
    'Connection DID',
    'Sender DID:\n' + senderDID + '\nMy DID:\n' + myDID,
    [{ text: 'OK' }],
    { cancelable: true }
  )
}

export default showDID


<|start_filename|>app/connection-history/connection-history-navigator.js<|end_filename|>
// @flow
import { createStackNavigator } from 'react-navigation'

import {
  connectionHistoryDetailsRoute,
  connectionHistoryPendingRoute,
  connectionHistoryRoute,
} from '../common/route-constants'
import ConnectionHistory from './connection-history'
import ConnectionHistoryDetails from './connection-history-details'
import { ConnectionHistoryPending } from './connection-history-pending'

export default createStackNavigator(
  {
    [connectionHistoryRoute]: {
      screen: ConnectionHistory,
    },
    [connectionHistoryDetailsRoute]: {
      screen: ConnectionHistoryDetails,
    },
    [connectionHistoryPendingRoute]: {
      screen: ConnectionHistoryPending,
    },
  },
  {
    headerMode: 'none',
  }
)


<|start_filename|>app/components/custom-date/__tests__/custom-date.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import CustomDate from '../custom-date'

describe('<CustomDate />', () => {
  it('should ConnectionHistoryDetails render properly', () => {
    const component = renderer.create(
      <CustomDate>{'2018-01-10T04:32:43+05:30'}</CustomDate>
    )
    expect(component).toMatchSnapshot()
  })
})


<|start_filename|>app/proof-request/proof-request-store.js<|end_filename|>
// @flow
import {
  put,
  takeLatest,
  takeEvery,
  call,
  select,
  all,
} from 'redux-saga/effects'
import type { CustomError } from '../common/type-common'
import type {
  ProofRequestStore,
  ProofRequestAction,
  ProofRequestShownAction,
  SendProofSuccessAction,
  SendProofFailAction,
  SendProofAction,
  ProofRequestIgnoredAction,
  ProofRequestRejectedAction,
  ProofRequestAcceptedAction,
  ProofRequestPayload,
  AdditionalProofDataPayload,
  MissingAttribute,
  SelfAttestedAttributes,
  MissingAttributes,
  ProofRequestReceivedAction,
} from './type-proof-request'

import {
  getUserPairwiseDid,
  getProofRequestPairwiseDid,
  getRemotePairwiseDidAndName,
  getProofRequest,
} from '../store/store-selector'
import {
  PROOF_REQUESTS,
  PROOF_REQUEST_RECEIVED,
  PROOF_REQUEST_STATUS,
  PROOF_STATUS,
  PROOF_REQUEST_SHOWN,
  PROOF_REQUEST_IGNORED,
  PROOF_REQUEST_ACCEPTED,
  PROOF_REQUEST_REJECTED,
  PROOF_REQUEST_AUTO_FILL,
  SEND_PROOF,
  SEND_PROOF_SUCCESS,
  SEND_PROOF_FAIL,
  MISSING_ATTRIBUTES_FOUND,
  ERROR_SEND_PROOF,
  HYDRATE_PROOF_REQUESTS,
  PROOF_SERIALIZED,
  UPDATE_PROOF_HANDLE,
  PROOF_REQUEST_SHOW_START,
} from './type-proof-request'
import type {
  NotificationPayloadInfo,
  Attribute,
} from '../push-notification/type-push-notification'
import {
  sendProof as sendProofApi,
  getHandleBySerializedConnection,
  proofSerialize,
} from '../bridge/react-native-cxs/RNCxs'
import type { Connection } from '../store/type-connection-store'
import type { UserOneTimeInfo } from '../store/user/type-user-store'
import { MESSAGE_TYPE } from '../api/api-constants'
import { RESET } from '../common/type-common'
import { PROOF_FAIL } from '../proof/type-proof'
import { getProofRequests } from './../store/store-selector'
import { captureError } from '../services/error/error-handler'
import { resetTempProofData, errorSendProofFail } from '../proof/proof-store'
import { secureSet, getHydrationItem } from '../services/storage'
import KeepScreenOn from 'react-native-keep-screen-on'

const proofRequestInitialState = {}

export const ignoreProofRequest = (uid: string): ProofRequestIgnoredAction => ({
  type: PROOF_REQUEST_IGNORED,
  uid,
})

export const rejectProofRequest = (
  uid: string
): ProofRequestRejectedAction => ({
  type: PROOF_REQUEST_REJECTED,
  uid,
})

export const acceptProofRequest = (
  uid: string
): ProofRequestAcceptedAction => ({
  type: PROOF_REQUEST_ACCEPTED,
  uid,
})
export const proofRequestShown = (uid: string): ProofRequestShownAction => ({
  type: PROOF_REQUEST_SHOWN,
  uid,
})
export const sendProof = (uid: string): SendProofAction => ({
  type: SEND_PROOF,
  uid,
})
export const sendProofSuccess = (uid: string): SendProofSuccessAction => ({
  type: SEND_PROOF_SUCCESS,
  uid,
})
export const hydrateProofRequests = (proofRequests: ProofRequestStore) => ({
  type: HYDRATE_PROOF_REQUESTS,
  proofRequests,
})

export const sendProofFail = (
  uid: string,
  error: CustomError
): SendProofFailAction => ({
  type: SEND_PROOF_FAIL,
  error,
  uid,
})

export function convertMissingAttributeListToObject(
  missingAttributes: Array<MissingAttribute>
): MissingAttributes {
  return missingAttributes.reduce(
    (selfAttestedAttributes, missingAttribute: MissingAttribute) => ({
      ...selfAttestedAttributes,
      [missingAttribute.name.toLocaleLowerCase()]: {
        name: missingAttribute.name,
        data: '',
        key: missingAttribute.key,
      },
    }),
    {}
  )
}

export const missingAttributesFound = (
  missingAttributeList: MissingAttribute[],
  uid: string
) => ({
  type: MISSING_ATTRIBUTES_FOUND,
  missingAttributes: convertMissingAttributeListToObject(missingAttributeList),
  uid,
})

export function* persistProofRequestsSaga(): Generator<*, *, *> {
  try {
    const proofRequests = yield select(getProofRequests)
    yield call(secureSet, PROOF_REQUESTS, JSON.stringify(proofRequests))
  } catch (e) {
    // capture error for safe set
    captureError(e)
    console.log(`persistProofRequestsSaga: ${e}`)
  }
}

export function* hydrateProofRequestsSaga(): Generator<*, *, *> {
  try {
    const proofRequests: string = yield call(getHydrationItem, PROOF_REQUESTS)
    if (proofRequests) {
      yield put(hydrateProofRequests(JSON.parse(proofRequests)))
    }
  } catch (e) {
    // capture error for safe get
    captureError(e)
    console.log(`hydrateProofRequestSaga: ${e}`)
  }
}

export function* proofAccepted(
  action: ProofRequestAcceptedAction
): Generator<*, *, *> {
  const { uid } = action
  const remoteDid: string = yield select(getProofRequestPairwiseDid, uid)
  const userPairwiseDid: string | null = yield select(
    getUserPairwiseDid,
    remoteDid
  )
  if (!userPairwiseDid) {
    captureError(new Error('OCS-002 No pairwise connection found'))
    yield put(
      errorSendProofFail(uid, {
        code: 'OCS-002',
        message: 'No pairwise connection found',
      })
    )
    return
  }

  const proofRequestPayload: ProofRequestPayload = yield select(
    getProofRequest,
    uid
  )
  const { proofHandle } = proofRequestPayload
  const connection: {
    remotePairwiseDID: string,
    remoteName: string,
  } & Connection = yield select(getRemotePairwiseDidAndName, userPairwiseDid)

  if (!connection.vcxSerializedConnection) {
    captureError(new Error('OCS-002 No pairwise connection found'))
    yield put(
      errorSendProofFail(uid, {
        code: 'OCS-002',
        message: 'No pairwise connection found',
      })
    )
    return
  }

  try {
    const connectionHandle: number = yield call(
      getHandleBySerializedConnection,
      connection.vcxSerializedConnection
    )
    yield call(sendProofApi, proofHandle, connectionHandle)
    yield put(sendProofSuccess(uid))
    yield put(resetTempProofData(uid))
    // turn off screen awake that was activated by generate-proof
    KeepScreenOn.setKeepScreenOn(false)
  } catch (e) {
    KeepScreenOn.setKeepScreenOn(false)
    captureError(e)
    yield put(errorSendProofFail(uid, ERROR_SEND_PROOF(e.message)))
  }
}

export function* watchProofRequestAccepted(): any {
  yield takeLatest(PROOF_REQUEST_ACCEPTED, proofAccepted)
}

export function* watchPersistProofRequests(): any {
  yield takeEvery(
    [PROOF_REQUEST_SHOWN, PROOF_REQUEST_RECEIVED, PROOF_SERIALIZED],
    persistProofRequestsSaga
  )
}

export const proofRequestAutoFill = (
  uid: string,
  requestedAttributes: Array<Attribute>
) => ({
  type: PROOF_REQUEST_AUTO_FILL,
  uid,
  requestedAttributes,
})

export const proofRequestReceived = (
  payload: AdditionalProofDataPayload,
  payloadInfo: NotificationPayloadInfo
) => ({
  type: PROOF_REQUEST_RECEIVED,
  payload,
  payloadInfo,
})

export const proofSerialized = (serializedProof: string, uid: string) => ({
  type: PROOF_SERIALIZED,
  serializedProof,
  uid,
})

export function* serializeProofRequestSaga(
  action: ProofRequestReceivedAction
): Generator<*, *, *> {
  try {
    const { proofHandle } = action.payload
    const serializedProof: string = yield call(proofSerialize, proofHandle)
    yield put(proofSerialized(serializedProof, action.payloadInfo.uid))
  } catch (e) {
    captureError(e)
    // TODO:KS Add action for serialization failure
    // need to figure out what happens if serialization fails
    console.log('failed to serialize proof')
  }
}

export function* watchProofRequestReceived(): any {
  yield takeEvery(PROOF_REQUEST_RECEIVED, serializeProofRequestSaga)
}

export const updateProofHandle = (proofHandle: number, uid: string) => ({
  type: UPDATE_PROOF_HANDLE,
  proofHandle,
  uid,
})

export const proofRequestShowStart = (uid: string) => ({
  type: PROOF_REQUEST_SHOW_START,
  uid,
})

export default function proofRequestReducer(
  state: ProofRequestStore = proofRequestInitialState,
  action: ProofRequestAction
) {
  switch (action.type) {
    case PROOF_REQUEST_RECEIVED:
      return {
        ...state,
        [action.payloadInfo.uid]: {
          ...action.payload,
          ...action.payloadInfo,
          status: PROOF_REQUEST_STATUS.RECEIVED,
          proofStatus: PROOF_STATUS.NONE,
        },
      }

    case PROOF_REQUEST_SHOW_START: {
      const data = state[action.uid].data
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: PROOF_REQUEST_STATUS.RECEIVED,
          proofStatus: PROOF_STATUS.NONE,
          missingAttributes: {},
          data: {
            ...data,
            requestedAttributes: data.requestedAttributes.map(attribute => {
              if (Array.isArray(attribute) && attribute.length > 0) {
                return {
                  label: attribute[0].label,
                }
              }
              return { label: attribute.label }
            }),
          },
        },
      }
    }

    case PROOF_REQUEST_SHOWN:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: PROOF_REQUEST_STATUS.SHOWN,
        },
      }

    case PROOF_REQUEST_ACCEPTED:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: PROOF_REQUEST_STATUS.ACCEPTED,
        },
      }

    case PROOF_REQUEST_IGNORED:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: PROOF_REQUEST_STATUS.IGNORED,
        },
      }

    case PROOF_REQUEST_REJECTED:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: PROOF_REQUEST_STATUS.REJECTED,
        },
      }

    case PROOF_REQUEST_AUTO_FILL:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          data: {
            ...state[action.uid].data,
            requestedAttributes: [...action.requestedAttributes],
          },
        },
      }

    case SEND_PROOF:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofStatus: PROOF_STATUS.SENDING_PROOF,
        },
      }

    case SEND_PROOF_SUCCESS:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofStatus: PROOF_STATUS.SEND_PROOF_SUCCESS,
        },
      }

    case PROOF_FAIL:
    case SEND_PROOF_FAIL:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofStatus: PROOF_STATUS.SEND_PROOF_FAIL,
        },
      }

    case MISSING_ATTRIBUTES_FOUND:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          missingAttributes: action.missingAttributes,
        },
      }
    case HYDRATE_PROOF_REQUESTS:
      return action.proofRequests

    case RESET:
      return proofRequestInitialState

    case PROOF_SERIALIZED:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          vcxSerializedProofRequest: action.serializedProof,
        },
      }

    case UPDATE_PROOF_HANDLE:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofHandle: action.proofHandle,
        },
      }
    default:
      return state
  }
}


<|start_filename|>e2e/proof-request.spec.js<|end_filename|>
describe('Proof Request', () => {
  it('Received Proof Request, Auto-fill, Generate, and Send', async () => {
    // verify Proof Request popup shows up
    // verify close button, requested attributes, ignore, and generate button is present
    // should have 1 attribute value missing
    // self attest popup should shows up
    // verify "GENERATE" button is disabled
    // tap on self attested entry and enter value
    // verify "GENERATE" button is enabled
    // tap on generate button
    // Auto-fill screen should come up
    // tap on send
    // verify Continue popup shows up
    // tap on continue
    // verify user is redirected to Dashboard screen
    // tap on Connection bubble from which Proof Request came
    // verify Connection History popup shows up
    // verify delete connection, close popup, connection logo, and connection history are present
    // verify Proof Request "SHARED" entry is present
    // tap on "SHARED"
    // verify History Details screen shows up
    // verify sent attributes is present
    // verify back button is present
    // tap on back button
    // user should come back to connection history popup
    // tap close button
    // user should back to dashboard screen
  })

  it('Received Claim Offer and Ignore', async () => {
    // verify Proof Request popup shows up
    // verify close button, attributes, ignore, and accept button is present
    // tap on Ignore
    // verify user is redirected to Dashboard screen
  })
})


<|start_filename|>app/store/__tests__/route-store.spec.js<|end_filename|>
// @flow
import routeReducer, { handleRouteUpdate } from '../route-store'
import { authenticationRoute } from '../../common/route-constants'
import { initialTestAction } from '../../common/type-common'

describe('route should update properly', () => {
  function setup() {
    return {
      initialState: routeReducer(undefined, initialTestAction()),
    }
  }

  it('should update current screen route', () => {
    const { initialState } = setup()
    const expectedState = {
      currentScreen: authenticationRoute,
    }
    const actualState = routeReducer(
      initialState,
      handleRouteUpdate(authenticationRoute)
    )
    expect(actualState).toMatchObject(expectedState)
  })
})


<|start_filename|>app/components/index.js<|end_filename|>
// @flow
import React from 'react'

export { default as Badge } from './badge'
export { default as InfoSectionList } from './info-section-list'
export { ListItem, ListItemData } from './info-section-list'
export { Avatar } from './avatar/avatar'
export { BadgeAvatar } from './avatar/badge-avatar'
export {
  Container,
  CustomView,
  headerStyles,
  CustomSafeAreaView,
} from './layout'
export { default as Icon } from './icon'
export { default as CustomText, styles as TextStyles } from './text'
export { default as CustomButton } from './button'
export { default as QRScanner } from './qr-scanner/qr-scanner'
export { default as TouchId } from './touch-id/touch-id'
export { default as Request } from './request/request'
export { default as PinCodeBox } from './pin-code/pin-code-box'
export {
  default as ImageColorPicker,
} from './image-color-picker/image-color-picker'
export {
  default as ConnectionTheme,
} from './image-color-picker/connection-theme'
export { default as AvatarsPair } from './AvatarsPair'
export { default as CustomModal } from './CustomModal'
export {
  default as ClaimProofHeader,
} from './claim-proof-header/claim-proof-header'
export { default as Separator } from './separator'
export { default as FooterActions } from './footer-actions/footer-actions'
export { default as CustomList } from './custom-list/custom-list'
export { default as CustomDate } from './custom-date/custom-date'
export { default as UserAvatar } from './user-avatar/user-avatar'
export { default as Keyboard } from './keyboard/keyboard'
export { default as CustomHeader } from './custom-header/custom-header'
export { default as Loader } from './loader/loader'


<|start_filename|>e2e/connection-invitation.spec.js<|end_filename|>
describe('Connection Invitation', () => {
  it('Enter Pin Code, show Connection Invitation, and Accept Invitation', async () => {
    // test enter Pin Code screen
    // test Invitation screen shows up
    // verify inviter and invitee avatar is present
    // test Accept button is tap-able
    // verify Continue popup shows up
    // tap on continue
    // verify user is redirected to Dashboard screen
    // verify new Connection is present
    // tap on new Connection bubble
    // verify Connection History popup shows up
    // verify new Connection "Connected" entry is present
    // test delete connection, close popup, and connection logo all are present
    // tap on close button
    // user should come back to dashboard screen
  })

  it('Enter Pin Code, show Connection Invitation, and Deny Invitation', async () => {
    // test enter pin code screen
    // test Connection Invitation screen came up
    // verify inviter and invitee avatar is present
    // tap on Deny button
    // verify user is redirected to Dashboard screen
  })

  it('Multiple Connection', async () => {
    // verify multiple connection on dashboard
  })
})


<|start_filename|>app/backup/generate-phrase.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { Image, Dimensions } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import type { Store } from '../store/type-store'
import type { ReactNavigation } from '../common/type-common'
import {
  Container,
  CustomView,
  CustomText,
  Icon,
  CustomButton,
  CustomHeader,
  Loader,
} from '../components'
import { isBiggerThanShortDevice } from '../common/styles'
import { genRecoveryPhraseRoute, verifyRecoveryPhraseRoute } from '../common'
import { color } from '../common/styles/constant'
import type {
  GenerateRecoveryPhraseProps,
  GenerateRecoveryPhraseState,
  Passphrase,
  ChatBubbleDimensions,
  PassphraseTextProps,
  PassphraseErrorProps,
} from './type-backup'
import { BACKUP_STORE_STATUS } from './type-backup'
import { generateRecoveryPhrase } from './backup-store'
import {
  RECOVERY_PHRASE_CLOSE_TEST_ID,
  SUBMIT_RECOVERY_PHRASE_TEST_ID,
  SUBMIT_RECOVERY_PHRASE_BUTTON_TITLE,
} from './backup-constants'
import styles, { chatBubbleTextOffset } from './styles'
import { getBackupPassphrase, getBackupStatus } from '../store/store-selector'
import { PASSPHRASE_GENERATION_ERROR } from '../common'

const closeImage = require('../images/iconClose.png')
const transparentBands = require('../images/transparentBands.png')
const textBubble = require('../images/textBubble.png')

const PassphraseLoader = () => {
  return (
    <CustomView style={[styles.genRecoveryPhraseLoadingContainer]}>
      <Loader delay={10} showMessage={false} size={30} />
    </CustomView>
  )
}

const PassphraseError = (props: PassphraseErrorProps) => {
  return (
    <CustomView
      style={[
        styles.genRecoveryPhraseContainer,
        {
          width:
            props.chatBubbleDimensions && props.chatBubbleDimensions.width
              ? props.chatBubbleDimensions.width - chatBubbleTextOffset
              : null,
        },
      ]}
    >
      <CustomText transparentBg darkgray center>
        {PASSPHRASE_GENERATION_ERROR}
      </CustomText>
    </CustomView>
  )
}

const PassphraseText = (props: PassphraseTextProps) => {
  return (
    <CustomView
      style={[
        styles.genRecoveryPhraseContainer,
        {
          //width of textContainer is chatBubbleDimensions width minus chatBubbleTextOffset
          //so that passPhrase text is not cutting beyond the chatBubble
          width:
            props.chatBubbleDimensions && props.chatBubbleDimensions.width
              ? props.chatBubbleDimensions.width - chatBubbleTextOffset
              : null,
        },
      ]}
    >
      <CustomText transparentBg style={[styles.genRecoveryPhrase]}>
        {props.recoveryPassphrase.phrase}
      </CustomText>
    </CustomView>
  )
}

export class GenerateRecoveryPhrase extends PureComponent<
  GenerateRecoveryPhraseProps,
  GenerateRecoveryPhraseState
> {
  state = {
    chatBubbleDimensions: {
      width: 0,
      height: 0,
      x: 0,
      y: 0,
    },
  }

  componentDidMount() {
    this.props.generateRecoveryPhrase()
  }

  verifyRecoveryPhrase = () => {
    const { navigation: { navigate, state } } = this.props

    navigate(verifyRecoveryPhraseRoute, {
      recoveryPassphrase: this.props.recoveryPassphrase.hash,
      initialRoute: state.params.initialRoute,
    })
  }

  static navigationOptions = ({ navigation }) => ({
    header: (
      <CustomHeader
        flatHeader
        largeHeader
        backgroundColor={color.bg.eleventh.color}
      >
        <CustomView />

        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => navigation.goBack(null)}
            testID={RECOVERY_PHRASE_CLOSE_TEST_ID}
            iconStyle={[styles.headerIcon]}
            src={closeImage}
          />
        </CustomView>
      </CustomHeader>
    ),
    gesturesEnabled: false,
  })

  //TODO fix refactor UI
  //first the image should be used as a ImageBackground component
  ImageContents = (
    recoveryStatus: string,
    recoveryPassphrase: Passphrase,
    chatBubbleDimensions: ChatBubbleDimensions
  ) => {
    if (recoveryStatus === BACKUP_STORE_STATUS.GENERATE_PHRASE_LOADING) {
      return <PassphraseLoader />
    }

    if (
      recoveryStatus === BACKUP_STORE_STATUS.GENERATE_PHRASE_FAILURE ||
      recoveryStatus === BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_FAILURE
    ) {
      // This block is where we need to try handling passphrase generation differently
      return <PassphraseError chatBubbleDimensions={chatBubbleDimensions} />
    }
    return (
      <PassphraseText
        recoveryPassphrase={recoveryPassphrase}
        chatBubbleDimensions={chatBubbleDimensions}
      />
    )
  }

  setChatBubbleDimensions = (chatBubbleDimensions: ChatBubbleDimensions) => {
    this.setState({
      chatBubbleDimensions,
    })
  }

  render() {
    const { recoveryPassphrase, recoveryStatus } = this.props
    const disableButton =
      recoveryStatus === BACKUP_STORE_STATUS.GENERATE_PHRASE_FAILURE ||
      recoveryStatus === BACKUP_STORE_STATUS.GENERATE_PHRASE_LOADING ||
      recoveryStatus === BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_FAILURE

    return (
      <Container style={[styles.genRecovery]} safeArea>
        <Image source={transparentBands} style={[styles.backgroundImage]} />
        <Container>
          <CustomView>
            <CustomText
              transparentBg
              numberOfLines={1}
              style={[styles.genRecoveryText]}
            >
              Recovery Phrase generated
            </CustomText>
          </CustomView>
          <CustomView center>
            <CustomText
              center
              transparentBg
              style={[styles.genRecoveryMessage]}
            >
              This is your Recovery Phrase. Write it down, and don't share it
              with anyone.
            </CustomText>
          </CustomView>
          <CustomView center>
            <Image
              source={textBubble}
              style={[styles.imageIcon]}
              onLayout={event =>
                this.setChatBubbleDimensions(event.nativeEvent.layout)
              }
            />
            {this.ImageContents(
              recoveryStatus,
              recoveryPassphrase,
              this.state.chatBubbleDimensions
            )}
          </CustomView>
          <CustomView center>
            <CustomText
              center
              transparentBg
              style={[styles.genRecoverySecondMessage]}
            >
              You will need this Recovery Phrase to restore from a backup. Keep
              it safe.
            </CustomText>
          </CustomView>
        </Container>
        <CustomView>
          <CustomView center>
            <CustomText
              transparentBg
              center
              style={[styles.genRecoverySmallMessage]}
            >
              Are you sure you wrote it down?
            </CustomText>
          </CustomView>
          <CustomButton
            disabled={disableButton}
            large={isBiggerThanShortDevice ? true : false}
            onPress={this.verifyRecoveryPhrase}
            testID={SUBMIT_RECOVERY_PHRASE_TEST_ID}
            style={[styles.submitButton]}
            customColor={{
              color: color.bg.eleventh.color,
              fontWeight: '600',
              fontSize: 18,
            }}
            title={SUBMIT_RECOVERY_PHRASE_BUTTON_TITLE}
          />
        </CustomView>
      </Container>
    )
  }
}

const mapStateToProps = (state: Store) => {
  return {
    recoveryPassphrase: getBackupPassphrase(state),
    recoveryStatus: getBackupStatus(state),
  }
}
const mapDispatchToProps = dispatch =>
  bindActionCreators({ generateRecoveryPhrase }, dispatch)

export default createStackNavigator({
  [genRecoveryPhraseRoute]: {
    screen: connect(mapStateToProps, mapDispatchToProps)(
      GenerateRecoveryPhrase
    ),
  },
})


<|start_filename|>app/lock/lock-store.js<|end_filename|>
// @flow
import { put, takeLatest, take, select, call, all } from 'redux-saga/effects'
import type { CustomError } from '../common/type-common'
import {
  PENDING_REDIRECT,
  CLEAR_PENDING_REDIRECT,
  SET_PIN,
  LOCK_ENABLE,
  LOCK_FAIL,
  CHECK_PIN,
  CHECK_PIN_FAIL,
  CHECK_PIN_IDLE,
  CHECK_PIN_SUCCESS,
  UNLOCK_APP,
  LONG_PRESSED_IN_LOCK_SELECTION_SCREEN,
  PRESSED_ON_OR_IN_LOCK_SELECTION_SCREEN,
  RESET_TOUCH_EVENT_VARIABLES,
  SHOW_DEV_MODE,
  HIDE_DEV_MODE,
  ENABLE_TOUCHID,
  DISABLE_TOUCHID,
  CHECK_TOUCHID,
  TOUCH_ID_STORAGE_KEY,
  PIN_ENABLED_KEY,
  IN_RECOVERY,
  PIN_HASH,
  SALT,
} from './type-lock'
import type {
  PendingRedirection,
  LockStore,
  AddPendingRedirectAction,
  ClearPendingRedirectAction,
  SetPinAction,
  LockEnable,
  InRecovery,
  LockFail,
  CheckPinAction,
  CheckPinFailAction,
  CheckPinSuccessAction,
  LockActions,
  UnlockAppAction,
  CheckPinIdleAction,
  LongPressedInLockSelectionScreen,
  PressedOnOrInLockSelectionScreen,
  ResetTouchEventVariables,
  EnableDevMode,
  DisableDevMode,
  CheckTouchIdAction,
  EnableTouchIdAction,
  DisableTouchIdAction,
} from './type-lock'
import {
  walletGet,
  walletSet,
  secureSet,
  secureGet,
  safeGet,
  safeSet,
  getHydrationItem,
} from '../services/storage'
import { pinHash, generateSalt } from './pin-hash'
import { Platform } from 'react-native'
import { getVcxInitializationState } from '../store/store-selector'
import { ensureVcxInitSuccess } from '../store/config-store'
import { captureError } from '../services/error/error-handler'

const initialState: LockStore = {
  pendingRedirection: null,
  checkPinStatus: CHECK_PIN_IDLE,
  // we are assuming that app will be locked by default
  // and it will be unlocked either when user set security first time
  // or user unlock the app every time user opens the app
  // this property needs to be set accordingly
  isAppLocked: true,
  isLockEnabled: 'false',
  inRecovery: 'false',
  isTouchIdEnabled: false,
  showDevMode: false,
  error: {
    code: null,
    message: null,
  },
}

export function addPendingRedirection(
  pendingRedirection: Array<PendingRedirection>
): AddPendingRedirectAction {
  return {
    type: PENDING_REDIRECT,
    pendingRedirection,
  }
}

export const clearPendingRedirect = (): ClearPendingRedirectAction => ({
  type: CLEAR_PENDING_REDIRECT,
})

export const setPinAction = (pin: string): SetPinAction => ({
  type: SET_PIN,
  pin,
})

export const lockEnable = (isLockEnable: string): LockEnable => ({
  type: LOCK_ENABLE,
  isLockEnable,
})

export const setInRecovery = (inRecovery: string): InRecovery => ({
  type: IN_RECOVERY,
  inRecovery,
})

export const lockFail = (error: CustomError): LockFail => ({
  type: LOCK_FAIL,
  error,
})

export function* setPin(action: SetPinAction): Generator<*, *, *> {
  try {
    const salt: string = yield call(generateSalt)
    const hashedPin: string = yield call(pinHash, action.pin.toString(), salt)
    yield call(secureSet, PIN_HASH, hashedPin)
    yield call(secureSet, SALT, salt)
    yield call(safeSet, PIN_ENABLED_KEY, 'true')
    yield call(safeSet, IN_RECOVERY, 'false')
    yield put(lockEnable('true'))
  } catch (e) {
    captureError(e)
    yield put(lockFail(e))
  }
}

export const enableTouchIdAction = () => ({
  type: ENABLE_TOUCHID,
})
export const disableTouchIdAction = (): DisableTouchIdAction => ({
  type: DISABLE_TOUCHID,
})

export function* enableTouchId(
  action: EnableTouchIdAction
): Generator<*, *, *> {
  try {
    yield call(safeSet, TOUCH_ID_STORAGE_KEY, 'true')
  } catch (e) {
    yield e
  }
}

export function* disableTouchId(
  action: DisableTouchIdAction
): Generator<*, *, *> {
  try {
    yield call(safeSet, TOUCH_ID_STORAGE_KEY, 'false')
  } catch (e) {
    yield e
  }
}

export function* watchEnableTouchId(): any {
  yield takeLatest(ENABLE_TOUCHID, enableTouchId)
}
export function* watchDisableTouchId(): any {
  yield takeLatest(DISABLE_TOUCHID, disableTouchId)
}

export function* watchSetPin(): any {
  yield takeLatest(SET_PIN, setPin)
}

export const checkPinSuccess = (): CheckPinSuccessAction => ({
  type: CHECK_PIN_SUCCESS,
})

export const checkPinFail = (): CheckPinFailAction => ({
  type: CHECK_PIN_FAIL,
})

export const checkPinAction = (pin: string): CheckPinAction => ({
  type: CHECK_PIN,
  pin,
})

export const enableDevMode = (): EnableDevMode => ({
  type: SHOW_DEV_MODE,
})

export const disableDevMode = (): DisableDevMode => ({
  type: HIDE_DEV_MODE,
})

export function* checkPin(action: CheckPinAction): Generator<*, *, *> {
  const inRecovery: string | null = yield call(safeGet, IN_RECOVERY)

  if (inRecovery === 'true') {
    const vcxResult = yield* ensureVcxInitSuccess()
    if (vcxResult && vcxResult.fail) {
      return
    }
  }
  const salt: string = yield call(getHydrationItem, SALT)
  const expectedPinHash: string = yield call(getHydrationItem, PIN_HASH)
  const enteredPinHash: string = yield call(pinHash, action.pin, salt)

  if (expectedPinHash === enteredPinHash) {
    yield put(checkPinSuccess())
    if (inRecovery == 'true') {
      yield call(safeSet, IN_RECOVERY, 'false')
      yield put(setInRecovery('false'))
    }
  } else {
    captureError(new Error('Check pin fail'))
    yield put(checkPinFail())
  }
}

export const longPressedInLockSelectionScreen = (): LongPressedInLockSelectionScreen => ({
  type: LONG_PRESSED_IN_LOCK_SELECTION_SCREEN,
})

export const pressedOnOrInLockSelectionScreen = (): PressedOnOrInLockSelectionScreen => ({
  type: PRESSED_ON_OR_IN_LOCK_SELECTION_SCREEN,
})

export const checkTouchIdAction = (
  isTouchIdEnabled: boolean
): CheckTouchIdAction => ({
  type: CHECK_TOUCHID,
  isTouchIdEnabled,
})

export function* checkTouchId(action: CheckTouchIdAction): Generator<*, *, *> {
  const isTouchIdEnabled = yield call(safeGet, TOUCH_ID_STORAGE_KEY)
  if (isTouchIdEnabled === true) {
    yield put(checkPinSuccess())
  } else {
    yield put(checkPinFail())
  }
}

export function* watchCheckPin(): any {
  yield takeLatest(CHECK_PIN, checkPin)
}

export function* watchPressEventInLockSelectionScreen(): any {
  while (true) {
    yield take('LONG_PRESSED_IN_LOCK_SELECTION_SCREEN')
    for (var i = 1; i <= 10; i++) {
      yield take('PRESSED_ON_OR_IN_LOCK_SELECTION_SCREEN')
    }
    yield put(enableDevMode())
  }
}

export const unlockApp = (): UnlockAppAction => ({
  type: UNLOCK_APP,
})

export const checkPinStatusIdle = (): CheckPinIdleAction => ({
  type: CHECK_PIN_IDLE,
})

export function* watchLock(): any {
  yield all([
    watchCheckPin(),
    watchSetPin(),
    watchEnableTouchId(),
    watchDisableTouchId(),
  ])
}

export default function lockReducer(
  state: LockStore = initialState,
  action: LockActions
): LockStore {
  switch (action.type) {
    case PENDING_REDIRECT:
      return {
        ...state,
        pendingRedirection: action.pendingRedirection,
      }
    case LOCK_ENABLE:
      return {
        ...state,
        isLockEnabled: action.isLockEnable,
      }
    case IN_RECOVERY:
      return {
        ...state,
        inRecovery: action.inRecovery,
      }
    case LOCK_FAIL:
      return {
        ...state,
        isLockEnabled: 'false',
        error: action.error,
      }
    case CLEAR_PENDING_REDIRECT:
      return {
        ...state,
        pendingRedirection: null,
      }
    case CHECK_PIN_SUCCESS:
      return {
        ...state,
        checkPinStatus: CHECK_PIN_SUCCESS,
      }
    case CHECK_PIN_FAIL:
      return {
        ...state,
        checkPinStatus: CHECK_PIN_FAIL,
      }
    case CHECK_PIN_IDLE:
      return {
        ...state,
        checkPinStatus: CHECK_PIN_IDLE,
      }
    case UNLOCK_APP:
      return {
        ...state,
        isAppLocked: false,
      }
    case ENABLE_TOUCHID:
      return {
        ...state,
        isTouchIdEnabled: true,
      }
    case SHOW_DEV_MODE:
      return {
        ...state,
        showDevMode: true,
      }
    case HIDE_DEV_MODE:
      return {
        ...state,
        showDevMode: false,
      }
    case DISABLE_TOUCHID:
      return {
        ...state,
        isTouchIdEnabled: false,
      }
    case CHECK_TOUCHID:
      return {
        ...state,
        isTouchIdEnabled: action.isTouchIdEnabled,
      }
    default:
      return state
  }
}


<|start_filename|>app/components/input-control/input-control.js<|end_filename|>
// @flow

// the component in which user can enter payment address, validation on address, error and how the text input would expand on the basis of how much text user has typed
// and other things would be combined into a component which could be used as
// <ControlInput validation={this.throttledAsyncValidationFunction} name="payment address" label="To" />
// <ControlInput label="For" />
// if validation prop is not specified then validation will not be applied
// if validation prop is specified, then we would throttle the function calls and assumes that validation function is async
// we should also be canceling the previous validation function calls, because ordering in async results are not guaranteed
// we could use saga to throttle and cancel previous calls if a new call is made during the progress of previous call
// we could use throttle and takeLatest combined to make this happen
// This input control does not need to over designed whatever can satisfy our requirements for now
// when and if we would new features, we would add those later

import React, { PureComponent } from 'react'
import { View, ListView, StyleSheet } from 'react-native'
import { CustomView } from '../layout/custom-view'
import { CustomList } from '../custom-list/custom-list'
import { TextInput } from 'react-native'
import { CustomText, Container, Icon } from '../index'
import throttle from 'lodash.throttle'
import { color } from '../../common/styles/constant'
import type { InputControlProps } from './type-input-control'

export default class ControlInput extends PureComponent<
  InputControlProps,
  void
> {
  throttledValidate = throttle(
    () => {
      if (this.props.validation) {
        this.props.validation()
      }
    },
    300,
    { leading: true }
  )

  onTextChange = (event: string) => {
    this.props.onChangeText(event, this.props.name)
    if (this.props.validation) {
      this.throttledValidate()
    }
  }

  render() {
    // Here we should call out any special props we need, otherwise any native props that <TextInput /> uses will be assigned to textInputProps
    const {
      label,
      multiline,
      isValid,
      onChangeText,
      validation,
      name,
      ...textInputProps
    } = this.props
    return (
      <CustomView
        style={[styles.container]}
        testID={`${label}-mainview-wallet-send-details`}
      >
        <CustomView
          fifth
          center
          row
          horizontalSpace
          testID={`${label}-subview-wallet-send-details`}
        >
          <CustomView fifth right style={[{ width: 35, paddingVertical: 25 }]}>
            <CustomText
              h5
              semiBold
              bg="tertiary"
              transparentBg
              quinaryText
              style={[{ lineHeight: 20 }]}
            >
              {`${label}:`}
            </CustomText>
          </CustomView>
          <CustomView
            fifth
            left
            horizontalSpace
            style={[
              {
                width: '83%',
              },
            ]}
            testID={`${label}-textinput-wallet-send-details`}
          >
            <TextInput
              testID={`${label}-token-send-details-label`}
              accessible={true}
              accessibilityLabel={`${label}-token-send-details-label`}
              style={[styles.textInput]}
              underlineColorAndroid="transparent"
              multiline={multiline ? true : false}
              onChangeText={this.onTextChange}
              {...textInputProps}
            />
          </CustomView>
          {this.props.validation && isValid === 'SUCCESS' ? (
            <SuccessIcon />
          ) : isValid === 'ERROR' ? (
            <ErrorIcon />
          ) : (
            <CustomView />
          )}
        </CustomView>
        {/* for validation */}
        {this.props.validation && isValid === 'ERROR' ? (
          <ErrorCustomInput>Invalid payment address</ErrorCustomInput>
        ) : null}
      </CustomView>
    )
  }
}

const ErrorCustomInput = props => {
  return (
    <CustomView column style={[{ paddingVertical: 5 }, styles.invalidBgColor]}>
      <CustomText
        center
        transparentBg
        primary
        style={[styles.errorCustomText, styles.invalidTextColor]}
      >
        {props.children}
      </CustomText>
    </CustomView>
  )
}

const SuccessIcon = () => {
  return (
    <CustomView>
      <Icon small src={require('../../images/Success.png')} />
    </CustomView>
  )
}

const ErrorIcon = () => {
  return (
    <CustomView style={[styles.errorIconView]} hCenter>
      <CustomText
        style={[
          {
            color: color.bg.tenth.font.color,
            fontSize: 13,
          },
        ]}
        center
        transparentBg
      >
        !
      </CustomText>
    </CustomView>
  )
}

const styles = StyleSheet.create({
  container: { borderBottomWidth: 1, borderBottomColor: color.border.primary },
  invalidBgColor: {
    backgroundColor: color.bg.tenth.color,
  },
  invalidTextColor: {
    color: color.bg.tenth.font.color,
  },
  errorIconView: {
    borderWidth: 2,
    borderColor: color.bg.tenth.font.color,
    borderRadius: 100,
    padding: 1,
    width: 22,
    height: 22,
  },
  errorCustomText: {
    fontSize: 14,
    lineHeight: 16,
    letterSpacing: -0.35,
  },
  textInput: {
    width: '100%',
    fontStyle: 'italic',
    fontSize: 17,
    lineHeight: 20,
  },
})


<|start_filename|>app/sms-pending-invitation/sms-pending-invitation-store.js<|end_filename|>
// @flow
import {
  put,
  takeLatest,
  takeEvery,
  call,
  take,
  all,
  select,
} from 'redux-saga/effects'
import type { CustomError } from '../common/type-common'
import type {
  SMSPendingInvitationStore,
  SMSPendingInvitationAction,
  SMSPendingInvitationStatusType,
  SMSPendingInvitationPayload,
  SMSPendingInvitationRequestAction,
} from './type-sms-pending-invitation'
import type { InvitationPayload } from '../invitation/type-invitation'
import {
  SMS_PENDING_INVITATION_REQUEST,
  SMS_PENDING_INVITATION_RECEIVED,
  SMS_PENDING_INVITATION_FAIL,
  SMS_PENDING_INVITATION_SEEN,
  SMSPendingInvitationStatus,
  SAFE_TO_DOWNLOAD_SMS_INVITATION,
} from './type-sms-pending-invitation'
import { invitationDetailsRequest, getInvitationLink } from '../api/api'
import {
  ERROR_PENDING_INVITATION_RESPONSE_PARSE,
  ERROR_PENDING_INVITATION_RESPONSE_PARSE_CODE,
} from '../api/api-constants'
import {
  getAgencyUrl,
  getCurrentScreen,
  getHydrationState,
} from '../store/store-selector'
import { invitationReceived } from '../invitation/invitation-store'
import {
  HYDRATED,
  UNSAFE_SCREENS_TO_DOWNLOAD_SMS,
} from '../store/type-config-store'
import { RESET } from '../common/type-common'
import { captureError } from '../services/error/error-handler'
import { isValidInvitationUrl } from '../components/qr-scanner/qr-invitation-url-validator'

const initialState = {}

export const getSmsPendingInvitation = (smsToken: string) => ({
  type: SMS_PENDING_INVITATION_REQUEST,
  smsToken,
})

export const smsPendingInvitationReceived = (
  smsToken: string,
  data: SMSPendingInvitationPayload
) => ({
  type: SMS_PENDING_INVITATION_RECEIVED,
  data,
  smsToken,
})

export const smsPendingInvitationFail = (
  smsToken: string,
  error: CustomError
) => ({
  type: SMS_PENDING_INVITATION_FAIL,
  smsToken,
  error,
})

export const smsPendingInvitationSeen = (smsToken: string) => ({
  type: SMS_PENDING_INVITATION_SEEN,
  smsToken,
})

// Below action tells that now user can't change the environment
// and so whatever environment we have available now, we can go ahead and
// start downloading SMS invitation from that environment
export const safeToDownloadSmsInvitation = () => ({
  type: SAFE_TO_DOWNLOAD_SMS_INVITATION,
})

export const convertSmsPayloadToInvitation = (
  pendingInvitation: SMSPendingInvitationPayload
): InvitationPayload => ({
  senderEndpoint: pendingInvitation.senderAgencyDetail.endpoint,
  requestId: pendingInvitation.connReqId,
  senderAgentKeyDelegationProof:
    pendingInvitation.senderDetail.agentKeyDlgProof,
  senderName: pendingInvitation.senderDetail.name,
  senderDID: pendingInvitation.senderDetail.DID,
  senderLogoUrl: pendingInvitation.senderDetail.logoUrl,
  senderVerificationKey: pendingInvitation.senderDetail.verKey,
  targetName: pendingInvitation.targetName,
  senderAgencyDetail: pendingInvitation.senderAgencyDetail,
  senderDetail: pendingInvitation.senderDetail,
})

export function* callSmsPendingInvitationRequest(
  action: SMSPendingInvitationRequestAction
): Generator<*, *, *> {
  // we wait to download SMS invitation till we know that we are safe
  // because user can still change the environment and point to something else
  // to download sms invitation from updated environment
  // if a user is gone past lock selection screen, then we know we are safe
  // or user has already setup lock and is now coming for second SMS invitation
  // or user is not on one of these screens
  // splash screen, lock selection, dev environment switch
  const currentScreen: string = yield select(getCurrentScreen)
  if (UNSAFE_SCREENS_TO_DOWNLOAD_SMS.indexOf(currentScreen) > -1) {
    // user is on screens where he has chance to change environment details
    // so we wait for event which tells that we are safe
    yield take(SAFE_TO_DOWNLOAD_SMS_INVITATION)
  }

  // if we reach this point, that means either user was not on some unsafe screen
  // or we waited till safe action was raised, either way
  // we can now go ahead and start downloading SMS invitation

  // I lied a bit in above statement that we can start downloading SMS now
  // there is one more scenario that we need to consider before we can start
  // downloading sms, this saga can also be triggered if user already has an app
  // and user switched environments while setting up the app first time
  // so now we need to maintain switched environment for the lifetime of app
  // so we store those environment details in phone storage and
  // hydrate them when app is killed and started again
  // now, when user starts the app second time, user's updated config
  // might still not be fetched or app is not fully hydrated yet,
  // so, we wait for app to be hydrated if not already hydrated
  const isAppHydrated: boolean = yield select(getHydrationState)
  if (!isAppHydrated) {
    yield take(HYDRATED)
  }

  // now we are sure that user can't change the environment for first time app
  // and also we are sure that if user did update the environment first time
  // then we have got the updated config
  // and now, we can go ahead and start downloading SMS pending invitation

  const agencyUrl: string = yield select(getAgencyUrl)
  const { smsToken } = action

  try {
    // there can be two types of token that we can get from deep link
    // 1. it can be 8 characters token
    // 2. it can be a url that would return invitation details

    if (!smsToken) {
      throw new Error('No data in token received')
    }

    let invitationLink = {
      url: '',
    }
    if (smsToken.length < 12) {
      // we are assuming that if length is less than 12, then we got a token
      // get invitation link
      invitationLink = yield call(getInvitationLink, {
        agencyUrl,
        smsToken,
      })
    } else if (isValidInvitationUrl(smsToken)) {
      // check if we got the url, then directly assign url
      invitationLink = {
        url: smsToken,
      }
    } else {
      throw new Error('Not recognized for any type of token that we know')
    }

    // get pending invitation
    // TODO:KS Handle error for this API, all business logic and API related
    const pendingInvitationPayload = yield call(invitationDetailsRequest, {
      url: invitationLink.url,
    })

    yield put(
      invitationReceived({
        payload: convertSmsPayloadToInvitation(pendingInvitationPayload),
      })
    )
    yield put(smsPendingInvitationReceived(smsToken, pendingInvitationPayload))
  } catch (e) {
    let error: CustomError = {
      code: ERROR_PENDING_INVITATION_RESPONSE_PARSE_CODE,
      message: `${ERROR_PENDING_INVITATION_RESPONSE_PARSE}: ${e.message}`,
    }

    try {
      error = JSON.parse(e.message)
    } catch (e) {}
    captureError(e)
    yield put(smsPendingInvitationFail(smsToken, error))
  }
}

function* watchSmsPendingInvitationRequest(): any {
  yield takeEvery(
    SMS_PENDING_INVITATION_REQUEST,
    callSmsPendingInvitationRequest
  )
}

export function* watchSmsPendingInvitationSaga(): any {
  yield all([watchSmsPendingInvitationRequest()])
}

export default function smsPendingInvitationReducer(
  state: SMSPendingInvitationStore = initialState,
  action: SMSPendingInvitationAction
) {
  switch (action.type) {
    case SMS_PENDING_INVITATION_REQUEST:
      if (state[action.smsToken] !== undefined) {
        return state
      } else {
        return {
          ...state,
          [action.smsToken]: {
            payload: null,
            isFetching: true,
            status: SMSPendingInvitationStatus.NONE,
            error: null,
          },
        }
      }

    case SMS_PENDING_INVITATION_RECEIVED:
      return {
        ...state,
        [action.smsToken]: {
          ...state[action.smsToken],
          isFetching: false,
          payload: action.data,
          status: SMSPendingInvitationStatus.RECEIVED,
        },
      }

    case SMS_PENDING_INVITATION_FAIL:
      return {
        ...state,
        [action.smsToken]: {
          ...state[action.smsToken],
          payload: null,
          isFetching: false,
          error: action.error,
          status: SMSPendingInvitationStatus.FETCH_FAILED,
        },
      }

    case SMS_PENDING_INVITATION_SEEN:
      if (action.smsToken) {
        return {
          ...state,
          [action.smsToken]: {
            ...state[action.smsToken],
            status: SMSPendingInvitationStatus.SEEN,
          },
        }
      } else {
        return state
      }

    case RESET:
      return initialState

    default:
      return state
  }
}


<|start_filename|>__mocks__/modal-mock.js<|end_filename|>
// @flow
import React from 'react'

const MockModal = (props: any) =>
  React.createElement('Modal', props, props.children)

export default MockModal


<|start_filename|>app/lock/__tests__/lock-authorization.spec.js<|end_filename|>
// @flow
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { LockAuthorization } from '../lock-authorization'
import { getNavigation, getStore } from '../../../__mocks__/static-data'

describe('<LockAuthorization />', () => {
  function getProps() {
    return {
      onSuccess: jest.fn(),
      onFail: jest.fn(),
      navigation: {
        ...getNavigation({ onSuccess: jest.fn(), onAvoid: jest.fn() }),
      },
    }
  }

  let component
  let props
  let store
  let componentInstance

  beforeEach(() => {
    props = getProps()
    store = getStore()
    component = renderer.create(
      <Provider store={store}>
        <LockAuthorization {...props} />
      </Provider>
    )
    componentInstance = component.root.findByType(LockAuthorization).instance
  })

  it('should match snapshot', () => {
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('go back and call success onSuccess', () => {
    jest.useFakeTimers()
    componentInstance.onSuccess()
    expect(props.navigation.goBack).toHaveBeenCalled()
    jest.runAllTimers()
    // Ignoring flow error inside test, we need to create type
    // that understand return type for navigation props
    expect(
      props.navigation.state &&
        props.navigation.state.params &&
        // $FlowFixMe
        props.navigation.state.params.onSuccess
    ).toHaveBeenCalled()
  })

  it('go back and call onAvoid', () => {
    jest.useFakeTimers()
    componentInstance.onClose()
    expect(props.navigation.goBack).toHaveBeenCalled()
    jest.runAllTimers()
    expect(
      // $FlowFixMe
      props.navigation.state && props.navigation.state.params.onAvoid
    ).toHaveBeenCalled()
  })
})


<|start_filename|>app/proof-request/proof-modal.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, StyleSheet, Image } from 'react-native'
import { Button } from 'react-native-elements'
import Modal from 'react-native-modal'
import {
  CustomModal,
  AvatarsPair,
  CustomView,
  CustomText,
  Loader,
} from '../components'
import { color, font, OFFSET_1X } from '../common/styles'
import { PROOF_STATUS } from './type-proof-request'
import type {
  ProofModalProps,
  ProofModalState,
  ProofStatus,
} from './type-proof-request'

export default class ProofModal extends PureComponent<
  ProofModalProps,
  ProofModalState
> {
  state = {
    isVisible: false,
  }

  // only states for which claim request modal will be visible
  visibleStates = [PROOF_STATUS.SENDING_PROOF, PROOF_STATUS.SEND_PROOF_SUCCESS]

  successStates = [PROOF_STATUS.SEND_PROOF_SUCCESS]

  onContinue = () => {
    this.hideModal()
    setTimeout(() => {
      this.props.onContinue()
    }, 1)
  }

  showModal() {
    this.setState({ isVisible: true })
  }

  hideModal() {
    this.setState({ isVisible: false })
  }

  toggleModal(proofStatus: ProofStatus) {
    if (this.successStates.indexOf(proofStatus) > -1) {
      return this.onContinue()
    }

    if (this.visibleStates.indexOf(proofStatus) > -1) {
      this.showModal()
    } else {
      this.hideModal()
    }
  }

  componentDidMount() {
    // if modal is opened when it was unmounted or freshly mounted
    this.toggleModal(this.props.proofStatus)
  }

  componentWillReceiveProps(nextProps: ProofModalProps) {
    // if component was not unmounted, and claim request status updates
    if (this.props.proofStatus !== nextProps.proofStatus) {
      this.toggleModal(nextProps.proofStatus)
    }
  }

  render() {
    const message = 'Sending...'

    return (
      <CustomModal
        testID={'send-proof'}
        isVisible={this.state.isVisible}
        fullScreen
      >
        <CustomView center style={[styles.container]}>
          <CustomText
            h5
            center
            tertiary
            bg="tertiary"
            transparentBg
            style={[styles.message]}
            testID={`send-proof-message`}
            bold
          >
            {message}
          </CustomText>
          <Loader />
        </CustomView>
      </CustomModal>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    height: '90%',
  },
  message: {
    paddingTop: OFFSET_1X,
    marginBottom: OFFSET_1X / 2,
  },
})


<|start_filename|>app/qr-code/type-qr-code.js<|end_filename|>
// @flow
import type {
  InvitationReceivedActionData,
  InvitationReceivedAction,
} from '../invitation/type-invitation'
import type { ReactNavigation } from '../common/type-common'

export type QRCodeScannerScreenState = {
  isCameraAuthorized: boolean,
  isCameraEnabled: boolean,
  appState: ?string,
}

export type QRCodeScannerScreenProps = {
  currentScreen: string,
  invitationReceived: (
    data: InvitationReceivedActionData
  ) => InvitationReceivedAction,
  changeEnvironmentUrl: (url: string) => void,
} & ReactNavigation

export const MESSAGE_NO_CAMERA_PERMISSION = 'No Camera permission'

export const MESSAGE_ALLOW_CAMERA_PERMISSION =
  'Please allow connect me to access camera from camera settings'

export const MESSAGE_RESET_CONNECT_ME = 'Reset Connect.Me?'

export const MESSAGE_RESET_DETAILS = (name: string) =>
  `You are about to switch to ${name} which is a test network. This will reset Connect.Me and you will PERMANENTLY lose all of your claims and connections. Proceed?`


<|start_filename|>app/wallet/wallet-send-amount.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { Text, Animated } from 'react-native'
import { scale } from 'react-native-size-matters'
import { Container, CustomView, CustomText, CustomButton } from '../components'
import { Keyboard } from '../components'
import { color, MEDIUM_DEVICE, deviceHeight } from '../common/styles/constant'
import { SEND_TOKEN_BUTTON, FONT_SIZE_MAPPING } from './wallet-constants'
import styles from './styles'
import type {
  WalletSendAmountState,
  WalletSendAmountProps,
} from './type-wallet'
import { walletTabSendDetailsRoute } from '../common/route-constants'
import { selectTokenAmount } from './wallet-store'
import { getWalletBalance } from '../store/store-selector'
import type { Store } from '../store/type-store'
import { STORE_STATUS } from './type-wallet'
import { conversionFactorLength } from '../bridge/react-native-cxs/vcx-transformers'

class WalletSendAmount extends PureComponent<
  WalletSendAmountProps,
  WalletSendAmountState
> {
  _shake: any
  _tokenKeyboard: null | Keyboard
  state = {
    text: '',
  }

  constructor(props) {
    super(props)
    this._shake = new Animated.Value(0)
  }

  changeText = (text: string, animate: boolean) => {
    if (animate) {
      return this.shake()
    }
    return this.setState({ text })
  }

  shake = () => {
    this._shake.setValue(0)
    Animated.spring(this._shake, {
      toValue: 1,
      friction: 3,
      tension: 10,
      useNativeDriver: true,
    }).start(() => {
      this._shake.setValue(0)
    })
  }

  sendTokenAmount = () => {
    this.props.selectTokenAmount(this.state.text)
    if (this.state.text.length) {
      this.props.screenProps.navigation.navigate(walletTabSendDetailsRoute, {
        ...this.props.navigation,
      })
    }
  }

  saveTokenKeyboardRef = tokenKeyboard => {
    this._tokenKeyboard = tokenKeyboard
  }

  render() {
    const { text } = this.state

    // adjust fontSize based on text length
    const fontSize = scale(FONT_SIZE_MAPPING(text.length))
    const animatedStyle = {
      transform: [
        {
          translateX: this._shake.interpolate({
            inputRange: [0, 0.1, 0.2, 0.3, 0.4, 0.55, 0.7, 0.8, 0.9, 1],
            outputRange: [0, -10, 0, -10, 0, -10, 0, -10, 0, 0],
          }),
        },
      ],
    }
    const isSendDisabled = text.length < 1 || text === '0'

    return (
      <Container tertiary style={[styles.verticalSpacing]}>
        <CustomView>
          <CustomView verticalSpace>
            <CustomText
              animated
              formatNumber
              transparentBg
              center
              style={[
                animatedStyle,
                {
                  fontSize,
                  color: color.bg.seventh.font.fifth,
                  height: deviceHeight < MEDIUM_DEVICE ? 70 : 90,
                  lineHeight: deviceHeight < MEDIUM_DEVICE ? 75 : 80,
                },
              ]}
              numberOfLines={1}
            >
              {text || 0}
            </CustomText>
          </CustomView>
          <CustomText h6 center tertiary demibold uppercase transparentBg>
            sovrin tokens
          </CustomText>
        </CustomView>
        <Keyboard
          color={color.bg.seventh.font.fifth}
          onPress={this.changeText}
          maxValue={this.props.walletBalance}
          ref={this.saveTokenKeyboardRef}
          afterDecimalSeparatorMaxLength={conversionFactorLength}
        />
        <CustomView safeArea style={[styles.alignItemsCenter]}>
          <CustomButton
            disabled={isSendDisabled}
            customColor={{ backgroundColor: color.bg.eighth.color }}
            onPress={this.sendTokenAmount}
            testID={SEND_TOKEN_BUTTON}
            style={[styles.ctaButton]}
            primary
            title="Select Recipient"
          />
        </CustomView>
      </Container>
    )
  }

  componentDidUpdate(prevProps: WalletSendAmountProps) {
    if (
      this.props.paymentStatus !== prevProps.paymentStatus &&
      this.props.paymentStatus === STORE_STATUS.SUCCESS
    ) {
      // if payment is successful, we can now reset token amount and keyboard
      this.setState({ text: '' })
      this._tokenKeyboard && this._tokenKeyboard.clear()
    }
  }
}

const mapStateToProps = (state: Store) => {
  return {
    walletBalance: getWalletBalance(state),
    paymentStatus: state.wallet.payment.status,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      selectTokenAmount,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(WalletSendAmount)


<|start_filename|>connectMeUITest/src/pageObjects/ProofRequestPage.java<|end_filename|>
package pageObjects;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

/**
 * Created by ankurmishra on 6/22/17.
 */
public class ProofRequestPage {
	
	AppiumDriver driver;

	private static WebElement element = null;

	public static WebElement Send_Button(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("(//XCUIElementTypeOther[@name='Send'])[3]"));
			System.out.println("Send Button is displayed on Proof Request screen");
			return element;
		} catch (Exception e) {

			System.out.println("Send Button is not displayed");
			throw (e);
		}
	}
	
	public static WebElement Continue_Button(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("//XCUIElementTypeOther[@name='Continue']"));
			System.out.println("Continue Button is displayed on Proof Request screen");
			return element;
		} catch (Exception e) {

			System.out.println("Continue Button is not displayed");
			throw (e);
		}
	}

}


<|start_filename|>app/components/ledger-fees-modal/__tests__/ledger-fees-modal.spec.js<|end_filename|>
// @flow

import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { STORE_STATUS } from '../../../common/type-common'
import type { GenericObject } from '../../../common/type-common'
import {
  LedgerFeesModalComponent,
  LedgerFeesModalStatus,
  LedgerFeesDescriptionText,
} from '../ledger-fees-modal'
import type { LedgerFeesModalProps } from '../ledger-fees-modal'
import { ERROR_GET_LEDGER_FEES } from '../../../store/ledger/type-ledger-store'
import type { LedgerFees } from '../../../store/ledger/type-ledger-store'

describe('<LedgerFeesModalComponent />', () => {
  const ledgerFees: LedgerFees = {
    data: {
      transfer: '0',
    },
    status: STORE_STATUS.IDLE,
    error: null,
  }

  function getCommonProps(
    props: LedgerFeesModalProps | GenericObject
  ): LedgerFeesModalProps {
    return {
      onYes: jest.fn(),
      onNo: jest.fn(),
      getLedgerFees: jest.fn(),
      resetLedgerFees: jest.fn(),
      isVisible: true,
      ledgerFees,
      walletBalance: '0',
      ...props,
    }
  }

  function setup(extraProps) {
    const props = getCommonProps(extraProps)
    const wrapper = renderer.create(<LedgerFeesModalComponent {...props} />)
    const instance = wrapper.root.findByType(LedgerFeesModalComponent).instance

    return { props, wrapper, instance }
  }

  it('trigger getLedgerFees to start fetching ledger fees', () => {
    const { wrapper, props } = setup({})
    expect(wrapper.toJSON()).toMatchSnapshot()
    expect(props.getLedgerFees).toHaveBeenCalled()
  })

  it('show loader, loading text, no buttons, if fetching fees', () => {
    const feesWithInProgress = {
      data: {
        transfer: '0',
      },
      status: STORE_STATUS.IN_PROGRESS,
      error: null,
    }
    const { wrapper } = setup({ ledgerFees: feesWithInProgress })
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('show error if fetching fees failed, show retry and cancel buttons', () => {
    const feesWithError = {
      data: {
        transfer: '0',
      },
      status: STORE_STATUS.ERROR,
      error: ERROR_GET_LEDGER_FEES('Test error'),
    }
    const { wrapper } = setup({ ledgerFees: feesWithError })
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('show transfer fees, Yes & No buttons, if fees is fetched', () => {
    const fees = {
      data: {
        transfer: '0.01',
      },
      status: STORE_STATUS.SUCCESS,
      error: null,
    }
    const { wrapper } = setup({ ledgerFees: fees, walletBalance: '1' })
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('show text passed by consumer of component, if renderFeesText is passed', () => {
    const fees = {
      data: {
        transfer: '0.01',
      },
      status: STORE_STATUS.SUCCESS,
      error: null,
    }
    const renderFeesText = (fees: string, status: string) => {
      switch (status) {
        case LedgerFeesModalStatus.TRANSFER_POSSIBLE_WITH_FEES:
          return (
            <LedgerFeesDescriptionText>
              Passed message {fees}
            </LedgerFeesDescriptionText>
          )
        default:
          return null
      }
    }
    const { wrapper } = setup({
      ledgerFees: fees,
      walletBalance: '1',
      renderFeesText,
    })
    expect(wrapper.toJSON()).toMatchSnapshot()
  })
})


<|start_filename|>connectMeUITest/src/test/java/App1InstallTest.java<|end_filename|>

package test.java;

import io.appium.java_client.AppiumDriver;
import org.testng.annotations.*;
import appModules.AppUtlis;
import funcModules.ConnectionModules;
import utility.Setup;

public class App1InstallTest {

	private AppiumDriver driver;
	static boolean Success=false;
	AppUtlis AppUtlisObj=new AppUtlis();
	ConnectionModules ConnectionModulesObj=new ConnectionModules();

	@BeforeMethod

	public void beforeMethod() throws Exception {

		driver = Setup.ConfigureDriver("Safari");
	}


    @Test (groups = { "Smoke","Regression"})
	public void AppInstall() throws Exception {

    	ConnectionModulesObj.InstallApp(driver,"Demo");
            AppUtlis.Success=true;
    }

	@AfterMethod
	public void afterMethod() {

		driver.quit();
		System.out.println("Cleaning up Completed");

	}
}

<|start_filename|>__mocks__/static-data.js<|end_filename|>
// @flow
import type { NavigationParams } from '../app/common/type-common'
import type { Store } from '../app/store/type-store'
import { CHECK_PIN_IDLE } from '../app/lock/type-lock'
import {
  PROOF_REQUEST_RECEIVED,
  PROOF_REQUEST_AUTO_FILL,
} from '../app/proof-request/type-proof-request'
import { INVITATION_RECEIVED } from '../app/invitation/type-invitation'
import {
  NEW_CONNECTION_SUCCESS,
  saveNewConnection,
} from '../app/store/connections-store'
import { CLAIM_OFFER_ACCEPTED } from '../app/claim-offer/type-claim-offer'
import { invitationReceived } from '../app/invitation/invitation-store'
import {
  claimOfferReceived,
  sendClaimRequestSuccess,
} from '../app/claim-offer/claim-offer-store'
import { claimReceived, claimStorageSuccess } from '../app/claim/claim-store'
import { saveNewConnectionSuccess } from '../app/store/connections-store'
import {
  proofRequestReceived,
  proofRequestAutoFill,
  sendProofSuccess,
} from '../app/proof-request/proof-request-store'
import { color } from '../app/common/styles/constant'
import {
  qrCodeScannerTabRoute,
  homeRoute,
  claimOfferRoute,
} from '../app/common/route-constants'
import {
  agencyUrl,
  agencyDID,
  agencyVerificationKey,
  poolConfig,
  vcxInitializationState,
  vcxInitializationError,
  configStoreNotHydratedInstalledVcxInit,
} from './data/config-store-mock-data'
import { userOneTimeInfo } from './data/user-store-mock-data'
import { STORE_STATUS } from '../app/wallet/type-wallet'
import { ledgerStoreWithTransferFees } from './data/ledger-store-mock-data'
import { PREPARE_BACKUP_SUCCESS } from '../app/backup/type-backup'

// sadly, we can't export all variables in one line and use them in file as well
// to use them in this file, we have to import them first
// and then export variables, we can't use default export
// and has to export each variables by name
// because es6 modules are statically resolved
// hopefully it will not be so bad once we move all of mocked data
// into it's own file and use those files to import data wherever we need it
// instead of going through one file
// or may be in this file we can do default export and then this file
// will be used for access to all other files
export {
  agencyUrl,
  agencyDID,
  agencyVerificationKey,
  poolConfig,
  configStoreNotHydratedInstalledVcxInit,
} from './data/config-store-mock-data'

export const senderDid1 = 'senderDID1'
export const senderName1 = 'sender1'
export const senderLogoUrl1 = 'http://testissuer.com/logoUrl.png'
export const senderVerKey1 = 'senderVerificationKey1'
export const senderAgentDID1 = 'senderAgentDID1'
export const endpoint = 'endpoint'
export const uid = 'uid'
export const smsToken = '<PASSWORD>'
export const proofHandle = 1

export const senderAgentKeyDelegationProof = {
  agentDID: senderAgentDID1,
  agentDelegatedKey: 'agentDelegatedKey',
  signature: 'signature',
}

export const senderDetail = {
  name: senderName1,
  agentKeyDlgProof: senderAgentKeyDelegationProof,
  DID: senderDid1,
  logoUrl: senderLogoUrl1,
  verKey: senderVerKey1,
}

export const senderAgencyDetail = {
  DID: senderDid1,
  verKey: senderVerKey1,
  endpoint: endpoint,
}

const targetName = 'target name'
const connectionRequestId1 = 'requestId1'
const connectionRequestId2 = 'requestId2'

export const smsDownloadedPayload = {
  senderDetail,
  senderAgencyDetail,
  targetName,
  connReqId: connectionRequestId1,
  statusCode: 'MS-102',
  statusMsg: 'message sent',
}

export function* getTestInvitationPayload(): Generator<*, *, *> {
  yield {
    payload: {
      senderEndpoint: 'endpoint',
      requestId: connectionRequestId1,
      senderAgentKeyDelegationProof,
      senderName: 'sender1',
      senderDID: senderDid1,
      senderLogoUrl: 'lu',
      senderVerificationKey: 'sVk',
      targetName,
      senderDetail,
      senderAgencyDetail,
    },
  }

  yield {
    payload: {
      senderEndpoint: 'endpoint',
      requestId: connectionRequestId2,
      senderAgentKeyDelegationProof,
      senderName: 'sender2',
      senderDID: 'senderDID2',
      senderLogoUrl: 'lu',
      senderVerificationKey: 'sVk 2',
      targetName: 'target name',
      senderDetail,
      senderAgencyDetail,
    },
  }
}

const gen = getTestInvitationPayload()
const firstInvitationPayload = gen.next().value

export const pairwiseConnection = {
  identifier: 'pairwiseIdentifier1',
  verificationKey: 'pairwiseVerificationKey1',
}

export const myPairWiseConnectionDetails = {
  myPairwiseAgentDid: 'myPairwiseAgentDID',
  myPairwiseAgentVerKey: 'myPairwiseAgentVerKey',
  myPairwiseDid: 'pairwiseIdentifier1',
  myPairwisePeerVerKey: 'senderVerificationKey1',
  myPairwiseVerKey: 'pairwiseVerificationKey1',
}

export const vcxSerializedConnection = '{someVcxSerializedFormat}'

export const successConnectionData = {
  newConnection: {
    identifier: pairwiseConnection.identifier,
    logoUrl: firstInvitationPayload
      ? firstInvitationPayload.payload.senderLogoUrl
      : '',
    ...(firstInvitationPayload ? firstInvitationPayload.payload : {}),
    ...myPairWiseConnectionDetails,
    // TODO Add vcxSerializedConnection key once vcx is integrated
    // vcxSerializedConnection
  },
}

export const claimOfferId = 'usd123'
export const claimDefinitionSchemaSequenceNumber = 36
const issuerDid = 'issuerDid'
export const senderLogoUrl = 'http://testissuer.com/logoUrl.png'

const requestedAttributes = [
  {
    label: 'address1',
    data: 'address1',
  },
  {
    label: 'address2',
    data: 'address2',
  },
]

export const originalProofRequestData = {
  nonce: '123432421212',
  name: 'proof_req_1',
  version: '0.1',
  requested_attributes: {
    attr1_uuid: {
      name: 'Address 1',
    },
    attr2_uuid: {
      name: 'Address 2',
    },
  },
  requested_predicates: {},
}
export const originalProofRequestDataWithSpaces = {
  nonce: '123432421212',
  name: 'proof_req_1',
  version: '0.1',
  requested_attributes: {
    attr1_uuid: {
      name: 'A d d r e s s    1',
    },
    attr2_uuid: {
      name: '  Ad  dress 2 ',
    },
  },
  requested_predicates: {},
}

export const originalProofRequestData10Attributes = {
  nonce: '123432421212',
  name: 'proof_req_2',
  version: '0.1',
  requested_attributes: {
    attr1_uuid: {
      name: 'Address 1',
    },
    attr2_uuid: {
      name: 'Address 2',
    },
    attr3_uuid: {
      name: 'Address 3',
    },
    attr4_uuid: {
      name: 'Address 4',
    },
    attr5_uuid: {
      name: 'Address 5',
    },
    attr6_uuid: {
      name: 'Address 6',
    },
    attr7_uuid: {
      name: 'Address 7',
    },
    attr8_uuid: {
      name: 'Address 8',
    },
    attr9_uuid: {
      name: 'Address 9',
    },
    attr10_uuid: {
      name: 'Address 10',
    },
  },
  requested_predicates: {},
}

export const originalProofRequestDataMissingAttribute = {
  nonce: '123432421212',
  name: 'proof_req_1',
  version: '0.1',
  requested_attributes: {
    attr1_uuid: {
      name: 'address1',
    },
    attr2_uuid: {
      name: 'address2',
    },
    attr3_uuid: {
      name: 'address3',
    },
  },
  requested_predicates: {},
}

export const proofRequestData = {
  name: 'Home Address',
  version: '1.0.0',
  requestedAttributes,
}

export const claimOfferPushAdditionalData = {
  msg_type: 'CLAIM_OFFER',
  version: '1.0.0',
  to_did: '8XFh8yBzrpJQmNyZzgoTqB',
  from_did: 'ha66899sadfjZJGINKN0770',
  claim: {
    ['Address 1']: ['Address Address Address'],
    ['Address 2']: ['Address 2 Address 2 Address 2'],
  },
  claim_name: 'Home Address',
  schema_seq_no: claimDefinitionSchemaSequenceNumber,
  remoteName: '<NAME>',
}

export const claimOfferPayload = {
  data: {
    name: 'Home Address',
    version: '1.0.0',
    revealedAttributes: [
      {
        label: 'Address 1',
        data: 'Address Address Address',
      },
      {
        label: 'Address 2',
        data: 'Address 2 Address 2 Address 2',
      },
    ],
    claimDefinitionSchemaSequenceNumber,
  },
  issuer: {
    name: '<NAME>',
    did: issuerDid,
  },
  statusMsg: 'pending',
  uid: claimOfferId,
  senderLogoUrl: 'http://testissuer.com/logoUrl.png',
  remotePairwiseDID: 'ha66899sadfjZJGINKN0770',
  status: 'RECEIVED',
  claimRequestStatus: 'CLAIM_REQUEST_SUCCESS',
}

export const pendingClaimHistory = {
  action: 'PENDING',
  data: [
    {
      label: 'Address 1',
      data: 'Address Address Address',
    },
    {
      label: 'Address 2',
      data: 'Address 2 Address 2 Address 2',
    },
  ],
  id: 'id',
  name: 'Home Address',
  status: 'PENDING',
  timestamp: 'timestamp',
  type: 'CLAIM',
  remoteDid: 'ha66899sadfjZJGINKN0770',
  originalPayload: {
    type: 'CLAIM_RECEIVED',
    messageId: claimOfferId,
  },
}

export const claimOffer = {
  payload: {
    data: {
      name: 'Home Address',
      version: '1.0.0',
      revealedAttributes: [
        {
          label: 'Address 1',
          data: 'Address Address Address',
        },
        {
          label: 'Address 2',
          data: 'Address 2 Address 2 Address 2',
        },
      ],
      claimDefinitionSchemaSequenceNumber,
    },
    issuer: {
      name: '<NAME>',
      did: issuerDid,
    },
    statusMsg: 'pending',
    status: 'RECEIVED',
    claimRequestStatus: 'CLAIM_REQUEST_SUCCESS',
  },
  payloadInfo: {
    uid: claimOfferId,
    senderLogoUrl: 'http://testissuer.com/logoUrl.png',
    remotePairwiseDID: 'ha66899sadfjZJGINKN0770',
  },
}

export const paidClaimOffer = {
  payload: {
    data: {
      name: 'Home Address',
      version: '1.0.0',
      revealedAttributes: [
        {
          label: 'Address 1',
          data: 'Address Address Address',
        },
        {
          label: 'Address 2',
          data: 'Address 2 Address 2 Address 2',
        },
      ],
      claimDefinitionSchemaSequenceNumber,
    },
    issuer: {
      name: '<NAME>',
      did: issuerDid,
    },
    statusMsg: 'pending',
    status: 'RECEIVED',
    claimRequestStatus: 'CLAIM_REQUEST_SUCCESS',
    payTokenValue: '<PASSWORD>',
  },
  payloadInfo: {
    uid: claimOfferId,
    senderLogoUrl: 'http://testissuer.com/logoUrl.png',
    remotePairwiseDID: 'ha66899sadfjZJGINKN0770',
  },
}

export const claimRequest = {
  blinded_ms: {
    prover_did: pairwiseConnection.identifier,
    u: 'u',
    ur: 'ur',
  },
  schema_seq_no: claimDefinitionSchemaSequenceNumber,
  issuer_did: issuerDid,
}

export const claim = {
  messageId: '1',
  claim: {
    name: ['test', 'anon cred test'],
    date_of_birth: ['20-2-1800', 'anon cred date'],
  },
  schema_seq_no: claimDefinitionSchemaSequenceNumber,
  issuer_did: issuerDid,
  signature: {
    primary_claim: {
      m2: 'm2',
      a: 'a',
      e: 'e',
      v: 'v',
    },
  },
  remoteDid: 'remoteDid',
  uid: claimOfferId,
  from_did: 'from_did',
  forDID: 'forDID',
}

export const claimWithUuid = [
  {
    messageId: '1',
    claim: {
      name: ['test', 'anon cred test'],
      date_of_birth: ['20-2-1800', 'anon cred date'],
    },
    schema_seq_no: claimDefinitionSchemaSequenceNumber,
    issuer_did: issuerDid,
    signature: {
      primary_claim: {
        m2: 'm2',
        a: 'a',
        e: 'e',
        v: 'v',
      },
    },
    remoteDid: 'remoteDid',
    uid: claimOfferId,
    from_did: 'from_did',
    forDID: 'forDID',
    claim_uuid: 'claim_uuid',
  },
]

export const proofRequestId = 'pid123'

export const proofRequestId10Attributes = 'pid10'

export const proofRequest = {
  payload: {
    data: {
      name: 'Home Address',
      version: '1.0.0',
      requestedAttributes: [
        {
          label: 'Address 1',
        },
        {
          label: 'Address 2',
        },
      ],
    },
    requester: {
      name: '<NAME>',
    },
    originalProofRequestData,
    statusMsg: 'pending',
    proofHandle,
  },
  payloadInfo: {
    uid: proofRequestId,
    senderLogoUrl: 'http://cr0ybot.github.io/ingress-logos/ingress.png',
    remotePairwiseDID: senderDid1,
  },
}

export const proofRequest10Attributes = {
  payload: {
    data: {
      name: 'Home Address',
      version: '1.0.0',
      requestedAttributes: [
        {
          label: 'Address 1',
        },
        {
          label: 'Address 2',
        },
        {
          label: 'Address 3',
        },
        {
          label: 'Address 4',
        },
        {
          label: 'Address 5',
        },
        {
          label: 'Address 6',
        },
        {
          label: 'Address 7',
        },
        {
          label: 'Address 8',
        },
        {
          label: 'Address 9',
        },
        {
          label: 'Address 10',
        },
      ],
    },
    requester: {
      name: '<NAME>',
    },
    originalProofRequestData: originalProofRequestData10Attributes,
    statusMsg: 'pending',
  },
  payloadInfo: {
    uid: proofRequestId10Attributes,
    senderLogoUrl: 'https://image.flaticon.com/icons/png/128/174/174851.png',
    remotePairwiseDID: senderDid1,
  },
}

export const fulfilledRequestedAttributes = [
  { label: 'address1', data: 'Address 1' },
  { label: 'address2', data: 'Address 2' },
]

export const proof = {
  proofs: {
    'claim::f760213b-e719-47fb-9669-b72c5c410e8c': {
      proof: {
        primary_proof: {
          eq_proof: {
            revealed_attrs: {
              name: '11',
              sex: '59',
            },
            a_prime: '13',
            e: '51',
            v: '13',
            m: {},
            m1: '67',
            m2: '60',
          },
          ge_proofs: [],
        },
        non_revoc_proof: null,
      },
      schema_seq_no: claimDefinitionSchemaSequenceNumber,
      issuer_did: issuerDid,
    },
  },
  aggregated_proof: {
    c_hash: '31',
    c_list: [[claimDefinitionSchemaSequenceNumber]],
  },
  requested_proof: {
    revealed_attrs: {
      attr2_uuid: ['claim::f760213b-e719-47fb-9669-b72c5c410e8c', 'male', '59'],
      attr1_uuid: ['claim::f760213b-e719-47fb-9669-b72c5c410e8c', 'Alex', '11'],
    },
    unrevealed_attrs: {},
    self_attested_attrs: {},
    predicates: {},
  },
}

export const proofWithMissingAttributes = {
  proofs: {
    'claim::f760213b-e719-47fb-9669-b72c5c410e8c': {
      proof: {
        primary_proof: {
          eq_proof: {
            revealed_attrs: {
              name: '11',
              sex: '59',
            },
            a_prime: '13',
            e: '51',
            v: '13',
            m: {},
            m1: '67',
            m2: '60',
          },
          ge_proofs: [],
        },
        non_revoc_proof: null,
      },
      schema_seq_no: claimDefinitionSchemaSequenceNumber,
      issuer_did: issuerDid,
    },
  },
  aggregated_proof: {
    c_hash: '31',
    c_list: [[claimDefinitionSchemaSequenceNumber]],
  },
  requested_proof: {
    revealed_attrs: {
      attr3_uuid: ['claim::f760213b-e719-47fb-9669-b72c5c410e8c', 'male', '59'],
      attr1_uuid: ['claim::f760213b-e719-47fb-9669-b72c5c410e8c', 'Alex', '11'],
    },
    unrevealed_attrs: {},
    self_attested_attrs: { attr2_uuid: 'male' },
    predicates: {},
  },
}

export const proofWith10Attributes = {
  proofs: {
    'claim::f760213b-e719-47fb-9669-b72c5c410e8c': {
      proof: {
        primary_proof: {
          eq_proof: {
            revealed_attrs: {
              name: '11',
              sex: '59',
            },
            a_prime: '13',
            e: '51',
            v: '13',
            m: {},
            m1: '67',
            m2: '60',
          },
          ge_proofs: [],
        },
        non_revoc_proof: null,
      },
      schema_seq_no: claimDefinitionSchemaSequenceNumber,
      issuer_did: issuerDid,
    },
  },
  aggregated_proof: {
    c_hash: '31',
    c_list: [[claimDefinitionSchemaSequenceNumber]],
  },
  requested_proof: {
    revealed_attrs: {
      attr2_uuid: ['claim::f760213b-e719-47fb-9669-b72c5c410e8c', 'male', '59'],
      attr1_uuid: ['claim::f760213b-e719-47fb-9669-b72c5c410e8c', 'Alex', '11'],
    },
    unrevealed_attrs: {},
    self_attested_attrs: {
      attr3_uuid: 'attr 3 value',
      attr4_uuid: 'attr 4 value',
      attr5_uuid: 'attr 5 value',
      attr6_uuid: 'attr 6 value',
      attr7_uuid: 'attr 7 value',
      attr8_uuid: 'attr 8 value',
      attr9_uuid: 'attr 9 value',
      attr10_uuid: 'attr 10 value',
    },
    predicates: {},
  },
}

export const pendingRedirection = [
  { routeName: homeRoute, params: {} },
  { routeName: claimOfferRoute, params: { uid: 'asd123' } },
]

export const proofWithTwoClaims = {
  proofs: {
    'claim::0f165ac3-97a7-40c0-a06a-c0330cc78e3c': {
      proof: {
        primary_proof: {
          eq_proof: {
            revealed_attrs: {
              height: '59',
            },
            a_prime: '59',
            e: '11',
            v: '12',
            m: {},
            m1: '12',
            m2: '89',
          },
          ge_proofs: [],
        },
        non_revoc_proof: null,
      },
      schema_seq_no: 286,
      issuer_did: 'V4SGRU86Z58d6TV7PBUe6f',
    },
    'claim::52889a2f-5820-4d7e-b3bf-fecaad92a149': {
      proof: {
        primary_proof: {
          eq_proof: {
            revealed_attrs: {
              name: '11',
              sex: '59',
            },
            a_prime: '70',
            e: '15',
            v: '93',
            m: {},
            m1: '12',
            m2: '37',
          },
          ge_proofs: [],
        },
        non_revoc_proof: null,
      },
      schema_seq_no: 285,
      issuer_did: 'V4SGRU86Z58d6TV7PBUe6f',
    },
  },
  aggregated_proof: {
    c_hash: '84',
    c_list: [[2], [47]],
  },
  requested_proof: {
    revealed_attrs: {
      attr2_uuid: ['claim::52889a2f-5820-4d7e-b3bf-fecaad92a149', 'male', '59'],
      attr1_uuid: ['claim::52889a2f-5820-4d7e-b3bf-fecaad92a149', 'Alex', '11'],
      attr3_uuid: ['claim::0f165ac3-97a7-40c0-a06a-c0330cc78e3c', '150', '59'],
    },
    unrevealed_attrs: {},
    self_attested_attrs: {},
    predicates: {},
  },
}

export const missingAttributes = [{ key: 'attr2_uuid', name: 'sex' }]
export const missingAttributes1 = [
  { key: 'attr2_uuid', name: 'sex' },
  { key: 'attr3_uuid', name: 'height' },
]

export const selfAttestedAttributes = {
  attr2_uuid: {
    name: 'sex',
    data: 'male',
    key: 'attr2_uuid',
  },
}

export const selfAttestedAttributes1 = {
  attr2_uuid: {
    name: 'sex',
    data: 'male',
    key: 'attr2_uuid',
  },
  attr3_uuid: {
    name: 'height',
    data: '190',
    key: 'attr3_uuid',
  },
}

export const preparedProof = {
  attrs: {
    attr1_uuid: [
      {
        cred_info: {
          referent: 'claim::ea03d8ca-eeb4-4944-b7d6-5abcf4503d73',
          attrs: { name: 'Alex', sex: 'male' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          schema_id: 'V4SGRU86Z58d6TV7Pf:2:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
    attr2_uuid: [
      {
        cred_info: {
          referent: 'claim::6a0f42b4-1210-4bdb-ad53-10ed765276b5',
          attrs: { height: '150' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          schema_id: 'V4SGRU86Z58d6TV7Pf:2:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
  },
  predicates: {},
}

export const homeAddressPreparedProof = {
  attrs: {
    attr1_uuid: [
      {
        cred_info: {
          referent: 'claim::ea03d8ca-eeb4-4944-b7d6-5abcf4503d73',
          attrs: { ['Address 1']: 'Address 1' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          schema_id: 'V4SGRU86Z58d6TV7Pf:2:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
    attr2_uuid: [
      {
        cred_info: {
          referent: 'claim::6a0f42b4-1210-4bdb-ad53-10ed765276b5',
          attrs: { ['Address 2']: 'Address 2' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          schema_id: 'V4SGRU86Z58d6TV7Pf:2:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
  },
  predicates: {},
}

export const preparedProofWithMissingAttribute = {
  attrs: {
    attr1_uuid: [
      {
        cred_info: {
          referent: 'claim::ea03d8ca-eeb4-4944-b7d6-5abcf4503d73',
          attrs: { name: 'Alex', sex: 'male' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          schema_id: 'V4SGRU86Z58d6TV7Pf:2:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
    attr3_uuid: [
      {
        cred_info: {
          referent: 'claim::6a0f42b4-1210-4bdb-ad53-10ed765276b5',
          attrs: { height: '150' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          schema_id: 'V4SGRU86Z58d6TV7Pf:2:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
    [missingAttributes[0].key]: [null],
  },
  predicates: {},
}

export const homeAddressPreparedProofWithMissingAttribute = {
  attrs: {
    attr1_uuid: [
      {
        cred_info: {
          referent: 'claim::ea03d8ca-eeb4-4944-b7d6-5abcf4503d73',
          attrs: { ['Address 1']: 'Sovrin Ltd, Hyd.' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          schema_id: 'V4SGRU86Z58d6TV7Pf:2:slKljrSQ80tCQ40F:33089',
        },
      },
      {
        cred_info: {
          referent: 'claim::ea03d8ca-eeb4-4944-b7d6-5abcf4503d73',
          attrs: { ['Address 1']: 'Sovrin Ltd, Utah.' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag2',
          schema_id: 'V4SGRU86Z58d6TV7P:3:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
    attr3_uuid: [
      {
        cred_info: {
          referent: 'claim::6a0f42b4-1210-4bdb-ad53-10ed765276b5',
          attrs: { ['Address 2']: 'Address 2' },
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag2',
          schema_id: 'V4SGRU86Z58d6TV7P:3:slKljrSQ80tCQ40F:33089',
        },
      },
    ],
    [missingAttributes[0].key]: [null],
  },
  predicates: {},
}

export function getNavigation(params?: NavigationParams) {
  return {
    // $FlowFixMe Don't know why this is failing, may be we upgrade to flow 0.63
    navigate: jest.fn(),
    state: {
      params: params || {},
    },
    // $FlowFixMe Don't know why this is failing, may be we upgrade to flow 0.63
    goBack: jest.fn(),
    // $FlowFixMe
    dispatch: jest.fn(),
    // $FlowFixMe Don't know why this is failing, may be we upgrade to flow 0.63
    setParams: jest.fn(),
    // $FlowFixMe Don't know why this is failing, may be we upgrade to flow 0.63
    isFocused: jest.fn().mockReturnValue(true),
    // $FlowFixMe Don't know why this is failing, may be we upgrade to flow 0.63
    push: jest.fn(),
  }
}

// TODO:  we should be just able to pass an object and
// TODO: it should deep extend default store state.if we dont deep extend We have to make many calls for getStore and getState
// TODO: for any property that we want to override
export function getStore(store?: Store) {
  return {
    getState() {
      return {
        backup: {
          backupWalletPath:
            '/Users/CoreSimulator/Devices/5F89AA14-B694-465F-82C3-838552AB4B85/data/Containers/Data/Application/4536A441-4B70-4A30-8DCC-5274E6781535/Documents/backup.zip',
          error: null,
          lastSuccessfulBackup: '2018-06-27T18:27:35+05:30',
          passphrase: {
            phrase:
              'gander troubling deodorize justify twitter darkish confront politely',
            salt: 's',
            hash: 'b7a563bcbbeb892b',
          },
          showBanner: true,
          status: 'BACKUP_COMPLETE',
          prepareBackupStatus: PREPARE_BACKUP_SUCCESS,
        },
        config: configStoreNotHydratedInstalledVcxInit,
        deepLink: {
          error: undefined,
          isLoading: true,
          tokens: {},
        },
        lock: {
          checkPinStatus: CHECK_PIN_IDLE,
          pendingRedirection: undefined,
          isAppLocked: false,
          isLockEnabled: 'true',
          isTouchIdEnabled: true,
          showDevMode: false,
          inRecovery: 'false',
        },
        connections: {
          connectionThemes: {
            default: {
              primary: `rgba(${color.actions.button.primary.rgba})`,
              secondary: `rgba(${color.actions.button.secondary.rgba})`,
            },
          },
          data: undefined,
        },
        route: {
          currentScreen: qrCodeScannerTabRoute,
          timeStamp: new Date().getTime(),
        },
        smsPendingInvitation: {},
        ...(store || {}),
        claim: {
          [uid]: {
            claim,
          },
          claimMap: claimMap,
        },
        user: {
          isFetching: false,
          error: null,
          userOneTimeInfo,
          avatarName: userAvatarImageName,
        },
        wallet: {
          walletBalance,
          walletAddresses,
          walletHistory,
          backup,
          payment,
        },
        restore: {
          status: 'none',
          error: null,
          restoreFile: {
            fileName: 'backup.zip',
            fileSize: 22,
            type: 'application/zip',
            uri:
              'file://data/Containers/Data/Application/021D78D1-044B-4874-BE8D-EC71781CA978/tmp/com.evernym.connectme.callcenter-Inbox/backup.zip',
          },
        },
        ledger: ledgerStoreWithTransferFees,
        offline: {
          offline: false,
        },
      }
    },
    dispatch() {
      // $FlowFixMe Don't why this is failing, may be we upgrade to flow 0.63
      return jest.fn()
    },
    subscribe() {
      // $FlowFixMe Don't why this is failing, may be we upgrade to flow 0.63
      return jest.fn()
    },
  }
}

export const invitationReceivedEvent = {
  type: INVITATION_RECEIVED,
  data: { ...firstInvitationPayload },
}

export const newConnectionSuccessEvent = saveNewConnectionSuccess(
  successConnectionData ? successConnectionData.newConnection : {}
)

export const claimOfferReceivedEvent = claimOfferReceived(
  claimOffer.payload,
  claimOffer.payloadInfo
)

export const claimReceivedEvent = claimReceived(claim)

export const sendClaimRequestSuccessEvent = sendClaimRequestSuccess(
  uid,
  claimOfferPayload
)

export const claimReceivedSuccessEvent = claimStorageSuccess(uid)

export const proofRequestReceivedEvent = proofRequestReceived(
  proofRequest.payload,
  proofRequest.payloadInfo
)

export const proofRequestAutofillEvent = proofRequestAutoFill(
  proofRequestId,
  requestedAttributes
)

export const proofSharedEvent = sendProofSuccess(proofRequestId)

export const proofRequestAutofill = {
  status: 'proofRequestStatus',
  proofStatus: 'NONE',
  uid: proofRequestId,
  senderLogoUrl,
  remotePairwiseDID: 'remotePairWiseDID',
  data: {
    name: 'proof_req_auto_filled',
    version: 'version',
    requestedAttributes,
  },
  requester: {
    name: 'reqeusterName',
  },
  originalProofRequestData,
  statusMsg: 'statusMsg',
}

export { userOneTimeInfo } from './data/user-store-mock-data'

export const backup = {
  status: STORE_STATUS.IDLE,
  fileStatus: STORE_STATUS.IDLE,
  error: null,
  latest: '2017-09-06T00:00:00+05:30',
  backupPath: 'hibob',
  encryptionKey: 'walletEncryptionKey',
}

export const qrData = {
  id: 'yta2odh',
  s: {
    n: 'ent-name',
    dp: {
      d: 'N2Uyi6SVsHZq1VWXuA3EMg',
      k: 'CTfF2sZ5q4oPcBvTP75pgx3WGzYiLSTwHGg9zUsJJegi',
      s:
        '/FxHMzX8JaH461k1SI5PfyxF5KwBAe6VlaYBNLI2aSZU3APsiWBfvSC+mxBYJ/zAhX9IUeTEX67fj+FCXZZ2Cg==',
    },
    d: 'F2axeahCaZfbUYUcKefc3j',
    l: 'ent-logo-url',
    v: '74xeXSEac5QTWzQmh84JqzjuXc8yvXLzWKeiqyUnYokx',
  },
  sa: {
    d: 'BDSmVkzxRYGE4HKyMKxd1H',
    v: '6yUatReYWNSUfEtC2ABgRXmmLaxCyQqsjLwv2BomxsxD',
    e: '172.16.31.10:80/agency/msg',
  },
  t: 'there',
}
export const parsedClaimRequest = {
  blinded_ms: {
    prover_did: 'prover_did',
    u: 'u',
  },
  issuer_did: 'issuer_did',
  schema_seq_no: 36,
}

export const validQrCodeEnvironmentSwitchUrl =
  'https://s3-us-west-2.amazonaws.com/vcx-env/dev'

export const validInvitationUrlQrCode = 'https://dev-agency.com/vcx-env/dev'

export const environmentSwitchQrCodeData = {
  name: 'dev',
  url: validQrCodeEnvironmentSwitchUrl,
}

export const connectionHistory = {
  'September 2017': [
    {
      id: '1',
      type: 'INVITATION',
      icon: require('../app/images/linked.png'),
      action: 'CONNECTED',
      timestamp: '2017-09-06T00:00:00+05:30',
      data: [
        {
          label: 'Sovrin',
          data: '2017-09-06T00:00:00+05:30',
        },
      ],
      name: 'Enterprise name',
      status: 'INVITATION_RECEIVED',
      remoteDid: 'remoteDid',
      originalPayload: {},
    },
  ],
}

export const activeConnectionThemePrimary = `rgba(${
  color.actions.button.primary.rgba
})`

export const activeConnectionThemeSecondary = `rgba(${
  color.actions.button.secondary.rgba
})`

export const connections = {
  ['4ej819kkjywdppuje79']: {
    ...successConnectionData.newConnection,
    vcxSerializedConnection: '',
    identifier: '4ej819kkjywdppuje79',
    name: 'Test Connection1',
    senderName: 'senderName',
    senderDID: 'senderDID',
    remoteConnectionId: '70075yyojywdppuje79',
    size: 100,
    logoUrl: 'https://logourl.com/logo.png',
  },
  ['3nj819kkjywdppuje86']: {
    ...successConnectionData.newConnection,
    vcxSerializedConnection: '',
    identifier: '3nj819kkjywdppuje86',
    name: 'Test Connection2',
    senderName: 'senderName',
    senderDID: 'senderDID',
    remoteConnectionId: '70075yyojywdppuje79',
    size: 100,
    logoUrl: 'https://logourl.com/logo.png',
  },
  ['7fj819kkjywdppuje34']: {
    ...successConnectionData.newConnection,
    vcxSerializedConnection: '',
    identifier: '7fj819kkjywdppuje34',
    name: 'Test Connection3',
    senderName: 'senderName',
    senderDID: 'senderDID',
    remoteConnectionId: '70075yyojywdppuje79',
    size: 100,
    logoUrl: 'https://logourl.com/logo.png',
  },
}

export const connection = {
  identifier: '90ij8167kkjywdppujer60',
  name: 'Test Connection4',
  senderName: 'senderName',
  senderDID: 'senderDID',
  remoteConnectionId: '70075yyojywdppuje79',
  size: 100,
  logoUrl: 'https://logourl.com/logo.png',
}

export const getClaimFormat = {
  issuer_did: senderDid1,
  schema_seq_no: claimDefinitionSchemaSequenceNumber,
  attrs: {
    address1: 'address1',
    address2: 'address2',
    state: 'state',
    city: 'city',
    zip: 'zip',
  },
  claim_uuid: 'claim_uuid',
}

export const claimMap = {
  claimUuid1: {
    logoUrl: senderLogoUrl,
    myPairwiseDID: myPairWiseConnectionDetails.myPairwiseDid,
    senderDID: senderDid1,
  },
}

export const claimOfferPushNotification = {
  additionalData: {
    data: {
      name: 'Home Address',
      version: '1.0.0',
      revealedAttributes: [
        {
          label: 'Address 1',
          data: 'Address Address Address',
        },
        {
          label: 'Address 2',
          data: 'Address 2 Address 2 Address 2',
        },
      ],
    },
    issuer: {
      name: '<NAME>',
      did: 'issuerDid',
    },
    statusMsg: 'pending',
  },
  type: 'claimOffer',
  uid: 'usd123',
  senderLogoUrl: 'http://testissuer.com/logoUrl.png',
  remotePairwiseDID: 'ha66899sadfjZJGINKN0770',
  forDID: 'forDID',
}

export const getSmsPendingInvitationOfToken = (token: string) => ({
  [token]: {
    error: null,
    isFetching: false,
    status: 'RECEIVED',
    payload: smsDownloadedPayload,
  },
})

export const connectionHistoryDetail = {
  type: 'claim',
  action: 'RECEIVED',
  claimMap: claimMap,
  data: [{ label: 'label', name: 'name' }],
  id: 'dsfd',
  image: senderLogoUrl,
  name: 'name',
  originalPayload: {
    messageId: 'messageId',
    type: 'CLAIM_STORAGE_SUCCESS',
  },
  remoteDid: 'remoteDid',
  senderDID: 'senderDID',
  senderName: 'DEV',
  status: 'RECEIVED',
  theme: activeConnectionThemePrimary,
  timestamp: '2018-04-05T20:57:07+05:30',
}

export const defaultUUID = 'a4f35623-b50c-40ea-a2b0-f7cd06e03142'

export const userAvatarImageName = `user-avatar.jpeg`

export const userAvatarImagePath = `/var/application/DocumentDir/${userAvatarImageName}`

export const walletBalance = {
  data: '1000',
  status: STORE_STATUS.SUCCESS,
  error: null,
}

export const payment = {
  tokenAmount: '5656',
  status: STORE_STATUS.SUCCESS,
  error: null,
}

export const walletAddresses = {
  data: ['sov:ksudgyi8f98gsih7655hgifuyg79s89s98ydf98fg7gks8fjhkss8f030'],
  status: STORE_STATUS.SUCCESS,
  error: null,
}

export const walletHistory = {
  transactions: [
    {
      id: 'asd',
      senderAddress: 'sov:senderAddress',
      action: 'Withdraw',
      tokenAmount: '5656',
      timeStamp: 'Tue, 04 Aug 2015 12:38:41 GMT',
    },
    {
      id: 'kld',
      senderName: 'senderName',
      senderAddress: 'sov:senderAddress',
      action: 'Purchase',
      tokenAmount: '10000',
      timeStamp: 'Tue, 04 Aug 2015 14:38:41 GMT',
    },
  ],
  status: STORE_STATUS.SUCCESS,
  error: null,
}

export {
  vcxProvisionResult,
  serializedClaimOffers,
  serializedClaimOffer,
  vcxClaimOffer,
} from './data/vcx-mock-data'
export { connectionThemes } from './data/connections-mock-data'

export const proofRequestPushPayloadAdditionalData = {
  '@type': {
    name: 'PROOF_REQUEST',
    version: '1.0',
  },
  '@topic': {
    tid: 1,
    mid: 9,
  },
  proof_request_data: originalProofRequestData,
  remoteName: 'Evernym',
  proofHandle,
}

export const vcxMatchingCredentials = {
  attrs: {
    self_attest_3: [],
    zip_2: [
      {
        cred_info: {
          referent: 'bcee6e4e-77f9-4c72-9481-2aba8d263326',
          attrs: {
            city: 'Draper',
            zip: '84000',
            address1: '123 Main St',
            address2: 'Suite 3',
            state: 'UT',
          },
          schema_id:
            'V4SGRU86Z58d6TV7PBUe6f:2:slKljrSQ80tCQ408c9HFU7oOF:3308974152.3403268968',
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          rev_reg_id: null,
          cred_rev_id: null,
        },
        interval: null,
      },
      {
        cred_info: {
          referent: '09165aee-8342-4c9b-829e-21435b0c57a6',
          attrs: {
            zip: '84000',
            city: 'Draper',
            address1: '123 Main St',
            state: 'UT',
            address2: 'Suite 3',
          },
          schema_id:
            'V4SGRU86Z58d6TV7PBUe6f:2:azHf3YSoOUfnaLQF5hZIvibQB:1745712737.4068194863',
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:22:tag1',
          rev_reg_id: null,
          cred_rev_id: null,
        },
        interval: null,
      },
    ],
    address1_1: [
      {
        cred_info: {
          referent: 'bcee6e4e-77f9-4c72-9481-2aba8d263326',
          attrs: {
            city: 'Draper',
            zip: '84000',
            address1: '123 Main St',
            address2: 'Suite 3',
            state: 'UT',
          },
          schema_id:
            'V4SGRU86Z58d6TV7PBUe6f:2:slKljrSQ80tCQ408c9HFU7oOF:3308974152.3403268968',
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:24:tag1',
          rev_reg_id: null,
          cred_rev_id: null,
        },
        interval: null,
      },
      {
        cred_info: {
          referent: '09165aee-8342-4c9b-829e-21435b0c57a6',
          attrs: {
            zip: '84000',
            city: 'Draper',
            address1: '123 Main St',
            state: 'UT',
            address2: 'Suite 3',
          },
          schema_id:
            'V4SGRU86Z58d6TV7PBUe6f:2:azHf3YSoOUfnaLQF5hZIvibQB:1745712737.4068194863',
          cred_def_id: 'V4SGRU86Z58d6TV7PBUe6f:3:CL:22:tag1',
          rev_reg_id: null,
          cred_rev_id: null,
        },
        interval: null,
      },
    ],
  },
  predicates: {},
}


<|start_filename|>app/lock/__tests__/lock-enter.spec.js<|end_filename|>
// @flow
import React from 'react'
import renderer from 'react-test-renderer'
import { LockEnter } from '../lock-enter'
import { CHECK_PIN_IDLE, CHECK_PIN_SUCCESS, CHECK_PIN_FAIL } from '../type-lock'
import { ENTER_YOUR_PASS_CODE_MESSAGE } from '../../common/message-constants'

describe('<LockEnter />', () => {
  function getProps() {
    return {
      checkPinAction: jest.fn(),
      checkPinStatusIdle: jest.fn(),
      switchErrorAlerts: jest.fn(),
      onSuccess: jest.fn(),
      message: ENTER_YOUR_PASS_CODE_MESSAGE,
      checkPinStatus: CHECK_PIN_IDLE,
    }
  }

  let component
  let props
  let cleared

  const options = {
    createNodeMock: element => {
      return {
        clear: () => {
          cleared = true
        },
        blur: () => {},
      }
    },
  }

  beforeEach(() => {
    props = getProps()
    component = renderer.create(
      <LockEnter {...props} fromRecovery={false} />,
      options
    )
  })

  it('should match snapshot', () => {
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should match snapshot for recovery flow', () => {
    const component1 = renderer.create(
      <LockEnter {...props} fromRecovery={true} />,
      options
    )
    expect(component1.toJSON()).toMatchSnapshot()
  })

  it('call onSuccess if pin matches', () => {
    component.update(
      <LockEnter
        {...props}
        checkPinStatus={CHECK_PIN_SUCCESS}
        fromRecovery={false}
      />
    )
    expect(props.onSuccess).toHaveBeenCalled()
  })

  it('clear pin code box if pin check fails', () => {
    jest.useFakeTimers()
    component.update(
      <LockEnter
        {...props}
        checkPinStatus={CHECK_PIN_FAIL}
        fromRecovery={false}
      />
    )
    jest.runAllTimers()
    expect(props.checkPinStatusIdle).toHaveBeenCalled()
  })
})


<|start_filename|>app/proof/proof-store.js<|end_filename|>
// @flow

import {
  put,
  takeLatest,
  take,
  call,
  all,
  select,
  takeEvery,
} from 'redux-saga/effects'
import type {
  Proof,
  ProofStore,
  UpdateAttributeClaimAction,
  ProofAction,
  GenerateProofAction,
  ProofSuccessAction,
  ProofFailAction,
  IndyPreparedProof,
  IndyRequestedAttributes,
  IndySelfAttestedAttributes,
  UserSelfAttestedAttributesAction,
  IndyRequestedProof,
  RequestedClaimsJson,
  RequestedAttrsJson,
  VcxSelectedCredentials,
} from './type-proof'
import type {
  ProofRequestData,
  SelfAttestedAttributes,
  MissingAttribute,
  IndySelfAttested,
  SelfAttestedAttribute,
  ProofRequestedAttributes,
  ProofRequestPayload,
} from '../proof-request/type-proof-request'
import {
  UPDATE_ATTRIBUTE_CLAIM,
  GENERATE_PROOF,
  PROOF_SUCCESS,
  PROOF_FAIL,
  ERROR_MISSING_ATTRIBUTE_IN_CLAIMS,
  USER_SELF_ATTESTED_ATTRIBUTES,
  PROOF_REQUEST_SEND_PROOF_HANDLE,
  RESET_TEMP_PROOF_DATA,
  ERROR_SEND_PROOF,
  CLEAR_ERROR_SEND_PROOF,
} from './type-proof'
import type { CustomError } from '../common/type-common'
import {
  generateProof,
  getMatchingCredentials,
  proofDeserialize,
} from '../bridge/react-native-cxs/RNCxs'
import {
  proofRequestAutoFill,
  missingAttributesFound,
  acceptProofRequest,
  sendProof,
  updateProofHandle,
} from '../proof-request/proof-request-store'
import {
  getOriginalProofRequestData,
  getProofRequestPairwiseDid,
  getPoolConfig,
  getProofRequesterName,
  getProofRequest,
  getProofData,
} from '../store/store-selector'
import type { Attribute } from '../push-notification/type-push-notification'
import { RESET } from '../common/type-common'
import { PROOF_REQUEST_SHOW_START } from '../proof-request/type-proof-request'
import { captureError } from '../services/error/error-handler'
import KeepScreenOn from 'react-native-keep-screen-on'

export const updateAttributeClaim = (
  uid: string,
  requestedAttrsJson: RequestedAttrsJson
): UpdateAttributeClaimAction => ({
  type: UPDATE_ATTRIBUTE_CLAIM,
  uid,
  requestedAttrsJson,
})

export const getProof = (uid: string) => ({
  type: GENERATE_PROOF,
  uid,
})

export const proofSuccess = (
  proof: Proof,
  uid: string
): ProofSuccessAction => ({
  type: PROOF_SUCCESS,
  proof,
  uid,
})

export const proofFail = (
  uid: string,
  error: CustomError
): ProofFailAction => ({
  type: PROOF_FAIL,
  uid,
  error,
})

export const userSelfAttestedAttributes = (
  selfAttestedAttributes: SelfAttestedAttributes,
  uid: string
) => ({
  type: USER_SELF_ATTESTED_ATTRIBUTES,
  selfAttestedAttributes,
  uid,
})

export const proofRequestDataToStore = (
  uid: string,
  proofHandle: number,
  selfAttestedAttributes: SelfAttestedAttributes
) => ({
  type: PROOF_REQUEST_SEND_PROOF_HANDLE,
  uid,
  proofHandle,
  selfAttestedAttributes,
})

export const resetTempProofData = (uid: string) => ({
  type: RESET_TEMP_PROOF_DATA,
  uid,
})

export const errorSendProofFail = (uid: string, error: CustomError) => ({
  type: ERROR_SEND_PROOF,
  uid,
  error,
})

export const clearSendProofFail = (uid: string) => ({
  type: CLEAR_ERROR_SEND_PROOF,
  uid,
})

export function convertSelfAttestedToIndySelfAttested(
  selfAttestedAttributes: SelfAttestedAttributes
): IndySelfAttested {
  return Object.keys(selfAttestedAttributes).reduce((acc, name) => {
    const { key, data }: SelfAttestedAttribute = selfAttestedAttributes[name]
    return {
      ...acc,
      [key]: data,
    }
  }, {})
}

export function convertPreparedProofToRequestedAttributes(
  preparedProof: IndyPreparedProof,
  proofRequest: ProofRequestData
): [IndyRequestedAttributes, MissingAttribute[]] {
  // apart from conversion, it finds attributes that are not in any claim

  const missingAttributes: MissingAttribute[] = []
  const requestedAttributes = Object.keys(
    proofRequest.requested_attributes
  ).reduce((acc, attrKey) => {
    const attributeClaimData = preparedProof.attrs[attrKey]

    if (!attributeClaimData || !attributeClaimData[0]) {
      missingAttributes.push({
        key: attrKey,
        name: proofRequest.requested_attributes[attrKey].name,
      })

      return acc
    }

    return {
      ...acc,
      [attrKey]: [attributeClaimData[0].cred_info.referent, true],
    }
  }, {})

  return [requestedAttributes, missingAttributes]
}

export function convertIndyPreparedProofToAttributes(
  preparedProof: IndyPreparedProof,
  requestedAttributes: ProofRequestedAttributes
): Array<Attribute> {
  let attributes = Object.keys(requestedAttributes).map(attributeKey => {
    const label = requestedAttributes[attributeKey].name
    const revealedAttributes = preparedProof.attrs[attributeKey]
    if (revealedAttributes && revealedAttributes.length > 0) {
      return revealedAttributes.map(revealedAttribute => {
        // convert attrs props to lowercase
        // maintain a mapping that will map case insensitive name to actual name in `attrs`
        let caseInsensitiveMap = null
        if (revealedAttribute) {
          caseInsensitiveMap = Object.keys(
            revealedAttribute.cred_info.attrs
          ).reduce(
            (acc, attributeName) => ({
              ...acc,
              [attributeName.toLowerCase().replace(/ /g, '')]: attributeName,
            }),
            {}
          )
        }

        return {
          label,
          key: attributeKey,
          data:
            revealedAttribute &&
            caseInsensitiveMap &&
            revealedAttribute.cred_info.attrs[
              caseInsensitiveMap[label.toLowerCase().replace(/ /g, '')]
            ],
          claimUuid: revealedAttribute && revealedAttribute.cred_info.referent,
          // TODO:KS Refactor this logic to not put cred_info here
          // We are putting cred_info here because we don't want to iterate
          // later to find whole credential
          cred_info: revealedAttribute ? revealedAttribute : null,
        }
      })
    }

    const selfAttestedAttribute =
      preparedProof.self_attested_attrs &&
      preparedProof.self_attested_attrs[label.toLowerCase().trim()].data

    return [
      {
        label,
        data: selfAttestedAttribute,
      },
    ]
  })

  // $FlowFixMe
  return attributes
}

export function convertUserSelectedCredentialToVcxSelectedCredentials(
  userSelectedCredentials: IndyRequestedAttributes
): VcxSelectedCredentials {
  const attrs = Object.keys(userSelectedCredentials).reduce(
    (acc, attributeKey) => ({
      ...acc,
      [attributeKey]: userSelectedCredentials[attributeKey][2],
    }),
    {}
  )

  if (Object.keys(attrs).length === 0) {
    return {}
  }

  return {
    attrs,
  }
}

export function convertSelectedCredentialAttributesToIndyProof(
  userSelectedCredentials: IndyRequestedAttributes
) {
  const credentialFilledAttributes = Object.keys(userSelectedCredentials)

  return credentialFilledAttributes.reduce((acc, attributeKey) => {
    const selectedAttribute = userSelectedCredentials[attributeKey]
    // we only have attribute key at this point, we can still get attribute name
    // but then we would have to do a lot of other mapping
    // we should still do that but for now we know that attribute keys are formed
    // by adding _<index> after the name of attribute
    // so we are removing that last _<index> from attribute key and generating attribute name
    // We will remove this logic and have it work without below hack
    // when we will refactor whole proof generation logic
    const caseInsensitiveMap = Object.keys(
      selectedAttribute[2].cred_info.attrs
    ).reduce(
      (acc, attributeName) => ({
        ...acc,
        [attributeName.toLowerCase().replace(/ /g, '')]: attributeName,
      }),
      {}
    )
    let attributeLabel = attributeKey.split('_')
    if (attributeLabel.length > 1) {
      attributeLabel = attributeLabel.slice(0, -1)
    }
    attributeLabel = attributeLabel.join('_')
    return {
      ...acc,
      [attributeKey]: [
        selectedAttribute[0],
        selectedAttribute[2].cred_info.attrs[
          caseInsensitiveMap[attributeLabel.toLowerCase().replace(/ /g, '')]
        ],
      ],
    }
  }, {})
}

export function* generateProofSaga(
  action: GenerateProofAction
): Generator<*, *, *> {
  try {
    const { uid } = action
    const proofRequestPayload: ProofRequestPayload = yield select(
      getProofRequest,
      uid
    )
    const proofRequest = proofRequestPayload.originalProofRequestData
    let proofHandle = proofRequestPayload.proofHandle
    let matchingCredentialsJson: string | null = null

    try {
      matchingCredentialsJson = yield call(getMatchingCredentials, proofHandle)
    } catch (e) {
      // the reason why are we doing this here is
      // we persist proofHandle along with proof request
      // proofHandle is given by vcx for the their internal object which is in memory
      // and using that proofHandle we can query data
      // However, if user kills the app, then vcx looses all in memory object
      // and proofHandle that we persisted no longer points to proof object
      // so we catch that exception here and we get new proofHandle
      // and then try to query data again
      // if it fails again, then there must be some error from vcx side which we bubble up

      // the way we achieve what is written above is that we take the serialized proof request
      // from vcx and store that object on our side and then we pass that serialized object
      // back to vcx, so that vcx can create it's internal proof object again
      const serializedProofRequest =
        proofRequestPayload.vcxSerializedProofRequest
      if (serializedProofRequest) {
        // it might happen that we won't have serialized proof request
        // so we guard against it and let fail
        proofHandle = yield call(proofDeserialize, serializedProofRequest)
        // update proof handle in store, because it would be used by proof-request store
        yield put(updateProofHandle(proofHandle, uid))
        matchingCredentialsJson = yield call(
          getMatchingCredentials,
          proofHandle
        )
      }
    }

    if (!matchingCredentialsJson) {
      throw new Error('No matching credential json result')
    }

    const matchingCredentials: IndyPreparedProof = JSON.parse(
      matchingCredentialsJson
    )
    const [
      requestedAttrsJson,
      missingAttributes,
    ] = convertPreparedProofToRequestedAttributes(
      matchingCredentials,
      proofRequest
    )
    let selfAttestedAttributes: SelfAttestedAttributes = {}

    if (missingAttributes.length > 0) {
      // if we find that there are some attributes that are not available
      // in any of the claims stored in user wallet
      // then we ask user to fill in those attributes
      // so we need to tell proof request screen to ask user to
      yield put(missingAttributesFound(missingAttributes, uid))

      // once user has filled all attributes, we need to get those details here
      // user filled details become self attested attributes
      const selfAttestedFilledAction: UserSelfAttestedAttributesAction = yield take(
        USER_SELF_ATTESTED_ATTRIBUTES
      )
      selfAttestedAttributes = selfAttestedFilledAction.selfAttestedAttributes
    }

    // auto-fill proof request
    const requestedAttributes = convertIndyPreparedProofToAttributes(
      {
        ...matchingCredentials,
        self_attested_attrs: { ...selfAttestedAttributes },
      },
      proofRequest.requested_attributes
    )
    yield put(proofRequestAutoFill(uid, requestedAttributes))

    yield put(proofRequestDataToStore(uid, proofHandle, selfAttestedAttributes))
  } catch (e) {
    // captureError(e)
    yield put(proofFail(action.uid, e))
  }
}

export function* updateAttributeClaimAndSendProof(
  action: any
): Generator<*, *, *> {
  try {
    yield put(clearSendProofFail(action.uid))
    const { proofHandle, selfAttestedAttributes } = yield select(
      getProofData,
      action.uid
    )
    const requestedAttrsJson = action.requestedAttrsJson
    yield put(sendProof(action.uid))

    const selectedCredentials = convertUserSelectedCredentialToVcxSelectedCredentials(
      requestedAttrsJson
    )
    const selectedSelfAttestedAttributes = convertSelfAttestedToIndySelfAttested(
      selfAttestedAttributes
    )
    // keeping device's screen ON so that phone doesn't lock
    // while generating or sending proof
    KeepScreenOn.setKeepScreenOn(true)
    yield call(
      generateProof,
      proofHandle,
      JSON.stringify(selectedCredentials),
      JSON.stringify(selectedSelfAttestedAttributes)
    )

    yield put(acceptProofRequest(action.uid))
    // create a proof object so that history store and others that depend on proof
    // can use this proof object, previously proof object was generated with libIndy
    // now that we have removed libIndy and use vcx, we are generating this object
    // We should re-write whole proof generation logic and events in a single saga
    // and merge two stores proof-request-store and proof-store
    const proof: Proof = {
      proofs: {},
      aggregated_proof: {
        c_hash: '',
        c_list: [[0]],
      },
      requested_proof: {
        revealed_attrs: convertSelectedCredentialAttributesToIndyProof(
          requestedAttrsJson
        ),
        unrevealed_attrs: {},
        self_attested_attrs: selectedSelfAttestedAttributes,
        predicates: {},
      },
    }
    yield put(proofSuccess(proof, action.uid))
  } catch (e) {
    KeepScreenOn.setKeepScreenOn(false)
    // captureError(e)
    yield put(errorSendProofFail(action.uid, e))
  }
}

export function* watchGenerateProof(): any {
  yield takeLatest(GENERATE_PROOF, generateProofSaga)
  yield takeLatest(UPDATE_ATTRIBUTE_CLAIM, updateAttributeClaimAndSendProof)
}

export function* watchProof(): any {
  yield all([watchGenerateProof()])
}

const initialState = {}

export default function proofReducer(
  state: ProofStore = initialState,
  action: ProofAction
) {
  switch (action.type) {
    case PROOF_SUCCESS: {
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          ...action.proof,
        },
      }
    }

    case PROOF_FAIL:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          error: action.error,
        },
      }

    case PROOF_REQUEST_SHOW_START: {
      return {
        ...state,
        [action.uid]: undefined,
      }
    }

    case PROOF_REQUEST_SEND_PROOF_HANDLE: {
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofData: {
            proofHandle: action.proofHandle,
            selfAttestedAttributes: action.selfAttestedAttributes,
          },
        },
      }
    }

    case RESET_TEMP_PROOF_DATA: {
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofData: null,
        },
      }
    }

    case ERROR_SEND_PROOF: {
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofData: {
            ...state[action.uid].proofData,
            error: action.error,
          },
        },
      }
    }

    case CLEAR_ERROR_SEND_PROOF: {
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          proofData: {
            ...state[action.uid].proofData,
            error: null,
          },
        },
      }
    }

    case RESET:
      return initialState

    default:
      return state
  }
}


<|start_filename|>app/components/input-control/type-input-control.js<|end_filename|>
// @flow

export type IsValid = 'IDLE' | 'SUCCESS' | 'ERROR'

export type InputControlProps = {
  isValid?: IsValid,
  onChangeText: (text: string, name: string) => void,
  placeholder: string,
  label: string,
  name: string,
  multiline?: boolean,
  validation?: () => void,
  maxLength?: number,
}


<|start_filename|>app/common/secure-storage-constants.js<|end_filename|>
// @flow

export const PUSH_COM_METHOD = 'pushComMethod'
export const CONNECT_ME_STORAGE_KEY = '@connectmeDefaults'
export const IS_ALREADY_INSTALLED = `${CONNECT_ME_STORAGE_KEY}:IS_ALREADY_INSTALLED`
export const CONNECTIONS = 'CONNECTIONS'
export const CLAIM_MAP = `CLAIM_MAP`
export const WALLET_ENCRYPTION_KEY = 'walletEncryptionKey'
export const WALLET_BALANCE = 'walletBalance'
export const WALLET_ADDRESSES = 'walletAddresses'
export const WALLET_HISTORY = 'walletHistory'
export const LAST_SUCCESSFUL_BACKUP = 'lastSuccessfulBackup'
export const PASSPHRASE_SALT_STORAGE_KEY = 'passphraseSalt'
export const PASSPHRASE_STORAGE_KEY = 'passphrase'


<|start_filename|>app/components/pin-code/pin-code-digit.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Image } from 'react-native'
import { CustomView } from '../../components'
import { color, OFFSET_1X } from '../../common/styles'
import type { PinCodeDigitProps } from './type-pin-code-box'

const sovrinIcon = require('../../images/icon_sovrin.png')

export default class PinCodeDigit extends PureComponent<
  PinCodeDigitProps,
  void
> {
  render() {
    const { entered, testID = undefined, onPress } = this.props
    const style = entered ? styles.entered : null

    return (
      <CustomView
        onPress={onPress}
        center
        style={[styles.digit, style]}
        testID={testID}
      >
        {entered && (
          <Image style={styles.icon} source={sovrinIcon} resizeMode="contain" />
        )}
      </CustomView>
    )
  }
}

const iconDimension = 26

const styles = StyleSheet.create({
  digit: {
    borderBottomWidth: 5,
    borderBottomColor: color.bg.tertiary.font.tertiary,
    marginHorizontal: OFFSET_1X / 2,
    height: 66,
    width: 38,
  },
  entered: {
    borderBottomColor: color.bg.tertiary.font.tertiary,
  },
  icon: {
    height: iconDimension,
    width: iconDimension,
  },
})


<|start_filename|>app/eula/eula.js<|end_filename|>
// @flow

// this is page displays, a webview with of our terms and conditions
// you should get the url value and title from constants
// on click accept take user to lock selection screen

import React, { PureComponent } from 'react'
import { WebView, Alert, View } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { tertiaryHeaderStyles } from '../components/layout/header-styles'
import {
  CustomText,
  Container,
  FooterActions,
  CustomHeader,
} from '../components'
import { eulaRoute, restoreRoute } from '../common'
import { eulaAccept } from './eula-store'
import type { Store } from '../store/type-store'
import { EULA_URL, localEulaSource } from './type-eula'
import { color } from '../common/styles/constant'
import { LoaderGif } from '../components/loader-gif/loader-gif'
import type { EulaScreenState } from './type-eula'
import type { CustomError } from '../common/type-common'

export class EulaScreen extends PureComponent<*, EulaScreenState> {
  state = {
    error: null,
  }

  static navigationOptions = ({ navigation }) => ({
    header: (
      <CustomHeader
        backgroundColor={color.bg.tertiary.color}
        flatHeader
        centerComponent={
          <CustomText bg="tertiary" tertiary transparentBg semiBold>
            Terms and Conditions
          </CustomText>
        }
      />
    ),
    swipeEnabled: false,
  })

  onReject = () => {
    Alert.alert(
      'Alert',
      'You will not be able to use the application without accepting Terms and Conditions'
    )
  }

  onError = (error: CustomError) => {
    if (error) {
      this.setState({ error })
    }
  }

  onAccept = () => {
    this.props.eulaAccept(true)
    this.props.navigation.navigate(restoreRoute)
  }

  render() {
    const webViewUri = this.state.error ? localEulaSource : EULA_URL

    return (
      <Container fifth>
        <WebView
          source={{ uri: webViewUri }}
          startInLoadingState={true}
          renderLoading={() => LoaderGif}
          onError={this.onError}
          renderError={() => <View />}
        />
        <FooterActions
          onAccept={this.onAccept}
          onDecline={this.onReject}
          denyTitle="Decline"
          acceptTitle="Accept"
          testID="eula"
        />
      </Container>
    )
  }
}

const mapStateToProps = ({ eula }: Store) => ({
  eula,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      eulaAccept,
    },
    dispatch
  )

export default createStackNavigator({
  [eulaRoute]: {
    screen: connect(mapStateToProps, mapDispatchToProps)(EulaScreen),
  },
})


<|start_filename|>app/store/ledger/type-ledger-store.js<|end_filename|>
// @flow

import type {
  StoreStatus,
  StoreError,
  CustomError,
} from '../../common/type-common'

export type LedgerStore = {
  +fees: LedgerFees,
}

export type LedgerAction =
  | GetLedgerFeesAction
  | GetLedgerFeesSuccessAction
  | GetLedgerFeesFailAction
  | ResetLedgerFeesAction

export type LedgerFees = {
  data: LedgerFeesData,
} & StoreError &
  StoreStatus

export type LedgerFeesData = {
  +transfer: string,
}

export const GET_LEDGER_FEES = 'GET_LEDGER_FEES'
export const getLedgerFees = () => ({
  type: GET_LEDGER_FEES,
})
export type GetLedgerFeesFn = typeof getLedgerFees
export type GetLedgerFeesAction = {
  type: typeof GET_LEDGER_FEES,
}

export const GET_LEDGER_FEES_SUCCESS = 'GET_LEDGER_FEES_SUCCESS'
export const getLedgerFeesSuccess = (fees: LedgerFeesData) => ({
  type: GET_LEDGER_FEES_SUCCESS,
  fees,
})
export type GetLedgerFeesSuccessAction = {
  type: typeof GET_LEDGER_FEES_SUCCESS,
  fees: LedgerFeesData,
}

export const GET_LEDGER_FEES_FAIL = 'GET_LEDGER_FEES_FAIL'
export const getLedgerFeesFail = (error: CustomError) => ({
  type: GET_LEDGER_FEES_FAIL,
  error,
})
export type GetLedgerFeesFailAction = {
  type: typeof GET_LEDGER_FEES_FAIL,
  error: CustomError,
}
export const ERROR_GET_LEDGER_FEES = (message: string) => ({
  code: 'LE-001',
  message: `Error occurred while fetching ledger fees: ${message}`,
})

export const RESET_LEDGER_FEES = 'RESET_LEDGER_FEES'
export const resetLedgerFees = () => ({
  type: RESET_LEDGER_FEES,
})
export type ResetLedgerFeesFn = typeof resetLedgerFees
export type ResetLedgerFeesAction = {
  type: typeof RESET_LEDGER_FEES,
}


<|start_filename|>app/components/image-color-picker/__tests__/image-color-picker.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import {
  ImageColorPicker,
  isAllowedColor,
  getImageType,
} from '../image-color-picker'
import renderer from 'react-test-renderer'

function getProps() {
  return {
    imageType: 'jpeg',
    imageUrl: 'https://image.url',
    updateConnectionTheme: jest.fn(),
  }
}

function setup() {
  const props = getProps()
  const wrapper = renderer.create(<ImageColorPicker {...props} />)
  const instance = wrapper.root.instance

  return {
    props,
    wrapper,
    instance,
  }
}

describe('<ImageColorPicker />', () => {
  it('should render properly', () => {
    const { instance, wrapper } = setup()
    instance.setState({ imageBlob: 'someblob' })
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should pick default color if color is light', () => {
    let color = [255, 255, 255]
    expect(isAllowedColor(color)).toBe(false)
    color = [224, 224, 224]
    expect(isAllowedColor(color)).toBe(false)
    color = [229, 255, 204]
    expect(isAllowedColor(color)).toBe(false)
    color = [0, 255, 255]
    expect(isAllowedColor(color)).toBe(false)
    color = [255, 248, 220]
    expect(isAllowedColor(color)).toBe(false)
    color = [240, 255, 255]
    expect(isAllowedColor(color)).toBe(false)
    color = [255, 255, 240]
    expect(isAllowedColor(color)).toBe(false)
    color = [245, 245, 245]
    expect(isAllowedColor(color)).toBe(false)
  })

  it('should pick correct image extension', () => {
    let imageUrl = 'a.jpG'
    expect(getImageType(imageUrl)).toBe('JPEG')
    imageUrl = 'a.jpG?'
    expect(getImageType(imageUrl)).toBe('JPEG')
  })
})


<|start_filename|>android/app/src/main/java/me/connect/MainApplication.java<|end_filename|>
package me.connect;

import android.app.Application;
import com.apptentive.android.sdk.reactlibrary.RNApptentivePackage;
import com.facebook.react.ReactApplication;
import com.gijoehosaphat.keepscreenon.KeepScreenOnPackage;
import com.horcrux.svg.SvgPackage;
import rnpbkdf2.PBKDF2Package;
import io.invertase.firebase.RNFirebasePackage;
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
import com.rnziparchive.RNZipArchivePackage;
import com.bitgo.randombytes.RandomBytesPackage;
import com.reactnativedocumentpicker.ReactNativeDocumentPicker;
import br.com.classapp.RNSensitiveInfo.RNSensitiveInfoPackage;
import cl.json.RNSharePackage;
import cl.json.ShareApplication;
import com.apsl.versionnumber.RNVersionNumberPackage;
import com.reactnative.ivpusic.imagepicker.PickerPackage;
import com.reactnative.ivpusic.imagepicker.PickerPackage;
import fr.bamlab.rnimageresizer.ImageResizerPackage;
import com.rnfingerprint.FingerprintAuthPackage;
import com.RNFetchBlob.RNFetchBlobPackage;
import com.lwansbrough.RCTCamera.RCTCameraPackage;
import io.branch.rnbranch.RNBranchPackage;
import io.branch.referral.Branch;
import com.oblador.vectoricons.VectorIconsPackage;
import org.devio.rn.splashscreen.SplashScreenReactPackage;
import me.connect.rnindy.RNIndyPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;

//import com.oblador.vectoricons.VectorIconsPackage;

public class MainApplication extends Application implements ShareApplication, ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
        new MainReactPackage(),
            new KeepScreenOnPackage(),
            new SvgPackage(),
            new PBKDF2Package(),
        new RNFirebasePackage(),
        new RNFirebaseNotificationsPackage(),
        new RNFirebaseMessagingPackage(),
        new RNZipArchivePackage(),
        new RandomBytesPackage(),
        new ReactNativeDocumentPicker(),
        new RNSensitiveInfoPackage(),
        new RNSharePackage(),
        new RNVersionNumberPackage(),
        new PickerPackage(),
        new ImageResizerPackage(),
        new FingerprintAuthPackage(),
        new RNFetchBlobPackage(),
        new RCTCameraPackage(),
        new RNBranchPackage(),
        new VectorIconsPackage(),
        new SplashScreenReactPackage(),
        new RNIndyPackage(),
        new RNApptentivePackage()
      );
    }

    @Override
    protected String getJSMainModuleName() {

      return "index";
    }
  };

  @Override
  public ReactNativeHost getReactNativeHost() {

    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    Branch.getAutoInstance(this);
    SoLoader.init(this, /* native exopackage */ false);
  }

  @Override
  public String getFileProviderAuthority() {
    return "me.connect.provider";
  }
}


<|start_filename|>app/components/image-color-picker/__tests__/connection-theme.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import { ConnectionTheme } from '../connection-theme'
import renderer from 'react-test-renderer'
import { color } from '../../../common/styles/constant'
import { Button } from 'react-native-elements'
import empty from '../../../common/empty'

function props() {
  return {
    connectionTheme: {
      primary: `rgba(${color.actions.button.primary.rgba})`,
      secondary: `rgba(${color.actions.button.secondary.rgba})`,
    },
    logoUrl: 'logoUrl',
    secondary: 'secondary',
    children: [Button],
    backgroundColor: '',
    style: empty,
    disabled: true,
  }
}

describe('<ConnectionTheme />', () => {
  it('should render default theme properly', () => {
    const connectionTheme = renderer
      .create(<ConnectionTheme {...props()} />)
      .toJSON()
    expect(connectionTheme).toMatchSnapshot()
  })
})


<|start_filename|>app/push-notification/index.js<|end_filename|>
// @flow
export { default as PushNotification } from './push-notification'
export {
  default as PushNotificationNavigator,
} from './push-notification-navigator'


<|start_filename|>app/components/layout/header-styles.js<|end_filename|>
// @flow
import React from 'react'
import { StyleSheet, Platform } from 'react-native'

import {
  PADDING_HORIZONTAL,
  PADDING_VERTICAL,
  color,
  font,
  whisper,
  whiteSmokeSecondary,
  OFFSET_1X,
  OFFSET_3X,
  OFFSET_2X,
  OFFSET_9X,
} from '../../common/styles/constant'

// TODO:KS Move this file to common/styles

const commonStyles = {
  padding: 0,
  shadowColor: 'transparent',
  shadowOpacity: 0,
  shadowOffset: {
    height: 0,
  },
  shadowRadius: 0,
  elevation: 0,
}

export default StyleSheet.create({
  header: {
    backgroundColor: color.bg.secondary.color,
    minHeight: 75,
    borderBottomWidth: 0,
    ...commonStyles,
  },
  headerLeft: {
    marginLeft: OFFSET_3X / 2,
  },
  headerLogoContainer: {
    height: OFFSET_9X + (Platform.OS === 'ios' ? 0 : OFFSET_1X),
  },
  clearBg: { backgroundColor: 'transparent' },
  centerTitle: {
    alignSelf: 'center',
  },
})

export const primaryHeaderStyles = StyleSheet.create({
  header: {
    backgroundColor: whiteSmokeSecondary,
    borderBottomColor: whisper,
    borderBottomWidth: 1,
    ...commonStyles,
  },
})

export const tertiaryHeaderStyles = StyleSheet.create({
  header: {
    backgroundColor: color.bg.tertiary.color,
    minHeight: 64,
    paddingHorizontal: OFFSET_2X,
    borderBottomWidth: 0,
    ...commonStyles,
  },
  title: {
    alignSelf: 'center',
    textAlign: 'center',
    fontSize: font.size.M,
    fontWeight: '600',
    color: color.bg.tertiary.font.tertiary,
  },
})


<|start_filename|>android/app/src/main/java/me/connect/keystore/LostKeyException.java<|end_filename|>
package me.connect.keystore;

public class LostKeyException extends Exception {
    public LostKeyException() {
        super();
    }
    public LostKeyException(String message) {
        super(message);
    }
}


<|start_filename|>app/components/keyboard/keyboard-constants.js<|end_filename|>
// @flow

export const KEYBOARD_TEST_ID = 'wallet-keyboard-id-label'
export const SPECIAL_DECIMAL_FORMAT = '0.'
export const BACK_SPACE_SYMBOL = '<'
export const BACK_SPACE = 'backspace'
export const MAX_LENGTH = 'maxLength'
export const DECIMAL = '.'
export const ZERO = '0'
export const ONE = '1'
export const TWO = '2'
export const THREE = '3'
export const FOUR = '4'
export const FIVE = '5'
export const SIX = '6'
export const SEVEN = '7'
export const EIGHT = '8'
export const NINE = '9'


<|start_filename|>app/components/banner/type-banner.js<|end_filename|>
// @flow
import type { ReactNavigation } from '../../common/type-common'

export type BannerProps = {
  walletBackup: () => {},
  promptBackupBanner: (showBackup: boolean) => {},
  lastSuccessfulBackupTimeStamp: string,
  showBanner: boolean,
} & ReactNavigation

export type DangerBannerProps = {
  testID: string,
  onPress?: () => void,
  bannerTitle: string,
  bannerSubtext: string,
}

export type OfflineBannerProps = {
  testID: string,
  onPress?: () => void,
  bannerTitle: string,
}


<|start_filename|>app/components/separator.js<|end_filename|>
// @flow
import React, { Component } from 'react'
import { StyleSheet } from 'react-native'
import { CustomView } from '../components'
import { color } from '../common/styles'

export default class Separator extends Component<void, void> {
  render() {
    return <CustomView style={[styles.separator]} />
  }
}

const styles = StyleSheet.create({
  separator: {
    height: 2,
    backgroundColor: color.bg.secondary.font.tertiary,
  },
})


<|start_filename|>app/restore/__tests__/restore-passphrase.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { RestorePassphrase } from '../restore-passphrase'
import { getNavigation, getStore } from '../../../__mocks__/static-data'

describe('Restore Passphrase screen', () => {
  function getProps() {
    return {
      navigation: getNavigation(),
      submitPassphrase: jest.fn(),
      restore: getStore().getState().restore,
    }
  }

  function setup() {
    const props = getProps()
    return { props }
  }

  it('should render properly and match the snapshot', () => {
    const { props } = setup()
    const tree = renderer.create(<RestorePassphrase {...props} />).toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/components/keyboard/__tests__/keyboard.spec.js<|end_filename|>
// @flow

import React from 'react'
import renderer from 'react-test-renderer'
import Keyboard from '../keyboard'
import { walletBalance } from '../../../../__mocks__/static-data'

describe('<Keyboard />', () => {
  const keyboardProps = {
    maxLength: 20,
    color: '#fff',
    onPress: jest.fn(),
    maxValue: walletBalance.data.toString(),
    afterDecimalSeparatorMaxLength: 8,
  }

  function setup() {
    const component = renderer.create(<Keyboard {...keyboardProps} />)
    const instance = component.getInstance()

    return { component, instance }
  }

  it('should render properly and match the snapshot', () => {
    const { component } = setup()
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })

  // TODO: Add extensive tests for onPress function of Keyboard
})


<|start_filename|>app/privacy-tnc/__test__/privacy-tnc.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { PrivacyTNC } from '../privacy-tnc-screen'
import { getNavigation } from '../../../__mocks__/static-data'

describe('Privacy and TNC screen', () => {
  const navigation = getNavigation({
    url: PrivacyTNC.INFO_TYPE.PRIVACY,
  })

  it('should render properly and snapshot should match', () => {
    const tree = renderer
      .create(<PrivacyTNC navigation={navigation} />)
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/store/ledger/__tests__/ledger-store.spec.js<|end_filename|>
// @flow

import { ledgerStoreReducer, getLedgerFeesSaga } from '../ledger-store'
import {
  getLedgerFees,
  getLedgerFeesSuccess,
  ERROR_GET_LEDGER_FEES,
  getLedgerFeesFail,
  resetLedgerFees,
} from '../type-ledger-store'
import { transferFees } from '../../../../__mocks__/data/ledger-store-mock-data'
import { configStoreHydratedInstalledVcxInitSuccess } from '../../../../__mocks__/data/config-store-mock-data'
import { expectSaga } from 'redux-saga-test-plan'
import * as matchers from 'redux-saga-test-plan/matchers'
import { throwError } from 'redux-saga-test-plan/providers'
import { getLedgerFees as getLedgerFeesApi } from '../../../bridge/react-native-cxs/RNCxs'

describe('ledgerStore', () => {
  it('action: GET_LEDGER_FEES', () => {
    expect(ledgerStoreReducer(undefined, getLedgerFees())).toMatchSnapshot()
  })

  it('action: GET_LEDGER_FEES_SUCCESS', () => {
    const stateAfterLedgerFeesStart = ledgerStoreReducer(
      undefined,
      getLedgerFees()
    )
    expect(
      ledgerStoreReducer(
        stateAfterLedgerFeesStart,
        getLedgerFeesSuccess(transferFees)
      )
    ).toMatchSnapshot()
  })

  it('action: GET_LEDGER_FEES_FAIL', () => {
    const stateAfterLedgerFeesStart = ledgerStoreReducer(
      undefined,
      getLedgerFees()
    )
    const error = ERROR_GET_LEDGER_FEES('Test error')
    expect(
      ledgerStoreReducer(stateAfterLedgerFeesStart, getLedgerFeesFail(error))
    ).toMatchSnapshot()
  })

  it('action: RESET_LEDGER_FEES', () => {
    const stateAfterLedgerFeesStart = ledgerStoreReducer(
      undefined,
      getLedgerFees()
    )
    const stateAfterSuccess = ledgerStoreReducer(
      stateAfterLedgerFeesStart,
      getLedgerFeesSuccess(transferFees)
    )
    expect(
      ledgerStoreReducer(stateAfterSuccess, resetLedgerFees())
    ).toMatchSnapshot()
  })

  it('saga: getLedgerFeesSaga => success', () => {
    const stateWithVcxSuccess = {
      config: configStoreHydratedInstalledVcxInitSuccess,
    }

    return expectSaga(getLedgerFeesSaga, getLedgerFees())
      .withState(stateWithVcxSuccess)
      .provide([[matchers.call.fn(getLedgerFeesApi), transferFees]])
      .put(getLedgerFeesSuccess(transferFees))
      .run()
  })

  it('saga: getLedgerFeesSaga => fail', () => {
    const stateWithVcxSuccess = {
      config: configStoreHydratedInstalledVcxInitSuccess,
    }
    const errorMessage = 'test error'
    const error = new Error(errorMessage)

    return expectSaga(getLedgerFeesSaga, getLedgerFees())
      .withState(stateWithVcxSuccess)
      .provide([[matchers.call.fn(getLedgerFeesApi), throwError(error)]])
      .put(getLedgerFeesFail(ERROR_GET_LEDGER_FEES(errorMessage)))
      .run()
  })
})


<|start_filename|>app/qr-code/__tests__/qr-code.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import { Alert } from 'react-native'
import renderer from 'react-test-renderer'
import Camera from 'react-native-camera'
import {
  qrCodeScannerTabRoute,
  invitationRoute,
  homeTabRoute,
} from '../../common/'
import { QRCodeScannerScreen, convertQrCodeToInvitation } from '../qr-code'
import {
  getNavigation,
  qrData,
  environmentSwitchQrCodeData,
  validQrCodeEnvironmentSwitchUrl,
} from '../../../__mocks__/static-data'

describe('<QRScannerScreen />', () => {
  function getProps() {
    return {
      navigation: getNavigation(),
      invitationReceived: jest.fn(),
      currentScreen: qrCodeScannerTabRoute,
      changeEnvironmentUrl: jest.fn(),
      enableCamera: jest.fn(),
      isCameraEnabled: true,
    }
  }

  function setup() {
    const props = getProps()
    const component = renderer.create(<QRCodeScannerScreen {...props} />)
    const instance: QRCodeScannerScreen = component.getInstance()

    return { props, component, instance }
  }

  it('should match snapshot', () => {
    const { instance, component } = setup()
    instance.setState({ isCameraAuthorized: true, isCameraEnabled: true })

    let tree = component.toJSON()
    expect(tree).toMatchSnapshot()
    expect(Camera.checkVideoAuthorizationStatus).toHaveBeenCalledTimes(1)
  })

  it('match snapshot when camera is not authorized', () => {
    const { component } = setup()
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should convert qr code to invitation', () => {
    expect(convertQrCodeToInvitation(qrData)).toMatchSnapshot()
  })

  it('should redirect user to invitation screen on success read', () => {
    const {
      instance,
      component,
      props: { invitationReceived, navigation },
    } = setup()

    instance.onRead(qrData)
    expect(invitationReceived).toHaveBeenCalledWith(
      expect.objectContaining({
        payload: convertQrCodeToInvitation(qrData),
      })
    )
    expect(navigation.push).toHaveBeenCalledWith(invitationRoute, {
      senderDID: qrData.s.d,
    })
  })

  it('should navigate back to home if qr code scanner is closed', () => {
    const { instance, component, props } = setup()
    instance.onClose()
    expect(props.navigation.navigate).toHaveBeenCalledWith(homeTabRoute)
  })

  it('check camera permission screen is updated', () => {
    const { instance, props, component } = setup()

    const calledTimesBeforeUpdating =
      Camera.checkVideoAuthorizationStatus.mock.calls.length
    const updatedComponent = (
      <QRCodeScannerScreen
        {...props}
        {...{ currentScreen: qrCodeScannerTabRoute }}
      />
    )

    // component.update(updatedComponent)

    expect(Camera.checkVideoAuthorizationStatus).toHaveBeenCalledTimes(
      calledTimesBeforeUpdating
    )
  })

  it(`show alert if environment switch url is scanned,
      trigger action when Switch is clicked,
      and redirect to home tab`, () => {
    const {
      instance,
      component,
      props: { changeEnvironmentUrl, navigation: { navigate } },
    } = setup()
    const alertSpy = jest.spyOn(Alert, 'alert')

    instance.onEnvironmentSwitchUrl(environmentSwitchQrCodeData)
    expect(alertSpy).toHaveBeenCalled()

    const switchButton = alertSpy.mock.calls[0][2][1]
    // click switch button
    switchButton.onPress()

    expect(changeEnvironmentUrl).toHaveBeenCalledWith(
      validQrCodeEnvironmentSwitchUrl
    )

    expect(navigate).toHaveBeenCalledWith(homeTabRoute)

    alertSpy.mockReset()
    alertSpy.mockRestore()
  })
})


<|start_filename|>app/components/footer-actions/footer-actions.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, StyleSheet } from 'react-native'
import { connect } from 'react-redux'
import type { Store } from '../../store/type-store'
import {
  CustomView,
  Container,
  CustomButton,
  ImageColorPicker,
  ConnectionTheme,
  CustomSafeAreaView,
} from '../../components'
import { DENY, CONNECT } from '../../common'
import type { FooterActionsProps } from './type-footer-actions'
import { noop } from '../../common'
import { white } from '../../common/styles/constant'
import { getConnectionTheme } from '../../store/store-selector'

const styles = StyleSheet.create({
  buttonStyle: {
    borderLeftColor: white,
    borderLeftWidth: StyleSheet.hairlineWidth,
  },
})

export class FooterActions extends PureComponent<FooterActionsProps, void> {
  render() {
    const {
      denyTitle = DENY,
      acceptTitle = CONNECT,
      logoUrl = '',
      onDecline = noop,
      onAccept = noop,
      testID,
      disableAccept = false,
      disableDeny = false,
      hidePrimary = false,
      useColorPicker = false,
    } = this.props

    return (
      <CustomSafeAreaView
        style={[{ backgroundColor: this.props.activeConnectionThemePrimary }]}
      >
        <CustomView fifth>
          <ConnectionTheme logoUrl={logoUrl}>
            <CustomView row>
              <Container>
                <ConnectionTheme logoUrl={logoUrl} disabled={disableDeny}>
                  <CustomButton
                    primary
                    medium
                    disabled={disableDeny}
                    title={denyTitle}
                    onPress={onDecline}
                    testID={`${testID}-deny`}
                  />
                </ConnectionTheme>
              </Container>
              {!hidePrimary && (
                <Container>
                  <ConnectionTheme logoUrl={logoUrl} disabled={disableAccept}>
                    <CustomButton
                      primary
                      medium
                      disabled={disableAccept}
                      title={acceptTitle}
                      onPress={onAccept}
                      testID={`${testID}-accept`}
                      style={[styles.buttonStyle]}
                      fontWeight="bold"
                    />
                  </ConnectionTheme>
                </Container>
              )}
            </CustomView>
          </ConnectionTheme>
          {useColorPicker && <ImageColorPicker imageUrl={logoUrl} />}
        </CustomView>
      </CustomSafeAreaView>
    )
  }
}

const mapStateToProps = (state: Store, props: FooterActionsProps) => {
  const activeConnectionThemePrimary = getConnectionTheme(
    state,
    props.logoUrl || ''
  ).primary

  return {
    activeConnectionThemePrimary,
  }
}

export default connect(mapStateToProps)(FooterActions)


<|start_filename|>app/push-notification/__tests__/push-notification-store.spec.js<|end_filename|>
// @flow
import { call, select, take } from 'redux-saga/effects'
import { expectSaga } from 'redux-saga-test-plan'
import * as matchers from 'redux-saga-test-plan/matchers'
import {
  getAgencyUrl,
  getAgencyVerificationKey,
  getHydrationState,
  getUserOneTimeInfo,
  getPoolConfig,
} from '../../store/store-selector'
import pushNotificationReducer, {
  pushNotificationPermissionAction,
  pushNotificationReceived,
  updatePushToken,
  onPushTokenUpdate,
} from '../push-notification-store'
import { updatePushTokenVcx } from '../../bridge/react-native-cxs/RNCxs'
import { PAYLOAD_TYPE } from '../../api/api-constants'
import {
  userOneTimeInfo,
  poolConfig,
  claimOfferPushNotification,
} from '../../../__mocks__/static-data'
import { CONNECT_REGISTER_CREATE_AGENT_DONE } from '../../store/user/type-user-store'
import { initialTestAction } from '../../common/type-common'
import uniqueId from 'react-native-unique-id'
import { VCX_INIT_SUCCESS } from '../../store/type-config-store'

describe('push notification store should work properly', () => {
  let initialState = {
    isAllowed: false,
    notification: null,
    pushToken: null,
    isPristine: true,
    isFetching: false,
    error: null,
  }

  beforeAll(() => {
    initialState = pushNotificationReducer(undefined, initialTestAction())
  })

  it('should set push notification permission accepted', () => {
    const expectedState = {
      ...initialState,
      isAllowed: true,
      notification: null,
    }
    const actualState = pushNotificationReducer(
      initialState,
      pushNotificationPermissionAction(true)
    )
    expect(actualState).toMatchObject(expectedState)
  })

  it('should set new push notification flag true', () => {
    const expectedState = {
      ...initialState,
      isAllowed: false,
      notification: claimOfferPushNotification,
    }
    const actualState = pushNotificationReducer(
      initialState,
      pushNotificationReceived(claimOfferPushNotification)
    )
    expect(actualState).toMatchObject(expectedState)
  })

  it('should update push token properly', () => {
    const pushToken = '<KEY>'
    const expectedState = {
      ...initialState,
      isAllowed: true,
      pushToken,
    }
    const actualState = pushNotificationReducer(
      initialState,
      updatePushToken(pushToken)
    )
    expect(actualState).toMatchObject(expectedState)
  })

  it('should reset push notification store, if RESET action is raised', () => {
    const afterPushNotificationReceivedState = pushNotificationReducer(
      initialState,
      pushNotificationReceived(claimOfferPushNotification)
    )
    expect(
      pushNotificationReducer(afterPushNotificationReceivedState, {
        type: 'RESET',
      })
    ).toMatchSnapshot()
  })

  it('saga:onPushTokenUpdateVcx', async () => {
    const pushToken = 'test:<KEY>'
    const vcxInitSuccessState = {
      config: {
        vcxInitializationState: VCX_INIT_SUCCESS,
        isHydrated: true,
      },
      connections: {
        data: null,
      },
      deepLink: {
        tokens: { token: { status: '', token: 'token' } },
      },
      invitation: {},
    }
    const id = await uniqueId()
    const cxsPushTokenConfig = { uniqueId: id, pushToken: `FCM:${pushToken}` }

    return expectSaga(onPushTokenUpdate, updatePushToken(pushToken))
      .withState(vcxInitSuccessState)
      .call(updatePushTokenVcx, cxsPushTokenConfig)
      .run()
  })
})


<|start_filename|>app/home/__tests__/bubbles.spec.js<|end_filename|>
// @flow
import Bubbles from '../../home/bubbles'
import React from 'react'
import renderer from 'react-test-renderer'
import { connections, getNavigation } from '../../../__mocks__/static-data'
import type { Connection } from '../../connection/type-connection'

describe('<Bubbles/>', () => {
  function getProps() {
    const allConnections: any[] = Object.values(connections)
    return {
      connections: allConnections,
      navigation: getNavigation(),
      height: 300,
      unSeenMessages: {},
    }
  }
  it('should render Bubbles', () => {
    const props = getProps()
    const wrapper = renderer
      .create(<Bubbles {...props} showBadge={false} />)
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
  it('should show the dot on the Bubbles', () => {
    const props = getProps()
    const wrapper = renderer
      .create(<Bubbles {...props} showBadge={true} />)
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>app/store/user/user-store.js<|end_filename|>
// @flow
import { put, takeLatest, call, all, select, take } from 'redux-saga/effects'
import type { Saga } from 'redux-saga'
import RNFetchBlob from 'react-native-fetch-blob'
import ImagePicker from 'react-native-image-crop-picker'

import {
  secureSet,
  safeSet,
  safeGet,
  safeDelete,
  getHydrationItem,
} from '../../services/storage'
import {
  CONNECT_REGISTER_CREATE_AGENT_DONE,
  HYDRATE_USER_STORE,
  STORAGE_KEY_USER_ONE_TIME_INFO,
  SAVE_USER_ONE_TIME_INFO_FAIL,
  ERROR_SAVE_USER_INFO_FAIL,
  ERROR_PARSE_USER_INFO_FAIL,
  PARSE_USER_ONE_TIME_INFO_FAIL,
  SAVE_USER_SELECTED_AVATAR,
  USER_AVATAR_IMAGE_NAME,
  ERROR_SAVE_USER_SELECTED_IMAGE,
  SAVE_USER_SELECTED_AVATAR_FAIL,
  SAVE_USER_SELECTED_AVATAR_SUCCESS,
  STORAGE_KEY_USER_AVATAR_NAME,
  ERROR_HYDRATE_USER_SELECTED_IMAGE,
  SELECT_USER_AVATAR,
  SELECT_USER_AVATAR_FAIL,
  ERROR_SELECT_USER_AVATAR,
} from './type-user-store'
import type {
  UserStore,
  UserStoreAction,
  UserOneTimeInfo,
  ConnectRegisterCreateAgentDoneAction,
  SaveUserSelectedAvatarAction,
  HydrateUserStoreData,
} from './type-user-store'
import type { CustomError } from '../../common/type-common'
import { RESET } from '../../common/type-common'
import { uuid } from '../../services/uuid'
import { getUserAvatarName } from '../../store/store-selector'
import { VCX_INIT_SUCCESS } from '../type-config-store'
import { captureError } from '../../services/error/error-handler'

const initialState = {
  isFetching: false,
  error: null,
  userOneTimeInfo: null,
  avatarName: null,
}

export const connectRegisterCreateAgentDone = (
  userOneTimeInfo: UserOneTimeInfo
) => ({
  type: CONNECT_REGISTER_CREATE_AGENT_DONE,
  userOneTimeInfo,
})

export const saveUserOneTimeInfoFail = (error: CustomError) => ({
  type: SAVE_USER_ONE_TIME_INFO_FAIL,
  error,
})

export function* saveUserOneTimeInfoSaga(
  action: ConnectRegisterCreateAgentDoneAction
): Saga<void> {
  const { userOneTimeInfo } = action
  try {
    // we know that user one time info is only created once
    // also this saga will only run while we are calling
    // vcx_init, that saga raises this action
    // so we can assume that when vcxInitSuccess Saga raises this action
    // then we can safely call secureSet
    // Ideally, we should run walletInitSuccess Saga inside all secure*
    // api calls, so that those APIs that needs only wallet access
    // has that wallet handle inside vcx and that should work
    yield take(VCX_INIT_SUCCESS)
    yield call(
      secureSet,
      STORAGE_KEY_USER_ONE_TIME_INFO,
      JSON.stringify(userOneTimeInfo)
    )
  } catch (e) {
    // we need to add some fallback if user storage is not available
    // or is full or if user deleted our data
    captureError(e)
    yield put(
      saveUserOneTimeInfoFail({
        code: ERROR_SAVE_USER_INFO_FAIL.code,
        message: `${ERROR_SAVE_USER_INFO_FAIL.message}${e.message}`,
      })
    )
  }
}

function* watchConnectRegisterCreateAgent(): any {
  yield takeLatest(CONNECT_REGISTER_CREATE_AGENT_DONE, saveUserOneTimeInfoSaga)
}

export const hydrateUserStore = (data: HydrateUserStoreData) => ({
  type: HYDRATE_USER_STORE,
  data,
})

export const hydrateUserStoreFail = (error: CustomError) => ({
  type: PARSE_USER_ONE_TIME_INFO_FAIL,
  error,
})

export function* hydrateUserStoreSaga(): Generator<*, *, *> {
  try {
    const userOneTimeInfoJson: string = yield call(
      getHydrationItem,
      STORAGE_KEY_USER_ONE_TIME_INFO
    )
    if (userOneTimeInfoJson) {
      const userOneTimeInfo: UserOneTimeInfo = JSON.parse(userOneTimeInfoJson)
      yield put(hydrateUserStore({ userOneTimeInfo }))
    }
  } catch (e) {
    yield put(
      hydrateUserStoreFail({
        code: ERROR_PARSE_USER_INFO_FAIL.code,
        message: `${ERROR_PARSE_USER_INFO_FAIL.message}${e.message}`,
      })
    )
  }

  yield* hydrateUserSelectedAvatarImage()
}

export const saveUserSelectedAvatar = (imagePath: string) => ({
  type: SAVE_USER_SELECTED_AVATAR,
  imagePath,
})

export const saveUserSelectedAvatarSuccess = (avatarName: string) => ({
  type: SAVE_USER_SELECTED_AVATAR_SUCCESS,
  avatarName,
})

export const saveUserSelectedAvatarFail = (error: CustomError) => ({
  type: SAVE_USER_SELECTED_AVATAR_FAIL,
  error,
})

export function getImageInfo(imagePath: string) {
  const parts = imagePath.split('/')
  const fileName = parts[parts.length - 1]
  const nameParts = fileName.split('.')
  return {
    name: nameParts[0],
    extension: nameParts[nameParts.length - 1],
  }
}

export function* saveUserSelectedAvatarSaga(
  action: SaveUserSelectedAvatarAction
): Generator<*, *, *> {
  const { imagePath } = action
  const { name, extension } = getImageInfo(imagePath)
  try {
    const appDirectory = RNFetchBlob.fs.dirs.DocumentDir
    const existingAvatarName = yield select(getUserAvatarName)
    const userAvatarPath = `${appDirectory}/${existingAvatarName}`
    const alreadyExist = yield call(RNFetchBlob.fs.exists, userAvatarPath)

    const imageId = uuid()
    const avatarName = `${imageId}.${extension}`
    const newImagePath = `${appDirectory}/${avatarName}`

    if (alreadyExist) {
      yield call(RNFetchBlob.fs.unlink, userAvatarPath)
    }

    yield call(RNFetchBlob.fs.cp, imagePath, newImagePath)
    yield* persistUserSelectedAvatar(avatarName)
    yield put(saveUserSelectedAvatarSuccess(avatarName))
  } catch (e) {
    yield put(
      saveUserSelectedAvatarFail(ERROR_SAVE_USER_SELECTED_IMAGE(e.message))
    )
  }
}

export function* persistUserSelectedAvatar(
  userAvatarName: string
): Generator<*, *, *> {
  yield call(safeSet, STORAGE_KEY_USER_AVATAR_NAME, userAvatarName)
}

export function* hydrateUserSelectedAvatarImage(): Generator<*, *, *> {
  try {
    const avatarName = yield call(safeGet, STORAGE_KEY_USER_AVATAR_NAME)
    if (avatarName) {
      yield put(
        hydrateUserStore({
          avatarName,
        })
      )
    }
  } catch (e) {
    yield put(
      hydrateUserStoreFail(ERROR_HYDRATE_USER_SELECTED_IMAGE(e.message))
    )
  }
}

export function* removePersistedUserSelectedAvatarImage(): Generator<*, *, *> {
  // TODO:KS User avatar should be moved inside wallet
  // either in zip or inside wallet
  // we need to store user avatar, so that on restore user sees same avatar
  yield call(safeDelete, STORAGE_KEY_USER_AVATAR_NAME)
}

export function* watchSaveUserSelectedAvatar(): any {
  yield takeLatest(SAVE_USER_SELECTED_AVATAR, saveUserSelectedAvatarSaga)
}

export const selectUserAvatar = () => ({
  type: SELECT_USER_AVATAR,
})

export const selectUserAvatarFail = (error: CustomError) => ({
  type: SELECT_USER_AVATAR_FAIL,
  error,
})

export function* selectUserAvatarSaga(): Generator<*, *, *> {
  try {
    const image = yield call(ImagePicker.openPicker, {
      mediaType: 'photo',
    })
    yield put(saveUserSelectedAvatar(image.path))
  } catch (e) {
    // TODO:KS Don't know what to do if image is not picked
    // or we get some error, there is no UI to communicate these errors
    yield put(selectUserAvatarFail(ERROR_SELECT_USER_AVATAR(e.message)))
  }
}

export function* watchSelectUserAvatar(): any {
  yield takeLatest(SELECT_USER_AVATAR, selectUserAvatarSaga)
}

export function* watchUserStore(): any {
  yield all([
    watchConnectRegisterCreateAgent(),
    watchSaveUserSelectedAvatar(),
    watchSelectUserAvatar(),
  ])
}

export default function user(
  state: UserStore = initialState,
  action: UserStoreAction
) {
  switch (action.type) {
    case CONNECT_REGISTER_CREATE_AGENT_DONE:
      return {
        ...state,
        userOneTimeInfo: action.userOneTimeInfo,
      }
    case PARSE_USER_ONE_TIME_INFO_FAIL:
      return {
        ...state,
        error: action.error,
      }
    case SAVE_USER_ONE_TIME_INFO_FAIL:
      return {
        ...state,
        error: action.error,
      }
    case HYDRATE_USER_STORE: {
      // HYDRATE_USER_STORE can be fired more than once, it can be called
      // a. when user one time info is fetched from storage
      // b. when user avatar image is fetched from storage
      // in any case, we want to keep previous state if one of the param is missing
      const {
        userOneTimeInfo = state.userOneTimeInfo,
        avatarName = state.avatarName,
      } = action.data

      return {
        ...state,
        userOneTimeInfo,
        avatarName,
      }
    }
    case RESET:
      return initialState
    case SAVE_USER_SELECTED_AVATAR_SUCCESS:
      return {
        ...state,
        avatarName: action.avatarName,
      }
    case SAVE_USER_SELECTED_AVATAR_FAIL:
      return {
        ...state,
        error: action.error,
      }
    default:
      return state
  }
}


<|start_filename|>app/backup/backup-constants.js<|end_filename|>
// @flow

export const RECOVERY_PHRASE_CLOSE_TEST_ID = 'recovery-header-close-image'
export const SHOW_RECOVERY_PHRASE_TEST_ID = 'show-recovery-passphrase'
export const SUBMIT_RECOVERY_PHRASE_TEST_ID = 'submit-recovery-passphrase'
export const SUBMIT_RECOVERY_PHRASE_BUTTON_TITLE = 'Continue'

export const VERIFY_BACK_TEST_ID = 'verify-passphrase-back-image'
export const VERIFY_CLOSE_TEST_ID = 'verify-passphrase-close-image'
export const VERIFY_CONTAINER_TEST_ID = 'verify-passphrase-container'
export const VERIFY_SUBMIT_BUTTON_TEST_ID = 'verify-passphrase-submit-button'
export const VERIFY_INPUT_PLACEHOLDER = 'Enter recovery phrase here'
export const VERIFY_BUTTON_TITLE = 'Submit'

export const EXPORT_BACKUP_BACK_TEST_ID = 'export-backup-back-image'
export const EXPORT_BACKUP_CLOSE_TEST_ID = 'export-backup-close-image'
export const EXPORT_BACKUP_SUBMIT_BUTTON_TEST_ID = 'export-encrypted-backup'
export const EXPORT_BACKUP_BUTTON_TITLE = 'Export Encrypted Backup'
export const BACKUP_ERROR_BACK_TEST_ID = 'backup-error-back-image'
export const BACKUP_ERROR_CLOSE_TEST_ID = 'backup-error-close-image'
export const BACKUP_COMPLETE_CLOSE_TEST_ID =
  'backup-complete-passphrase-close-image'
export const BACKUP_COMPLETE_SUBMIT_BUTTON = 'backup-complete-submit-button'
export const BACKUP_COMPLETE_SUBMIT_BUTTON_TITLE = 'Done'


<|start_filename|>tools/reactotron-config.js<|end_filename|>
import Reactotron from 'reactotron-react-native'

Reactotron.configure()
  .useReactNative()
  .connect()

console.tron = Reactotron


<|start_filename|>app/connection-history/__tests__/connection-history-details.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { ConnectionHistoryDetails } from '../connection-history-details'
import {
  getStore,
  senderLogoUrl,
  claimMap,
  activeConnectionThemePrimary,
  connectionHistoryDetail,
} from '../../../__mocks__/static-data'

describe('<ConnectionHistoryDetails />', () => {
  const store = getStore()
  function props() {
    return {
      navigation: {
        state: {
          params: connectionHistoryDetail,
        },
      },
    }
  }

  it('should ConnectionHistoryDetails render properly', () => {
    const component = renderer.create(
      <Provider store={store}>
        <ConnectionHistoryDetails {...props()} />
      </Provider>
    )
    expect(component).toMatchSnapshot()
  })
})


<|start_filename|>app/common/privacyTNC-constants.js<|end_filename|>
// @flow

import { Platform } from 'react-native'

const isAndroid = Platform.OS === 'android'
export { EULA_URL as TermsAndConditionUrl } from '../eula/type-eula'
export const TermsAndConditionsTitle = 'Terms and Conditions'

export const PrivacyPolicyUrl = 'https://www.connect.me/privacy.html'
export const localPrivacyPolicySource = isAndroid
  ? 'file:///android_asset/external/connectme/privacy.html'
  : './privacy.html'
export const PrivacyPolicyTitle = 'Privacy Policy'


<|start_filename|>app/store/user/type-user-store.js<|end_filename|>
// @flow
import type { CustomError, InitialTestAction } from '../../common/type-common'

export type UserOneTimeInfo = {
  oneTimeAgencyDid: string,
  oneTimeAgencyVerificationKey: string,
  myOneTimeDid: string,
  myOneTimeVerificationKey: string,
  myOneTimeAgentDid: string,
  myOneTimeAgentVerificationKey: string,
}

export type UserStore = {
  isFetching: boolean,
  error: ?CustomError,
  userOneTimeInfo: ?UserOneTimeInfo,
  avatarName: ?string,
}

export type ChangeEnvironment = {
  agencyUrl: string,
  poolConfig: string,
  agencyDID: string,
  agencyVerificationKey: string,
}

export const CONNECT_REGISTER_CREATE_AGENT_DONE =
  'CONNECT_REGISTER_CREATE_AGENT_DONE'

export type ConnectRegisterCreateAgentDoneAction = {
  type: typeof CONNECT_REGISTER_CREATE_AGENT_DONE,
  userOneTimeInfo: UserOneTimeInfo,
}

export const HYDRATE_USER_STORE = 'HYDRATE_USER_STORE'

export type HydrateUserStoreData = {
  userOneTimeInfo?: ?UserOneTimeInfo,
  avatarName?: ?string,
}

export type HydrateUserStoreAction = {
  type: typeof HYDRATE_USER_STORE,
  data: HydrateUserStoreData,
}

export const SAVE_USER_ONE_TIME_INFO_FAIL = 'SAVE_USER_ONE_TIME_INFO_FAIL'

export type SaveUserOneTimeInfoFailAction = {
  type: typeof SAVE_USER_ONE_TIME_INFO_FAIL,
  error: CustomError,
}

export const PARSE_USER_ONE_TIME_INFO_FAIL = 'PARSE_USER_ONE_TIME_INFO_FAIL'

export type ParseUserOneTimeInfoFailAction = {
  type: typeof PARSE_USER_ONE_TIME_INFO_FAIL,
  error: CustomError,
}

export const SAVE_USER_SELECTED_AVATAR = 'SAVE_USER_SELECTED_AVATAR'

export type SaveUserSelectedAvatarAction = {
  type: typeof SAVE_USER_SELECTED_AVATAR,
  imagePath: string,
}

export const SAVE_USER_SELECTED_AVATAR_SUCCESS =
  'SAVE_USER_SELECTED_AVATAR_SUCCESS'
export type SaveUserSelectedAvatarSuccessAction = {
  type: typeof SAVE_USER_SELECTED_AVATAR_SUCCESS,
  avatarName: string,
}

export const SAVE_USER_SELECTED_AVATAR_FAIL = 'SAVE_USER_SELECTED_AVATAR_FAIL'
export type SaveUserSelectedAvatarFailAction = {
  type: typeof SAVE_USER_SELECTED_AVATAR_FAIL,
  error: CustomError,
}

export const SELECT_USER_AVATAR = 'SELECT_USER_AVATAR'
export type SelectUserAvatarAction = {
  type: typeof SELECT_USER_AVATAR,
}

export const SELECT_USER_AVATAR_FAIL = 'SELECT_USER_AVATAR_FAIL'
export type SelectUserAvatarFailAction = {
  type: typeof SELECT_USER_AVATAR_FAIL,
  error: CustomError,
}

export const USER_AVATAR_IMAGE_NAME = 'user-avatar'

export type UserStoreAction =
  | ConnectRegisterCreateAgentDoneAction
  | HydrateUserStoreAction
  | SaveUserOneTimeInfoFailAction
  | ParseUserOneTimeInfoFailAction
  | SaveUserSelectedAvatarAction
  | SaveUserSelectedAvatarSuccessAction
  | SaveUserSelectedAvatarFailAction
  | SelectUserAvatarAction
  | SelectUserAvatarFailAction
  | InitialTestAction

export const STORAGE_KEY_USER_ONE_TIME_INFO = 'STORAGE_KEY_USER_ONE_TIME_INFO'
export const STORAGE_KEY_USER_AVATAR_NAME = 'STORAGE_KEY_USER_AVATAR_NAME'

export const ERROR_SAVE_USER_INFO_FAIL = {
  message: 'Failed to store user one time info: ',
  code: 'US-001',
}

export const ERROR_PARSE_USER_INFO_FAIL = {
  message: 'Failed to parse user info: ',
  code: 'US-002',
}

export const ERROR_SAVE_USER_SELECTED_IMAGE = (message: string) => ({
  message: `Failed to store user avatar: ${message}`,
  code: 'US-003',
})

export const ERROR_HYDRATE_USER_SELECTED_IMAGE = (message: string) => ({
  message: `Failed to get user avatar: ${message}`,
  code: 'US-004',
})

export const ERROR_SELECT_USER_AVATAR = (message: string) => ({
  message: `Failed to select user avatar: ${message}`,
  code: 'US-005',
})


<|start_filename|>app/services/__mocks__/uuid.js<|end_filename|>
// @flow
import { defaultUUID } from '../../../__mocks__/static-data'

export function uuid() {
  return defaultUUID
}


<|start_filename|>connectMeUITest/src/funcModules/LockModules.java<|end_filename|>
package funcModules;

import appModules.AppUtlis;
import io.appium.java_client.AppiumDriver;
import pageObjects.ChooseLockPage;
import pageObjects.PincodePage;

public class LockModules {
	
	AppUtlis AppUtlisObj=new AppUtlis();

	public void PinCodeSetup(AppiumDriver driver) throws Exception{
		
	for(int j=0;j<2;j++)
	{
		AppUtlisObj.enterPincode(driver);
	}
	PincodePage.Close_Button(driver).click();
	
	}
	
	public void InvalidPinCodeSetup(AppiumDriver driver) throws Exception{
		
	ChooseLockPage.PinCodeLock_Button(driver).click();
	AppUtlisObj.enterPincode(driver);
	AppUtlisObj.enterPincodeReverse(driver);
		
    }

}


<|start_filename|>e2e/first-install.spec.js<|end_filename|>
import { exec } from 'child-process-async'

describe('ConnectMe without invitation', () => {
  beforeEach(async () => {
    await device.reloadReactNative()
  })

  it('switch environment, pin code setup, show dashboard', async () => {
    const orText = element(by.id('lock-selection-or-text-touchable'))

    await orText.longPress()
    for (let i = 0; i < 10; i++) {
      await orText.tap()
    }
    if (device.getPlatform() === 'ios') {
      await element(
        by.label('OK').and(by.type('_UIAlertControllerActionView'))
      ).tap()
    } else {
      await element(by.type('android.widget.Button').and(by.text('OK'))).tap()
    }

    await element(by.id('switch-environment-dev')).tap()
    await element(by.id('switch-environment-footer-accept')).tap()

    await element(by.id('pin-code-selection-touchable')).tap()

    await element(by.id('pin-code-input-box')).replaceText('000000')
    await element(by.id('pin-code-input-box')).replaceText('000000')

    await element(by.id('close-button')).tap()

    await expect(element(by.id('user-avatar'))).toBeVisible()

    if (device.getPlatform() === 'ios') {
      await exec('xcrun simctl io booted screenshot e2e/screenshots/home.jpg')
    }
  })
})


<|start_filename|>app/wallet/__tests__/wallet.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { walletRoute } from '../../common'
import { Wallet } from '../wallet'
import { getNavigation, getStore } from '../../../__mocks__/static-data'

function props() {
  return {
    navigation: getNavigation(),
    route: {
      currentScreen: walletRoute,
    },
  }
}

describe('<Wallet />', () => {
  const store = getStore()

  jest.useFakeTimers()

  it('should render Wallet', () => {
    const walletProps = props()
    const wrapper = renderer
      .create(
        <Provider store={store}>
          <Wallet {...walletProps} />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>app/components/layout/container.js<|end_filename|>
// @flow
import React from 'react'
import { CustomView } from './custom-view'
import style from './layout-style'
import type { GenericObject } from '../../common/type-common'

const empty = []

// Use -
// When a View is supposed to take all space available to it
// When used as <Container> siblings, they all take space in equal ratio
export const Container = (props: GenericObject) => {
  const passedStyles = props.style ? props.style : empty
  return (
    <CustomView {...props} style={[...passedStyles, style.container]}>
      {props.children}
    </CustomView>
  )
}


<|start_filename|>app/wallet/__tests__/wallet-send-amount.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import { Provider } from 'react-redux'
import renderer from 'react-test-renderer'
import WalletSendAmount from '../wallet-send-amount'
import { getNavigation, getStore } from '../../../__mocks__/static-data'

describe('<WalletSendAmount />', () => {
  let outerNavigation = {
    navigation: getNavigation(),
  }
  let navigation = {
    ...getNavigation(),
  }
  let selectTokenAmount = jest.fn()
  function setup() {
    const component = renderer.create(
      <Provider store={getStore()}>
        <WalletSendAmount
          screenProps={outerNavigation}
          navigation={navigation}
          selectTokenAmount={selectTokenAmount}
        />
      </Provider>
    )
    const instance = component.getInstance()

    return { component, instance }
  }
  it('should render properly and match the snapshot', () => {
    const { component } = setup()
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/authentication/__tests__/authentication-store.spec.js<|end_filename|>
// @flow
import authentication, {
  sendUserAuthenticationResponseSuccess,
  sendUserAuthenticationResponseFailure,
  authenticationRequestReceived,
  resetAuthenticationStatus,
  sendUserAuthenticationResponse,
  AUTHENTICATION_TYPE,
  AUTHENTICATION_STATUS,
} from '../authentication-store'
import type {
  AuthenticationStatus,
  AuthenticationType,
  AuthenticationStore,
  AuthenticationPayload,
  NewConnection,
  AuthenticationError,
  ResetAuthenticationStatus,
  AuthenticationAction,
  SendUserAuthenticationResponse,
  AuthenticationSuccessData,
  SendUserAuthenticationResponseSuccess,
  SendUserAuthenticationResponseFailure,
  AuthenticationRequestReceived,
} from '../type-authentication'
import { PUSH_NOTIFICATION_SENT_CODE } from '../../api/api-constants'
import { RESET } from '../../common/type-common'
import { getStore } from '../../../__mocks__/static-data'

describe('Authentication request tests', () => {
  const initialAction: AuthenticationAction = {
    type: 'INITIAL_TEST_ACTION',
  }

  let initialState
  beforeEach(() => {
    initialState = authentication(undefined, initialAction)
  })

  it('should correctly match initial state', () => {
    expect(initialState).toMatchSnapshot()
  })

  it('send user authentication response success action should update store', () => {
    const successData = {
      newStatus: AUTHENTICATION_STATUS.ACCEPTED,
      dataBody: { challenge: 'challenge', signature: 'signature' },
      identifier: 'identifier',
      remoteConnectionId: 'remoteConnectionId',
    }
    const successAction: SendUserAuthenticationResponseSuccess = sendUserAuthenticationResponseSuccess(
      successData
    )
    expect(authentication(initialState, successAction)).toMatchSnapshot()
  })

  it('send user authentication response failure action should update store', () => {
    const error = {
      message: '',
      authenticationType: AUTHENTICATION_TYPE.AUTHENTICATION_REQUEST,
    }
    const errorAction: SendUserAuthenticationResponseFailure = sendUserAuthenticationResponseFailure(
      error
    )
    expect(authentication(initialState, errorAction)).toMatchSnapshot()
  })

  it('authentication status reset action should update store', () => {
    const resetAction: ResetAuthenticationStatus = resetAuthenticationStatus()
    expect(authentication(initialState, resetAction)).toMatchSnapshot()
  })

  it('send user authentication response received action should update store', () => {
    const receivedData = {
      offerMsgTitle: 'Hi There',
      offerMsgText: 'Suncoast Credit Union (sandbox) wants to connect with you',
      statusCode: PUSH_NOTIFICATION_SENT_CODE,
      logoUrl: null,
      remoteConnectionId: 'B4Y9fhpeHdGHBKKtSgAYrB',
    }
    const receivedAction: AuthenticationRequestReceived = authenticationRequestReceived(
      receivedData
    )
    expect(authentication(initialState, receivedAction)).toMatchSnapshot()
  })

  it('send user authentication response', () => {
    const newStatus = 'some status'
    const challenge = 'some challenge'
    const signature = 'some signature'
    const identifier = 'some identifier'
    const config = getStore().getState().config

    const responseAction: SendUserAuthenticationResponse = sendUserAuthenticationResponse(
      {
        newStatus,
        identifier,
        remoteConnectionId: 'remoteConnectionId',
        dataBody: {
          challenge,
          signature,
        },
      },
      config,
      AUTHENTICATION_TYPE.AUTHENTICATION_REQUEST
    )
    expect(authentication(initialState, responseAction)).toMatchSnapshot()
  })

  it('should reset authentication store when reset action is raised', () => {
    const successData = {
      newStatus: AUTHENTICATION_STATUS.ACCEPTED,
      dataBody: { challenge: 'challenge', signature: 'signature' },
      identifier: 'identifier',
      remoteConnectionId: 'remoteConnectionId',
    }
    const successState = authentication(
      initialState,
      sendUserAuthenticationResponseSuccess(successData)
    )
    expect(authentication(successState, { type: RESET })).toMatchSnapshot()
  })
})


<|start_filename|>app/restore/restore-passphrase.js<|end_filename|>
// @flow
import React, { Component, PureComponent } from 'react'
import EnterPassphrase from '../components/backup-restore-passphrase/backup-restore-passphrase'
import { createStackNavigator } from 'react-navigation'
import { color } from '../common/styles/constant'
import { restorePassphraseRoute, restoreWaitRoute } from '../common'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { submitPassphrase } from './restore-store'
import type { RestorePassphraseProps } from './type-restore'
import type { Store } from '../store/type-store'
import { CustomView, Icon, CustomHeader } from '../components'
import {
  RESTORE_BACK_BUTTON_TEST_ID,
  RESTORE_CLOSE_BUTTON_TEST_ID,
} from './type-restore'
import styles from '../backup/styles'

const backImage = require('../images/icon_backArrow_white.png')
const closeImage = require('../images/iconClose.png')

export class RestorePassphrase extends Component<RestorePassphraseProps, void> {
  static navigationOptions = ({ navigation }) => ({
    header: (
      <CustomHeader flatHeader backgroundColor={color.bg.twelfth.color}>
        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => {
              navigation.goBack(null)
            }}
            testID={RESTORE_BACK_BUTTON_TEST_ID}
            iconStyle={[styles.headerBackIcon]}
            src={backImage}
          />
        </CustomView>

        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => {
              navigation.goBack(null)
            }}
            testID={RESTORE_CLOSE_BUTTON_TEST_ID}
            iconStyle={[styles.headerIcon]}
            src={closeImage}
          />
        </CustomView>
      </CustomHeader>
    ),
    gesturesEnabled: false,
  })

  submitPhrase = (event: any) => {
    this.props.submitPassphrase(event.nativeEvent.text)
    this.props.navigation.navigate(restoreWaitRoute)
  }

  componentDidMount() {
    this.props.navigation.setParams({
      ...this.props,
    })
  }

  render() {
    const filename = this.props.restore.restoreFile.fileName

    return (
      <EnterPassphrase
        testID={'restore-encrypt-phrase'}
        onSubmit={this.submitPhrase}
        placeholder={'Enter Recovery Phrase here'}
        filename={filename}
      />
    )
  }
}

const mapStateToProps = (state: Store) => {
  return {
    restore: state.restore,
    route: state.route.currentScreen,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators({ submitPassphrase }, dispatch)

export default createStackNavigator({
  [restorePassphraseRoute]: {
    screen: connect(mapStateToProps, mapDispatchToProps)(RestorePassphrase),
  },
})


<|start_filename|>app/deep-link/__test__/deep-link-store.spec.js<|end_filename|>
// @flow
import deepLinkReducer, {
  deepLinkData,
  deepLinkEmpty,
  deepLinkError,
} from '../deep-link-store'
import { RESET, initialTestAction } from '../../common/type-common'

describe('Deep link store', () => {
  let initialState
  beforeEach(() => {
    initialState = deepLinkReducer(undefined, initialTestAction())
  })

  it('should correctly update store when we get deep link data', () => {
    expect(
      deepLinkReducer(initialState, deepLinkData('erg76sd'))
    ).toMatchSnapshot()
  })

  it('should update store for empty link', () => {
    expect(deepLinkReducer(initialState, deepLinkEmpty())).toMatchSnapshot()
  })

  it('should update store for error', () => {
    expect(
      deepLinkReducer(initialState, deepLinkError('error'))
    ).toMatchSnapshot()
  })

  it('should reset, if RESET action is raised', () => {
    const afterDeepLinkDataState = deepLinkReducer(
      initialState,
      deepLinkData('erg76esd')
    )
    expect(
      deepLinkReducer(afterDeepLinkDataState, { type: 'RESET' })
    ).toMatchSnapshot()
  })
})


<|start_filename|>connectMeUITest/src/pageObjects/GmailPage.java<|end_filename|>
package pageObjects;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
  
/**
 * Created by ankurmishra on 6/22/17.
 */
public class GmailPage {

	private static WebElement element = null;

	
	@FindBy(name= "identifierId") 
	public static WebElement userName;
	
	public static WebElement UserNameText(AppiumDriver driver) throws Exception {

		try {
			
			WebDriverWait wait = new WebDriverWait(driver, 120);
			element = driver.findElement(By.id("identifierId"));

			//element = wait.until(ExpectedConditions.elementToBeClickable(By.id("identifierId")));
			System.out.println("UserNameText is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("UserNameText  is not found.");


			throw (e);
		}
	}
	
	public static WebElement FirstEmailLink(AppiumDriver driver) throws Exception {

		try {
			WebDriverWait wait = new WebDriverWait(driver, 90);
			element = driver.findElement(By.xpath("//div[@role='listitem']/div"));

			//element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@role='listitem']/div")));	
			System.out.println("FirstEmail Link is displayed");

			return element;
		} catch (Exception e) {

			System.out.println("FirstEmail Link  is not found.");


			throw (e);
		}

	}
	
	public static WebElement ConnectMeLink(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("//td/a[2]"));
			System.out.println("ConnectMeLink is displayed");

			
			return element;
		} catch (Exception e) {

			System.out.println("ConnectMeLink  is not found.");


			throw (e);
		}

	}

	public static WebElement PasswordText(AppiumDriver driver) throws Exception {
		try {

			element = driver.findElement(By.name("password"));
			System.out.println("Password Text is displayed");
			return element;

		} catch (Exception e) {
			System.out.println("Password is not displayed");

			throw (e);

		}
	}

	public static WebElement UserNameNextButton(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.id("identifierNext"));
			System.out.println("NextButton is displayed");

			return element;
		    } catch (Exception e) {

			System.out.println("NextButton is not displayed");

			throw (e);
		}
	}
	
	public static WebElement PasswordNextButton(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.id("passwordNext"));
			System.out.println("NextButton is displayed");

			return element;
		    } catch (Exception e) {

				System.out.println("NextButton is not displayed");
			throw (e);
		}
	}
	
    public static WebElement MobileGmailSiteLink(AppiumDriver driver) throws Exception {

			try {
				element =driver.findElement(By.xpath("//a[text()='mobile Gmail site']"));
				System.out.println("MobileGmail Site Link is displayed");
				return element;
			    } catch (Exception e) {

				System.out.println("MobileGmailSite Link is not displayed");

				throw (e);
			}

	}
		
	public static WebElement Signin(AppiumDriver driver) throws Exception {

			try {
				element = driver.findElement(By.xpath("//button[@type='submit']"));
				System.out.println("Signin is displayed");

				return element;
			    } catch (Exception e) {

				System.out.println("Signin is not displayed");

				throw (e);
			}

	}

	public static WebElement Email_CheckBox(AppiumDriver driver)  {

		try {
			element = driver.findElement(By.xpath("(//div[@role='checkbox'])[1]"));
			System.out.println("Email checkbox is displayed");

		    } catch (Exception e) {
            element =null;
			System.out.println("Email checkbox is not displayed");

		}
		return element;


}

	public static WebElement Delete_Button(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("//div[@aria-label='Delete']/div"));
			System.out.println("Delete button is displayed");

			return element;
		    } catch (Exception e) {

			System.out.println("Delete button is not displayed");

			throw (e);
		}

}

}


<|start_filename|>app/components/__tests__/badge.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import Badge from '../badge'
import renderer from 'react-test-renderer'

describe('<Badge />', () => {
  function getProps() {
    return {
      count: 10,
      secondary: false,
      badgeStyle: {},
      shadow: false,
      onPress: jest.fn(),
    }
  }

  it('should render light colored badge', () => {
    const props = getProps()
    const badge = renderer.create(<Badge {...props} center={true} />).toJSON()
    expect(badge).toMatchSnapshot()
  })

  it('should render dark colored badge', () => {
    const props = getProps()
    const badge = renderer.create(<Badge {...props} text={10} />).toJSON()
    expect(badge).toMatchSnapshot()
  })
})


<|start_filename|>app/store/__tests__/config-store.spec.js<|end_filename|>
// @flow
import 'react-native'
import { Alert } from 'react-native'
import renderer from 'react-test-renderer'
import { put, take, call, select } from 'redux-saga/effects'
import { expectSaga } from 'redux-saga-test-plan'
import * as matchers from 'redux-saga-test-plan/matchers'
import { throwError } from 'redux-saga-test-plan/providers'
import configReducer, {
  watchSwitchErrorAlerts,
  changeServerEnvironment,
  toggleErrorAlerts,
  baseUrls,
  alreadyInstalledAction,
  hydrated,
  onEnvironmentSwitch,
  hydrateSwitchedEnvironmentDetails,
  changeEnvironment,
  onChangeEnvironmentUrl,
  changeEnvironmentUrl,
  vcxInitReset,
  vcxInitStart,
  vcxInitSuccess,
  vcxInitFail,
  initVcx,
  ensureVcxInitSuccess,
  getEnvironmentName,
} from '../config-store'
import {
  SERVER_ENVIRONMENT_CHANGED,
  SERVER_ENVIRONMENT,
  SWITCH_ERROR_ALERTS,
  STORAGE_KEY_SWITCHED_ENVIRONMENT_DETAIL,
  ERROR_VCX_INIT_FAIL,
  HYDRATED,
  ERROR_VCX_PROVISION_FAIL,
  VCX_INIT_NOT_STARTED,
  VCX_INIT_SUCCESS,
  VCX_INIT_START,
} from '../type-config-store'
import {
  agencyDID,
  agencyUrl,
  agencyVerificationKey,
  poolConfig,
  validQrCodeEnvironmentSwitchUrl,
  userOneTimeInfo,
} from '../../../__mocks__/static-data'
import { downloadEnvironmentDetails } from '../../api/api'
import {
  RESET,
  REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS,
} from '../../common/type-common'
import {
  resetVcx as resetNative,
  createOneTimeInfo,
  vcxShutdown,
  init,
} from '../../bridge/react-native-cxs/RNCxs'
import { updatePushToken } from '../../push-notification/push-notification-store'
import { getPushToken } from '../../store/store-selector'
import { connectRegisterCreateAgentDone } from '../user/user-store'
import { homeRoute } from '../../common/route-constants'
import {
  walletGet,
  walletSet,
  secureSet,
  secureGet,
  getHydrationItem,
} from '../../services/storage'

const getConfigStoreInitialState = () =>
  configReducer(undefined, { type: 'INITIAL_TEST_ACTION' })

describe('server environment should change', () => {
  let initialConfig = null
  const serializedEnvironmentDetail = JSON.stringify({
    poolConfig,
    agencyDID,
    agencyVerificationKey,
    agencyUrl,
  })

  beforeEach(() => {
    initialConfig = getConfigStoreInitialState()
  })

  it('initial app should always point to demo', () => {
    if (initialConfig) {
      expect(initialConfig.agencyUrl).toBe(baseUrls.DEMO.agencyUrl)
    }
  })

  it('to demo if previously it was set to sandbox', () => {
    const expectedConfig = {
      ...initialConfig,
      ...baseUrls[SERVER_ENVIRONMENT.DEMO],
    }

    if (initialConfig) {
      expect(
        configReducer(
          initialConfig,
          changeServerEnvironment(SERVER_ENVIRONMENT.DEMO)
        )
      ).toEqual(expectedConfig)
    } else {
      // we fail the test if we don't get any initial state
      expect(1).toBe(2)
    }
  })

  it('toggle showErrorAlerts if action is raised more than 3 times', () => {
    const gen = watchSwitchErrorAlerts()
    for (let i = 0; i < 4; i++) {
      expect(gen.next().value).toEqual(take(SWITCH_ERROR_ALERTS))
    }

    // after 3 times, it should raise an action to toggle showErrorAlerts
    gen.next()
    expect(gen.next().value).toEqual(put(toggleErrorAlerts(true)))
  })

  it('should store switched environment details', () => {
    const gen = onEnvironmentSwitch(
      changeEnvironment(agencyUrl, agencyDID, agencyVerificationKey, poolConfig)
    )
    let switchedEnvironmentDetails = {
      poolConfig,
      agencyDID,
      agencyVerificationKey,
      agencyUrl,
    }
    expect(gen.next().value).toEqual(
      call(
        secureSet,
        STORAGE_KEY_SWITCHED_ENVIRONMENT_DETAIL,
        JSON.stringify(switchedEnvironmentDetails)
      )
    )
    expect(gen.next().done).toBe(true)
  })

  it('should hydrate switched environment details', () => {
    const gen = hydrateSwitchedEnvironmentDetails()
    expect(gen.next().value).toEqual(
      call(getHydrationItem, STORAGE_KEY_SWITCHED_ENVIRONMENT_DETAIL)
    )
    let switchedEnvironmentDetails = {
      poolConfig,
      agencyDID,
      agencyVerificationKey,
      agencyUrl,
    }
    expect(gen.next(serializedEnvironmentDetail).value).toEqual(
      put(
        changeEnvironment(
          agencyUrl,
          agencyDID,
          agencyVerificationKey,
          poolConfig
        )
      )
    )
  })

  // Below test is written for switching environment with scanning QR code
  // we are not using this feature as of now, we will come to this feature later
  // when we add this with vcx, and then we will un-skip this test
  xit('should change environment via url, show success alert', () => {
    const alertSpy = jest.spyOn(Alert, 'alert')
    const gen = onChangeEnvironmentUrl(
      changeEnvironmentUrl(validQrCodeEnvironmentSwitchUrl)
    )

    expect(gen.next().value).toEqual(
      call(downloadEnvironmentDetails, validQrCodeEnvironmentSwitchUrl)
    )

    const environmentDetails = {
      agencyDID,
      agencyUrl,
      agencyVerificationKey,
      poolConfig,
    }
    // delete stored data, not interested in actual calls
    // those tests are being taken care in other test
    // TODO: Change index value to constant that better describes what the number represents
    // for (let index = 0; index < 6; index++) {
    //   gen.next()
    // }

    // expect(gen.next().value).toEqual(
    //   put({ type: REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS })
    // )
    // gen.next()
    expect(gen.next(environmentDetails).value).toEqual(put({ type: RESET }))
    expect(gen.next().value).toEqual(
      put(
        changeEnvironment(
          agencyUrl,
          agencyDID,
          agencyVerificationKey,
          poolConfig
        )
      )
    )
    expect(gen.next().value).toEqual(select(getPushToken))
    const pushToken = 'token'
    expect(gen.next(pushToken).value).toEqual(put(updatePushToken(pushToken)))
    expect(gen.next().value).toEqual(call(resetNative, true))
    expect(gen.next().value).toEqual(put(vcxInitReset()))

    expect(gen.next().done).toBe(true)

    expect(alertSpy).toHaveBeenCalledTimes(1)

    alertSpy.mockReset()
    alertSpy.mockRestore()
  })

  it('should not change environment via url if downloaded data is not correct', () => {
    const alertSpy = jest.spyOn(Alert, 'alert')
    const gen = onChangeEnvironmentUrl(
      changeEnvironmentUrl(validQrCodeEnvironmentSwitchUrl)
    )

    expect(gen.next().value).toEqual(
      call(downloadEnvironmentDetails, validQrCodeEnvironmentSwitchUrl)
    )
    const invalidEnvironmentDetails = {
      agencyDID,
      agencyUrl,
      agencyVerificationKey,
    }

    expect(gen.next(invalidEnvironmentDetails).done).toBe(true)

    expect(alertSpy).toHaveBeenCalledTimes(1)

    alertSpy.mockReset()
    alertSpy.mockRestore()
  })

  it('should show alert with error message if any error occurs', () => {
    const alertSpy = jest.spyOn(Alert, 'alert')
    const gen = onChangeEnvironmentUrl(
      changeEnvironmentUrl(validQrCodeEnvironmentSwitchUrl)
    )

    expect(gen.next().value).toEqual(
      call(downloadEnvironmentDetails, validQrCodeEnvironmentSwitchUrl)
    )

    gen.throw(new Error('Some error'))

    expect(alertSpy).toHaveBeenCalledTimes(1)

    alertSpy.mockReset()
    alertSpy.mockRestore()
  })
})

describe('reducer:config', () => {
  it('action:VCX_INIT_NOT_STARTED', () => {
    const initialState = getConfigStoreInitialState()
    expect(configReducer(initialState, vcxInitReset())).toMatchSnapshot()
  })

  it('action:VCX_INIT_START', () => {
    const initialState = getConfigStoreInitialState()
    expect(configReducer(initialState, vcxInitStart())).toMatchSnapshot()
  })

  it('action:VCX_INIT_SUCCESS', () => {
    const initialState = getConfigStoreInitialState()
    expect(configReducer(initialState, vcxInitSuccess())).toMatchSnapshot()
  })

  it('action:VCX_INIT_FAIL', () => {
    const initialState = getConfigStoreInitialState()
    const error = ERROR_VCX_INIT_FAIL('error from test')
    expect(configReducer(initialState, vcxInitFail(error))).toMatchSnapshot()
  })
})

describe('config-store:saga', () => {
  const notHydratedNoOneTimeInfoState = {
    config: {
      isHydrated: false,
      vcxInitializationState: VCX_INIT_NOT_STARTED,
    },
    user: {},
    route: {
      currentScreen: homeRoute,
    },
  }
  const agencyConfig = {
    agencyUrl,
    agencyDID,
    agencyVerificationKey,
    poolConfig,
  }

  it('initVcx, success', () => {
    return expectSaga(initVcx)
      .withState(notHydratedNoOneTimeInfoState)
      .dispatch({ type: HYDRATED })
      .provide([
        [matchers.call.fn(createOneTimeInfo, agencyConfig), userOneTimeInfo],
        [matchers.call.fn(init, { ...userOneTimeInfo, ...agencyConfig }), true],
      ])
      .put(connectRegisterCreateAgentDone(userOneTimeInfo))
      .put(vcxInitSuccess())
      .run()
  })

  it('initVcx, fail provision', () => {
    const errorMessage = 'test provision fail error'
    const failProvisionError = new Error(errorMessage)

    return expectSaga(initVcx)
      .withState(notHydratedNoOneTimeInfoState)
      .dispatch({ type: HYDRATED })
      .provide([
        [
          matchers.call.fn(createOneTimeInfo, agencyConfig),
          throwError(failProvisionError),
        ],
        [matchers.call.fn(vcxShutdown, false), true],
      ])
      .put(vcxInitFail(ERROR_VCX_PROVISION_FAIL(errorMessage)))
      .run()
  })

  it('initVcx, fail init', () => {
    const errorMessage = 'test init fail error'
    const failInitError = new Error(errorMessage)

    return expectSaga(initVcx)
      .withState(notHydratedNoOneTimeInfoState)
      .dispatch({ type: HYDRATED })
      .provide([
        [matchers.call.fn(createOneTimeInfo, agencyConfig), userOneTimeInfo],
        [
          matchers.call.fn(init, { ...userOneTimeInfo, ...agencyConfig }),
          throwError(failInitError),
        ],
      ])
      .put(connectRegisterCreateAgentDone(userOneTimeInfo))
      .put(vcxInitFail(ERROR_VCX_INIT_FAIL(errorMessage)))
      .run()
  })

  it('ensureVcxInitSuccess, not initialized', () => {
    return expectSaga(ensureVcxInitSuccess)
      .withState(notHydratedNoOneTimeInfoState)
      .dispatch({ type: VCX_INIT_SUCCESS })
      .put(vcxInitStart())
      .run()
  })

  it('ensureVcxInitSuccess, already started', () => {
    return expectSaga(ensureVcxInitSuccess)
      .withState({
        config: {
          vcxInitializationState: VCX_INIT_START,
        },
      })
      .dispatch({ type: VCX_INIT_SUCCESS })
      .not.put(vcxInitStart())
      .run()
  })

  it('ensureVcxInitSuccess, already initialized', () => {
    return expectSaga(ensureVcxInitSuccess)
      .withState({
        config: {
          vcxInitializationState: VCX_INIT_SUCCESS,
        },
      })
      .not.take(VCX_INIT_SUCCESS)
      .run()
  })

  it('fn:getEnvironmentName', () => {
    expect(getEnvironmentName(getConfigStoreInitialState())).toMatchSnapshot()
  })
})


<|start_filename|>flow-typed/react-native-image-resizer_v1.0.0.js<|end_filename|>
// @flow

declare module 'react-native-image-resizer' {
  declare type ResizedImageInfo = {
    path: string,
    uri: string,
    size?: number,
    name?: string,
  }

  declare type ImageResizer = {
    createResizedImage: (
      uri: string,
      width: number,
      height: number,
      format: 'PNG' | 'JPEG' | 'WEBP',
      quality: number,
      rotation?: number,
      outputPath?: string
    ) => Promise<ResizedImageInfo>,
  }

  declare export default ImageResizer
}


<|start_filename|>app/lock/__tests__/lock-fingerprint-setup.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { PIN_SETUP_STATE } from '../type-lock'
import { LockFingerprintSetup } from '../lock-fingerprint-setup'
import { lockPinSetupRoute, lockTouchIdSetupRoute } from '../../common'
import { getNavigation } from '../../../__mocks__/static-data'

describe('<LockFingerprintSetup />', () => {
  const getProps = () => ({
    navigation: getNavigation({ touchIdActive: true }),
    touchIdActive: true,
    fromSettings: false,
    currentScreen: lockTouchIdSetupRoute,
    disableTouchIdAction: jest.fn(),
    enableTouchIdAction: jest.fn(),
  })

  const options = {
    createNodeMock: element => {
      return {
        clear: () => {
          cleared = true
        },
      }
    },
  }

  let component
  let props
  let cleared

  beforeEach(() => {
    props = getProps()
    component = renderer.create(<LockFingerprintSetup {...props} />, options)
  })

  it('should render touchId modal', () => {
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should test touchId handler is called', () => {
    let tree = component.toJSON()
    let instance = component.getInstance()
    //manually set to true"
    instance.touchIdHandler()
    tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/proof-request/type-proof-request.js<|end_filename|>
// @flow
import { INITIAL_TEST_ACTION } from '../common/type-common'
import type {
  CustomError,
  GenericObject,
  MessageAnnotation,
  TopicAnnotation,
  ReactNavigation,
  GenericStringObject,
  ResetAction,
  ImageSource,
  NotificationPayload,
} from '../common/type-common'
import type {
  ClaimProofNavigation,
  Attribute,
  NotificationPayloadInfo,
} from '../push-notification/type-push-notification'
import type { Proof, RequestedAttrsJson } from '../proof/type-proof'
import type { ClaimMap } from '../claim/type-claim'

export type RequestedAttribute = {|
  name: string,
|}
export type RequestedPredicates = {
  attr_name: string,
  p_type: string,
  value: number,
  schema_seq_no?: number,
  issuer_did?: string,
}

export type ProofRequestedAttributes = {
  +[string]: RequestedAttribute,
}

export type ProofRequestData = {
  nonce: string,
  name: string,
  version: string,
  requested_attributes: ProofRequestedAttributes,
  requested_predicates?: ?{
    +[string]: RequestedPredicates,
  },
}

export type ProofRequest = {
  '@topic': {
    mid: number,
    tid: number,
  },
  '@type': {
    name: string,
    version: string,
  },
  msg_ref_id: string,
  proof_request_data: ProofRequestData,
}

export type StringifiableProofRequest = {
  data: {
    agent_did: null,
    agent_vk: null,
    link_secret_alias: string,
    my_did: null,
    my_vk: null,
    proof: null,
    proof_request: ?ProofRequest,
    source_id: string,
    state: number,
    their_did: null,
    their_vk: null,
  },
  version: string,
}

export type ProofRequestPushPayload = {
  '@type': MessageAnnotation,
  '@topic': TopicAnnotation,
  intended_use?: string,
  proof_request_data: ProofRequestData,
  remoteName: string,
  proofHandle: number,
}

export type ProofApiData = {
  requested: {
    +[string]: Array<string>,
  },
  remoteDid: string,
  userPairwiseDid?: string,
  claim_proofs: {
    +[string]: Array<string>,
  },
  aggregated_proof: string,
}

export type AdditionalProofData = {
  name: string,
  version: string,
  requestedAttributes: Array<Attribute>,
}

export type AdditionalProofDataPayload = {
  data: AdditionalProofData,
  requester: {
    name: string,
  },
  originalProofRequestData: ProofRequestData,
  statusMsg?: string,
  proofHandle: number,
}

export type ProofRequestAttributeListProp = {
  list: Array<Attribute>,
  claimMap?: ?ClaimMap,
  missingAttributes: MissingAttributes | {},
  canEnablePrimaryAction: (
    canEnable: boolean,
    selfAttestedAttributes: GenericStringObject
  ) => void,
  disableUserInputs: boolean,
  userAvatarSource: ?ImageSource,
  updateSelectedClaims: (item: Attribute) => void,
}

export type ProofRequestAttributeListState = {
  [string]: string,
}

export type ProofModalState = {
  isVisible: boolean,
}

export type ProofModalProps = {
  proofStatus: ProofStatus,
  name: string,
  title: string,
  logoUrl: string,
  onContinue: () => void,
}

export type ProofRequestPayload = AdditionalProofDataPayload & {
  status: ProofRequestStatus,
  proofStatus: ProofStatus,
  uid: string,
  senderLogoUrl?: ?string,
  remotePairwiseDID: string,
  missingAttributes?: MissingAttributes,
  vcxSerializedProofRequest?: string,
}

export type ProofRequestProps = {
  isValid: boolean,
  data: AdditionalProofData,
  logoUrl: string,
  proofStatus: ProofStatus,
  originalProofRequestData: ProofRequestData,
  remotePairwiseDID: string,
  name: string,
  ignoreProofRequest: (uid: string) => void,
  rejectProofRequest: (uid: string) => void,
  acceptProofRequest: (uid: string) => void,
  proofRequestShown: (uid: string) => void,
  updateAttributeClaim: (requestedAttrsJson: RequestedAttrsJson) => void,
  getProof: (uid: string) => void,
  uid: string,
  proofGenerationError?: ?CustomError,
  claimMap?: ?ClaimMap,
  missingAttributes: MissingAttributes | {},
  userSelfAttestedAttributes: (
    selfAttestedAttributes: SelfAttestedAttributes,
    uid: string
  ) => void,
  userAvatarSource: ?ImageSource,
  proofRequestShowStart: (uid: string) => ProofRequestShowStartAction,
} & ReactNavigation

export type ProofRequestState = {
  allMissingAttributesFilled: boolean,
  generateProofClicked: boolean,
  selfAttestedAttributes: GenericStringObject,
  disableUserInputs: boolean,
  selectedClaims: RequestedAttrsJson,
  disableSendButton: boolean,
}

export const PROOF_REQUESTS = 'PROOF_REQUESTS'
export const PROOF_REQUEST_RECEIVED = 'PROOF_REQUEST_RECEIVED'
export type ProofRequestReceivedAction = {
  type: typeof PROOF_REQUEST_RECEIVED,
  payload: AdditionalProofDataPayload,
  payloadInfo: NotificationPayloadInfo,
}

export const PROOF_REQUEST_STATUS = {
  IDLE: 'IDLE',
  RECEIVED: 'RECEIVED',
  SHOWN: 'SHOWN',
  ACCEPTED: 'ACCEPTED',
  IGNORED: 'IGNORED',
  REJECTED: 'REJECTED',
}

export const PROOF_STATUS = {
  NONE: 'NONE',
  SENDING_PROOF: 'SENDING_PROOF',
  SEND_PROOF_FAIL: 'SEND_PROOF_FAIL',
  SEND_PROOF_SUCCESS: 'SEND_PROOF_SUCCESS',
}

export type ProofRequestStatus = $Keys<typeof PROOF_REQUEST_STATUS>
export type ProofStatus = $Keys<typeof PROOF_STATUS>

export const PROOF_REQUEST_SHOWN = 'PROOF_REQUEST_SHOWN'
export type ProofRequestShownAction = {
  type: typeof PROOF_REQUEST_SHOWN,
  uid: string,
}

export const SEND_PROOF_SUCCESS = 'SEND_PROOF_SUCCESS'
export type SendProofSuccessAction = {
  type: typeof SEND_PROOF_SUCCESS,
  uid: string,
}

export const HYDRATE_PROOF_REQUESTS = 'HYDRATE_PROOF_REQUESTS'
export type HydrateProofRequestsAction = {
  type: typeof HYDRATE_PROOF_REQUESTS,
  proofRequests: ProofRequestStore,
}

export const SEND_PROOF_FAIL = 'SEND_PROOF_FAIL'
export type SendProofFailAction = {
  type: typeof SEND_PROOF_FAIL,
  uid: string,
  error: CustomError,
}

export const SEND_PROOF = 'SEND_PROOF'
export type SendProofAction = {
  type: typeof SEND_PROOF,
  uid: string,
}

export const PROOF_REQUEST_IGNORED = 'PROOF_REQUEST_IGNORED'
export type ProofRequestIgnoredAction = {
  type: typeof PROOF_REQUEST_IGNORED,
  uid: string,
}

export const PROOF_REQUEST_REJECTED = 'PROOF_REQUEST_REJECTED'
export type ProofRequestRejectedAction = {
  type: typeof PROOF_REQUEST_REJECTED,
  uid: string,
}

export const PROOF_REQUEST_ACCEPTED = 'PROOF_REQUEST_ACCEPTED'
export type ProofRequestAcceptedAction = {
  type: typeof PROOF_REQUEST_ACCEPTED,
  uid: string,
}

export const PROOF_REQUEST_AUTO_FILL = 'PROOF_REQUEST_AUTO_FILL'
export type ProofRequestAutoFillAction = {
  type: typeof PROOF_REQUEST_AUTO_FILL,
  uid: string,
  requestedAttributes: Array<Attribute>,
}

export type MissingAttribute = {
  key: string,
  name: string,
}

export type SelfAttestedAttribute = {
  name: string,
  data: string,
  key: string,
}

export type SelfAttestedAttributes = {
  [attributeName: string]: SelfAttestedAttribute,
}

export type MissingAttributes = SelfAttestedAttributes

export type IndySelfAttested = GenericStringObject

export const MISSING_ATTRIBUTES_FOUND = 'MISSING_ATTRIBUTES_FOUND'
export type MissingAttributesFoundAction = {
  type: typeof MISSING_ATTRIBUTES_FOUND,
  missingAttributes: MissingAttributes,
  uid: string,
}

export type ProofRequestInitialAction = {
  type: typeof INITIAL_TEST_ACTION,
}

export const PROOF_SERIALIZED = 'PROOF_SERIALIZED'
export type ProofSerializedAction = {
  type: typeof PROOF_SERIALIZED,
  serializedProof: string,
  uid: string,
}

export const UPDATE_PROOF_HANDLE = 'UPDATE_PROOF_HANDLE'
export type UpdateProofHandleAction = {
  type: typeof UPDATE_PROOF_HANDLE,
  proofHandle: number,
  uid: string,
}

export const PROOF_REQUEST_SHOW_START = 'PROOF_REQUEST_SHOW_START'
export type ProofRequestShowStartAction = {
  type: typeof PROOF_REQUEST_SHOW_START,
  uid: string,
}

export type ProofRequestAction =
  | ProofRequestReceivedAction
  | SendProofSuccessAction
  | SendProofFailAction
  | SendProofAction
  | ProofRequestIgnoredAction
  | ProofRequestAcceptedAction
  | ProofRequestShownAction
  | ProofRequestInitialAction
  | ProofRequestRejectedAction
  | ProofRequestAutoFillAction
  | MissingAttributesFoundAction
  | ProofSerializedAction
  | UpdateProofHandleAction
  | ProofRequestShowStartAction
  | ResetAction

export type ProofRequestStore = {
  +[string]: ProofRequestPayload,
}

export const PRIMARY_ACTION_SEND = 'Send'
export const PRIMARY_ACTION_GENERATE_PROOF = 'Generate'
export const SECONDARY_ACTION_IGNORE = 'Ignore'

export const MESSAGE_MISSING_ATTRIBUTES_TITLE = 'Missing information'
export const MESSAGE_MISSING_ATTRIBUTES_DESCRIPTION = (
  connectionname: string
) =>
  `You don't have all the attributes ${connectionname} is asking you to share with them. Manually fill in the missing attributes and tap Generate.`

export const MESSAGE_ERROR_PROOF_GENERATION_TITLE = 'Error generating proof'
export const MESSAGE_ERROR_PROOF_GENERATION_DESCRIPTION = 'Please try again.'

export const ERROR_SEND_PROOF = (message: string) => ({
  code: 'PR-001',
  message: `Error sending proof: ${message}`,
})


<|start_filename|>app/wallet/wallet.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { Image, StyleSheet } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { scale } from 'react-native-size-matters'
import {
  Container,
  CustomView,
  CustomText,
  Icon,
  CustomHeader,
} from '../components'
import { walletRoute } from '../common'
import {
  color,
  isSmallWidthDevice,
  responsiveHorizontalPadding,
} from '../common/styles/constant'
import WalletBalance from './wallet-balance'
import WalletTabs from './wallet-tabs'
import type { WalletProps } from './type-wallet'
import styles from './styles'

const closeImage = require('../images/iconClose.png')
const sovrinLogo = require('../images/sovrinLogo.png')
const tokenLogo = require('../images/sovrinTokenWhite.png')

const walletTabsHeaderBalanceFontSize = (balance: string) => {
  /**
   * TODO:KS below logic to select size as per length is an ugly logic
   * adjustsFontSizeToFit is not working due to center alignment and no width
   * on parent container, we can't set width as well from Dimensions module
   * because there are other elements besides this which are taking up space
   * also, other elements width are not defined, so we can't calculate width as well
   * Even if we would have used adjustsFontSizeToFit, we can't control the scale
   * with which font size is reduced on Android, a scale factor is provided for ios
   * So, for now as a hack we are providing font by ourselves.
   * Normally, we would have preferred to just wrap the text, but we can't wrap it
   * because it is a number. Also, header is hard coded with a height
   */
  const digits = balance ? balance.length : 0
  switch (true) {
    case digits < 13:
      return scale(30)
    case digits < 16:
      return scale(25)
    case digits < 20:
      return scale(19)
    default:
      return scale(16)
  }
}

const walletTabsHeaderStyles = StyleSheet.create({
  outerContainer: {
    height: 120,
    paddingHorizontal: responsiveHorizontalPadding,
  },
  closeButtonContainer: { height: '100%', alignItems: 'flex-end', zIndex: 1 },
})
// sovrin currency logo beside the amount also needs to be scaled down
// this cannot be scaled down just one the basis of device
// because if wallet balance is just 5 or 6 characters, then font size
// for wallet balance will be big, so we want to scale this logo as well
// as per the size of wallet balance text as well
const sovrinTokenIconSize = (balanceLength: number) =>
  balanceLength > 14 && isSmallWidthDevice ? { small: true } : { medium: true }

export class Wallet extends PureComponent<WalletProps, void> {
  static navigationOptions = ({ navigation }) => ({
    // Makes it so that headerTitle is centered Android
    header: (
      <CustomHeader
        backgroundColor={color.actions.font.seventh}
        outerContainerStyles={walletTabsHeaderStyles.outerContainer}
        largeHeader
      >
        <Container />

        <WalletBalance
          render={(balance: string) => (
            <Container>
              <Container center>
                <Icon extraLarge src={sovrinLogo} />
              </Container>
              <CustomView row center>
                <Icon
                  {...sovrinTokenIconSize(balance ? balance.length : 0)}
                  src={tokenLogo}
                />
                <CustomView horizontalSpace>
                  <CustomText
                    medium
                    formatNumber
                    transparentBg
                    style={[
                      {
                        width: '100%',
                        fontSize: walletTabsHeaderBalanceFontSize(balance),
                      },
                    ]}
                  >
                    {balance}
                  </CustomText>
                </CustomView>
              </CustomView>
              <CustomView center>
                <CustomText h6 demiBold transparentBg uppercase>
                  current balance
                </CustomText>
              </CustomView>
            </Container>
          )}
        />

        <Container
          testID={'wallet-header-close'}
          style={[walletTabsHeaderStyles.closeButtonContainer]}
        >
          <Icon
            medium
            onPress={() => navigation.goBack(null)}
            testID="wallet-header-close-image"
            iconStyle={[styles.headerCloseIcon]}
            src={closeImage}
          />
        </Container>
      </CustomHeader>
    ),
    gesturesEnabled: true,
  })

  render() {
    return (
      <Container tertiary>
        <WalletTabs navigation={this.props.navigation} />
      </Container>
    )
  }
}

export default createStackNavigator({
  [walletRoute]: {
    screen: Wallet,
  },
})


<|start_filename|>app/push-notification/type-push-notification.js<|end_filename|>
// @flow

import type {
  CustomError,
  GenericObject,
  InitialTestAction,
  NavigationParams,
  ResetAction,
  NotificationPayload,
} from '../common/type-common'
import type { PendingRedirection } from '../lock/type-lock'
import type { Claim, ClaimVcx } from '../claim/type-claim'
import type { AdditionalProofDataPayload } from '../proof-request/type-proof-request'
import type { MatchingCredential } from '../proof/type-proof'

export const PUSH_NOTIFICATION_PERMISSION = 'PUSH_NOTIFICATION_PERMISSION'
export type PushNotificationPermissionAction = {
  type: typeof PUSH_NOTIFICATION_PERMISSION,
  isAllowed: boolean,
}

export const PUSH_NOTIFICATION_RECEIVED = 'PUSH_NOTIFICATION_RECEIVED'
export type PushNotificationReceivedAction = {
  type: typeof PUSH_NOTIFICATION_RECEIVED,
  notification: DownloadedNotification,
}

export const PUSH_NOTIFICATION_UPDATE_TOKEN = 'PUSH_NOTIFICATION_UPDATE_TOKEN'
export type PushNotificationUpdateTokenAction = {
  type: typeof PUSH_NOTIFICATION_UPDATE_TOKEN,
  token: string,
}

export const FETCH_ADDITIONAL_DATA = 'FETCH_ADDITIONAL_DATA'
export type FetchAdditionalDataAction = {
  type: typeof FETCH_ADDITIONAL_DATA,
  notificationPayload: NotificationPayload,
}

export const FETCH_ADDITIONAL_DATA_PENDING_KEYS =
  'FETCH_ADDITIONAL_DATA_PENDING_KEYS'
export type PendingSetFetchAdditionalDataAction = {
  type: typeof FETCH_ADDITIONAL_DATA_PENDING_KEYS,
  uid: string,
  forDID: string,
}

export const FETCH_ADDITIONAL_DATA_ERROR = 'FETCH_ADDITIONAL_DATA_ERROR'
export type FetchAdditionalDataErrorAction = {
  type: typeof FETCH_ADDITIONAL_DATA_ERROR,
  isPristine: boolean,
  isFetching: boolean,
  error: CustomError,
}

export type PushNotificationAction =
  | PushNotificationPermissionAction
  | PushNotificationReceivedAction
  | PushNotificationUpdateTokenAction
  | FetchAdditionalDataAction
  | FetchAdditionalDataErrorAction
  | InitialTestAction
  | HydratePushTokenAction
  | ResetAction
  | PendingSetFetchAdditionalDataAction

export type DownloadedNotification = {
  additionalData: GenericObject,
  type: string,
  uid: string,
  senderLogoUrl?: ?string,
  remotePairwiseDID: string,
  forDID: string,
}

export type PushNotificationStore = {
  isAllowed: boolean,
  notification: ?DownloadedNotification,
  pushToken: ?string,
  isPristine: boolean,
  isFetching: boolean,
  error: ?CustomError,
  pendingFetchAdditionalDataKey?: ?{
    [string]: boolean,
  },
  navigateRoute?: ?{
    routeName: string,
    params: GenericObject,
  },
}

export type AdditionalDataResponse = {
  statusCode: string,
  payload: string,
  type: string,
  uid: string,
  senderDID: string,
}

export type Attribute = {
  label: string,
  key?: string,
  data?: string,
  logoUrl?: string,
  claimUuid?: ?string,
  cred_info?: MatchingCredential,
}

export type AdditionalData = {
  name: string,
  version: string,
  revealedAttributes: Array<Attribute>,
  claimDefinitionSchemaSequenceNumber: number,
}

export type AdditionalDataPayload = {
  data: AdditionalData,
  issuer: {
    name: string,
    did: string,
  },
  statusMsg?: string,
  price?: ?string,
}

export type ClaimOfferPushPayload = {
  msg_type: string,
  version: string,
  to_did: string,
  from_did: string,
  iid?: string,
  mid?: string,
  claim: {
    name: Array<string>,
    date_of_birth: Array<string>,
    height: Array<string>,
  },
  claim_name: string,
  schema_seq_no: number,
  issuer_did: string,
  issuer_name?: string,
  nonce?: string,
  optional_data?: GenericObject,
  remoteName: string,
  price?: ?string,
}

export type ClaimOfferMessagePayload = {
  msg_type: string,
  version: string,
  to_did: string,
  from_did: string,
  cred_def_id: string,
  claim: {
    [string]: Array<string>,
  },
  claim_name: string,
  schema_seq_no: number,
  issuer_did: string,
  issuer_name?: string,
  remoteName?: string,
}

export type NotificationPayloadInfo = {
  uid: string,
  senderLogoUrl: ?string,
  remotePairwiseDID: string,
}

export type ClaimPushPayload = {
  msg_type: string,
  version: string,
  claim_offer_id: string,
  from_did: string,
  to_did: string,
  claim: {
    [string]: Array<string>,
  },
  schema_seq_no: number,
  issuer_did: string,
  signature: {
    primary_claim: {
      m2: string,
      a: string,
      e: string,
      v: string,
    },
    non_revocation_claim?: GenericObject,
  },
  optional_data?: GenericObject,
}

export type NextPropsPushNotificationNavigator = {
  pushNotification: {
    notification: DownloadedNotification,
    navigateRoute: ?{
      routeName: string,
      params: GenericObject,
    },
  },
  navigateToRoute: (routeName: string, params: NavigationParams) => void,
}

export type PairwiseIdentifyingInfo = {
  uid: string,
  senderLogoUrl?: ?string,
  remotePairwiseDID?: ?string,
}

export type PushNotificationNavigatorProps = {
  clearNavigateToRoutePN: () => void,
  updatePayloadToRelevantStoreAndRedirect: (
    notification: DownloadedNotification
  ) => void,
} & NextPropsPushNotificationNavigator

export type UiType = {
  uiType?: ?string,
}

export type RedirectToRelevantScreen = DownloadedNotification & UiType

export type ClaimProofNavigation = {
  goBack: () => void,
  state: {
    params: {
      uid: string,
    },
  },
}

export type PushNotificationProps = {
  fetchAdditionalData: NotificationPayload => void,
  pushNotificationPermissionAction: boolean => void,
  updatePushToken: string => void,
  navigateToRoute: (routeName: string, params: NavigationParams) => void,
  isAllowed: boolean,
  pushToken?: string,
}

export const HYDRATE_PUSH_TOKEN = 'HYDRATE_PUSH_TOKEN'
export type HydratePushTokenAction = {
  type: typeof HYDRATE_PUSH_TOKEN,
  token: string,
}
export const UPDATE_RELEVANT_PUSH_PAYLOAD_STORE_AND_REDIRECT =
  'UPDATE_RELEVANT_PUSH_PAYLOAD_STORE_AND_REDIRECT'
export type updatePayloadToRelevantStoreAndRedirectAction = {
  type: typeof UPDATE_RELEVANT_PUSH_PAYLOAD_STORE_AND_REDIRECT,
  notification: DownloadedNotification,
}
export const UPDATE_RELEVANT_PUSH_PAYLOAD_STORE =
  'UPDATE_RELEVANT_PUSH_PAYLOAD_STORE'
export type updatePayloadToRelevantStoreAction = {
  type: typeof UPDATE_RELEVANT_PUSH_PAYLOAD_STORE,
  notification: DownloadedNotification,
}


<|start_filename|>android/app/src/main/java/me/connect/rnindy/RNIndyModule.java<|end_filename|>
//  Created by react-native-create-bridge

package me.connect.rnindy;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Environment;
import android.support.v7.graphics.Palette;
import android.util.Base64;
import android.util.Log;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.content.Context;
import android.content.ContextWrapper;

import me.connect.BridgeUtils;
import com.evernym.sdk.vcx.VcxException;
import com.evernym.sdk.vcx.wallet.WalletApi;
import com.evernym.sdk.vcx.connection.ConnectionApi;
import com.evernym.sdk.vcx.credential.CredentialApi;
import com.evernym.sdk.vcx.credential.GetCredentialCreateMsgidResult;
import com.evernym.sdk.vcx.proof.CreateProofMsgIdResult;
import com.evernym.sdk.vcx.proof.DisclosedProofApi;
import com.evernym.sdk.vcx.proof.ProofApi;
import com.evernym.sdk.vcx.token.TokenApi;
import com.evernym.sdk.vcx.utils.UtilsApi;
import com.evernym.sdk.vcx.vcx.AlreadyInitializedException;
import com.evernym.sdk.vcx.vcx.VcxApi;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import android.net.Uri;
import java.io.InputStream;
import java.lang.Long;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;

public class RNIndyModule extends ReactContextBaseJavaModule {
    public static final String REACT_CLASS = "RNIndy";
    public static final String TAG = "RNIndy::";
    private static final int BUFFER = 2048;
    private static ReactApplicationContext reactContext = null;
    // TODO:Remove this class once integration with vcx is done
    private static RNIndyStaticData staticData = new RNIndyStaticData();

    public RNIndyModule(ReactApplicationContext context) {
        // Pass in the context to the constructor and save it so you can emit events
        // https://facebook.github.io/react-native/docs/native-modules-android.html#the-toast-module
        super(context);

        reactContext = context;
    }

    @Override
    public String getName() {
        // Tell React the name of the module
        // https://facebook.github.io/react-native/docs/native-modules-android.html#the-toast-module
        return REACT_CLASS;
    }

    @ReactMethod
    public void createOneTimeInfo(String agencyConfig, Promise promise) {
        Log.d(TAG, "createOneTimeInfo() called with: agencyConfig = [" + agencyConfig + "]");
        // We have top create thew ca cert for the openssl to work properly on android
        BridgeUtils.writeCACert(this.getReactApplicationContext());

        try {
            UtilsApi.vcxAgentProvisionAsync(agencyConfig).exceptionally((t) -> {
                Log.e(TAG, "createOneTimeInfo: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                Log.d(TAG, "vcx::APP::async result Prov: " + result);
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void getGenesisPathWithConfig(String poolConfig, String fileName, Promise promise) {
        Log.d(TAG, "getGenesisPathWithConfig() called with: poolConfig = [" + poolConfig + "], promise = [" + promise
                + "]");
        ContextWrapper cw = new ContextWrapper(reactContext);
        File genFile = new File(cw.getFilesDir().toString() + "/genesis_" + fileName + ".txn");
        if (genFile.exists()) {
            genFile.delete();
        }

        try (FileOutputStream fos = new FileOutputStream(genFile)) {
            fos.write(poolConfig.getBytes());
            promise.resolve(genFile.getAbsolutePath());
        } catch (IOException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void init(String config, Promise promise) {
        Log.d(TAG, " ==> init() called with: config = [" + config + "], promise = [" + promise + "]");
        // When we restore data, then we are not calling createOneTimeInfo
        // and hence ca-crt is not written within app directory
        // since the logic to write ca cert checks for file existence
        // we won't have to pay too much cost for calling this function inside init
        BridgeUtils.writeCACert(this.getReactApplicationContext());

        try {
            VcxApi.vcxInitWithConfig(config).exceptionally((t) -> {
                Log.e(TAG, "init: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                // Need to put this logic in every accept because that is how ugly Java's
                // promise API is
                // even if exceptionally is called, then also thenAccept block will be called
                // we either need to switch to complete method and pass two callbacks as
                // parameter
                // till we change to that API, we have to live with this IF condition
                // also reason to add this if condition is because we already rejected promise
                // in
                // exceptionally block, if we call promise.resolve now, then it `thenAccept`
                // block
                // would throw an exception that would not be caught here, because this is an
                // async
                // block and above try catch would not catch this exception
                if (result != -1) {
                    promise.resolve(true);
                }
            });

        } catch (AlreadyInitializedException e) {
            // even if we get already initialized exception
            // then also we will resolve promise, because we don't care if vcx is already
            // initialized
            promise.resolve(true);
        } catch (VcxException e) {
            e.printStackTrace();
            promise.reject(e);
        }
    }

    @ReactMethod
    public void createConnectionWithInvite(String invitationId, String inviteDetails, Promise promise) {
        Log.d(TAG, "createConnectionWithInvite() called with: invitationId = [" + invitationId + "], inviteDetails = ["
                + inviteDetails + "], promise = [" + promise + "]");
        try {
            ConnectionApi.vcxCreateConnectionWithInvite(invitationId, inviteDetails).exceptionally((t) -> {
                Log.e(TAG, "createConnectionWithInvite: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });

        } catch (Exception e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void vcxAcceptInvitation(int connectionHandle, String connectionType, Promise promise) {
        Log.d(TAG, "acceptInvitation() called with: connectionHandle = [" + connectionHandle + "], connectionType = ["
                + connectionType + "], promise = [" + promise + "]");
        try {
            ConnectionApi.vcxAcceptInvitation(connectionHandle, connectionType).exceptionally((t) -> {
                Log.e(TAG, "vcxAcceptInvitation: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> BridgeUtils.resolveIfValid(promise, result));
        } catch (VcxException e) {
            e.printStackTrace();
            promise.reject(e);
        }
    }

    @ReactMethod
    public void vcxUpdatePushToken(String config, Promise promise) {
        try {
            UtilsApi.vcxUpdateAgentInfo(config).exceptionally((t) -> {
                Log.e(TAG, "vcxUpdatePushToken: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            e.printStackTrace();
            promise.reject(e);
        }
    }

    @ReactMethod
    public void getMessage(String url, String requestId, String myPairwiseDid, String myPairwiseVerKey,
            String myPairwiseAgentDid, String myPairwiseAgentVerKey, String myOneTimeAgentDid,
            String myOneTimeAgentVerKey, String myOneTimeDid, String myOneTimeVerKey, String myAgencyVerKey,
            String poolConfig, Promise promise) {
        promise.resolve(staticData.getMessage());
    }

    @ReactMethod
    public void sendMessage(String url, String messageType, String messageReplyId, String message, String myPairwiseDid,
            String myPairwiseVerKey, String myPairwiseAgentDid, String myPairwiseAgentVerKey, String myOneTimeAgentDid,
            String myOneTimeAgentVerKey, String myOneTimeDid, String myOneTimeVerKey, String myAgencyVerKey,
            String myPairwisePeerVerKey, String poolConfig, Promise promise) {
        promise.resolve(true);
    }

    @ReactMethod
    public void generateClaimRequest(String remoteDid, String claimOffer, String poolConfig, Promise promise) {
        promise.resolve(staticData.generateClaimRequest());
    }

    @ReactMethod
    public void addClaim(String claim, String poolConfig, Promise promise) {
        promise.resolve("{}");
    }

    @ReactMethod
    public void getClaim(String filterJson, String poolConfig, Promise promise) {
        promise.resolve(staticData.getClaim());
    }

    @ReactMethod
    public void prepareProof(String proofRequest, String poolConfig, Promise promise) {
        promise.resolve("{}");
    }

    @ReactMethod
    public void generateProof(String proofRequestId, String requestedAttrs, String requestedPredicates,
            String proofName, Promise promise) {
        try {
            ProofApi.proofCreate(proofRequestId, requestedAttrs, requestedPredicates, proofName).exceptionally((t) -> {
                Log.e(TAG, "generateProof: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void getColor(String imagePath, final Promise promise) {
        Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
        Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
            @Override
            public void onGenerated(Palette palette) {
                try {
                    Palette.Swatch swatch = palette.getVibrantSwatch();
                    if (swatch == null) {
                        swatch = palette.getDarkVibrantSwatch();
                    }
                    if (swatch == null) {
                        swatch = palette.getLightVibrantSwatch();
                    }
                    if (swatch == null) {
                        swatch = palette.getMutedSwatch();
                    }
                    if (swatch == null) {
                        swatch = palette.getDarkMutedSwatch();
                    }
                    if (swatch == null) {
                        swatch = palette.getLightMutedSwatch();
                    }
                    if (swatch == null) {
                        swatch = palette.getDominantSwatch();
                    }
                    if (swatch == null) {
                        List<Palette.Swatch> swatchList = palette.getSwatches();
                        for (Palette.Swatch swatchItem : swatchList) {
                            if (swatchItem != null) {
                                swatch = swatchItem;
                                break;
                            }
                        }
                    }

                    int rgb = swatch.getRgb();
                    int r = Color.red(rgb);
                    int g = Color.green(rgb);
                    int b = Color.blue(rgb);
                    WritableArray colors = Arguments.createArray();
                    colors.pushString(String.valueOf(r));
                    colors.pushString(String.valueOf(g));
                    colors.pushString(String.valueOf(b));
                    // add a value for alpha factor
                    colors.pushString("1");
                    promise.resolve(colors);
                } catch (Exception e) {
                    promise.reject("No color", e);
                }
            }
        });
    }

    @ReactMethod
    public void reset(boolean reset, final Promise promise) {
        // TODO: call vcx_reset or vcx_shutdown if later is available
        // pass true to indicate that we delete both pool and wallet objects
        Timer t = new Timer();
        t.schedule(new TimerTask() {
            @Override
            public void run() {
                promise.resolve(true);
            }
        }, (long) (Math.random() * 1000));
    }

    @ReactMethod
    public void backupWallet(String documentDirectory, String encryptionKey, String agencyConfig, Promise promise) {
        // TODO: Remove this file, this is a dummy file, testing for backup the wallet
        String fileName = "backup.txt";
        File file = new File(documentDirectory, fileName);
        String contentToWrite = "Dummy Content";
        try (FileWriter fileWriter = new FileWriter(file)) {
            fileWriter.append(contentToWrite);
            fileWriter.flush();
        } catch (IOException e) {
            promise.reject(e);
        }

        // convert the file to zip
        String inputDir = documentDirectory + "/" + fileName;
        String zipPath = documentDirectory + "/backup.zip";
        try (FileOutputStream dest = new FileOutputStream(zipPath);
                ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
                FileInputStream fi = new FileInputStream(inputDir);
                BufferedInputStream origin = new BufferedInputStream(fi);) {
            byte data[] = new byte[BUFFER];
            // fileName will be the wallet filename
            ZipEntry entry = new ZipEntry(fileName);
            out.putNextEntry(entry);
            int count;
            while ((count = origin.read(data, 0, BUFFER)) != -1) {
                out.write(data, 0, count);
            }
            out.closeEntry();
            promise.resolve(zipPath);
        } catch (IOException e) {
            promise.reject(e);
        }
    }

    @ReactMethod
    public void getSerializedConnection(int connectionHandle, Promise promise) {
        // TODO:KS call vcx_connection_serialize and pass connectionHandle
        try {
            ConnectionApi.connectionSerialize(connectionHandle).exceptionally((t) -> {
                Log.e(TAG, "getSerializedConnection: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void deserializeConnection(String serializedConnection, Promise promise) {
        // TODO call vcx_connection_deserialize and pass serializedConnection
        // it would return an error code and an integer connection handle in callback
        try {
            ConnectionApi.connectionDeserialize(serializedConnection).exceptionally((t) -> {
                Log.e(TAG, "deserializeConnection: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void credentialCreateWithMsgId(String sourceId, int connectionHandle, String messageId, Promise promise) {
        // TODO call vcx_credential_create_with_msgid
        // pass sourceId, connectionHandle, & messageId
        // it would return an error code, an integer credential handle, a json string of
        // credential offer in callback
        // notice that we are returning a Map from here, not string or error code
        // JavaScript layer is expecting a map with two keys defined below
        // with one as an integer and another as json string of claim offer received
        // from vcx

        try {
            CredentialApi.credentialCreateWithMsgid(sourceId, connectionHandle, messageId).exceptionally((t) -> {
                Log.e(TAG, "credentialCreateWithMsgId: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                GetCredentialCreateMsgidResult typedResult = (GetCredentialCreateMsgidResult) result;
                WritableMap vcxCredentialCreateResult = Arguments.createMap();
                vcxCredentialCreateResult.putInt("credential_handle", typedResult.getCredential_handle());
                vcxCredentialCreateResult.putString("credential_offer", typedResult.getOffer());
                BridgeUtils.resolveIfValid(promise, vcxCredentialCreateResult);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }

    }

    @ReactMethod
    public void serializeClaimOffer(int credentialHandle, Promise promise) {
        // it would return error code, json string of credential inside callback

        try {
            CredentialApi.credentialSerialize(credentialHandle).exceptionally((t) -> {
                Log.e(TAG, "serializeClaimOffer: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }

    }

    @ReactMethod
    public void deserializeClaimOffer(String serializedCredential, Promise promise) {
        // it would return an error code and an integer credential handle in callback

        try {
            CredentialApi.credentialDeserialize(serializedCredential).exceptionally((t) -> {
                Log.e(TAG, "deserializeClaimOffer: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void sendClaimRequest(int credentialHandle, int connectionHandle, int paymentHandle, Promise promise) {
        // it would return an error code in callback
        // we resolve promise with an empty string after success
        // or reject promise with error code

        try {
            CredentialApi.credentialSendRequest(credentialHandle, connectionHandle, paymentHandle)
                    .exceptionally((t) -> {
                        Log.e(TAG, "sendClaimRequest: ", t);
                        promise.reject("FutureException", t.getMessage());
                        return null;
                    }).thenAccept(result -> {
                        BridgeUtils.resolveIfValid(promise, result);
                    });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void updateClaimOfferState(int credentialHandle, Promise promise) {
        try {
            CredentialApi.credentialUpdateState(credentialHandle).exceptionally((t) -> {
                Log.e(TAG, "updateClaimOfferState: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void getClaimOfferState(int credentialHandle, Promise promise) {
        try {
            CredentialApi.credentialGetState(credentialHandle).exceptionally((t) -> {
                Log.e(TAG, "getClaimOfferState: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void getClaimVcx(int credentialHandle, Promise promise) {
        try {
            CredentialApi.getCredential(credentialHandle).exceptionally((t) -> {
                Log.e(TAG, "getClaimVcx: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void exportWallet(String exportPath, String encryptionKey, Promise promise) {
        Log.d(TAG, "exportWallet() called with: exportPath = [" + exportPath + "], encryptionKey = [" + encryptionKey
                + "], promise = [" + promise + "]");
        try {
            WalletApi.exportWallet(exportPath, encryptionKey).exceptionally((t) -> {
                Log.e(TAG, "exportWallet: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if(result != -1){
                   BridgeUtils.resolveIfValid(promise, result);
                }
            });


        } catch (Exception e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void decryptWalletFile(String config, Promise promise) {
        try {
            WalletApi.importWallet(config).exceptionally((t) -> {
                Log.e(TAG, "importWallet: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (Exception e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void copyToPath(String uri, String zipPath, Promise promise) {

        InputStream input = null;
        BufferedOutputStream output = null;
        try {

            input = reactContext.getContentResolver().openInputStream(Uri.parse(uri));
            output = new BufferedOutputStream(new FileOutputStream(zipPath));

            {
                byte data[] = new byte[BUFFER];
                int count;
                while ((count = input.read(data, 0, BUFFER)) != -1) {
                    output.write(data, 0, count);
                }
                input.close();
                output.close();
                promise.resolve(zipPath);
            }
        }

        catch (IOException e) {
            promise.reject("copyToPathException", e.getMessage());
            e.printStackTrace();
        }
    }

    @ReactMethod
    public void setWalletItem(String key, String value, Promise promise) {
        try {
            WalletApi.addRecordWallet("record_type", key, value).exceptionally((t) -> {
                Log.e(TAG, "setWalletItem: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VcxException", e.getMessage());
        }
    }

    @ReactMethod
    public void getWalletItem(String key, Promise promise) {
        try {
            WalletApi.getRecordWallet("record_type", key, "").exceptionally((t) -> {
                Log.e(TAG, "getWalletItem: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VcxException", e.getMessage());
        }
    }

    @ReactMethod
    public void deleteWalletItem(String key, Promise promise) {
        try {
            WalletApi.deleteRecordWallet("record_type", key).exceptionally((t) -> {
                Log.e(TAG, "deleteWalletItem: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VcxException", e.getMessage());
        }
    }

    @ReactMethod
    public void updateWalletItem(String key, String value, Promise promise) {
        try {
            WalletApi.updateRecordWallet("record_type", key, value).exceptionally((t) -> {
                Log.e(TAG, "updateWalletItem: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VcxException", e.getMessage());
        }
    }

    @ReactMethod
    public void exitAppAndroid() {
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    @ReactMethod
    public void proofCreateWithMsgId(String sourceId, int connectionHandle, String messageId, Promise promise) {
        try {
            DisclosedProofApi.proofCreateWithMsgId(sourceId, connectionHandle, messageId).exceptionally((t) -> {
                Log.e(TAG, "proofCreateWithMsgId: ", t);
                promise.reject("FutureException: ", t.getMessage());
                return null;
            }).thenAccept(result -> {
                if (result != null) {
                    CreateProofMsgIdResult typedResult = (CreateProofMsgIdResult) result;
                    WritableMap vcxProofCreateResult = Arguments.createMap();
                    vcxProofCreateResult.putInt("proofHandle", typedResult.proofHandle);
                    vcxProofCreateResult.putString("proofRequest", typedResult.proofRequest);
                    BridgeUtils.resolveIfValid(promise, vcxProofCreateResult);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void proofRetrieveCredentials(int proofHandle, Promise promise) {
        try {
            DisclosedProofApi.proofRetrieveCredentials(proofHandle).exceptionally((t) -> {
                Log.e(TAG, "proofRetrieveCredentials: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void proofGenerate(int proofHandle, String selectedCredentials, String selfAttestedAttributes,
            Promise promise) {
        try {
            DisclosedProofApi.proofGenerate(proofHandle, selectedCredentials, selfAttestedAttributes)
                    .exceptionally((t) -> {
                        Log.e(TAG, "proofGenerate: ", t);
                        promise.reject("FutureException", t.getMessage());
                        return -1;
                    }).thenAccept(result -> {
                        if (result != -1) {
                            BridgeUtils.resolveIfValid(promise, result);
                        }
                    });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void proofSend(int proofHandle, int connectionHandle, Promise promise) {
        try {
            DisclosedProofApi.proofSend(proofHandle, connectionHandle).exceptionally((t) -> {
                Log.e(TAG, "proofSend: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void shutdownVcx(Boolean deleteWallet, Promise promise) {
        Log.d(TAG, " ==> shutdownVcx() called with: deleteWallet = [" + deleteWallet);
        try {
            VcxApi.vcxShutdown(deleteWallet);
            promise.resolve("");
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void getTokenInfo(int paymentHandle, Promise promise) {
        try {
            TokenApi.getTokenInfo(paymentHandle).exceptionally((t) -> {
                Log.e(TAG, "getTokenInfo: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void sendTokens(int paymentHandle, String tokens, String recipient, Promise promise) {
        try {
            TokenApi.sendTokens(paymentHandle, tokens, recipient).exceptionally((t) -> {
                Log.e(TAG, "sendTokens: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void createPaymentAddress(String seed, Promise promise) {
        try {
            TokenApi.createPaymentAddress(seed).exceptionally((t) -> {
                Log.e(TAG, "createPaymentAddress: ", t);
                promise.reject("FutureException", t.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void deleteConnection(int connectionHandle, Promise promise) {
        try {
            ConnectionApi.deleteConnection(connectionHandle).exceptionally((t) -> {
                Log.e(TAG, "deleteConnection: ", t);
                promise.reject("FutureException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch (VcxException e) {
            promise.reject("VCXException", e.getMessage());
        }
    }

    @ReactMethod
    public void downloadMessages(String messageStatus, String uid_s, String pwdids, Promise promise) {
      Log.d(TAG, "downloadMessages() called with: messageStatus = [ " + messageStatus + "] , uid_s =[" + uid_s
          + "] and pwdids =[ " + pwdids);
      try {
        UtilsApi.vcxGetMessages(messageStatus, uid_s, pwdids).exceptionally((t) -> {
          Log.d(TAG, "downloadMessages: ", t);
          promise.reject("FutureException", t.getMessage());
          return null;
        }).thenAccept(result -> BridgeUtils.resolveIfValid(promise, result));

      } catch (VcxException e) {
        promise.reject("VCXException", e.getMessage());
      }
    }

    @ReactMethod
    public void updateMessages(String messageStatus, String pwdidsJson, Promise promise) {
      Log.d(TAG, "updateMessages() called with messageStatus = [ " + messageStatus + "], pwdidJson = [" + pwdidsJson);

      try {
        UtilsApi.vcxUpdateMessages(messageStatus, pwdidsJson).exceptionally((t) -> {
          Log.d(TAG, "updateMessages: ", t);
          promise.reject("FutureException", t.getMessage());
          return null;
        }).thenAccept(result -> BridgeUtils.resolveIfValid(promise, result));
      } catch (VcxException e) {
        promise.reject("FutureException", e.getMessage());
      }
    }

    @ReactMethod
    public void proofCreateWithRequest(String sourceId, String proofRequest, Promise promise) {
        Log.d(TAG, "proofCreateWithRequest() called with sourceId = ["+ sourceId +"], proofRequest =["+ proofRequest +"]");

        try {
            DisclosedProofApi.proofCreateWithRequest(sourceId, proofRequest).exceptionally((t)-> {
                Log.d(TAG, "proofCreateWithRequest", t);
                promise.reject("VcxException", t.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch(VcxException e) {
            promise.reject("VcxException", e.getMessage());
        }
    }

    @ReactMethod
    public void proofSerialize(int proofHandle, Promise promise) {
        Log.d(TAG, "proofSerialize() called with proofHandle = ["+ proofHandle +"]");
        try {
            DisclosedProofApi.proofSerialize(proofHandle).exceptionally((e) -> {
                Log.d(TAG, "proofSerialize", e);
                promise.reject("VcxException", e.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch(VcxException e) {
            promise.reject("VcxException", e.getMessage());
        }
    }

    @ReactMethod
    public void proofDeserialize(String serializedProof, Promise promise) {
        Log.d(TAG, "proofDeserialize() called with serializedProof = ["+ serializedProof +"]");

        try {
            DisclosedProofApi.proofDeserialize(serializedProof).exceptionally((e)-> {
                Log.d(TAG, "proofDeserialize", e);
                promise.reject("VcxException", e.getMessage());
                return -1;
            }).thenAccept(result -> {
                if (result != -1) {
                    BridgeUtils.resolveIfValid(promise, result);
                }
            });
        } catch(VcxException e) {
            promise.reject("VcxException", e.getMessage());
        }
    }

    @ReactMethod
    public void createWalletKey(int lengthOfKey, Promise promise) {
        try {
            SecureRandom random = new SecureRandom();
            byte bytes[] = new byte[lengthOfKey];
            random.nextBytes(bytes);
            promise.resolve(Base64.encodeToString(bytes, Base64.NO_WRAP));
        } catch(Exception e) {
            Log.e(TAG, "createWalletKey: ", e);
            promise.reject("Exception", e.getMessage());
        }
    }

    @ReactMethod
    public void getLedgerFees(Promise promise) {
        Log.d(TAG, "getLedgerFees()");

        try {
            UtilsApi.getLedgerFees().exceptionally((e)-> {
                Log.d(TAG, "getLedgerFees", e);
                promise.reject("VcxException", e.getMessage());
                return null;
            }).thenAccept(result -> {
                BridgeUtils.resolveIfValid(promise, result);
            });
        } catch(VcxException e) {
            Log.e(TAG, "createWalletKey: ", e);
            promise.reject("Exception", e.getMessage());
        }
    }

    @Override
    public @Nullable
    Map<String, Object> getConstants() {
    HashMap<String, Object> constants = new HashMap<String, Object>();
      ActivityManager actManager = (ActivityManager) reactContext.getSystemService(Context.ACTIVITY_SERVICE);
      MemoryInfo memInfo = new ActivityManager.MemoryInfo();
      actManager.getMemoryInfo(memInfo);
      constants.put("totalMemory", memInfo.totalMem);
      return constants;
    }
}


<|start_filename|>app/about-app/type-about-app.js<|end_filename|>
// @flow
import type { CustomError, ReactNavigation } from '../common/type-common'

export type AboutAppProps = {
  environmentName: string,
} & ReactNavigation

export type AboutAppListItemProps = {
  onPress: () => void,
  titleValue: string,
}


<|start_filename|>app/restore/restore.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { Image, StyleSheet, Dimensions, Platform } from 'react-native'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Container, CustomView, CustomText, CustomButton } from '../components'
import {
  isBiggerThanShortDevice,
  grey,
  venetianRed,
  cornFlowerBlue,
  white,
} from '../common/styles/constant'
import {
  lockSelectionRoute,
  restorePassphraseRoute,
  restoreRoute,
} from '../common'
import { DocumentPicker } from 'react-native-document-picker'
import RNFetchBlob from 'react-native-fetch-blob'
import { updateStatusBarTheme } from '../store/connections-store'
import type { RestoreProps } from './type-restore'

import { saveFileToAppDirectory } from './restore-store'
import { NavigationActions } from 'react-navigation'
import type { Store } from '../store/type-store'
import { RestoreStatus } from './type-restore'

export class RestoreStartScreen extends PureComponent<RestoreProps, void> {
  restoreBackup = () => {
    DocumentPicker.show(
      {
        filetype: [
          Platform.OS === 'android' ? 'application/zip' : 'public.zip-archive',
        ],
      },
      (error, res) => {
        if (res) {
          this.props.saveFileToAppDirectory(res)
        } else {
          //TODO handle else
          console.log('err', error)
        }
      }
    )
  }

  startFresh = () => {
    this.props.navigation.navigate(lockSelectionRoute)
  }

  componentDidUpdate(prevProps: RestoreProps) {
    if (
      this.props.restore.status !== prevProps.restore.status &&
      this.props.restore.status === RestoreStatus.fileSaved &&
      this.props.route === restoreRoute
    ) {
      this.props.navigation.navigate(restorePassphraseRoute)
    }
    let statusBarColor =
      this.props.restore.error && this.props.route === restoreRoute
        ? venetianRed
        : white
    this.props.updateStatusBarTheme(statusBarColor)
  }

  componentDidMount() {
    if (!this.props.restore.error) {
      this.props.updateStatusBarTheme(white)
    } else {
      this.props.updateStatusBarTheme(venetianRed)
    }
  }

  render() {
    //TODO set error to display screen in error mode
    const error =
      this.props.restore.status === RestoreStatus.failedStatus ||
      (this.props.restore.status === RestoreStatus.FILE_SAVE_ERROR &&
        this.props.restore.error)
    let restoreIcon = require('../images/logo_connectme.png')
    let restoreBackground = require('../images/wave2.png')
    let restoreButtonTitle = 'Restore From A Backup'
    let restoreButtonColor = cornFlowerBlue

    if (error) {
      restoreIcon = require('../images/alertRed.png')
      restoreBackground = require('../images/transparentBands2.png')
      restoreButtonTitle = 'Select A Different File'
      restoreButtonColor = venetianRed
    }
    return (
      <Container
        safeArea
        testID={'restore-container'}
        style={[
          error ? styles.restoreErrorContainer : styles.restoreMainContainer,
        ]}
      >
        <Image
          source={restoreBackground}
          style={[styles.backgroundWaveImage]}
        />
        <Container testID={'restore-innercontainer'}>
          <CustomView center>
            <Image
              source={restoreIcon}
              style={[
                error ? styles.errorImageContainer : styles.imageContainer,
              ]}
            />
          </CustomView>

          {error ? (
            <CustomView center pad>
              <CustomText
                transparentBg
                style={[styles.errorText]}
                center
                medium
                h4a
                center
              >
                Either your passphrase was incorrect or the backup file you
                chose is corrupt or not a Connect.Me backup file. Please try
                again or start fresh.
              </CustomText>
            </CustomView>
          ) : null}
        </Container>
        <CustomView verticalSpace>
          {!error ? (
            <CustomView
              center
              doubleVerticalSpace
              style={[styles.textContainer]}
            >
              <CustomText
                transparentBg
                style={[styles.secondText, styles.textBox]}
                medium
                center
                h4a
              >
                Thanks for installing Connect.Me.
              </CustomText>
              <CustomText
                center
                transparentBg
                style={[styles.marginHorizontal, styles.textBox]}
                medium
                h4a
              >
                You can restore from a backup or start with a brand new install.
              </CustomText>
              <CustomText transparentBg style={[styles.textBox]} h4a medium>
                How would you like to proceed?
              </CustomText>
            </CustomView>
          ) : null}
          <CustomView pad>
            <CustomButton
              large={isBiggerThanShortDevice ? true : false}
              style={[styles.customButton, styles.buttonShadow]}
              title={restoreButtonTitle}
              onPress={this.restoreBackup}
              testID={'restore-from-backup'}
              customColor={{
                color: restoreButtonColor,
                fontWeight: '600',
              }}
            />
            <CustomButton
              large={isBiggerThanShortDevice ? true : false}
              style={[styles.customButton, styles.buttonShadow]}
              title={'Start Fresh'}
              onPress={this.startFresh}
              testID={'start-fresh'}
              customColor={{
                color: restoreButtonColor,
                fontWeight: '600',
              }}
            />
          </CustomView>
        </CustomView>
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  restoreMainContainer: {
    backgroundColor: white,
  },
  restoreErrorContainer: {
    backgroundColor: venetianRed,
  },
  backgroundWaveImage: {
    position: 'absolute',
    top: isBiggerThanShortDevice ? '30%' : '20%',
    left: 0,
    right: 0,
    resizeMode: 'stretch',
    width: '100%',
  },
  customButton: {
    width: '100%',
    height: isBiggerThanShortDevice ? 57 : 43,
    borderRadius: 5,
    marginTop: 10,
  },
  buttonShadow: {
    shadowColor: grey,
    shadowOffset: {
      width: 0,
      height: 5,
    },
    shadowRadius: 5,
    shadowOpacity: 0.3,
    elevation: 4,
  },
  imageContainer: {
    marginTop: isBiggerThanShortDevice ? '30%' : '20%',
    zIndex: -1,
  },
  errorImageContainer: {
    marginTop: '5%',
    zIndex: -1,
  },
  textContainer: {
    marginBottom: '10%',
  },
  secondText: {
    marginBottom: '6%',
  },
  errorText: {
    color: white,
    paddingLeft: '5%',
    paddingRight: '5%',
  },
  marginHorizontal: {
    marginLeft: '6%',
    marginRight: '6%',
    marginBottom: '6%',
  },
  textBox: {
    color: '#717171',
  },
})

const mapStateToProps = (state: Store) => {
  return {
    restore: state.restore,
    route: state.route.currentScreen,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators({ saveFileToAppDirectory, updateStatusBarTheme }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(RestoreStartScreen)


<|start_filename|>app/components/ledger-fees-modal/ledger-fees-modal.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Platform } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import Modal from 'react-native-modal'
import { BigNumber } from 'bignumber.js'
import type { Store } from '../../store/type-store'
import {
  getLedgerFees,
  resetLedgerFees,
} from '../../store/ledger/type-ledger-store'
import type {
  GetLedgerFeesFn,
  LedgerFees,
  ResetLedgerFeesFn,
} from '../../store/ledger/type-ledger-store'
import { formatNumbers } from '../text'
import { STORE_STATUS } from '../../common/type-common'
import type { StoreStatus } from '../../common/type-common'
import {
  CustomView,
  Icon,
  CustomText,
  CustomButton,
  Container,
  Loader,
} from '../../components'
import {
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_6X,
  OFFSET_7X,
  color,
  HAIRLINE_WIDTH,
  whiteSmoke,
} from '../../common/styles/constant'

export type LedgerFeesModalProps = {
  transferAmount?: string,
  onYes: () => void,
  onNo: () => void,
  getLedgerFees: GetLedgerFeesFn,
  resetLedgerFees: ResetLedgerFeesFn,
  ledgerFees: LedgerFees,
  isVisible: boolean,
  walletBalance: string,
  // Adding React.Node type as return type failing something entirely
  // different in flow definition, it seems like we need to properly fix fot React types
  renderFeesText?: (fees: string, status: LedgerFeesModalStatusEnum) => any,
}

const testID = 'ledger-fees'

export class LedgerFeesModalComponent extends PureComponent<
  LedgerFeesModalProps,
  void
> {
  onRetry = () => {
    this.props.getLedgerFees()
  }

  componentDidMount() {
    this.props.getLedgerFees()
  }

  componentDidUpdate(prevProps: LedgerFeesModalProps) {
    if (
      this.props.ledgerFees.status !== prevProps.ledgerFees.status &&
      this.props.ledgerFees.status === STORE_STATUS.SUCCESS &&
      this.props.ledgerFees.data.transfer === '0' &&
      this.props.isVisible === true
    ) {
      // if we got the fees successfully and it is zero, then auto close pop up
      // with Yes as action after user has read success text after 2 seconds
      setTimeout(this.props.onYes, 2000)
    }

    if (this.props.isVisible !== prevProps.isVisible) {
      if (this.props.isVisible === false) {
        this.props.resetLedgerFees()
      }

      if (this.props.isVisible === true) {
        this.props.getLedgerFees()
      }
    }
  }

  componentWillUnmount() {
    this.props.resetLedgerFees()
  }

  render() {
    const {
      transferAmount = null,
      isVisible,
      ledgerFees,
      onNo,
      onYes,
      walletBalance,
      renderFeesText,
    } = this.props
    const { data, error, status } = ledgerFees
    const feesModalStatus = getLedgerFeesModalStatus(
      data.transfer,
      status,
      walletBalance,
      transferAmount
    )
    const ledgerFeesText = getLedgerFeesText(
      data.transfer,
      feesModalStatus,
      walletBalance,
      transferAmount
    )
    // if consumer of this component wants to handle
    // rendering of text differently, then that consumer
    // can pass it's own description text rendering function
    let consumerLedgerFeesText = null
    if (renderFeesText) {
      consumerLedgerFeesText = renderFeesText(data.transfer, feesModalStatus)
    }
    const isSuccess = status === STORE_STATUS.SUCCESS

    return (
      <CustomView fifth shadow style={[styles.container]}>
        <CustomView spaceBetween style={[styles.innerContainer]}>
          <LedgerFeesModalIcon status={status} />
          {isSuccess && (
            <CustomText
              h3
              center
              tertiary
              bg="tertiary"
              transparentBg
              style={[styles.message]}
              bold
              testID={`${testID}-modal-title`}
            >
              {formatNumbers(data.transfer)}
            </CustomText>
          )}
          {isSuccess && (
            <CustomText
              h4
              center
              tertiary
              bg="tertiary"
              transparentBg
              style={[styles.message]}
              bold
              testID={`${testID}-modal-title`}
            >
              {'Transaction fee'}
            </CustomText>
          )}
          {/*
            if consumer of component has handled text rendering,
            then this component will not render it's own description text
          */}
          {consumerLedgerFeesText || ledgerFeesText}
        </CustomView>
        <ActionButtons
          status={feesModalStatus}
          onYes={onYes}
          onNo={onNo}
          onRetry={this.onRetry}
          fees={data.transfer}
        />
      </CustomView>
    )
  }
}

const mapStateToProps = (state: Store) => ({
  ledgerFees: state.ledger.fees,
  walletBalance: state.wallet.walletBalance.data,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators({ getLedgerFees, resetLedgerFees }, dispatch)

export const LedgerFeesModal = connect(mapStateToProps, mapDispatchToProps)(
  LedgerFeesModalComponent
)

export const LedgerFeesDescriptionText = (props: {
  children: any,
  bold?: boolean,
}) => (
  <CustomText
    h5
    center
    tertiary
    bg="tertiary"
    transparentBg
    style={[styles.message]}
    testID={`${testID}-modal-content`}
    bold={props.bold}
  >
    {props.children}
  </CustomText>
)

const zeroAmount = new BigNumber('0')
const TEXT_LEDGER_FEES_FETCH_ERROR = (
  <LedgerFeesDescriptionText>
    There was a problem checking transaction fees. Retry?
  </LedgerFeesDescriptionText>
)

const TEXT_LEDGER_FEES_FETCHING = (
  <LedgerFeesDescriptionText>Getting fees...</LedgerFeesDescriptionText>
)

const TEXT_NO_LEDGER_FEES = (
  <LedgerFeesDescriptionText>
    No fees for this transaction. Transferring tokens...
  </LedgerFeesDescriptionText>
)

const TEXT_LEDGER_FEES = (fees: string) => (
  <LedgerFeesDescriptionText>
    This transaction will cost you{' '}
    <LedgerFeesDescriptionText bold={true}>
      {formatNumbers(fees)}
    </LedgerFeesDescriptionText>{' '}
    Sovrin Tokens. Do you wish to continue?
  </LedgerFeesDescriptionText>
)

const TEXT_AMOUNT_AFTER_FEES_DEDUCTION = (fees: string, transfer: ?string) => {
  const feesAmount = new BigNumber(fees)
  const transferAmount = new BigNumber(transfer || '0')
  const amountAfterFeesDeduction = transferAmount
    .minus(feesAmount)
    .toFixed()
    .toString()

  return (
    <LedgerFeesDescriptionText>
      The recipient will receive{' '}
      <LedgerFeesDescriptionText bold={true}>
        {amountAfterFeesDeduction}
      </LedgerFeesDescriptionText>{' '}
      after the transaction fee. Proceed?
    </LedgerFeesDescriptionText>
  )
}

const TEXT_TRANSFER_LESS_THAN_EQUAL_TO_ZERO = (
  <LedgerFeesDescriptionText>
    You do not have enough tokens to pay the transaction fee.
  </LedgerFeesDescriptionText>
)

export const LedgerFeesModalStatus = {
  IN_PROGRESS: 'IN_PROGRESS',
  ERROR: 'ERROR',
  ZERO_FEES: 'ZERO_FEES',
  TRANSFER_EQUAL_TO_BALANCE: 'TRANSFER_EQUAL_TO_BALANCE',
  TRANSFER_POSSIBLE_WITH_FEES: 'TRANSFER_POSSIBLE_WITH_FEES',
  TRANSFER_NOT_POSSIBLE_WITH_FEES: 'TRANSFER_NOT_POSSIBLE_WITH_FEES',
}

export type LedgerFeesModalStatusEnum = $Keys<typeof LedgerFeesModalStatus>

const getLedgerFeesModalStatus = (
  fees: string,
  status: $PropertyType<StoreStatus, 'status'>,
  walletBalance: string,
  transfer: ?string
): LedgerFeesModalStatusEnum => {
  switch (status) {
    case STORE_STATUS.IDLE:
    case STORE_STATUS.IN_PROGRESS:
      return LedgerFeesModalStatus.IN_PROGRESS

    case STORE_STATUS.SUCCESS: {
      // we can get the success, but it might happen that fees is zero
      const feesAmount = new BigNumber(fees)
      if (feesAmount.isGreaterThan(zeroAmount)) {
        if (!transfer) {
          // if consumer of this component has not passed any transfer amount
          // then we don't need to perform any calculation for that amount
          // also, we will show regular transaction message
          return LedgerFeesModalStatus.TRANSFER_POSSIBLE_WITH_FEES
        }

        const walletBalanceAmount = new BigNumber(walletBalance)
        const transferAmount = new BigNumber(transfer || '0')

        if (walletBalanceAmount.isEqualTo(transferAmount)) {
          // if amount that we want to transfer is equal to wallet balance
          // and there is a fees that we have to pay
          // there can be two scenarios
          // 1. transferFees is greater than transferAmount
          // 2. transferFees is equal to transferAmount
          // 3. transferFees is less than transferAmount

          // for scenario 1, we can't transfer amount
          2 // because fees is more than what we have in wallet, also user is trying
          // to transfer same amount, but this transaction cannot be done
          if (transferAmount.minus(feesAmount).isLessThanOrEqualTo(0)) {
            return LedgerFeesModalStatus.TRANSFER_NOT_POSSIBLE_WITH_FEES
          }

          // for scenario 3, we can go with below approach and show amount
          // that will be transferred after deducting fees
          return LedgerFeesModalStatus.TRANSFER_EQUAL_TO_BALANCE
        }

        if (walletBalanceAmount.isLessThan(transferAmount.plus(feesAmount))) {
          // if wallet does not enough balance to pay for transfer amount and fees
          // then we need to tell user that this transaction cannot be done
          return LedgerFeesModalStatus.TRANSFER_NOT_POSSIBLE_WITH_FEES
        }

        return LedgerFeesModalStatus.TRANSFER_POSSIBLE_WITH_FEES
      }

      return LedgerFeesModalStatus.ZERO_FEES
    }

    case STORE_STATUS.ERROR:
    default:
      return LedgerFeesModalStatus.ERROR
  }
}

const getLedgerFeesText = (
  fees: string,
  status: LedgerFeesModalStatusEnum,
  walletBalance: string,
  transfer: ?string
) => {
  switch (status) {
    case LedgerFeesModalStatus.IN_PROGRESS:
      return TEXT_LEDGER_FEES_FETCHING

    case LedgerFeesModalStatus.ZERO_FEES:
      return TEXT_NO_LEDGER_FEES

    case LedgerFeesModalStatus.TRANSFER_EQUAL_TO_BALANCE:
      return TEXT_AMOUNT_AFTER_FEES_DEDUCTION(fees, transfer)

    case LedgerFeesModalStatus.TRANSFER_POSSIBLE_WITH_FEES:
      return TEXT_LEDGER_FEES(fees)

    case LedgerFeesModalStatus.TRANSFER_NOT_POSSIBLE_WITH_FEES:
      return TEXT_TRANSFER_LESS_THAN_EQUAL_TO_ZERO

    case LedgerFeesModalStatus.ERROR:
    default:
      return TEXT_LEDGER_FEES_FETCH_ERROR
  }
}

const alertIcon = require('../../images/alertInfo.png')
const sovrinIconOrange = require('../../images/iconTokenOrange.png')

const SovrinIcon = ({ icon }: *) => (
  <Icon
    iconStyle={[styles.icon]}
    src={icon}
    medium
    center
    resizeMode="contain"
    testID={`${testID}-modal-header-icon`}
  />
)

const LedgerFeesModalIcon = ({ status }: *) => {
  switch (status) {
    case STORE_STATUS.IDLE:
    case STORE_STATUS.IN_PROGRESS:
      return LoaderComponent

    case STORE_STATUS.SUCCESS:
      return <SovrinIcon icon={sovrinIconOrange} />

    case STORE_STATUS.ERROR:
    default:
      return <SovrinIcon icon={alertIcon} />
  }
}

const LedgerFeesModalActionButton = ({ onPress, title }: *) => (
  <Container>
    <CustomButton
      fifth
      onPress={onPress}
      title={title}
      testID={`${testID}-modal-${title}`}
      textStyle={styles.actionButton}
    />
  </Container>
)

const ActionButtons = ({ status, fees, onYes, onNo, onRetry }: *) => {
  switch (status) {
    case LedgerFeesModalStatus.IN_PROGRESS:
    case LedgerFeesModalStatus.ZERO_FEES:
      return null

    case LedgerFeesModalStatus.TRANSFER_NOT_POSSIBLE_WITH_FEES:
      return (
        <CustomView row>
          <LedgerFeesModalActionButton onPress={onNo} title={'Ok'} />
        </CustomView>
      )

    case LedgerFeesModalStatus.TRANSFER_EQUAL_TO_BALANCE:
    case LedgerFeesModalStatus.TRANSFER_POSSIBLE_WITH_FEES:
      return (
        <CustomView row>
          <LedgerFeesModalActionButton onPress={onNo} title={'No'} />
          <LedgerFeesModalActionButton onPress={onYes} title={'Yes'} />
        </CustomView>
      )

    case LedgerFeesModalStatus.ERROR:
    default:
      return (
        <CustomView row>
          <LedgerFeesModalActionButton onPress={onNo} title={'Cancel'} />
          <LedgerFeesModalActionButton onPress={onRetry} title={'Retry'} />
        </CustomView>
      )
  }
}

const styles = StyleSheet.create({
  container: {
    marginHorizontal: OFFSET_3X,
  },
  innerContainer: {
    ...Platform.select({
      ios: {
        borderBottomColor: color.bg.fifth.font.tertiary,
        borderBottomWidth: HAIRLINE_WIDTH,
      },
      android: {
        borderBottomColor: color.bg.fifth.font.secondary,
        borderBottomWidth: 1,
      },
    }),
    padding: OFFSET_2X,
  },
  message: {
    marginBottom: OFFSET_1X / 2,
  },
  icon: {
    margin: 10,
  },
  loaderContainer: {
    height: 40,
  },
  actionButton: {
    fontWeight: 'bold',
  },
})

const LoaderComponent = (
  <CustomView center style={[styles.loaderContainer]}>
    <Loader showMessage={false} />
  </CustomView>
)


<|start_filename|>app/lock/__tests__/lock-enter-fingerprint.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { LockEnterFingerprint } from '../lock-enter-fingerprint'
import { homeRoute, claimOfferRoute } from '../../common'
import {
  getNavigation,
  pendingRedirection,
  getStore,
} from '../../../__mocks__/static-data'

function props() {
  return {
    switchErrorAlerts: jest.fn(),
    clearPendingRedirect: jest.fn(),
    unlockApp: jest.fn(),
    pendingRedirection,
    isAppLocked: true,
    navigation: {
      ...getNavigation(),
    },
  }
}

const store = {
  getState() {
    return jest.fn()
  },
  subscribe() {
    return jest.fn()
  },
  dispatch() {
    return jest.fn()
  },
}

describe('app lock selection page should', () => {
  it('render properly', () => {
    const component = renderer.create(
      <Provider store={getStore()}>
        <LockEnterFingerprint {...props()} />
      </Provider>
    )
    let tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })

  it('in case of fetching invitation show message', () => {
    const component = renderer.create(
      <Provider store={getStore()}>
        <LockEnterFingerprint {...props()} isFetchingInvitation={true} />
      </Provider>
    )
    let LockEnterFingerprintInstance = component.root.findByType(
      LockEnterFingerprint
    ).instance
    LockEnterFingerprintInstance.setState({ authenticationSuccess: true })
    let tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/invitation/invitation-store.js<|end_filename|>
// @flow
import { Platform } from 'react-native'
import { put, takeLatest, call, all, select } from 'redux-saga/effects'
import {
  INVITATION_RECEIVED,
  INVITATION_RESPONSE_SEND,
  INVITATION_RESPONSE_SUCCESS,
  INVITATION_RESPONSE_FAIL,
  INVITATION_REJECTED,
  ERROR_INVITATION_VCX_INIT,
  ERROR_INVITATION_CONNECT,
} from './type-invitation'
import { ResponseType } from '../components/request/type-request'
import {
  ERROR_ALREADY_EXIST,
  ERROR_INVITATION_RESPONSE_PARSE_CODE,
  ERROR_INVITATION_RESPONSE_PARSE,
  SERVER_ERROR_CODE,
} from '../api/api-constants'
import {
  getAgencyUrl,
  getAgencyDID,
  getAgencyVerificationKey,
  getPushToken,
  getInvitationPayload,
  isDuplicateConnection,
  getUserOneTimeInfo,
  getPoolConfig,
} from '../store/store-selector'
import { saveNewConnection } from '../store/connections-store'
import {
  createConnectionWithInvite,
  acceptInvitationVcx,
  serializeConnection,
} from '../bridge/react-native-cxs/RNCxs'
import type {
  InvitationResponseSendData,
  InvitationResponseSendAction,
  InvitationPayload,
  InvitationStore,
  InvitationAction,
  InvitationReceivedActionData,
} from './type-invitation'
import type { CustomError } from '../common/type-common'
import { captureError } from '../services/error/error-handler'
import type {
  ConnectAgencyResponse,
  RegisterAgencyResponse,
  CreateOneTimeAgentResponse,
  CreatePairwiseAgentResponse,
  AcceptInvitationResponse,
} from '../bridge/react-native-cxs/type-cxs'
import type { UserOneTimeInfo } from '../store/user/type-user-store'
import { connectRegisterCreateAgentDone } from '../store/user/user-store'
import { RESET } from '../common/type-common'
import { ensureVcxInitSuccess } from '../store/config-store'
import { VCX_INIT_SUCCESS } from '../store/type-config-store'
import type { MyPairwiseInfo } from '../store/type-connection-store'
import { safeSet, safeGet } from '../services/storage'

export const invitationInitialState = {}

export const invitationReceived = (data: InvitationReceivedActionData) => ({
  type: INVITATION_RECEIVED,
  data,
})

export const sendInvitationResponse = (data: InvitationResponseSendData) => ({
  type: INVITATION_RESPONSE_SEND,
  data,
})

export const invitationSuccess = (senderDID: string) => ({
  type: INVITATION_RESPONSE_SUCCESS,
  senderDID,
})

export const invitationFail = (error: CustomError, senderDID: string) => ({
  type: INVITATION_RESPONSE_FAIL,
  error,
  senderDID,
})

export const invitationRejected = (senderDID: string) => ({
  type: INVITATION_REJECTED,
  senderDID,
})

export function* sendResponse(
  action: InvitationResponseSendAction
): Generator<*, *, *> {
  const { senderDID } = action.data

  try {
    const vcxResult = yield* ensureVcxInitSuccess()
    const alreadyExist: boolean = yield select(isDuplicateConnection, senderDID)
    if (alreadyExist) {
      yield put(invitationFail(ERROR_ALREADY_EXIST, senderDID))

      return
    }
    if (vcxResult && vcxResult.fail) {
      throw new Error(vcxResult.fail.message)
    }
    const payload: InvitationPayload = yield select(
      getInvitationPayload,
      senderDID
    )
    const connectionHandle: number = yield call(
      createConnectionWithInvite,
      payload
    )
    const pairwiseInfo: MyPairwiseInfo = yield call(
      acceptInvitationVcx,
      connectionHandle
    )

    yield put(invitationSuccess(senderDID))

    // once the connection is successful, we need to save serialized connection
    // in secure storage as well, because libIndy does not handle persistence
    // once we have persisted serialized state, we can hydrate vcx
    // if we need anything from that connection
    const vcxSerializedConnection: string = yield call(
      serializeConnection,
      connectionHandle
    )
    // TODO:KS Above call will probably interfere with showing bubbles as soon as user
    // is on home screen after accepting connection
    // there are few more things that we can do, but we are not doing those here for now

    const connection = {
      newConnection: {
        identifier: pairwiseInfo.myPairwiseDid,
        logoUrl: payload.senderLogoUrl,
        myPairwiseDid: pairwiseInfo.myPairwiseDid,
        myPairwiseVerKey: pairwiseInfo.myPairwiseVerKey,
        myPairwiseAgentDid: pairwiseInfo.myPairwiseAgentDid,
        myPairwiseAgentVerKey: pairwiseInfo.myPairwiseAgentVerKey,
        myPairwisePeerVerKey: pairwiseInfo.myPairwisePeerVerKey,
        vcxSerializedConnection,
        ...payload,
      },
    }
    yield put(saveNewConnection(connection))
  } catch (e) {
    captureError(e)
    yield put(invitationFail(ERROR_INVITATION_CONNECT(e.message), senderDID))
  }
}

function* watchSendInvitationResponse(): any {
  yield takeLatest(INVITATION_RESPONSE_SEND, sendResponse)
}

export function* watchInvitation(): any {
  yield all([watchSendInvitationResponse()])
}

export default function invitationReducer(
  state: InvitationStore = invitationInitialState,
  action: InvitationAction
) {
  switch (action.type) {
    case INVITATION_RECEIVED:
      return {
        ...state,
        [action.data.payload.senderDID]: {
          ...action.data,
          status: ResponseType.none,
          isFetching: false,
          error: null,
        },
      }

    case INVITATION_RESPONSE_SEND:
      return {
        ...state,
        [action.data.senderDID]: {
          ...state[action.data.senderDID],
          isFetching: true,
          status: action.data.response,
          error: null,
        },
      }

    case INVITATION_RESPONSE_SUCCESS:
      return {
        ...state,
        [action.senderDID]: {
          ...state[action.senderDID],
          isFetching: false,
          error: null,
        },
      }

    case INVITATION_RESPONSE_FAIL:
      return {
        ...state,
        [action.senderDID]: {
          ...state[action.senderDID],
          isFetching: false,
          error: action.error,
          status: ResponseType.none,
        },
      }

    case INVITATION_REJECTED:
      return {
        ...state,
        [action.senderDID]: {
          ...state[action.senderDID],
          isFetching: false,
          error: null,
          status: ResponseType.rejected,
        },
      }

    case RESET:
      return invitationInitialState

    default:
      return state
  }
}


<|start_filename|>app/wallet/wallet-tab-history.js<|end_filename|>
// @flow
import React, { Component } from 'react'
import { ScrollView, StyleSheet } from 'react-native'
import { connect } from 'react-redux'
import { List, ListItem } from 'react-native-elements'

import {
  Container,
  CustomView,
  Icon,
  CustomText,
  CustomDate,
  Loader,
} from '../components'
import { color, OFFSET_1X, OFFSET_3X } from '../common/styles/constant'
import type { Store } from '../store/type-store'
import type { WalletHistoryProps, WalletHistoryEvent } from './type-wallet'
import { getWalletHistory } from '../store/store-selector'
import { refreshWalletHistory } from './wallet-store'
import { bindActionCreators } from 'redux'
import { STORE_STATUS } from './type-wallet'

const HistoryItem = ({
  senderName,
  senderAddress,
  action,
  tokenAmount,
  timeStamp,
}: WalletHistoryEvent) => {
  return (
    <CustomView row vCenter columnBottom>
      <CustomView style={[styles.listItemBody]}>
        <CustomView>
          <CustomText bg="fifth" style={[styles.listItemTitle]}>
            {senderName || senderAddress}
          </CustomText>
        </CustomView>

        <CustomView>
          <CustomText bg="tertiary" style={[styles.listItemSubTitle]}>
            {action}
          </CustomText>
        </CustomView>
        <CustomDate uppercase bg="tertiary" style={[styles.listItemSubTitle]}>
          {timeStamp}
        </CustomDate>
      </CustomView>

      <CustomView row>
        <CustomText bold bg="tertiary" style={[styles.itemWalletSign]}>
          {action.toLowerCase() === 'withdraw' ? '-' : '+'}
        </CustomText>
        <CustomText
          bold
          bg="tertiary"
          formatNumber
          style={[styles.listItemWallet]}
        >
          {tokenAmount}
        </CustomText>
      </CustomView>
    </CustomView>
  )
}

const historyIcons = {
  ['WITHDRAW']: require('../images/sent.png'),
  ['PURCHASE']: require('../images/received.png'),
  ['RECEIVED']: require('../images/received.png'),
}

export class WalletTabHistory extends Component<WalletHistoryProps, void> {
  componentDidMount() {
    this.props.refreshWalletHistory()
  }

  getHistoryIcons = (action: string) => {
    return (
      <Icon
        src={historyIcons[action.toUpperCase()]}
        iconStyle={[{ tintColor: color.bg.fifth.font.fifth }]}
        small
      />
    )
  }

  render() {
    const { transactions, status } = this.props.walletHistory
    const walletHistory = transactions.map(transaction => {
      let itemProps = {
        key: transaction.id,
        avatar: this.getHistoryIcons(transaction.action),
        hideChevron: true,
        subtitle: <HistoryItem {...transaction} />,
        avatarStyle: styles.avatarStyle,
        avatarOverlayContainerStyle: styles.avatarOverlayContainerStyle,
        containerStyle: styles.listItemContainer,
      }
      return <ListItem {...itemProps} />
    })

    return (
      <Container>
        {status === STORE_STATUS.IN_PROGRESS && <Loader showMessage={false} />}
        {transactions.length < 1 &&
          status !== STORE_STATUS.SUCCESS && (
            <Container center>
              <CustomText h5 bg="tertiary" style={[styles.noHistory]}>
                No history to show
              </CustomText>
            </Container>
          )}
        {transactions.length > 0 && (
          <ScrollView>
            <List containerStyle={styles.listContainer}>{walletHistory}</List>
          </ScrollView>
        )}
      </Container>
    )
  }
}

const mapStateToProps = (state: Store) => {
  return {
    walletHistory: getWalletHistory(state) || {
      transactions: [],
      error: '',
      status: STORE_STATUS.IDLE,
    },
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators({ refreshWalletHistory }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(WalletTabHistory)

const styles = StyleSheet.create({
  listContainer: {
    marginTop: -1,
    borderBottomWidth: 0,
  },
  listItemContainer: {
    borderBottomWidth: 1,
    borderBottomColor: color.border.primary,
  },
  avatarStyle: {
    width: 16,
    height: 20,
    marginVertical: OFFSET_1X,
    resizeMode: 'contain',
  },
  avatarOverlayContainerStyle: {
    backgroundColor: 'transparent',
  },
  listItemTitle: {
    color: color.bg.tertiary.font.sixth,
    fontSize: 16,
  },
  listItemBody: {
    marginHorizontal: OFFSET_3X / 2,
    flex: 1,
  },
  listItemSubTitle: {
    fontSize: 14,
    color: color.bg.tertiary.font.fifth,
  },
  noHistory: {
    color: color.bg.tertiary.font.fifth,
    marginVertical: OFFSET_1X,
  },
  itemWalletSign: {
    fontSize: 18,
    color: color.bg.tertiary.font.quaternary,
  },
  listItemWallet: {
    fontSize: 18,
    paddingRight: OFFSET_1X,
    color: color.bg.tertiary.font.quaternary,
  },
})


<|start_filename|>app/components/layout/layout-style.js<|end_filename|>
// @flow
import React from 'react'
import { StyleSheet } from 'react-native'

import {
  PADDING_HORIZONTAL,
  PADDING_VERTICAL,
  color,
  OFFSET_2X,
} from '../../common/styles/constant'

export default StyleSheet.create({
  container: {
    flex: 1,
  },
  row: {
    flexDirection: 'row',
  },
  horizontalSpaced: {
    paddingHorizontal: PADDING_HORIZONTAL,
  },
  verticalSpaced: {
    paddingVertical: PADDING_VERTICAL,
  },
  doubleVerticalSpaced: {
    paddingVertical: PADDING_VERTICAL * 2,
  },
  transparentBg: {
    backgroundColor: 'transparent',
  },
  primaryBg: {
    backgroundColor: color.bg.primary.color,
  },
  secondaryBg: {
    backgroundColor: color.bg.secondary.color,
  },
  tertiaryBg: {
    backgroundColor: color.bg.tertiary.color,
  },
  quaternaryBg: {
    backgroundColor: color.bg.quaternary.color,
  },
  fifthBg: {
    backgroundColor: color.bg.fifth.color,
  },
  senaryBg: {
    backgroundColor: color.bg.sixth.color,
  },
  septenaryBg: {
    backgroundColor: color.bg.seventh.color,
  },
  darkBg: {
    backgroundColor: color.bg.dark.color,
  },
  left: {
    // this is assuming that we are aligning items in column
    alignItems: 'flex-start',
  },
  right: {
    alignItems: 'flex-end',
  },
  center: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  hCenter: {
    justifyContent: 'center',
  },
  vCenter: {
    alignItems: 'center',
  },
  rowBottom: {
    alignItems: 'flex-end',
  },
  columnBottom: {
    justifyContent: 'flex-end',
  },
  spaceBetween: {
    justifyContent: 'space-between',
  },
  list: {
    marginHorizontal: OFFSET_2X,
  },
  listItem: {
    marginVertical: OFFSET_2X,
  },
  shadow: {
    shadowColor: 'rgba(0, 0, 0, 0.2)',
    shadowOpacity: 1,
    shadowOffset: { width: 0, height: 10 },
    shadowRadius: 30,
    elevation: 10,
  },
  imageShadow: {
    shadowColor: 'rgba(0, 0, 0, 0.25)',
    elevation: 3,
    shadowOpacity: 1,
    shadowOffset: { width: 0, height: 3 },
    shadowRadius: 8,
  },
  absolute: {
    position: 'absolute',
  },
  absoluteTopRight: {
    top: 0,
    right: 0,
  },
  absoluteTopLeft: {
    top: 0,
    left: 0,
  },
  absoluteFill: {
    ...StyleSheet.absoluteFillObject,
  },
  spaceAround: {
    justifyContent: 'space-around',
  },
  zeroWidthBottomBorder: {
    borderBottomWidth: 0,
  },
})


<|start_filename|>app/connection-history/connection-history-details.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Dimensions, Platform, ScrollView } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import type { ConnectionHistoryDetailsProps } from './type-connection-history'
import {
  Container,
  CustomView,
  CustomText,
  CustomList,
  headerStyles,
  ConnectionTheme,
  CustomDate,
  Icon,
  CustomSafeAreaView,
} from '../components'
import {
  connectionHistoryDetailsRoute,
  connectionHistoryRoute,
} from '../common'
import {
  OFFSET_1X,
  OFFSET_3X,
  OFFSET_9X,
  OFFSET_2X,
  iPhoneXHeight,
} from '../common/styles/constant'

const styles = StyleSheet.create({
  headerContent: {
    marginTop: OFFSET_1X / 2,
  },
  headerDate: {
    marginBottom: OFFSET_3X / 2,
  },
  headerContainer: {
    minHeight: 109,
  },
})

export class ConnectionHistoryDetails extends PureComponent<
  ConnectionHistoryDetailsProps,
  void
> {
  static navigationOptions = ({
    navigation: {
      goBack,
      state: {
        params: {
          action,
          name,
          timestamp,
          theme,
          senderName,
          image,
          senderDID,
        },
      },
    },
  }) => ({
    headerLeft: (
      <CustomView>
        <Icon
          testID={'history-details-back-arrow'}
          iconStyle={[headerStyles.headerLeft]}
          small
          src={require('../images/icon_backArrow_white.png')}
          resizeMode="contain"
          onPress={() => goBack(null)}
        />
      </CustomView>
    ),
    headerTitle: (
      <Container clearBg center style={[headerStyles.centerTitle]}>
        {action && (
          <CustomText transparentBg center>
            {action}
          </CustomText>
        )}
        {name && (
          <CustomText
            style={[styles.headerContent]}
            transparentBg
            semiBold
            center
            numberOfLines={1}
          >
            {name}
          </CustomText>
        )}

        {timestamp && (
          <CustomDate
            transparentBg
            h7
            center
            uppercase
            style={[styles.headerContent, styles.headerDate]}
          >
            {timestamp}
          </CustomDate>
        )}
      </Container>
    ),
    headerRight: <Container />,
    headerStyle: [
      headerStyles.header,
      styles.headerContainer,
      { backgroundColor: theme },
    ],
  })

  getContainerStyle = (deviceClass: string) => {
    if (deviceClass === 'IphoneX') {
      return {
        marginTop: OFFSET_2X,
      }
    }
    return {
      marginTop: OFFSET_9X / 2,
    }
  }

  render() {
    const { height } = Dimensions.get('window')

    const deviceClass =
      Platform.OS === 'ios'
        ? height === iPhoneXHeight ? 'IphoneX' : 'ios'
        : 'android'

    if (this.props.navigation.state) {
      const { type, data, claimMap } = this.props.navigation.state.params
      const listType = type === 'CLAIM' ? 'center' : 'end'

      return (
        <Container style={[this.getContainerStyle(deviceClass)]}>
          {data && (
            <ScrollView>
              <CustomList items={data} type={listType} claimMap={claimMap} />
            </ScrollView>
          )}
        </Container>
      )
    }

    // TODO: Handle scenario if no navigation props are passed
    return <Container />
  }
}

export default createStackNavigator({
  [connectionHistoryDetailsRoute]: {
    screen: ConnectionHistoryDetails,
  },
})


<|start_filename|>app/api/api-constants.js<|end_filename|>
// @flow

export const TOKEN_EXPIRED_CODE = 'VES-101'
export const SERVER_ERROR_CODE = 'OCS-000'
export const SERVER_API_CALL_ERROR = 'OCS-001'
export const PENDING_CONNECTION_REQUEST_CODE = 'CRS-103'
export const PUSH_NOTIFICATION_SENT_CODE = 'push-notification-sent'

export const QR_CODE_REQUEST_ID = 'id'
export const QR_CODE_SENDER_DETAIL = 's'
export const QR_CODE_SENDER_DID = 'd'
export const QR_CODE_SENDER_NAME = 'n'
export const QR_CODE_LOGO_URL = 'l'
export const QR_CODE_SENDER_VERIFICATION_KEY = 'v'
export const QR_CODE_SENDER_KEY_DELEGATION = 'dp'
export const QR_CODE_DELEGATION_DID = 'd'
export const QR_CODE_DELEGATION_KEY = 'k'
export const QR_CODE_DELEGATION_SIGNATURE = 's'
export const QR_CODE_SENDER_AGENCY = 'sa'
export const QR_CODE_SENDER_AGENCY_DID = 'd'
export const QR_CODE_SENDER_AGENCY_KEY = 'v'
export const QR_CODE_SENDER_AGENCY_ENDPOINT = 'e'
export const QR_CODE_TARGET_NAME = 't'
export const GENESIS_FILE_NAME = 'pool_transactions_genesis'

export const MESSAGE_TYPE = {
  AUTH: 'auth-req',
  CLAIM_OFFER: 'credOffer',
  CLAIM_REQUEST: 'credReq',
  PROOF_REQUEST: 'proofReq',
  PROOF: 'proof',
  CLAIM: 'cred',
}

export const PAYLOAD_TYPE = {
  GET_MESSAGE: 'GET_MSGS',
  UPDATE_PUSH_COM_METHOD: 'UPDATE_PUSH_COM_METHOD',
  SEND_MESSAGE: 'SEND_MSG',
}

export const STATUS_CODE = {
  ACCEPT: 'MS-104',
}

export const ERROR_ALREADY_EXIST = {
  code: 'OCS',
  message: 'You already have a relationship with ',
}

export const ERROR_ALREADY_EXIST_TITLE = 'Relationship already established'

export const ERROR_INVITATION_RESPONSE_PARSE_CODE = 'RN-100'

export const ERROR_INVITATION_RESPONSE_PARSE =
  'Error parsing error message in invitation response'

export const ERROR_PENDING_INVITATION_RESPONSE_PARSE_CODE = 'RN-101'

export const ERROR_PENDING_INVITATION_RESPONSE_PARSE =
  'Error parsing error message Pending Invitation SMS'

export const ERROR_INVITATION_RESPONSE_FAILED =
  'Failed to establish connection. Please try again later.'


<|start_filename|>app/claim-offer/__tests__/claim-offer.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { ClaimOffer } from '../claim-offer'
import {
  CLAIM_OFFER_STATUS,
  CLAIM_REQUEST_STATUS,
  CREDENTIAL_OFFER_MODAL_STATUS,
} from '../type-claim-offer'
import { color } from '../../common/styles'
import {
  getStore,
  paidClaimOffer,
  claimOffer,
  senderLogoUrl1,
} from '../../../__mocks__/static-data'

describe('Paid <ClaimOffer />', () => {
  const store = getStore()

  let wrapper
  let claimOfferShown
  let acceptClaimOffer
  let claimOfferRejected
  let claimOfferIgnored
  let tree
  let navigation
  let componentInstance
  let claimOfferShowStart
  let resetClaimRequestStatus
  const logoUrl = senderLogoUrl1

  const paidClaimOfferData = {
    data: {
      name: '<NAME>',
      version: '1.0.0',
      revealedAttributes: [
        {
          label: 'Address 1',
          data: 'An Address',
        },
        {
          label: 'Address 2',
          data: 'An Address 2',
        },
      ],
      claimDefinitionSchemaSequenceNumber: 36,
    },
    issuer: {
      name: '<NAME>',
      did: 'issuerDid',
    },
    uid: 'asd123',
    remotePairwiseDID: 'ha66899sadfjZJGINKN0770',
    payTokenValue: '<PASSWORD>',
    status: CLAIM_OFFER_STATUS.RECEIVED,
    claimRequestStatus: CLAIM_REQUEST_STATUS.NONE,
    error: null,
  }

  const isValid = true
  const claimThemePrimary = color.bg.secondary.color
  const claimThemeSecondary = color.bg.secondary.color
  const updateStatusBarTheme = jest.fn()

  beforeEach(() => {
    claimOfferShown = jest.fn()
    acceptClaimOffer = jest.fn()
    claimOfferRejected = jest.fn()
    claimOfferIgnored = jest.fn()
    claimOfferShowStart = jest.fn()
    resetClaimRequestStatus = jest.fn()
    navigation = {
      goBack: jest.fn(),
      state: {
        params: {
          uid: 'asd123',
        },
      },
    }
    wrapper = renderer.create(
      <Provider store={store}>
        <ClaimOffer
          claimOfferData={paidClaimOfferData}
          claimOfferShown={claimOfferShown}
          acceptClaimOffer={acceptClaimOffer}
          claimOfferIgnored={claimOfferIgnored}
          claimOfferRejected={claimOfferRejected}
          navigation={navigation}
          uid={navigation.state.params.uid}
          isValid={isValid}
          logoUrl={logoUrl}
          claimThemeSecondary={claimThemeSecondary}
          claimThemePrimary={claimThemePrimary}
          updateStatusBarTheme={updateStatusBarTheme}
          claimOfferShowStart={claimOfferShowStart}
          resetClaimRequestStatus={resetClaimRequestStatus}
        />
      </Provider>
    )
    tree = wrapper.toJSON()
    componentInstance = wrapper.root.findByType(ClaimOffer).instance
  })

  // Todo: write test to check if token balance is displayed.
  // However not clear how to write and assertion of token balance text
  it('should call claimOfferShown on componentDidMount', () => {
    expect(tree).toMatchSnapshot()
    expect(claimOfferShown).toHaveBeenCalled()
  })
})

describe('<ClaimOffer />', () => {
  const store = getStore()

  let wrapper
  let claimOfferShown
  let acceptClaimOffer
  let claimOfferRejected
  let claimOfferIgnored
  let tree
  let navigation
  let componentInstance
  let claimOfferShowStart
  let resetClaimRequestStatus
  const logoUrl = senderLogoUrl1
  const claimOfferData = {
    data: {
      name: '<NAME>',
      version: '1.0.0',
      revealedAttributes: [
        {
          label: 'Address 1',
          data: 'An Address',
        },
        {
          label: 'Address 2',
          data: 'An Address 2',
        },
      ],
      claimDefinitionSchemaSequenceNumber: 36,
    },
    issuer: {
      name: '<NAME>',
      did: 'issuerDid',
    },
    uid: 'asd123',
    remotePairwiseDID: 'ha66899sadfjZJGINKN0770',
    status: CLAIM_OFFER_STATUS.RECEIVED,
    claimRequestStatus: CLAIM_REQUEST_STATUS.NONE,
    error: null,
  }
  const isValid = true
  const claimThemePrimary = color.bg.secondary.color
  const claimThemeSecondary = color.bg.secondary.color
  const updateStatusBarTheme = jest.fn()

  beforeEach(() => {
    claimOfferShown = jest.fn()
    acceptClaimOffer = jest.fn()
    claimOfferRejected = jest.fn()
    claimOfferIgnored = jest.fn()
    claimOfferShowStart = jest.fn()
    resetClaimRequestStatus = jest.fn()
    navigation = {
      goBack: jest.fn(),
      state: {
        params: {
          uid: 'asd123',
        },
      },
    }
    wrapper = renderer.create(
      <Provider store={store}>
        <ClaimOffer
          claimOfferData={claimOfferData}
          claimOfferShown={claimOfferShown}
          acceptClaimOffer={acceptClaimOffer}
          claimOfferIgnored={claimOfferIgnored}
          claimOfferRejected={claimOfferRejected}
          navigation={navigation}
          uid={navigation.state.params.uid}
          isValid={isValid}
          logoUrl={logoUrl}
          claimThemeSecondary={claimThemeSecondary}
          claimThemePrimary={claimThemePrimary}
          updateStatusBarTheme={updateStatusBarTheme}
          claimOfferShowStart={claimOfferShowStart}
          resetClaimRequestStatus={resetClaimRequestStatus}
        />
      </Provider>
    )
    tree = wrapper.toJSON()
    componentInstance = wrapper.root.findByType(ClaimOffer).instance
  })

  it('should call claimOfferShown on componentDidMount', () => {
    expect(tree).toMatchSnapshot()
    expect(claimOfferShown).toHaveBeenCalled()
  })
  it('should call acceptClaimOffer if offer is accepted', () => {
    componentInstance.onAccept()
    expect(acceptClaimOffer).toHaveBeenCalled()
  })

  it('should call claimOfferIgnored if ignored', () => {
    componentInstance.onIgnore()
    expect(claimOfferIgnored).toHaveBeenCalled()
    expect(navigation.goBack).toHaveBeenCalled()
  })

  it('should show Insufficient Balance Modal', () => {
    jest.useFakeTimers()
    wrapper.update(
      <Provider store={store}>
        <ClaimOffer
          claimOfferData={{
            ...claimOfferData,
            claimRequestStatus: CLAIM_REQUEST_STATUS.INSUFFICIENT_BALANCE,
          }}
          claimOfferShown={claimOfferShown}
          acceptClaimOffer={acceptClaimOffer}
          claimOfferIgnored={claimOfferIgnored}
          claimOfferRejected={claimOfferRejected}
          navigation={navigation}
          uid={navigation.state.params.uid}
          isValid={isValid}
          logoUrl={logoUrl}
          claimThemeSecondary={claimThemeSecondary}
          claimThemePrimary={claimThemePrimary}
          updateStatusBarTheme={updateStatusBarTheme}
          claimOfferShowStart={claimOfferShowStart}
          resetClaimRequestStatus={resetClaimRequestStatus}
        />
      </Provider>
    )
    componentInstance.onCredentialOfferModalHide()
    jest.runOnlyPendingTimers()
    expect(componentInstance.state.credentialOfferModalStatus).toBe(
      CREDENTIAL_OFFER_MODAL_STATUS.INSUFFICIENT_BALANCE
    )
  })

  it('should show Send Paid Credential Request Fail Modal', () => {
    jest.useFakeTimers()
    wrapper.update(
      <Provider store={store}>
        <ClaimOffer
          claimOfferData={{
            ...claimOfferData,
            claimRequestStatus:
              CLAIM_REQUEST_STATUS.PAID_CREDENTIAL_REQUEST_FAIL,
          }}
          claimOfferShown={claimOfferShown}
          acceptClaimOffer={acceptClaimOffer}
          claimOfferIgnored={claimOfferIgnored}
          claimOfferRejected={claimOfferRejected}
          navigation={navigation}
          uid={navigation.state.params.uid}
          isValid={isValid}
          logoUrl={logoUrl}
          claimThemeSecondary={claimThemeSecondary}
          claimThemePrimary={claimThemePrimary}
          updateStatusBarTheme={updateStatusBarTheme}
          claimOfferShowStart={claimOfferShowStart}
          resetClaimRequestStatus={resetClaimRequestStatus}
        />
      </Provider>
    )
    componentInstance.onCredentialOfferModalHide()
    jest.runOnlyPendingTimers()
    expect(componentInstance.state.credentialOfferModalStatus).toBe(
      CREDENTIAL_OFFER_MODAL_STATUS.SEND_PAID_CREDENTIAL_REQUEST_FAIL
    )
  })

  it('should enable accept button if claim offer error occurs', () => {
    jest.useFakeTimers()
    wrapper.update(
      <Provider store={store}>
        <ClaimOffer
          claimOfferData={{
            ...claimOfferData,
            claimRequestStatus: CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_FAIL,
          }}
          claimOfferShown={claimOfferShown}
          acceptClaimOffer={acceptClaimOffer}
          claimOfferIgnored={claimOfferIgnored}
          claimOfferRejected={claimOfferRejected}
          navigation={navigation}
          uid={navigation.state.params.uid}
          isValid={isValid}
          logoUrl={logoUrl}
          claimThemeSecondary={claimThemeSecondary}
          claimThemePrimary={claimThemePrimary}
          updateStatusBarTheme={updateStatusBarTheme}
          claimOfferShowStart={claimOfferShowStart}
          resetClaimRequestStatus={resetClaimRequestStatus}
        />
      </Provider>
    )
    jest.runOnlyPendingTimers()
    expect(componentInstance.state.disableAcceptButton).toBe(false)
  })

  it('should call claimOfferRejected if rejected', () => {
    componentInstance.onReject()
    expect(claimOfferRejected).toHaveBeenCalled()
    expect(navigation.goBack).toHaveBeenCalled()
  })
})


<|start_filename|>app/components/qr-scanner/qr-invitation-url-validator.js<|end_filename|>
// @flow

import urlParse from 'url-parse'
import type { InvitationUrlQrCode } from './type-qr-scanner'

// only trust if scheme is https, http is not allowed
export const validInvitationUrlScheme = ['https:', 'http:']

// maximum length allowed for whole url-qr-code
export const validInvitationUrlLength = 2048

export function isValidInvitationUrl(
  passedUrlString: string
): InvitationUrlQrCode | boolean {
  if (passedUrlString.length > validInvitationUrlLength) {
    return false
  }

  const { protocol } = urlParse(passedUrlString, {}, true)

  if (validInvitationUrlScheme.indexOf(protocol) < 0) {
    return false
  }

  return {
    url: passedUrlString,
  }
}


<|start_filename|>flow-typed/npm/react-native-linear-gradient.js<|end_filename|>
declare module 'react-native-linear-gradient' {
  declare module.exports: any
}


<|start_filename|>app/components/request/request-detail-avatars.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Image } from 'react-native'
import { View as AnimatedView } from 'react-native-animatable'
import { Container, CustomView, UserAvatar, Avatar } from '../../components'
import { getConnectionLogo } from '../../store/connections-store'
import type { RequestDetailAvatarProps } from './type-request'
import { OFFSET_4X, OFFSET_1X } from '../../common/styles'
import type { ImageSource } from '../../common/type-common'

export default class RequestDetailAvatars extends PureComponent<
  RequestDetailAvatarProps,
  void
> {
  renderAvatarWithSource = (avatarSource: number | ImageSource) => (
    <Avatar
      medium
      shadow
      src={avatarSource}
      testID={'invitation-text-avatars-invitee'}
    />
  )

  render() {
    const senderAvatar = getConnectionLogo(this.props.senderLogoUrl)

    return (
      <AnimatedView
        animation="bounceInUp"
        delay={300}
        duration={1500}
        testID={'invitation-text-container-avatars-animation'}
        accessible={true}
        accessibilityLabel={'invitation-text-container-avatars-animation'}
      >
        <CustomView center spaceBetween>
          <CustomView
            row
            vCenter
            spaceBetween
            style={[styles.avatarsContainer]}
            testID={'invitation-text-avatars-container'}
          >
            <UserAvatar>{this.renderAvatarWithSource}</UserAvatar>
            <Image
              style={styles.forwardArrow}
              source={require('../../images/connectDots.png')}
            />
            <Avatar
              medium
              shadow
              src={senderAvatar}
              testID={'invitation-text-avatars-inviter'}
            />
          </CustomView>
        </CustomView>
      </AnimatedView>
    )
  }
}

const styles = StyleSheet.create({
  avatarsContainer: {
    marginVertical: OFFSET_4X,
  },
  forwardArrow: {
    width: 60,
    height: 8,
    marginHorizontal: OFFSET_1X / 2,
  },
})


<|start_filename|>app/lock/lock-fingerprint-setup.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Alert, StyleSheet, Platform } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { TouchId } from '../components/touch-id/touch-id'
import { Container } from '../components'
import { captureError } from '../services/error/error-handler'
import type { Store } from '../store/type-store'

import {
  lockPinSetupRoute,
  lockSelectionRoute,
  settingsTabRoute,
  settingsRoute,
} from '../common'

import {
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_6X,
  isiPhone5,
} from '../common/styles/constant'
import { disableTouchIdAction, enableTouchIdAction } from '../lock/lock-store'
import {
  AllowedFallbackToucheIDErrors,
  LAErrorTouchIDTooManyAttempts,
  LAErrorTouchIDNotSupported,
  touchIDAlerts,
  touchIDNotSupportAlertAndroid,
} from './type-lock'
import type { LockFingerprintSetupProps } from './type-lock'
import { AsyncStorage } from 'react-native'
import { safeSet } from '../services/storage'
import { getBiometricError } from '../bridge/react-native-cxs/RNCxs'

export class LockFingerprintSetup extends PureComponent<
  LockFingerprintSetupProps,
  void
> {
  goToSettingsScreen = () => {
    if (this.props.touchIdActive) {
      this.props.disableTouchIdAction()
      Alert.alert(
        null,
        touchIDAlerts.usePasscodeAlert,
        [
          {
            text: 'Ok',
            onPress: () => this.props.navigation.goBack(null),
          },
        ],
        { cancelable: false }
      )
    } else {
      this.props.enableTouchIdAction()
      this.props.navigation.goBack(null)
    }
  }
  goToPinSetupScreen = () => {
    this.props.enableTouchIdAction()
    this.props.navigation.navigate(lockPinSetupRoute, { touchIdActive: true })
  }

  popUpNativeAlert = (message: string) => {
    Alert.alert(
      null,
      message,
      [
        {
          text: 'Ok',
          onPress: () => {
            this.props.fromSettings
              ? this.props.navigation.goBack(null)
              : this.props.navigation.navigate(lockSelectionRoute)
          },
        },
      ],
      { cancelable: false }
    )
  }

  touchIdHandler = () => {
    if (
      !this.props.fromSettings ||
      (this.props.fromSettings && this.props.currentScreen === settingsRoute)
    )
      TouchId.isSupported()
        .then(success => {
          TouchId.authenticate('', this.touchIdHandler)
            .then(success => {
              this.props.fromSettings
                ? this.goToSettingsScreen()
                : this.goToPinSetupScreen()
            })
            .catch(error => {
              // captureError(error)
              if (AllowedFallbackToucheIDErrors.indexOf(error.name) >= 0) {
                if (error.code === LAErrorTouchIDTooManyAttempts) {
                  this.popUpNativeAlert(touchIDAlerts.biometricsExceedAlert)
                } else {
                  this.props.fromSettings
                    ? this.props.navigation.goBack(null)
                    : this.props.navigation.navigate(lockSelectionRoute)
                }
              }
            })
        })
        .catch(error => {
          captureError(error)
          if (AllowedFallbackToucheIDErrors.indexOf(error.name) >= 0) {
            let alertMessage = touchIDAlerts.notSupportedBiometrics
            if (Platform.OS === 'android') {
              if (touchIDNotSupportAlertAndroid.indexOf(error.code) < 0) {
                alertMessage = touchIDAlerts.enableBiometrics
              }
              this.popUpNativeAlert(alertMessage)
            } else {
              getBiometricError()
                .then()
                .catch(err => {
                  if (err.code === 'BiometricsLockOut') {
                    alertMessage = touchIDAlerts.biometricsExceedAlert
                  } else if (err.code === 'BiometricsNotEnrolled') {
                    alertMessage = touchIDAlerts.enableBiometrics
                  } else {
                    alertMessage = touchIDAlerts.notSupportedBiometrics
                  }
                  this.popUpNativeAlert(alertMessage)
                })
            }
          }
        })
  }

  componentDidMount() {
    this.touchIdHandler()
  }

  render() {
    return <Container tertiary style={[style.pinSelectionContainer]} />
  }
}

const mapStateToProps = (state: Store, props) => ({
  touchIdActive: state.lock.isTouchIdEnabled,
  currentScreen: state.route.currentScreen,
  fromSettings:
    props.navigation.state.params !== undefined
      ? props.navigation.state.params.fromSettings
      : false,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      disableTouchIdAction,
      enableTouchIdAction,
    },
    dispatch
  )

const style = StyleSheet.create({
  pinSelectionContainer: {
    paddingTop: OFFSET_3X,
    paddingBottom: isiPhone5 ? OFFSET_2X : OFFSET_6X,
    paddingHorizontal: OFFSET_2X,
  },
})

export default connect(mapStateToProps, mapDispatchToProps)(
  LockFingerprintSetup
)


<|start_filename|>connectMeUITest/src/funcModules/ConnectionModules.java<|end_filename|>
package funcModules;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import appModules.AppUtlis;
import appModules.ReadMail;
import appModules.RestApi;
import io.appium.java_client.AppiumDriver;
import pageObjects.ChooseLockPage;
import pageObjects.ConnectionDetailPage;
import pageObjects.GmailPage;
import pageObjects.HockeyAppPage;
import pageObjects.PincodePage;
import utility.Setup;

public class ConnectionModules {
	

	AppUtlis AppUtlisObj=new AppUtlis();
	RestApi RestApiObj=new RestApi();
	private AppiumDriver driver;

	
	
	public void InstallApp(AppiumDriver driver,String Link)throws Exception
	{
		
		Thread.sleep(3000);
		driver.get(Link);
		HockeyAppPage.UserNameText(driver).sendKeys("<EMAIL>");
		HockeyAppPage.PasswordText(driver).sendKeys("<PASSWORD>$");
		HockeyAppPage.SigninButton(driver).click();    	
     	HockeyAppPage.QAConnectIcon(driver).click(); 
     	String InstallConnectMeLink =HockeyAppPage.InstallButton(driver).getAttribute("href");
     	System.out.println(InstallConnectMeLink);
        driver.get(InstallConnectMeLink);
        Thread.sleep(10000);
        //used sleep which is not recommended as we have issue with synch of alert box
    	driver.switchTo().alert().accept();
		
	}

	public void AppProvisioningRequest(String RequestType,AppiumDriver driver) throws Exception
	{

		if (RequestType=="Accept"){
	      AppUtlisObj.RequestProvisioning(driver,"Accept");
		  driver.switchTo().alert().accept();

	      }
		
	 else {
		   AppUtlisObj.RequestProvisioning(driver,"Deny");
		   driver.switchTo().alert().accept(); 
   	      }
	   Thread.sleep(5000);
	   ConnectionDetailPage.Continue_Button(driver).click();
	}
	

}


<|start_filename|>app/backup/export-backup.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { Image, Dimensions } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import {
  Container,
  CustomView,
  CustomText,
  Icon,
  CustomButton,
  CustomHeader,
  Loader,
} from '../components'

import {
  exportBackupFileRoute,
  backupCompleteRoute,
  backupErrorRoute,
} from '../common'
import {
  isBiggerThanShortDevice,
  isBiggerThanVeryShortDevice,
} from '../common/styles'
import { color } from '../common/styles/constant'
import type { ExportBackupFileProps } from './type-backup'
import styles from './styles'
import { exportBackup } from './backup-store'
import type { Store } from '../store/type-store'
import {
  EXPORT_BACKUP_BACK_TEST_ID,
  EXPORT_BACKUP_CLOSE_TEST_ID,
  EXPORT_BACKUP_SUBMIT_BUTTON_TEST_ID,
  EXPORT_BACKUP_BUTTON_TITLE,
} from './backup-constants'
import { BACKUP_STORE_STATUS } from './type-backup'
import { getBackupStatus, getBackupWalletPath } from '../store/store-selector'

const transparentBands = require('../images/transparentBands.png')
const backImage = require('../images/icon_backArrow_white.png')
const closeImage = require('../images/iconClose.png')
const encryptedFile = require('../images/encryptedFile.png')

export class ExportBackupFile extends PureComponent<
  ExportBackupFileProps,
  void
> {
  parseFilePath = (path: string) => {
    const beginning = path.lastIndexOf('/') + 1
    const end = path.length

    return path.slice(beginning, end)
  }

  componentDidUpdate(prevProps: ExportBackupFileProps) {
    const { navigation: { navigate, state, goBack }, backupStatus } = this.props
    if (
      prevProps.backupStatus !== BACKUP_STORE_STATUS.BACKUP_COMPLETE &&
      backupStatus === BACKUP_STORE_STATUS.BACKUP_COMPLETE
    ) {
      navigate(backupCompleteRoute, {
        initialRoute: state.params.initialRoute,
      })
    } else if (
      prevProps.backupStatus !== BACKUP_STORE_STATUS.EXPORT_BACKUP_FAILURE &&
      backupStatus === BACKUP_STORE_STATUS.EXPORT_BACKUP_FAILURE
    ) {
      navigate(backupErrorRoute, {
        initialRoute: state.params.initialRoute,
      })
    }
  }

  encryptAndBackup = () => {
    this.props.exportBackup()
  }

  BackupPath = (path: string) => {
    if (path) {
      return (
        <CustomView center>
          <CustomText center transparentBg style={[styles.exportBackupFile]}>
            {this.parseFilePath(path)}
          </CustomText>
        </CustomView>
      )
    }

    return null
  }

  ExportImage = (status: string) => {
    if (
      status === BACKUP_STORE_STATUS.EXPORT_BACKUP_LOADING ||
      status === BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_LOADING
    ) {
      return (
        <CustomView doubleVerticalSpace>
          <Loader showMessage={false} type="light" size={40} />
        </CustomView>
      )
    }

    return (
      <CustomView center style={[styles.lockIconImage]}>
        <Image source={encryptedFile} style={[styles.imageIconEncryptFile]} />
      </CustomView>
    )
  }

  static navigationOptions = ({ navigation: { goBack, navigate, state } }) => ({
    header: (
      <CustomHeader
        flatHeader
        largeHeader
        backgroundColor={color.bg.thirteenth.color}
      >
        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => goBack(null)}
            testID={EXPORT_BACKUP_BACK_TEST_ID}
            iconStyle={[styles.headerBackIcon]}
            src={backImage}
          />
        </CustomView>

        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => navigate(state.params.initialRoute)}
            testID={EXPORT_BACKUP_CLOSE_TEST_ID}
            iconStyle={[styles.headerIcon]}
            src={closeImage}
          />
        </CustomView>
      </CustomHeader>
    ),
    gesturesEnabled: true,
  })

  render() {
    const { backupPath, backupStatus } = this.props
    const disableButton =
      backupStatus === BACKUP_STORE_STATUS.GENERATE_BACKUP_FILE_LOADING
        ? true
        : false

    return (
      <Container style={[styles.exportBackup]} safeArea>
        <Image source={transparentBands} style={[styles.backgroundImage]} />
        <Container style={[styles.wrapper]}>
          <CustomView center>
            <CustomText transparentBg center style={[styles.exportBackupTitle]}>
              Export your encrypted backup file
            </CustomText>
          </CustomView>
          <CustomView center>
            <CustomText
              center
              transparentBg
              style={[styles.exportBackupMainText]}
            >
              You will need your recovery phrase to unlock this backup file.
            </CustomText>
          </CustomView>
          <CustomView
            center
            verticalSpace
            doubleVerticalSpace={isBiggerThanVeryShortDevice ? true : false}
          >
            <CustomText
              center
              transparentBg
              style={[styles.exportBackupMainText]}
            >
              Don’t worry, only you can decrypt the backup with your recovery
              phrase.
            </CustomText>
          </CustomView>

          {this.ExportImage(backupStatus)}
          {this.BackupPath(backupPath)}
        </Container>

        <CustomView verticalSpace={isBiggerThanVeryShortDevice ? true : false}>
          <CustomView center>
            <CustomText
              center
              transparentBg
              bold
              style={[styles.exportBackupSmallMessage]}
            >
              This backup contains all your data in Connect.Me. Store it
              somewhere safe.
            </CustomText>
          </CustomView>
          <CustomButton
            large={isBiggerThanShortDevice ? true : false}
            disabled={disableButton}
            onPress={this.encryptAndBackup}
            testID={EXPORT_BACKUP_SUBMIT_BUTTON_TEST_ID}
            style={[styles.submitButton]}
            customColor={{
              color: color.bg.thirteenth.color,
              fontWeight: '600',
              fontSize: 18,
            }}
            title={EXPORT_BACKUP_BUTTON_TITLE}
          />
        </CustomView>
      </Container>
    )
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators({ exportBackup }, dispatch)

const mapStateToProps = (state: Store) => {
  return {
    backupStatus: getBackupStatus(state),
    backupPath: getBackupWalletPath(state),
  }
}

export default createStackNavigator({
  [exportBackupFileRoute]: {
    screen: connect(mapStateToProps, mapDispatchToProps)(ExportBackupFile),
  },
})


<|start_filename|>app/components/touch-id/__tests__/touch-id.spec.js<|end_filename|>
// @flow
import TouchId from '../touch-id'

describe('<TouchId />', () => {
  it('passes', () => {
    const onSuccess = jest.fn()
    const onFail = jest.fn()

    jest.useFakeTimers()

    TouchId.authenticate('test')
      .then(onSuccess)
      .catch(onFail)

    jest.runAllTimers()
    expect(onSuccess).toHaveBeenCalled()
  })
})


<|start_filename|>app/wallet/wallet-store.js<|end_filename|>
// @flow

import RNFetchBlob from 'react-native-fetch-blob'
import {
  put,
  takeLatest,
  call,
  all,
  select,
  takeEvery,
  take,
} from 'redux-saga/effects'
import { Platform } from 'react-native'
import Share from 'react-native-share'
import moment from 'moment'
import {
  secureSet,
  secureGet,
  secureDelete,
  getHydrationItem,
} from '../services/storage'
import {
  HYDRATE_WALLET_BALANCE_FAIL,
  HYDRATE_WALLET_ADDRESSES_FAIL,
  HYDRATE_WALLET_HISTORY_FAIL,
  REFRESH_WALLET_ADDRESSES,
  REFRESH_WALLET_HISTORY,
  PROMPT_WALLET_BACKUP_BANNER,
  REFRESH_WALLET_BALANCE_FAIL,
  REFRESH_WALLET_ADDRESSES_FAIL,
  REFRESH_WALLET_HISTORY_FAIL,
  ERROR_REFRESHING_WALLET_BALANCE,
  REFRESH_WALLET_BALANCE,
  WALLET_BALANCE_REFRESHED,
  WALLET_ADDRESSES_REFRESHED,
  WALLET_HISTORY_REFRESHED,
  ERROR_REFRESHING_WALLET_ADDRESSES,
  ERROR_REFRESHING_WALLET_HISTORY,
  HYDRATE_WALLET_BALANCE,
  HYDRATE_WALLET_ADDRESSES,
  HYDRATE_WALLET_HISTORY,
  ERROR_LOADING_WALLET_BALANCE,
  ERROR_LOADING_WALLET_ADDRESSES,
  ERROR_LOADING_WALLET_HISTORY,
  STORE_STATUS,
  BACKUP_WALLET,
  BACKUP_WALLET_FAIL,
  BACKUP_WALLET_SUCCESS,
  BACKUP_WALLET_PATH,
  SHARE_WALLET_BACKUP,
  GET_WALLET_ENCRYPTION_KEY,
  ERROR_BACKUP_WALLET,
  ERROR_BACKUP_WALLET_SHARE,
  SEND_TOKENS,
  SEND_TOKENS_FAIL,
  ERROR_SENDING_TOKENS,
  TOKEN_SENT_SUCCESS,
  SELECT_TOKEN_AMOUNT,
  WALLET_ADDRESSES_FETCH_START,
  ERROR_SENDING_TOKENS_WITH_FEES,
} from './type-wallet'
import { NEW_CONNECTION_SUCCESS } from '../store/connections-store'
import type { AgencyPoolConfig } from '../store/type-config-store'
import { VCX_INIT_SUCCESS } from '../store/type-config-store'
import type {
  WalletStore,
  WalletStoreAction,
  HydrateWalletBalanceData,
  HydrateWalletAddressesData,
  HydrateWalletHistoryTransactions,
  RefreshWalletHistoryAction,
  RefreshWalletAddressesAction,
  RefreshWalletBalanceAction,
  BackupWalletAction,
  WalletHistory,
  WalletBalance,
  WalletAddresses,
  SendTokensAction,
  ShareBackupAction,
  PromptBackupBannerAction,
} from './type-wallet'
import type { CustomError } from '../common/type-common'
import { RESET } from '../common/type-common'
import {
  WALLET_BALANCE,
  WALLET_ADDRESSES,
  WALLET_HISTORY,
} from '../common/secure-storage-constants'
import {
  getWalletBalance,
  getWalletAddresses,
  getWalletHistory,
  sendTokenAmount,
  createPaymentAddress,
  getLedgerFees,
} from '../bridge/react-native-cxs/RNCxs'
import { promptBackupBanner } from '../backup/backup-store'
import {
  getConfig,
  getWalletBalance as getWalletBalanceSelector,
} from '../store/store-selector'
import { WALLET_ENCRYPTION_KEY } from '../common/secure-storage-constants'
import { ensureVcxInitSuccess } from '../store/config-store'
import type { LedgerFeesData } from '../store/ledger/type-ledger-store'
import { BigNumber } from 'bignumber.js'
import { captureError } from '../services/error/error-handler'

export const walletInitialState = {
  walletBalance: { data: '0', status: STORE_STATUS.IDLE, error: null },
  walletAddresses: { data: [], status: STORE_STATUS.IDLE, error: null },
  walletHistory: { transactions: [], status: STORE_STATUS.IDLE, error: null },
  backup: {
    status: STORE_STATUS.IDLE,
    latest: null,
    error: null,
    backupPath: null,
  },
  payment: { tokenAmount: '0', status: STORE_STATUS.IDLE, error: null },
}

export function* shareBackupSaga(
  action: ShareBackupAction
): Generator<*, *, *> {
  // SHARE BACKUP FLOW
  const { data } = action
  const { backupPath }: { backupPath: any } = data

  try {
    Platform.OS === 'android'
      ? yield call(Share.open, {
          title: 'Share Your Data Wallet',
          url: `file://${backupPath}`,
          type: 'application/zip',
        })
      : yield call(Share.open, {
          title: 'Share Your Data Wallet',
          url: backupPath,
          type: 'application/zip',
          message: 'here we go!',
          subject: 'something here maybe?',
        })
    yield put(walletBackupComplete(backupPath))
    yield put(promptBackupBanner(false))
    let encryptionKey = yield call(secureGet, WALLET_ENCRYPTION_KEY)
    // TODO: has to be removed, only for android testing and the above let has to be changed to const
    if (encryptionKey === null) {
      encryptionKey = WALLET_ENCRYPTION_KEY
    }
    yield put(walletEncryptionKey(encryptionKey))
  } catch (e) {
    yield put(
      backupWalletFail({
        ...ERROR_BACKUP_WALLET_SHARE,
        message: `${ERROR_BACKUP_WALLET_SHARE.message}.${e}`,
      })
    )
  }
}

export const backupWalletFail = (error: CustomError) => ({
  type: BACKUP_WALLET_FAIL,
  error,
  status: STORE_STATUS.ERROR,
})

export const backupWalletPath = (backupPath: string) => ({
  type: BACKUP_WALLET_PATH,
  backupPath,
})

export const walletEncryptionKey = (WALLET_ENCRYPTION_KEY: string) => ({
  type: GET_WALLET_ENCRYPTION_KEY,
  data: {
    encryptionKey: WALLET_ENCRYPTION_KEY,
    status: STORE_STATUS.SUCCESS,
  },
})

export const walletBackup = () => ({
  type: BACKUP_WALLET,
  data: {
    status: STORE_STATUS.IN_PROGRESS,
    error: null,
  },
})

export const walletBackupShare = (WALLET_BACKUP_PATH: string) => ({
  type: SHARE_WALLET_BACKUP,
  data: {
    status: STORE_STATUS.IN_PROGRESS,
    backupPath: WALLET_BACKUP_PATH,
    error: null,
  },
})

export const walletBackupComplete = (WALLET_BACKUP_PATH: string) => ({
  type: BACKUP_WALLET_SUCCESS,
  data: {
    status: STORE_STATUS.SUCCESS,
    latest: moment().format(),
    backupPath: WALLET_BACKUP_PATH,
    error: null,
  },
})

export function* hydrateWalletStoreSaga(): Generator<*, *, *> {
  yield all([
    call(hydrateWalletBalanceSaga),
    call(hydrateWalletAddressesSaga),
    call(hydrateWalletHistorySaga),
  ])
}

export function* hydrateWalletBalanceSaga(): Generator<*, *, *> {
  try {
    const walletBalance: string = yield call(getHydrationItem, WALLET_BALANCE)
    if (walletBalance) {
      yield put(hydrateWalletBalanceStore(walletBalance))
    } else {
      yield put(
        hydrateWalletBalanceFail({
          ...ERROR_LOADING_WALLET_BALANCE,
          message: `${ERROR_LOADING_WALLET_BALANCE.message}`,
        })
      )
    }
  } catch (e) {
    yield put(
      hydrateWalletBalanceFail({
        ...ERROR_LOADING_WALLET_BALANCE,
        message: `${ERROR_LOADING_WALLET_BALANCE.message} ${e.message}`,
      })
    )
  }
}

export function* hydrateWalletAddressesSaga(): Generator<*, *, *> {
  try {
    const walletAddressesJson = yield call(getHydrationItem, WALLET_ADDRESSES)
    if (walletAddressesJson !== null) {
      const walletAddresses = JSON.parse(walletAddressesJson)
      yield put(hydrateWalletAddressesStore(walletAddresses))
    } else {
      yield put(
        hydrateWalletAddressesFail({
          ...ERROR_LOADING_WALLET_ADDRESSES,
          message: `${ERROR_LOADING_WALLET_ADDRESSES.message}`,
        })
      )
    }
  } catch (e) {
    yield put(
      hydrateWalletAddressesFail({
        ...ERROR_LOADING_WALLET_ADDRESSES,
        message: `${ERROR_LOADING_WALLET_ADDRESSES.message} ${e.message}`,
      })
    )
  }
}

export function* hydrateWalletHistorySaga(): Generator<*, *, *> {
  try {
    const walletHistoryJson = yield call(getHydrationItem, WALLET_HISTORY)
    if (walletHistoryJson !== null) {
      const walletHistory = JSON.parse(walletHistoryJson)
      yield put(hydrateWalletHistoryStore(walletHistory))
    } else {
      yield put(
        hydrateWalletHistoryFail({
          ...ERROR_LOADING_WALLET_HISTORY,
          message: `${ERROR_LOADING_WALLET_HISTORY.message}`,
        })
      )
    }
  } catch (e) {
    yield put(
      hydrateWalletHistoryFail({
        ...ERROR_LOADING_WALLET_HISTORY,
        message: `${ERROR_LOADING_WALLET_HISTORY.message} ${e.message}`,
      })
    )
  }
}

export function* deletePersistedWalletBalance(): Generator<*, *, *> {
  yield call(secureDelete, WALLET_BALANCE)
}

export function* deletePersistedWalletAddresses(): Generator<*, *, *> {
  yield call(secureDelete, WALLET_ADDRESSES)
}

export function* deletePersistedWalletHistory(): Generator<*, *, *> {
  yield call(secureDelete, WALLET_HISTORY)
}

export function* watchWalletStore(): any {
  yield all([
    watchRefreshWalletBalance(),
    watchRefreshWalletAddresses(),
    watchRefreshWalletHistory(),
    watchSendTokens(),
  ])
}

function* watchRefreshWalletBalance(): any {
  yield takeLatest(REFRESH_WALLET_BALANCE, refreshWalletBalanceSaga)
}

function* watchRefreshWalletAddresses(): any {
  yield takeLatest(REFRESH_WALLET_ADDRESSES, refreshWalletAddressesSaga)
}

function* watchRefreshWalletHistory(): any {
  yield takeLatest(REFRESH_WALLET_HISTORY, refreshWalletHistorySaga)
}

function* watchSendTokens(): any {
  yield takeLatest(SEND_TOKENS, sendTokensSaga)
}

export function* getAmountToTransfer(
  action: SendTokensAction
): Generator<*, *, *> {
  const { transfer }: LedgerFeesData = yield call(getLedgerFees)
  const transferFeesAmount = new BigNumber(transfer)
  const transferAmount = new BigNumber(action.tokenAmount)
  const walletBalance: string = yield select(getWalletBalanceSelector)
  const walletBalanceAmount = new BigNumber(walletBalance)
  let amountToTransfer = transferAmount

  if (walletBalanceAmount.isEqualTo(transferAmount)) {
    // if user is trying to transfer whole amount
    // then deduct transfer fees
    amountToTransfer = transferAmount.minus(transferFeesAmount)
  }

  if (
    walletBalanceAmount.isLessThan(transferFeesAmount.plus(amountToTransfer))
  ) {
    // wallet does not have enough balance to pay fees and transfer amount
    amountToTransfer = new BigNumber(0)
  }

  // if we are here, that means
  // 1. wallet has enough balance for transfer amount and transfer fees
  //  OR
  // 2. if whole amount was transferred, then transfer amount is adjusted
  //    after deducting ledger transfer fees

  return amountToTransfer
}

export function* sendTokensSaga(action: SendTokensAction): Generator<*, *, *> {
  try {
    const vcxResult = yield* ensureVcxInitSuccess()
    if (vcxResult && vcxResult.fail) {
      throw new Error(JSON.stringify(vcxResult.fail.message))
    }
    const amountToTransfer: BigNumber = yield* getAmountToTransfer(action)

    if (amountToTransfer.isLessThanOrEqualTo(0)) {
      yield put(
        sendTokensFail(action.tokenAmount, ERROR_SENDING_TOKENS_WITH_FEES)
      )
      return
    }

    yield call(
      sendTokenAmount,
      amountToTransfer.toFixed().toString(),
      action.recipientWalletAddress
    )
    yield all([
      put(tokenSentSuccess(action.tokenAmount)),
      refreshWalletBalanceSaga(),
      refreshWalletHistorySaga(),
    ])
  } catch (e) {
    captureError(e)
    yield put(
      sendTokensFail(action.tokenAmount, {
        ...ERROR_SENDING_TOKENS,
        message: `${ERROR_SENDING_TOKENS.message} ${e.message}`,
      })
    )
  }
}

export function* refreshWalletBalanceSaga(): any {
  const vcxResult = yield* ensureVcxInitSuccess()
  if (vcxResult && vcxResult.fail) {
    yield take(VCX_INIT_SUCCESS)
  }
  try {
    const walletBalanceData: string = yield call(getWalletBalance)
    yield put(walletBalanceRefreshed(walletBalanceData))
    yield call(secureSet, WALLET_BALANCE, walletBalanceData)
  } catch (e) {
    captureError(e)
    yield put(
      refreshWalletBalanceFail({
        ...ERROR_REFRESHING_WALLET_BALANCE,
        message: `${ERROR_REFRESHING_WALLET_BALANCE.message} ${e.message}`,
      })
    )
  }
}

export function* refreshWalletHistorySaga(): any {
  const vcxResult = yield* ensureVcxInitSuccess()
  if (vcxResult && vcxResult.fail) {
    yield take(VCX_INIT_SUCCESS)
  }
  try {
    const walletHistoryData = yield call(getWalletHistory)
    yield put(walletHistoryRefreshed(walletHistoryData))
    yield call(secureSet, WALLET_HISTORY, JSON.stringify(walletHistoryData))
  } catch (e) {
    captureError(e)
    yield put(
      refreshWalletHistoryFail({
        ...ERROR_REFRESHING_WALLET_HISTORY,
        message: `${ERROR_REFRESHING_WALLET_HISTORY.message} ${e.message}`,
      })
    )
  }
}

export function* refreshWalletAddressesSaga(): Generator<*, *, *> {
  yield put(walletAddressesFetchStart())
  const vcxResult = yield* ensureVcxInitSuccess()
  if (vcxResult && vcxResult.fail) {
    yield take(VCX_INIT_SUCCESS)
  }
  try {
    let walletAddressesData: string[] = yield call(getWalletAddresses)
    if (walletAddressesData.length === 0) {
      // not passing any seed for now
      yield call(createPaymentAddress, null)
      // we could put recursion here as well
      // but we would have to change saga signature so that we can have
      // exit condition for recursion, for now we are just trying once
      // and if we don't get any address even after creating it
      // we won't try again
      walletAddressesData = yield call(getWalletAddresses)
    }
    yield put(walletAddressesRefreshed(walletAddressesData))
    yield call(secureSet, WALLET_ADDRESSES, JSON.stringify(walletAddressesData))
  } catch (e) {
    captureError(e)
    yield put(
      refreshWalletAddressesFail({
        ...ERROR_REFRESHING_WALLET_ADDRESSES,
        message: `${ERROR_REFRESHING_WALLET_ADDRESSES.message} ${e.message}`,
      })
    )
  }
}

export const walletBalanceRefreshed = (walletBalanceData: string) => ({
  type: WALLET_BALANCE_REFRESHED,
  walletBalance: {
    data: walletBalanceData,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
})

export const tokenSentSuccess = (tokenAmount: string) => ({
  type: TOKEN_SENT_SUCCESS,
  payment: {
    tokenAmount,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
})

export const selectTokenAmount = (tokenAmount: string) => ({
  type: SELECT_TOKEN_AMOUNT,
  payment: {
    tokenAmount,
    status: STORE_STATUS.IDLE,
    error: null,
  },
})

export const walletAddressesRefreshed = (
  walletAddressesData: Array<string>
) => ({
  type: WALLET_ADDRESSES_REFRESHED,
  walletAddresses: {
    data: walletAddressesData,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
})

export const walletAddressesFetchStart = () => ({
  type: WALLET_ADDRESSES_FETCH_START,
})

export const walletHistoryRefreshed = (walletHistoryData: any) => ({
  type: WALLET_HISTORY_REFRESHED,
  walletHistory: {
    transactions: walletHistoryData,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
})

export const refreshWalletBalance = () => ({
  type: REFRESH_WALLET_BALANCE,
})

export const refreshWalletAddresses = () => ({
  type: REFRESH_WALLET_ADDRESSES,
})

export const refreshWalletHistory = () => ({
  type: REFRESH_WALLET_HISTORY,
})

export const hydrateWalletBalanceStore = (
  walletBalanceData: HydrateWalletBalanceData
) => ({
  type: HYDRATE_WALLET_BALANCE,
  walletBalance: {
    data: walletBalanceData,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
})

export const hydrateWalletAddressesStore = (
  walletAddressesData: HydrateWalletAddressesData
) => ({
  type: HYDRATE_WALLET_ADDRESSES,
  walletAddresses: {
    data: walletAddressesData,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
})

export const hydrateWalletHistoryStore = (
  walletHistoryTransactions: HydrateWalletHistoryTransactions
) => ({
  type: HYDRATE_WALLET_HISTORY,
  walletHistory: {
    transactions: walletHistoryTransactions,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
})

export const hydrateWalletBalanceFail = (error: CustomError) => ({
  type: HYDRATE_WALLET_BALANCE_FAIL,
  error,
  status: STORE_STATUS.ERROR,
})

export const hydrateWalletAddressesFail = (error: CustomError) => ({
  type: HYDRATE_WALLET_ADDRESSES_FAIL,
  error,
  status: STORE_STATUS.ERROR,
})

export const hydrateWalletHistoryFail = (error: CustomError) => ({
  type: HYDRATE_WALLET_HISTORY_FAIL,
  error,
  status: STORE_STATUS.ERROR,
})

export const refreshWalletBalanceFail = (error: CustomError) => ({
  type: REFRESH_WALLET_BALANCE_FAIL,
  error,
  status: STORE_STATUS.ERROR,
})

export const sendTokensFail = (tokenAmount: string, error: CustomError) => ({
  type: SEND_TOKENS_FAIL,
  payment: {
    tokenAmount,
    error,
    status: STORE_STATUS.ERROR,
  },
})

export const refreshWalletAddressesFail = (error: CustomError) => ({
  type: REFRESH_WALLET_ADDRESSES_FAIL,
  error,
  status: STORE_STATUS.ERROR,
})

export const refreshWalletHistoryFail = (error: CustomError) => ({
  type: REFRESH_WALLET_HISTORY_FAIL,
  error,
  status: STORE_STATUS.ERROR,
})

export const sendTokens = (
  tokenAmount: string,
  recipientWalletAddress: string
) => ({
  type: SEND_TOKENS,
  tokenAmount,
  recipientWalletAddress,
})

export default function walletReducer(
  state: WalletStore = walletInitialState,
  action: WalletStoreAction
) {
  switch (action.type) {
    case HYDRATE_WALLET_BALANCE: {
      return {
        ...state,
        walletBalance: action.walletBalance,
      }
    }
    case HYDRATE_WALLET_ADDRESSES: {
      return {
        ...state,
        walletAddresses: action.walletAddresses,
      }
    }
    case HYDRATE_WALLET_HISTORY: {
      return {
        ...state,
        walletHistory: action.walletHistory,
      }
    }
    case HYDRATE_WALLET_BALANCE_FAIL: {
      return {
        ...state,
        walletBalance: {
          ...state.walletBalance,
          status: action.status,
          error: action.error,
        },
      }
    }
    case HYDRATE_WALLET_ADDRESSES_FAIL: {
      return {
        ...state,
        walletAddresses: {
          ...state.walletAddresses,
          status: action.status,
          error: action.error,
        },
      }
    }
    case HYDRATE_WALLET_HISTORY_FAIL: {
      return {
        ...state,
        walletHistory: {
          ...state.walletHistory,
          status: action.status,
          error: action.error,
        },
      }
    }
    case WALLET_BALANCE_REFRESHED: {
      const { walletBalance } = action
      return {
        ...state,
        walletBalance,
      }
    }
    case WALLET_ADDRESSES_REFRESHED: {
      const { walletAddresses } = action
      return {
        ...state,
        walletAddresses,
      }
    }

    case WALLET_ADDRESSES_FETCH_START:
      return {
        ...state,
        walletAddresses: {
          ...state.walletAddresses,
          status: STORE_STATUS.IN_PROGRESS,
          error: null,
        },
      }

    case WALLET_HISTORY_REFRESHED: {
      const { walletHistory } = action
      return {
        ...state,
        walletHistory,
      }
    }
    case REFRESH_WALLET_BALANCE_FAIL: {
      return {
        ...state,
        walletBalance: {
          ...state.walletBalance,
          status: action.status,
          error: action.error,
        },
      }
    }
    case REFRESH_WALLET_ADDRESSES_FAIL: {
      return {
        ...state,
        walletAddresses: {
          ...state.walletAddresses,
          status: action.status,
          error: action.error,
        },
      }
    }
    case REFRESH_WALLET_HISTORY_FAIL: {
      return {
        ...state,
        walletHistory: {
          ...state.walletHistory,
          status: action.status,
          error: action.error,
        },
      }
    }
    case BACKUP_WALLET: {
      const { status, error } = action.data
      return {
        ...state,
        backup: {
          ...state.backup,
          status,
          error,
        },
      }
    }
    case BACKUP_WALLET_PATH: {
      const { backupPath } = action
      return {
        ...state,
        backup: {
          ...state.backup,
          backupPath,
        },
      }
    }
    case BACKUP_WALLET_SUCCESS: {
      const { status, error, latest, backupPath } = action.data

      return {
        ...state,
        backup: {
          latest,
          status,
          error,
          backupPath,
        },
      }
    }
    case GET_WALLET_ENCRYPTION_KEY: {
      const { encryptionKey, status } = action.data
      return {
        ...state,
        backup: {
          ...state.backup,
          encryptionKey,
          status,
        },
      }
    }
    case BACKUP_WALLET_FAIL: {
      const { status, error } = action

      return {
        ...state,
        backup: {
          ...state.backup,
          status,
          error,
        },
      }
    }
    case TOKEN_SENT_SUCCESS: {
      const { payment } = action
      return {
        ...state,
        payment,
      }
    }

    case SEND_TOKENS:
      return {
        ...state,
        payment: {
          ...state.payment,
          status: STORE_STATUS.IN_PROGRESS,
        },
      }

    case SEND_TOKENS_FAIL: {
      const { payment } = action
      return {
        ...state,
        payment,
      }
    }
    case SELECT_TOKEN_AMOUNT: {
      const { payment } = action
      return {
        ...state,
        payment,
      }
    }

    case RESET:
      return walletInitialState
    default:
      return state
  }
}


<|start_filename|>app/home/home-constants.js<|end_filename|>
// @flow

export const FEEDBACK_TEST_ID = 'home-feedback-id-label'
export const SOVRINTOKEN_TEST_ID = 'home-sovrintoken-id-label'
export const SOVRINTOKEN_AMOUNT_TEST_ID = 'home-sovrintoken-amount'


<|start_filename|>app/components/backup-restore-passphrase/backup-restore-passphrase.js<|end_filename|>
// @flow
import React, { Component, PureComponent } from 'react'
import {
  Image,
  Keyboard,
  StyleSheet,
  TextInput,
  Dimensions,
  Platform,
} from 'react-native'
import { Container, CustomView, CustomText } from '../index'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import { color } from '../../common/styles/constant'
import {
  isBiggerThanShortDevice,
  errorBoxVerifyPassphraseContainer,
  inputBoxVerifyPassphraseHeight,
  dangerBannerHeight,
} from '../../common/styles/constant'
import type { BackupRestorePassphraseProps } from './type-backup-restore-passphrase'
import ErrorBanner from '../banner/banner-danger'

export default class BackupRestorePassphrase extends PureComponent<
  BackupRestorePassphraseProps,
  void
> {
  render() {
    const { filename, testID, onSubmit, placeholder, errorState } = this.props
    return (
      <Container
        testID={`${testID}-container`}
        style={[styles.verifyMainContainer]}
        onPress={Keyboard.dismiss}
        safeArea
      >
        <Image
          source={require('../../images/transparentBands2.png')}
          style={[styles.backgroundImageVerify]}
        />
        <KeyboardAwareScrollView extraHeight={50}>
          <Container testID={`${testID}-inputbox`}>
            <CustomView center>
              {filename ? (
                <CustomView center>
                  <Image
                    source={require('../../images/encryptedFileGreen.png')}
                  />
                  <CustomText center transparentBg h5 style={[styles.filename]}>
                    {filename}
                  </CustomText>
                </CustomView>
              ) : (
                <CustomText transparentBg center style={[styles.title]}>
                  Verify your Recovery Phrase
                </CustomText>
              )}
            </CustomView>
            <CustomView center>
              <CustomText
                center
                transparentBg
                h5
                style={[styles.verifyMainText]}
              >
                {filename
                  ? 'Enter the Recovery Phrase you used to create this backup.'
                  : 'To verify that you have copied down your recovery phrase correctly, please enter it below.'}
              </CustomText>
            </CustomView>
            {errorState ? (
              <ErrorBanner
                bannerTitle={'Recovery Phrase does not match!'}
                bannerSubtext={'Try entering it again or go back and verify'}
                style={[styles.dangerBannerBox]}
                testID={'verify-passphrase-error-banner'}
              />
            ) : null}
            <TextInput
              autoCapitalize="none"
              testID={`${testID}-text-input`}
              accessible={true}
              accessibilityLabel={`${testID}-text-input`}
              autoFocus={true}
              onSubmitEditing={onSubmit}
              style={[styles.inputBox]}
              placeholder={placeholder}
              placeholderTextColor="white"
              autoCorrect={false}
              underlineColorAndroid="transparent"
              multiline={Platform.OS === 'ios' ? true : false}
              clearButtonMode="always"
              returnKeyType="done"
              returnKeyLabel="done"
              numberOfLines={1}
            />
          </Container>
        </KeyboardAwareScrollView>
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  verifyMainContainer: {
    flex: 1,
    backgroundColor: color.bg.twelfth.color,
  },
  backgroundImageVerify: {
    flex: 1,
    position: 'absolute',
  },
  filename: {
    fontWeight: 'bold',
  },
  title: {
    fontWeight: '600',
    lineHeight: 27,
    fontSize: 22,
    marginBottom: 20,
    width: '100%',
  },
  verifyMainText: {
    paddingHorizontal: 20,
    fontSize: 18,
    lineHeight: 22,
    fontWeight: '500',
    marginTop: isBiggerThanShortDevice ? 40 : 20,
    marginBottom: isBiggerThanShortDevice ? 40 : 20,
  },
  inputBox: {
    marginBottom: 24,
    marginRight: 20,
    marginLeft: 20,
    height: inputBoxVerifyPassphraseHeight,
    backgroundColor: 'rgba(0,0,0,0.33)',
    color: 'white',
    padding: 10,
    textAlignVertical: 'top',
    fontSize: 20,
    fontStyle: 'italic',
  },
  dangerBannerBox: {
    marginLeft: 20,
    marginRight: 20,
    height: dangerBannerHeight,
  },
})


<|start_filename|>app/deep-link/type-deep-link.js<|end_filename|>
// @flow
import type { CustomError, ResetAction } from '../common/type-common'

export const DEEP_LINK_ERROR = 'DEEP_LINK_ERROR'
export const DEEP_LINK_DATA = 'DEEP_LINK_DATA'
export const DEEP_LINK_EMPTY = 'DEEP_LINK_EMPTY'
export const DEEP_LINK_PROCESSED = 'DEEP_LINK_PROCESSED'

export const DEEP_LINK_STATUS = {
  NONE: 'NONE',
  PROCESSED: 'PROCESSED',
}

export type DeepLinkDataAction = {
  type: typeof DEEP_LINK_DATA,
  data: string,
}

export type DeepLinkEmptyAction = {
  type: typeof DEEP_LINK_EMPTY,
}

export type DeepLinkProcessedAction = {
  type: typeof DEEP_LINK_PROCESSED,
  data: string,
}

export type DeepLinkErrorAction = {
  type: typeof DEEP_LINK_ERROR,
  error: ?any,
}

export type Token = {
  +status: string,
  +token: string,
  +error: ?CustomError,
}

export type DeepLinkStore = {
  tokens:
    | {
        +[string]: Token,
      }
    | {},
  isLoading: boolean,
  error: ?string,
}

export type DeepLinkAction =
  | DeepLinkDataAction
  | DeepLinkEmptyAction
  | DeepLinkErrorAction
  | ResetAction

export type DeepLinkBundle = {
  error: ?string,
  params: ?{
    ['+clicked_branch_link']: boolean,
    t: string,
  },
}

export type DeepLinkProps = {
  deepLinkData: (token: string) => void,
  deepLinkEmpty: () => void,
  deepLinkError: string => void,
  tokens: {
    [string]: Token,
  },
}


<|start_filename|>app/components/custom-list/type-custom-list.js<|end_filename|>
// @flow

import type { ImageSource } from '../../common/type-common'
import type { ClaimMap } from '../../claim/type-claim'

export type Item = {
  label: string,
  data?: string,
  claimUuid?: string,
  logoUrl?: string,
  key?: string,
}

export type CustomListProps = {
  items: Array<Item>,
  type?: string,
  claimMap?: ?ClaimMap,
  avatarSource?: ?ImageSource,
}


<|start_filename|>app/components/user-avatar/__tests__/user-avatar.spec.js<|end_filename|>
// @flow
import React from 'react'
import { View } from 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import ImagePicker from 'react-native-image-crop-picker'
import {
  getStore,
  userAvatarImagePath,
  userAvatarImageName,
} from '../../../../__mocks__/static-data'

import ConnectedUserAvatar, { UserAvatar } from '../user-avatar'
import type { GenericObject } from '../../../common/type-common'
import { getUserAvatarSource } from '../../../store/store-selector'

describe('<ConnectedUserAvatar />', () => {
  const store = getStore()

  function getProps(extraProps = {}) {
    return {
      selectUserAvatar: jest.fn(),
      ...extraProps,
    }
  }

  function setup(extraProps?: GenericObject = {}) {
    const props = getProps(extraProps)
    const component = renderer.create(<UserAvatar {...props} />)
    const instance = component.getInstance()

    return { props, component, instance }
  }

  it('should match snapshot when no user image is selected', () => {
    const { component } = setup()
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should match snapshot when user image is selected', () => {
    const component = renderer.create(
      <Provider store={store}>
        <ConnectedUserAvatar />
      </Provider>
    )
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should call children function if children is passed', () => {
    const functionAsChild = jest.fn()
    const child = avatarSource => {
      functionAsChild(avatarSource)
      return <View />
    }
    const props = getProps({
      avatarName: getUserAvatarSource(userAvatarImageName),
    })
    const component = renderer.create(
      <UserAvatar {...props}>{child}</UserAvatar>
    )
    expect(functionAsChild).toHaveBeenCalled()
    expect(functionAsChild).toHaveBeenCalledWith({
      uri: userAvatarImagePath,
    })
  })

  it('should raise select avatar action if user can change image', () => {
    const extraProps = {
      userCanChange: true,
    }
    const { instance, props } = setup(extraProps)
    instance.changeAvatar()
    expect(props.selectUserAvatar).toHaveBeenCalledWith()
  })

  it(`should not raise select avatar action if user can't change image`, () => {
    const extraProps = {
      userCanChange: false,
    }
    const { instance, props } = setup(extraProps)
    instance.changeAvatar()
    expect(props.selectUserAvatar).not.toHaveBeenCalled()
  })
})


<|start_filename|>app/components/__tests__/badge-dot.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import { Dot } from '../badges-dot'
import renderer from 'react-test-renderer'

describe('<Dot />', () => {
  it('should render with small Dot', () => {
    const dotComponent = renderer.create(<Dot size={'small'} />).toJSON()
    expect(dotComponent).toMatchSnapshot()
  })
  it('should render with medium Dot', () => {
    const dotComponent = renderer.create(<Dot size={'medium'} />).toJSON()
    expect(dotComponent).toMatchSnapshot()
  })
  it('should render with large Dot', () => {
    const dotComponent = renderer.create(<Dot size={'large'} />).toJSON()
    expect(dotComponent).toMatchSnapshot()
  })
})


<|start_filename|>app/components/loader/type-loader.js<|end_filename|>
// @flow

export const DARK = 'dark'
export const LIGHT = 'light'

export type ColorType = 'dark' | 'light'

export type LoadingIndicatorProps = {
  type: ColorType,
  size: number,
}

export type LoaderState = {
  message: string,
  show: boolean,
}

export type LoaderProps = {
  type: ColorType,
  message?: string,
  interval: any,
  timeout: number,
  delay: number,
  showMessage: boolean,
  size: number,
}


<|start_filename|>app/common/styles/tab-constants.js<|end_filename|>
// @flow
export const CURVE_WIDTH = 320
export const CURVE_HEIGHT = 200
export const ICON_WIDTH = 30
export const INNER_PADDING = 30
export const ACTIVE_ICON_WIDTH = 50
export const ICON_BACKGROUND_WIDTH = 90
export const INACTIVE_ICON_OPACITY = 0.2
export const DISABLED_ICON_OPACITY = 0


<|start_filename|>app/push-notification/__tests__/push-notification-navigator.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { homeTabRoute } from '../../common'
import { PushNotificationNavigator } from '../push-notification-navigator'
import {
  convertClaimOfferPushPayloadToAppClaimOffer,
  convertClaimPushPayloadToAppClaim,
  convertProofRequestPushPayloadToAppProofRequest,
} from '../push-notification-store'
import {
  claimOfferPushNotification,
  proofRequestPushPayloadAdditionalData,
} from '../../../__mocks__/static-data'

describe('<PushNotificationNavigator />', () => {
  let store = {}

  const storeToProps = {
    pushNotification: {
      notification: claimOfferPushNotification,
      navigateRoute: null,
    },
  }

  beforeAll(() => {
    store = {
      getState() {
        return {
          ...storeToProps,
        }
      },
      subscribe() {
        return jest.fn()
      },
      dispatch() {
        return jest.fn()
      },
    }
  })

  function props() {
    return {
      ...storeToProps,
      updatePayloadToRelevantStoreAndRedirect: jest.fn(),
      clearNavigateToRoutePN: jest.fn(),
      navigateToRoute: jest.fn(),
    }
  }

  it('should render PushNotification Navigator components properly', () => {
    const wrapper = renderer
      .create(
        <Provider store={store}>
          <PushNotificationNavigator {...props()} />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})

describe('convertProofRequestPushPayloadToAppProofRequest', () => {
  it('should convert push payload to proof request format correctly', () => {
    expect(
      convertProofRequestPushPayloadToAppProofRequest(
        proofRequestPushPayloadAdditionalData
      )
    ).toMatchSnapshot()
  })
})

describe('convertClaimPushPayloadToAppClaim', () => {
  it('should match snapshot', () => {
    const claimPushPayload = {
      msg_type: 'claim',
      version: '0.1',
      claim_offer_id: '7TNw2k5',
      from_did: '3KFuh4jmMC5Agsy5HcCwFB',
      to_did: '5RHwxmBrGxaEskHcBnLKve',
      claim: { name: ['Test', '12'] },
      schema_seq_no: 12,
      issuer_did: 'V4SGRU86Z58d6TV7PBUe6f',
      signature: { primary_claim: { m2: 'm2', a: 'a', e: 'e', v: 'v' } },
    }
    const claim = convertClaimPushPayloadToAppClaim(
      claimPushPayload,
      '1',
      claimPushPayload.to_did
    )
    expect(claim).toMatchSnapshot()
  })
})

describe('convertClaimOfferPushPayloadToAppClaimOffer', () => {
  it('should convert push payload to claim offer format correctly', () => {
    const claimOfferPushPayload = {
      msg_type: 'CLAIM_OFFER',
      version: '0.1',
      to_did: 'BnRXf8yDMUwGyZVDkSENeq',
      from_did: 'GxtnGN6ypZYgEqcftSQFnC',
      iid: 'cCanHnpFAD',
      mid: '',
      claim: {
        name: ['Alice'],
        date_of_birth: ['2000-05-17'],
        height: ['175'],
      },
      schema_seq_no: 12,
      issuer_did: 'V4SGRU86Z58d6TV7PBUe6f',
      nonce: '351590',
      claim_name: 'Profile detail',
      issuer_name: 'Test Enterprise',
      optional_data: { terms_of_service: '<Large block of text>', price: 6 },
      remoteName: 'Test remote name',
    }

    expect(
      convertClaimOfferPushPayloadToAppClaimOffer(claimOfferPushPayload)
    ).toMatchSnapshot()
  })
})


<|start_filename|>app/restore/__tests__/restore.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { RestoreStartScreen } from '../restore'
import { getNavigation, getStore } from '../../../__mocks__/static-data'
import { restorePassphraseRoute } from '../../common'

describe('Restore screen', () => {
  function getProps() {
    return {
      store: getStore(),
      navigation: getNavigation(),
      restore: getStore().getState().restore,
      route: restorePassphraseRoute,
      updateStatusBarTheme: jest.fn(),
      saveFileToAppDirectory: jest.fn(),
    }
  }

  function setup() {
    const props = getProps()
    return { props }
  }

  it('should render properly and match the snapshot', () => {
    const { props } = setup()
    const tree = renderer.create(<RestoreStartScreen {...props} />).toJSON()
    expect(tree).toMatchSnapshot()
  })

  //TODO add snapshot for error screen
})


<|start_filename|>app/lock/pin-hash.js<|end_filename|>
// @flow
import PBKDF2 from 'react-native-pbkdf2'
import { NativeModules, Platform } from 'react-native'
import { captureError } from '../services/error/error-handler'

const { RNRandomBytes } = NativeModules

const generateKey = (password: string, salt: string) =>
  PBKDF2.derivationKey(password, salt, 1000)

export const generateSalt = async () => {
  const numBytes = 32
  return new Promise(function(resolve, reject) {
    RNRandomBytes.randomBytes(numBytes, (err: any, bytes: string) => {
      if (err) {
        reject(err)
      } else {
        if (Platform.OS === 'android') {
          resolve(bytes.slice(0, -1))
        } else {
          resolve(bytes)
        }
      }
    })
  })
}

export async function pinHash(pin: string, salt: string) {
  try {
    const key = await generateKey(pin, salt)
    if (__DEV__) {
      console.log('pinHash: salt: ', salt)
      console.log('pinHash: key: ', key)
    }
    //TODO: This is hack due to android
    return key.substring(0, 16)
  } catch (e) {
    console.error(`pinHash: ${e}`)
    captureError(new Error(`pinHash: ${e}`))
    return null
  }
}


<|start_filename|>app/connection-history/connection-history.js<|end_filename|>
// @flow
import React, { Component } from 'react'
import {
  Alert,
  ScrollView,
  StyleSheet,
  Dimensions,
  View,
  StatusBar,
} from 'react-native'
import { connect } from 'react-redux'
import { List, ListItem } from 'react-native-elements'
import moment from 'moment'
import groupBy from 'lodash.groupby'
import { bindActionCreators } from 'redux'
import { updateStatusBarTheme } from '../../app/store/connections-store'
import {
  InfoSectionList,
  ClaimProofHeader,
  Container,
  ConnectionTheme,
  CustomView,
  Icon,
  CustomText,
  Separator,
  CustomDate,
  headerStyles,
} from '../components'
import { dimGray, OFFSET_9X, white } from '../../app/common/styles'
import {
  homeRoute,
  connectionHistoryRoute,
  connectionHistoryDetailsRoute,
  connectionHistoryPendingRoute,
} from '../common/route-constants'
import {
  color,
  OFFSET_1X,
  OFFSET_3X,
  alertCancel,
} from '../common/styles/constant'
import type { Store } from '../store/type-store'
import type {
  ConnectionHistoryItem,
  ConnectionHistoryProps,
  ConnectionHistoryState,
  ConnectionHistoryEvent,
} from './type-connection-history'
import {
  HISTORY_EVENT_STATUS,
  HISTORY_EVENT_OCCURRED,
} from './type-connection-history'
import type { ReactNavigation } from '../common/type-common'
import showDID from '../components/show-pairwise-info'
import {
  SEND_CLAIM_REQUEST,
  CLAIM_REQUEST_STATUS,
  SEND_CLAIM_REQUEST_SUCCESS,
} from '../claim-offer/type-claim-offer'
import { deleteConnectionAction } from '../store/connections-store'
import { getConnection, getConnectionTheme } from '../store/store-selector'
import { Dot as BadgeDot } from '../components/badges-dot'

import debounce from 'lodash.debounce'
import { getUnseenMessages } from '../store/store-selector'
import { goToUIScreen } from '../push-notification/push-notification-store'
import Color from 'color'
import { getStatusBarStyle } from '../components/custom-header/custom-header'

const statusMsg = {
  ['PENDING']: 'Pending',
  ['CONNECTED']: 'Established on',
  ['RECEIVED']: 'Accepted on',
  ['ACCEPTED & SAVED']: 'Accepted on',
  ['SHARED']: 'Sent on',
  ['PROOF RECEIVED']: 'New request to share',
  ['CLAIM OFFER RECEIVED']: 'New credential offer',
}

const historyIcons = {
  ['PENDING']: require('../images/received.png'),
  ['CONNECTED']: require('../images/linked.png'),
  ['RECEIVED']: require('../images/received.png'),
  ['CLAIM OFFER RECEIVED']: require('../images/received.png'),
  ['PROOF RECEIVED']: require('../images/received.png'),
  ['ACCEPTED & SAVED']: require('../images/received.png'),
  ['SHARED']: require('../images/sent.png'),
}

const historyShowUI = ['CLAIM OFFER RECEIVED', 'PROOF RECEIVED']

const HistoryTitle = ({ action, name, theme }) => (
  <CustomView>
    <CustomView>
      <CustomText
        h5
        semiBold
        uppercase
        bg="fifth"
        style={[styles.listItemAction, { color: theme }]}
      >
        {action && historyShowUI.indexOf(action) > -1
          ? statusMsg[action]
          : action}
      </CustomText>
    </CustomView>
    <CustomView>
      {name && (
        <CustomText
          h5
          semiBold
          bg="fifth"
          style={[styles.listItemTitleEvent, styles.listItemAction]}
        >
          {name}
        </CustomText>
      )}
    </CustomView>
  </CustomView>
)

const HistoryBody = ({ action, timestamp }) => {
  return (
    <CustomView row>
      <CustomDate h7 uppercase bg="fifth" style={[styles.listItemBody]}>
        {timestamp}
      </CustomDate>
    </CustomView>
  )
}

export class ConnectionHistory extends Component<
  ConnectionHistoryProps,
  ConnectionHistoryState
> {
  state = {
    disableTaps: false,
  }

  connectionDetailHandlerDebounce = debounce(
    ({ h, activeConnectionThemePrimary, senderName, image, senderDID }) => {
      this.connectionDetailHandler({
        h,
        activeConnectionThemePrimary,
        senderName,
        image,
        senderDID,
      })
    },
    300,
    { leading: false, trailing: true }
  )

  componentDidMount() {
    this.props.updateStatusBarTheme(this.props.activeConnectionThemePrimary)
  }

  closeDebounce = () => {
    if (!this.state.disableTaps) {
      const { navigation } = this.props

      navigation.goBack(null)
      this.setState({ disableTaps: true })
    }
  }

  connectionDetailHandler = (history: any) => {
    if (history.h.action === HISTORY_EVENT_STATUS[SEND_CLAIM_REQUEST_SUCCESS]) {
      this.props.navigation.navigate(connectionHistoryPendingRoute, {
        payload: history.h.originalPayload.payload,
      })
    } else {
      this.props.navigation.navigate(connectionHistoryDetailsRoute, {
        ...history.h,
        theme: history.activeConnectionThemePrimary,
        senderName: history.senderName,
        image: history.image,
        senderDID: history.senderDID,
        claimMap: this.props.claimMap,
      })
    }
  }

  getHistoryIcons = (action: string, showBadge?: boolean) => {
    return (
      <CustomView center>
        {}
        {showBadge && (
          <View style={[styles.badgeDotStyle]}>
            <BadgeDot size="small" />
          </View>
        )}
        <Icon
          src={historyIcons[action]}
          iconStyle={[{ tintColor: this.props.activeConnectionThemePrimary }]}
          small
        />
      </CustomView>
    )
  }

  handleRedirectionScreens(
    h: ConnectionHistoryEvent,
    activeConnectionThemePrimary: string,
    senderName: string,
    image: string,
    senderDID: string
  ) {
    if (h.showBadge || historyShowUI.indexOf(h.action) != -1) {
      this.props.goToUIScreen(
        h.originalPayload.type,
        h.originalPayload.payloadInfo.uid,
        this.props.navigation
      )
    } else {
      this.connectionDetailHandlerDebounce({
        h,
        activeConnectionThemePrimary,
        senderName,
        image,
        senderDID,
      })
    }
  }

  onDeleteConnection = (senderName: string, senderDID: string) => {
    Alert.alert(
      `Delete ${senderName}?`,
      `Are you sure you want to delete ${senderName} as a connection? You will still keep the information they have given you, but you will not be able to contact them without re-establishing a new connection. Proceed?`,
      [alertCancel, { text: 'Delete', onPress: () => this.delete(senderDID) }]
    )
  }

  delete = (senderDID: string) => {
    this.props.deleteConnectionAction(senderDID)
    this.closeDebounce()
  }

  render() {
    const { width } = Dimensions.get('window')
    if (this.props.navigation.state) {
      const {
        senderName,
        image,
        senderDID,
        identifier,
      } = this.props.navigation.state.params
      const { activeConnectionThemePrimary, connectionHistory } = this.props
      const testID = 'connection-history'
      const logoUri = image
        ? { uri: image }
        : require('../images/logo_sovrin.png')

      const historySenderDIDs = Object.keys(connectionHistory)
      const historyList = historySenderDIDs.map((sdid, i) => {
        const historyItems = connectionHistory[sdid].map((h, i) => {
          const itemProps = {
            avatar: this.getHistoryIcons(h.action, h.showBadge),
            key: h.id,
            title: <HistoryTitle {...h} theme={activeConnectionThemePrimary} />,
            subtitle: <HistoryBody {...h} />,
            chevronColor: color.bg.fifth.font.fifth,
            avatarStyle: styles.avatarStyle,
            avatarOverlayContainerStyle: styles.avatarOverlayContainerStyle,
            containerStyle: styles.listItemContainer,
            hideChevron: false,
            rightIcon:
              h.action === HISTORY_EVENT_STATUS[SEND_CLAIM_REQUEST_SUCCESS] ? (
                <Icon src={require('../images/e15c.1.png')} small />
              ) : (
                {
                  name: 'chevron-right',
                  color: dimGray,
                }
              ),
            onPress: () => {
              this.handleRedirectionScreens(
                h,
                activeConnectionThemePrimary,
                senderName,
                image,
                senderDID
              )
            },
          }

          if (h.action === 'CONNECTED') {
            itemProps.hideChevron = true
            delete itemProps.onPress
          }

          return <ListItem {...itemProps} />
        })
        const history = (
          <CustomView key={i}>
            <CustomText
              h4
              semiBold
              bg="septenary"
              style={[styles.listItemLabel]}
            >
              {sdid}
            </CustomText>
            {historyItems}
          </CustomView>
        )
        return history
      })

      return (
        <Container fifth>
          <StatusBar
            backgroundColor={this.props.activeConnectionThemePrimary}
            barStyle={getStatusBarStyle(
              this.props.activeConnectionThemePrimary
            )}
          />
          <CustomView
            style={[
              { backgroundColor: this.props.activeConnectionThemePrimary },
            ]}
          >
            <ClaimProofHeader
              message={senderName}
              onClose={this.closeDebounce}
              logoUrl={image}
              testID={testID}
              containerStyle={{ backgroundColor: 'transparent' }}
              textContainerStyle={[
                styles.textContainerStyle,
                { backgroundColor: 'transparent' },
              ]}
              messageStyle={[
                styles.senderName,
                { backgroundColor: 'transparent' },
              ]}
            >
              <CustomView
                fifth
                hCenter
                style={[
                  headerStyles.headerLogoContainer,
                  { backgroundColor: 'transparent' },
                ]}
              >
                <Icon
                  absolute="TopRight"
                  src={require('../images/close_white.png')}
                  small
                  testID={`${testID}-icon-close`}
                  onPress={this.closeDebounce}
                  iconStyle={[styles.headerCloseIcon]}
                  style={[styles.headerIconContainer]}
                />
                <Icon
                  center
                  halo
                  extraLarge
                  resizeMode="cover"
                  src={logoUri}
                  style={[styles.issuerLogo]}
                  iconStyle={[styles.issuerLogoIcon]}
                  testID={`${testID}-issuer-logo`}
                  onLongPress={() => showDID(senderDID, identifier)}
                  backgroundRoundWhite
                />
                <Icon
                  absolute="TopLeft"
                  src={require('../images/delete.png')}
                  small
                  iconStyle={[styles.headerDeleteIcon]}
                  style={[styles.headerIconContainer]}
                  resizeMode="contain"
                  testID={`${testID}-icon-delete`}
                  onPress={() => {
                    this.onDeleteConnection(senderName, senderDID)
                  }}
                />
              </CustomView>
            </ClaimProofHeader>
          </CustomView>
          <ScrollView>
            <List containerStyle={styles.listContainer}>{historyList}</List>
          </ScrollView>
        </Container>
      )
    }
  }
}

const mapStateToProps = (state: Store, props: ReactNavigation) => {
  let connectionHistory: ConnectionHistoryEvent[] =
    state.history.data && props.navigation.state
      ? state.history.data[props.navigation.state.params.senderDID]
      : []

  if (connectionHistory) {
    connectionHistory = connectionHistory.filter(history => {
      if (statusMsg[history.action]) {
        return history
      }
    })
  }

  const unSeenMessages = getUnseenMessages(state)
  if (connectionHistory) {
    connectionHistory = connectionHistory.map(history => {
      if (
        history.originalPayload &&
        history.originalPayload.payloadInfo &&
        history.originalPayload.payloadInfo.uid &&
        unSeenMessages[history.remoteDid] &&
        unSeenMessages[history.remoteDid].length > 0 &&
        unSeenMessages[history.remoteDid].indexOf(
          history.originalPayload.payloadInfo.uid
        ) >= 0
      ) {
        history.showBadge = true
      } else {
        history.showBadge = false
      }
      return history
    })
  }

  const themeForLogo = getConnectionTheme(
    state,
    props.navigation.state ? props.navigation.state.params.image : ''
  )

  return {
    activeConnectionThemePrimary: themeForLogo.primary,
    activeConnectionThemeSecondary: themeForLogo.secondary,
    connectionHistory: groupBy(
      connectionHistory.sort((a, b) => {
        return new Date(b.timestamp) - new Date(a.timestamp)
      }),
      history => moment(history.timestamp).format('MMMM YYYY')
    ),
    claimMap: state.claim.claimMap,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    { deleteConnectionAction, updateStatusBarTheme, goToUIScreen },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(ConnectionHistory)

const styles = StyleSheet.create({
  headerCloseIcon: {
    marginRight: 15,
  },
  headerIconContainer: {
    zIndex: 2,
  },
  headerDeleteIcon: {
    marginLeft: 15,
  },
  issuerLogo: {
    ...StyleSheet.absoluteFillObject,
    alignSelf: 'center',
    zIndex: 1,
  },
  textContainerStyle: {
    paddingBottom: 0,
    marginBottom: OFFSET_3X / 2,
  },
  senderName: {
    marginTop: OFFSET_1X / 2,
    color: color.bg.primary.font.primary,
  },
  issuerLogoIcon: {
    borderRadius: 40,
  },
  listContainer: {
    marginTop: 0,
    borderBottomWidth: 0,
  },
  listItemLabel: {
    paddingLeft: OFFSET_3X / 2,
    paddingVertical: OFFSET_1X,
  },
  listItemContainer: {
    borderBottomWidth: 1,
  },
  listItemAction: {
    marginLeft: OFFSET_1X,
    marginBottom: OFFSET_1X / 2,
  },
  listItemTitleEvent: {
    color: color.bg.fifth.font.fifth,
  },
  listItemBody: {
    marginLeft: OFFSET_1X,
  },
  avatarStyle: {
    width: 17,
    height: 17,
    marginVertical: OFFSET_1X,
    resizeMode: 'contain',
  },
  avatarOverlayContainerStyle: { backgroundColor: 'transparent' },
  badgeDotStyle: {
    marginBottom: 5,
  },
  issuerLogoHaloStyle: {
    backgroundColor: white,
  },
})


<|start_filename|>app/push-notification/__tests__/push-notification.spec.js<|end_filename|>
// @flow
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { PushNotification } from '../push-notification'
import { getStore } from '../../../__mocks__/static-data'

// mock connected component
jest.mock('../push-notification-navigator', () => 'PushNotificationNavigator')

describe('<PushNotification />', () => {
  const store = getStore()

  function props() {
    return {
      navigateToRoute: jest.fn(),
      fetchAdditionalData: jest.fn(),
      pushNotificationPermissionAction: jest.fn(),
      updatePushToken: jest.fn(),
      isAllowed: false,
    }
  }

  it('should render PushNotification Navigator components properly', () => {
    const wrapper = renderer
      .create(
        <Provider store={store}>
          <PushNotification {...props()} />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>connectMeUITest/src/pageObjects/ChooseLockPage.java<|end_filename|>
package pageObjects;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

/**
 * Created by ankurmishra on 6/22/17.
 */
public class ChooseLockPage {
	
	AppiumDriver driver;

	private static WebElement element = null;

	public static WebElement PinCodeLock_Button(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.name("pin-code-selection-touchable"));
			System.out.println("Pin Code Selection Button is displayed");
			return element;
		} catch (Exception e) {

			System.out.println(" Pin Code Selection Button is not displayed");
			throw (e);
		}
	}

}


<|start_filename|>app/components/keyboard/keyboard.js<|end_filename|>
// @flow

import React, { Component } from 'react'
import { Animated, TouchableWithoutFeedback } from 'react-native'
import { CustomView, CustomText, Container } from '../../components'
import type { KeyboardProps } from './type-keyboard'
import {
  KEYBOARD_TEST_ID,
  SPECIAL_DECIMAL_FORMAT,
  BACK_SPACE_SYMBOL,
  BACK_SPACE,
  MAX_LENGTH,
  DECIMAL,
  ZERO,
  ONE,
  TWO,
  THREE,
  FOUR,
  FIVE,
  SIX,
  SEVEN,
  EIGHT,
  NINE,
} from './keyboard-constants'
import { styles, INPUT_RANGE, OUTPUT_RANGE } from './styles'
import { WALLET_BALANCE } from '../../common'
import { BigNumber } from 'bignumber.js'

export default class Keyboard extends Component<KeyboardProps, void> {
  originalOptions: Array<string>
  _animation: any
  _walletBalance: BigNumber = new BigNumber('0')
  text: string = ''

  constructor(props: KeyboardProps) {
    super(props)
    this.originalOptions = [
      ONE,
      TWO,
      THREE,
      FOUR,
      FIVE,
      SIX,
      SEVEN,
      EIGHT,
      NINE,
      DECIMAL,
      ZERO,
      BACK_SPACE_SYMBOL,
    ]
    this._animation = this.originalOptions.map(i => new Animated.Value(0))
  }

  static defaultProps = {
    maxLength: 20,
  }

  animation = (key: string) => {
    const animationKey = this.originalOptions.indexOf(key)

    this._animation[animationKey].setValue(0)
    Animated.spring(this._animation[animationKey], {
      speed: 120,
      toValue: 1,
      bounciness: 10,
      overshootClamping: false,
    }).start(() => {
      this._animation[animationKey].setValue(0)
    })
  }

  Backspace(symbol: string) {
    const animationKey = this.originalOptions.indexOf(symbol)
    const textSize = this._animation[animationKey].interpolate({
      inputRange: INPUT_RANGE,
      outputRange: OUTPUT_RANGE,
    })
    return (
      <Container
        accessibilityLabel={BACK_SPACE}
        center
        testID={`${KEYBOARD_TEST_ID}-back-space`}
        onPress={() => {
          this.onPress(BACK_SPACE_SYMBOL)
        }}
      >
        <CustomText
          transparentBg
          animated
          allowFontScaling
          center
          style={[
            styles.number,
            { color: this.props.color, fontSize: textSize },
          ]}
        >
          {symbol}
        </CustomText>
      </Container>
    )
  }

  Row(numbersArray: Array<string>) {
    const rowStyle = numbersArray.includes(ONE) ? styles.firstRow : styles.row
    let cells = numbersArray.map(val => this.Cell(val))

    return (
      <CustomView row style={[rowStyle]}>
        {cells}
      </CustomView>
    )
  }

  Cell(symbol: string) {
    const animationKey = this.originalOptions.indexOf(symbol)
    const { maxLength } = this.props
    const textSize = this._animation[animationKey].interpolate({
      inputRange: INPUT_RANGE,
      outputRange: OUTPUT_RANGE,
    })
    return (
      <TouchableWithoutFeedback
        key={symbol}
        testID={`${KEYBOARD_TEST_ID}-${symbol}`}
        accessible={true}
        accessibilityLabel={`${KEYBOARD_TEST_ID}-${symbol}`}
        onPressIn={() => {
          maxLength && maxLength > this.text.length
            ? this.onPress(symbol)
            : this.onPress(symbol, MAX_LENGTH)
        }}
      >
        <Container center>
          <CustomText
            transparentBg
            allowFontScaling
            animated
            center
            style={[
              styles.number,
              { color: this.props.color, fontSize: textSize },
            ]}
          >
            {symbol}
          </CustomText>
        </Container>
      </TouchableWithoutFeedback>
    )
  }

  onPress(key: string, MAX_LENGTH: ?string) {
    this.animation(key)

    const text = this.text
    const NO_DECIMAL = !text.includes(DECIMAL)
    const HAS_INPUT = text.length

    let curText: string = text

    let isAfterDecimalMaxLengthReached = false
    if (!NO_DECIMAL) {
      // if user has already entered decimal separator, then we need to validate
      // length after decimal separator does not exceed set value in props
      const afterDecimalSeparatorText = text.split(DECIMAL)
      if (afterDecimalSeparatorText.length === 2) {
        // there can be only two values after we split string with a valid
        // decimal number
        isAfterDecimalMaxLengthReached =
          afterDecimalSeparatorText[1].length ===
          this.props.afterDecimalSeparatorMaxLength
      }
    }

    if (this.props.customKeyboard) {
      let animate = false
      const manualUpdatedText: string =
        key === BACK_SPACE_SYMBOL ? curText.slice(0, -1) : (curText += key)
      this.text = manualUpdatedText
      return this.props.onPress(manualUpdatedText, animate)
    }

    if (
      MAX_LENGTH ||
      (isAfterDecimalMaxLengthReached && key !== BACK_SPACE_SYMBOL)
    ) {
      const animate = true
      this.text = curText

      return this.props.onPress(curText, animate)
    } else if (key === BACK_SPACE_SYMBOL) {
      const updatedText =
        curText === SPECIAL_DECIMAL_FORMAT
          ? (curText = '')
          : curText.slice(0, -1)
      // animate if backspace is pressed with nothing stored in text
      const animate = HAS_INPUT ? false : true

      this.text = updatedText

      return this.props.onPress(updatedText, animate)
    } else if (key === DECIMAL) {
      // only allow one decimal place
      const updatedText = HAS_INPUT
        ? NO_DECIMAL ? (curText += key) : curText
        : SPECIAL_DECIMAL_FORMAT
      const animate = HAS_INPUT ? (NO_DECIMAL ? false : true) : false

      this.text = updatedText

      return this.props.onPress(updatedText, animate)
    } else if (key === ZERO && !HAS_INPUT) {
      const animate = true
      this.text = text

      return this.props.onPress(text, animate)
    } else {
      let updatedText: string = (curText += key)
      let animate = false
      const previousEnteredValue = new BigNumber(this.text)
      const updatedEnteredValue = new BigNumber(updatedText)
      if (previousEnteredValue.isEqualTo(this._walletBalance)) {
        animate = true
        updatedText = this.props.maxValue
      } else if (updatedEnteredValue.isGreaterThan(this._walletBalance)) {
        updatedText = this.props.maxValue
      }
      this.text = updatedText
      return this.props.onPress(updatedText, animate)
    }
  }

  clear() {
    this.text = ''
  }

  componentDidMount() {
    this._walletBalance = new BigNumber(this.props.maxValue)
  }

  render() {
    return (
      <CustomView left style={[styles.container]}>
        {this.Row([ONE, TWO, THREE])}
        {this.Row([FOUR, FIVE, SIX])}
        {this.Row([SEVEN, EIGHT, NINE])}
        <CustomView row style={[styles.row]}>
          {this.props.showDecimal ? <Container /> : this.Cell(DECIMAL)}
          {this.Cell(ZERO)}
          {this.Backspace(BACK_SPACE_SYMBOL)}
        </CustomView>
      </CustomView>
    )
  }

  componentDidUpdate(prevProps: KeyboardProps) {
    if (this.props.maxValue !== prevProps.maxValue) {
      this._walletBalance = new BigNumber(this.props.maxValue)
    }
  }
}


<|start_filename|>app/lock/__tests__/lock-enter-pin-code.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { CHECK_PIN_IDLE, CHECK_PIN_FAIL, CHECK_PIN_SUCCESS } from '../type-lock'
import { LockEnterPin } from '../lock-enter-pin-code'
import {
  homeRoute,
  claimOfferRoute,
  lockPinSetupRoute,
  lockEnterPinRoute,
} from '../../common'
import {
  getStore,
  getNavigation,
  pendingRedirection,
} from '../../../__mocks__/static-data'

describe('<LockPinCodeEnter />', () => {
  const getProps = (pinStatus = CHECK_PIN_IDLE) => ({
    existingPin: true,
    pendingRedirection,
    navigation: {
      ...getNavigation(),
    },
    clearPendingRedirect: jest.fn(),
    unlockApp: jest.fn(),
    isFetchingInvitation: false,
    isAppLocked: true,
    inRecovery: 'false',
    currentScreen: lockEnterPinRoute,
  })

  let component
  let props
  let cleared
  let store
  let componentInstance

  const options = {
    createNodeMock: element => {
      return {
        clear: () => {
          cleared = true
        },
      }
    },
  }

  beforeEach(() => {
    props = getProps()
    store = getStore()

    component = renderer.create(
      <Provider store={store}>
        <LockEnterPin {...props} />
      </Provider>,
      options
    )
    componentInstance = component.root.findByType(LockEnterPin).instance
  })

  it('should render pin code box', () => {
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should navigate to pin setup onSuccess', () => {
    componentInstance.onSuccess()
    componentInstance.keyboardHideState()
    expect(props.navigation.push).toHaveBeenCalledWith(lockPinSetupRoute, {
      existingPin: true,
    })
  })

  it('redirect to pendingRedirection', () => {
    component.update(
      <Provider store={store}>
        <LockEnterPin {...props} existingPin={false} />
      </Provider>
    )
    jest.useFakeTimers()
    componentInstance.onSuccess()
    jest.runAllTimers()
    expect(props.navigation.navigate).toHaveBeenCalledTimes(2)
    expect(props.clearPendingRedirect).toHaveBeenCalled()
  })
})


<|start_filename|>app/lock/__tests__/lock-store.spec.js<|end_filename|>
// @flow
import { put, call } from 'redux-saga/effects'
import type { LockStore } from '../type-lock'
import {
  SET_PIN,
  CHECK_PIN,
  CHECK_PIN_IDLE,
  LOCK_ENABLE,
  PIN_ENABLED_KEY,
  IN_RECOVERY,
  PIN_HASH,
  SALT,
} from '../type-lock'
import lockReducer, {
  addPendingRedirection,
  clearPendingRedirect,
  setPin,
  lockEnable,
  checkPin,
  checkPinSuccess,
  checkPinFail,
  setPinAction,
  checkPinStatusIdle,
  checkPinAction,
  setInRecovery,
} from '../lock-store'
import {
  secureSet,
  secureGet,
  safeSet,
  safeGet,
  getHydrationItem,
} from '../../services/storage'
import { generateSalt, pinHash } from '../pin-hash'
import { VCX_INIT_SUCCESS } from '../../store/type-config-store'
import { expectSaga } from 'redux-saga-test-plan'
import * as matchers from 'redux-saga-test-plan/matchers'
import { throwError } from 'redux-saga-test-plan/providers'
import { configStoreHydratedInstalledVcxInitSuccess } from '../../../__mocks__/data/config-store-mock-data'

const initialState: LockStore = {
  pendingRedirection: null,
  checkPinStatus: CHECK_PIN_IDLE,
  // we are assuming that app will be locked by default
  // and it will be unlocked either when user set security first time
  // or user unlock the app every time user opens the app
  // this property needs to be set accordingly
  isAppLocked: true,
  showDevMode: false,
  isLockEnabled: 'false',
  isTouchIdEnabled: false,
  inRecovery: 'false',
}

describe('LockStore', () => {
  it('add pending redirection change state correctly', () => {
    const expectedState = lockReducer(
      initialState,
      addPendingRedirection([{ routeName: 'home' }])
    )
    expect(expectedState).toMatchSnapshot()
  })

  it('clear pending redirect if clear action is raised', () => {
    const pendingState = lockReducer(
      initialState,
      addPendingRedirection([{ routeName: 'home' }])
    )
    const expectedState = lockReducer(pendingState, clearPendingRedirect())
    expect(expectedState).toMatchSnapshot()
  })

  it('set pin should work fine', () => {
    const pin = '123456'
    const salt = '<PASSWORD>'
    const hashedPin = 'some-hash'

    return expectSaga(setPin, setPinAction(pin))
      .provide([
        [matchers.call.fn(generateSalt), salt],
        [matchers.call.fn(pinHash, pin, salt), hashedPin],
      ])
      .call(secureSet, PIN_HASH, hashedPin)
      .call(secureSet, SALT, salt)
      .call(safeSet, PIN_ENABLED_KEY, 'true')
      .call(safeSet, IN_RECOVERY, 'false')
      .put(lockEnable('true'))
      .run()
  })

  it('check pin flow should work if correct pin is passed', () => {
    const pin = '123456'
    const salt = '<PASSWORD>'
    const expectedPinHash = 'expectedPinHash'

    return expectSaga(checkPin, checkPinAction(pin))
      .provide([
        [matchers.call.fn(safeGet, IN_RECOVERY), null],
        [call(getHydrationItem, SALT), salt],
        [call(getHydrationItem, PIN_HASH), expectedPinHash],
        [matchers.call.fn(pinHash, pin, salt), expectedPinHash],
      ])
      .put(checkPinSuccess())
      .run()
  })

  it('check pin flow should work if correct pin is passed in recovery', () => {
    const pin = '123456'
    const salt = '<PASSWORD>'
    const expectedPinHash = 'expectedPinHash'

    return expectSaga(checkPin, checkPinAction(pin))
      .withState({ config: configStoreHydratedInstalledVcxInitSuccess })
      .provide([
        [matchers.call.fn(safeGet, IN_RECOVERY), 'true'],
        [call(getHydrationItem, SALT), salt],
        [call(getHydrationItem, PIN_HASH), expectedPinHash],
        [matchers.call.fn(pinHash, pin, salt), expectedPinHash],
      ])
      .call(safeSet, IN_RECOVERY, 'false')
      .put(setInRecovery('false'))
      .put(checkPinSuccess())
      .run()
  })

  it('check pin flow should fail if incorrect pin is passed', () => {
    const pin = '123456'
    const salt = '<PASSWORD>'
    const expectedPinHash = 'expectedPinHash'
    const enteredPinHash = 'enteredPinHash'

    return expectSaga(checkPin, checkPinAction(pin))
      .provide([
        [matchers.call.fn(safeGet, IN_RECOVERY), null],
        [call(getHydrationItem, SALT), salt],
        [call(getHydrationItem, PIN_HASH), expectedPinHash],
        [matchers.call.fn(pinHash, pin, salt), enteredPinHash],
      ])
      .put(checkPinFail())
      .run()
  })

  it('should set checkPinStatus to idle', () => {
    const failedState = lockReducer(initialState, checkPinFail())
    expect(failedState).toMatchSnapshot()
    const expectedState = lockReducer(failedState, checkPinStatusIdle())
    expect(expectedState).toMatchSnapshot()
  })
})


<|start_filename|>app/components/vector-icon/vector-icon.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import Svg, { Path } from 'react-native-svg'
import { ICON_PATHS } from './type-vector-icon'
import type { VectorIconProps } from './type-vector-icon'
import { color } from '../../common/styles/constant'

export default class VectorIcon extends PureComponent<VectorIconProps, void> {
  static defaultProps = {
    fill: color.actions.font.primary,
    width: 25,
    height: 25,
  }

  render() {
    const { width, height, icon, fill } = this.props

    return (
      <Svg width={width} height={height} viewBox="0 0 1200 1200">
        <Path d={ICON_PATHS[icon]} fill={fill} />
      </Svg>
    )
  }
}


<|start_filename|>app/sms-pending-invitation/__tests__/sms-pending-invitation-store.spec.js<|end_filename|>
// @flow
import { call, select, put, take } from 'redux-saga/effects'
import {
  getAgencyUrl,
  getCurrentScreen,
  getHydrationState,
} from '../../store/store-selector'
import smsPendingInvitationReducer, {
  callSmsPendingInvitationRequest,
  convertSmsPayloadToInvitation,
  smsPendingInvitationFail,
  smsPendingInvitationReceived,
  getSmsPendingInvitation,
  smsPendingInvitationSeen,
} from '../sms-pending-invitation-store'
import {
  SMSPendingInvitationStatus,
  SAFE_TO_DOWNLOAD_SMS_INVITATION,
} from '../type-sms-pending-invitation'
import { getInvitationLink, invitationDetailsRequest } from '../../api/api'
import { PENDING_CONNECTION_REQUEST_CODE } from '../../api/api-constants'
import { initialTestAction } from '../../common/type-common'
import { invitationReceived } from '../../invitation/invitation-store'
import {
  smsDownloadedPayload as payload,
  smsToken,
  getStore,
} from '../../../__mocks__/static-data'
import { HYDRATED } from '../../store/type-config-store'
import { lockSelectionRoute } from '../../common/route-constants'

describe('SMS Connection Request store', () => {
  const initialState = {}
  const smsToken = 'gm<PASSWORD>'
  const store = getStore()

  const getPendingInvitationState = state =>
    smsPendingInvitationReducer(state, getSmsPendingInvitation(smsToken))

  it('should be correct initial state', () => {
    const actualInitialState = smsPendingInvitationReducer(
      undefined,
      initialTestAction()
    )
    expect(actualInitialState).toEqual(initialState)
  })

  it('should update store when pending invitation is requested', () => {
    const nextState = getPendingInvitationState(initialState)

    expect(nextState).toMatchSnapshot()
  })

  it('should update store when invitation received', () => {
    const invitationRequestedState = getPendingInvitationState(initialState)
    const nextState = smsPendingInvitationReducer(
      invitationRequestedState,
      smsPendingInvitationReceived(smsToken, payload)
    )

    expect(nextState).toMatchSnapshot()
  })

  it('should update store when invitation receive fail', () => {
    const invitationRequestedState = getPendingInvitationState(initialState)
    const nextState = smsPendingInvitationReducer(
      invitationRequestedState,
      smsPendingInvitationFail(smsToken, {
        code: 'TEST-FAIL',
        message: 'Test fail message',
      })
    )

    expect(nextState).toMatchSnapshot()
  })

  it('should update store when invitation is seen', () => {
    const invitationRequestedState = getPendingInvitationState(initialState)
    const afterReceived = smsPendingInvitationReducer(
      invitationRequestedState,
      smsPendingInvitationReceived(smsToken, payload)
    )
    const nextState = smsPendingInvitationReducer(
      afterReceived,
      smsPendingInvitationSeen(smsToken)
    )

    expect(nextState).toMatchSnapshot()
  })

  it('sms invitation download workflow should work fine if api returns success', () => {
    const gen = callSmsPendingInvitationRequest(
      getSmsPendingInvitation(smsToken)
    )

    expect(gen.next().value).toEqual(select(getCurrentScreen))
    // we are explicitly adding test dependency on getCurrentScreen
    // so that if someone changes this selector or store state/structure
    // they should know that this part of app breaks if we change this selector
    expect(getCurrentScreen(store.getState())).toMatchSnapshot()

    expect(gen.next(lockSelectionRoute).value).toEqual(
      take(SAFE_TO_DOWNLOAD_SMS_INVITATION)
    )

    expect(gen.next().value).toEqual(select(getHydrationState))
    // again add explicit test dependency on selector, so that this test breaks
    // if any change is done for selector or store/structure
    expect(getHydrationState(store.getState())).toMatchSnapshot()

    expect(gen.next(false).value).toEqual(take(HYDRATED))

    expect(gen.next().value).toEqual(select(getAgencyUrl))
    const agencyUrl = 'http://test-agency.com'

    expect(gen.next(agencyUrl).value).toEqual(
      call(getInvitationLink, {
        agencyUrl,
        smsToken,
      })
    )

    const invitationData = { url: 'http://enterprise-agency.com' }

    expect(gen.next(invitationData).value).toEqual(
      call(invitationDetailsRequest, {
        url: invitationData.url,
      })
    )
    expect(gen.next(payload).value).toEqual(
      put(
        invitationReceived({
          payload: convertSmsPayloadToInvitation(payload),
        })
      )
    )

    expect(gen.next().value).toEqual(
      put(smsPendingInvitationReceived(smsToken, payload))
    )

    expect(gen.next().done).toBe(true)
  })

  //TODO : need to add test cases for multiple test cases whhen code is refactored.

  it('sms invitation download error should raise fail action', () => {
    const error = {
      code: 'OCS',
      message: 'sms connection pending request api error',
    }

    const gen = callSmsPendingInvitationRequest(
      getSmsPendingInvitation(smsToken)
    )

    // Need to find better way to share common tests for sagas
    // and common way forward

    expect(gen.next().value).toEqual(select(getCurrentScreen))
    // we are explicitly adding test dependency on getCurrentScreen
    // so that if someone changes this selector or store state/structure
    // they should know that this part of app breaks if we change this selector
    expect(getCurrentScreen(store.getState())).toMatchSnapshot()

    expect(gen.next(lockSelectionRoute).value).toEqual(
      take(SAFE_TO_DOWNLOAD_SMS_INVITATION)
    )

    expect(gen.next().value).toEqual(select(getHydrationState))
    // again add explicit test dependency on selector, so that this test breaks
    // if any change is done for selector or store/structure
    expect(getHydrationState(store.getState())).toMatchSnapshot()

    expect(gen.next(false).value).toEqual(take(HYDRATED))

    expect(gen.next().value).toEqual(select(getAgencyUrl))
    const agencyUrl = 'http://test-agency.com'

    expect(gen.next(agencyUrl).value).toEqual(
      call(getInvitationLink, {
        agencyUrl,
        smsToken,
      })
    )

    expect(gen.throw(new Error(JSON.stringify(error))).value).toEqual(
      put(smsPendingInvitationFail(smsToken, error))
    )

    expect(gen.next().done).toBe(true)
  })

  it('should reset store, if RESET action is raised', () => {
    const afterInvitationReceivedState = getPendingInvitationState(initialState)
    expect(
      smsPendingInvitationReducer(afterInvitationReceivedState, {
        type: 'RESET',
      })
    ).toMatchSnapshot()
  })
})


<|start_filename|>app/push-notification/push-notification-navigator.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Platform } from 'react-native'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'

import type {
  PushNotificationNavigatorProps,
  NextPropsPushNotificationNavigator,
  ClaimOfferPushPayload,
  AdditionalDataPayload,
  ClaimPushPayload,
} from './type-push-notification'
import {
  updatePayloadToRelevantStoreAndRedirect,
  clearNavigateToRoutePN,
} from './push-notification-store'
import type {
  NavigationParams,
  NotificationPayload,
} from '../common/type-common'
import type { Claim } from '../claim/type-claim'
import type {
  ProofRequestPushPayload,
  AdditionalProofDataPayload,
} from '../proof-request/type-proof-request'

export class PushNotificationNavigator extends PureComponent<
  PushNotificationNavigatorProps,
  void
> {
  componentWillReceiveProps(nextProps: PushNotificationNavigatorProps) {
    if (
      nextProps.pushNotification.notification &&
      nextProps.pushNotification.notification !==
        this.props.pushNotification.notification
    ) {
      this.props.updatePayloadToRelevantStoreAndRedirect(
        nextProps.pushNotification.notification
      )
    }
    if (
      nextProps.pushNotification.navigateRoute &&
      nextProps.pushNotification.navigateRoute !==
        this.props.pushNotification.navigateRoute
    ) {
      const { routeName, params } = nextProps.pushNotification.navigateRoute
      this.props.clearNavigateToRoutePN()
      this.props.navigateToRoute(routeName, params)
    }
  }

  render() {
    return null
  }
}

const mapStateToProps = ({ pushNotification, route, lock }) => ({
  pushNotification,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      updatePayloadToRelevantStoreAndRedirect,
      clearNavigateToRoutePN,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(
  PushNotificationNavigator
)


<|start_filename|>app/wallet/__tests__/wallet-store.spec.js<|end_filename|>
// @flow
import { put, call, select, all } from 'redux-saga/effects'
import walletReducer, {
  refreshWalletHistory,
  hydrateWalletStoreSaga,
  hydrateWalletBalanceSaga,
  hydrateWalletAddressesSaga,
  hydrateWalletHistorySaga,
  walletBalanceRefreshed,
  walletAddressesRefreshed,
  walletHistoryRefreshed,
  hydrateWalletBalanceStore,
  hydrateWalletAddressesStore,
  hydrateWalletHistoryStore,
  hydrateWalletBalanceFail,
  hydrateWalletAddressesFail,
  hydrateWalletHistoryFail,
  refreshWalletBalanceFail,
  refreshWalletAddressesFail,
  backupWalletFail,
  walletBackup,
  walletBackupComplete,
  sendTokensFail,
  walletInitialState,
  getAmountToTransfer,
  sendTokens,
  sendTokensSaga,
  tokenSentSuccess,
} from '../wallet-store'
import { initialTestAction } from '../../common/type-common'
import {
  walletBalance,
  walletAddresses,
  walletHistory,
} from '../../../__mocks__/static-data'
import {
  ERROR_LOADING_WALLET,
  ERROR_REFRESHING_WALLET_BALANCE,
  STORE_STATUS,
  ERROR_BACKUP_WALLET,
  ERROR_BACKUP_WALLET_SHARE,
  ERROR_LOADING_WALLET_BALANCE,
  ERROR_LOADING_WALLET_ADDRESSES,
  ERROR_LOADING_WALLET_HISTORY,
  ERROR_REFRESHING_WALLET_ADDRESSES,
  ERROR_REFRESHING_WALLET_HISTORY,
  ERROR_SENDING_TOKENS,
  ERROR_SENDING_TOKENS_WITH_FEES,
} from '../type-wallet'
import { WALLET_BALANCE, WALLET_ADDRESSES, WALLET_HISTORY } from '../../common'
import { getHydrationItem } from '../../services/storage'
import { expectSaga } from 'redux-saga-test-plan'
import * as matchers from 'redux-saga-test-plan/matchers'
import {
  getLedgerFees,
  sendTokenAmount,
} from '../../bridge/react-native-cxs/RNCxs'
import BigNumber from 'bignumber.js'
import { VCX_INIT_SUCCESS } from '../../store/type-config-store'

describe('store: wallet-store: ', () => {
  let initialState

  beforeEach(() => {
    initialState = walletInitialState
  })

  it('action: BACKUP_WALLET', () => {
    expect(walletReducer(initialState, walletBackup())).toMatchSnapshot()
  })

  it('action: BACKUP_WALLET_SUCCESS', () => {
    expect(
      walletReducer(initialState, walletBackupComplete('hibob'))
    ).toMatchSnapshot()
  })

  it('action: ERROR_BACKUP_WALLET', () => {
    expect(
      walletReducer(initialState, backupWalletFail(ERROR_BACKUP_WALLET))
    ).toMatchSnapshot()
  })

  it('action: ERROR_BACKUP_WALLET_SHARE', () => {
    expect(
      walletReducer(initialState, backupWalletFail(ERROR_BACKUP_WALLET_SHARE))
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_BALANCE', () => {
    expect(
      walletReducer(initialState, hydrateWalletBalanceStore(walletBalance.data))
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_ADDRESSES', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletAddressesStore(walletAddresses.data)
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_HISTORY', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletHistoryStore(walletHistory.transactions)
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_BALANCE_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletBalanceFail(ERROR_LOADING_WALLET_BALANCE)
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_ADDRESSES_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletAddressesFail({ ...ERROR_LOADING_WALLET_ADDRESSES })
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_HISTORY_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletHistoryFail({ ...ERROR_LOADING_WALLET_HISTORY })
      )
    ).toMatchSnapshot()
  })

  it('action: WALLET_BALANCE_REFRESHED', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletBalanceFail({ ...ERROR_LOADING_WALLET_BALANCE })
      )
    ).toMatchSnapshot()
  })

  it('action: WALLET_ADDRESSES_REFRESHED', () => {
    expect(
      walletReducer(
        initialState,
        walletAddressesRefreshed(walletAddresses.data)
      )
    ).toMatchSnapshot()
  })

  it('action: WALLET_HISTORY_REFRESHED', () => {
    expect(
      walletReducer(
        initialState,
        walletHistoryRefreshed(walletHistory.transactions)
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_BALANCE_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletBalanceFail(ERROR_LOADING_WALLET_BALANCE)
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_ADDRESSES_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletAddressesFail(ERROR_LOADING_WALLET_ADDRESSES)
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_WALLET_HISTORY_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        hydrateWalletHistoryFail(ERROR_LOADING_WALLET_HISTORY)
      )
    ).toMatchSnapshot()
  })

  it('action: WALLET_BALANCE_REFRESHED', () => {
    expect(
      walletReducer(initialState, walletBalanceRefreshed(walletBalance.data))
    ).toMatchSnapshot()
  })

  it('action: WALLET_ADDRESSES_REFRESHED', () => {
    expect(
      walletReducer(
        initialState,
        walletAddressesRefreshed(walletAddresses.data)
      )
    ).toMatchSnapshot()
  })

  it('action: WALLET_HISTORY_REFRESHED', () => {
    expect(
      walletReducer(
        initialState,
        walletHistoryRefreshed(walletHistory.transactions)
      )
    ).toMatchSnapshot()
  })

  it('action: REFRESH_WALLET_BALANCE_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        refreshWalletBalanceFail(ERROR_REFRESHING_WALLET_BALANCE)
      )
    ).toMatchSnapshot()
  })

  it('action: REFRESH_WALLET_ADDRESSES_FAIL', () => {
    expect(
      walletReducer(
        initialState,
        refreshWalletAddressesFail(ERROR_REFRESHING_WALLET_ADDRESSES)
      )
    ).toMatchSnapshot()
  })

  it('action: SEND_TOKENS_FAIL', () => {
    expect(
      walletReducer(initialState, sendTokensFail('5656', ERROR_SENDING_TOKENS))
    ).toMatchSnapshot()
  })

  it('action: SEND_TOKENS_FAIL', () => {
    expect(
      walletReducer(initialState, sendTokensFail('5656', ERROR_SENDING_TOKENS))
    ).toMatchSnapshot()
  })

  it('saga: hydrateWalletStoreSaga => success', () => {
    const gen = hydrateWalletStoreSaga()
    expect(gen.next().value).toEqual(
      all([
        call(hydrateWalletBalanceSaga),
        call(hydrateWalletAddressesSaga),
        call(hydrateWalletHistorySaga),
      ])
    )
  })

  it('saga: hydrateWalletBalanceSaga => success', () => {
    const walletBalance = '1'

    return expectSaga(hydrateWalletBalanceSaga)
      .provide([
        [matchers.call.fn(getHydrationItem, WALLET_BALANCE), walletBalance],
      ])
      .put(hydrateWalletBalanceStore(walletBalance))
      .run()
  })

  function testGetAmountToTransfer(tokenAmountToTransfer: *, ledgerFees: *) {
    const walletBalance = '1'

    return expectSaga(
      getAmountToTransfer,
      sendTokens(tokenAmountToTransfer, 'recipient-address')
    )
      .withState({
        wallet: { walletBalance: { data: walletBalance } },
      })
      .provide([[matchers.call.fn(getLedgerFees), ledgerFees]])
      .run()
      .then(finalAmount => {
        expect(finalAmount.returnValue.toJSON()).toMatchSnapshot()
      })
  }

  it('getAmountToTransfer, transfer whole balance, fees zero', () => {
    const tokenAmountToTransfer = '1'
    const ledgerFees = {
      transfer: '0',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('getAmountToTransfer, transfer whole balance, fees equal to wallet balance', () => {
    const tokenAmountToTransfer = '1'
    const ledgerFees = {
      transfer: '1',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('getAmountToTransfer, transfer whole balance, fees greater than wallet balance', () => {
    const tokenAmountToTransfer = '1'
    const ledgerFees = {
      transfer: '1',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('getAmountToTransfer, transfer whole balance, fees more than zero less than wallet balance', () => {
    const tokenAmountToTransfer = '1'
    const ledgerFees = {
      transfer: '0.1',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('getAmountToTransfer, transfer less than wallet balance, fees zero', () => {
    const tokenAmountToTransfer = '0.5'
    const ledgerFees = {
      transfer: '0',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('getAmountToTransfer, transfer less than wallet balance, fees + transfer more than wallet balance ', () => {
    const tokenAmountToTransfer = '0.5'
    const ledgerFees = {
      transfer: '0.6',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('getAmountToTransfer, transfer less than wallet balance, fees + transfer equal to wallet balance ', () => {
    const tokenAmountToTransfer = '0.5'
    const ledgerFees = {
      transfer: '0.5',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('getAmountToTransfer, transfer less than wallet balance, fees + transfer less than wallet balance ', () => {
    const tokenAmountToTransfer = '0.5'
    const ledgerFees = {
      transfer: '0.3',
    }

    return testGetAmountToTransfer(tokenAmountToTransfer, ledgerFees)
  })

  it('saga: sendTokensSaga => success', () => {
    const walletBalance = '1'
    const stateWithVcxInitSuccess = {
      config: {
        vcxInitializationState: VCX_INIT_SUCCESS,
      },
      wallet: { walletBalance: { data: walletBalance } },
    }
    const tokenAmount = '0.9'
    const recipientAddress = 'recipientAddress'
    const ledgerFees = {
      transfer: '0.1',
    }

    return expectSaga(sendTokensSaga, sendTokens(tokenAmount, recipientAddress))
      .withState(stateWithVcxInitSuccess)
      .provide([
        [matchers.call.fn(getLedgerFees), ledgerFees],
        [matchers.call.fn(sendTokenAmount, tokenAmount, recipientAddress), {}],
      ])
      .call(sendTokenAmount, tokenAmount, recipientAddress)
      .put(tokenSentSuccess(tokenAmount))
      .run()
  })

  it('saga: sendTokensSaga => fail', () => {
    const walletBalance = '1'
    const stateWithVcxInitSuccess = {
      config: {
        vcxInitializationState: VCX_INIT_SUCCESS,
      },
      wallet: { walletBalance: { data: walletBalance } },
    }
    const tokenAmount = '2'
    const recipientAddress = 'recipientAddress'
    const ledgerFees = {
      transfer: '0.1',
    }

    return expectSaga(sendTokensSaga, sendTokens(tokenAmount, recipientAddress))
      .withState(stateWithVcxInitSuccess)
      .provide([[matchers.call.fn(getLedgerFees), ledgerFees]])
      .put(sendTokensFail(tokenAmount, ERROR_SENDING_TOKENS_WITH_FEES))
      .run()
  })
})


<|start_filename|>android/app/src/androidTest/java/me/connect/BridgeUtilsTests.java<|end_filename|>
package me.connect;

/**
 * Created by abdussami on 08/06/18.
 */

import android.Manifest;
import android.os.Environment;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;

import java.io.File;

import static me.connect.BridgeUtils.generateCaCertContents;
import static me.connect.BridgeUtils.writeCACert;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class BridgeUtilsTests {
    public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);

    public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);


    @Rule
    public final RuleChain mRuleChain = RuleChain.outerRule(readPermissionRule)
            .around(writePermissionRule);
    String TAG = "BRIDGE TESTS::";

    @Before
    public void cleanup(){
        File f = new File(Environment.getExternalStorageDirectory().getPath() + "/cacert.pem");
        f.delete();

    }

    @Test
    public void caCertTest() throws InterruptedException {



        String certContents = generateCaCertContents();
        Log.i(TAG, "caCertTest: permission test");
        writeCACert(InstrumentationRegistry.getContext());
        Assert.assertTrue(certContents.contains("MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB"));


    }


}


<|start_filename|>app/backup/__tests__/generate-phrase.spec.js<|end_filename|>
// @flow

import React from 'react'
import renderer from 'react-test-renderer'
import { GenerateRecoveryPhrase } from '../generate-phrase'
import { getNavigation } from '../../../__mocks__/static-data'
import { settingsRoute } from '../../common'
import { BACKUP_STORE_STATUS } from '../type-backup'

describe('<GenerateRecoveryPhrase />', () => {
  const recoveryPassphrase = '<PASSWORD>'
  const navigation = {
    navigate: jest.fn(),
    goBack: jest.fn(),
    state: {
      params: {
        recoveryPassphrase,
        initialRoute: settingsRoute,
      },
    },
  }

  it('should match snapshot', () => {
    const tree = renderer.create(
      <GenerateRecoveryPhrase
        recoveryPassphrase={{
          phrase: recoveryPassphrase,
          salt: 'salt',
          hash: 'hash',
        }}
        generateRecoveryPhrase={jest.fn()}
        recoveryStatus={BACKUP_STORE_STATUS.GENERATE_PHRASE_SUCCESS}
        navigation={navigation}
      />
    )
    tree.getInstance().setState({
      chatBubbleDimensions: {
        width: 360,
        height: 199,
        x: 0,
        y: 0,
      },
    })
    expect(tree.toJSON()).toMatchSnapshot()
  })
  it('should match snapshot for loading state', () => {
    const tree = renderer.create(
      <GenerateRecoveryPhrase
        recoveryPassphrase={{
          phrase: recoveryPassphrase,
          salt: 'salt',
          hash: 'hash',
        }}
        generateRecoveryPhrase={jest.fn()}
        recoveryStatus={BACKUP_STORE_STATUS.GENERATE_PHRASE_LOADING}
        navigation={navigation}
      />
    )
    expect(tree.toJSON()).toMatchSnapshot()
  })
  it('should match snapshot for error state', () => {
    const tree = renderer.create(
      <GenerateRecoveryPhrase
        recoveryPassphrase={{
          phrase: recoveryPassphrase,
          salt: 'salt',
          hash: 'hash',
        }}
        generateRecoveryPhrase={jest.fn()}
        recoveryStatus={BACKUP_STORE_STATUS.GENERATE_PHRASE_FAILURE}
        navigation={navigation}
      />
    )
    tree.getInstance().setState({
      chatBubbleDimensions: {
        width: 360,
        height: 199,
        x: 0,
        y: 0,
      },
    })

    expect(tree.toJSON()).toMatchSnapshot()
  })
})


<|start_filename|>app/sms-pending-invitation/type-sms-pending-invitation.js<|end_filename|>
// @flow
import type {
  CustomError,
  InitialTestAction,
  ResetAction,
} from '../common/type-common'

export const SMSPendingInvitationStatus = {
  NONE: 'NONE',
  FETCH_FAILED: 'FETCH_FAILED',
  RECEIVED: 'RECEIVED',
  SEEN: 'SEEN',
}

export type SMSPendingInvitationStatusType = $Keys<
  typeof SMSPendingInvitationStatus
>

export type AgentKeyDelegationProof = {
  agentDID: string,
  agentDelegatedKey: string,
  signature: string,
}

export type InvitationSenderDetail = {
  name: string,
  agentKeyDlgProof: AgentKeyDelegationProof,
  DID: string,
  logoUrl: string,
  verKey: string,
}

export type InvitationSenderAgencyDetail = {
  DID: string,
  verKey: string,
  endpoint: string,
}

export type SMSPendingInvitationPayload = {
  connReqId: string,
  statusCode: string,
  senderDetail: InvitationSenderDetail,
  senderAgencyDetail: InvitationSenderAgencyDetail,
  targetName: string,
}

export type SMSPendingInvitation = {
  +payload: ?SMSPendingInvitationPayload,
  +status: SMSPendingInvitationStatusType,
  +isFetching: boolean,
  +error?: ?CustomError,
}

export type SMSPendingInvitations = Array<
  SMSPendingInvitation & { invitationToken: string }
>

export type SMSPendingInvitationStore = {
  +[string]: SMSPendingInvitation,
}

export const SMS_PENDING_INVITATION_REQUEST: 'SMS_PENDING_INVITATION_REQUEST' =
  'SMS_PENDING_INVITATION_REQUEST'

export type SMSPendingInvitationRequestAction = {
  type: typeof SMS_PENDING_INVITATION_REQUEST,
  smsToken: string,
}

export const SMS_PENDING_INVITATION_RECEIVED: 'SMS_PENDING_INVITATION_RECEIVED' =
  'SMS_PENDING_INVITATION_RECEIVED'

export type SMSPendingInvitationReceivedAction = {
  type: typeof SMS_PENDING_INVITATION_RECEIVED,
  data: SMSPendingInvitationPayload,
  smsToken: string,
}

export const SMS_PENDING_INVITATION_FAIL: 'SMS_PENDING_INVITATION_FAIL' =
  'SMS_PENDING_INVITATION_FAIL'

export type SMSPendingInvitationFailAction = {
  type: typeof SMS_PENDING_INVITATION_FAIL,
  error: CustomError,
  smsToken: string,
}

export const SMS_PENDING_INVITATION_SEEN: 'SMS_PENDING_INVITATION_SEEN' =
  'SMS_PENDING_INVITATION_SEEN'

export type SMSPendingInvitationSeenAction = {
  type: typeof SMS_PENDING_INVITATION_SEEN,
  smsToken: string,
}

export const SAFE_TO_DOWNLOAD_SMS_INVITATION = 'SAFE_TO_DOWNLOAD_SMS_INVITATION'

export type SafeToDownloadSmsInvitationAction = {
  type: typeof SAFE_TO_DOWNLOAD_SMS_INVITATION,
}

export type SMSPendingInvitationAction =
  | SMSPendingInvitationRequestAction
  | SMSPendingInvitationReceivedAction
  | SMSPendingInvitationFailAction
  | SMSPendingInvitationSeenAction
  | SafeToDownloadSmsInvitationAction
  | InitialTestAction
  | ResetAction


<|start_filename|>app/components/__tests__/text.spec.js<|end_filename|>
// @flow
import { formatNumbers } from '../text'

const toFormatNumber = '1234567890.12345678901234567890'
const formattedNumber = '1,234,567,890.12345678901234567890'

describe('Check the functionality for the number format function', () => {
  it('should return the proper formatted text', () => {
    expect(formatNumbers(toFormatNumber)).toEqual(formattedNumber)
  })
})


<|start_filename|>app/components/qr-scanner/qr-scanner.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Vibration, StyleSheet, View, Dimensions, Platform } from 'react-native'
import Camera from 'react-native-camera'
import { CustomView, Container, CustomText, Icon } from '../../components/'
import {
  color,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_5X,
} from '../../common/styles/constant'
import { isValidQrCode } from './qr-scanner-validator'
import {
  SCAN_STATUS,
  BOTTOM_RIGHT,
  BOTTOM_LEFT,
  TOP_RIGHT,
  TOP_LEFT,
} from './type-qr-scanner'
import type {
  QrScannerProps,
  QrScannerState,
  CameraMarkerProps,
  CornerBoxProps,
} from './type-qr-scanner'
import { isValidUrlQrCode } from './qr-url-validator'
import { isValidInvitationUrl } from './qr-invitation-url-validator'
import { invitationDetailsRequest } from '../../api/api'
import { convertSmsPayloadToInvitation } from '../../sms-pending-invitation/sms-pending-invitation-store'
import type { SMSPendingInvitationPayload } from '../../sms-pending-invitation/type-sms-pending-invitation'

export default class QRScanner extends PureComponent<
  QrScannerProps,
  QrScannerState
> {
  state = {
    // this flag is used to restrict camera to keep on scanning QR codes
    // if this is set to false, only then we
    scanning: false,
    scanStatus: SCAN_STATUS.SCANNING,
    cameraActive: true,
  }

  // Need to have this property because we can't rely
  // on state being updated immediately
  // so, while state being updated by react asynchronously,
  // onRead can be called multiple times and we don't want it
  isScanning = false

  // we queue few async tasks by assuming that camera might still be active
  // however, if this component is unmounted before we could call timers
  // then we possibly might have memory leak and React issue of updating
  // state on unmounted components
  timers = []

  reactivateScanning = () => {
    // this method sets scanning status
    // so that we stop accepting qr code scans and user can see
    // "scanning..." text, otherwise as soon as we set state
    // in "reactivate" function, "scanning..." text will disappear and it looks bad
    const reactivateTimer = setTimeout(() => {
      this.setState({ scanning: false })
      this.isScanning = false
    }, 2000)
    this.timers.push(reactivateTimer)
  }

  reactivate = () => {
    this.setState(
      {
        scanStatus: SCAN_STATUS.SCANNING,
      },
      this.reactivateScanning
    )
  }

  delayedReactivate = () => {
    // no anonymous function to save closure to avoid memory leak
    const delayedTimer = setTimeout(this.reactivate, 3000)
    this.timers.push(delayedTimer)
  }

  onSuccessRead = (nextState: QrScannerState) => {
    nextState.scanStatus = SCAN_STATUS.SUCCESS
    nextState.cameraActive = false
    this.setState(nextState)
    // reset state after work is done
    // expectation is that parent will finish it's work within this timeout
    this.delayedReactivate()
  }

  componentWillUnmount() {
    this.timers.map(clearTimeout)
    this.timers = []
  }

  onRead = async (event: {| data: string |}) => {
    if (!this.state.scanning && !this.isScanning) {
      // set this instance property to avoid async state issue
      this.isScanning = true

      const qrData = isValidQrCode(event.data)
      let nextState = { scanning: true, scanStatus: SCAN_STATUS.SCANNING }

      if (qrData && typeof qrData === 'object') {
        this.onSuccessRead(nextState)
        this.props.onRead(qrData)
      } else {
        // we support another type of qr code as well
        // in which we recognize the url which allows us
        // to switch environment
        const urlQrCode = isValidUrlQrCode(event.data)
        if (urlQrCode && typeof urlQrCode === 'object') {
          this.onSuccessRead(nextState)
          this.props.onEnvironmentSwitchUrl(urlQrCode)
        } else {
          // now check if we get invitation url in qr-code
          const urlInvitationQrCode = isValidInvitationUrl(event.data)
          if (urlInvitationQrCode && typeof urlInvitationQrCode === 'object') {
            nextState.scanStatus = SCAN_STATUS.DOWNLOADING_INVITATION
            this.setState(nextState)
            try {
              const invitationData: SMSPendingInvitationPayload = await invitationDetailsRequest(
                {
                  url: urlInvitationQrCode.url,
                }
              )
              const invitationPayload = convertSmsPayloadToInvitation(
                invitationData
              )
              nextState.scanStatus = SCAN_STATUS.SUCCESS
              this.onSuccessRead(nextState)
              this.props.onInvitationUrl(invitationPayload)
            } catch (e) {
              // set status that no invitation data was found at the url
              nextState.scanStatus = SCAN_STATUS.NO_INVITATION_DATA
              // re-activate scanning after setting fail status
              this.setState(nextState, this.delayedReactivate)
            }
          } else {
            // qr code read failed
            nextState.scanStatus = SCAN_STATUS.FAIL
            // if qr code read failed, we reactivate qr code scan after delay
            // so that user can see that QR code scan failed
            this.setState(nextState, this.delayedReactivate)
          }
        }
      }
    }
  }

  render() {
    return (
      <Container>
        {this.state.cameraActive ? (
          <Camera onBarCodeRead={this.onRead} style={[cameraStyle.camera]}>
            <CameraMarker
              status={this.state.scanStatus}
              onClose={this.props.onClose}
            />
          </Camera>
        ) : null}
      </Container>
    )
  }
}
export class CameraMarker extends PureComponent<CameraMarkerProps, void> {
  render() {
    const { status, onClose } = this.props

    return (
      <CustomView center style={[cameraMarkerStyles.container]}>
        <CustomText h4 semiBold transparentBg>
          Scan QR Code
        </CustomText>
        <CustomView
          transparentBg
          spaceBetween
          style={[cameraMarkerStyles.cameraMarker]}
        >
          <CustomView row spaceBetween>
            <CornerBox status={status} position={TOP_LEFT} />
            <CornerBox status={status} position={TOP_RIGHT} />
          </CustomView>
          <CustomView row spaceBetween>
            <CornerBox status={status} position={BOTTOM_LEFT} />
            <CornerBox status={status} position={BOTTOM_RIGHT} />
          </CustomView>
        </CustomView>
        <CustomView
          style={[cameraMarkerStyles.container, cameraMarkerStyles.overlay]}
        />
        <CustomText
          h5
          semiBold
          transparentBg
          // $FlowFixMe
          style={[scanStatusStyle[status], scanStatusStyle.scanStatusOffset]}
        >
          {status}
        </CustomText>
        <CustomView
          row
          center
          style={[closeIconStyle.closeIcon]}
          testID={'close-qr-scanner-container'}
        >
          <Icon
            src={require('../../images/close_white.png')}
            testID={'close-qr-scanner-icon'}
            onPress={onClose}
            small
          />
        </CustomView>
      </CustomView>
    )
  }
}

export class CornerBox extends PureComponent<CornerBoxProps, void> {
  render() {
    const { status } = this.props
    const borderStyle =
      status === SCAN_STATUS.SUCCESS ||
      status === SCAN_STATUS.DOWNLOADING_INVITATION
        ? cameraMarkerStyles.borderSuccess
        : status === SCAN_STATUS.FAIL ||
          status === SCAN_STATUS.NO_INVITATION_DATA
          ? cameraMarkerStyles.borderFail
          : cameraMarkerStyles.border

    return (
      <CustomView
        transparentBg
        style={[
          cameraMarkerStyles.cornerBox,
          // $FlowFixMe
          cameraMarkerStyles[`${this.props.position}Box`],
          borderStyle,
        ]}
      />
    )
  }
}

const markerSize = 250
const cornerBoxSize = 70
const cornerBoxBorderSize = 5

const cameraMarkerStyles = StyleSheet.create({
  container: {
    ...StyleSheet.absoluteFillObject,
  },
  overlay: {
    zIndex: -1,
    backgroundColor: 'rgba(0, 0, 0, 0.2)',
  },
  cameraMarker: {
    width: markerSize,
    height: markerSize,
    marginVertical: OFFSET_5X,
  },
  border: {
    borderColor: color.bg.primary.font.primary,
  },
  borderSuccess: {
    borderColor: color.actions.tertiary,
  },
  borderFail: {
    borderColor: color.actions.dangerous,
  },
  cornerBox: {
    width: cornerBoxSize,
    height: cornerBoxSize,
  },
  topLeftBox: {
    borderTopWidth: cornerBoxBorderSize,
    borderLeftWidth: cornerBoxBorderSize,
  },
  topRightBox: {
    borderTopWidth: cornerBoxBorderSize,
    borderRightWidth: cornerBoxBorderSize,
  },
  bottomLeftBox: {
    borderBottomWidth: cornerBoxBorderSize,
    borderLeftWidth: cornerBoxBorderSize,
  },
  bottomRightBox: {
    borderBottomWidth: cornerBoxBorderSize,
    borderRightWidth: cornerBoxBorderSize,
  },
})

const cameraStyle = StyleSheet.create({
  camera: {
    // magical number 50 can be set here due to footer height
    // we want our QR code to go behind the footer slightly
    // but at the same time we want qr scan status to stay sufficient above footer
    // without margin or padding, by setting height
    // we automatically align qr scanner using flex
    height: Dimensions.get('screen').height,
    backgroundColor: 'transparent',
  },
})

const scanStatusStyle = StyleSheet.create({
  [SCAN_STATUS.SCANNING]: {
    color: color.actions.none,
  },
  [SCAN_STATUS.SUCCESS]: {
    color: color.actions.tertiary,
  },
  [SCAN_STATUS.FAIL]: {
    color: color.actions.dangerous,
  },
  [SCAN_STATUS.DOWNLOADING_INVITATION]: {
    color: color.actions.tertiary,
  },
  [SCAN_STATUS.NO_INVITATION_DATA]: {
    color: color.actions.dangerous,
  },
  scanStatusOffset: {
    marginVertical: OFFSET_3X,
  },
})

const closeIconStyle = StyleSheet.create({
  closeIcon: {
    marginVertical: OFFSET_2X,
  },
})


<|start_filename|>app/wallet/type-wallet.js<|end_filename|>
// @flow
import type { ReactNavigation } from '../common/type-common'
import type { CustomError } from '../common/type-common'
import type { IsValid } from '../components/input-control/type-input-control'
import type { CredentialOfferModalStatus } from '../claim-offer/type-claim-offer'

export type BackupWalletProps = {
  backup: BackupInfo,
  render: (backup: string, backupWallet: () => void) => void,
  walletBackup: () => void,
} & ReactNavigation

export type BackupInfo = {
  latest: ?string,
  error: ?CustomError,
  backupPath: ?string,
} & StoreStatus

export const BACKUP_WALLET = 'BACKUP_WALLET'

export const BACKUP_WALLET_FAIL = 'BACKUP_WALLET_FAIL'

export const BACKUP_WALLET_SUCCESS = 'BACKUP_WALLET_SUCCESS'

export const GET_WALLET_ENCRYPTION_KEY = 'GET_WALLET_ENCRYPTION_KEY'

export const BACKUP_WALLET_PATH = 'BACKUP_WALLET_PATH'

export const SHARE_WALLET_BACKUP = 'SHARE_WALLET_BACKUP'

export const ERROR_BACKUP_WALLET = {
  code: 'WB-001',
  message: 'Error while backing up wallet',
}

export const ERROR_BACKUP_WALLET_SHARE = {
  code: 'WB-002',
  message: 'Error while sharing zipped backup',
}

export type WalletTabSendDetailsProps = {
  tokenAmount: string,
  tokenSentStatus: $Keys<typeof STORE_STATUS>,
  sendTokens: (
    tokenAmount: string,
    recipientAddress: string
  ) => SendTokensAction,
} & ReactNavigation

export type BackupWalletAction = {
  type: typeof BACKUP_WALLET,
  data: BackupInfo,
}

export type ShareBackupAction = {
  type: typeof SHARE_WALLET_BACKUP,
  data: BackupInfo,
}

export type WalletBalanceProps = {
  walletBalance: string,
  refreshWalletBalance: () => {},
  render: Function,
}

export type WalletSendAmountState = {
  text: string,
}

export type WalletSendAmountProps = {
  screenProps: ReactNavigation,
  selectTokenAmount: (tokenAmount: string) => {},
  walletBalance: string,
  paymentStatus: $Keys<typeof STORE_STATUS>,
} & ReactNavigation

export type WalletProps = {} & ReactNavigation

export type WalletPayload = {
  walletPath: string,
  encryptionKey: string,
}

export type WalletTabReceiveProps = {
  walletAddresses: Array<string>,
  refreshWalletAddresses: () => {},
  promptBackupBanner: (showBackup: boolean) => {},
  addressStatus: $Keys<typeof STORE_STATUS>,
  currentScreen: string,
}

export type WalletTabReceiveState = {
  copyButtonText: string,
}

export type WalletSendPaymentData = {
  paymentTo: string,
  paymentFor?: string,
}

export type WalletTabSendDetailsState = {
  showPaymentAddress: boolean,
  isPaymentAddressValid: IsValid,
  credentialOfferModalStatus: CredentialOfferModalStatus,
}

export type WalletHistoryProps = {
  walletHistory: WalletHistory,
  refreshWalletHistory: () => {},
}

export type WalletTabsProps = {} & ReactNavigation

export type WalletHistoryEvent = {
  id: string,
  senderName?: string,
  senderAddress: string,
  action: string,
  tokenAmount: string,
  timeStamp: string,
}

export type WalletBalance = {
  data: string,
} & StoreStatus &
  StoreError

export type WalletAddresses = {
  data: Array<string>,
} & StoreStatus &
  StoreError

export type WalletHistory = {
  transactions: WalletHistoryEvent[],
} & StoreStatus &
  StoreError

export type Payment = {
  tokenAmount: string,
} & StoreStatus &
  StoreError

export const ERROR_LOADING_WALLET = {
  code: 'W001',
  message: 'Error while loading wallet data',
}

export const ERROR_REFRESHING_WALLET_BALANCE = {
  code: 'W002',
  message: 'Error while refreshing wallet balance',
}

export const ERROR_REFRESHING_WALLET_ADDRESSES = {
  code: 'W003',
  message: 'Error while refreshing wallet addresses',
}

export const ERROR_REFRESHING_WALLET_HISTORY = {
  code: 'W004',
  message: 'Error while refreshing wallet history',
}

export const ERROR_LOADING_WALLET_BALANCE = {
  code: 'W005',
  message: 'Error while loading wallet balance',
}

export const ERROR_LOADING_WALLET_ADDRESSES = {
  code: 'W006',
  message: 'Error while loading wallet addresses',
}

export const ERROR_LOADING_WALLET_HISTORY = {
  code: 'W007',
  message: 'Error while loading wallet history',
}

export const ERROR_SENDING_TOKENS = {
  code: 'W008',
  message: 'Error sending tokens',
}

export const ERROR_SENDING_TOKENS_WITH_FEES = {
  code: 'W009',
  message:
    'Error sending tokens while transfer fees is greater than or equal to transfer amount',
}

export const STORE_STATUS = {
  IDLE: 'IDLE',
  IN_PROGRESS: 'IN_PROGRESS',
  ERROR: 'ERROR',
  SUCCESS: 'SUCCESS',
}

export type StoreError = { error: ?CustomError }
export type StoreStatus = { status: $Keys<typeof STORE_STATUS> }

export type WalletStore = {
  walletBalance: WalletBalance,
  walletAddresses: WalletAddresses,
  walletHistory: WalletHistory,
  backup: BackupInfo,
  payment: Payment,
}

export type HydrateWalletBalanceFailAction = {
  type: typeof HYDRATE_WALLET_BALANCE_FAIL,
  error: CustomError,
  status: StoreStatus,
}

export type HydrateWalletAddressesFailAction = {
  type: typeof HYDRATE_WALLET_ADDRESSES_FAIL,
  error: CustomError,
  status: StoreStatus,
}

export type HydrateWalletHistoryFailAction = {
  type: typeof HYDRATE_WALLET_HISTORY_FAIL,
  error: CustomError,
  status: StoreStatus,
}

export type SendTokensAction = {
  type: typeof SEND_TOKENS,
  tokenAmount: string,
  recipientWalletAddress: string,
}

export type SelectTokensAction = {
  type: typeof SEND_TOKENS,
  tokenAmount: string,
}

export const HYDRATE_WALLET_BALANCE_FAIL = 'HYDRATE_WALLET_BALANCE_FAIL'
export const HYDRATE_WALLET_ADDRESSES_FAIL = 'HYDRATE_WALLET_ADDRESSES_FAIL'
export const HYDRATE_WALLET_HISTORY_FAIL = 'HYDRATE_WALLET_HISTORY_FAIL'
export const REFRESH_WALLET_BALANCE_FAIL = 'REFRESH_WALLET_BALANCE_FAIL'
export const REFRESH_WALLET_ADDRESSES_FAIL = 'REFRESH_WALLET_ADDRESSES_FAIL'
export const REFRESH_WALLET_HISTORY_FAIL = 'REFRESH_WALLET_HISTORY_FAIL'
export const HYDRATE_WALLET_BALANCE = 'HYDRATE_WALLET_BALANCE'
export const HYDRATE_WALLET_ADDRESSES = 'HYDRATE_WALLET_ADDRESSES'
export const HYDRATE_WALLET_HISTORY = 'HYDRATE_WALLET_HISTORY'
export const REFRESH_WALLET = 'REFRESH_WALLET'
export const REFRESH_WALLET_ADDRESSES = 'REFRESH_WALLET_ADDRESSES'
export const REFRESH_WALLET_HISTORY = 'REFRESH_WALLET_HISTORY'
export const REFRESH_WALLET_BALANCE = 'REFRESH_WALLET_BALANCE'
export const WALLET_BALANCE_REFRESHED = 'WALLET_BALANCE_REFRESHED'
export const WALLET_ADDRESSES_REFRESHED = 'WALLET_ADDRESSES_REFRESHED'
export const WALLET_HISTORY_REFRESHED = 'WALLET_HISTORY_REFRESHED'
export const SEND_TOKENS = 'SEND_TOKENS'
export const SEND_TOKENS_FAIL = 'SEND_TOKENS_FAIL'
export const TOKEN_SENT_SUCCESS = 'TOKEN_SENT_SUCCESS'
export const SELECT_TOKEN_AMOUNT = 'SELECT_TOKEN_AMOUNT'
export const PROMPT_WALLET_BACKUP_BANNER = 'PROMPT_WALLET_BACKUP_BANNER'
export const WALLET_ADDRESSES_FETCH_START = 'WALLET_ADDRESSES_FETCH_START'

export type PromptBackupBannerAction = {
  type: typeof PROMPT_WALLET_BACKUP_BANNER,
  showBanner: boolean,
}

export type HydrateWalletBalanceData = string

export type HydrateWalletAddressesData = Array<string>

export type HydrateWalletHistoryTransactions = WalletHistoryEvent[]

export type RefreshWalletHistoryAction = {
  type: typeof REFRESH_WALLET_HISTORY,
}

export type WalletBalanceRefreshedAction = {
  type: typeof WALLET_BALANCE_REFRESHED,
  walletBalance: WalletBalance,
}

export type WalletAddressesRefreshedAction = {
  type: typeof WALLET_ADDRESSES_REFRESHED,
  walletAddresses: WalletAddresses,
}

export type WalletHistoryRefreshedAction = {
  type: typeof WALLET_HISTORY_REFRESHED,
  walletHistory: WalletHistory,
}

export type RefreshWalletAddressesAction = {
  type: typeof REFRESH_WALLET_ADDRESSES,
}

export type RefreshWalletBalanceAction = {
  type: typeof REFRESH_WALLET_BALANCE,
  walletBalance: WalletBalance,
}

export type HydrateWalletBalanceAction = {
  type: typeof HYDRATE_WALLET_BALANCE,
  walletBalance: WalletBalance,
}

export type HydrateWalletAddressesAction = {
  type: typeof HYDRATE_WALLET_ADDRESSES,
  walletAddresses: WalletAddresses,
}

export type HydrateWalletHistoryAction = {
  type: typeof HYDRATE_WALLET_HISTORY,
  walletHistory: WalletHistory,
}

export type TokenSentSuccessAction = {
  type: typeof TOKEN_SENT_SUCCESS,
  payment: Payment,
}

export type WalletStoreAction =
  | HydrateWalletBalanceFailAction
  | HydrateWalletAddressesFailAction
  | HydrateWalletHistoryFailAction
  | RefreshWalletBalanceAction
  | RefreshWalletAddressesAction
  | RefreshWalletHistoryAction
  | WalletHistoryRefreshedAction
  | WalletBalanceRefreshedAction
  | WalletAddressesRefreshedAction
  | HydrateWalletBalanceAction
  | HydrateWalletAddressesAction
  | HydrateWalletHistoryAction
  | BackupWalletAction
  | SendTokensAction
  | TokenSentSuccessAction
  | SelectTokensAction


<|start_filename|>connectMeUITest/src/pageObjects/PincodePage.java<|end_filename|>
package pageObjects;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

/**
 * Created by ankurmishra on 6/22/17.
 */
public class PincodePage {

	private static WebElement element = null;
	public static WebElement PinCodeLock_TextBox(AppiumDriver driver,int i) throws Exception {

		try {
			element = driver.findElement(By.name("pin-code-digit-"+i+""));
			System.out.println("PinCodeLock_TextBox"+i+"is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("PinCodeLock_TextBox"+i+"is not displayed");
			throw (e);
		}
	}
		
	public static WebElement Close_Button(AppiumDriver driver) throws Exception {

			try {
				element = driver.findElement(By.name(("Close")));
				System.out.println("Close Button is displayed");
				return element;
			} catch (Exception e) {

				System.out.println(" Code Button is not displayed");
				throw (e);
			}
	}
	
	public static WebElement Message_PinCodeSetup(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.name(("Enter pin code to unlock app")));
			System.out.println("Message_PinCodeSetup is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("Message_PinCodeSetup is not displayed");
			throw (e);
		}
}







}


<|start_filename|>connectMeUITest/src/pageObjects/InvitationPage.java<|end_filename|>
package pageObjects;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import io.appium.java_client.AppiumDriver;

public class InvitationPage {
	
	private static WebElement element = null;

	public static WebElement Allow_Button(AppiumDriver driver) throws Exception {

		try {
			element =  driver.findElementByXPath("(//XCUIElementTypeOther[@name='Connect'])[2]");
			System.out.println("Allow Button is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("Allow Button is not displayed");
			throw (e);
		}
	}

	public static WebElement Inviation_Text_Container(AppiumDriver driver) throws Exception {

		try {
			element =  driver.findElement(By.xpath("//XCUIElementTypeStaticText[@name='invitation-text-container-title']"));
			System.out.println("Inviation_Text_Container is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("Inviation_Text_Container is not displayed");
			throw (e);
		}
	}
	
	public static WebElement Deny_Button(AppiumDriver driver) throws Exception {

		try {
			element =  driver.findElementByXPath("(//XCUIElementTypeOther[@name='Deny'])[2]");
			System.out.println("Allow Button is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("Allow Button is not displayed");
			throw (e);
		}
	}

}


<|start_filename|>app/components/request/__tests__/request.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import TouchId from 'react-native-touch-id'
import firebase from 'react-native-firebase'

import { Request } from '../request'
import type { RequestProps, ResponseTypes } from '../type-request'
import { color } from '../../../common/styles/constant'
import { lockAuthorizationRoute } from '../../../common/route-constants'
import { getNavigation, getStore } from '../../../../__mocks__/static-data'

describe('<Request />', () => {
  let store
  let request
  let requestComponent
  let tree
  const accepted = 'accepted'
  const rejected = 'rejected'
  const defaultProps = {
    title: 'Hi Test User',
    message: 'Enterprise A agent wants to connect with you',
    senderLogoUrl: 'https://image.url',
    senderName: 'Enterprise A agent',
    onAction: jest.fn(),
    showErrorAlerts: false,
    testID: 'request',
    isTouchIdEnabled: true,
    pushNotificationPermissionAction: jest.fn(),
  }
  let navigation

  beforeAll(() => {
    store = getStore()
  })

  beforeEach(() => {
    navigation = getNavigation({ onSuccess: jest.fn() })

    // onAction = jest.fn()
    request = renderer.create(
      <Provider store={store}>
        <Request
          {...defaultProps}
          onAction={defaultProps.onAction}
          navigation={navigation}
          showErrorAlerts={defaultProps.showErrorAlerts}
        />
      </Provider>
    )
    tree = request.toJSON()
    requestComponent = request.root.findByType(Request).instance
  })

  it('should match snapshot', () => {
    expect(tree).toMatchSnapshot()
  })

  it('TouchId and calls onAction if Connect/Deny button is pressed', async () => {
    const touchIdAuth = await requestComponent.onAccept()
    await touchIdAuth
    expect(defaultProps.onAction).toBeCalled()
    expect(defaultProps.onAction).toHaveBeenCalledWith(accepted)
  })

  it('redirect user to lock authorization page if TouchId fails', async () => {
    TouchId.authenticate.mockImplementation(message => Promise.reject())
    await requestComponent.authenticate(accepted)
    expect(navigation.navigate).toHaveBeenCalledWith(lockAuthorizationRoute, {
      onSuccess: expect.any(Function),
      onAvoid: expect.any(Function),
    })
  })

  it('call authenticate even if user allow push notification', async () => {
    await requestComponent.onAction(accepted)
    expect(defaultProps.onAction).toHaveBeenCalledWith(accepted)
  })

  it('call authenticate even if user does not allow push notification', async () => {
    firebase
      .messaging()
      .requestPermission.mockImplementation(() => Promise.reject())
    await requestComponent.onAction(accepted)
    expect(defaultProps.onAction).toHaveBeenCalledWith(accepted)
  })
})


<|start_filename|>app/about-app/__test__/about-app.spec.js<|end_filename|>
// @flow

import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { AboutApp } from '../about-app'
import { getStore } from '../../../__mocks__/static-data'
import { getNavigation } from '../../../__mocks__/static-data'

import type {} from '../type-about-app'

describe('user about app screen', () => {
  const props = {
    navigation: getNavigation(),
    environmentName: 'DEMO',
  }

  it('should render properly and snapshot should match', () => {
    const tree = renderer.create(<AboutApp {...props} />).toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/components/image-color-picker/canvas-html.js<|end_filename|>
// @flow

export const canvasHtml = (imageBlob: string, imageType: string) => {
  return `
    <!DOCTYPE html>
    <html>
    <script>
    function fetchColorFromCanvas() {
      const options = {
        imageElement: document.getElementById("__colorPickerCanvasImage")
      }
      var rgba = getColorPalettes(options);
      var message = {"message":'rgbValues',"payload":rgba};
      window.postMessage(JSON.stringify(message));
    }

    function getColorPalettes({imageElement, 
        count=3, 
        defaultPalette=[0, 0, 0, 1], 
        paletteType='dominant', 
        colorType='rgba'}
      ) {       
      const canvas = document.createElement('canvas');
      const	canvasContext = canvas.getContext && canvas.getContext('2d');

      if (!canvasContext) return defaultPalette;
      
      let imageWidth = canvas.width = imageElement.naturalWidth 
        || imageElement.offsetWidth 
        || imageElement.width;                

      const imageHeight = canvas.height = imageElement.naturalHeight 
        || imageElement.offsetHeight 
        || imageElement.height;                   

      canvasContext.drawImage(imageElement, 0, 0);
      if (paletteType === 'average')
        return getAveragePalette({imageWidth, imageHeight, canvasContext, colorType});
      else
        return getDominantPalettes(getAllPalettes(imageWidth, imageHeight, canvasContext), count, colorType);
    }

    function getAveragePalette({imageWidth, imageHeight, canvasContext, colorType = 'rgb'}) {
      const blockSize = 5
      let i = -4;
      let rgb = {r:0,g:0,b:0,a:1};
      let count = 0;
      
      try {
        data = canvasContext.getImageData(0, 0, imageWidth, imageHeight);
      } catch(e) {
        console.log(e);
      }
    
      while ((i += blockSize * 4) < data.data.length) {
        ++count;
        rgb.r += data.data[i];
        rgb.g += data.data[i+1];
        rgb.b += data.data[i+2];
      }
      rgb.r = ~~(rgb.r/count);
      rgb.g = ~~(rgb.g/count);
      rgb.b = ~~(rgb.b/count);
      if (colorType === 'hex')
        return [[rgbToHex([rgb.r, rgb.g, rgb.b])]]
      else
        return [[rgb.r, rgb.g, rgb.b, rgb.a]];
    }

    function rgbToHex(rgba) {
      let hexColor = '#';
      rgba.slice(0, 3).forEach(c => {
        let hex = c.toString(16);
        hexColor += hex.length == 1 ? "0" + hex : hex;  
      });
      return hexColor
    }

    function getAllPalettes(width, height, context) {
      let distinctPalettes = [];        
      for (var i=0; i<=height; i++) { 
        for (var j=0; j<=width; j++) { 
          try {
            data = context.getImageData(i, j, 1, 1);
            if (data.data.toString().trim() != "0,0,0,0") {
              distinctPalettes.push(data.data);
            }
          } catch(e) {
            console.log(e);
          }
        }
      }  
      return distinctPalettes;
    }

    function getDominantPalettes(allPalettes, distinctCount, colorType = 'rgb') {
      const combinations = getPaletteOccurrences(allPalettes);
      let palettes = combinations[0];
      let occurrences = combinations[1];
      const dominantPalettes = [];

      while (distinctCount) {               
        let dominant = 0, dominantKey = 0;  
        occurrences.forEach((v, k) => {           
          if (v > dominant) {
            dominant = v;              
            dominantKey = k;                               
          }
        });
        if (colorType === 'hex')
          dominantPalettes.push(rgbToHex(palettes[dominantKey]));
        else
          dominantPalettes.push(palettes[dominantKey]);
          
        palettes.splice(dominantKey, 1);            
        occurrences.splice(dominantKey, 1);
        distinctCount--;
      }
      return dominantPalettes;
    }        

    function getPaletteOccurrences(palettes) {
      let paletteList = [], occurrenceList = [], previousPalette;
      palettes.sort();
      palettes.forEach((palette, key) => {
        if (palette.toString() !== previousPalette) {
          paletteList.push(palette);
          occurrenceList.push(1);
        } else {
          occurrenceList[occurrenceList.length-1]++;
        }
        previousPalette = palettes[key].toString();
      });
      return [paletteList, occurrenceList];
    }

    const interval = setInterval(() => {
      var img = document.getElementById('__colorPickerCanvasImage');
      if (img.src.length !== 0) {
        fetchColorFromCanvas();
        clearInterval(interval);
      }
    },10);        

    </script>
    <body>
      <img src='data:image/${imageType};base64,${imageBlob}' 
        id='__colorPickerCanvasImage' onload='fetchColorFromCanvas()'/>
    </body>
    </html>
  `
}


<|start_filename|>app/backup/__tests__/verify-phrase.spec.js<|end_filename|>
// @flow

import React from 'react'
import renderer from 'react-test-renderer'
import { VerifyRecoveryPhrase } from '../verify-phrase'
import { getNavigation } from '../../../__mocks__/static-data'
import { settingsRoute } from '../../common'

describe('<VerifyRecoveryPhrase />', () => {
  const recoveryPassphrase = '<PASSWORD>'
  const navigation = {
    navigate: jest.fn(),
    goBack: jest.fn(),
    state: {
      params: {
        recoveryPassphrase,
        initialRoute: settingsRoute,
      },
    },
  }

  it('should match snapshot', () => {
    const tree = renderer
      .create(
        <VerifyRecoveryPhrase
          recoveryPassphrase={{
            phrase: recoveryPassphrase,
            salt: '<PASSWORD>',
            hash: 'hash',
          }}
          navigation={navigation}
        />
      )
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/bridge/react-native-cxs/vcx-transformers.js<|end_filename|>
// @flow
import { NativeModules, Platform } from 'react-native'
import memoize from 'lodash.memoize'
import type { AgencyPoolConfig } from '../../store/type-config-store'
import type {
  VcxProvision,
  VcxProvisionResult,
  CxsInitConfig,
  InitWithGenesisPathConfig,
  VcxInitConfig,
  CxsPushTokenConfig,
  VcxPushTokenConfig,
  VcxCreateConnection,
  VcxConnectionConnectResult,
  VcxCredentialOffer,
  WalletPoolName,
} from './type-cxs'
import type { UserOneTimeInfo } from '../../store/user/type-user-store'
import type { InvitationPayload } from '../../invitation/type-invitation'
import type { MyPairwiseInfo } from '../../store/type-connection-store'
import type { ClaimOfferPushPayload } from '../../push-notification/type-push-notification'
import { secureSet, secureGet } from '../../services/storage'
import { BigNumber } from 'bignumber.js'
import type { LedgerFeesData } from '../../store/ledger/type-ledger-store'

const { RNIndy } = NativeModules

export const paymentHandle = 0

export const WALLET_KEY = 'WALLET_KEY'
export const getWalletKey = memoize(async function(): Promise<string> {
  try {
    let walletKey: string | null = await secureGet(WALLET_KEY)
    if (walletKey) {
      return walletKey
    }

    const lengthOfKey = 64
    walletKey = await RNIndy.createWalletKey(lengthOfKey)
    // createWalletKey sometimes returns with a whitespace character at the end so we need to trim it
    walletKey = walletKey.trim()

    await secureSet(WALLET_KEY, walletKey)

    return walletKey
  } catch (e) {
    // not sure what to do if keychain/keystore fails
    throw e
  }
})

export async function convertAgencyConfigToVcxProvision(
  config: AgencyPoolConfig,
  walletPoolName: WalletPoolName
): Promise<VcxProvision> {
  const wallet_key = await getWalletKey()
  return {
    agency_url: config.agencyUrl,
    agency_did: config.agencyDID,
    agency_verkey: config.agencyVerificationKey,
    wallet_name: walletPoolName.walletName,
    wallet_key,
    agent_seed: null,
    enterprise_seed: null,
  }
}

export function convertVcxProvisionResultToUserOneTimeInfo(
  provision: VcxProvisionResult
): UserOneTimeInfo {
  return {
    oneTimeAgencyDid: provision.institution_did,
    oneTimeAgencyVerificationKey: provision.institution_verkey,
    myOneTimeDid: provision.sdk_to_remote_did,
    myOneTimeVerificationKey: provision.sdk_to_remote_verkey,
    myOneTimeAgentDid: provision.remote_to_sdk_did,
    myOneTimeAgentVerificationKey: provision.remote_to_sdk_verkey,
  }
}

export async function convertCxsInitToVcxInit(
  init: InitWithGenesisPathConfig,
  walletPoolName: WalletPoolName
): Promise<VcxInitConfig> {
  const wallet_key = await getWalletKey()
  return {
    agency_endpoint: init.agencyUrl,
    agency_did: init.agencyDID,
    agency_verkey: init.agencyVerificationKey,
    config: init.poolConfig,
    pool_name: walletPoolName.poolName,
    wallet_name: walletPoolName.walletName,
    wallet_key,
    genesis_path: init.genesis_path,
    remote_to_sdk_did: init.myOneTimeAgentDid,
    remote_to_sdk_verkey: init.myOneTimeAgentVerificationKey,
    sdk_to_remote_did: init.myOneTimeDid,
    sdk_to_remote_verkey: init.myOneTimeVerificationKey,
    // TODO: These should be removed after we sdk team fix these as optional
    institution_name: 'some-random-name',
    institution_logo_url: 'https://robothash.com/logo.png',
    institution_did: init.oneTimeAgencyDid,
    institution_verkey: init.oneTimeAgencyVerificationKey,
  }
}

export function convertCxsPushConfigToVcxPushTokenConfig(
  pushConfig: CxsPushTokenConfig
): VcxPushTokenConfig {
  return {
    id: pushConfig.uniqueId,
    value: pushConfig.pushToken,
  }
}

export function convertInvitationToVcxConnectionCreate(
  invitation: InvitationPayload
): VcxCreateConnection {
  return {
    source_id: invitation.requestId,
    invite_details: {
      connReqId: invitation.requestId,
      // TODO: Add status code to be available in invitation payload
      // for now, it would always be MS-102
      statusCode: 'MS-102',
      senderDetail: invitation.senderDetail,
      senderAgencyDetail: invitation.senderAgencyDetail,
      targetName: invitation.senderName,
      // hard coding this for now, because this field does not matter anywhere for processing
      // and it will always be message sent for the purpose of connection create
      statusMsg: 'message sent',
    },
  }
}

export function convertVcxConnectionToCxsConnection(
  vcxConnection: VcxConnectionConnectResult
): MyPairwiseInfo {
  return {
    myPairwiseDid: vcxConnection.pw_did,
    myPairwiseVerKey: vcxConnection.pw_verkey,
    myPairwiseAgentDid: vcxConnection.agent_did,
    myPairwiseAgentVerKey: vcxConnection.agent_vk,
    myPairwisePeerVerKey: vcxConnection.their_pw_verkey,
    senderDID: vcxConnection.their_pw_did,
  }
}

export function convertVcxCredentialOfferToCxsClaimOffer(
  vcxCredentialOffer: VcxCredentialOffer
): ClaimOfferPushPayload {
  return {
    msg_type: vcxCredentialOffer.msg_type,
    version: vcxCredentialOffer.version,
    to_did: vcxCredentialOffer.to_did,
    from_did: vcxCredentialOffer.from_did,
    claim: vcxCredentialOffer.credential_attrs,
    claim_name: vcxCredentialOffer.claim_name,
    schema_seq_no: vcxCredentialOffer.schema_seq_no,
    issuer_did: vcxCredentialOffer.from_did,
    // should override it when generating claim offer object
    remoteName: '',
    price: vcxCredentialOffer.price,
  }
}

// 1 sovrin token = <PASSWORD> sovrin atoms
const sovrinAtomsToSovrinTokensConversionFactor = 100000000

// this determines what is the length after decimal separator
export const conversionFactorLength =
  `${sovrinAtomsToSovrinTokensConversionFactor}`.length - 1

export function convertSovrinAtomsToSovrinTokens(
  sovrinAtoms: string | number
): string {
  const atoms = new BigNumber(sovrinAtoms)
  return atoms
    .dividedBy(sovrinAtomsToSovrinTokensConversionFactor)
    .toFixed()
    .toString()
}

export function convertSovrinTokensToSovrinAtoms(sovrinTokens: string): string {
  const tokens = new BigNumber(sovrinTokens)

  return tokens
    .multipliedBy(sovrinAtomsToSovrinTokensConversionFactor)
    .toFixed()
    .toString()
}

const LEDGER_FEE_TRANSFER_CODE = '10001'
const noTransferFees = {
  transfer: '0',
}

export function convertVcxLedgerFeesToLedgerFees(
  feesJson: string
): LedgerFeesData {
  const fees = JSON.parse(feesJson)
  const transferFees: ?string = fees[LEDGER_FEE_TRANSFER_CODE]

  if (!transferFees) {
    return noTransferFees
  }

  const transferFeesAtoms = new BigNumber(transferFees)
  if (transferFeesAtoms.isNaN()) {
    return noTransferFees
  }

  // if there is value, then, that value is in sov-atoms
  // so we need to convert that to sovrin tokens
  return {
    transfer: convertSovrinAtomsToSovrinTokens(transferFeesAtoms),
  }
}


<|start_filename|>app/proof/__tests__/proof-store.spec.js<|end_filename|>
// @flow
import renderer from 'react-test-renderer'
import { put, call, select, take } from 'redux-saga/effects'
import { initialTestAction } from '../../common/type-common'
import proofReducer, {
  proofSuccess,
  generateProofSaga,
  convertPreparedProofToRequestedAttributes,
  convertSelfAttestedToIndySelfAttested,
  proofFail,
  convertIndyPreparedProofToAttributes,
  getProof,
} from '../proof-store'
import {
  acceptProofRequest,
  missingAttributesFound,
  proofRequestAutoFill,
  sendProof,
  proofRequestShowStart,
} from '../../proof-request/proof-request-store'
import { generateProof } from '../../bridge/react-native-cxs/RNCxs'
import {
  proofRequest,
  proofRequest10Attributes,
  proof,
  proofWithMissingAttributes,
  proofWith10Attributes,
  originalProofRequestData,
  originalProofRequestData10Attributes,
  originalProofRequestDataMissingAttribute,
  preparedProof,
  homeAddressPreparedProof,
  preparedProofWithMissingAttribute,
  homeAddressPreparedProofWithMissingAttribute,
  selfAttestedAttributes,
  selfAttestedAttributes1,
  poolConfig,
  originalProofRequestDataWithSpaces,
} from '../../../__mocks__/static-data'
import {
  getOriginalProofRequestData,
  getProofRequestPairwiseDid,
  getPoolConfig,
} from '../../store/store-selector'
import {
  USER_SELF_ATTESTED_ATTRIBUTES,
  UPDATE_ATTRIBUTE_CLAIM,
} from '../type-proof'
import { PROOF_REQUEST_SHOW_START } from '../../proof-request/type-proof-request'

describe('Proof Store', () => {
  const remoteDid = proofRequest.payloadInfo.remotePairwiseDID
  const uid = proofRequest.payloadInfo.uid

  let initialState
  let afterProofSuccess
  beforeEach(() => {
    initialState = proofReducer(undefined, initialTestAction())
    afterProofSuccess = proofReducer(initialState, proofSuccess(proof, uid))
  })

  it('should match snapshot for proof received action', () => {
    expect(afterProofSuccess).toMatchSnapshot()
  })

  it('should convert prepared proof to indy proof format', () => {
    expect(
      convertPreparedProofToRequestedAttributes(
        preparedProof,
        originalProofRequestData
      )
    ).toMatchSnapshot()
  })

  it('should find missing attributes if any missing', () => {
    expect(
      convertPreparedProofToRequestedAttributes(
        preparedProofWithMissingAttribute,
        originalProofRequestDataMissingAttribute
      )
    ).toMatchSnapshot()
  })

  it('match snapshot while converting SelfAttestedAttributes to Indy format', () => {
    expect(
      convertSelfAttestedToIndySelfAttested(selfAttestedAttributes)
    ).toMatchSnapshot()
    expect(
      convertSelfAttestedToIndySelfAttested(selfAttestedAttributes1)
    ).toMatchSnapshot()
  })

  it('fn:convertPreparedProofToRequestedAttributes', () => {
    expect(
      convertIndyPreparedProofToAttributes(
        homeAddressPreparedProof,
        originalProofRequestData.requested_attributes
      )
    ).toMatchSnapshot()
    expect(
      convertIndyPreparedProofToAttributes(
        homeAddressPreparedProof,
        originalProofRequestData10Attributes.requested_attributes
      )
    ).toMatchSnapshot()

    expect(
      convertIndyPreparedProofToAttributes(
        homeAddressPreparedProof,
        originalProofRequestDataWithSpaces.requested_attributes
      )
    ).toMatchSnapshot()
  })

  it('store update correctly if proof fails', () => {
    expect(
      proofReducer(
        initialState,
        proofFail(uid, {
          code: 'TEST-CODE',
          message: 'test error message',
        })
      )
    ).toMatchSnapshot()
  })

  // TODO:KS Fix these tests before July 25
  xit('generate proof saga should generate proof', () => {
    const gen = generateProofSaga(getProof(uid))
    expect(gen.next().value).toEqual(select(getOriginalProofRequestData, uid))

    expect(gen.next(originalProofRequestData).value).toEqual(
      select(getPoolConfig)
    )

    const preparedProofJson = JSON.stringify(homeAddressPreparedProof)
    const requestedClaimsJson = {
      self_attested_attributes: {},
      requested_attrs: convertPreparedProofToRequestedAttributes(
        homeAddressPreparedProof,
        originalProofRequestData
      )[0],
      requested_predicates: {},
    }

    const requestedAttributes = convertIndyPreparedProofToAttributes(
      {
        ...homeAddressPreparedProof,
        self_attested_attrs: {},
      },
      originalProofRequestData.requested_attributes
    )

    expect(gen.next(preparedProofJson).value).toEqual(
      put(proofRequestAutoFill(uid, requestedAttributes))
    )

    expect(gen.next().value).toEqual(select(getProofRequestPairwiseDid, uid))

    expect(gen.next(remoteDid).value).toEqual(take(UPDATE_ATTRIBUTE_CLAIM))

    expect(
      gen.next({
        type: UPDATE_ATTRIBUTE_CLAIM,
        requestedAttrsJson: requestedClaimsJson.requested_attrs,
      }).value
    ).toEqual(put(sendProof(uid)))

    expect(gen.next(JSON.stringify(proof)).value).toEqual(
      put(proofSuccess(proof, uid))
    )

    expect(gen.next().value).toEqual(put(acceptProofRequest(uid)))

    expect(gen.next().done).toBe(true)
  })

  // TODO:KS Fix this tests before July 25
  xit('generate proof saga should work fine with missing attributes', () => {
    const gen = generateProofSaga(getProof(uid))
    expect(gen.next().value).toEqual(select(getOriginalProofRequestData, uid))

    expect(gen.next(originalProofRequestDataMissingAttribute).value).toEqual(
      select(getPoolConfig)
    )

    const preparedProofJson = JSON.stringify(
      homeAddressPreparedProofWithMissingAttribute
    )
    const [
      requestedAttributesJson,
      missingAttributes,
    ] = convertPreparedProofToRequestedAttributes(
      homeAddressPreparedProofWithMissingAttribute,
      originalProofRequestDataMissingAttribute
    )

    expect(gen.next(preparedProofJson).value).toEqual(
      put(missingAttributesFound(missingAttributes, uid))
    )

    expect(gen.next(preparedProofJson).value).toEqual(
      take(USER_SELF_ATTESTED_ATTRIBUTES)
    )

    const requestedClaimsJson = {
      self_attested_attributes: convertSelfAttestedToIndySelfAttested(
        selfAttestedAttributes
      ),
      requested_attrs: requestedAttributesJson,
      requested_predicates: {},
    }

    const requestedAttributes = convertIndyPreparedProofToAttributes(
      {
        ...homeAddressPreparedProofWithMissingAttribute,
        self_attested_attrs: { ...selfAttestedAttributes },
      },
      originalProofRequestDataMissingAttribute.requested_attributes
    )

    expect(
      gen.next({
        type: USER_SELF_ATTESTED_ATTRIBUTES,
        selfAttestedAttributes,
        uid,
      }).value
    ).toEqual(put(proofRequestAutoFill(uid, requestedAttributes)))

    expect(gen.next().value).toEqual(select(getProofRequestPairwiseDid, uid))

    expect(gen.next(remoteDid).value).toEqual(take(UPDATE_ATTRIBUTE_CLAIM))

    expect(
      gen.next({
        type: UPDATE_ATTRIBUTE_CLAIM,
        requestedAttrsJson: requestedClaimsJson.requested_attrs,
      }).value
    ).toEqual(put(sendProof(uid)))

    expect(gen.next(JSON.stringify(proof)).value).toEqual(
      put(proofSuccess(proof, uid))
    )

    expect(gen.next().value).toEqual(put(acceptProofRequest(uid)))

    expect(gen.next().done).toBe(true)
  })

  it('should reset proof store, if RESET action is raised', () => {
    expect(proofReducer(afterProofSuccess, { type: 'RESET' })).toMatchSnapshot()
  })

  it('proof store should reset for a given proof request if PROOF_REQUEST_SHOW_START is raised', () => {
    const proofStateAfterFail = proofReducer(
      initialState,
      proofFail(uid, {
        code: 'TEST-CODE',
        message: 'test error message',
      })
    )
    expect(
      proofReducer(proofStateAfterFail, proofRequestShowStart(uid))
    ).toMatchSnapshot()
  })
})


<|start_filename|>app/proof-request/proof-request.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Image, FlatList, Alert, TextInput } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { KeyboardAwareFlatList } from 'react-native-keyboard-aware-scroll-view'
import debounce from 'lodash.debounce'
import Swiper from 'react-native-swiper'

import {
  Container,
  CustomView,
  CustomButton,
  CustomText,
  Avatar,
  Icon,
  ConnectionTheme,
  ClaimProofHeader,
  Separator,
  FooterActions,
  UserAvatar,
  headerStyles,
} from '../components'
import { homeRoute } from '../common/'
import {
  OFFSET_2X,
  OFFSET_1X,
  color,
  OFFSET_3X,
  OFFSET_4X,
  OFFSET_5X,
  OFFSET_9X,
  isiPhone5,
} from '../common/styles'
import type { Attribute } from '../push-notification/type-push-notification'
import type { Store } from '../store/type-store'
import type {
  ProofRequestProps,
  AdditionalProofDataPayload,
  ProofRequestAttributeListState,
  MissingAttributes,
  ProofRequestState,
  ProofRequestAttributeListProp,
  SelfAttestedAttributes,
} from './type-proof-request'
import ProofModal from './proof-modal'
import {
  rejectProofRequest,
  acceptProofRequest,
  ignoreProofRequest,
  proofRequestShown,
  proofRequestShowStart,
} from './proof-request-store'
import {
  getConnectionLogoUrl,
  getUserAvatarSource,
} from '../store/store-selector'
import { ERROR_CODE_MISSING_ATTRIBUTE } from '../proof/type-proof'
import type {
  GenericObject,
  CustomError,
  GenericStringObject,
} from '../common/type-common'
import {
  PRIMARY_ACTION_SEND,
  PRIMARY_ACTION_GENERATE_PROOF,
  SECONDARY_ACTION_IGNORE,
  MESSAGE_MISSING_ATTRIBUTES_DESCRIPTION,
  MESSAGE_MISSING_ATTRIBUTES_TITLE,
  MESSAGE_ERROR_PROOF_GENERATION_TITLE,
  MESSAGE_ERROR_PROOF_GENERATION_DESCRIPTION,
  PROOF_STATUS,
} from './type-proof-request'
import {
  userSelfAttestedAttributes,
  updateAttributeClaim,
  getProof,
} from '../proof/proof-store'
import type { ImageSource } from '../common/type-common'

export function generateStateForMissingAttributes(
  missingAttributes: MissingAttributes | {}
) {
  return Object.keys(missingAttributes).reduce(
    (acc, attributeName) => ({
      ...acc,
      [attributeName]: '',
    }),
    {}
  )
}

export function isInvalidValues(
  missingAttributes: MissingAttributes | {},
  userFilledValues: GenericObject
): boolean {
  return Object.keys(missingAttributes).some(attributeName => {
    const userFilledValue = userFilledValues[attributeName]

    if (!userFilledValue) {
      return true
    }

    const adjustedUserFilledValue = userFilledValue.trim()

    if (!adjustedUserFilledValue) {
      return true
    }

    return false
  })
}

class ProofRequestAttributeList extends PureComponent<
  ProofRequestAttributeListProp,
  ProofRequestAttributeListState
> {
  constructor(props: ProofRequestAttributeListProp) {
    super(props)
    this.canEnableGenerateProof = debounce(
      this.canEnableGenerateProof.bind(this),
      250
    )
  }

  componentWillReceiveProps(nextProps: ProofRequestAttributeListProp) {
    if (this.props.missingAttributes !== nextProps.missingAttributes) {
      // once we know that there are missing attributes
      // then we generate state variable for each of them
      // because we will show user some input boxes and need to capture values
      // that user fills in them, also we need to enable generate proof button
      // once all the missing attributes are filled in by user
      this.setState(
        generateStateForMissingAttributes(nextProps.missingAttributes)
      )
    }
  }

  // this form is needed to fix flow error
  // because methods of a class are by default covariant
  // so we need an invariance to tell method signature
  canEnableGenerateProof = function() {
    const isInvalid = isInvalidValues(this.props.missingAttributes, this.state)
    this.props.canEnablePrimaryAction(!isInvalid, this.state)
  }

  onTextChange = (e, name: string) => {
    const { text } = e.nativeEvent
    this.setState(
      {
        [name]: text,
      },
      this.canEnableGenerateProof
    )
  }

  onSwipe = (item: Attribute) => {
    this.props.updateSelectedClaims(item)
  }

  keyExtractor = ({ label }: Attribute, index: number) => `${label}${index}`

  renderItem = ({ item, index }) => {
    // convert item to array of item
    let items = item
    if (!Array.isArray(items)) {
      items = [items]
    }

    return (
      <Swiper
        showsButtons={false}
        showsPagination={false}
        height={69}
        onIndexChanged={swipeIndex => this.onSwipe(items[swipeIndex])}
      >
        {items.map((item, itemIndex) => {
          const adjustedLabel = item.label.toLocaleLowerCase()
          const testID = 'proof-request-attribute-item'
          const logoUrl = item.data
            ? item.claimUuid &&
              this.props.claimMap &&
              this.props.claimMap[item.claimUuid] &&
              this.props.claimMap[item.claimUuid].logoUrl
              ? { uri: this.props.claimMap[item.claimUuid].logoUrl }
              : this.props.userAvatarSource ||
                require('../images/UserAvatar.png')
            : null
          const showInputBox =
            adjustedLabel in this.props.missingAttributes && !item.data

          return (
            <Container key={itemIndex}>
              <Container
                fifth
                style={[styles.attributeItem]}
                testID={`${testID}-${index}`}
                row
              >
                <Container fifth verticalSpace style={[styles.label]}>
                  <CustomView fifth style={[styles.attributeListLabel]}>
                    <CustomText
                      h7
                      uppercase
                      semiBold
                      bg="tertiary"
                      transparentBg
                      style={[styles.attributeListLabelText]}
                    >
                      {item.label}
                    </CustomText>
                  </CustomView>
                  <CustomView fifth style={[styles.attributeListValue]}>
                    {showInputBox ? (
                      <TextInput
                        autoCorrect={false}
                        blurOnSubmit={true}
                        clearButtonMode="always"
                        numberOfLines={3}
                        name={adjustedLabel}
                        multiline={true}
                        maxLength={200}
                        maxHeight={50}
                        placeholder={`Enter ${item.label}`}
                        returnKeyType="done"
                        testID={`${testID}-input-${adjustedLabel}`}
                        accessible={true}
                        accessibilityLabel={`${testID}-input-${adjustedLabel}`}
                        onChange={e => this.onTextChange(e, adjustedLabel)}
                        editable={!this.props.disableUserInputs}
                        underlineColorAndroid="transparent"
                      />
                    ) : (
                      <CustomText h6 demiBold bg="tertiary" transparentBg>
                        {item.data}
                      </CustomText>
                    )}
                  </CustomView>
                </Container>
                <Icon
                  center
                  medium
                  round
                  resizeMode="cover"
                  src={logoUrl}
                  testID={`proof-requester-logo-${index}`}
                />
              </Container>
            </Container>
          )
        })}
      </Swiper>
    )
  }

  render() {
    const attributes: Array<Attribute> = this.props.list

    return (
      <Container fifth style={[styles.proofRequestData]}>
        <KeyboardAwareFlatList
          data={attributes}
          keyExtractor={this.keyExtractor}
          ItemSeparatorComponent={Separator}
          ListFooterComponent={Separator}
          renderItem={this.renderItem}
          extraData={this.props}
          extraHeight={235}
          enableResetScrollToCoords={false}
        />
      </Container>
    )
  }
}

export function convertUserFilledValuesToSelfAttested(
  userFilledValues: GenericStringObject,
  missingAttributes: MissingAttributes | {}
): SelfAttestedAttributes {
  return Object.keys(missingAttributes).reduce((acc, name) => {
    return {
      ...acc,
      [name]: {
        name,
        data: userFilledValues[name],
        key: missingAttributes[name].key,
      },
    }
  }, {})
}

export function getPrimaryActionText(
  missingAttributes: MissingAttributes | {},
  generateProofClicked: boolean
) {
  if (generateProofClicked) {
    return PRIMARY_ACTION_SEND
  }

  return Object.keys(missingAttributes).length > 0
    ? PRIMARY_ACTION_GENERATE_PROOF
    : PRIMARY_ACTION_SEND
}

export const isPropEmpty = (prop: string) => (
  data: GenericObject | Array<Attribute>
) => {
  if (Array.isArray(data)) {
    return data.some(missingData)
  }
  return !data[prop]
}

export const missingData = isPropEmpty('data')

export function enablePrimaryAction(
  missingAttributes: MissingAttributes | {},
  generateProofClicked: boolean,
  allMissingAttributesFilled: boolean,
  error: ?CustomError,
  requestedAttributes: Attribute[]
) {
  // we need to decide on whether to enable Send/Generate-Proof button

  if (error) {
    return false
  }

  const missingCount = Object.keys(missingAttributes).length
  if (missingCount > 0) {
    if (allMissingAttributesFilled === false) {
      return false
    }

    if (generateProofClicked === false) {
      return true
    }
  }

  const isMissingData = requestedAttributes.some(missingData)
  if (isMissingData) {
    return false
  }

  return true
}

export function hasMissingAttributes(
  missingAttributes: MissingAttributes | {}
) {
  return Object.keys(missingAttributes).length > 0
}

export function getMissingAttributeNames(
  missingAttributes: MissingAttributes | {}
) {
  return Object.keys(missingAttributes).join(', ')
}

export class ProofRequest extends PureComponent<
  ProofRequestProps,
  ProofRequestState
> {
  constructor(props: ProofRequestProps) {
    super(props)
    if (props.navigation.state) {
      props.proofRequestShowStart(props.navigation.state.params.uid)
    }
  }

  state = {
    allMissingAttributesFilled: false,
    generateProofClicked: false,
    selfAttestedAttributes: {},
    disableUserInputs: false,
    selectedClaims: {},
    disableSendButton: false,
  }

  close = () => {
    this.props.navigation.goBack()
  }

  onIgnore = () => {
    this.props.ignoreProofRequest(this.props.uid)
    this.close()
  }

  onReject = () => {
    this.props.rejectProofRequest(this.props.uid)
    this.close()
  }

  onSend = () => {
    if (
      this.state.generateProofClicked ||
      !hasMissingAttributes(this.props.missingAttributes)
    ) {
      // if we don't find any missing attributes then
      // user will never see generate proof button and we don't need to wait for
      // generate proof button to be clicked after all attributes are filled
      // this.props.getProof(this.props.uid)
      this.setState({
        disableSendButton: true,
      })
      this.props.updateAttributeClaim(this.props.uid, this.state.selectedClaims)
    } else {
      // we need to change the text to send once we know that generate proof is clicked
      // also, we need to disable user inputs once user has submitted those fields
      // because user can't change them now
      this.setState({
        generateProofClicked: true,
        disableUserInputs: true,
        disableSendButton: false,
      })
      this.props.userSelfAttestedAttributes(
        convertUserFilledValuesToSelfAttested(
          this.state.selfAttestedAttributes,
          this.props.missingAttributes
        ),
        this.props.uid
      )
    }
  }

  onRetry = () => {
    this.props.updateAttributeClaim(this.props.uid, this.state.selectedClaims)
  }

  canEnablePrimaryAction = (
    canEnable: boolean,
    selfAttestedAttributes: GenericStringObject
  ) => {
    this.setState({
      allMissingAttributesFilled: canEnable,
      selfAttestedAttributes,
    })
  }

  componentDidMount() {
    this.props.proofRequestShown(this.props.uid)
    this.props.getProof(this.props.uid)
  }

  componentWillReceiveProps(nextProps: ProofRequestProps) {
    if (
      this.props.missingAttributes !== nextProps.missingAttributes &&
      hasMissingAttributes(nextProps.missingAttributes)
    ) {
      Alert.alert(
        MESSAGE_MISSING_ATTRIBUTES_TITLE,
        MESSAGE_MISSING_ATTRIBUTES_DESCRIPTION(nextProps.name)
      )
    }

    if (
      (this.props.proofGenerationError !== nextProps.proofGenerationError &&
        nextProps.proofGenerationError) ||
      nextProps.proofStatus === PROOF_STATUS.SEND_PROOF_FAIL
    ) {
      setTimeout(() => {
        Alert.alert(
          MESSAGE_ERROR_PROOF_GENERATION_TITLE,
          MESSAGE_ERROR_PROOF_GENERATION_DESCRIPTION,
          [
            {
              text: 'Ok',
              onPress: () => {
                this.setState({
                  disableSendButton: false,
                })
              },
            },
          ],
          { cancelable: false }
        )
      }, 300)
    }

    if (
      this.props.errorProofSendData !== nextProps.errorProofSendData &&
      nextProps.errorProofSendData
    ) {
      setTimeout(() => {
        Alert.alert(
          MESSAGE_ERROR_PROOF_GENERATION_TITLE,
          MESSAGE_ERROR_PROOF_GENERATION_DESCRIPTION,
          [
            {
              text: 'Retry',
              onPress: () => {
                this.onRetry()
              },
            },
            {
              text: 'Cancel',
              onPress: () => {
                this.onIgnore()
              },
            },
          ],
          { cancelable: false }
        )
      }, 300)
    }

    if (
      this.props.data &&
      this.props.data.requestedAttributes !== nextProps.data.requestedAttributes
    ) {
      const selectedClaims = nextProps.data.requestedAttributes.reduce(
        (acc, item) => {
          const items = { ...acc }
          if (Array.isArray(item)) {
            if (item[0].claimUuid) {
              items[`${item[0].key}`] = [
                item[0].claimUuid,
                true,
                item[0].cred_info,
              ]
            }
          }
          return items
        },
        {}
      )
      this.setState({ selectedClaims })
    }
  }

  updateSelectedClaims = (item: Attribute) => {
    if (this.state.selectedClaims && item && item.key) {
      const selectedClaims = {
        ...this.state.selectedClaims,
        [`${item.key}`]: [item.claimUuid, true, item.cred_info],
      }
      this.setState({ selectedClaims })
    }
  }

  renderAvatarWithSource = (avatarSource: number | ImageSource) => (
    <Icon
      center
      halo
      extraLarge
      resizeMode="cover"
      src={avatarSource}
      style={[styles.verifierLogo]}
      iconStyle={[styles.verifierLogoIcon]}
      haloStyle={styles.logoHaloStyle}
      testID="proof-request-verifier-logo"
    />
  )

  render() {
    const {
      data,
      name,
      uid,
      isValid,
      proofStatus,
      remotePairwiseDID,
      logoUrl,
      claimMap,
      missingAttributes,
      proofGenerationError,
    } = this.props
    const testID = 'proof-request'
    const { name: title, requestedAttributes } = data
    const logoUri = logoUrl
      ? { uri: logoUrl }
      : require('../images/logo_sovrin.png')

    const primaryActionText = getPrimaryActionText(
      missingAttributes,
      this.state.generateProofClicked
    )
    const enablePrimaryActionStatus = enablePrimaryAction(
      missingAttributes,
      this.state.generateProofClicked,
      this.state.allMissingAttributesFilled,
      proofGenerationError,
      requestedAttributes
    )

    if (!isValid) {
      return (
        <Container>
          <Container fifth center>
            <CustomText h5 bg="fifth">
              Invalid proof request. Please ignore.
            </CustomText>
          </Container>
          <FooterActions
            onDecline={this.onReject}
            denyTitle="Ignore"
            testID={testID}
          />
        </Container>
      )
    }

    return (
      <Container fifth>
        <ClaimProofHeader
          message={`${name} would like you to share:`}
          title={title}
          onClose={this.onIgnore}
          logoUrl={logoUrl}
          testID={testID}
        >
          <Icon
            absolute="TopRight"
            src={require('../images/close.png')}
            small
            testID={`${testID}-icon-close`}
            onPress={this.close}
            style={[styles.headerCloseIconContainer]}
          />
          <CustomView fifth hCenter style={[styles.headerStripLogoContainer]}>
            <ConnectionTheme logoUrl={logoUrl} style={[styles.strip]} />
            <CustomView
              row
              vCenter
              spaceBetween
              style={[styles.avatarsContainer]}
              testID={`${testID}-text-avatars-container`}
            >
              <UserAvatar>{this.renderAvatarWithSource}</UserAvatar>
              <Image
                style={[styles.checkMark]}
                source={require('../images/icon_rightArrow.png')}
                testID={`${testID}-check-mark`}
                accessible={true}
                accessibilityLabel={`${testID}-check-mark`}
              />
              <Icon
                center
                halo
                extraLarge
                resizeMode="cover"
                src={logoUri}
                haloStyle={styles.logoHaloStyle}
                style={[styles.verifierLogo]}
                iconStyle={[styles.verifierLogoIcon]}
                testID={`${testID}-verifier-logo`}
                backgroundRoundWhite
              />
            </CustomView>
          </CustomView>
        </ClaimProofHeader>

        <ProofRequestAttributeList
          list={requestedAttributes}
          claimMap={claimMap}
          missingAttributes={missingAttributes}
          canEnablePrimaryAction={this.canEnablePrimaryAction}
          disableUserInputs={this.state.disableUserInputs}
          userAvatarSource={this.props.userAvatarSource}
          updateSelectedClaims={this.updateSelectedClaims}
        />
        <FooterActions
          logoUrl={logoUrl}
          onAccept={this.onSend}
          onDecline={this.onReject}
          denyTitle="Ignore"
          acceptTitle={primaryActionText}
          disableAccept={
            !enablePrimaryActionStatus || this.state.disableSendButton
          }
          testID={testID}
        />
        {proofStatus !== PROOF_STATUS.SEND_PROOF_FAIL ? (
          <ProofModal
            proofStatus={proofStatus}
            title={title}
            name={name}
            onContinue={this.close}
            logoUrl={logoUrl}
          />
        ) : null}
      </Container>
    )
  }
}

// we need to navigate to this screen only by passing "proofRequestId"  in the props like below.
// this.props.navigation.navigate(proofRequestRoute,{'proofRequestId': 'CRM2M28')
const mapStateToProps = (state: Store, props) => {
  const { proofRequest } = state
  const { uid } = props.navigation.state.params
  const proofRequestData = proofRequest[uid] || {}
  const {
    data,
    requester = {},
    proofStatus,
    remotePairwiseDID,
    missingAttributes = {},
  } = proofRequestData
  const { name } = requester
  const isValid = proofRequestData && data && data.requestedAttributes
  const proofGenerationError = state.proof[uid] ? state.proof[uid].error : null
  const errorProofSendData =
    state.proof[uid] && state.proof[uid].proofData
      ? state.proof[uid].proofData.error
      : null

  return {
    isValid,
    data,
    logoUrl: getConnectionLogoUrl(state, remotePairwiseDID),
    name,
    uid,
    proofStatus,
    proofGenerationError,
    claimMap: state.claim.claimMap,
    missingAttributes,
    userAvatarSource: getUserAvatarSource(state.user.avatarName),
    errorProofSendData,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      proofRequestShown,
      acceptProofRequest,
      ignoreProofRequest,
      rejectProofRequest,
      updateAttributeClaim,
      getProof,
      userSelfAttestedAttributes,
      proofRequestShowStart,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(ProofRequest)

const styles = StyleSheet.create({
  headerStripLogoContainer: {
    height: 90,
    marginHorizontal: isiPhone5 ? OFFSET_5X / 2 : OFFSET_4X,
  },
  strip: {
    position: 'absolute',
    left: isiPhone5 ? OFFSET_3X : OFFSET_5X,
    right: isiPhone5 ? OFFSET_3X : OFFSET_5X,
    height: 30,
    backgroundColor: color.actions.secondary,
    zIndex: -1,
  },
  verifierLogo: {
    zIndex: 1,
  },
  verifierLogoIcon: {
    borderRadius: 35,
  },
  logoHaloStyle: {
    width: 87,
    height: 87,
  },
  proofRequestData: {
    zIndex: -1,
  },
  attributeListLabel: {
    marginVertical: 2,
  },
  attributeListLabelText: {
    paddingVertical: 2,
  },
  attributeListValue: {
    marginBottom: OFFSET_1X,
  },
  headerCloseIconContainer: {
    position: 'absolute',
    top: OFFSET_3X,
    right: OFFSET_3X / 2,
    zIndex: 3,
  },
  avatarsContainer: {
    height: OFFSET_9X,
    marginVertical: OFFSET_3X,
    marginHorizontal: OFFSET_1X,
  },
  checkMark: {
    width: 20,
    height: 20,
  },
  attributeItem: {
    paddingHorizontal: OFFSET_1X,
  },
  label: {
    marginLeft: OFFSET_1X / 2,
  },
})


<|start_filename|>app/lock/lock-pin-code-setup.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Keyboard, Platform } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import {
  Container,
  CustomText,
  CustomButton,
  CustomView,
  PinCodeBox,
  Icon,
  CustomHeader,
} from '../components'
import {
  lockSelectionRoute,
  lockPinSetupHomeRoute,
  lockSetupSuccessRoute,
  settingsTabRoute,
  lockEnterPinRoute,
} from '../common'
import {
  color,
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_6X,
  OFFSET_7X,
} from '../common/styles'
import { setPinAction, enableTouchIdAction } from './lock-store'
import type { LockPinSetupState, LockPinCodeSetupProps } from './type-lock'
import { PIN_SETUP_STATE } from './type-lock'
import { tertiaryHeaderStyles } from '../components/layout/header-styles'

const styles = StyleSheet.create({
  headerLeft: {
    width: OFFSET_2X,
  },
  title: {
    marginTop: OFFSET_6X,
    marginBottom: OFFSET_7X,
  },
  titleText: {
    lineHeight: 28,
    letterSpacing: 0.5,
    paddingHorizontal: OFFSET_1X,
  },
})

const ReEnterPinFailText = (
  <CustomText style={[styles.titleText]} center h4 bg="tertiary" tertiary thick>
    Your passcodes do not match, please start over.
  </CustomText>
)

export class LockPinSetup extends PureComponent<
  LockPinCodeSetupProps,
  LockPinSetupState
> {
  state: LockPinSetupState = {
    pinSetupState: PIN_SETUP_STATE.INITIAL,
    enteredPin: null,
    pinReEnterSuccessPin: null,
    keyboardHidden: false,
    showCustomKeyboard: false,
  }

  pinCodeBox = null
  keyboardDidHideListener = null
  keyboardDidShowListener = null

  static navigationOptions = ({ navigation }) => ({
    header: (
      <CustomHeader
        flatHeader
        backgroundColor={color.bg.tertiary.color}
        leftComponent={
          <CustomView>
            <Icon
              small
              testID={'back-arrow'}
              iconStyle={[styles.headerLeft]}
              src={require('../images/icon_backArrow.png')}
              resizeMode="contain"
              onPress={() =>
                navigation.state.params &&
                navigation.state.params.existingPin === true
                  ? navigation.navigate(settingsTabRoute)
                  : navigation.navigate(lockSelectionRoute)
              }
            />
          </CustomView>
        }
        centerComponent={
          <CustomText bg="tertiary" tertiary transparentBg semiBold>
            App Security
          </CustomText>
        }
      />
    ),
  })

  setPinSetupStateToInitial = () => {
    this.setState({ pinSetupState: PIN_SETUP_STATE.INITIAL })
  }

  setPinSetupStateToInitialDelayed = () => {
    setTimeout(this.setPinSetupStateToInitial, 1000)
  }

  onPinSetup = (pin: string) => {
    this.props.setPinAction(pin)
    this.props.navigation.state &&
    this.props.navigation.state.params &&
    this.props.navigation.state.params.existingPin === true
      ? this.props.navigation.navigate(lockSetupSuccessRoute, {
          changePin: true,
        })
      : this.props.navigation.navigate(lockSetupSuccessRoute)
  }

  onTouchIdSetup = () => {
    this.props.enableTouchIdAction()
  }

  onPinReEnterFail = () => {
    this.setState({
      pinSetupState: PIN_SETUP_STATE.REENTER_FAIL,
      enteredPin: null,
    })
    this.pinCodeBox && this.pinCodeBox.clear()
    this.setPinSetupStateToInitialDelayed()
  }

  onPinReEnterSuccess = (pin: string) => {
    this.pinCodeBox && this.pinCodeBox.hideKeyboard()
    this.setState({
      pinSetupState: PIN_SETUP_STATE.REENTER_SUCCESS,
      pinReEnterSuccessPin: pin,
    })
  }

  onKeyboardHide = (status: boolean, event: any = null) => {
    if (this.state.keyboardHidden !== status) {
      this.setState({
        keyboardHidden: status,
        showCustomKeyboard: false,
      })
    } else {
      if (
        status === false &&
        event &&
        event.endCoordinates.height < 100 &&
        !this.state.keyboardHidden &&
        Platform.OS === 'ios'
      ) {
        this.setState({
          showCustomKeyboard: true,
        })
      } else {
        this.setState({
          showCustomKeyboard: false,
        })
      }
    }
  }

  onFirstPinEnter = (enteredPin: string) => {
    this.setState({
      pinSetupState: PIN_SETUP_STATE.REENTER,
      enteredPin,
    })
    this.pinCodeBox && this.pinCodeBox.clear()
  }

  onPinComplete = (pin: string) => {
    if (this.state.enteredPin) {
      // if we found a entered pin, that means user is re-entering pin
      if (this.state.enteredPin === pin) {
        this.onPinReEnterSuccess(pin)
      } else {
        this.onPinReEnterFail()
      }
    } else {
      // this is the first time user has entered pin
      this.onFirstPinEnter(pin)
    }
  }

  componentDidMount() {
    this.keyboardDidHideListener = Keyboard.addListener(
      'keyboardDidHide',
      () => {
        this.onKeyboardHide(true)
      }
    )
    this.keyboardDidShowListener = Keyboard.addListener(
      'keyboardDidShow',
      e => {
        this.onKeyboardHide(false, e)
      }
    )
  }

  componentDidUpdate(prevProps: LockPinCodeSetupProps) {
    if (
      this.state.keyboardHidden &&
      this.state.pinSetupState === PIN_SETUP_STATE.REENTER_SUCCESS &&
      this.props.navigation.isFocused()
    ) {
      const pin = this.state.pinReEnterSuccessPin || ''
      this.onPinSetup(pin)
    }
    if (this.props.navigation.isFocused()) {
      if (!this.keyboardDidHideListener && !this.keyboardDidShowListener) {
        this.keyboardDidHideListener = Keyboard.addListener(
          'keyboardDidHide',
          () => {
            this.onKeyboardHide(true)
          }
        )
        this.keyboardDidShowListener = Keyboard.addListener(
          'keyboardDidShow',
          e => {
            this.onKeyboardHide(false, e)
          }
        )
      }
    } else {
      if (this.state.pinSetupState === PIN_SETUP_STATE.REENTER_SUCCESS) {
        this.setState({
          pinSetupState: PIN_SETUP_STATE.INITIAL,
          pinReEnterSuccessPin: null,
          keyboardHidden: false,
        })
      }
      this.keyboardDidShowListener && this.keyboardDidShowListener.remove()
      this.keyboardDidHideListener && this.keyboardDidHideListener.remove()
    }
  }

  componentWillUnmount() {
    this.keyboardDidShowListener && this.keyboardDidShowListener.remove()
    this.keyboardDidHideListener && this.keyboardDidHideListener.remove()
  }

  render() {
    const { pinSetupState } = this.state
    const passCodeSetupText =
      this.props.navigation.state &&
      this.props.navigation.state.params &&
      this.props.navigation.state.params.touchIdActive === true
        ? 'Set up a passcode in case Biometrics fails'
        : 'Set up a passcode'

    const EnterPinText = (
      <CustomText
        style={[styles.titleText]}
        center
        h4
        bg="tertiary"
        tertiary
        thick
      >
        {this.props.navigation.state &&
        this.props.navigation.state.params &&
        this.props.navigation.state.params.existingPin === true
          ? 'Set up a new passcode'
          : passCodeSetupText}
      </CustomText>
    )
    const ReEnterPinText = (
      <CustomText
        style={[styles.titleText]}
        center
        h4
        bg="tertiary"
        tertiary
        thick
      >
        {this.props.navigation.state &&
        this.props.navigation.state.params &&
        this.props.navigation.state.params.existingPin === true
          ? 'Re-enter new passcode'
          : 'Re-enter passcode'}
      </CustomText>
    )

    return (
      <Container tertiary>
        <CustomView style={[styles.title]}>
          {pinSetupState === PIN_SETUP_STATE.INITIAL && EnterPinText}
          {pinSetupState === PIN_SETUP_STATE.REENTER && ReEnterPinText}
          {pinSetupState === PIN_SETUP_STATE.REENTER_SUCCESS && ReEnterPinText}
          {pinSetupState === PIN_SETUP_STATE.REENTER_FAIL && ReEnterPinFailText}
        </CustomView>
        <CustomView center>
          <PinCodeBox
            ref={pinCodeBox => {
              this.pinCodeBox = pinCodeBox
            }}
            onPinComplete={this.onPinComplete}
            enableCustomKeyboard={this.state.showCustomKeyboard}
          />
        </CustomView>
      </Container>
    )
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      setPinAction,
      enableTouchIdAction,
    },
    dispatch
  )

export default createStackNavigator({
  [lockPinSetupHomeRoute]: {
    screen: connect(null, mapDispatchToProps)(LockPinSetup),
  },
})


<|start_filename|>app/api/type-api.js<|end_filename|>
// @flow
import type { GenericObject } from '../common/type-common'
import { MESSAGE_TYPE } from './api-constants'
import type { IndyClaimRequest } from '../bridge/react-native-cxs/type-cxs'
import type { ProofApiData } from '../proof-request/type-proof-request'

export type ApiData = {
  method: string,
  mode: string,
  headers: { [string]: string },
  body?: string,
}

export type BackendError = {
  statusCode: string,
  statusMsg: string,
}

export type GetInvitationLinkApiData = {
  agencyUrl: string,
  smsToken: string,
}

export type MessageApiData = {
  agencyUrl: string,
  dataBody: GenericObject,
}

export type DownloadInvitationApiData = {
  url: string,
}

export type SendAuthenticationResponseApiData = {
  data: {
    identifier: string,
    dataBody: GenericObject,
  },
  config: {
    agencyUrl: string,
  },
}

export type SendMessageApiData = {
  agencyUrl: string,
  userPairwiseDid: string,
  agentPayload: GenericObject,
}

export type ApiClaimRequest = {
  userPairwiseDid: string,
  remoteDid: string,
} & IndyClaimRequest

export type SendClaimRequestApiData = {
  agencyUrl: string,
  userPairwiseDid: string,
  responseMsgId: string,
  claimRequest: ApiClaimRequest,
}
export type SendProofApiData = {
  agencyUrl: string,
  userPairwiseDid: string,
  responseMsgId: string,
  proof: ProofApiData,
}

export type EdgeClaimRequest = {
  msg_type: typeof MESSAGE_TYPE.CLAIM_REQUEST,
  version: string,
  to_did: string,
  from_did: string,
  tid: string,
  mid: string,
} & IndyClaimRequest

export type EnvironmentDetailUrlDownloaded = {
  agencyDID: string,
  agencyUrl: string,
  agencyVerificationKey: string,
  poolConfig: string,
}


<|start_filename|>app/feedback/index.js<|end_filename|>
// @flow

import { Apptentive, ApptentiveConfiguration } from 'apptentive-react-native'
import { apptentiveCredentials } from './message-constants'

const configuration = new ApptentiveConfiguration(
  apptentiveCredentials.apptentiveKey,
  apptentiveCredentials.apptentiveSignature
)

export const setupFeedback = ApptentiveMessage()

function ApptentiveMessage() {
  if (__DEV__) configuration.logLevel = 'verbose'
  Apptentive.register(configuration)
    .then(() => {
      Apptentive.onAuthenticationFailed = reason => {
        if (__DEV__) {
          console.log('Error', `Authentication failed:\n${reason}`)
        }
      }
    })
    .catch(error => {
      if (__DEV__) {
        console.log('Error', `Can't register Apptentive:\n${error.message}`)
      }
    })
}


<|start_filename|>app/components/badges-dot.js<|end_filename|>
// @flow
import React, { Component, PureComponent } from 'react'
import { View, StyleSheet, Platform } from 'react-native'
import { HAIRLINE_WIDTH, maroonRed, white } from '../common/styles/constant'

type DotProps = {
  size: string,
}

export class Dot extends PureComponent<DotProps, void> {
  render() {
    const { size } = this.props
    const dotSize =
      size === 'small'
        ? styles.badgeSmall
        : size === 'medium' ? styles.badgeMedium : styles.badgeLarge
    return <View style={[styles.badge, dotSize]} />
  }
}

const styles = StyleSheet.create({
  badge: {
    backgroundColor: maroonRed,
    ...Platform.select({
      ios: {
        borderWidth: HAIRLINE_WIDTH,
      },
      android: {
        borderWidth: 1,
      },
    }),
    borderColor: white,
  },
  badgeSmall: {
    width: 15,
    height: 15,
    borderRadius: 10,
  },
  badgeMedium: {
    width: 20,
    height: 20,
    borderRadius: 10,
  },
  badgeLarge: {
    width: 25,
    height: 25,
    borderRadius: 15,
  },
})


<|start_filename|>app/offline/offline-store.js<|end_filename|>
// @flow
import { takeLatest, all, call, select, take } from 'redux-saga/effects'
import { OFFLINE_STATUS } from './type-offline'
import type {
  OfflineStatus,
  OfflineStore,
  OfflineActions,
} from './type-offline'
import { captureError } from '../services/error/error-handler'
import { ensureVcxInitSuccess } from '../store/config-store'
import { VCX_INIT_FAIL } from '../store/type-config-store'
import { getOfflineStatus } from '../store/store-selector'

const initialState: OfflineStore = {
  offline: false,
}

export const offline = (offline: boolean): OfflineStatus => ({
  type: OFFLINE_STATUS,
  offline,
})

export function* watchOffline(): any {
  yield all([watchVcxInitFail()])
}

export function* watchVcxInitFail(): any {
  yield takeLatest(VCX_INIT_FAIL, vcxFailedOfflineSaga)
}

export function* vcxFailedOfflineSaga(): Generator<*, *, *> {
  try {
    const offline: boolean = yield select(getOfflineStatus)
    if (offline) {
      // since vcx failed, we want to know if vcx failed while app is offline
      // if app is in offline mode, only then we want to execute this saga

      while (true) {
        // if app was offline, now we wait for offline status to change
        const offlineAction: OfflineStatus = yield take(OFFLINE_STATUS)
        if (!offlineAction.offline) {
          // if device is connected now, then we re-trigger vcxInit
          yield call(ensureVcxInitSuccess)
          // end function execution once we have triggered vcx init
          return
        }
      }
    }
  } catch (e) {
    captureError(e)
    console.error(`vcxFailedOfflineSaga: ${e}`)
  }
}

export default function offlineReducer(
  state: OfflineStore = initialState,
  action: OfflineActions
): OfflineStore {
  switch (action.type) {
    case OFFLINE_STATUS:
      return {
        offline: action.offline,
      }
    default:
      return state
  }
}


<|start_filename|>app/bridge/react-native-cxs/RNCxs.js<|end_filename|>
// @flow
import { NativeModules, Platform } from 'react-native'
import memoize from 'lodash.memoize'
import type {
  Metadata,
  IndyClaimOffer,
  ConnectAgencyResponse,
  RegisterAgencyResponse,
  CreateOneTimeAgentResponse,
  CreatePairwiseAgentResponse,
  AcceptInvitationResponse,
  CxsCredentialOfferResult,
  InitWithGenesisPathConfig,
  VcxProvisionResult,
  VcxProvision,
  CxsInitConfig,
  VcxInitConfig,
  CxsPushTokenConfig,
  VcxCredentialOfferResult,
  VcxCredentialOffer,
  VcxClaimInfo,
  VcxConnectionConnectResult,
  VcxProofRequest,
  WalletTokenInfo,
  PaymentAddress,
} from './type-cxs'
import type { InvitationPayload } from '../../invitation/type-invitation'
import {
  convertAgencyConfigToVcxProvision,
  convertVcxProvisionResultToUserOneTimeInfo,
  convertCxsInitToVcxInit,
  convertCxsPushConfigToVcxPushTokenConfig,
  convertInvitationToVcxConnectionCreate,
  convertVcxConnectionToCxsConnection,
  convertVcxCredentialOfferToCxsClaimOffer,
  paymentHandle,
  getWalletKey,
  convertSovrinTokensToSovrinAtoms,
  convertSovrinAtomsToSovrinTokens,
  convertVcxLedgerFeesToLedgerFees,
} from './vcx-transformers'
import type { UserOneTimeInfo } from '../../store/user/type-user-store'
import type { AgencyPoolConfig } from '../../store/type-config-store'
import type { MyPairwiseInfo } from '../../store/type-connection-store'
import type {
  ClaimOfferPushPayload,
  ClaimPushPayload,
} from '../../push-notification/type-push-notification'
import type {
  WalletHistoryEvent,
  WalletPayload,
} from '../../wallet/type-wallet'
import type { GenericStringObject } from '../../common/type-common'
import type { Passphrase } from '../../backup/type-backup'
import type { GetClaimVcxResult } from '../../claim/type-claim'
import uniqueId from 'react-native-unique-id'
import { smallDeviceMemory } from './type-cxs'
import { secureSet } from '../../services/storage'
import { __uniqueId } from '../../store/type-config-store'
import type { LedgerFeesData } from '../../store/ledger/type-ledger-store'

const { RNIndy } = NativeModules

export async function acceptInvitationVcx(
  connectionHandle: number
): Promise<MyPairwiseInfo> {
  // hard coding connection options to QR type for now, because vcx needs connection options
  // API for vcx assumes that it is running on enterprise side and not from consumer side
  // hence it tries to create connection with connection type.
  // However, our need is not to create a connection but to create a connection instance
  // with existing invitation. So, for now for any invitation type QR or SMS
  // we are hard coding connection option to QR
  const connectionOptions = { connection_type: 'QR', phone: '' }
  const result: string = await RNIndy.vcxAcceptInvitation(
    connectionHandle,
    JSON.stringify(connectionOptions)
  )
  // TODO:KS Remove below API call once sdk team returns pairwise info in above api
  // above call does not return pairwise did information, but we need pairwise info
  // to store that information and have those details available while making a connection
  // we have to make an extra call to get pairwise info
  const serializedConnection: string = await serializeConnection(
    connectionHandle
  )

  const vcxConnection: { data: VcxConnectionConnectResult } = JSON.parse(
    serializedConnection
  )

  return convertVcxConnectionToCxsConnection(vcxConnection.data)
}

export async function updatePushTokenVcx(pushTokenConfig: CxsPushTokenConfig) {
  return await RNIndy.vcxUpdatePushToken(
    JSON.stringify(convertCxsPushConfigToVcxPushTokenConfig(pushTokenConfig))
  )
}

export async function deleteConnection(connectionHandle: number) {
  return await RNIndy.deleteConnection(connectionHandle)
}

export async function resetVcx(removeData: boolean): Promise<boolean> {
  // we would remove above reset method and rename this method to reset
  // once we have integration available with vcx
  const result: boolean = await RNIndy.reset(true)

  return result
}

export async function vcxShutdown(deletePool: boolean): Promise<boolean> {
  const result: Number = await RNIndy.shutdownVcx(deletePool)

  return true
}

export async function getColor(imagePath: string): Promise<Array<string>> {
  return RNIndy.getColor(imagePath)
}

export async function sendTokenAmount(
  tokenAmount: string,
  recipientWalletAddress: string
): Promise<boolean> {
  const sovrinAtoms = convertSovrinTokensToSovrinAtoms(tokenAmount)
  return RNIndy.sendTokens(paymentHandle, sovrinAtoms, recipientWalletAddress)
}

export async function createOneTimeInfo(
  agencyConfig: AgencyPoolConfig
): Promise<UserOneTimeInfo> {
  const walletPoolName = await getWalletPoolName()
  const vcxProvisionConfig: VcxProvision = await convertAgencyConfigToVcxProvision(
    agencyConfig,
    walletPoolName
  )
  const provisionVcxResult: string = await RNIndy.createOneTimeInfo(
    JSON.stringify(vcxProvisionConfig)
  )
  const provisionResult: VcxProvisionResult = JSON.parse(provisionVcxResult)
  return convertVcxProvisionResultToUserOneTimeInfo(provisionResult)
}

export async function init(
  config: CxsInitConfig,
  fileName: string
): Promise<boolean> {
  const genesis_path: string = await RNIndy.getGenesisPathWithConfig(
    config.poolConfig,
    fileName
  )

  const initConfig = {
    ...config,
    genesis_path,
  }
  const walletPoolName = await getWalletPoolName()
  const vcxInitConfig: VcxInitConfig = await convertCxsInitToVcxInit(
    initConfig,
    walletPoolName
  )
  const initResult: boolean = await RNIndy.init(JSON.stringify(vcxInitConfig))

  return initResult
}

// TODO:KS Need to rename this to something like walletInit
export async function simpleInit(): Promise<boolean> {
  const walletPoolName = await getWalletPoolName()
  const wallet_key = await getWalletKey()
  const initConfig = {
    wallet_name: walletPoolName.walletName,
    wallet_key,
  }
  const initResult: boolean = await RNIndy.init(JSON.stringify(initConfig))
  return initResult
}

export const getWalletPoolName = memoize(async function() {
  const appUniqueId = await uniqueId()
  await secureSet(__uniqueId, appUniqueId)
  const walletName = `${appUniqueId}-cm-wallet`
  // Not sure why, but VCX is applying validation check on pool name
  // they don't like alphanumeric or _, so we have to remove "-"
  // from our guid that we generated
  const strippedAppUniqueId = appUniqueId.replace(/\-/g, '')
  const poolName = `${strippedAppUniqueId}cmpool`
  return {
    walletName,
    poolName,
  }
})

export async function createConnectionWithInvite(
  invitation: InvitationPayload
): Promise<number> {
  const { invite_details } = convertInvitationToVcxConnectionCreate(invitation)
  const connectionHandle: number = await RNIndy.createConnectionWithInvite(
    invitation.requestId,
    JSON.stringify(invite_details)
  )

  return connectionHandle
}

export async function serializeConnection(
  connectionHandle: number
): Promise<string> {
  const serializedConnection: string = await RNIndy.getSerializedConnection(
    connectionHandle
  )

  return serializedConnection
}

// cache Promise of serializedString so that we don't call Bridge method again
export const getHandleBySerializedConnection = memoize(async function(
  serializedConnection: string
): Promise<number> {
  const connectionHandle: number = await RNIndy.deserializeConnection(
    serializedConnection
  )

  return connectionHandle
})

export async function downloadClaimOffer(
  connectionHandle: number,
  sourceId: string,
  messageId: string
): Promise<CxsCredentialOfferResult> {
  const {
    credential_offer,
    credential_handle,
  }: VcxCredentialOfferResult = await RNIndy.credentialCreateWithMsgId(
    sourceId,
    connectionHandle,
    messageId
  )

  const {
    credential_offer: vcxCredentialOffer,
    price,
  }: { credential_offer: VcxCredentialOffer, price: number } = JSON.parse(
    credential_offer
  )

  vcxCredentialOffer.price = price
    ? convertSovrinAtomsToSovrinTokens(price)
    : null

  return {
    claimHandle: credential_handle,
    claimOffer: convertVcxCredentialOfferToCxsClaimOffer(vcxCredentialOffer),
  }
}

export async function serializeClaimOffer(
  claimHandle: number
): Promise<string> {
  const serializedClaimOffer: string = await RNIndy.serializeClaimOffer(
    claimHandle
  )

  return serializedClaimOffer
}

export const getClaimHandleBySerializedClaimOffer = memoize(async function(
  serializedClaimOffer: string
): Promise<number> {
  const claimHandle: number = await RNIndy.deserializeClaimOffer(
    serializedClaimOffer
  )

  return claimHandle
})

export async function sendClaimRequest(
  claimHandle: number,
  connectionHandle: number,
  paymentHandle: number
): Promise<void> {
  return await RNIndy.sendClaimRequest(
    claimHandle,
    connectionHandle,
    paymentHandle
  )
}

export async function downloadProofRequest(
  sourceId: string,
  connectionHandle: number,
  messageId: string
): Promise<VcxProofRequest> {
  const {
    proofHandle,
    proofRequest,
  }: {
    proofHandle: number,
    proofRequest: string,
  } = await RNIndy.proofCreateWithMsgId(sourceId, connectionHandle, messageId)

  const vcxProofRequest: VcxProofRequest = JSON.parse(proofRequest)

  return {
    ...vcxProofRequest,
    proofHandle,
  }
}

export async function getWalletBalance(): Promise<string> {
  const { balance_str: balance }: WalletTokenInfo = await getWalletTokenInfo()

  return convertSovrinAtomsToSovrinTokens(balance)
}

export async function getWalletAddresses(): Promise<string[]> {
  const { addresses }: WalletTokenInfo = await getWalletTokenInfo()

  // TODO:KS For now we don't need to store any other data on our react-native
  // when we need to store all data, then we would return only addresses
  // for now we are just returning addresses and ignoring anything else
  return addresses.map((address: PaymentAddress) => address.address)
}

export async function getWalletHistory(): Promise<WalletHistoryEvent[]> {
  const walletHistoryData = [
    {
      id: 'asd',
      senderAddress:
        'sov:ksudgyi8f98gsih7655hgifuyg79s89s98ydf98fg7gks8fjhkss8f030',
      action: 'Withdraw',
      tokenAmount: '5656',
      timeStamp: 'Tue, 04 Aug 2015 12:38:41 GMT',
    },
    {
      id: 'kld',
      senderName: '<NAME>',
      senderAddress:
        'sov:ksudgyi8f98gsih7655hgifuyg79s89s98ydf98fg7gks8fjhkss8f030',
      action: 'Purchase',
      tokenAmount: '10000',
      timeStamp: 'Tue, 04 Aug 2015 14:38:41 GMT',
    },
  ]

  return new Promise.resolve(walletHistoryData)
}

export async function encryptWallet({
  encryptedFileLocation,
  recoveryPassphrase,
}: {
  encryptedFileLocation: string,
  recoveryPassphrase: Passphrase,
}): Promise<number> {
  const exportHandle: number = await RNIndy.exportWallet(
    encryptedFileLocation,
    recoveryPassphrase.hash
  )

  return exportHandle
}

export async function decryptWalletFile(
  walletPath: string,
  decryptionKey: string
): Promise<number> {
  const { walletName } = await getWalletPoolName()
  const wallet_key = await getWalletKey()

  const config = JSON.stringify({
    wallet_name: walletName,
    wallet_key,
    exported_wallet_path: walletPath,
    backup_key: decryptionKey,
  })
  const importHandle: number = await RNIndy.decryptWalletFile(config)

  return importHandle
}

export async function copyToPath(
  uri: string,
  destPath: string
): Promise<number> {
  return await RNIndy.copyToPath(uri, destPath)
}

export async function updateClaimOfferState(claimHandle: number) {
  const updatedState: number = await RNIndy.updateClaimOfferState(claimHandle)

  return updatedState
}

export async function getClaimOfferState(claimHandle: number): Promise<number> {
  const state: number = await RNIndy.getClaimOfferState(claimHandle)

  return state
}

export async function getClaimVcx(
  claimHandle: number
): Promise<GetClaimVcxResult> {
  const vcxClaimResult: string = await RNIndy.getClaimVcx(claimHandle)
  const vcxClaim: VcxClaimInfo = JSON.parse(vcxClaimResult)
  const { credential, credential_id } = vcxClaim

  if (!credential || !credential_id) {
    throw new Error('credential not found in vcx')
  }

  return {
    claimUuid: credential_id,
    claim: credential,
  }
}

export async function exportWallet(wallet: WalletPayload): Promise<number> {
  const exportHandle: number = await RNIndy.exportWallet(
    wallet.walletPath,
    wallet.encryptionKey
  )

  return exportHandle
}

export async function setWalletItem(
  key: string,
  value: string
): Promise<number> {
  return await RNIndy.setWalletItem(key, value)
}

export async function getWalletItem(key: string): Promise<string> {
  const response: string = await RNIndy.getWalletItem(key)
  if (response) {
    const itemValue = JSON.parse(response)
    const { value } = itemValue

    if (!value) {
      throw new Error('cannot get value')
    }

    return value
  } else {
    return response
  }
}

export async function deleteWalletItem(key: string): Promise<number> {
  return await RNIndy.deleteWalletItem(key)
}

export async function updateWalletItem(
  key: string,
  data: string
): Promise<number> {
  return await RNIndy.updateWalletItem(key, data)
}

export function exitAppAndroid() {
  if (Platform.OS === 'android') {
    RNIndy.exitAppAndroid()
  }
}

export async function getMatchingCredentials(
  proofHandle: number
): Promise<string> {
  // TODO:KS Add a transformer here, for now we are just passing through
  return await RNIndy.proofRetrieveCredentials(proofHandle)
}

export async function generateProof(
  proofHandle: number,
  selectedCredentials: string,
  selfAttestedAttributes: string
): Promise<void> {
  return await RNIndy.proofGenerate(
    proofHandle,
    selectedCredentials,
    selfAttestedAttributes
  )
}

export async function sendProof(
  proofHandle: number,
  connectionHandle: number
): Promise<void> {
  return await RNIndy.proofSend(proofHandle, connectionHandle)
}

export async function proofCreateWithRequest(
  sourceId: string,
  proofRequest: string
): Promise<number> {
  return await RNIndy.proofCreateWithRequest(sourceId, proofRequest)
}

export async function proofSerialize(proofHandle: number): Promise<string> {
  return await RNIndy.proofSerialize(proofHandle)
}

export async function proofDeserialize(
  serializedProofRequest: string
): Promise<number> {
  return await RNIndy.proofDeserialize(serializedProofRequest)
}

export async function downloadMessages(
  messageStatus: string,
  uid_s: ?string,
  pwdids: string
): Promise<string> {
  return await RNIndy.downloadMessages(messageStatus, uid_s, pwdids)
}

export async function updateMessages(
  messageStatus: string,
  pwdidsJson: string
): Promise<number> {
  return await RNIndy.updateMessages(messageStatus, pwdidsJson)
}

export async function getWalletTokenInfo(): Promise<WalletTokenInfo> {
  const paymentHandle = 0
  const tokenInfo: string = await RNIndy.getTokenInfo(paymentHandle)
  return JSON.parse(tokenInfo)
}

export async function createPaymentAddress(seed: ?string) {
  return RNIndy.createPaymentAddress(seed)
}

export async function getLedgerFees(): Promise<LedgerFeesData> {
  const fees: string = await RNIndy.getLedgerFees()

  return convertVcxLedgerFeesToLedgerFees(fees)
}

export const checkIfAnimationToUse = memoize(function() {
  return Platform.OS === 'android'
    ? RNIndy.totalMemory / smallDeviceMemory < 1 ? true : false
    : false
})

export async function getBiometricError(): Promise<string> {
  if (Platform.OS === 'ios') {
    return await RNIndy.getBiometricError()
  }
  return ''
}


<|start_filename|>__mocks__/data/ledger-store-mock-data.js<|end_filename|>
// @flow
import { STORE_STATUS } from '../../app/common/type-common'

export const transferFees = {
  transfer: '0.00001',
}

export const ledgerStoreWithTransferFees = {
  fees: {
    data: transferFees,
    status: STORE_STATUS.SUCCESS,
    error: null,
  },
}


<|start_filename|>connectMeUITest/src/pageObjects/ConnectionDetailPage.java<|end_filename|>
package pageObjects;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import io.appium.java_client.AppiumDriver;

public class ConnectionDetailPage {
	
	private static WebElement element = null;

	public static WebElement Cross_Button(AppiumDriver driver) throws Exception {

		try {
			element =   driver.findElementByXPath("//XCUIElementTypeOther[@name='connection-header-close']");
			System.out.println("Cross Button is displayed");
			return element;
		} catch (Exception e) {
			System.out.println("Cross Button is not displayed");
			throw (e);
		}
	}

	public static WebElement Continue_Button(AppiumDriver driver) throws Exception {

		try {
			element =   driver.findElementByXPath("//XCUIElementTypeOther[@name='Continue']");
			System.out.println("Continue Button is displayed");
			return element;
		} catch (Exception e) {

			System.out.println("Continue Button is not displayed");
			throw (e);
		}
	}

	
	

}


<|start_filename|>app/lock/__tests__/lock-pin-code-setup.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { PIN_SETUP_STATE } from '../type-lock'
import { LockPinSetup } from '../lock-pin-code-setup'
import { lockSetupSuccessRoute } from '../../common'
import { getNavigation } from '../../../__mocks__/static-data'
import { pinHash } from '../pin-hash'

describe('<LockPinCodeSetup />', () => {
  const getProps = () => ({
    setPinAction: jest.fn(),
    enableTouchIdAction: jest.fn(),
    navigation: getNavigation(),
    lockEnable: jest.fn(),
  })
  const options = {
    createNodeMock: element => {
      return {
        clear: () => {
          cleared = true
        },
        blur: () => {},
      }
    },
  }

  let component
  let props
  let cleared

  beforeEach(() => {
    props = getProps()
    component = renderer.create(<LockPinSetup {...props} />, options)
  })

  it('should render pin code box', () => {
    expect(component.toJSON()).toMatchSnapshot()
  })

  it('should show re enter pass code after first entry', () => {
    let tree = component.toJSON()
    let instance = component.getInstance()
    //manually trigger onComplete method by passing "pass code"
    instance.onPinComplete('123456')
    tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })

  it('should set pinSetupState and pinReEnterSuccessPin for after pin is success for redirection', () => {
    let instance = component.getInstance()
    //manually trigger onComplete method by passing "pass code" for first time
    instance.onPinComplete('123456')
    //manually trigger onComplete method by passing "same pass code" for second time
    instance.onPinComplete('123456')
    //checking if the states are fine with the values so that the redirection can take place in the next function
    expect(instance.state.pinSetupState).toEqual(
      PIN_SETUP_STATE.REENTER_SUCCESS
    )
    expect(instance.state.pinReEnterSuccessPin).toEqual('123456')
  })

  it('should redirect to lockSetupSuccessRoute after pin is success', () => {
    let instance = component.getInstance()
    instance.setState({
      pinSetupState: PIN_SETUP_STATE.REENTER_SUCCESS,
      pinReEnterSuccessPin: '123456',
    })
    // this is called after the keyboard is hidden
    instance.onKeyboardHide(true)
    // if the pinSetupState is in PIN_SETUP_STATE.REENTER_SUCCESS, then we will be navigating to the lockSetupSuccessRoute screen
    expect(props.navigation.navigate).toHaveBeenCalledWith(
      lockSetupSuccessRoute
    )
  })

  it('should show "pass code mismatch ..." message and reset to initial state after passcode mismatch', () => {
    jest.useFakeTimers()

    let instance = component.getInstance()
    //manually trigger onComplete method by passing "some pass code" for first time
    instance.onPinComplete('123456')
    //manually trigger onComplete method by passing "some another pass code" for second time
    instance.onPinComplete('000000')
    expect(component.toJSON()).toMatchSnapshot()
    expect(instance.state.pinSetupState).toEqual(PIN_SETUP_STATE.REENTER_FAIL)
    jest.runAllTimers()
    expect(instance.state.pinSetupState).toBe(PIN_SETUP_STATE.INITIAL)
  })

  it('hashed lock code not equal plain text lock code', () => {
    let pin = '123456'
    let salt = '<PASSWORD>'
    let instance = component.getInstance()
    let hashedPin = pinHash(pin, salt)
    instance.onPinComplete(pin)
    expect(hashedPin).not.toEqual(instance.state.enteredPin)
  })
})


<|start_filename|>app/connection/type-connection.js<|end_filename|>
// @flow

export type Connection = {
  identifier: string,
  logoUrl: ?string,
  name: string,
  senderDID: string,
  senderEndpoint: string,
  size: number,
}

export type Connections = {
  +[string]: Connection,
}


<|start_filename|>app/restore/__tests__/restore-wait.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { RestoreWaitScreen } from '../restore-wait'
import { getNavigation, getStore } from '../../../__mocks__/static-data'
import { restoreWaitRoute } from '../../common'

describe('RestoreWait screen', () => {
  function getProps() {
    return {
      navigation: getNavigation(),
      route: restoreWaitRoute,
      restore: getStore().getState().restore,
    }
  }

  function setup() {
    const props = getProps()
    return { props }
  }

  it('should render properly and match the snapshot', () => {
    const { props } = setup()
    const tree = renderer.create(<RestoreWaitScreen {...props} />).toJSON()
    expect(tree).toMatchSnapshot()
  })

  //TODO add snapshot for error screen
})


<|start_filename|>app/offline/type-offline.js<|end_filename|>
// @flow
export const OFFLINE_STATUS = 'OFFLINE_STATUS'

export type OfflineStore = {
  offline: boolean,
}

export type OfflineActions = OfflineStatus

export type OfflineStatus = {
  type: typeof OFFLINE_STATUS,
  offline: boolean,
}

export type OfflineProps = {
  overlay?: boolean,
  isOffline: boolean,
  offline: (offline: boolean) => void,
  render?: (isConnected: ?boolean) => any,
}


<|start_filename|>app/wallet/__tests__/wallet-tab-history.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { WalletTabHistory } from '../wallet-tab-history'
import { walletHistory } from '../../../__mocks__/static-data'
import { STORE_STATUS } from '../type-wallet'

describe('<WalletTabHistory />', () => {
  it('should render properly and match the snapshot', () => {
    const component = renderer.create(
      <WalletTabHistory
        walletHistory={walletHistory}
        refreshWalletHistory={jest.fn()}
      />
    )
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })

  it('should render no history view properly and match the snapshot', () => {
    const noHistory = {
      transactions: [],
      status: STORE_STATUS.IDLE,
      error: null,
    }
    const component = renderer.create(
      <WalletTabHistory
        walletHistory={noHistory}
        refreshWalletHistory={jest.fn()}
      />
    )
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/components/avatar/type-avatar.js<|end_filename|>
// @flow
import type { GenericObject } from '../../common/type-common'

export type AvatarProps = {
  // TODO:KS Add specific props that are needed by Avatar component
} & GenericObject

export type BadgeAvatarProps = {
  onPress: (event: any) => void,
  count: number | string,
}


<|start_filename|>app/home/__tests__/home.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { CLAIM_OFFER_STATUS } from '../../claim-offer/type-claim-offer'
import {
  claimOfferRoute,
  homeTabRoute,
  authenticationRoute,
} from '../../common'
import {
  MESSAGE_TYPE,
  PUSH_NOTIFICATION_SENT_CODE,
} from '../../api/api-constants'
import { DashboardScreen } from '../home'
import {
  getNavigation,
  getStore,
  myPairWiseConnectionDetails,
  vcxSerializedConnection,
} from '../../../__mocks__/static-data'

function props(claimOfferStatus) {
  return {
    connections: {
      data: {
        '3nj819kkjywdppuje79': {
          identifier: '3nj819kkjywdppuje79',
          name: 'Test Connection',
          senderDID: '70075yyojywdppuje79',
          senderEndpoint: '34.216.340.155:3000',
          size: 100,
          logoUrl: 'https://logourl.com/logo.png',
          vcxSerializedConnection,
          ...myPairWiseConnectionDetails,
        },
      },
      hydrated: true,
    },
    navigation: getNavigation(),
    claimOfferStatus: claimOfferStatus || CLAIM_OFFER_STATUS.RECEIVED,
    route: {
      currentScreen: homeTabRoute,
    },
    pushNotification: {
      notification: null,
    },
    getUserInfo: jest.fn(),
    pushNotificationReceived: jest.fn(),
    authenticationRequestReceived: jest.fn(),
    unSeenMessages: {},
  }
}

describe('<DashboardScreen />', () => {
  const store = getStore()

  jest.useFakeTimers()
  it('should render Home and redirect user to claim offer modal', () => {
    const dashboardProps = props()
    const wrapper = renderer
      .create(
        <Provider store={store}>
          <DashboardScreen {...dashboardProps} />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })

  it('should render Home and show loader', () => {
    const dashboardProps = props()
    dashboardProps.connections.hydrated = false
    const wrapper = renderer
      .create(
        <Provider store={store}>
          <DashboardScreen {...dashboardProps} />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>app/eula/eula-store.js<|end_filename|>
// @flow
import { takeLatest, call, put, all } from 'redux-saga/effects'
import { safeSet } from '../services/storage'
import {
  EULA_ACCEPT,
  STORAGE_KEY_EULA_ACCEPTANCE,
  HYDRATE_EULA_ACCEPT,
} from './type-eula'
import type {
  EulaAccept,
  EulaStore,
  EulaActions,
  HydrateEulaAcceptAction,
} from './type-eula'
import { captureError } from '../services/error/error-handler'

const initialState: EulaStore = {
  isEulaAccept: false,
}

export const eulaAccept = (isEulaAccept: boolean): EulaAccept => ({
  type: EULA_ACCEPT,
  isEulaAccept,
})

// if we see that both this action and eulaAccept action creator
// does the same thing inside the reducer and while raising action as well
// the reason we have two action creators is that on EULA_ACCEPT
// we have a watch that runs and store this data inside wallet
// we do not want to wastefully make an API call when we just hydrated data
export const hydrateEulaAccept = (
  isEulaAccept: boolean
): HydrateEulaAcceptAction => ({
  type: HYDRATE_EULA_ACCEPT,
  isEulaAccept,
})

export function* watchEula(): any {
  yield all([watchEulaAcceptance()])
}

export function* watchEulaAcceptance(): any {
  yield takeLatest(EULA_ACCEPT, eulaAcceptanceSaga)
}

export function* eulaAcceptanceSaga(action: EulaAccept): Generator<*, *, *> {
  try {
    const { isEulaAccept } = action

    yield call(
      safeSet,
      STORAGE_KEY_EULA_ACCEPTANCE,
      JSON.stringify(isEulaAccept)
    )
  } catch (e) {
    captureError(e)
    console.error(`eulaAcceptanceSaga: ${e}`)
  }
}

export default function eulaReducer(
  state: EulaStore = initialState,
  action: EulaActions
): EulaStore {
  switch (action.type) {
    case HYDRATE_EULA_ACCEPT:
    case EULA_ACCEPT:
      return {
        ...state,
        isEulaAccept: action.isEulaAccept,
      }
    default:
      return state
  }
}


<|start_filename|>app/backup/styles.js<|end_filename|>
// @flow
import { StyleSheet, Dimensions, Platform } from 'react-native'
import {
  PADDING_HORIZONTAL,
  PADDING_VERTICAL,
  isBiggerThanShortDevice,
  color,
  grey,
} from '../common/styles/constant'

const { width, height } = Dimensions.get('window')
const SPACE_FILLER = 50
const amountSpacing = isBiggerThanShortDevice ? PADDING_VERTICAL * 2 : 0
const submitButtonHeight = isBiggerThanShortDevice ? 63 : 43
const showRecoveryButtonHeight = isBiggerThanShortDevice ? 150 : 100
const inputBoxHeight =
  isBiggerThanShortDevice || Platform.OS === 'ios' ? 137 : 40
export const chatBubbleTextOffset = 40
const styles = StyleSheet.create({
  tabContainer: {
    maxHeight: 60,
  },
  backgroundImage: {
    width: '100%',
    flex: 1,
    position: 'absolute',
  },
  headerCloseIcon: {
    marginRight: PADDING_HORIZONTAL,
    marginBottom: PADDING_VERTICAL,
    alignSelf: 'flex-end',
  },
  headerIcon: {
    marginRight: isBiggerThanShortDevice ? 5 : 0,
    marginTop: isBiggerThanShortDevice ? 15 : 0,
    alignSelf: 'flex-end',
  },
  headerBackIcon: {
    marginLeft: isBiggerThanShortDevice ? 5 : 0,
    marginTop: isBiggerThanShortDevice ? 15 : 5,
    alignSelf: 'flex-start',
  },
  headerSpacer: {
    height: '100%',
    width: isBiggerThanShortDevice ? SPACE_FILLER : SPACE_FILLER * 3 / 4,
  },
  showRecoveryPassphrase: {
    width: '86%',
    height: showRecoveryButtonHeight,
    borderRadius: 5,
    alignSelf: 'center',
    backgroundColor: color.bg.tertiary.color,
    elevation: 7,
    marginBottom: 60,
  },
  genRecovery: {
    backgroundColor: color.bg.eleventh.color,
  },
  genRecoveryHeader: {
    width: '100%',
  },
  genRecoveryPhraseContainer: {
    position: 'absolute',
    top: 20,
    left: chatBubbleTextOffset / 2,
    paddingHorizontal: '7%',
  },
  genRecoveryPhraseLoadingContainer: {
    padding: 40,
    position: 'absolute',
    top: 0,
  },
  genRecoveryPhrase: {
    textAlign: 'center',
    color: color.bg.eleventh.color,
    fontSize: isBiggerThanShortDevice ? 20 : 18,
    lineHeight: isBiggerThanShortDevice ? 30 : 28,
    fontWeight: '900',
  },
  genRecoveryText: {
    marginBottom: isBiggerThanShortDevice ? 10 : '2%',
    alignSelf: 'center',
    fontSize: isBiggerThanShortDevice ? 22 : 20,
    fontWeight: '600',
  },
  genRecoveryMessage: {
    paddingHorizontal: 20,
    alignSelf: 'center',
    fontSize: isBiggerThanShortDevice ? 18 : 16,
    lineHeight: isBiggerThanShortDevice ? 22 : 20,
    fontWeight: '500',
    marginBottom: isBiggerThanShortDevice ? 20 : 5,
  },
  genRecoverySecondMessage: {
    paddingHorizontal: 20,
    alignSelf: 'center',
    fontSize: isBiggerThanShortDevice ? 18 : 16,
    lineHeight: isBiggerThanShortDevice ? 22 : 20,
    fontWeight: 'bold',
  },
  genRecoverySmallMessage: {
    fontSize: 14,
    lineHeight: 17,
    fontWeight: 'bold',
    marginBottom: isBiggerThanShortDevice ? 15 : '3%',
  },
  verifyMainContainer: {
    flex: 1,
    backgroundColor: color.bg.twelfth.color,
  },
  verifyMainText: {
    paddingHorizontal: 20,
    fontSize: 18,
    lineHeight: 22,
    fontWeight: '500',
    marginTop: isBiggerThanShortDevice ? 40 : 20,
    marginBottom: isBiggerThanShortDevice ? 40 : 20,
  },
  exportBackupMainText: {
    paddingHorizontal: 10,
    fontSize: isBiggerThanShortDevice ? 18 : 16,
    lineHeight: isBiggerThanShortDevice ? 22 : 20,
    fontWeight: '500',
  },
  inputBox: {
    marginBottom: 24,
    marginRight: 20,
    marginLeft: 20,
    height: inputBoxHeight,
    backgroundColor: 'rgba(0,0,0,0.33)',
    color: 'white',
    padding: 10,
    textAlignVertical: 'top',
  },
  submitButton: {
    marginLeft: '2%',
    marginRight: '2%',
    marginBottom: 15,
    borderRadius: 5,
    shadowColor: grey,
    shadowOffset: {
      width: 1,
      height: 1,
    },
    shadowRadius: 5,
    shadowOpacity: 0.3,
    elevation: 7,
    height: isBiggerThanShortDevice ? 53 : 43,
  },
  backgroundImageVerify: {
    flex: 1,
    position: 'absolute',
  },
  exportBackup: {
    backgroundColor: color.bg.thirteenth.color,
  },
  wrapper: {
    paddingHorizontal: PADDING_HORIZONTAL,
  },
  title: {
    fontWeight: '600',
    lineHeight: isBiggerThanShortDevice ? 27 : 22,
    fontSize: isBiggerThanShortDevice ? 22 : 20,
    marginBottom: isBiggerThanShortDevice ? 20 : 10,
    width: '100%',
  },
  exportBackupTitle: {
    fontWeight: '600',
    lineHeight: isBiggerThanShortDevice ? 27 : 22,
    fontSize: isBiggerThanShortDevice ? 22 : 20,
    marginBottom: isBiggerThanShortDevice ? 30 : 10,
    marginTop: isBiggerThanShortDevice ? 10 : 0,
    maxWidth: 290,
  },
  exportBackupText: {
    marginBottom: 20,
    backgroundColor: color.bg.thirteenth.color,
    alignSelf: 'center',
    fontSize: 22,
  },
  exportBackupMessage: {
    backgroundColor: color.bg.thirteenth.color,
    alignSelf: 'center',
    fontSize: 18,
  },
  exportBackupFile: {
    fontSize: 15,
    lineHeight: 18,
    fontWeight: '900',
  },
  exportBackupSmallMessage: {
    fontSize: 14,
    maxWidth: 300,
    lineHeight: 17,
    marginBottom: isBiggerThanShortDevice ? 30 : 10,
  },
  backupComplete: {
    backgroundColor: color.bg.fourteenth.color,
  },
  backupCompleteHeader: {
    width: '100%',
  },
  backupCompleteText: {
    fontSize: 18,
    fontWeight: '500',
    lineHeight: 22,
  },
  alignItemsCenter: {
    marginBottom: 6,
    marginLeft: '5%',
    marginRight: '5%',
  },
  verticalSpacing: {
    paddingTop: amountSpacing,
  },
  customButtonColor: {
    fontWeight: '600',
    fontSize: 18,
  },
  lockIconImage: {
    paddingTop: isBiggerThanShortDevice ? 40 : '2%',
  },
  imageIcon: {
    resizeMode: 'stretch',
    width: '100%',
    marginBottom: isBiggerThanShortDevice ? 20 : 0,
  },
  imageIconEncryptFile: {
    resizeMode: 'contain',
    width: isBiggerThanShortDevice ? '100%' : '80%',
    marginBottom: isBiggerThanShortDevice ? 20 : 0,
  },
})

export default styles


<|start_filename|>app/store/route-store.js<|end_filename|>
// @flow
import { splashScreenRoute } from '../common/route-constants'
import type { RouteStore } from './type-store'
import type { InitialTestAction } from '../common/type-common'

export type RouteStoreAction = typeof handleRouteUpdate | InitialTestAction

const initialState = {
  currentScreen: splashScreenRoute,
  timeStamp: new Date().getTime(),
}

export const ROUTE_UPDATE = 'ROUTE_UPDATE'

export const handleRouteUpdate = (currentScreen: string) => ({
  type: ROUTE_UPDATE,
  currentScreen,
})

export default function routeReducer(
  state: RouteStore = initialState,
  action: RouteStoreAction
) {
  switch (action.type) {
    case ROUTE_UPDATE:
      return {
        currentScreen: action.currentScreen,
        timeStamp: new Date().getTime(),
      }
    default:
      return state
  }
}


<|start_filename|>app/components/avatar/avatar.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Image, TouchableWithoutFeedback, View, StyleSheet } from 'react-native'
import debounce from 'lodash.debounce'
import { CustomView } from '../layout/custom-view'
import avatarStyle from './avatar-style'
import type { AvatarProps } from './type-avatar'

const empty = []

export class Avatar extends PureComponent<AvatarProps, void> {
  onPressDebounce = debounce(
    event => {
      if (this.props.onPress) {
        this.props.onPress(event)
      }
    },
    300,
    { leading: true, trailing: false }
  )

  render() {
    const {
      small,
      medium,
      large,
      square,
      shadow,
      style = empty,
      imageStyle = empty,
      src,
      extraNode,
      onPress,
      onLongPress,
      testID,
      onLoad,
      onError,
      clearBg,
      radius,
    } = this.props
    const size = small ? 'small' : medium ? 'medium' : 'large'
    const imageShadow = shadow ? 'imageShadow' : null
    const elementStyle = [
      ...style,
      square
        ? null
        : // $FlowFixMe flow does not support dynamic property lookup
          avatarStyle[`${size}Round`],
      clearBg ? avatarStyle['clearBg'] : null,
    ]
    const elementContentStyle = [
      radius ? { width: radius * 2, height: radius * 2 } : avatarStyle[size],
      // avatar style contains round styles on the basis of size of Image
      // if we passed size as small, then corresponding style for round image
      // will be `smallRound`, that's why we are concatenating
      // value of `size` with "Round"
      // for example: if this component is used like <Avatar small round />
      // then we will get size="small" and we get round as true,
      // then style that we get from avatarStyle will be `smallRound`
      square
        ? null
        : radius
          ? { borderRadius: radius }
          : // $FlowFixMe flow does not support dynamic property lookup
            avatarStyle[`${size}Round`],
      ...imageStyle,
    ]

    return (
      <CustomView
        imageShadow={imageShadow}
        style={elementStyle}
        testID={testID}
      >
        <TouchableWithoutFeedback
          onPress={this.onPressDebounce}
          onLongPress={onLongPress}
        >
          <Image
            source={src}
            style={elementContentStyle}
            testID={`${testID}-image`}
            accessible={true}
            accessibilityLabel={`${testID}-image`}
            onLoad={onLoad}
            onError={onError}
          />
        </TouchableWithoutFeedback>
        {extraNode && extraNode}
      </CustomView>
    )
  }
}


<|start_filename|>app/connection-history/type-connection-history.js<|end_filename|>
// @flow

import type { Item } from '../components/custom-list/type-custom-list'
import type {
  ReactNavigation,
  GenericObject,
  CustomError,
  ResetAction,
} from '../common/type-common'
import {
  INVITATION_RECEIVED,
  INVITATION_REJECTED,
} from '../invitation/type-invitation'
import type { InvitationReceivedAction } from '../invitation/type-invitation'
import type { NewConnectionAction } from '../store/type-connection-store'
import {
  CLAIM_OFFER_RECEIVED,
  CLAIM_OFFER_ACCEPTED,
  CLAIM_OFFER_IGNORED,
  CLAIM_OFFER_REJECTED,
  SEND_CLAIM_REQUEST,
  SEND_CLAIM_REQUEST_SUCCESS,
} from '../claim-offer/type-claim-offer'
import type { SendClaimRequestAction } from '../claim-offer/type-claim-offer'
import type { ClaimReceivedAction } from '../claim/type-claim'
import type { ClaimOfferReceivedAction } from '../claim-offer/type-claim-offer'
import { CLAIM_STORAGE_SUCCESS } from '../claim/type-claim'
import {
  PROOF_REQUEST_RECEIVED,
  PROOF_REQUEST_ACCEPTED,
  PROOF_REQUEST_IGNORED,
  PROOF_REQUEST_REJECTED,
  SEND_PROOF_SUCCESS,
} from '../proof-request/type-proof-request'
import type { Connection } from '../connection/type-connection'
import type {
  ProofRequestReceivedAction,
  SendProofSuccessAction,
  AdditionalProofDataPayload,
} from '../proof-request/type-proof-request'
import { NEW_CONNECTION_SUCCESS } from '../store/connections-store'
import { PROOF_SUCCESS } from '../proof/type-proof'
import type {
  Attribute,
  AdditionalDataPayload,
  NotificationPayloadInfo,
} from '../push-notification/type-push-notification'
import type { ClaimMap } from '../claim/type-claim'

export const HISTORY_EVENT_STATUS = {
  [INVITATION_RECEIVED]: 'CONNECTION REQUEST',
  [NEW_CONNECTION_SUCCESS]: 'CONNECTED',
  [INVITATION_REJECTED]: 'CONNECTION REJECTED',
  [SEND_CLAIM_REQUEST_SUCCESS]: 'PENDING',
  [CLAIM_OFFER_RECEIVED]: 'CLAIM OFFER RECEIVED',
  [CLAIM_OFFER_ACCEPTED]: 'ACCEPTED OFFER',
  [CLAIM_OFFER_IGNORED]: 'IGNORED OFFER',
  [CLAIM_OFFER_REJECTED]: 'REJECTED OFFER',
  [CLAIM_STORAGE_SUCCESS]: 'RECEIVED',
  [PROOF_REQUEST_RECEIVED]: 'PROOF RECEIVED',
  [PROOF_REQUEST_IGNORED]: 'IGNORED',
  [PROOF_REQUEST_REJECTED]: 'REJECTED',
  [SEND_PROOF_SUCCESS]: 'SHARED',
}

export type HistoryEventStatus = $Keys<typeof HISTORY_EVENT_STATUS>

export const HISTORY_EVENT_TYPE = {
  INVITATION: 'INVITATION',
  CLAIM: 'CLAIM',
  PROOF: 'PROOF',
  AUTHENTICATION: 'AUTHENTICATION',
}

export type HistoryEventType = $Keys<typeof HISTORY_EVENT_TYPE>

export const EventTypeToEventStatusMap = {
  INVITATION: [
    INVITATION_RECEIVED,
    NEW_CONNECTION_SUCCESS,
    INVITATION_REJECTED,
  ],
  CLAIM: [
    CLAIM_OFFER_RECEIVED,
    CLAIM_OFFER_ACCEPTED,
    CLAIM_OFFER_IGNORED,
    CLAIM_OFFER_REJECTED,
    CLAIM_STORAGE_SUCCESS,
  ],
  PROOF: [
    PROOF_REQUEST_RECEIVED,
    PROOF_REQUEST_ACCEPTED,
    PROOF_REQUEST_IGNORED,
    PROOF_REQUEST_REJECTED,
  ],
}

export type ConnectionHistoryEvent = {
  action: string,
  data: Array<Item> | GenericObject,
  id: string,
  name: string,
  status: string, // HistoryEventStatus
  timestamp: string,
  type: HistoryEventType,
  remoteDid: string,
  originalPayload: GenericObject,
  showBadge?: boolean,
}

export type ConnectionHistoryItem = {
  action: string,
  data: Array<Attribute>,
  id: string,
  name: string,
  originalPayload: {
    type: typeof CLAIM_OFFER_RECEIVED | typeof PROOF_REQUEST_RECEIVED,
    payload: AdditionalDataPayload | AdditionalProofDataPayload,
    payloadInfo: NotificationPayloadInfo,
  },
  remoteDid: string,
  status: string,
  timestamp: string,
  type: string,
}

export type ConnectionHistoryDetailsProps = {
  navigation: {
    state: {
      params: {
        type: string,
        id?: string,
        type?: string,
        icon?: string,
        action?: string,
        status?: string,
        timestamp?: string,
        data?: Array<Item>,
        claimMap?: ?ClaimMap,
      },
    },
  },
}

export type ConnectionHistoryData = {
  [string]: Array<ConnectionHistoryEvent>,
}

export const LOAD_HISTORY = 'LOAD_HISTORY'

export type LoadHistoryAction = {
  type: typeof LOAD_HISTORY,
}

export const LOAD_HISTORY_SUCCESS = 'LOAD_HISTORY_SUCCESS'

export type LoadHistorySuccessAction = {
  type: typeof LOAD_HISTORY_SUCCESS,
  data: ConnectionHistoryData,
}

export const LOAD_HISTORY_FAIL = 'LOAD_HISTORY_FAIL'
export const LOAD_HISTORY_EVENT_OCCURED_FAIL = 'LOAD_HISTORY_EVENT_OCCURED_FAIL'

export type LoadHistoryFailAction = {
  type: typeof LOAD_HISTORY_FAIL,
  error: CustomError,
}

export const HISTORY_EVENT_OCCURRED = 'HISTORY_EVENT_OCCURRED'

//TODO : add ClaimReceivedAction
export type HistoryEventOccurredEventType =
  | InvitationReceivedAction
  | NewConnectionAction
  | ClaimOfferReceivedAction
  | ProofRequestReceivedAction
  | SendProofSuccessAction
  | SendClaimRequestAction
  | ResetAction

export type HistoryEventOccurredAction = {
  type: typeof HISTORY_EVENT_OCCURRED,
  event: HistoryEventOccurredEventType,
}

export const RECORD_HISTORY_EVENT = 'RECORD_HISTORY_EVENT'

export type RecordHistoryEventAction = {
  type: typeof RECORD_HISTORY_EVENT,
  historyEvent: ConnectionHistoryEvent,
}

export const DELETE_HISTORY_EVENT = 'DELETE_HISTORY_EVENT'

export type DeleteHistoryEventAction = {
  type: typeof DELETE_HISTORY_EVENT,
  historyEvent: ConnectionHistoryEvent,
}

export const ERROR_LOADING_HISTORY = {
  code: 'CN002',
  message: 'Error while loading connection history data',
}

export const ERROR_HISTORY_EVENT_OCCURRED = {
  code: 'CN003',
  message: 'Error while history event occurred',
}

export type ConnectionHistoryAction =
  | LoadHistoryAction
  | LoadHistorySuccessAction
  | LoadHistoryFailAction
  | RecordHistoryEventAction
  | HistoryEventOccurredAction
  | DeleteHistoryEventAction

export type ConnectionHistoryStore = {
  error?: ?CustomError,
  isLoading: boolean,
  data: ?ConnectionHistoryData,
}

export const HISTORY_EVENT_STORAGE_KEY = 'HISTORY_EVENT_STORAGE_KEY'

export type ConnectionHistoryState = {
  disableTaps: boolean,
}

export type ConnectionHistoryProps = {
  claimMap: ?ClaimMap,
  activeConnectionThemePrimary: string,
  activeConnectionThemeSecondary: string,
  connectionHistory: {
    [string]: ConnectionHistoryEvent[],
  },
  updateStatusBarTheme: (color?: string) => void,
  deleteConnectionAction: (senderDID: string) => void,
  goToUIScreen: (
    string,
    string,
    $PropertyType<ReactNavigation, 'navigation'>
  ) => void,
} & ReactNavigation


<|start_filename|>app/components/layout/custom-view.js<|end_filename|>
// @flow
import React from 'react'
import {
  View,
  StyleSheet,
  TouchableWithoutFeedback,
  SafeAreaView,
  Platform,
} from 'react-native'
import { color } from '../../common/styles/constant'
import empty from '../../common/empty'
import style from './layout-style'
import debounce from 'lodash.debounce'
import type { GenericObject } from '../../common/type-common'

// TODO:KS Change generic object to actual props
// CustomView is used for different types of background for our app
// default styles for a view such a padding, shadow or transparent background
export const CustomView = (props: GenericObject) => {
  const {
    clearBg,
    horizontalSpace,
    verticalSpace,
    doubleVerticalSpace,
    pad,
    primary,
    secondary,
    tertiary,
    quaternary,
    fifth,
    senary,
    septenary,
    dark,
    row,
    left,
    right,
    center,
    hCenter,
    vCenter,
    bottom,
    onPress,
    onLongPress,
    spaceBetween,
    shadow,
    imageShadow,
    absolute,
    absoluteFill,
    spaceAround,
    small,
    safeArea,
    debounceAction = true,
  } = props
  const passedStyles = props.style || []
  const absoluteStyles = absolute
    ? // $FlowFixMe flow does not support below syntax for dynamic property access
      [style.absolute, style[`absolute${absolute}`]]
    : []
  // TODO:KS We can keep same name as style and use it directly with props
  const styles = StyleSheet.flatten([
    clearBg ? style.transparentBg : null,
    horizontalSpace ? style.horizontalSpaced : null,
    verticalSpace ? style.verticalSpaced : null,
    doubleVerticalSpace ? style.doubleVerticalSpaced : null,
    pad ? [style.horizontalSpaced, style.verticalSpaced] : null,
    primary ? style.primaryBg : null,
    secondary ? style.secondaryBg : null,
    tertiary ? style.tertiaryBg : null,
    quaternary ? style.quaternaryBg : null,
    fifth ? style.fifthBg : null,
    senary ? style.senaryBg : null,
    septenary ? style.septenaryBg : null,
    dark ? style.darkBg : null,
    row ? style.row : null,
    left ? style.left : null,
    right ? style.right : null,
    center ? style.center : null,
    hCenter ? style.hCenter : null,
    vCenter ? style.vCenter : null,
    row && bottom ? style.rowBottom : null,
    bottom && !row ? style.columnBottom : null,
    spaceBetween ? style.spaceBetween : null,
    shadow ? style.shadow : null,
    imageShadow ? style.imageShadow : null,
    spaceAround ? style.spaceAround : null,
    ...absoluteStyles,
    ...passedStyles,
  ])
  let filteredProps = { ...props }
  delete filteredProps.onLongPress
  delete filteredProps.onPress
  delete filteredProps.left
  delete filteredProps.right
  delete filteredProps.bottom
  if (typeof props.testID === 'undefined') {
    delete filteredProps.testID
  } else {
    filteredProps.accessible = true
    filteredProps.accessibilityLabel = filteredProps.testID
  }
  const customView = safeArea ? (
    <SafeAreaView {...filteredProps} style={styles}>
      {filteredProps.children}
    </SafeAreaView>
  ) : (
    <View {...filteredProps} style={styles}>
      {filteredProps.children}
    </View>
  )

  if (onPress || onLongPress) {
    let touchProps = {}
    if (typeof props.testID !== 'undefined') {
      touchProps.testID = `${props.testID}-touchable`
      touchProps.accessible = Platform.OS === 'ios' ? false : true
      touchProps.accessibilityLabel = `${props.testID}-touchable`
    }
    if (typeof onPress !== 'undefined') {
      if (debounceAction) {
        touchProps.onPress = debounce(
          event => {
            onPress(event)
          },
          900,
          { leading: true, trailing: false }
        )
      } else {
        touchProps.onPress = onPress
      }
    }
    if (typeof onLongPress !== 'undefined') {
      touchProps.onLongPress = onLongPress
    }
    let hitSlopWidth = small ? 30 : 20
    return (
      <TouchableWithoutFeedback
        {...touchProps}
        hitSlop={{
          top: hitSlopWidth,
          right: hitSlopWidth,
          bottom: hitSlopWidth,
          left: hitSlopWidth,
        }}
      >
        {customView}
      </TouchableWithoutFeedback>
    )
  }

  return customView
}


<|start_filename|>app/components/__tests__/custom-view.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { CustomView } from '../../components'
import { PADDING_VERTICAL } from './../../common/styles/constant'

describe('<CustomView />', () => {
  it('doubleVerticalSpace should overwrite verticalSpace style if both were provided as props to customView', () => {
    // icon should have only icon props
    // and rest of the props should be passed to CustomView
    const wrapper = renderer
      .create(<CustomView verticalSpace doubleVerticalSpace />)
      .toJSON()

    expect(wrapper).toMatchSnapshot()
    expect(wrapper.props.style.paddingVertical).toBe(PADDING_VERTICAL * 2)
  })
})


<|start_filename|>app/components/image-color-picker/connection-theme.js<|end_filename|>
// @flow
import React, { Component } from 'react'
import { View } from 'react-native'
import { connect } from 'react-redux'

import empty from '../../common/empty'
import type { ConnectionThemeProps } from './type-color-picker'
import { getConnectionTheme } from '../../store/store-selector'

export class ConnectionTheme extends Component<ConnectionThemeProps, void> {
  render() {
    const {
      logoUrl,
      secondary,
      connectionTheme,
      children,
      style,
      disabled = false,
    } = this.props
    let styles = style || empty

    let themeType = secondary
      ? connectionTheme.secondary
      : connectionTheme.primary

    if (disabled) {
      const colorsWithoutOpacity = themeType.split(',', 3)
      // change opacity to 0.4 if child is disabled
      // do not remove `)` from end of 0.4, that's how we generate
      // rgba(hex, hex, hex, opacity) this is last parenthesis
      colorsWithoutOpacity.push('0.4)')
      themeType = colorsWithoutOpacity.join(',')
    }

    let childrenWithProps = React.Children.map(children, child =>
      React.cloneElement(child, {
        customColor: {
          backgroundColor: themeType,
        },
      })
    )

    if (styles && styles != empty)
      styles = [styles, { backgroundColor: themeType }]

    return <View style={styles}>{childrenWithProps}</View>
  }
}

const mapStateToProps = (store, { logoUrl }) => ({
  connectionTheme: getConnectionTheme(store, logoUrl),
})

export default connect(mapStateToProps, null)(ConnectionTheme)


<|start_filename|>connectMeUITest/src/appModules/ReadMail.java<|end_filename|>
package appModules;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.mail.BodyPart;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class ReadMail {

   public static String GetInstallLInk() 
   {

	      String host = "pop.gmail.com";// change accordingly
	      String mailStoreType = "pop3";
	      String user = "<EMAIL>";// change accordingly
	      String password = "<PASSWORD>";// change accordingly
	       String link = "" ;
      try {

      //create properties field
      Properties properties = new Properties();

      properties.put("mail.pop3.host", host);
      properties.put("mail.pop3.port", "995");
     // properties.put("mail.pop3.starttls.enable", "true");
      Session emailSession = Session.getDefaultInstance(properties);
  
      //create the POP3 store object and connect with the pop server
      Store store = emailSession.getStore("pop3s");

      store.connect(host, user, password);

      //create the folder object and open it
      Folder emailFolder = store.getFolder("INBOX");
      emailFolder.open(Folder.READ_ONLY);

      // retrieve the messages from the folder in an array and print it
      Message[] messages = emailFolder.getMessages();
      System.out.println("messages.length---" + messages.length);
     Message message = messages[messages.length-1];
         

         System.out.println(getTextFromMessage(message));
         String MessageBody=getTextFromMessage(message);
         link = MessageBody.substring(MessageBody.indexOf("verification: ") + 14 , MessageBody.indexOf("link") + 15);
         System.out.println(link);

      //close the store and folder objects
      emailFolder.close(false);
      store.close();

      } catch (NoSuchProviderException e) {
         e.printStackTrace();
      } catch (MessagingException e) {
         e.printStackTrace();
      } catch (Exception e) {
         e.printStackTrace();
      }
	return link;
   }

  
   private static  String getTextFromMimeMultipart(
	        MimeMultipart mimeMultipart)  throws MessagingException, IOException{
	    String result = "";
	    int count = mimeMultipart.getCount();
	    for (int i = 0; i < count; i++) {
	        BodyPart bodyPart = mimeMultipart.getBodyPart(i);
	        if (bodyPart.isMimeType("text/plain")) {
	            result = result + "\n" + bodyPart.getContent();
	            break; // without break same text appears twice in my tests
	        } else if (bodyPart.isMimeType("text/html")) {
	            String html = (String) bodyPart.getContent();
	           // result = result + "\n" + org.jsoup.Jsoup.parse(html).text();
	        } else if (bodyPart.getContent() instanceof MimeMultipart){
	            result = result + getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
	        }
	    }
	    return result;
	}
  
   
   private static  String getTextFromMessage(Message message) throws MessagingException, IOException {
	    String result = "";
	    if (message.isMimeType("text/plain")) {
	        result = message.getContent().toString();
	    } else if (message.isMimeType("multipart/*")) {
	        MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
	        result = getTextFromMimeMultipart(mimeMultipart);
	    }
	    return result;
	}
  
}

<|start_filename|>app/bridge/react-native-cxs/type-cxs.js<|end_filename|>
// @flow

import type { SMSPendingInvitationPayload } from '../../sms-pending-invitation/type-sms-pending-invitation'
import type { UserOneTimeInfo } from '../../store/user/type-user-store'
import type { AgencyPoolConfig } from '../../store/type-config-store'
import type { GenericObject } from '../../common/type-common'
import type {
  ClaimOfferPushPayload,
  ClaimPushPayload,
} from '../../push-notification/type-push-notification'
import type { ProofRequestPushPayload } from '../../proof-request/type-proof-request'

export type Metadata = {
  [string]: any,
}

export type IndyClaimOffer = {
  issuerDid: string,
  schemaSequenceNumber: number,
}

export type IndyConnectionHistory = {
  issuerDid: string,
  schemaSequenceNumber: number,
}

export type IndyClaimRequest = {
  blinded_ms: {
    prover_did: string,
    u: string,
    ur?: string,
  },
  issuer_did: string,
  schema_seq_no: number,
}

export type ConnectAgencyResponse = {
  '@type': {
    name: string,
    ver: string,
  },
  withPairwiseDID: string,
  withPairwiseDIDVerKey: string,
}

export type RegisterAgencyResponse = {
  '@type': { name: string, ver: string },
}

export type CreateOneTimeAgentResponse = {
  '@type': { name: string, ver: string },
  withPairwiseDID: string,
  withPairwiseDIDVerKey: string,
}

export type CreatePairwiseAgentResponse = {
  '@type': { name: string, ver: string },
  withPairwiseDID: string,
  withPairwiseDIDVerKey: string,
}

export type AcceptInvitationResponse = {
  '@type': { name: string, ver: string },
  uid: string,
}

// TODO: Remove types that will not be used once vcx is integrated
export type VcxProvision = {
  agency_url: string,
  agency_did: string,
  agency_verkey: string,
}

export type VcxProvisionResult = {
  wallet_name: string,
  wallet_key: string,
  agency_endpoint: string,
  agency_did: string,
  agency_verkey: string,
  // myOneTimeDid
  sdk_to_remote_did: string,
  // myOneTimeVerificationKey
  sdk_to_remote_verkey: string,
  // oneTimeAgencyDid
  institution_did: string,
  // oneTimeAgencyVerificationKey
  institution_verkey: string,
  // myOneTimeAgentDid
  remote_to_sdk_did: string,
  // myOneTimeAgentVerificationKey
  remote_to_sdk_verkey: string,
}

export type CxsInitConfig = UserOneTimeInfo & AgencyPoolConfig

export type InitWithGenesisPathConfig = CxsInitConfig & { genesis_path: string }

export type VcxInitConfig = {
  agency_endpoint: string,
  agency_did: string,
  agency_verkey: string,
  genesis_path: string,
  wallet_key: string,
  config: string,
  pool_name: string,
  wallet_name: string,
  remote_to_sdk_did: string,
  remote_to_sdk_verkey: string,
  sdk_to_remote_did: string,
  sdk_to_remote_verkey: string,
  institution_did: string,
  institution_verkey: string,
}

export type VcxPushTokenConfig = {
  id: string,
  value: string,
}

export type CxsPushTokenConfig = {
  uniqueId: string,
  pushToken: string,
}

export type VcxCreateConnection = {
  source_id: string,
  invite_details: SMSPendingInvitationPayload,
}

export type VcxConnectionCreateResult = number

export type VcxConnectionConnectResult = {
  source_id: string,
  pw_did: string,
  pw_verkey: string,
  uuid: string,
  endpoint: string,
  agent_did: string,
  agent_vk: string,
  their_pw_did: string,
  their_pw_verkey: string,
}

export type VcxCredentialOfferResult = {
  credential_handle: number,
  credential_offer: string,
}

export type VcxCredentialOffer = {
  msg_type: string,
  version: string,
  to_did: string,
  from_did: string,
  libindy_offer: string,
  cred_def_id: string,
  credential_attrs: { [string]: Array<string> },
  schema_seq_no: number,
  claim_name: string,
  claim_id: string,
  payment_address?: ?string,
  price?: ?string,
}

export type CxsCredentialOfferResult = {
  claimHandle: number,
  claimOffer: ClaimOfferPushPayload,
}

export type VcxSendCredentialRequest = {}

export type VcxClaimInfo = {
  credential_id?: string,
  credential?: ClaimPushPayload,
  credential_offer?: string,
}

export type VcxProofRequest = ProofRequestPushPayload

export type WalletPoolName = {
  walletName: string,
  poolName: string,
}

export type UTXO = {
  amount: number,
  extra: string,
  paymentAddress: string,
  source: string,
}

export type PaymentAddress = {
  address: string,
  balance: number,
  utxo: UTXO[],
}

export type WalletTokenInfo = {
  balance_str: string,
  addresses: PaymentAddress[],
}

export const smallDeviceMemory = 1073741824


<|start_filename|>app/claim/claim-store.js<|end_filename|>
// @flow
import { Platform } from 'react-native'
import {
  put,
  takeLatest,
  call,
  all,
  select,
  takeEvery,
  fork,
} from 'redux-saga/effects'
import type {
  Claim,
  ClaimStore,
  ClaimAction,
  ClaimReceivedAction,
  ClaimStorageFailAction,
  ClaimStorageSuccessAction,
  MapClaimToSenderAction,
  ClaimMap,
  HydrateClaimMapAction,
  HydrateClaimMapFailAction,
  ClaimWithUuid,
  ClaimReceivedVcxAction,
  ClaimVcx,
  GetClaimVcxResult,
} from './type-claim'
import {
  CLAIM_RECEIVED,
  CLAIM_STORAGE_FAIL,
  CLAIM_STORAGE_SUCCESS,
  MAP_CLAIM_TO_SENDER,
  HYDRATE_CLAIM_MAP,
  HYDRATE_CLAIM_MAP_FAIL,
  ERROR_CLAIM_HYDRATE_FAIL,
  CLAIM_RECEIVED_VCX,
} from './type-claim'
import type { CustomError } from '../common/type-common'
import {
  getClaimHandleBySerializedClaimOffer,
  updateClaimOfferState,
  getClaimVcx,
} from '../bridge/react-native-cxs/RNCxs'
import { CLAIM_STORAGE_ERROR } from '../services/error/error-code'
import {
  getConnectionLogoUrl,
  getPoolConfig,
  getClaimMap,
  getSerializedClaimOffers,
  getConnectionByUserDid,
} from '../store/store-selector'
import { secureSet, getHydrationItem } from '../services/storage'
import { CLAIM_MAP } from '../common/secure-storage-constants'
import { RESET } from '../common/type-common'
import {
  ensureVcxInitSuccess,
  updateMessageStatus,
} from '../store/config-store'
import type { SerializedClaimOffer } from '../claim-offer/type-claim-offer'
import { VCX_CLAIM_OFFER_STATE } from '../claim-offer/type-claim-offer'
import { saveSerializedClaimOffer } from '../claim-offer/claim-offer-store'
import type { Connection } from '../store/type-connection-store'
import { promptBackupBanner } from '../backup/backup-store'
import { captureError } from '../services/error/error-handler'

export const claimReceived = (claim: Claim): ClaimReceivedAction => ({
  type: CLAIM_RECEIVED,
  claim,
})

export const claimStorageSuccess = (
  messageId: string
): ClaimStorageSuccessAction => ({
  type: CLAIM_STORAGE_SUCCESS,
  messageId,
})

export const claimStorageFail = (
  messageId: string,
  error: CustomError
): ClaimStorageFailAction => ({
  type: CLAIM_STORAGE_FAIL,
  messageId,
  error,
})

export const mapClaimToSender = (
  claimUuid: string,
  senderDID: string,
  myPairwiseDID: string,
  logoUrl: string
): MapClaimToSenderAction => ({
  type: MAP_CLAIM_TO_SENDER,
  claimUuid,
  senderDID,
  myPairwiseDID,
  logoUrl,
})

export const hydrateClaimMap = (claimMap: ClaimMap) => ({
  type: HYDRATE_CLAIM_MAP,
  claimMap,
})

export const hydrateClaimMapFail = (error: CustomError) => ({
  type: HYDRATE_CLAIM_MAP_FAIL,
  error,
})

export function* hydrateClaimMapSaga(): Generator<*, *, *> {
  try {
    const fetchedClaimMap = yield call(getHydrationItem, CLAIM_MAP)
    if (fetchedClaimMap) {
      const claimMap: ClaimMap = JSON.parse(fetchedClaimMap)
      yield put(hydrateClaimMap(claimMap))
    }
  } catch (e) {
    captureError(e)
    yield put(
      hydrateClaimMapFail({
        code: ERROR_CLAIM_HYDRATE_FAIL.code,
        message: `${ERROR_CLAIM_HYDRATE_FAIL.message}:${e.message}`,
      })
    )
  }
}

export const claimReceivedVcx = (claim: ClaimVcx): ClaimReceivedVcxAction => ({
  type: CLAIM_RECEIVED_VCX,
  claim,
})

export function* claimReceivedVcxSaga(
  action: ClaimReceivedAction
): Generator<*, *, *> {
  const { forDID, remotePairwiseDID, connectionHandle, uid } = action.claim
  const vcxResult = yield* ensureVcxInitSuccess()
  if (vcxResult && vcxResult.fail) {
    return
  }

  // when we receive a claim we only know claim message id,
  // and user id for which claim was sent
  // but we don't know for which claim offer this claim was sent
  // so, we take out all the claim offers for the connection
  // and then check each claim offer for update and download latest message
  // for each claim offer and see which claim offer received claim
  const serializedClaimOffers: SerializedClaimOffer[] = yield select(
    getSerializedClaimOffers,
    forDID
  )

  if (connectionHandle != null) {
    for (const serializedClaimOffer of serializedClaimOffers) {
      // run each claim offer check in parallel and wait for all of them to finish
      yield call(
        checkForClaim,
        serializedClaimOffer,
        connectionHandle,
        forDID,
        uid
      )
    }
  }
}

export function* checkForClaim(
  serializedClaimOffer: SerializedClaimOffer,
  connectionHandle: number,
  userDID: string,
  uid: string
): Generator<*, *, *> {
  if (serializedClaimOffer.state === VCX_CLAIM_OFFER_STATE.ACCEPTED) {
    // if claim offer is already in accepted state, then we don't want to update state
    return
  }
  const { messageId } = serializedClaimOffer
  try {
    const claimHandle: number = yield call(
      getClaimHandleBySerializedClaimOffer,
      serializedClaimOffer.serialized
    )
    const vcxClaimOfferState: number = yield call(
      updateClaimOfferState,
      claimHandle
    )

    if (vcxClaimOfferState === VCX_CLAIM_OFFER_STATE.ACCEPTED) {
      // once we know that this claim offer state was updated to accepted
      // that means that we downloaded the claim for this claim offer
      // and saved to wallet, now we need to know claim uuid and exact claim
      const vcxClaim: GetClaimVcxResult = yield call(getClaimVcx, claimHandle)
      const connection: ?Connection = yield select(
        getConnectionByUserDid,
        userDID
      )
      if (connection) {
        yield put(
          mapClaimToSender(
            vcxClaim.claimUuid,
            connection.senderDID,
            userDID,
            connection.logoUrl
          )
        )
        yield fork(saveClaimUuidMap)
      }

      yield put(claimStorageSuccess(serializedClaimOffer.messageId))
      yield* updateMessageStatus([
        {
          pairwiseDID: userDID,
          uids: [messageId, uid],
        },
      ])
      yield put(promptBackupBanner(true))

      // since we asked vcx to update state, we should also update serialized state in redux
      // so that we don't go out of sync with vcx
      yield fork(
        saveSerializedClaimOffer,
        claimHandle,
        userDID,
        serializedClaimOffer.messageId
      )
    }
  } catch (e) {
    // we got error while saving claim in wallet, what to do now?
    captureError(e)
    yield put(
      claimStorageFail(serializedClaimOffer.messageId, CLAIM_STORAGE_ERROR(e))
    )
  }
}

export function* saveClaimUuidMap(): Generator<*, *, *> {
  const claimMap: ClaimMap = yield select(getClaimMap)

  try {
    yield call(secureSet, CLAIM_MAP, JSON.stringify(claimMap))
  } catch (e) {
    // TODO:KS what should we do if storage fails
    captureError(e)
    console.error(`Failed to store claim uuid map:${e}`)
  }
}

export function* watchClaimReceivedVcx(): any {
  yield takeEvery(CLAIM_RECEIVED_VCX, claimReceivedVcxSaga)
}

export function* watchClaim(): any {
  yield all([watchClaimReceivedVcx()])
}

const initialState = {
  claimMap: {},
}

export default function claimReducer(
  state: ClaimStore = initialState,
  action: ClaimAction
) {
  switch (action.type) {
    case CLAIM_RECEIVED:
      return {
        ...state,
        [action.claim.messageId]: {
          claim: action.claim,
        },
      }

    case CLAIM_STORAGE_FAIL:
      return {
        ...state,
        [action.messageId]: {
          ...state[action.messageId],
          error: action.error,
        },
      }

    case CLAIM_STORAGE_SUCCESS: {
      const { [action.messageId]: deleted, ...newState } = state
      return newState
    }

    case MAP_CLAIM_TO_SENDER:
      const { claimUuid, senderDID, myPairwiseDID, logoUrl } = action
      return {
        ...state,
        claimMap: {
          ...state.claimMap,
          [claimUuid]: {
            senderDID,
            myPairwiseDID,
            logoUrl,
          },
        },
      }

    case HYDRATE_CLAIM_MAP:
      return {
        ...state,
        claimMap: action.claimMap,
      }

    case RESET:
      return initialState

    default:
      return state
  }
}


<|start_filename|>app/api/api-utils.js<|end_filename|>
// @flow
import { SERVER_ERROR_CODE, SERVER_API_CALL_ERROR } from './api-constants'
import { captureError } from '../services/error/error-handler'
import type { CustomError } from '../common/type-common'
import type { ApiData, BackendError } from './type-api'

export const options = (
  method: string = 'GET',
  body: ?{ [string]: any } = null
) => {
  let data: ApiData = {
    method,
    mode: 'cors',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
  }

  if (body) {
    data.body = JSON.stringify(body)
  }

  return data
}

export const api = (
  url: string,
  apiOptions: ApiData,
  showAlert: boolean = false
) =>
  fetch(url, apiOptions)
    .then(res => {
      // TODO:KS create common method to return successful
      // and unsuccessful api response
      if (res.status >= 200 && res.status < 300) {
        return res
          .json()
          .then(response => ({
            payload: response,
          }))
          .catch((error: Error) => ({
            // our api call was successful,
            // however server did not return any json response
            // Ideally server should send such response with status code 204
            // so that we don't try to parse response for such methods.
            // As of now just send an empty payload signalling that call went fine
            payload: {},
          }))
      } else {
        // Fail with error code if status code is above 300
        return res.text().then((response: string) => ({
          error: response,
        }))
      }
    })
    .then(response => {
      // if response contains payload and no error, that means we got success
      if (response.payload && !response.error) {
        return response.payload
      } else {
        let errorResponse: CustomError = {
          message: response.error,
          code: SERVER_ERROR_CODE,
        }

        try {
          // try to convert error response to json, if it fails that means
          // we did not get error code and message
          const backendError = (JSON.parse(response.error): BackendError)
          errorResponse = {
            message: backendError.statusMsg,
            code: backendError.statusCode,
          }
        } catch (e) {
          // since we did not get error code and message
          // let's just use default that we assigned above,
          // we don't need to do anything here
        }

        throw new Error(JSON.stringify(errorResponse))
      }
    })
    // .catch(captureError) Commenting this for now, it is not returning errors back to saga as of now, Fix this
    .catch((e: Error) => {
      // we don't want to throw JavaScript with simple message
      // we want it to be JSON parse compatible, so that error handlers
      // can parse and use this error
      // Here we are handling network and other http status code errors
      let error = {
        message: e.message,
        code: SERVER_API_CALL_ERROR,
      }

      try {
        // if we already converted JavaScript error to CustomError
        // then pass through same error
        error = JSON.parse(e.message)
      } finally {
      }

      throw new Error(JSON.stringify(error))
    })


<|start_filename|>app/components/loader/__tests__/loader.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import Loader from '../loader'

describe('<Loader />', () => {
  it('should render properly and match the snapshot', () => {
    const component = renderer.create(<Loader delay={0} message="test" />)
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })

  it('should check that delay works', () => {
    const component = renderer.create(<Loader delay={1000} message="test" />)
    const tree = component.toJSON()

    expect(tree).toBe(null)
  })

  xit('should check that interval works', () => {
    // const component = renderer.create(<Loader />)
    // const tree = component.toJSON()
    // expect(tree).toMatchSnapshot()
  })
  xit('should check that timeout works', () => {
    // const component = renderer.create(<Loader />)
    // const tree = component.toJSON()
    // expect(tree).toMatchSnapshot()
  })

  it('should check that custom message works', () => {
    const component = renderer.create(<Loader message="sovrin is cool" />)
    const tree = component.toJSON()

    expect(tree).toMatchSnapshot()
  })

  it('should check that showMessage works as expected when true', () => {
    const component = renderer.create(<Loader showMessage message="show me" />)
    const tree = component.toJSON()

    expect(tree).toMatchSnapshot()
  })

  it('should check that showMessage works as expected when false', () => {
    const component = renderer.create(
      <Loader showMessage={false} message="don't show me" />
    )
    const tree = component.toJSON()

    expect(tree).toMatchSnapshot()
  })

  it('should check that light type works', () => {
    const component = renderer.create(
      <Loader type="light" showMessage={false} />
    )
    const tree = component.toJSON()

    expect(tree).toMatchSnapshot()
  })

  it('should check that dark type works', () => {
    const component = renderer.create(
      <Loader type="dark" showMessage={false} />
    )
    const tree = component.toJSON()

    expect(tree).toMatchSnapshot()
  })

  it('should check that size works', () => {
    const component = renderer.create(<Loader size={48} showMessage={false} />)
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/wallet/styles.js<|end_filename|>
// @flow
import { StyleSheet, Dimensions } from 'react-native'
import {
  PADDING_HORIZONTAL,
  PADDING_VERTICAL,
  isBiggerThanShortDevice,
  color,
} from '../common/styles/constant'

const { width } = Dimensions.get('window')
const SPACE_FILLER = 50
const amountSpacing = isBiggerThanShortDevice ? PADDING_VERTICAL * 2 : 0
const ctaButtonHeight = isBiggerThanShortDevice ? 63 : 43

const styles = StyleSheet.create({
  headerCloseIcon: {
    marginTop: PADDING_VERTICAL,
  },
  ctaButton: {
    flex: -1,
    height: ctaButtonHeight,
    borderRadius: 5,
    backgroundColor: color.bg.eighth.color,
  },
  alignItemsCenter: {
    marginBottom: 6,
    marginHorizontal: '5%',
  },
  verticalSpacing: {
    flexDirection: 'column',
    alignContent: 'center',
    justifyContent: 'space-around',
  },
})

export default styles


<|start_filename|>app/privacy-tnc/type-privacy-tnc.js<|end_filename|>
// @flow
import type { ReactNavigation, CustomError } from '../common/type-common'

export type PrivacyTNCProps = {} & ReactNavigation

export type PrivacyTNCState = {
  error: null | CustomError,
}


<|start_filename|>app/claim/__tests__/claim-store.spec.js<|end_filename|>
// @flow
import renderer from 'react-test-renderer'
import { put, call, select } from 'redux-saga/effects'
import { initialTestAction } from '../../common/type-common'
import claimReducer, {
  claimReceived,
  claimStorageFail,
  claimStorageSuccess,
  mapClaimToSender,
} from '../claim-store'
import { CLAIM_STORAGE_ERROR } from '../../services/error/error-code'
import {
  getConnectionLogoUrl,
  getPoolConfig,
  getClaimMap,
} from '../../store/store-selector'
import {
  claim,
  claimWithUuid,
  senderDid1,
  claimDefinitionSchemaSequenceNumber,
  getClaimFormat,
  senderLogoUrl1,
  myPairWiseConnectionDetails,
  poolConfig,
  claimMap,
} from '../../../__mocks__/static-data'
import type { ClaimWithUuid } from '../../claim/type-claim'
import { promptBackupBanner } from '../../backup/backup-store'

describe('Claim Store', () => {
  let initialState = { claimMap: {} }
  let afterClaimReceived

  beforeEach(() => {
    initialState = claimReducer(undefined, initialTestAction())
    afterClaimReceived = claimReducer(initialState, claimReceived(claim))
  })

  it('should match snapshot for claim received action', () => {
    expect(afterClaimReceived).toMatchSnapshot()
  })

  it('should match snapshot when claim storage fails', () => {
    const nextState = claimReducer(
      afterClaimReceived,
      claimStorageFail(claim.messageId, CLAIM_STORAGE_ERROR())
    )
    expect(nextState).toMatchSnapshot()
  })

  it('should match snapshot when claim storage is success', () => {
    const nextState = claimReducer(
      afterClaimReceived,
      claimStorageSuccess(claim.messageId)
    )
    expect(nextState).toMatchSnapshot()
  })

  it('should reset claim store, if RESET action is raised', () => {
    expect(
      claimReducer(afterClaimReceived, { type: 'RESET' })
    ).toMatchSnapshot()
  })
})


<|start_filename|>app/restore/restore-wait.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { Image, StyleSheet, Dimensions } from 'react-native'
import { Container, CustomView, CustomText, Icon } from '../components'
import { darkGray } from '../common/styles/constant'
import { connect } from 'react-redux'
import { restoreRoute, restoreWaitRoute, lockEnterPinRoute } from '../common'
import type { RestoreWaitScreenProps } from './type-restore'
import type { Store } from '../store/type-store'
import { RestoreStatus } from './type-restore'

export class RestoreWaitScreen extends PureComponent<
  RestoreWaitScreenProps,
  void
> {
  componentDidUpdate(prevProps: RestoreWaitScreenProps) {
    if (
      !this.props.restore.error &&
      this.props.restore.status === RestoreStatus.RESTORE_DATA_STORE_SUCCESS &&
      this.props.route === restoreWaitRoute
    ) {
      // TODO: the params have to be removed when the lockEnterPinRoute design is changed in according with the recovery screen.
      this.props.navigation.navigate(lockEnterPinRoute, {
        fromScreen: 'recovery',
      })
    }

    if (
      this.props.restore.error !== prevProps.restore.error &&
      this.props.route === restoreWaitRoute
    ) {
      //the navigation stack here is like Restore Start-> Restore Wait->Restore Start
      // So before going to Restore Start goBack two times and remove the routes from the stack
      this.props.navigation.navigate(restoreRoute)
    }
  }

  render() {
    return (
      <Container fifth safeArea center>
        <CustomView style={[styles.mainContainer]}>
          <Image
            source={require('../images/bkgCurve.png')}
            style={[styles.backgroundImage]}
          />

          <CustomView center>
            <CustomView style={[styles.strip]} />

            <Icon
              xxLarge
              style={[styles.iconStyle]}
              src={require('../images/dataRestore.png')}
            />
          </CustomView>

          <CustomView center>
            <CustomText
              bold
              center
              transparentBg
              style={[styles.textContainer]}
              heavy
            >
              Please wait while your data is restored.
            </CustomText>
          </CustomView>
        </CustomView>
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  mainContainer: {
    marginTop: '-20%',
  },
  textContainer: {
    marginBottom: '6%',
    marginTop: '15%',
    paddingHorizontal: '5%',
    color: darkGray,
    fontSize: 23,
  },
  backgroundImage: {
    position: 'absolute',
    marginTop: '-58%',
    width: '100%',
    zIndex: -1,
  },

  iconStyle: {
    borderRadius: 80,
    padding: 15,
    backgroundColor: darkGray,
  },
  strip: {
    position: 'absolute',
    width: '110%',
    height: 8,
    backgroundColor: darkGray,
  },
})

const mapStateToProps = (state: Store) => {
  return {
    restore: state.restore,
    route: state.route.currentScreen,
  }
}

export default connect(mapStateToProps, null)(RestoreWaitScreen)


<|start_filename|>__mocks__/data/connections-mock-data.js<|end_filename|>
// @flow

export const botLogoUrl = 'http://cr0ybot.github.io/ingress-logos/ingress.png'
export const connectionThemes = {
  [botLogoUrl]: {
    primary: 'rgba(100,200,100,1)',
    secondary: 'rgba(100,200,100,0.6)',
  },
}


<|start_filename|>app/store/user/__tests__/user-store.spec.js<|end_filename|>
// @flow
import { put, call, select, take } from 'redux-saga/effects'
import RNFetchBlob from 'react-native-fetch-blob'

import userReducer, {
  connectRegisterCreateAgentDone,
  hydrateUserStoreFail,
  saveUserOneTimeInfoFail,
  hydrateUserStore,
  hydrateUserStoreSaga,
  saveUserOneTimeInfoSaga,
  saveUserSelectedAvatarSaga,
  saveUserSelectedAvatar,
  saveUserSelectedAvatarSuccess,
  saveUserSelectedAvatarFail,
  persistUserSelectedAvatar,
  hydrateUserSelectedAvatarImage,
  selectUserAvatarSaga,
  selectUserAvatarFail,
} from '../user-store'
import { initialTestAction } from '../../../common/type-common'
import {
  userOneTimeInfo,
  userAvatarImagePath,
  userAvatarImageName,
  defaultUUID,
} from '../../../../__mocks__/static-data'
import {
  ERROR_PARSE_USER_INFO_FAIL,
  ERROR_SAVE_USER_INFO_FAIL,
  STORAGE_KEY_USER_ONE_TIME_INFO,
  STORAGE_KEY_USER_AVATAR_NAME,
  ERROR_HYDRATE_USER_SELECTED_IMAGE,
  ERROR_SAVE_USER_SELECTED_IMAGE,
  ERROR_SELECT_USER_AVATAR,
} from '../type-user-store'
import {
  secureSet,
  safeSet,
  safeGet,
  getHydrationItem,
} from '../../../services/storage'
import { getUserAvatarName } from '../../store-selector'
import { uuid } from '../../../services/uuid'
import ImagePicker from 'react-native-image-crop-picker'
import { VCX_INIT_SUCCESS } from '../../type-config-store'

jest.mock('../../../services/uuid')

describe('store: user-store: ', () => {
  let initialState

  beforeEach(() => {
    // get initial state without any action
    initialState = userReducer(undefined, initialTestAction())
  })

  it('action: CONNECT_REGISTER_CREATE_AGENT_DONE', () => {
    expect(
      userReducer(initialState, connectRegisterCreateAgentDone(userOneTimeInfo))
    ).toMatchSnapshot()
  })

  it('action: PARSE_USER_ONE_TIME_INFO_FAIL', () => {
    expect(
      userReducer(
        initialState,
        hydrateUserStoreFail(ERROR_PARSE_USER_INFO_FAIL)
      )
    ).toMatchSnapshot()
  })

  it('action: SAVE_USER_ONE_TIME_INFO_FAIL', () => {
    expect(
      userReducer(
        initialState,
        saveUserOneTimeInfoFail(ERROR_SAVE_USER_INFO_FAIL)
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_USER_STORE', () => {
    expect(
      userReducer(initialState, hydrateUserStore({ userOneTimeInfo }))
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_USER_STORE: avatarName', () => {
    expect(
      userReducer(
        initialState,
        hydrateUserStore({ avatarName: userAvatarImageName })
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_USER_STORE, after user one time info is hydrated', () => {
    const afterUserOneTimeInfoState = userReducer(
      initialState,
      hydrateUserStore({ userOneTimeInfo })
    )
    expect(
      userReducer(
        afterUserOneTimeInfoState,
        hydrateUserStore({ avatarName: userAvatarImageName })
      )
    ).toMatchSnapshot()
  })

  it('action: HYDRATE_USER_STORE, after avatar name is hydrated', () => {
    const afterAvatarNameState = userReducer(
      initialState,
      hydrateUserStore({ avatarName: userAvatarImageName })
    )
    expect(
      userReducer(afterAvatarNameState, hydrateUserStore({ userOneTimeInfo }))
    ).toMatchSnapshot()
  })

  it('saga: saveUserOneTimeInfoSaga => success', () => {
    const gen = saveUserOneTimeInfoSaga(
      connectRegisterCreateAgentDone(userOneTimeInfo)
    )
    expect(gen.next().value).toEqual(take(VCX_INIT_SUCCESS))
    expect(gen.next().value).toEqual(
      call(
        secureSet,
        STORAGE_KEY_USER_ONE_TIME_INFO,
        JSON.stringify(userOneTimeInfo)
      )
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: saveUserOneTimeInfoSaga => fail', () => {
    const gen = saveUserOneTimeInfoSaga(
      connectRegisterCreateAgentDone(userOneTimeInfo)
    )
    expect(gen.next().value).toEqual(take(VCX_INIT_SUCCESS))
    expect(gen.next().value).toEqual(
      call(
        secureSet,
        STORAGE_KEY_USER_ONE_TIME_INFO,
        JSON.stringify(userOneTimeInfo)
      )
    )

    const errorMessage = 'No storage available'
    expect(gen.throw(new Error(errorMessage)).value).toEqual(
      put(
        saveUserOneTimeInfoFail({
          code: ERROR_SAVE_USER_INFO_FAIL.code,
          message: `${ERROR_SAVE_USER_INFO_FAIL.message}${errorMessage}`,
        })
      )
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: hydrateUserStoreSaga => success', () => {
    const gen = hydrateUserStoreSaga()
    expect(gen.next().value).toEqual(
      call(getHydrationItem, STORAGE_KEY_USER_ONE_TIME_INFO)
    )
    expect(gen.next(JSON.stringify(userOneTimeInfo)).value).toEqual(
      put(hydrateUserStore({ userOneTimeInfo }))
    )
    expect(gen.next().value).toEqual(
      call(safeGet, STORAGE_KEY_USER_AVATAR_NAME)
    )
    expect(gen.next(userAvatarImageName).value).toEqual(
      put(hydrateUserStore({ avatarName: userAvatarImageName }))
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: hydrateUserStoreSaga => fail', () => {
    const gen = hydrateUserStoreSaga()
    expect(gen.next().value).toEqual(
      call(getHydrationItem, STORAGE_KEY_USER_ONE_TIME_INFO)
    )
    const error = 'test error'
    expect(gen.throw(new Error(error)).value).toEqual(
      put(
        hydrateUserStoreFail({
          code: ERROR_PARSE_USER_INFO_FAIL.code,
          message: `${ERROR_PARSE_USER_INFO_FAIL.message}${error}`,
        })
      )
    )
    expect(gen.next().value).toEqual(
      call(safeGet, STORAGE_KEY_USER_AVATAR_NAME)
    )
    const errorMessage = 'test error in storage key'
    expect(gen.throw(new Error(errorMessage)).value).toEqual(
      put(hydrateUserStoreFail(ERROR_HYDRATE_USER_SELECTED_IMAGE(errorMessage)))
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: saveUserSelectedAvatarSaga => success', () => {
    const gen = saveUserSelectedAvatarSaga(
      saveUserSelectedAvatar(userAvatarImagePath)
    )
    const userAvatarAppPath = `${
      RNFetchBlob.fs.dirs.DocumentDir
    }/${userAvatarImageName}`
    expect(gen.next().value).toEqual(select(getUserAvatarName))
    expect(gen.next(userAvatarImageName).value).toEqual(
      call(RNFetchBlob.fs.exists, userAvatarAppPath)
    )
    expect(gen.next(true).value).toEqual(
      call(RNFetchBlob.fs.unlink, userAvatarAppPath)
    )
    const newImageName = `${defaultUUID}.jpeg`
    const newImagePath = `${RNFetchBlob.fs.dirs.DocumentDir}/${newImageName}`
    expect(gen.next().value).toEqual(
      call(RNFetchBlob.fs.cp, userAvatarImagePath, newImagePath)
    )
    expect(gen.next().value).toEqual(
      call(safeSet, STORAGE_KEY_USER_AVATAR_NAME, newImageName)
    )
    expect(gen.next().value).toEqual(
      put(saveUserSelectedAvatarSuccess(newImageName))
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: saveUserSelectedAvatarSaga => failure', () => {
    const gen = saveUserSelectedAvatarSaga(
      saveUserSelectedAvatar(userAvatarImagePath)
    )
    const userAvatarAppPath = `${
      RNFetchBlob.fs.dirs.DocumentDir
    }/${userAvatarImageName}`
    expect(gen.next().value).toEqual(select(getUserAvatarName))
    expect(gen.next(userAvatarImageName).value).toEqual(
      call(RNFetchBlob.fs.exists, userAvatarAppPath)
    )
    expect(gen.next(true).value).toEqual(
      call(RNFetchBlob.fs.unlink, userAvatarAppPath)
    )
    const newImageName = `${defaultUUID}.jpeg`
    const newImagePath = `${RNFetchBlob.fs.dirs.DocumentDir}/${newImageName}`
    expect(gen.next().value).toEqual(
      call(RNFetchBlob.fs.cp, userAvatarImagePath, newImagePath)
    )
    const errorMessage = 'error while copying image'
    expect(gen.throw(new Error(errorMessage)).value).toEqual(
      put(
        saveUserSelectedAvatarFail(ERROR_SAVE_USER_SELECTED_IMAGE(errorMessage))
      )
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: persistUserSelectedAvatar', () => {
    const gen = persistUserSelectedAvatar(userAvatarImageName)
    expect(gen.next().value).toEqual(
      call(safeSet, STORAGE_KEY_USER_AVATAR_NAME, userAvatarImageName)
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: hydrateUserSelectedAvatarImage => success', () => {
    const gen = hydrateUserSelectedAvatarImage()
    expect(gen.next().value).toEqual(
      call(safeGet, STORAGE_KEY_USER_AVATAR_NAME)
    )
    expect(gen.next(userAvatarImageName).value).toEqual(
      put(hydrateUserStore({ avatarName: userAvatarImageName }))
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: hydrateUserSelectedAvatarImage => failure', () => {
    const gen = hydrateUserSelectedAvatarImage()
    expect(gen.next().value).toEqual(
      call(safeGet, STORAGE_KEY_USER_AVATAR_NAME)
    )
    const errorMessage = 'error getting user avatar name'
    expect(gen.throw(new Error(errorMessage)).value).toEqual(
      put(hydrateUserStoreFail(ERROR_HYDRATE_USER_SELECTED_IMAGE(errorMessage)))
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: selectUserAvatarSaga => success', () => {
    const gen = selectUserAvatarSaga()
    expect(gen.next().value).toEqual(
      call(ImagePicker.openPicker, { mediaType: 'photo' })
    )
    expect(gen.next({ path: userAvatarImagePath }).value).toEqual(
      put(saveUserSelectedAvatar(userAvatarImagePath))
    )
    expect(gen.next().done).toBe(true)
  })

  it('saga: selectUserAvatarSaga => failure', () => {
    const gen = selectUserAvatarSaga()
    expect(gen.next().value).toEqual(
      call(ImagePicker.openPicker, { mediaType: 'photo' })
    )
    const errorMessage = 'image picker user cancelled'
    const error = new Error(errorMessage)
    expect(gen.throw(error).value).toEqual(
      put(selectUserAvatarFail(ERROR_SELECT_USER_AVATAR(errorMessage)))
    )
    expect(gen.next().done).toBe(true)
  })
})


<|start_filename|>app/components/claim-proof-header/type-claim-proof-header.js<|end_filename|>
// @flow
import type { Element } from 'react'
import type { GenericObject } from '../../common/type-common'

export type ClaimProofHeaderProps = {
  children?: Element<*> | Array<Element<*>>,
  message?: string,
  title?: string,
  logoUrl: ?string,
  testID: string,
  containerStyle?: GenericObject,
  textContainerStyle?: Array<GenericObject | number>,
  messageStyle?: Array<GenericObject | number>,
  titleStyle?: Array<GenericObject | number>,
  payTokenValue?: ?string,
}

export type ClaimProofHeaderNotchProps = {
  containerStyle?: GenericObject,
  titleStyle?: Array<GenericObject | number>,
}


<|start_filename|>app/store/hydration-store.js<|end_filename|>
// @flow
import { call, put, fork, all } from 'redux-saga/effects'
import {
  safeDelete,
  safeGet,
  safeSet,
  safeMultiRemove,
  secureDelete,
  secureGet,
} from '../services/storage'
import { hydratePushTokenSaga } from '../push-notification/push-notification-store'
import { hydrateEulaAccept } from '../eula/eula-store'
import {
  hydrateConnections,
  hydrateThemes,
  removePersistedThemes,
  hydrateConnectionSaga,
} from '../store/connections-store'
import { hydrateClaimMapSaga } from '../claim/claim-store'
import {
  CONNECTIONS,
  PUSH_COM_METHOD,
  LAST_SUCCESSFUL_BACKUP,
  CONNECT_ME_STORAGE_KEY,
  CLAIM_MAP,
  WALLET_ENCRYPTION_KEY,
  WALLET_BALANCE,
  WALLET_ADDRESSES,
  WALLET_HISTORY,
  PASSPHRASE_SALT_STORAGE_KEY,
  PASSPHRASE_STORAGE_KEY,
} from '../common'
import { STORAGE_KEY_USER_ONE_TIME_INFO } from '../store/user/type-user-store'
import { CLAIM_OFFERS } from '../claim-offer/type-claim-offer'
import { STORAGE_KEY_THEMES } from '../store/type-connection-store'
import { HISTORY_EVENT_STORAGE_KEY } from '../connection-history/type-connection-history'
import {
  TOUCH_ID_STORAGE_KEY,
  PIN_ENABLED_KEY,
  IN_RECOVERY,
  PIN_HASH,
  SALT,
} from '../lock/type-lock'
import {
  hydrateUserStoreSaga,
  removePersistedUserSelectedAvatarImage,
} from './user/user-store'
import { hydrateWalletStoreSaga } from '../wallet/wallet-store'
import {
  promptBackupBanner,
  deletePersistedPassphrase,
  hydratePassphraseFromWallet,
} from '../backup/backup-store'
import {
  STORAGE_KEY_SWITCHED_ENVIRONMENT_DETAIL,
  __uniqueId,
  ERROR_NO_WALLET_NAME,
} from './type-config-store'
import { STORAGE_KEY_SHOW_BANNER } from '../components/banner/banner-constants'
import { STORAGE_KEY_EULA_ACCEPTANCE } from '../eula/type-eula'
import { hydrateClaimOffersSaga } from '../claim-offer/claim-offer-store'
import { hydrateBackupSaga } from '../backup/backup-store'
import { loadHistorySaga } from '../connection-history/connection-history-store'
import { IS_ALREADY_INSTALLED } from '../common'
import {
  alreadyInstalledAction,
  hydrated,
  ensureVcxInitSuccess,
  hydrateSwitchedEnvironmentDetails,
  initialized,
} from './config-store'
import {
  lockEnable,
  enableTouchIdAction,
  disableTouchIdAction,
  setInRecovery,
} from '../lock/lock-store'
import { captureError } from '../services/error/error-handler'
import {
  simpleInit,
  vcxShutdown,
  getWalletPoolName,
} from '../bridge/react-native-cxs/RNCxs'
import { STORAGE_KEY_USER_AVATAR_NAME } from './user/type-user-store'
import { safeToDownloadSmsInvitation } from '../sms-pending-invitation/sms-pending-invitation-store'
import { hydrateProofRequestsSaga } from './../proof-request/proof-request-store'
import { WALLET_KEY } from '../bridge/react-native-cxs/vcx-transformers'
import RNFetchBlob from 'react-native-fetch-blob'
import { Platform } from 'react-native'

export function* deleteDeviceSpecificData(): Generator<*, *, *> {
  try {
    const keysToDelete = [
      STORAGE_KEY_SHOW_BANNER,
      PUSH_COM_METHOD,
      LAST_SUCCESSFUL_BACKUP,
      STORAGE_KEY_USER_AVATAR_NAME,
    ]
    yield call(safeMultiRemove, keysToDelete)
    yield call(deleteSecureStorageData)
  } catch (e) {
    console.log(e)
    // deletion fails, now what to do
    captureError(e)
  }
}

function* deleteSecureStorageData(): Generator<*, *, *> {
  try {
    const secureKeysToDelete = [
      WALLET_KEY,
      STORAGE_KEY_SWITCHED_ENVIRONMENT_DETAIL,
      CONNECTIONS,
      CONNECT_ME_STORAGE_KEY,
      CLAIM_MAP,
      WALLET_ENCRYPTION_KEY,
      WALLET_BALANCE,
      WALLET_ADDRESSES,
      WALLET_HISTORY,
      PASSPHRASE_SALT_STORAGE_KEY,
      PASSPHRASE_STORAGE_KEY,
      CLAIM_OFFERS,
      STORAGE_KEY_USER_ONE_TIME_INFO,
      STORAGE_KEY_THEMES,
      HISTORY_EVENT_STORAGE_KEY,
      PIN_HASH,
      SALT,
    ]
    const deleteOperations = []
    for (let index = 0; index < secureKeysToDelete.length; index++) {
      const secureKey = secureKeysToDelete[index]
      // not waiting for one delete operation to finish
      deleteOperations.push(call(secureDelete, secureKey))
    }
    // wait till all delete operations are done in parallel
    yield all(deleteOperations)
  } catch (e) {
    console.log(e)
    // not sure what to do when deletion fails
    captureError(e)
  }
}

export function* deleteWallet(): Generator<*, *, *> {
  try {
    yield* deletePersistedPassphrase()
  } catch (e) {
    // if there is any error thrown from deletePersistedPassphrase
    captureError(e)
    //TODO handle catch
  }
}

export function* alreadyInstalledNotFound(): Generator<*, *, *> {
  yield put(alreadyInstalledAction(false))
  yield call(deleteDeviceSpecificData)
  yield put(lockEnable('false'))
  yield put(initialized())
  yield put(hydrated())

  try {
    yield call(safeSet, IS_ALREADY_INSTALLED, 'true')
  } catch (e) {
    // somehow the storage failed, so we need to find someway to store
    // maybe we fallback to file based storage

    // Capture AsyncStorage failed
    captureError(e)
  }
}

export function* confirmFirstInstallationWithWallet(): Generator<*, *, *> {
  const appUniqueId = yield call(secureGet, __uniqueId)
  const walletName = appUniqueId && `${appUniqueId}-cm-wallet`
  if (!walletName) {
    throw new Error(ERROR_NO_WALLET_NAME)
  }
  const { fs } = RNFetchBlob
  const documentDirectory: string = fs.dirs.DocumentDir
  const walletNameExists = yield call(
    fs.exists,
    `${documentDirectory}/.indy_client/wallet/${walletName}`
  )
  if (!walletNameExists) {
    throw new Error(ERROR_NO_WALLET_NAME)
  }
  // do the async set operations
  yield call(safeSet, IS_ALREADY_INSTALLED, 'true')
  yield call(safeSet, STORAGE_KEY_EULA_ACCEPTANCE, 'true')
  yield call(safeSet, PIN_ENABLED_KEY, 'true')
  yield call(safeSet, __uniqueId, appUniqueId)
}

export function* hydrate(): any {
  try {
    let isAlreadyInstalled = yield call(safeGet, IS_ALREADY_INSTALLED)
    if (isAlreadyInstalled !== 'true') {
      try {
        yield* confirmFirstInstallationWithWallet()
      } catch (e) {
        yield* alreadyInstalledNotFound()
        return
      }
    }

    yield put(alreadyInstalledAction(true))
    try {
      // check if privacy policy was accepted or not
      let isEulaAccept = yield call(safeGet, STORAGE_KEY_EULA_ACCEPTANCE)
      if (!isEulaAccept) {
        // if eula was not accepted, then we know that lock was never set
        // so no need to go any further
        yield* alreadyInstalledNotFound()
        return
      }
      isEulaAccept = JSON.parse(isEulaAccept)
      yield put(hydrateEulaAccept(isEulaAccept))

      // restore app lock settings
      const [isLockEnabled, isTouchIdEnabled] = yield all([
        call(safeGet, PIN_ENABLED_KEY),
        call(safeGet, TOUCH_ID_STORAGE_KEY),
      ])

      if (isLockEnabled !== 'true') {
        yield* alreadyInstalledNotFound()
        // do not move forward and end here
        return
      }
      yield put(lockEnable(isLockEnabled))

      //InRecovery determines if we are in the recovery flow
      //and still need to choose if we want to use previous pin or set new pin
      let inRecovery = yield call(safeGet, IN_RECOVERY)
      if (inRecovery === 'true') {
        yield put(setInRecovery(inRecovery))
      }
      if (isTouchIdEnabled === 'true') {
        yield put(enableTouchIdAction())
      } else {
        yield put(disableTouchIdAction())
      }
      // Splash screen does redirection on the basis of three flags
      // 1. if app is opened for first time or not
      // 2. If user has already accepted privacy policy or not
      // 3. If user has enabled any type of lock (pass code, touch id, face id, etc.)
      // Splash screen can start redirection as soon as we have above three flags
      // so we are raising this action which tells splash screen that we have values
      // for all three flags and redirection logic can move forward
      yield put(initialized())

      if (inRecovery === 'true') {
        // replace below line with wallet init saga
        yield call(simpleInit)
      }

      yield* hydrateSwitchedEnvironmentDetails()
      // since we hydrated environment details, so now we can start downloading sms
      yield put(safeToDownloadSmsInvitation())

      yield* hydratePushTokenSaga()
      yield* hydrateWalletStoreSaga()
      yield* hydrateConnectionSaga()
      yield* hydrateProofRequestsSaga()
      yield* hydrateThemes()
      yield* hydrateUserStoreSaga()
      yield* hydrateBackupSaga()
      yield* hydrateClaimMapSaga()
      yield* hydrateClaimOffersSaga()
      yield* loadHistorySaga()

      if (inRecovery === 'true') {
        // TODO: Move vcx shutdown logic inside ensureVcxInitSuccess
        yield call(vcxShutdown, false)
      }
      yield put(hydrated())
      const vcxResult = yield* ensureVcxInitSuccess()
      if (vcxResult && vcxResult.fail) {
        throw new Error(JSON.stringify(vcxResult.fail.message))
      }
    } catch (e) {
      captureError(e)
      console.error(`hydrateSaga: ${e}`)
      // somehow the secure storage failed, so we need to find someway to store
      // maybe we fallback to file based storage
    }
  } catch (e) {
    // if we did not find any value in user default storage
    // it means that user uninstalled the app and is now trying again
    // or this is a new installation
    console.error(`hydrateSaga: ${e}`)
    yield* alreadyInstalledNotFound()
  }
}

export function* hydrateNonReduxData(): Generator<*, *, *> {
  // this saga is supposed to be run while restoring wallet
  // gets the data from wallet and hydrate that data in keychain/keystore
  // reason we are doing this separately than in hydrate saga
  // is that this data is not stored in redux-store because we pull it
  // when needed, so hydrate won't hydrate this data
  // but we still need to take this data out of wallet and put in Keychain
  yield* hydratePassphraseFromWallet()
}


<|start_filename|>app/claim-offer/__tests__/claim-offer-store.spec.js<|end_filename|>
// @flow
import { put, call, select, race, take } from 'redux-saga/effects'
import claimOfferStore, {
  claimOfferReceived,
  claimOfferShown,
  claimOfferIgnored,
  claimOfferRejected,
  sendClaimRequest,
  claimRequestSuccess,
  claimRequestFail,
  acceptClaimOffer,
  convertClaimRequestToEdgeClaimRequest,
  addSerializedClaimOffer,
  hydrateClaimOffers,
  saveClaimOffersSaga,
  removePersistedSerializedClaimOffersSaga,
  hydrateClaimOffersSaga,
  saveSerializedClaimOffer,
  claimOfferAccepted,
  claimOfferShowStart,
  resetClaimRequestStatus,
} from '../claim-offer-store'
import {
  CLAIM_OFFER_ACCEPTED,
  CLAIM_OFFERS,
  SAVE_CLAIM_OFFERS_SUCCESS,
  SAVE_CLAIM_OFFERS_FAIL,
  ERROR_SAVE_CLAIM_OFFERS,
  REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS,
} from '../type-claim-offer'
import { INITIAL_TEST_ACTION } from '../../common/type-common'
import type { ClaimOfferAcceptedAction } from '../type-claim-offer'
import {
  getClaimOffer,
  getUserPairwiseDid,
  getAgencyUrl,
  getUserOneTimeInfo,
  getAgencyVerificationKey,
  getRemotePairwiseDidAndName,
  getPoolConfig,
} from '../../store/store-selector'
import {
  serializeClaimOffer,
  getHandleBySerializedConnection,
  getClaimHandleBySerializedClaimOffer,
  getClaimOfferState,
  sendClaimRequest as sendClaimRequestApi,
} from '../../bridge/react-native-cxs/RNCxs'
import {
  CLAIM_STORAGE_FAIL,
  CLAIM_STORAGE_SUCCESS,
} from '../../claim/type-claim'
import { MESSAGE_TYPE } from '../../api/api-constants'
import {
  claimOffer,
  claimOfferId as uid,
  pairwiseConnection,
  claimRequest,
  claimOfferPayload,
  poolConfig,
  serializedClaimOffers,
  serializedClaimOffer,
  vcxSerializedConnection,
} from '../../../__mocks__/static-data'
import { expectSaga } from 'redux-saga-test-plan'
import * as matchers from 'redux-saga-test-plan/matchers'
import { throwError } from 'redux-saga-test-plan/providers'
import {
  secureSet,
  secureDelete,
  getHydrationItem,
} from '../../services/storage'

describe('claim offer store', () => {
  const initialAction = { type: 'INITIAL_TEST_ACTION' }
  let initialState = {
    vcxSerializedClaimOffers: {},
  }
  let newState = {
    vcxSerializedClaimOffers: {},
  }
  const claimOfferVcxInitialState = 1

  beforeEach(() => {
    initialState = claimOfferStore(undefined, initialAction)
  })

  it('should correctly calculate initial state', () => {
    expect(initialState).toMatchSnapshot()
  })

  it('claim offer is received', () => {
    newState = claimOfferStore(
      initialState,
      claimOfferReceived(claimOffer.payload, claimOffer.payloadInfo)
    )
    expect(newState).toMatchSnapshot()
  })

  it('claim offer is shown', () => {
    newState = claimOfferStore(newState, claimOfferShown(uid))
    expect(newState).toMatchSnapshot()
  })

  it('claim offer is ignored', () => {
    newState = claimOfferStore(newState, claimOfferIgnored(uid))
    expect(newState).toMatchSnapshot()
  })

  it('claim offer is rejected', () => {
    newState = claimOfferStore(newState, claimOfferRejected(uid))
    expect(newState).toMatchSnapshot()
  })

  it('claim offer is accepted', () => {
    newState = claimOfferStore(newState, acceptClaimOffer(uid))
    expect(newState).toMatchSnapshot()
  })

  it('claim request is sent', () => {
    newState = claimOfferStore(
      newState,
      sendClaimRequest(uid, claimOfferPayload)
    )
    expect(newState).toMatchSnapshot()
  })

  it('claim request is success', () => {
    newState = claimOfferStore(newState, claimRequestSuccess(uid))
    expect(newState).toMatchSnapshot()
  })

  it('claim request is fail', () => {
    newState = claimOfferStore(
      newState,
      claimRequestFail(uid, {
        code: 'TEST-100',
        message: 'Claim request failed',
      })
    )
    expect(newState).toMatchSnapshot()
  })

  it('action: ADD_SERIALIZED_CLAIM_OFFER', () => {
    newState = claimOfferStore(
      newState,
      addSerializedClaimOffer(
        serializedClaimOffer,
        pairwiseConnection.identifier,
        uid,
        claimOfferVcxInitialState
      )
    )
    expect(newState).toMatchSnapshot()
  })

  it('action: CLAIM_OFFER_SHOW_START', () => {
    expect(
      claimOfferStore(newState, claimOfferShowStart(uid))
    ).toMatchSnapshot()
  })

  it('action: RESET_CLAIM_REQUEST_STATUS', () => {
    const stateAfterClaimRequestFail = claimOfferStore(
      newState,
      claimRequestFail(uid, {
        code: 'TEST-100',
        message: 'Claim request failed',
      })
    )
    expect(
      claimOfferStore(stateAfterClaimRequestFail, resetClaimRequestStatus(uid))
    ).toMatchSnapshot()
  })

  it('should reset claim offer store, if RESET action is raised', () => {
    expect(claimOfferStore(newState, { type: 'RESET' })).toMatchSnapshot()
  })

  it('action: HYDRATE_CLAIM_OFFERS_SUCCESS', () => {
    newState = claimOfferStore(
      newState,
      hydrateClaimOffers(JSON.parse(serializedClaimOffers))
    )
    expect(newState).toMatchSnapshot()
  })

  it('saga: saveSerializedClaimOfferSaga, success', () => {
    return expectSaga(
      saveClaimOffersSaga,
      addSerializedClaimOffer(
        serializedClaimOffer,
        pairwiseConnection.identifier,
        uid,
        claimOfferVcxInitialState
      )
    )
      .withState({ claimOffer: { vcxSerializedClaimOffers: {} } })
      .call(secureSet, CLAIM_OFFERS, '{"vcxSerializedClaimOffers":{}}')
      .put({ type: SAVE_CLAIM_OFFERS_SUCCESS })
      .run()
  })

  it('saga: saveSerializedClaimOfferSaga, fail', () => {
    const errorMessage = 'test error'
    const failSaveSerializedClaimOffers = new Error(errorMessage)

    return expectSaga(
      saveClaimOffersSaga,
      addSerializedClaimOffer(
        serializedClaimOffer,
        pairwiseConnection.identifier,
        uid,
        claimOfferVcxInitialState
      )
    )
      .withState({ claimOffer: { vcxSerializedClaimOffers: {} } })
      .provide([
        [
          matchers.call.fn(secureSet, CLAIM_OFFERS, '{}'),
          throwError(failSaveSerializedClaimOffers),
        ],
      ])
      .put({
        type: SAVE_CLAIM_OFFERS_FAIL,
        error: ERROR_SAVE_CLAIM_OFFERS(errorMessage),
      })
      .run()
  })

  it('saga: removePersistedSerializedClaimOffersSaga, success', () => {
    return expectSaga(removePersistedSerializedClaimOffersSaga)
      .call(secureDelete, CLAIM_OFFERS)
      .put({
        type: REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS,
      })
      .run()
  })

  it('saga: hydrateClaimOffersSaga, success', () => {
    return expectSaga(hydrateClaimOffersSaga)
      .provide([
        [
          matchers.call.fn(getHydrationItem, CLAIM_OFFERS),
          serializedClaimOffers,
        ],
      ])
      .put(hydrateClaimOffers(JSON.parse(serializedClaimOffers)))
      .run()
  })

  it('saga: claimOfferAccepted, success', () => {
    const claimOfferPayload = {
      ...claimOffer.payload,
      ...claimOffer.payloadInfo,
    }
    const userDID = pairwiseConnection.identifier
    const claimOfferSerialized = {
      messageId: uid,
      serialized: serializedClaimOffer,
      state: 1,
    }
    const stateWithClaimOfferAndSerialized = {
      claimOffer: {
        [uid]: claimOfferPayload,
        vcxSerializedClaimOffers: {
          [userDID]: {
            [uid]: claimOfferSerialized,
          },
        },
      },
      connections: {
        data: {
          [userDID]: {
            ...pairwiseConnection,
            senderDID: claimOfferPayload.remotePairwiseDID,
            vcxSerializedConnection: vcxSerializedConnection,
          },
        },
      },
    }
    const claimHandle = 1
    const connectionHandle = 1
    const paymentHandle = 0

    return expectSaga(claimOfferAccepted, acceptClaimOffer(uid))
      .withState(stateWithClaimOfferAndSerialized)
      .provide([
        [
          matchers.call.fn(
            getHandleBySerializedConnection,
            vcxSerializedConnection
          ),
          connectionHandle,
        ],
        [
          matchers.call.fn(
            getClaimHandleBySerializedClaimOffer,
            claimOfferSerialized
          ),
          claimHandle,
        ],
        [
          matchers.call.fn(
            sendClaimRequestApi,
            claimHandle,
            connectionHandle,
            paymentHandle
          ),
          true,
        ],
      ])
      .dispatch({ type: CLAIM_STORAGE_SUCCESS, messageId: uid })
      .call(sendClaimRequestApi, claimHandle, connectionHandle, paymentHandle)
      .call(
        saveSerializedClaimOffer,
        claimHandle,
        pairwiseConnection.identifier,
        uid
      )
      .put(sendClaimRequest(uid, claimOfferPayload))
      .run()
  })

  it('saga: saveSerializedClaimOffer', () => {
    const claimHandle = 1
    return expectSaga(
      saveSerializedClaimOffer,
      claimHandle,
      pairwiseConnection.identifier,
      uid
    )
      .provide([
        [
          matchers.call.fn(serializeClaimOffer, claimHandle),
          serializedClaimOffer,
        ],
        [
          matchers.call.fn(getClaimOfferState, claimHandle),
          claimOfferVcxInitialState,
        ],
      ])
      .put(
        addSerializedClaimOffer(
          serializedClaimOffer,
          pairwiseConnection.identifier,
          uid,
          claimOfferVcxInitialState
        )
      )
      .call(serializeClaimOffer, claimHandle)
      .call(getClaimOfferState, claimHandle)
      .run()
  })
})

describe('convertClaimRequestToEdgeClaimRequest', () => {
  it('should convert correctly', () => {
    const edgeClaimRequest = convertClaimRequestToEdgeClaimRequest({
      blinded_ms: {
        prover_did: 'userPairwiseDid',
        u: 'u',
        ur: 'ur',
      },
      schema_seq_no: 12,
      issuer_did: 'issuer_did',
      remoteDid: 'remoteDid',
      userPairwiseDid: 'userPairwiseDid',
    })
    expect(edgeClaimRequest).toMatchSnapshot()
  })
})


<|start_filename|>app/components/badge.js<|end_filename|>
// @flow
import React from 'react'
import { Image, Text, StyleSheet, TouchableWithoutFeedback } from 'react-native'
import { CustomView } from './layout/custom-view'
import { color, font } from '../common/styles/constant'
import empty from '../common/empty'

// We need both type of ribbon and it is better to load them once
const whiteRibbon = require('../images/ribbon_white.png')
const grayRibbon = require('../images/ribbon.png')

// TODO:KS Add props, this component is not being used right now
// so it is not that important to add types here
export const BadgeLabel = (props: *) => {
  const textColor = props.secondary ? styles.secondary : styles.primary
  const center = props.center ? styles.center : null

  return (
    <Text {...props} style={[styles.label, textColor, center, props.style]}>
      {props.text}
    </Text>
  )
}

const Badge = ({ count, secondary, badgeStyle, shadow, onPress }: *) => {
  const badgeColor = secondary
    ? color.bg.primary.font.primary
    : color.bg.secondary.font.primary
  const ribbon = secondary ? whiteRibbon : grayRibbon
  const style = shadow ? styles.shadow : null

  return (
    <CustomView clearBg style={[badgeStyle, style]}>
      <TouchableWithoutFeedback onPress={onPress}>
        <Image
          resizeMode="contain"
          source={ribbon}
          style={styles.image}
          onPress={onPress}
        />
      </TouchableWithoutFeedback>
      <BadgeLabel center secondary={secondary} text={count} style={empty} />
    </CustomView>
  )
}

const styles = StyleSheet.create({
  image: {
    width: 22,
    height: 26,
  },
  shadow: {
    shadowColor: color.bg.primary.color,
    shadowOffset: {
      width: 1,
      height: 1,
    },
    shadowRadius: 4,
    shadowOpacity: 0.9,
  },
  label: {
    fontSize: font.size.XS,
    fontWeight: 'bold',
  },
  primary: {
    color: color.bg.secondary.font.tertiary,
  },
  secondary: {
    color: color.bg.primary.font.primary,
  },
  center: {
    textAlign: 'center',
    textAlignVertical: 'center',
  },
})

export default Badge


<|start_filename|>app/components/request/request-detail-text.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { View as AnimatedView } from 'react-native-animatable'
import { CustomText, CustomView } from '../../components'
import { OFFSET_1X, OFFSET_3X } from '../../common/styles'
import { noop } from '../../common'
import type { RequestDetailTextProps } from './type-request'

export default class RequestDetailText extends PureComponent<
  RequestDetailTextProps,
  void
> {
  render() {
    const { testID } = this.props
    return (
      <AnimatedView
        testID={`${testID}-text-container-animation`}
        accessible={true}
        accessibilityLabel={`${testID}-text-container-animation`}
        animation="bounceInDown"
        duration={1500}
        delay={100}
      >
        <CustomView center testID={`${testID}-text-container-message-title`}>
          <CustomText
            testID={`${testID}-text-title`}
            h4
            center
            thick
            bg="fifth"
            style={[styles.textTitle]}
            testID={`${testID}-text-container-title`}
          >
            {this.props.title}
          </CustomText>
          <CustomText
            h5
            center
            bold
            bg="fifth"
            style={[styles.textMessage]}
            testID={`${testID}-text-container-message`}
          >
            {this.props.message}
          </CustomText>
        </CustomView>
      </AnimatedView>
    )
  }
}

const styles = StyleSheet.create({
  textMessage: {
    margin: OFFSET_1X,
  },
  textTitle: {
    marginVertical: OFFSET_1X,
    marginHorizontal: OFFSET_3X,
    lineHeight: OFFSET_3X,
  },
})


<|start_filename|>app/common/styles/constant.js<|end_filename|>
// @flow
import { StyleSheet } from 'react-native'
import { Dimensions, Platform } from 'react-native'

// TODO:KS Add support for themes as well
// Color name taken from http://www.htmlcsscolor.com/
const zircon = '#ebebea'
export const nightRider = '#333333'
export const grey = '#777777'
export const matterhornSecondary = '#505050'
export const charcoal = '#464646'
export const whiteSmoke = '#f0f0f0'
export const whiteSmokeSecondary = '#f7f7f7'
export const whiteSmokeRGBA = 'rgba(240, 240, 240, 0)'
export const mantis = '#85bf43'
const mantisRGB = '133, 191, 67'
export const greyRGB = '119, 119, 119'
export const white = '#ffffff'
export const whisper = '#EAEAEA'
export const lightDarkBlue = '#4A8FE3'
export const darkGray = '#505050'
export const maroonRed = '#d1021b'

const sirocco = '#636564'
const corduroy = '#3f4140'
const eclipse = '#3f3f3f'
const matterhorn = '#535353'
const blackPearl = '#242b2d'
export const dimGray = '#686868'
const dimGraySecondary = '#6D6D6D'
export const lightGray = '#D8D8D8'
const nobel = '#a0a0a0'
const nobelSecondary = '#9B9B9B'
export const venetianRed = '#d0021b'
export const veniceBlue = '#2A5270'
export const hitSlop = { top: 15, bottom: 15, left: 15, right: 15 }
export const iPhoneXHeight = 812
const dodgerBlue = '#0d8ffc'
const black = '#000000'
const yellowSea = '#EB9B2D'
export const cornFlowerBlue = '#4A90E2'
const atlantis = '#86B93B'
const gamboge = '#DD9012'
const blueViolet = '#8D13FE'
const seaBuckthorn = '#f79347'
const pumpkin = '#F68127'
const olivine = '#97C85F'
const denim = '#1159A9'
const orange = 'rgba(237, 156, 46, 1)'
const orangeDisabled = 'rgba(237, 156, 46, 0.5)'
const darkOrange = 'rgba(207, 127, 20, 1)'
const errorBg = 'rgba(255, 214, 219, 1)'
const darkgray = '#4A4A4A'
const jordyBlue = '#79ade7'
const palePink = '#FFD5DB'

// color shades
const primaryShade = '1.0'
const secondaryShade = '0.6'
export const alertCancel = { text: 'Cancel', style: 'cancel' }
export const color = {
  actions: {
    primary: pumpkin,
    secondary: seaBuckthorn,
    tertiary: mantis,
    quaternary: olivine,
    fifth: white,
    sixth: grey,
    eighth: white,
    dangerous: venetianRed,
    none: white,
    button: {
      primary: {
        rgba: greyRGB + ', ' + primaryShade,
        shade: primaryShade,
      },
      secondary: {
        rgba: greyRGB + ', ' + secondaryShade,
        shade: secondaryShade,
      },
    },
    font: {
      primary: white,
      secondary: white,
      tertiary: white,
      quaternary: white,
      fifth: mantis,
      dangerous: white,
      sixth: white,
      seventh: yellowSea,
      eighth: lightDarkBlue,
    },
  },
  bg: {
    primary: {
      color: nightRider,
      font: {
        primary: white,
        secondary: zircon,
        tertiary: nightRider,
      },
    },
    secondary: {
      color: grey,
      font: {
        primary: white,
        secondary: matterhorn,
        tertiary: whiteSmoke,
        quaternary: dodgerBlue,
      },
    },
    tertiary: {
      color: white,
      font: {
        primary: nightRider,
        secondary: dimGray,
        tertiary: grey,
        quaternary: yellowSea,
        fifth: nobelSecondary,
        sixth: dimGraySecondary,
      },
    },
    quaternary: {
      color: mantis,
      font: {
        primary: white,
      },
    },
    fifth: {
      color: white,
      font: {
        primary: grey,
        secondary: zircon,
        tertiary: eclipse,
        fifth: nightRider,
      },
    },
    sixth: {
      color: nightRider,
      font: {
        primary: white,
      },
    },
    seventh: {
      color: whiteSmoke,
      font: {
        primary: nightRider,
        secondary: dimGray,
        tertiary: grey,
        fifth: yellowSea,
        sixth: dimGraySecondary,
        seventh: nobelSecondary,
      },
    },
    eighth: {
      color: orange,
      disabled: orangeDisabled,
      border: {
        color: darkOrange,
      },
    },
    ninth: {
      color: dimGraySecondary,
    },
    tenth: {
      color: errorBg,
      font: {
        color: venetianRed,
      },
    },
    eleventh: {
      color: cornFlowerBlue,
    },
    twelfth: {
      color: atlantis,
    },
    thirteenth: {
      color: gamboge,
    },
    fourteenth: {
      color: blueViolet,
    },
    fifteenth: {
      color: jordyBlue,
    },
    dark: {
      color: black,
      font: {
        primary: white,
      },
    },
  },
  border: {
    primary: whisper,
    secondary: yellowSea,
  },
  textColor: {
    charcoal: charcoal,
    grey: grey,
    darkgray: darkgray,
  },
  palePink,
}

export const font = {
  size: {
    XS: 12,
    S: 15,
    M: 17,
    M1: 18,
    ML: 20,
    L1: 34,
    L: 40,
    PREFIX: 14,
  },
  family: 'Lato',
}

export const PADDING_HORIZONTAL = 15
export const PADDING_VERTICAL = 8
export const MARGIN_BOTTOM = 4
export const OFFSET_1X = 10
export const OFFSET_2X = 20
export const OFFSET_3X = 30
export const OFFSET_4X = 40
export const OFFSET_5X = 50
export const OFFSET_6X = 60
export const OFFSET_7X = 70
export const OFFSET_9X = 90
export const barStyleDark = 'dark-content'
export const barStyleLight = 'light-content'
export const SHADOW_RADIUS = 8
export const HAIRLINE_WIDTH = StyleSheet.hairlineWidth / 2

export const bubbleSize = {
  XS: 40,
  S: 60,
  M: 80,
  L: 100,
  XL: 120,
  XXL: 140,
}

export const PIN_CODE_BORDER_BOTTOM = 4

const { width, height } = Dimensions.get('screen')
export const isiPhone5 = width >= 320 && width < 375
export const isSmallWidthDevice = isiPhone5
export const responsiveHorizontalPadding = isSmallWidthDevice
  ? 5
  : PADDING_HORIZONTAL
export const MEDIUM_DEVICE = 700
export const SHORT_DEVICE = 600
export const VERY_SHORT_DEVICE = 570
export const errorBoxVerifyPassphraseContainer = height > SHORT_DEVICE ? 60 : 90
export const dangerBannerHeight = height > SHORT_DEVICE ? 64 : 90
export const inputBoxVerifyPassphraseHeight =
  height > SHORT_DEVICE || Platform.OS === 'ios' ? 137 : 40
export const isBiggerThanShortDevice = height > SHORT_DEVICE
export const isBiggerThanVeryShortDevice = height > VERY_SHORT_DEVICE
export const isIphoneX = Platform.OS === 'ios' && height === 812
export const deviceHeight = height


<|start_filename|>app/components/custom-date/type-custom-date.js<|end_filename|>
// @flow
import type { GenericObject, ReactChildren } from '../../common/type-common'

export type CustomTextProps = {
  h4: string,
  h5: string,
  h6: string,
  h7: string,
  bold: string,
  thick: string,
  semiBold: string,
  demiBold: string,
  center: string,
  bg: string,
  primary: string,
  secondary: string,
  tertiary: string,
  quaternary: string,
  style: Array<GenericObject>,
  testID: string,
  onPress: () => void,
  onLongPress: () => void,
  transparentBg: string,
  uppercase: string,
  heavy: string,
}

export type CustomDateProps = {
  format?: string,
  children: string,
}


<|start_filename|>app/components/footer-actions/__tests__/footer-actions.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import FooterActions from '../footer-actions'
import { getStore } from '../../../../__mocks__/static-data'
import type { FooterActionsProps } from '../type-footer-actions'

describe('<FooterActions />', () => {
  function getProps(props?: * = {}) {
    return {
      testID: 'test',
      useColorPicker: true,
      ...props,
    }
  }

  function setup(override?: * = {}) {
    const store = getStore()
    const props = getProps(override)
    const wrapper = renderer.create(
      <Provider store={store}>
        <FooterActions {...props} />
      </Provider>
    )

    return { store, wrapper, props }
  }

  it('should match snapshot', () => {
    const { wrapper } = setup()

    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('match snapshot when hidePrimary is true', () => {
    const { wrapper } = setup({ hidePrimary: true })

    expect(wrapper.toJSON()).toMatchSnapshot()
  })
})


<|start_filename|>__mocks__/data/vcx-mock-data.js<|end_filename|>
// @flow

import {
  agencyUrl,
  agencyDID,
  agencyVerificationKey,
} from './config-store-mock-data'
import { userOneTimeInfo } from './user-store-mock-data'
import { WALLET_FILE_NAME } from '../../app/backup/type-backup'

// I believe now is the time when we should start splitting static-data.js
// we are starting to see that we shy away from utilizing existing data,
// which was the intention of creating one file, so that same object
// would be used all throughout app and we would know breakage of contract
// among screens/components as soon as we change some data at one place.
// `flow` solves most of those issues, but still there are some issues
// that flow can't solve, and for those we need test to identify
// and for tests we need some mocked data which will be used throughout tests

export const vcxProvisionResult = {
  wallet_name: WALLET_FILE_NAME,
  wallet_key: 'walletKey',
  agency_endpoint: agencyUrl,
  agency_did: agencyDID,
  agency_verkey: agencyVerificationKey,
  sdk_to_remote_did: userOneTimeInfo.myOneTimeDid,
  sdk_to_remote_verkey: userOneTimeInfo.myOneTimeVerificationKey,
  institution_did: userOneTimeInfo.oneTimeAgencyDid,
  institution_verkey: userOneTimeInfo.oneTimeAgencyVerificationKey,
  remote_to_sdk_did: userOneTimeInfo.myOneTimeAgentDid,
  remote_to_sdk_verkey: userOneTimeInfo.myOneTimeAgentVerificationKey,
}

export const vcxConnectionSerialized = JSON.stringify({})

export const serializedClaimOffer = '{}'

export const serializedClaimOffers = JSON.stringify({
  pairwiseIdentifier1: {
    uid: serializedClaimOffer,
  },
})

export const vcxClaimOffer = {
  msg_type: 'CLAIM_OFFER',
  version: '1.0.0',
  to_did: '8XFh8yBzrpJQmNyZzgoTqB',
  from_did: 'ha66899sadfjZJGINKN0770',
  libindy_offer: '',
  cred_def_id: 'cred_def_id',
  credential_attrs: {
    ['Address 1']: ['Address Address Address'],
    ['Address 2']: ['Address 2 Address 2 Address 2'],
  },
  claim_name: '<NAME>',
  schema_seq_no: 36,
  claim_id: 'jhkad:97:kkda:jhh',
}


<|start_filename|>app/authentication/__tests__/splash-screen.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import {
  splashScreenRoute,
  homeRoute,
  waitForInvitationRoute,
  invitationRoute,
} from '../../common/'
import { PUSH_NOTIFICATION_SENT_CODE } from '../../api/api-constants'
import {
  default as connectedSplashScreen,
  SplashScreenView,
} from '../splash-screen'
import { color } from '../../common/styles'
import SplashScreen from 'react-native-splash-screen'
import {
  getNavigation,
  getStore,
  getSmsPendingInvitationOfToken,
  senderDid1,
} from '../../../__mocks__/static-data'
import { DEEP_LINK_STATUS } from '../../deep-link/type-deep-link'

describe('<SplashScreen />', () => {
  function getProps(overrideProps = {}) {
    const getLock = () => {
      const { lock } = getStore().getState()
      return lock
    }
    // TODO: We have to fix the problem in getStore function, we should be just able to pass an object and
    // TODO: it should deep extend default store state. We can't do these many calls for getStore and getState
    // TODO: for any property that we want to override
    const store = getStore({
      ...getStore().getState(),
      lock: { ...getLock(), isAppLocked: true },
    })
    const {
      deepLink,
      config,
      lock,
      smsPendingInvitation,
      eula,
    } = store.getState()
    const props = {
      navigation: getNavigation(),
      deepLink,
      isInitialized: config.isInitialized,
      lock,
      eula,
      smsPendingInvitation,
      addPendingRedirection: jest.fn(),
      getSmsPendingInvitation: jest.fn(),
      safeToDownloadSmsInvitation: jest.fn(),
      deepLinkProcessed: jest.fn(),
      ...overrideProps,
    }

    return { store, props }
  }

  function setup() {
    const { store, props } = getProps()
    const component = renderer.create(<SplashScreenView {...props} />)
    const instance = component.root.instance

    return { store, props, component, instance }
  }

  it('should match snapshot', () => {
    const { component } = setup()
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })

  it('should add home route to pending redirection if deepLink is empty', () => {
    const { component, props } = setup()
    const { deepLink, addPendingRedirection } = props
    component.update(
      <SplashScreenView
        {...props}
        deepLink={{ ...deepLink, isLoading: false }}
      />
    )
    expect(addPendingRedirection).toHaveBeenCalledWith([
      { routeName: homeRoute },
    ])
  })

  it('should go To homeRoute if deepLink is empty and app was unlocked', () => {
    const { component, props } = setup()
    const { deepLink, navigation, addPendingRedirection, lock } = props
    component.update(
      <SplashScreenView
        {...props}
        lock={{ ...lock, isAppLocked: false }}
        deepLink={{ ...deepLink, isLoading: false }}
      />
    )
    expect(navigation.navigate).toHaveBeenCalledWith(homeRoute)
  })

  it(`should goto 'waitForInvitation' screen and fetch invitation if a deepLink was found and app was unlocked`, () => {
    const { component, props } = setup()
    const { deepLink, getSmsPendingInvitation, lock, navigation } = props
    const updatedDeepLink = {
      ...deepLink,
      isLoading: false,
      tokens: {
        token1: {
          status: DEEP_LINK_STATUS.NONE,
          token: 'token1',
          error: null,
        },
      },
    }
    component.update(
      <SplashScreenView
        {...props}
        deepLink={updatedDeepLink}
        lock={{ ...lock, isAppLocked: false }}
      />
    )
    expect(getSmsPendingInvitation).toHaveBeenCalledWith('token1')
    expect(navigation.navigate).toHaveBeenCalledWith(waitForInvitationRoute)
  })

  it(`should show invitation if invitation is fetched and app is unlocked`, () => {
    const { component, props } = setup()
    const { deepLink, deepLinkProcessed, lock, navigation } = props
    const updatedDeepLink = {
      ...deepLink,
      isLoading: false,
      tokens: {
        '3651947c': {
          status: DEEP_LINK_STATUS.NONE,
          token: '3651947c',
          error: null,
        },
      },
    }
    const smsPendingInvitation = getSmsPendingInvitationOfToken('3651947c')
    component.update(
      <SplashScreenView
        {...props}
        deepLink={updatedDeepLink}
        lock={{ ...lock, isAppLocked: false }}
        smsPendingInvitation={smsPendingInvitation}
      />
    )
    expect(deepLinkProcessed).toHaveBeenCalledWith('3651947c')
    expect(navigation.push).toHaveBeenCalledWith(invitationRoute, {
      senderDID: senderDid1,
      token: '3651947c',
    })
  })

  it(`should add invitation route to pending redirection if invitation is fetched and app is locked`, () => {
    const { component, props } = setup()
    const {
      deepLink,
      deepLinkProcessed,
      addPendingRedirection,
      lock,
      navigation,
    } = props
    const updatedDeepLink = {
      ...deepLink,
      isLoading: false,
      tokens: {
        '3651947c': {
          status: DEEP_LINK_STATUS.NONE,
          token: '3651947c',
          error: null,
        },
      },
    }
    const smsPendingInvitation = getSmsPendingInvitationOfToken('3651947c')
    component.update(
      <SplashScreenView
        {...props}
        deepLink={updatedDeepLink}
        lock={{ ...lock, isAppLocked: true }}
        smsPendingInvitation={smsPendingInvitation}
      />
    )
    expect(deepLinkProcessed).toHaveBeenCalledWith('3651947c')
    expect(addPendingRedirection).toHaveBeenCalledWith([
      {
        routeName: invitationRoute,
        params: { senderDID: senderDid1, token: '3651947c' },
      },
    ])
  })
})


<|start_filename|>app/backup/__tests__/backup-store.spec.js<|end_filename|>
// @flow

import backupReducer, {
  generateBackupFile,
  generateRecoveryPhrase,
  generateRecoveryPhraseSuccess,
  generateBackupFileSuccess,
  exportBackup,
  exportBackupSuccess,
  promptBackupBanner,
  prepareBackup,
  prepareBackupSuccess,
  prepareBackupFail,
} from '../backup-store'
import { BACKUP_STORE_STATUS } from '../type-backup'
import { getStore } from '../../../__mocks__/static-data'
import { backupWalletFail } from '../../wallet/wallet-store'
import { ERROR_BACKUP_WALLET } from '../../wallet/type-wallet'
describe('store: backup-store: ', () => {
  let initialState
  beforeEach(() => {
    initialState = {
      passphrase: { phrase: '', salt: 's', hash: 'h' },
      status: BACKUP_STORE_STATUS.IDLE,
      error: null,
      showBanner: false,
      lastSuccessfulBackup: '',
      backupWalletPath: '',
      prepareBackupStatus: BACKUP_STORE_STATUS.PREPARE_BACK_IDLE,
    }
  })
  const {
    backupWalletPath,
    passphrase,
    lastSuccessfulBackup,
  } = getStore().getState().backup
  const generateRecoveryPhraseState = backupReducer(
    initialState,
    generateRecoveryPhrase()
  )
  const generateRecoveryPhraseSuccessState = backupReducer(
    generateRecoveryPhraseState,
    generateRecoveryPhraseSuccess(passphrase)
  )
  const generateBackupFileState = backupReducer(
    generateRecoveryPhraseState,
    generateBackupFile()
  )
  const generateBackupFileSuccessState = backupReducer(
    generateBackupFileState,
    generateBackupFileSuccess(backupWalletPath)
  )
  const exportBackupState = backupReducer(
    generateBackupFileSuccessState,
    exportBackup()
  )

  it('action: GENERATE_RECOVERY_PHRASE', () => {
    expect(
      backupReducer(initialState, generateRecoveryPhrase())
    ).toMatchSnapshot()
  })

  it('action: GENERATE_RECOVERY_PHRASE_SUCCESS', () => {
    expect(
      backupReducer(
        generateRecoveryPhraseState,
        generateRecoveryPhraseSuccess(passphrase)
      )
    ).toMatchSnapshot()
  })

  it('action: GENERATE_BACKUP_FILE', () => {
    expect(
      backupReducer(generateRecoveryPhraseSuccessState, generateBackupFile())
    ).toMatchSnapshot()
  })

  it('action: GENERATE_BACKUP_FILE_SUCCESS', () => {
    expect(
      backupReducer(
        generateBackupFileState,
        generateBackupFileSuccess(backupWalletPath)
      )
    ).toMatchSnapshot()
  })

  it('action: EXPORT_BACKUP', () => {
    expect(
      backupReducer(generateBackupFileSuccessState, exportBackup())
    ).toMatchSnapshot()
  })

  it('action: EXPORT_BACKUP_SUCCESS', () => {
    expect(
      backupReducer(
        exportBackupState,
        exportBackupSuccess(lastSuccessfulBackup)
      )
    ).toMatchSnapshot()
  })

  // TODO: fix flow type
  // it('action: PROMPT_WALLET_BACKUP_BANNER', () => {
  //   expect(
  //     backupReducer(initialState, promptBackupBanner(true))
  //   ).toMatchSnapshot()
  // })

  it('action: BACKUP_WALLET_FAIL', () => {
    expect(
      backupReducer(initialState, backupWalletFail(ERROR_BACKUP_WALLET))
    ).toMatchSnapshot()
  })

  it('action: PREPARE_BACKUP_LOADING', () => {
    expect(backupReducer(initialState, prepareBackup())).toMatchSnapshot()
  })

  it('action: PREPARE_BACKUP_SUCCESS', () => {
    expect(
      backupReducer(initialState, prepareBackupSuccess())
    ).toMatchSnapshot()
  })

  it('action: PREPARE_BACKUP_FAILURE', () => {
    const testError = {
      code: '000',
      message: 'test message',
    }
    expect(
      backupReducer(initialState, prepareBackupFail(testError))
    ).toMatchSnapshot()
  })

  // TODO:KS Start adding tests for all sagas inside backup store
})


<|start_filename|>app/settings/__tests/settings.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { Settings } from '../settings'
import { getStore, getNavigation } from '../../../__mocks__/static-data'
import { settingsRoute } from '../../common'

describe('user settings screen', () => {
  const store = getStore()

  function getProps() {
    return {
      walletBackup: {
        encryptionKey: 'walletEncryptionKey',
        status: 'IDLE',
      },
      timeStamp: new Date().getTime(),
      currentScreen: settingsRoute,
      navigation: getNavigation(),
      selectUserAvatar: jest.fn(),
      touchIdActive: false,
      navigationOptions: jest.fn(),
    }
  }

  function setup() {
    const props = getProps()
    return { props }
  }

  it('should render properly and snapshot should match', () => {
    const { props } = setup()
    const tree = renderer
      .create(
        <Provider store={store}>
          <Settings {...props} />
        </Provider>
      )
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/offline/offline.js<|end_filename|>
// @flow

import React, { PureComponent } from 'react'
import { View, StyleSheet, NetInfo } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { offline } from './offline-store'
import type { OfflineProps } from './type-offline'
import type { Store } from '../store/type-store'
import { getOfflineStatus } from '../store/store-selector'
import { Container } from '../components'
import VectorIcon from '../components/vector-icon/vector-icon'

export class Offline extends PureComponent<OfflineProps> {
  connectivityChecker: number

  componentDidMount() {
    NetInfo.isConnected.addEventListener(
      'connectionChange',
      this.handleConnectivityChange
    )
  }

  componentWillUnmount() {
    NetInfo.isConnected.removeEventListener(
      'connectionChange',
      this.handleConnectivityChange
    )
    this.clearInternetCheck()
  }

  clearInternetCheck() {
    this.connectivityChecker && clearInterval(this.connectivityChecker)
  }

  handleConnectivityChange = (isConnected: boolean) => {
    if (!isConnected) {
      // NetInfo does not reliably change status to connected
      // however, it works pretty well to change status to offline
      if (!this.connectivityChecker) {
        // once we know that we are offline, then we start checking for online
        // and does not solely rely on NetInfo module
        this.connectivityChecker = setInterval(this.checkConnectivity, 5000)
      }
    } else {
      this.clearInternetCheck()
    }
    this.props.offline(!isConnected)
  }

  checkConnectivity = () => {
    fetch('https://www.google.com/', {
      method: 'HEAD',
    })
      .then(response => {
        if (response.status < 500) {
          this.handleConnectivityChange(true)
          this.clearInternetCheck()
        } else {
          this.handleConnectivityChange(false)
        }
      })
      .catch(error => {
        this.handleConnectivityChange(false)
      })
  }

  render() {
    const { isOffline, overlay, render } = this.props
    // Will only render if it's passed the banner prop. This allows us to add the component
    // to the app root so that it's the only one setting/removing the connectionChange event listener

    if (isOffline && !overlay && render) {
      return render(!isOffline)
    }

    if (isOffline && overlay) {
      return (
        <View style={styles.overlay}>
          <Container vCenter hCenter>
            <VectorIcon icon="offline" width={64} height={64} />
          </Container>
        </View>
      )
    }

    return null
  }
}

const mapStateToProps = (state: Store) => ({
  isOffline: getOfflineStatus(state),
})

const mapDispatchToProps = dispatch => bindActionCreators({ offline }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(Offline)

const styles = StyleSheet.create({
  overlay: {
    position: 'absolute',
    width: '100%',
    height: '100%',
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
})


<|start_filename|>app/components/avatar/avatar-style.js<|end_filename|>
// @flow
import React from 'react'
import { StyleSheet } from 'react-native'
const size = {
  small: 50,
  medium: 76,
  large: 100,
}

export default StyleSheet.create({
  small: {
    width: size.small,
    height: size.small,
  },
  medium: {
    width: size.medium,
    height: size.medium,
  },
  large: {
    width: size.large,
    height: size.large,
  },
  smallRound: {
    borderRadius: size.small / 2,
  },
  mediumRound: {
    borderRadius: size.medium / 2,
  },
  largeRound: {
    borderRadius: size.large / 2,
  },
  clearBg: {
    backgroundColor: 'transparent',
  },
})


<|start_filename|>app/settings/type-settings.js<|end_filename|>
// @flow
import type { ReactNavigation } from '../common/type-common'

export type SettingsProps = {
  touchIdActive: boolean,
  currentScreen: string,
  timeStamp: number,
  selectUserAvatar: () => void,
  walletBackup: {
    status: string,
    encryptionKey: string,
  },
} & ReactNavigation

export type SettingsState = {
  walletBackupModalVisible: boolean,
  disableTouchIdSwitch: boolean,
}


<|start_filename|>app/common/empty.js<|end_filename|>
// @flow
// sometimes we need an empty object to use as a placeholder in destructuring
export default {}


<|start_filename|>app/switch-environment/type-switch-environment.js<|end_filename|>
// @flow
import type { ReactNavigation } from '../common/type-common'

export type SwitchEnvironmentProps = {
  changeEnvironment: (
    agencyUrl: string,
    agencyDID: string,
    agencyVerificationKey: string,
    poolConfig: string
  ) => void,
  agencyDID: string,
  agencyVerificationKey: string,
  agencyUrl: string,
  poolConfig: string,
  disableDevMode: () => void,
} & ReactNavigation

export type SwitchEnvironmentState = {
  agencyDID: string,
  agencyVerificationKey: string,
  agencyUrl: string,
  poolConfig: string,
}


<|start_filename|>app/claim/type-claim.js<|end_filename|>
// @flow

import type {
  GenericObject,
  CustomError,
  InitialTestAction,
  ResetAction,
  NotificationPayload,
} from '../common/type-common'
import type { ClaimPushPayload } from '../push-notification/type-push-notification'

export type Claim = {
  messageId: string,
  claim: { [string]: Array<string> },
  schema_seq_no: number,
  issuer_did: string,
  signature: {
    primary_claim: {
      m2: string,
      a: string,
      e: string,
      v: string,
    },
    non_revocation_claim?: GenericObject,
  },
  optional_data?: GenericObject,
  remoteDid: string,
  uid: string,
  from_did: string,
  forDID: string,
  connectionHandle?: number,
  remotePairwiseDID?: string,
}

export type ClaimWithUuid = Claim & {
  claim_uuid: string,
}

export const CLAIM_RECEIVED = 'CLAIM_RECEIVED'
export type ClaimReceivedAction = {
  type: typeof CLAIM_RECEIVED,
  claim: Claim,
}

export const CLAIM_STORAGE_SUCCESS = 'CLAIM_STORAGE_SUCCESS'
export type ClaimStorageSuccessAction = {
  type: typeof CLAIM_STORAGE_SUCCESS,
  messageId: string,
}

export const CLAIM_STORAGE_FAIL = 'CLAIM_STORAGE_FAIL'
export type ClaimStorageFailAction = {
  type: typeof CLAIM_STORAGE_FAIL,
  messageId: string,
  error: CustomError,
}

export const MAP_CLAIM_TO_SENDER = 'MAP_CLAIM_TO_SENDER'
export type MapClaimToSenderAction = {
  type: typeof MAP_CLAIM_TO_SENDER,
  claimUuid: string,
  senderDID: string,
  myPairwiseDID: string,
  logoUrl: string,
}

export type ClaimMap = {
  +[claimUuid: string]: {
    senderDID: string,
    myPairwiseDID: string,
    logoUrl: string,
  },
}

export const HYDRATE_CLAIM_MAP = 'HYDRATE_CLAIM_MAP'
export type HydrateClaimMapAction = {
  type: typeof HYDRATE_CLAIM_MAP,
  claimMap: ClaimMap,
}

export const HYDRATE_CLAIM_MAP_FAIL = 'HYDRATE_CLAIM_MAP_FAIL'
export type HydrateClaimMapFailAction = {
  type: typeof HYDRATE_CLAIM_MAP_FAIL,
  error: CustomError,
}

export type ClaimPushPayloadVcx = {
  connectionHandle: number,
}
export type ClaimVcx = NotificationPayload & ClaimPushPayloadVcx

export const CLAIM_RECEIVED_VCX = 'CLAIM_RECEIVED_VCX'
export type ClaimReceivedVcxAction = {
  type: typeof HYDRATE_CLAIM_MAP_FAIL,
  claim: ClaimVcx,
}

export type ClaimAction =
  | ClaimReceivedAction
  | ClaimStorageSuccessAction
  | ClaimStorageFailAction
  | MapClaimToSenderAction
  | HydrateClaimMapAction
  | HydrateClaimMapFailAction
  | InitialTestAction
  | ResetAction
  | ClaimReceivedVcxAction

export type ClaimStore = {
  +[string]: {
    claim: Claim,
    error?: CustomError,
  },
  claimMap: ClaimMap,
}

export const ERROR_CLAIM_HYDRATE_FAIL = {
  message: 'Failed to hydrate claim map',
  code: 'CL-001',
}

export type GetClaimVcxResult = {
  claimUuid: string,
  claim: ClaimPushPayload,
}


<|start_filename|>app/services/storage.js<|end_filename|>
// @flow
import { AsyncStorage } from 'react-native'
import { call, select } from 'redux-saga/effects'
import RNSensitiveInfo from 'react-native-sensitive-info'
import {
  setWalletItem,
  getWalletItem,
  deleteWalletItem,
  updateWalletItem,
  vcxShutdown,
} from '../bridge/react-native-cxs/RNCxs'
import { captureError } from './error/error-handler'
import { IN_RECOVERY } from '../lock/type-lock'
import { noop } from '../common'

const storageName = {
  sharedPreferencesName: 'ConnectMeSharedPref',
  keychainService: 'ConnectMeKeyChain',
}

// SECURE STORAGE
export const secureSet = (key: string, data: string) =>
  RNSensitiveInfo.setItem(key, data, storageName)

export const secureGet = async (key: string) => {
  const data = await RNSensitiveInfo.getItem(key, storageName)

  return data
}

export const secureGetAll = () => RNSensitiveInfo.getAllItems(storageName)

export const secureDelete = (key: string) =>
  RNSensitiveInfo.deleteItem(key, storageName)

export const getStackTrace = () => {
  var obj = {}
  Error.captureStackTrace(obj, getStackTrace)
  return obj.stack
}

// WALLET STORAGE
export const walletSet = async (key: string, data: string) => {
  try {
    await setWalletItem(key, data)
  } catch (err) {
    captureError(err)
    try {
      // if add item fails, try update item
      await walletUpdate(key, data)
    } catch (e) {
      captureError(e)
      // need to think about what happens if storage fails
      console.log(`Storage fails: key: ${key}, Error: ${e}`)
    }
  }
}

export const walletGet = async (key: string) => {
  try {
    const data: string = await getWalletItem(key)
    return data
  } catch (e) {
    captureError(e)
    console.log(`walletGet: key: ${key}, Error: ${e}`)
    return null
  }
}

export const walletDelete = async (key: string) => {
  try {
    const del = await deleteWalletItem(key)
    return del
  } catch (e) {
    captureError(e)
  }
}

export async function walletUpdate(key: string, data: string) {
  try {
    await updateWalletItem(key, data)
  } catch (err) {
    captureError(err)
    console.log(
      'walletUpdate error :: key: ' + key + ' :: data: ' + data + ' :: err: ',
      err
    )
  }
}

// NON-SECURE STORAGE
export const safeSet = (key: string, data: string) =>
  AsyncStorage.setItem(key, data)

export const safeGet = (key: string) => AsyncStorage.getItem(key)

export const safeDelete = (key: string) => AsyncStorage.removeItem(key)

export const safeMultiRemove = (keys: string[]) =>
  AsyncStorage.multiRemove(keys)

// GET ITEM USED FOR HYDRATION METHODS
export const getHydrationItem = async (key: string) => {
  let inRecovery: string = await safeGet(IN_RECOVERY)

  if (inRecovery === 'true') {
    const walletItem: string | null = await walletGet(key)

    if (walletItem) {
      // put items inside secure storage in background
      // not using await syntax, because we want this in background
      secureSet(key, walletItem)
        .then(noop)
        .catch(noop)
    }

    return walletItem
  } else {
    const secureItem = secureGet(key)

    return secureItem
  }
}


<|start_filename|>connectMeUITest/src/test/java/App1PositiveTest.java<|end_filename|>

package test.java;

import io.appium.java_client.AppiumDriver;
import pageObjects.ChooseLockPage;
import pageObjects.ClaimOfferPage;
import pageObjects.ProofRequestPage;
import org.testng.annotations.*;
import appModules.AppUtlis;
import appModules.ReadMail;
import appModules.RestApi;
import funcModules.AuthRequestModules;
import funcModules.ClaimOfferModules;
import funcModules.ConnectionModules;
import funcModules.LockModules;
import utility.Setup;

public class App1PositiveTest {
	
	AppiumDriver driver;
	public static String pairwiseDID;
	static boolean Success=false;
	AppUtlis appUtlisObj=new AppUtlis();
	LockModules lockModlesObj=new LockModules();
	ConnectionModules connectionModulesObj =new ConnectionModules();
	
	     @BeforeClass
         public void BeforeClass() throws Exception {
	     System.out.println(" Before class of first class");


	}


    @Test (groups = { "Smoke","Regression"})
	public void App0Install() throws Exception {
    	pairwiseDID= appUtlisObj.sendSmsRestApi();
    	Thread.sleep(30000);
    	String InstallConnectMeLink =ReadMail.GetInstallLInk();
    	Thread.sleep(3000);
    	driver = Setup.ConfigureDriver("Safari");
     	connectionModulesObj.InstallApp(driver,InstallConnectMeLink);
		driver.quit();
        AppUtlis.Success=true;
        

    }
    
    @Test (groups = { "Smoke","Regression"})
    public void App1PincodeSetup() throws Exception {
    	
      	Thread.sleep(40000);
		driver = Setup.ConfigureDriver("App");
		System.out.println("pin setup tc");
		ChooseLockPage.PinCodeLock_Button(driver).click();
		lockModlesObj.PinCodeSetup(driver);
		AppUtlis.Success=true;		

	}
    @Test(enabled = true,groups = { "Smoke","Regression"})
	public void App2Provisioning() throws Exception {

		appUtlisObj.CheckSkip();
		Thread.sleep(2000);
		connectionModulesObj.AppProvisioningRequest("Accept",driver);
		AppUtlis.Success=true;

	}

    
    @Test (enabled = true,groups = { "Smoke","Regression"})
   	public void App4ClaimOfferTest() throws Exception {
		
    	appUtlisObj.sendClaimofferRestApi(pairwiseDID);
    	ClaimOfferPage.Accept_Button(driver).click();
   		appUtlisObj.CheckSkip();
   		AppUtlis.Success=true;
   		
   	}
    
    @Test (enabled = true,groups = { "Smoke","Regression"})
   	public void App5ClaimTest() throws Exception {
		
    	appUtlisObj.sendClaimRestApi(pairwiseDID);
    	ClaimOfferPage.Continue_Button(driver).click();
   		appUtlisObj.CheckSkip();
   		AppUtlis.Success=true;
   		
   	}
    
    @Test (enabled = true,groups = { "Smoke","Regression"})
   	public void App5proofRequestTest() throws Exception {
	
    	Thread.sleep(3000);
    	appUtlisObj.sendProofRequestRestApi(pairwiseDID);
    	ProofRequestPage.Send_Button(driver).click();;
    	ProofRequestPage.Continue_Button(driver).click();
   		appUtlisObj.CheckSkip();
   		AppUtlis.Success=true;
   		
   	}
    @Test (groups = { "Smoke","Regression"})
	public void App6PincodeCheck() throws Exception {
	
		driver.quit();
		driver = Setup.ConfigureDriver("App");
	    appUtlisObj.enterPincode(driver);
		AppUtlis.Success=true;

	}

	@AfterClass
	public void AfterClass() {
		
		driver.removeApp("com.evernym.connectme.callcenter");
		driver.quit();
		System.out.println("Cleaning up Completed");

	}
}

<|start_filename|>app/authentication/splash-screen.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { View } from 'react-native'
import { bindActionCreators } from 'redux'
import SplashScreen from 'react-native-splash-screen'
import {
  homeRoute,
  splashScreenRoute,
  expiredTokenRoute,
  lockSelectionRoute,
  lockEnterPinRoute,
  lockEnterFingerprintRoute,
  invitationRoute,
  waitForInvitationRoute,
  eulaRoute,
  restoreRoute,
} from '../common/route-constants'
import { Container, Loader } from '../components'
import {
  TOKEN_EXPIRED_CODE,
  PENDING_CONNECTION_REQUEST_CODE,
} from '../api/api-constants'
import { addPendingRedirection } from '../lock/lock-store'
import {
  getSmsPendingInvitation,
  safeToDownloadSmsInvitation,
} from '../sms-pending-invitation/sms-pending-invitation-store'
import type { SplashScreenProps } from './type-splash-screen'
import type { Store } from '../store/type-store'
import { SMSPendingInvitationStatus } from '../sms-pending-invitation/type-sms-pending-invitation'
import type { SMSPendingInvitations } from '../sms-pending-invitation/type-sms-pending-invitation'
import { deepLinkProcessed } from '../deep-link/deep-link-store'
import { DEEP_LINK_STATUS } from '../deep-link/type-deep-link'

const isReceived = ({ payload, status }) =>
  payload &&
  payload.senderDetail.DID &&
  status === SMSPendingInvitationStatus.RECEIVED

export class SplashScreenView extends PureComponent<SplashScreenProps, void> {
  ifDeepLinkFoundGoToWaitForInvitationScreenNFetchInvitation = (
    prevProps: SplashScreenProps
  ) => {
    const nextDeepLinkTokens = this.props.deepLink.tokens
    if (
      this.props.deepLink.isLoading === false &&
      Object.keys(nextDeepLinkTokens).length >
        Object.keys(prevProps.deepLink.tokens).length
    ) {
      Object.keys(nextDeepLinkTokens).map(
        smsToken =>
          nextDeepLinkTokens[smsToken].status !== DEEP_LINK_STATUS.PROCESSED &&
          this.props.getSmsPendingInvitation(smsToken)
      )
      if (this.props.lock.isAppLocked === false) {
        this.props.navigation.navigate(waitForInvitationRoute)
      }
    }
  }

  getUnHandledSmsPendingInvitations = () => {
    const smsPendingInvitations = Object.keys(
      this.props.smsPendingInvitation
    ).map(invitationToken => {
      return {
        ...this.props.smsPendingInvitation[invitationToken],
        invitationToken,
      }
    })
    const unHandledSmsPendingInvitations: SMSPendingInvitations = smsPendingInvitations.filter(
      ({ invitationToken }) =>
        invitationToken &&
        this.props.deepLink.tokens[invitationToken].status !==
          DEEP_LINK_STATUS.PROCESSED
    )
    return unHandledSmsPendingInvitations
  }

  handleExpiredTokens = (
    unHandledSmsPendingInvitations: SMSPendingInvitations
  ) => {
    const isAnyOneOfSmsPendingInvitationHasError: boolean = unHandledSmsPendingInvitations.some(
      ({ error }) => error
    )
    const isAnyOneOfSmsPendingInvitationWasExpired: boolean = unHandledSmsPendingInvitations.some(
      ({ error }) => error && error.code && error.code === TOKEN_EXPIRED_CODE
    )
    if (isAnyOneOfSmsPendingInvitationWasExpired) {
      // TODO: This conditions pops up too many times, we should create a common function for this.
      // TODO: It should be something like this this.redirect(nextProps.lock, routeName)
      if (this.props.lock.isAppLocked === false) {
        this.props.navigation.navigate(expiredTokenRoute)
      } else {
        this.props.addPendingRedirection([{ routeName: expiredTokenRoute }])
      }
    } else if (isAnyOneOfSmsPendingInvitationHasError) {
      // * This condition is needed to avoid un wanted redirection to home screen if unHandledSmsPendingInvitations are empty
      // * or if we are in middle of other invitation fetching process
      if (this.props.lock.isAppLocked === false) {
        this.props.navigation.navigate(homeRoute)
      } else {
        this.props.addPendingRedirection([{ routeName: homeRoute }])
      }
    }
    unHandledSmsPendingInvitations.map(({ error, invitationToken }) => {
      error ? this.props.deepLinkProcessed(invitationToken) : null
    })
  }

  handleSmsPendingInvitations = (prevProps: SplashScreenProps) => {
    const nextDeepLinkTokens = this.props.deepLink.tokens
    if (
      JSON.stringify(prevProps.smsPendingInvitation) !==
      JSON.stringify(this.props.smsPendingInvitation)
    ) {
      const unHandledSmsPendingInvitations = this.getUnHandledSmsPendingInvitations()
      this.handleExpiredTokens(unHandledSmsPendingInvitations)
      const unseenSmsPendingInvitations = unHandledSmsPendingInvitations.filter(
        isReceived
      )

      const pendingRedirectionList = unseenSmsPendingInvitations.map(
        ({ payload, invitationToken }) => {
          if (payload) {
            const senderDID = payload.senderDetail.DID
            this.props.deepLinkProcessed(invitationToken)
            if (this.props.lock.isAppLocked === false) {
              this.props.navigation.push(invitationRoute, {
                senderDID,
                token: invitationToken,
              })
            }
            return {
              routeName: invitationRoute,
              params: { senderDID, token: invitationToken },
            }
          }
        }
      )

      pendingRedirectionList.length !== 0 &&
        this.props.lock.isAppLocked === true &&
        this.props.addPendingRedirection(pendingRedirectionList)

      // * all error token links should be processed
    }
  }

  componentDidUpdate(prevProps: SplashScreenProps) {
    if (this.props.isInitialized !== prevProps.isInitialized) {
      // hydrated is changed, and if it is changed to true,
      // that means this is the only time we would get inside this if condition
      this.initializationCheck()
    }

    // check if deepLink is changed, then that means we either got token
    // or we got error or nothing happened with deep link
    const nextDeepLinkTokens = this.props.deepLink.tokens
    if (
      prevProps.deepLink.isLoading !== this.props.deepLink.isLoading &&
      this.props.deepLink.isLoading === false &&
      Object.keys(nextDeepLinkTokens).length === 0
    ) {
      if (this.props.lock.isAppLocked === false) {
        // we did not get any token and deepLink data loading is done
        SplashScreen.hide()
        this.props.navigation.navigate(homeRoute)
      } else {
        this.props.addPendingRedirection([{ routeName: homeRoute }])
      }
    }

    this.ifDeepLinkFoundGoToWaitForInvitationScreenNFetchInvitation(prevProps)
    this.handleSmsPendingInvitations(prevProps)
  }

  componentDidMount() {
    // if the SplashScreen component has been mounted for 2 seconds, hide it to render the Loading component
    global.setTimeout(() => {
      SplashScreen.hide()
    }, 2000)
    // It might be the case the hydration finishes
    // even before component is mounted,
    // so we need to check for pin code here as well

    this.initializationCheck()
  }

  initializationCheck() {
    if (this.props.isInitialized) {
      SplashScreen.hide()
      // now we can safely check value of isAlreadyInstalled
      if (
        !this.props.lock.isLockEnabled ||
        this.props.lock.isLockEnabled === 'false'
      ) {
        // user is opening the app for first time after installing
        if (!this.props.eula.isEulaAccept) {
          this.props.navigation.navigate(eulaRoute)
        } else {
          this.props.navigation.navigate(restoreRoute)
        }
      } else {
        // not the first time user is opening app
        if (this.props.lock.isTouchIdEnabled) {
          this.props.navigation.navigate(lockEnterFingerprintRoute)
        } else {
          this.props.navigation.navigate(lockEnterPinRoute)
        }
      }
    }
  }

  // conditional render is to eliminate InteractionManager.allowInteractions issues
  render() {
    return this.props.isInitialized ? null : (
      <Container center>
        <Loader />
      </Container>
    )
  }
}

const mapStateToProps = ({
  config,
  deepLink,
  lock,
  smsPendingInvitation,
  eula,
}: Store) => ({
  isInitialized: config.isInitialized,
  // DeepLink should be it's own component that will handle only deep link logic
  // in that way, we will be able to restrict re-render and re-run of code
  deepLink,
  // only need 3 props
  lock,
  smsPendingInvitation,
  // only need isEulaAccept
  eula,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      getSmsPendingInvitation,
      addPendingRedirection,
      safeToDownloadSmsInvitation,
      deepLinkProcessed,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(SplashScreenView)


<|start_filename|>app/components/keyboard/type-keyboard.js<|end_filename|>
// @flow

export type KeyboardProps = {
  maxLength: number,
  onPress: (text: string, animate: boolean) => void,
  color: string,
  maxValue: string,
  afterDecimalSeparatorMaxLength?: number,
  customKeyboard?: boolean,
  showDecimal?: boolean,
}


<|start_filename|>connectMeUITest/src/pageObjects/ClaimOfferPage.java<|end_filename|>
package pageObjects;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

/**
 * Created by ankurmishra on 6/22/17.
 */
public class ClaimOfferPage {
	
	AppiumDriver driver;

	private static WebElement element = null;

	public static WebElement Accept_Button(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("(//XCUIElementTypeOther[@name='Accept'])[3]"));
			System.out.println("Accept Button is displayed on CLAIM OFFER screen");
			return element;
		} catch (Exception e) {

			System.out.println("ACCEPT Button is not displayed");
			throw (e);
		}
	}
	
	public static WebElement Continue_Button(AppiumDriver driver) throws Exception {

		try {
			element = driver.findElement(By.xpath("//XCUIElementTypeOther[@name='Continue']"));
			System.out.println("Continue Button is displayed on CLAIM OFFER screen");
			return element;
		} catch (Exception e) {

			System.out.println("Continue Button is not displayed");
			throw (e);
		}
	}

}


<|start_filename|>app/settings/settings.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Text, Switch, StyleSheet, Platform, ScrollView } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import BackupWallet from './backup-wallet'
import {
  UserAvatar,
  CustomText,
  Icon,
  Avatar,
  CustomHeader,
} from '../components'
import { CustomList, CustomView, Container } from '../components/layout'
import {
  settingsRoute,
  lockEnterPinRoute,
  lockTouchIdSetupRoute,
  aboutAppRoute,
  privacyTNCRoute,
} from '../common/route-constants'
import AndroidSwitch from 'react-native-flip-toggle-button'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import {
  white,
  mantis,
  OFFSET_1X,
  color,
  grey,
} from '../common/styles/constant'
import {
  EDIT_ICON_DIMENSIONS,
  PASS_CODE_ASTERISK_TOP_OFFSET,
  PASS_CODE_ASTERISK_TEST_ID,
  PASS_CODE_TEST_ID,
  TOUCH_ID_TEST_ID,
  USERNAME_TEST_ID,
  CHAT_TEST_ID,
  USER_AVATAR_TEST_ID,
  BACKUP_DATA_WALLET,
  ABOUT_APP_TEST_ID,
} from './settings-constant'

import type { Store } from '../store/type-store'
import type { SettingsProps, SettingsState } from './type-settings'
import { tertiaryHeaderStyles } from '../components/layout/header-styles'
import type { ImageSource } from '../common/type-common'
import { selectUserAvatar } from '../store/user/user-store'
import { Apptentive } from 'apptentive-react-native'
//import WalletBackupSuccessModal from '../backup/wallet-backup-success-modal'
import AboutApp from '../about-app/about-app'
import PrivacyTNC from '../privacy-tnc/privacy-tnc-screen'
import Banner from '../components/banner/banner'

const style = StyleSheet.create({
  container: {
    overflow: 'scroll',
  },
  editIcon: {
    width: EDIT_ICON_DIMENSIONS,
    height: EDIT_ICON_DIMENSIONS,
  },
  labelImage: {
    marginRight: OFFSET_1X,
  },
  labelPassCode: {
    marginTop: PASS_CODE_ASTERISK_TOP_OFFSET,
  },
})

const SettingText = props => (
  <CustomText h5 bg="fifth" tertiary semiBold {...props}>
    {props.children}
  </CustomText>
)

export class Settings extends PureComponent<SettingsProps, SettingsState> {
  state = {
    walletBackupModalVisible: false,
    disableTouchIdSwitch: false,
  }
  onChangePinClick = () => {
    if (this.props.navigation.isFocused()) {
      this.props.navigation.push(lockEnterPinRoute, {
        existingPin: true,
      })
    }
  }

  onChangeTouchId = (switchState: boolean) => {
    // when the navigation from settings is done by touching the Switch, then the touch id enables with wiered behaviour
    // reason for the behaviour: the onChangeTouchId function is being invoked twice making to navigate twice.
    // solution: the if condition will check for the current state of the switch and compares with the actual state of the switch
    // this confirms to make the onChangeTouchId function to invoke only once at all the times
    if (
      this.props.touchIdActive !== switchState &&
      this.props.navigation.isFocused()
    ) {
      this.props.navigation.push(lockTouchIdSetupRoute, {
        fromSettings: true,
      })
    }
  }

  openAboutApp = () => {
    if (this.props.navigation.isFocused()) {
      this.props.navigation.navigate(aboutAppRoute, {})
    }
  }

  openFeedback = () => {
    Apptentive.presentMessageCenter()
  }

  static navigationOptions = {
    header: (
      <CustomHeader
        backgroundColor={color.bg.tertiary.color}
        largeHeader
        zeroBottomBorder
        centerComponent={
          <CustomText bg="tertiary" tertiary transparentBg semiBold>
            {settingsRoute}
          </CustomText>
        }
      />
    ),
  }

  renderAvatarWithSource = (avatarSource: number | ImageSource) => (
    <Avatar medium round src={avatarSource} />
  )

  hideWalletPopupModal = () => {
    this.setState({
      walletBackupModalVisible: false,
    })
  }

  componentWillReceiveProps(nextProps: SettingsProps) {
    if (
      this.props.currentScreen === nextProps.currentScreen &&
      nextProps.currentScreen === settingsRoute &&
      this.props.timeStamp !== nextProps.timeStamp
    ) {
      this.setState({ disableTouchIdSwitch: false })
    } else if (
      nextProps.currentScreen === lockTouchIdSetupRoute &&
      this.props.currentScreen === settingsRoute
    ) {
      // if user has left settings screen and navigated to lockTouchIdSetup screen
      this.setState({ disableTouchIdSwitch: true })
    }
    if (
      nextProps.walletBackup.status !== this.props.walletBackup.status &&
      nextProps.walletBackup.status === 'SUCCESS'
    ) {
      this.setState({
        walletBackupModalVisible: true,
      })
    }
  }

  render() {
    const userAvatar = (
      <UserAvatar testID={USER_AVATAR_TEST_ID} userCanChange>
        {this.renderAvatarWithSource}
      </UserAvatar>
    )
    const editIcon = (
      <Icon
        iconStyle={[style.editIcon, { tintColor: 'grey' }]}
        resizeMode={'contain'}
        src={require('../images/edit.png')}
        onPress={this.props.selectUserAvatar}
      />
    )

    const editIconChangePin = (
      <Icon
        iconStyle={[style.editIcon, { tintColor: 'grey' }]}
        resizeMode={'contain'}
        src={require('../images/edit.png')}
        onPress={this.onChangePinClick}
      />
    )

    const userName = (
      <SettingText testID={USERNAME_TEST_ID}>Name: Anonymous</SettingText>
    )

    const passCode = (
      <CustomView row>
        <SettingText testID={PASS_CODE_TEST_ID} onPress={this.onChangePinClick}>
          Passcode:{' '}
        </SettingText>
        <SettingText
          onPress={this.onChangePinClick}
          testID={PASS_CODE_ASTERISK_TEST_ID}
          style={[style.labelPassCode]}
        >
          ******
        </SettingText>
      </CustomView>
    )
    const touchId = (
      <CustomView row>
        <Icon
          iconStyle={[style.labelImage, style.editIcon, { tintColor: mantis }]}
          src={require('../images/biometrics.png')}
        />
        <CustomView center>
          <SettingText onPress={this.onChangeTouchId} testID={TOUCH_ID_TEST_ID}>
            Enable Biometrics
          </SettingText>
        </CustomView>
      </CustomView>
    )
    const toggleSwitch =
      Platform.OS === 'ios' ? (
        <Switch
          disabled={this.state.disableTouchIdSwitch}
          onTintColor={mantis}
          onValueChange={this.onChangeTouchId}
          value={this.props.touchIdActive}
        />
      ) : (
        <AndroidSwitch
          onToggle={this.onChangeTouchId}
          value={this.props.touchIdActive}
          buttonWidth={55}
          buttonHeight={30}
          buttonRadius={30}
          sliderWidth={28}
          sliderHeight={28}
          sliderRadius={58}
          buttonOnColor={mantis}
          buttonOffColor={grey}
          sliderOnColor={white}
          sliderOffColor={white}
        />
      )

    const onChat = (
      <CustomView row onPress={this.openFeedback} testID={CHAT_TEST_ID}>
        <Icon
          iconStyle={[style.labelImage, style.editIcon, { tintColor: mantis }]}
          src={require('../images/icon_feedback.png')}
        />
        <CustomView center>
          <SettingText>Chat with us</SettingText>
        </CustomView>
      </CustomView>
    )

    const onAboutApp = (
      <CustomView row onPress={this.openAboutApp} testID={ABOUT_APP_TEST_ID}>
        <Icon
          iconStyle={[style.labelImage, style.editIcon, { tintColor: mantis }]}
          src={require('../images/icon_aboutApp.png')}
        />
        <CustomView center>
          <SettingText>About this App</SettingText>
        </CustomView>
      </CustomView>
    )

    const onBackup = (
      <BackupWallet
        navigation={this.props.navigation}
        render={(status, backupWallet) => (
          <CustomView row onPress={backupWallet} testID={BACKUP_DATA_WALLET}>
            {/* TODO: change out placeholder icon */}
            <Icon
              iconStyle={[
                style.labelImage,
                style.editIcon,
                { tintColor: mantis },
              ]}
              src={require('../images/icon_backup.png')}
            />
            <CustomView center>
              <SettingText>Back up my wallet</SettingText>
            </CustomView>
          </CustomView>
        )}
      />
    )

    const itemList = [
      {
        id: 0,
        left: userAvatar,
        right: editIcon,
      },
      // We don't need Name option for now, will add it later when story comes up
      // {
      //   id: 1,
      //   left: userName,
      //   right: editIcon,
      // },
      {
        id: 2,
        left: passCode,
        right: editIconChangePin,
      },
      {
        id: 3,
        left: touchId,
        right: toggleSwitch,
      },
      {
        id: 4,
        left: onAboutApp,
      },
      {
        id: 5,
        left: onChat,
      },
      {
        id: 6,
        left: onBackup,
      },
    ]

    return (
      <Container tertiary>
        <CustomView style={[style.container]}>
          <Banner navigation={this.props.navigation} />
          <ScrollView>
            <CustomList data={itemList} />
          </ScrollView>
        </CustomView>
      </Container>
    )
  }
}

const mapStateToProps = (state: Store) => ({
  touchIdActive: state.lock.isTouchIdEnabled,
  walletBackup: state.wallet.backup,
  currentScreen: state.route.currentScreen,
  timeStamp: state.route.timeStamp,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators({ selectUserAvatar }, dispatch)

export const SettingStack = createStackNavigator({
  [settingsRoute]: {
    screen: connect(mapStateToProps, mapDispatchToProps)(Settings),
  },
  [aboutAppRoute]: {
    screen: AboutApp,
  },
  [privacyTNCRoute]: {
    screen: PrivacyTNC,
  },
})

SettingStack.navigationOptions = ({ navigation }) => {
  let tabBarVisible = true
  let swipeEnabled = true
  if (navigation.state.index > 0) {
    tabBarVisible = false
    swipeEnabled = false
  }
  return {
    tabBarVisible,
    swipeEnabled,
  }
}

export default SettingStack


<|start_filename|>app/lock/lock-selection.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import {
  Image,
  View,
  StyleSheet,
  TouchableHighlight,
  Alert,
  Keyboard,
} from 'react-native'
import { connect } from 'react-redux'
import { select } from 'redux-saga/effects'
import { bindActionCreators } from 'redux'
import type { Store } from '../store/type-store'
import { Container, CustomText, CustomView } from '../components'
import {
  lockPinSetupRoute,
  lockTouchIdSetupRoute,
  switchEnvironmentRoute,
} from '../common/'
import type { LockSelectionProps } from './type-lock'
import {
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_5X,
  OFFSET_6X,
  OFFSET_7X,
  color,
  isiPhone5,
  PIN_CODE_BORDER_BOTTOM,
} from '../common/styles/constant'
import { switchErrorAlerts } from '../store/config-store'
import {
  disableDevMode,
  longPressedInLockSelectionScreen,
  pressedOnOrInLockSelectionScreen,
} from './lock-store'
import { safeToDownloadSmsInvitation } from '../sms-pending-invitation/sms-pending-invitation-store'

export class LockSelection extends PureComponent<LockSelectionProps, void> {
  constructor(props: LockSelectionProps) {
    super(props)
    Keyboard.dismiss()
  }

  goTouchIdSetup = () => {
    if (this.props.navigation.isFocused()) {
      this.props.navigation.navigate(lockTouchIdSetupRoute)
      this.props.safeToDownloadSmsInvitation()
    }
  }

  goPinCodeSetup = () => {
    this.props.navigation.navigate(lockPinSetupRoute)
    this.props.safeToDownloadSmsInvitation()
  }

  _onLongPressButton = () => {
    this.props.longPressedInLockSelectionScreen()
  }

  _onTextPressButton = () => {
    this.props.pressedOnOrInLockSelectionScreen()
  }

  componentWillReceiveProps(nextProps: LockSelectionProps) {
    if (nextProps.showDevMode) {
      Alert.alert(
        'Developer Mode',
        'you are enabling developer mode and it will delete all existing data. Are you sure?',
        [
          {
            text: 'Cancel',
            style: 'cancel',
            onPress: () => nextProps.disableDevMode(),
          },
          {
            text: 'OK',
            onPress: () =>
              nextProps.navigation.navigate(switchEnvironmentRoute),
          },
        ]
      )
    }
  }

  render() {
    return (
      <Container tertiary style={[style.pinSelectionContainer]}>
        <CustomView
          onPress={this.props.switchErrorAlerts}
          onLongPress={this._onLongPressButton}
        >
          <CustomText h5 bg="tertiary" tertiary semiBold center>
            Choose how to unlock App
          </CustomText>
        </CustomView>
        <CustomView style={[style.messageText]}>
          <CustomText h5 bg="tertiary" tertiary bold center>
            This application must be protected by Biometrics or a passcode at
            all times.
          </CustomText>
        </CustomView>
        <Container spaceAround>
          <CustomView
            center
            fifth
            shadow
            testID="touch-id-selection"
            style={[style.touchIdPinContainer]}
            onPress={this.goTouchIdSetup}
            onLongPress={this._onLongPressButton}
          >
            <Image
              style={style.fingerPrintIcon}
              source={require('../images/icon_fingerPrint.png')}
            />
            <CustomText
              h5
              semiBold
              center
              tertiary
              transparentBg
              testID="use-touch-id-text"
              onPress={this.goTouchIdSetup}
              onLongPress={this._onLongPressButton}
            >
              Use Biometrics
            </CustomText>
          </CustomView>
          <CustomView
            testID="lock-selection-or-text"
            onLongPress={this._onLongPressButton}
            onPress={this._onTextPressButton}
            debounceAction={false}
          >
            <CustomText h4 bg="tertiary" tertiary transparentBg thick center>
              or
            </CustomText>
          </CustomView>
          <CustomView
            fifth
            shadow
            testID="pin-code-selection"
            style={[style.touchIdPinContainer]}
            onPress={this.goPinCodeSetup}
            onLongPress={this._onLongPressButton}
          >
            <CustomView row center style={[style.pinContainer]}>
              <CustomView style={[style.pin]}>
                <CustomText h4 thick center bg="fifth">
                  1
                </CustomText>
              </CustomView>
              <CustomView style={[style.pin]}>
                <CustomText h4 thick center bg="fifth">
                  2
                </CustomText>
              </CustomView>
              <CustomView style={[style.pin]}>
                <CustomText h4 thick center bg="fifth">
                  3
                </CustomText>
              </CustomView>
              <CustomView style={[style.pin]}>
                <CustomText h4 thick center bg="fifth">
                  4
                </CustomText>
              </CustomView>
              <CustomView style={[style.pin]}>
                <CustomText h4 thick center bg="fifth">
                  5
                </CustomText>
              </CustomView>
              <CustomView style={[style.pin]}>
                <CustomText h4 thick center bg="fifth">
                  6
                </CustomText>
              </CustomView>
            </CustomView>
            <CustomText
              h5
              semiBold
              center
              tertiary
              transparentBg
              style={[style.usePinText]}
              onPress={this.goPinCodeSetup}
              testID="use-pass-code-text"
              onLongPress={this._onLongPressButton}
            >
              Use Passcode
            </CustomText>
          </CustomView>
        </Container>
      </Container>
    )
  }
}

const mapStateToProps = ({ lock }: Store) => {
  return {
    showDevMode: lock.showDevMode,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      switchErrorAlerts,
      longPressedInLockSelectionScreen,
      pressedOnOrInLockSelectionScreen,
      disableDevMode,
      safeToDownloadSmsInvitation,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(LockSelection)

const style = StyleSheet.create({
  pinSelectionContainer: {
    paddingTop: OFFSET_3X,
    paddingBottom: isiPhone5 ? OFFSET_2X : OFFSET_6X,
    paddingHorizontal: OFFSET_2X,
  },
  messageText: {
    paddingHorizontal: isiPhone5 ? 0 : OFFSET_5X / 2,
    paddingTop: isiPhone5 ? OFFSET_5X / 2 : OFFSET_5X,
    paddingBottom: isiPhone5 ? OFFSET_3X / 2 : OFFSET_7X / 2,
  },
  touchIdPinContainer: {
    paddingTop: OFFSET_1X / 2,
    paddingHorizontal: OFFSET_2X,
    paddingBottom: OFFSET_2X,
    borderRadius: 13,
    marginHorizontal: OFFSET_3X,
  },
  fingerPrintIcon: {
    marginVertical: OFFSET_3X / 2,
    height: 60,
    width: 60,
  },
  pinContainer: {
    marginVertical: OFFSET_3X,
    marginBottom: OFFSET_5X / 2,
  },
  pin: {
    borderBottomColor: color.bg.fifth.font.primary,
    borderBottomWidth: PIN_CODE_BORDER_BOTTOM,
    marginRight: OFFSET_1X / 2,
    paddingHorizontal: OFFSET_1X / 2,
    paddingBottom: OFFSET_1X,
  },
  usePinText: {
    lineHeight: 22,
    paddingBottom: OFFSET_1X / 2,
  },
})


<|start_filename|>app/push-notification/push-notification-store.js<|end_filename|>
// @flow
import { Platform } from 'react-native'
import {
  call,
  all,
  takeLatest,
  takeEvery,
  take,
  select,
  put,
  fork,
} from 'redux-saga/effects'
import { PAYLOAD_TYPE, MESSAGE_TYPE } from '../api/api-constants'
import { captureError } from '../services/error/error-handler'
import {
  getAgencyUrl,
  getAllConnection,
  getRemotePairwiseDidAndName,
  getUserOneTimeInfo,
  getAgencyVerificationKey,
  getHydrationState,
  getPoolConfig,
  getInvitations,
  getDeepLinkTokens,
  getPendingFetchAdditionalDataKey,
  getIsAppLocked,
  getSerializedClaimOffer,
  getCurrentScreen,
} from '../store/store-selector'
import {
  PUSH_NOTIFICATION_PERMISSION,
  PUSH_NOTIFICATION_UPDATE_TOKEN,
  PUSH_NOTIFICATION_RECEIVED,
  FETCH_ADDITIONAL_DATA,
  FETCH_ADDITIONAL_DATA_ERROR,
  HYDRATE_PUSH_TOKEN,
  FETCH_ADDITIONAL_DATA_PENDING_KEYS,
  UPDATE_RELEVANT_PUSH_PAYLOAD_STORE_AND_REDIRECT,
  UPDATE_RELEVANT_PUSH_PAYLOAD_STORE,
} from './type-push-notification'

import type {
  CustomError,
  NotificationPayload,
  ReactNavigation,
} from '../common/type-common'
import type {
  AdditionalDataPayload,
  PushNotificationPermissionAction,
  PushNotificationUpdateTokenAction,
  PushNotificationReceivedAction,
  FetchAdditionalDataAction,
  AdditionalDataResponse,
  PushNotificationAction,
  PushNotificationStore,
  DownloadedNotification,
  ClaimOfferPushPayload,
  ClaimPushPayload,
  HydratePushTokenAction,
  updatePayloadToRelevantStoreAndRedirectAction,
  RedirectToRelevantScreen,
} from './type-push-notification'
import type { Connections } from '../connection/type-connection'
import type { UserOneTimeInfo } from '../store/user/type-user-store'
import {
  updatePushTokenVcx,
  downloadClaimOffer,
  downloadProofRequest,
  getHandleBySerializedConnection,
  serializeClaimOffer,
} from '../bridge/react-native-cxs/RNCxs'
import { HYDRATED, VCX_INIT_SUCCESS } from '../store/type-config-store'
import { CONNECT_REGISTER_CREATE_AGENT_DONE } from '../store/user/type-user-store'
import uniqueId from 'react-native-unique-id'
import { RESET } from '../common/type-common'
import { ensureVcxInitSuccess } from '../store/config-store'
import type { Connection } from '../store/type-connection-store'
import type { CxsCredentialOfferResult } from '../bridge/react-native-cxs/type-cxs'
import type {
  ProofRequestPushPayload,
  AdditionalProofDataPayload,
} from '../proof-request/type-proof-request'
import { saveSerializedClaimOffer } from '../claim-offer/claim-offer-store'
import type { ClaimPushPayloadVcx } from '../claim/type-claim'
import { safeGet, safeSet } from '../services/storage'
import { PUSH_COM_METHOD } from '../common'
import type { NavigationParams, GenericObject } from '../common/type-common'

import { addPendingRedirection } from '../lock/lock-store'
import { authenticationRequestReceived } from '../authentication/authentication-store'
import { claimOfferReceived } from '../claim-offer/claim-offer-store'
import { proofRequestReceived } from '../proof-request/proof-request-store'
import { updateMessageStatus } from '../store/config-store'
import {
  claimOfferRoute,
  invitationRoute,
  proofRequestRoute,
  qrCodeScannerTabRoute,
  homeTabRoute,
  lockPinSetupRoute,
  lockTouchIdSetupRoute,
  lockPinSetupHomeRoute,
  lockEnterPinRoute,
  lockEnterFingerprintRoute,
  lockAuthorizationRoute,
  lockAuthorizationHomeRoute,
} from '../common'
import type { Claim } from '../claim/type-claim'
import { claimReceivedVcx } from '../claim/claim-store'
import { NavigationActions } from 'react-navigation'
import type { SerializedClaimOffer } from './../claim-offer/type-claim-offer'

async function delay(ms): Promise<number> {
  return new Promise(res => setTimeout(res, ms))
}

const blackListedRoute = {
  [proofRequestRoute]: proofRequestRoute,
  [claimOfferRoute]: claimOfferRoute,
  [lockPinSetupRoute]: lockPinSetupRoute,
  [lockTouchIdSetupRoute]: lockTouchIdSetupRoute,
  [lockPinSetupHomeRoute]: lockPinSetupHomeRoute,
  [lockEnterPinRoute]: lockEnterPinRoute,
  [lockEnterFingerprintRoute]: lockEnterFingerprintRoute,
  [lockAuthorizationRoute]: lockAuthorizationRoute,
  [lockAuthorizationHomeRoute]: lockAuthorizationHomeRoute,
  [invitationRoute]: invitationRoute,
}

const initialState = {
  isAllowed: false,
  notification: null,
  pushToken: null,
  isPristine: true,
  isFetching: false,
  error: null,
  pendingFetchAdditionalDataKey: null,
  navigateRoute: null,
}

export const pushNotificationPermissionAction = (isAllowed: boolean) => ({
  type: PUSH_NOTIFICATION_PERMISSION,
  isAllowed,
})

export const updatePushToken = (token: string) => ({
  type: PUSH_NOTIFICATION_UPDATE_TOKEN,
  token,
})

export function* onPushTokenUpdate(
  action: PushNotificationUpdateTokenAction
): Generator<*, *, *> {
  try {
    const pushToken = `FCM:${action.token}`
    const id = yield uniqueId()
    const vcxResult = yield* ensureVcxInitSuccess()
    if (vcxResult && vcxResult.fail) {
      yield take(VCX_INIT_SUCCESS)
    }
    yield call(updatePushTokenVcx, { uniqueId: id, pushToken })
    yield* savePushTokenSaga(pushToken)
  } catch (e) {
    captureError(e)
  }
}

export function convertClaimOfferPushPayloadToAppClaimOffer(
  pushPayload: ClaimOfferPushPayload
): AdditionalDataPayload {
  /**
   * Below expression Converts this format
   * {
   *  name: ["Test"],
   *  height: ["170"]
   * }
   * TO
   * [
   *  {label: "name", data: "Test"},
   *  {label: "height", data: "170"},
   * ]
   */
  const revealedAttributes = Object.keys(pushPayload.claim).map(
    attributeName => ({
      label: attributeName,
      data: pushPayload.claim[attributeName][0],
    })
  )

  return {
    issuer: {
      name: pushPayload.issuer_name || pushPayload.remoteName,
      did: pushPayload.issuer_did,
    },
    data: {
      name: pushPayload.claim_name,
      version: pushPayload.version,
      revealedAttributes,
      claimDefinitionSchemaSequenceNumber: pushPayload.schema_seq_no,
    },
    payTokenValue: pushPayload.price,
  }
}

export function convertProofRequestPushPayloadToAppProofRequest(
  pushPayload: ProofRequestPushPayload
): AdditionalProofDataPayload {
  const { proof_request_data, remoteName, proofHandle } = pushPayload
  const { requested_attributes, name, version } = proof_request_data

  const requestedAttributes = Object.keys(requested_attributes).map(
    attributeKey => ({
      label: requested_attributes[attributeKey].name,
    })
  )

  return {
    data: {
      name,
      version,
      requestedAttributes,
    },
    requester: {
      name: remoteName,
    },
    originalProofRequestData: proof_request_data,
    proofHandle,
  }
}

export function convertClaimPushPayloadToAppClaim(
  pushPayload: ClaimPushPayload,
  uid: string,
  forDID: string
): Claim {
  return {
    ...pushPayload,
    messageId: pushPayload.claim_offer_id,
    remoteDid: pushPayload.from_did,
    uid,
    forDID,
  }
}

function* watchPushTokenUpdate(): any {
  yield takeLatest(PUSH_NOTIFICATION_UPDATE_TOKEN, onPushTokenUpdate)
}

export const pushNotificationReceived = (
  notification: DownloadedNotification
) => ({
  type: PUSH_NOTIFICATION_RECEIVED,
  notification,
})

export const fetchAdditionalData = (
  notificationPayload: NotificationPayload
) => ({
  type: FETCH_ADDITIONAL_DATA,
  notificationPayload,
})

export const fetchAdditionalDataError = (error: CustomError) => ({
  type: FETCH_ADDITIONAL_DATA_ERROR,
  error,
})

export const setFetchAdditionalDataPendingKeys = (
  uid: string,
  forDID: string
) => ({
  type: FETCH_ADDITIONAL_DATA_PENDING_KEYS,
  uid,
  forDID,
})

export function* fetchAdditionalDataSaga(
  action: FetchAdditionalDataAction
): Generator<*, *, *> {
  const { forDID, uid, type, senderLogoUrl } = action.notificationPayload
  if (forDID && uid) {
    const fetchDataAlreadyExists = yield select(
      getPendingFetchAdditionalDataKey
    )
    if (fetchDataAlreadyExists && fetchDataAlreadyExists[`${uid}-${forDID}`]) {
      return
    }
    yield put(setFetchAdditionalDataPendingKeys(uid, forDID))
  }

  const vcxResult = yield* ensureVcxInitSuccess()
  if (vcxResult && vcxResult.fail) {
    yield take(VCX_INIT_SUCCESS)
  }

  if (!forDID) {
    yield put(
      fetchAdditionalDataError({
        code: 'OCS-001',
        message: 'Missing forDID in notification payload',
      })
    )
    return
  }

  const {
    remotePairwiseDID,
    remoteName,
    ...connection
  }: {
    remotePairwiseDID: string,
    remoteName: string,
  } & Connection = yield select(getRemotePairwiseDidAndName, forDID)

  if (!remotePairwiseDID || !connection.vcxSerializedConnection) {
    yield put(
      fetchAdditionalDataError({
        code: 'OCS-002',
        message: 'No pairwise connection found',
      })
    )

    return
  }

  const connectionHandle = yield call(
    getHandleBySerializedConnection,
    connection.vcxSerializedConnection
  )

  try {
    let additionalData:
      | ClaimOfferPushPayload
      | ProofRequestPushPayload
      | ClaimPushPayload
      | ClaimPushPayloadVcx
      | null = null

    if (type === MESSAGE_TYPE.CLAIM_OFFER) {
      const vcxSerializedClaimOffer: SerializedClaimOffer | null = yield select(
        getSerializedClaimOffer,
        forDID,
        uid
      )
      if (!vcxSerializedClaimOffer) {
        const {
          claimHandle,
          claimOffer,
        }: CxsCredentialOfferResult = yield call(
          downloadClaimOffer,
          connectionHandle,
          uid,
          uid
        )
        additionalData = claimOffer
        yield fork(saveSerializedClaimOffer, claimHandle, forDID, uid)
      }
    }

    if (type === MESSAGE_TYPE.CLAIM) {
      // as per vcx apis we are not downloading claim
      // we will update state of existing claim offer instance
      // and vcx will internally download claim and store inside wallet
      additionalData = {
        connectionHandle,
      }
    }

    if (type === MESSAGE_TYPE.PROOF_REQUEST) {
      additionalData = yield call(
        downloadProofRequest,
        uid,
        connectionHandle,
        uid
      )
    }

    if (!additionalData) {
      // we did not get any data or either push notification type is not supported
      return
    }

    yield put(
      pushNotificationReceived({
        type,
        additionalData: {
          ...additionalData,
          remoteName,
        },
        uid,
        senderLogoUrl,
        remotePairwiseDID,
        forDID,
      })
    )
  } catch (e) {
    captureError(e)
    yield put(
      fetchAdditionalDataError({
        code: 'OCS-000',
        message: 'Invalid additional data',
      })
    )
  }
}

export const updatePayloadToRelevantStoreAndRedirect = (
  notification: DownloadedNotification
) => ({
  type: UPDATE_RELEVANT_PUSH_PAYLOAD_STORE_AND_REDIRECT,
  notification,
})

export const updatePayloadToRelevantStore = (
  notification: DownloadedNotification
) => ({
  type: UPDATE_RELEVANT_PUSH_PAYLOAD_STORE,
  notification,
})

export const goToUIScreen = (
  uiType: string,
  uid: string,
  navigation: $PropertyType<ReactNavigation, 'navigation'>
) => ({
  type: 'GO_TO_UI_SCREEN',
  uiType,
  uid,
  navigation,
})

function* watchUpdateRelevantPushPayloadStoreAndRedirect(): any {
  yield takeEvery(UPDATE_RELEVANT_PUSH_PAYLOAD_STORE_AND_REDIRECT, function*({
    notification,
  }: updatePayloadToRelevantStoreAndRedirectAction) {
    yield* updatePayloadToRelevantStoreSaga(notification)
    yield* redirectToRelevantScreen({ ...notification, uiType: null })
    const { forDID: pairwiseDID, uid } = notification
    if (notification.type === MESSAGE_TYPE.PROOF_REQUEST) {
      yield* updateMessageStatus([{ pairwiseDID, uids: [uid] }])
    }
  })
}

export function* watchGoToUIScreen(): any {
  yield takeEvery('GO_TO_UI_SCREEN', redirectToRelevantScreen)
}

export function* updatePayloadToRelevantStoreSaga(
  message: DownloadedNotification
): Generator<*, *, *> {
  const {
    type,
    additionalData,
    uid,
    senderLogoUrl,
    remotePairwiseDID,
    forDID,
  } = message
  if (type) {
    switch (type) {
      case MESSAGE_TYPE.CLAIM_OFFER:
        yield put(
          claimOfferReceived(
            convertClaimOfferPushPayloadToAppClaimOffer(additionalData),
            {
              uid,
              senderLogoUrl,
              remotePairwiseDID,
            }
          )
        )

        break
      case MESSAGE_TYPE.PROOF_REQUEST:
        yield put(
          proofRequestReceived(
            convertProofRequestPushPayloadToAppProofRequest(additionalData),
            {
              uid,
              senderLogoUrl,
              remotePairwiseDID,
            }
          )
        )
        break
      case MESSAGE_TYPE.CLAIM:
        yield put(
          claimReceivedVcx({
            connectionHandle: additionalData.connectionHandle,
            uid,
            type,
            forDID,
            remotePairwiseDID,
          })
        )
        break
    }
  }
}

function* redirectToRelevantScreen({
  uiType,
  type,
  uid,
}: RedirectToRelevantScreen) {
  const currentScreen: string = yield select(getCurrentScreen)
  if (uiType || type)
    if (!blackListedRoute[currentScreen])
      switch (uiType || type) {
        case 'CLAIM_OFFER_RECEIVED':
          //TODO fix the scenario where claim-offer is not added to pending redirection when app is unlocked
          //Redirect to claimOffer after 1 sec because after unlocking the app
          //it redirects to home screen
          //If we don't wait and redirect to claimOffer immediately , then
          //sometimes claim offer screen disappears as home screen redirection will happen
          //after it
          // yield call(delay, 1000)
          yield call(delay, 1000)

          yield handleRedirection(claimOfferRoute, {
            uid,
          })

          break

        case MESSAGE_TYPE.CLAIM_OFFER:
          yield call(delay, 1000)
          yield handleRedirection(claimOfferRoute, {
            uid,
          })

          break

        case MESSAGE_TYPE.PROOF_REQUEST:
          yield handleRedirection(proofRequestRoute, {
            uid,
          })
          break

        case 'PROOF_REQUEST_RECEIVED':
          yield handleRedirection(proofRequestRoute, {
            uid,
          })
          break
      }
}

function* handleRedirection(routeName: string, params: NavigationParams): any {
  const isAppLocked = yield select(getIsAppLocked)
  if (isAppLocked)
    yield put(
      addPendingRedirection([
        { routeName: homeTabRoute },
        { routeName, params },
      ])
    )
  else yield put(navigateToRoutePN(routeName, params))
}

export const navigateToRoutePN = (
  routeName: string,
  params: GenericObject
) => ({
  type: 'NAVIGATE_TO_ROUTE',
  routeName,
  params,
})

export const clearNavigateToRoutePN = () => ({
  type: 'CLEAR_NAVIGATE_TO_ROUTE',
})

function* watchFetchAdditionalData(): any {
  yield takeEvery(FETCH_ADDITIONAL_DATA, fetchAdditionalDataSaga)
}

export const hydratePushToken = (token: string): HydratePushTokenAction => ({
  type: HYDRATE_PUSH_TOKEN,
  token,
})

export function* hydratePushTokenSaga(): Generator<*, *, *> {
  try {
    const token = yield call(safeGet, PUSH_COM_METHOD)
    if (token) {
      yield put(hydratePushToken(token))
    }
  } catch (e) {
    // capture error for safe get
    captureError(e)
    console.error(`hydratePushTokenSaga: ${e}`)
  }
}

export function* savePushTokenSaga(pushToken: string): Generator<*, *, *> {
  try {
    yield call(safeSet, PUSH_COM_METHOD, pushToken)
  } catch (e) {
    // Need to figure out what should be done if storage fails
    console.error(`savePushTokenSaga: ${e}`)
  }
}

export function* watchPushNotification(): any {
  yield all([
    watchPushTokenUpdate(),
    watchFetchAdditionalData(),
    watchGoToUIScreen(),
    watchUpdateRelevantPushPayloadStoreAndRedirect(),
  ])
}

export default function pushNotification(
  state: PushNotificationStore = initialState,
  action: PushNotificationAction
) {
  switch (action.type) {
    case PUSH_NOTIFICATION_PERMISSION:
      return {
        ...state,
        isAllowed: action.isAllowed,
      }
    case HYDRATE_PUSH_TOKEN:
    case PUSH_NOTIFICATION_UPDATE_TOKEN:
      return {
        ...state,
        pushToken: action.token,
        isAllowed: true,
      }
    case FETCH_ADDITIONAL_DATA:
      return {
        ...state,
        isPristine: false,
        isFetching: true,
      }
    case FETCH_ADDITIONAL_DATA_ERROR:
      return {
        ...state,
        isPristine: false,
        isFetching: false,
        error: action.error,
      }
    case PUSH_NOTIFICATION_RECEIVED:
      return {
        ...state,
        notification: action.notification,
      }
    case FETCH_ADDITIONAL_DATA_PENDING_KEYS:
      return {
        ...state,
        pendingFetchAdditionalDataKey: {
          ...state.pendingFetchAdditionalDataKey,
          [`${action.uid}-${action.forDID}`]: true,
        },
      }
    case RESET:
      return {
        ...state,
        notification: null,
        error: null,
      }
    case 'NAVIGATE_TO_ROUTE':
      return {
        ...state,
        navigateRoute: {
          routeName: action.routeName,
          params: action.params,
        },
      }
    case 'CLEAR_NAVIGATE_TO_ROUTE':
      return {
        ...state,
        navigateRoute: null,
      }
    default:
      return state
  }
}


<|start_filename|>app/components/loader/__tests__/loading-indicator.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import LoadingIndicator from '../loading-indicator'

describe('<LoadingIndicator />', () => {
  it('should render properly and match the snapshot', () => {
    const component = renderer.create(<LoadingIndicator size={30} />)
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/claim-offer/claim-offer.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import {
  StyleSheet,
  Platform,
  FlatList,
  View,
  StatusBar,
  Alert,
} from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import {
  claimOfferShown,
  acceptClaimOffer,
  claimOfferRejected,
  claimOfferIgnored,
  claimOfferShowStart,
  resetClaimRequestStatus,
} from './claim-offer-store'
import {
  Container,
  CustomView,
  CustomButton,
  CustomText,
  Icon,
  ConnectionTheme,
  ClaimProofHeader,
  Separator,
  FooterActions,
  CustomSafeAreaView,
  headerStyles,
} from '../components'
import { homeRoute } from '../common/'
import {
  OFFSET_2X,
  OFFSET_1X,
  color,
  OFFSET_3X,
  OFFSET_5X,
} from '../common/styles'
import type {
  AdditionalDataPayload,
  Attribute,
} from '../push-notification/type-push-notification'
import type {
  ClaimOfferProps,
  ClaimOfferPayload,
  ClaimOfferAttributeListProps,
  ClaimOfferState,
} from './type-claim-offer'
import {
  CLAIM_REQUEST_STATUS,
  CREDENTIAL_OFFER_MODAL_STATUS,
} from './type-claim-offer'
import type { Store } from '../store/type-store'
import { ClaimRequestStatusModal } from './claim-request-modal'
import {
  getConnectionLogoUrl,
  getConnectionTheme,
} from '../store/store-selector'

import type { ReactNavigation } from '../common/type-common'
import { updateStatusBarTheme } from '../../app/store/connections-store'
import { CustomModal } from '../components'
import PaymentFailureModal from '../wallet/payment-failure-modal'
import CredentialOfferModal from '../wallet/credential-offer-modal'
import { getStatusBarStyle } from '../components/custom-header/custom-header'
import {
  LedgerFeesModalStatus,
  LedgerFeesDescriptionText,
} from '../components/ledger-fees-modal/ledger-fees-modal'
import { BigNumber } from 'bignumber.js'

class ClaimOfferAttributeList extends PureComponent<
  ClaimOfferAttributeListProps,
  void
> {
  keyExtractor = ({ label }: Attribute, index: number) => `${label}${index}`

  renderItem = ({ item }: { item: Attribute }) => {
    return (
      <CustomView fifth row horizontalSpace doubleVerticalSpace>
        <CustomView fifth right style={[styles.attributeListLabel]}>
          <CustomText
            h7
            uppercase
            semiBold
            bg="tertiary"
            transparentBg
            style={[styles.attributeListLabelText]}
          >
            {item.label}
          </CustomText>
        </CustomView>
        <CustomView fifth left style={[styles.attributeListValue]}>
          <CustomText h6 demiBold bg="tertiary" transparentBg>
            {item.data}
          </CustomText>
        </CustomView>
      </CustomView>
    )
  }

  render() {
    const attributes: Array<Attribute> = this.props.list
    return (
      <Container fifth style={[styles.claimOfferData]}>
        <FlatList
          data={attributes}
          keyExtractor={this.keyExtractor}
          ItemSeparatorComponent={Separator}
          ListFooterComponent={Separator}
          renderItem={this.renderItem}
        />
      </Container>
    )
  }
}

export class ClaimOffer extends PureComponent<
  ClaimOfferProps,
  ClaimOfferState
> {
  constructor(props: ClaimOfferProps) {
    super(props)
    if (props.navigation.state) {
      props.claimOfferShowStart(props.navigation.state.params.uid)
    }
  }

  state = {
    disableAcceptButton: false,
    credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.NONE,
  }

  close = () => {
    this.setState({
      credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.NONE,
    })
    this.props.navigation.goBack()
  }

  hideInsufficientBalanceModal = () => {
    // the reason why we can't just use close method is our CustomModal
    // somehow on some Android devices, if we open claim offer screen again
    // modal component flashes for a second and then goes away
    // however, props to the component are updated ones and does not satisfy
    // condition to show modal, but Modal still shows up
    // We have tried using this format as well isValid ? <Modal /> : null
    // However, in this format, Modal freezes the screen with Modal's background
    // and user can't tap anywhere on screen and app seems to be frozen
    // then only workaround is to kill the app and run again
    // So we can't go back to ternary based null rendering as well
    this.props.resetClaimRequestStatus(this.props.uid)
  }

  onIgnore = () => {
    this.props.claimOfferIgnored(this.props.uid)
    this.close()
  }

  onReject = () => {
    this.props.claimOfferRejected(this.props.uid)
    this.close()
  }

  onProceedPaidCredTransaction = () => {
    this.setState({
      credentialOfferModalStatus:
        CREDENTIAL_OFFER_MODAL_STATUS.CREDENTIAL_REQUEST_STATUS,
    })
    this.props.acceptClaimOffer(this.props.uid)
  }

  onRejectPaidCredTransaction = () => {
    this.setState({
      credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.NONE,
      disableAcceptButton: false,
    })
  }

  onAccept = () => {
    this.setState({
      disableAcceptButton: true,
    })
    if (this.props.claimOfferData.payTokenValue) {
      this.setState({
        credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.LEDGER_FEES,
      })
    } else {
      this.setState({
        credentialOfferModalStatus:
          CREDENTIAL_OFFER_MODAL_STATUS.CREDENTIAL_REQUEST_STATUS,
      })
      this.props.acceptClaimOffer(this.props.uid)
    }
  }

  componentDidMount() {
    // update store that offer is shown to user
    this.props.claimOfferShown(this.props.uid)
    this.props.updateStatusBarTheme(this.props.claimThemePrimary)
  }

  onCredentialOfferModalHide = () => {
    const { claimOfferData } = this.props
    const { claimRequestStatus }: ClaimOfferPayload = claimOfferData
    if (
      claimRequestStatus === CLAIM_REQUEST_STATUS.INSUFFICIENT_BALANCE &&
      this.state.credentialOfferModalStatus !==
        CREDENTIAL_OFFER_MODAL_STATUS.INSUFFICIENT_BALANCE
    ) {
      this.setState({
        credentialOfferModalStatus:
          CREDENTIAL_OFFER_MODAL_STATUS.INSUFFICIENT_BALANCE,
      })
    } else if (
      claimRequestStatus === CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_FAIL ||
      claimRequestStatus === CLAIM_REQUEST_STATUS.CLAIM_REQUEST_FAIL
    ) {
      if (this.state.disableAcceptButton === true) {
        this.setState({
          disableAcceptButton: false,
          credentialOfferModalStatus:
            CREDENTIAL_OFFER_MODAL_STATUS.CREDENTIAL_REQUEST_FAIL,
        })
      }
    } else if (
      claimRequestStatus ===
        CLAIM_REQUEST_STATUS.PAID_CREDENTIAL_REQUEST_FAIL &&
      this.state.credentialOfferModalStatus !==
        CREDENTIAL_OFFER_MODAL_STATUS.SEND_PAID_CREDENTIAL_REQUEST_FAIL
    ) {
      this.setState({
        credentialOfferModalStatus:
          CREDENTIAL_OFFER_MODAL_STATUS.SEND_PAID_CREDENTIAL_REQUEST_FAIL,
      })
    } else if (
      claimRequestStatus === CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_SUCCESS &&
      this.state.credentialOfferModalStatus !==
        CREDENTIAL_OFFER_MODAL_STATUS.NONE
    ) {
      this.close()
    }
  }

  renderFeesText = (fees: string, status: string) => {
    const credentialFees = this.props.claimOfferData.payTokenValue
    if (!credentialFees) {
      // if not paid credential, we don't want to render any text
      return null
    }

    const credentialFeesAmount = new BigNumber(credentialFees)
    const transferFeesAmount = new BigNumber(fees)
    const totalSpend = credentialFeesAmount
      .plus(transferFeesAmount)
      .toFixed()
      .toString()

    switch (status) {
      // this component will show it's own text only in case of following statues
      case LedgerFeesModalStatus.TRANSFER_EQUAL_TO_BALANCE:
      case LedgerFeesModalStatus.TRANSFER_POSSIBLE_WITH_FEES:
        return (
          <LedgerFeesDescriptionText>
            The Sovrin Ledger transaction fees brings your total spend to{' '}
            <LedgerFeesDescriptionText bold>
              {totalSpend}
            </LedgerFeesDescriptionText>. Proceed?
          </LedgerFeesDescriptionText>
        )

      default:
        return null
    }
  }

  render() {
    const {
      claimOfferData,
      isValid,
      logoUrl,
      claimThemePrimary,
      claimThemeSecondary,
    } = this.props
    const {
      claimRequestStatus,
      issuer,
      data,
      payTokenValue,
    }: ClaimOfferPayload = claimOfferData
    const logoUri = logoUrl
      ? { uri: logoUrl }
      : require('../images/logo_sovrin.png')
    const testID = 'claim-offer'
    let acceptButtonText = payTokenValue ? 'Accept & Pay' : 'Accept'
    return (
      <Container style={[{ backgroundColor: claimThemePrimary }]}>
        <StatusBar
          backgroundColor={claimThemePrimary}
          barStyle={getStatusBarStyle(claimThemePrimary)}
        />
        {isValid && (
          <ClaimProofHeader
            message={`${issuer.name} is offering you`}
            title={data.name}
            onClose={this.onIgnore}
            logoUrl={logoUrl}
            testID={testID}
            payTokenValue={payTokenValue}
            containerStyle={{
              backgroundColor: claimThemePrimary,
              borderBottomColor: claimThemePrimary,
            }}
            textContainerStyle={[headerStyles.clearBg]}
            messageStyle={[headerStyles.clearBg, styles.messageStyle]}
            titleStyle={[styles.titleStyles]}
          >
            <CustomView
              fifth
              hCenter
              style={[headerStyles.headerLogoContainer, headerStyles.clearBg]}
            >
              <Icon
                absolute="TopRight"
                src={require('../images/iconClose.png')}
                medium
                testID={`${testID}-icon-close`}
                onPress={this.close}
                iconStyle={[styles.headerCloseIcon]}
                style={[styles.headerCloseIconContainer]}
              />
              <Icon
                center
                halo
                extraLarge
                resizeMode="cover"
                src={logoUri}
                style={[styles.issuerLogo]}
                iconStyle={[styles.issuerLogoIcon]}
                testID={`${testID}-issuer-logo`}
                backgroundRoundWhite
              />
            </CustomView>
          </ClaimProofHeader>
        )}
        {isValid ? (
          <ClaimOfferAttributeList list={data.revealedAttributes} />
        ) : (
          <Container fifth center>
            <CustomText h5 bg="fifth">
              Invalid credential offer. Please ignore.
            </CustomText>
          </Container>
        )}
        <FooterActions
          logoUrl={logoUrl}
          onAccept={this.onAccept}
          onDecline={this.onReject}
          denyTitle="Ignore"
          acceptTitle={acceptButtonText}
          testID={`${testID}-footer`}
          disableAccept={this.state.disableAcceptButton}
        />
        {this.state.credentialOfferModalStatus !==
          CREDENTIAL_OFFER_MODAL_STATUS.NONE && (
          <CredentialOfferModal
            isValid={isValid}
            claimRequestStatus={claimRequestStatus}
            onModalHide={this.onCredentialOfferModalHide}
            claimOfferData={claimOfferData}
            onClose={this.close}
            logoUrl={logoUrl}
            payTokenValue={payTokenValue}
            credentialOfferModalStatus={this.state.credentialOfferModalStatus}
            testID={`${testID}-payment-failure-modal`}
            onRetry={this.onAccept}
            onNo={this.onRejectPaidCredTransaction}
            onYes={this.onProceedPaidCredTransaction}
            renderFeesText={this.renderFeesText}
          />
        )}
      </Container>
    )
  }
}

const mapStateToProps = (state: Store, props: ReactNavigation) => {
  const { claimOffer } = state
  const { uid } =
    props.navigation.state && props.navigation.state.params
      ? props.navigation.state.params
      : { uid: '' }
  const claimOfferData = claimOffer[uid]
  const logoUrl = getConnectionLogoUrl(state, claimOfferData.remotePairwiseDID)
  const themeForLogo = getConnectionTheme(state, logoUrl)
  const isValid =
    claimOfferData &&
    claimOfferData.data &&
    claimOfferData.issuer &&
    claimOfferData.data.revealedAttributes

  return {
    claimThemePrimary: themeForLogo.primary,
    claimThemeSecondary: themeForLogo.secondary,
    uid,
    claimOfferData,
    isValid,
    logoUrl,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      claimOfferShown,
      acceptClaimOffer,
      claimOfferRejected,
      claimOfferIgnored,
      updateStatusBarTheme,
      claimOfferShowStart,
      resetClaimRequestStatus,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(ClaimOffer)

const styles = StyleSheet.create({
  headerCloseIcon: {
    marginRight: 15,
  },
  headerCloseIconContainer: {
    zIndex: 2,
  },
  strip: {
    height: 20,
    width: '100%',
    backgroundColor: color.actions.secondary,
    zIndex: -1,
  },
  issuerLogo: {
    ...StyleSheet.absoluteFillObject,
    alignSelf: 'center',
    zIndex: 1,
  },
  issuerLogoIcon: {
    borderRadius: 40,
  },
  claimOfferData: {
    zIndex: -1,
  },
  attributeListLabel: {
    flex: 4,
    paddingRight: OFFSET_3X / 2,
  },
  attributeListLabelText: {
    lineHeight: 19,
  },
  attributeListValue: {
    flex: 6,
  },
  messageStyle: {
    color: color.bg.primary.font.primary,
  },
  titleStyles: {
    backgroundColor: 'transparent',
    color: color.bg.primary.font.primary,
  },
})


<|start_filename|>app/components/custom-header/type-custom-header.js<|end_filename|>
// @flow
import type { GenericObject, ReactChildren } from '../../common/type-common'
import * as React from 'react'

// backgroundColor is required as this handles statusbar color in the given screen
export type CustomHeaderProps = {
  backgroundColor: string,
  children?: React.Node,
  centerComponent?: ReactChildren,
  leftComponent?: ReactChildren,
  rightComponent?: ReactChildren,
  outerContainerStyles?: GenericObject,
  flatHeader?: boolean,
  zeroBottomBorder?: boolean,
  largeHeader?: boolean,
  isFocused?: boolean,
}


<|start_filename|>app/store/store-selector.js<|end_filename|>
// @flow
import type { Store } from './type-store'
import type { ClaimOfferStore } from '../claim-offer/type-claim-offer'
import type { ProofRequestStore } from '../proof-request/type-proof-request'
import type {
  ClaimOfferPayload,
  SerializedClaimOffersPerDid,
} from '../claim-offer/type-claim-offer'
import type { Connections, Connection } from './type-connection-store'
import type { ConnectionHistoryEvent } from '../connection-history/type-connection-history'
import RNFetchBlob from 'react-native-fetch-blob'
import { Platform } from 'react-native'
import { whiteSmoke } from '../common/styles/constant'
import memoize from 'lodash.memoize'
import { CLAIM_OFFER_STATUS } from './../claim-offer/type-claim-offer'
import { PROOF_REQUEST_STATUS } from './../proof-request/type-proof-request'

export const getConfig = (state: Store) => state.config

export const getAgencyUrl = (state: Store) => state.config.agencyUrl

export const getAgencyDID = (state: Store) => state.config.agencyDID

export const getPoolConfig = (state: Store) => state.config.poolConfig

export const getAgencyVerificationKey = (state: Store) =>
  state.config.agencyVerificationKey

export const getPushToken = (state: Store) => state.pushNotification.pushToken

export const getAllConnection = (state: Store) => state.connections.data

export const getConnectionTheme = (state: Store, logoUrl: string) =>
  state.connections.connectionThemes[logoUrl] ||
  state.connections.connectionThemes['default']

export const getErrorAlertsSwitchValue = (state: Store) =>
  state.config.showErrorAlerts

export const getInvitationPayload = (
  state: Store,
  invitationSenderDID: string
) => state.invitation[invitationSenderDID].payload

export const getConnectionLogoUrl = (
  state: Store,
  remotePairwiseDid: string
): string => {
  const connections = getConnection(state, remotePairwiseDid)
  return connections.length > 0 ? connections[0].logoUrl : ''
}

export const getConnection = (
  state: Store,
  senderDID: string
): Array<Connection> => {
  const connections = getAllConnection(state)
  if (connections) {
    // Had to use `any` type here even though we know `Array<Connection>`
    // will be returned, as of now Flow returns mixed type for
    // all Object.{map,keys,values} operations and we can't do
    // anything unless we specify $Exact type, which we can't define
    // in this case, because for $Exact type, we should know each
    // key in advance which is not the case here because we don't know DIDs
    // with which we will make connections
    const savedConnections: Array<any> = Object.values(connections)
    return savedConnections.filter(
      (connection: Connection) => connection.senderDID === senderDID
    )
  }

  return []
}

export const isDuplicateConnection = (state: Store, senderDID: string) => {
  const connections = getConnection(state, senderDID)

  return connections.length > 0
}

export const getHydrationState = (state: Store) => state.config.isHydrated

export const getInitializedState = (state: Store) => state.config.isInitialized

export const getClaimOffer = (state: Store, claimOfferId: string) =>
  state.claimOffer[claimOfferId]

//TODO - delete this selector and handle it in the reducer (no need to filter twice)
export const getPendingHistoryEvent = (
  state: Store,
  claim: ClaimOfferPayload
) => {
  const historyItems =
    state.history && state.history.data
      ? state.history.data[claim.remotePairwiseDID]
      : []
  return historyItems.filter(item => {
    return item.action === 'PENDING' && item.originalPayload.uid === claim.uid
  })[0]
}

export const getHistoryEvent = (
  state: Store,
  uid: string,
  remoteDid: string,
  type: string
) => {
  const historyItems =
    state.history && state.history.data ? state.history.data[remoteDid] : []
  return historyItems.filter(item => {
    return (
      item.originalPayload &&
      item.originalPayload.type === type &&
      item.originalPayload.payloadInfo &&
      item.originalPayload.payloadInfo.uid === uid
    )
  })[0]
}

export const getPendingHistory = (
  state: Store,
  uid: string,
  remoteDid: string,
  type: string
) => {
  const historyItems =
    state.history && state.history.data ? state.history.data[remoteDid] : []
  return historyItems.filter(item => {
    return (
      item.originalPayload &&
      item.originalPayload.type === type &&
      item.originalPayload.uid === uid
    )
  })[0]
}

export const getClaimReceivedHistory = (
  state: Store,
  uid: string,
  remoteDid: string,
  type: string
) => {
  const historyItems =
    state.history && state.history.data ? state.history.data[remoteDid] : []
  return historyItems.filter(item => {
    return (
      item.originalPayload &&
      item.originalPayload.type === type &&
      item.originalPayload.messageId === uid
    )
  })[0]
}

export const getProofRequest = (state: Store, proofRequestId: string) =>
  state.proofRequest[proofRequestId]

export const getProofRequesterName = (state: Store, proofRequestId: string) => {
  if (
    state.proofRequest[proofRequestId] &&
    state.proofRequest[proofRequestId].requester &&
    state.proofRequest[proofRequestId].requester.name
  ) {
    return state.proofRequest[proofRequestId].requester.name
  }

  return 'requester'
}

export const getOriginalProofRequestData = (
  state: Store,
  proofRequestId: string
) => state.proofRequest[proofRequestId].originalProofRequestData

export const getProofRequestPairwiseDid = (
  state: Store,
  proofRequestId: string
) => state.proofRequest[proofRequestId].remotePairwiseDID

export const getProof = (state: Store, proofRequestId: string) =>
  state.proof[proofRequestId]
export const getProofRequests = (state: Store) => state.proofRequest

export const getUserPairwiseDid = (state: Store, senderDID: string) => {
  const connections = getConnection(state, senderDID)
  if (connections.length > 0) {
    return connections[0].identifier
  }

  return null
}

export const getRemotePairwiseDidAndName = (state: Store, userDid: string) => {
  if (state.connections.data) {
    const connection = state.connections.data[userDid]
    if (connection) {
      return {
        remotePairwiseDID: connection.senderDID,
        remoteName: connection.senderName,
        ...connection,
      }
    }

    return {}
  }

  return {}
}

export const getUserOneTimeInfo = (state: Store) => state.user.userOneTimeInfo

export const getClaimMap = (state: Store) => state.claim.claimMap

export const getCurrentScreen = (state: Store) => state.route.currentScreen

export const getWalletBalance = (state: Store) =>
  state.wallet.walletBalance.data

export const getWalletAddresses = (state: Store) =>
  state.wallet.walletAddresses.data

export const getTokenAmount = (state: Store) => state.wallet.payment.tokenAmount

export const getWalletHistory = (state: Store) => state.wallet.walletHistory

export const getStatusBarTheme = (state: Store) => {
  const statusBarTheme =
    state.connections !== undefined &&
    state.connections.statusBarTheme != undefined
      ? state.connections.statusBarTheme
      : whiteSmoke
  return statusBarTheme
}

export const getUserAvatarSource = (name: ?string) => {
  if (name) {
    const uri =
      Platform.OS === 'ios'
        ? `${RNFetchBlob.fs.dirs.DocumentDir}/${name}`
        : `file://${RNFetchBlob.fs.dirs.DocumentDir}/${name}`
    return {
      uri,
    }
  }

  return undefined
}

export const getUserAvatarName = (state: Store) => state.user.avatarName

export const getThemes = (state: Store) => state.connections.connectionThemes

export const getVcxInitializationState = (state: Store) =>
  state.config.vcxInitializationState

export const getIsLockEnabledState = (state: Store) => state.lock.isLockEnabled
export const getIsAppLocked = (state: Store) => state.lock.isAppLocked

export const getIsAlreadyInstalledState = (state: Store) =>
  state.config.isAlreadyInstalled

export const getClaimOffers = (state: Store) => state.claimOffer

export const getSerializedClaimOffer = (
  state: Store,
  userDID: string,
  messageId: string
) => {
  const userClaimOffers = state.claimOffer.vcxSerializedClaimOffers[userDID]
  if (!userClaimOffers) {
    // we did not find any claim offers with user pairwise did (userDID)
    return null
  }

  return userClaimOffers[messageId]
}

export const getSerializedClaimOffers = (state: Store, userDID: string) => {
  const serializedClaimOffers: SerializedClaimOffersPerDid =
    state.claimOffer.vcxSerializedClaimOffers[userDID]

  if (serializedClaimOffers) {
    return Object.values(serializedClaimOffers)
  }

  return []
}

export const getAllConnectionsPairwiseDid = (state: Store) => {
  const connections = getAllConnection(state)

  if (connections) {
    return Object.keys(connections).map(
      userDID => connections[userDID].myPairwiseDid
    )
  }
  return null
}

export const getConnectionByUserDid = (state: Store, userDID: string) => {
  const connections = getAllConnection(state)

  if (connections) {
    return connections[userDID]
  }

  return null
}

export const getOfflineStatus = (state: Store) => state.offline.offline

export const getInvitations = (state: Store) => state.invitation

export const getDeepLinkTokens = (state: Store) => state.deepLink.tokens

export const getBackupPassphrase = (state: Store) => state.backup.passphrase

export const getBackupStatus = (state: Store) => state.backup.status

export const getBackupWalletPath = (state: Store) =>
  state.backup.backupWalletPath

export const getBackupShowBanner = (state: Store) => state.backup.showBanner

const addUidsWithStatusToConnections = (
  events: ProofRequestStore | ClaimOfferStore,
  filterStatus,
  obj
) => {
  ;(Object.keys(events): Array<string>).map(uid => {
    if (events[uid].status === filterStatus) {
      const remoteDid: string = events[uid].remotePairwiseDID
      obj[remoteDid] = obj[remoteDid] || []
      obj[remoteDid].push(uid)
    }
  })
}

//  getUnseenMessages should take a connection, and parse though claim store and proof requests for unseen messages and return a json object like bellow.
export const getUnseenMessages = memoize(
  (state: Store) => {
    const { claimOffer, proofRequest } = state
    let obj = {}

    addUidsWithStatusToConnections(claimOffer, CLAIM_OFFER_STATUS.RECEIVED, obj)
    addUidsWithStatusToConnections(
      proofRequest,
      PROOF_REQUEST_STATUS.RECEIVED,
      obj
    )
    return obj
  },
  ({ claimOffer, proofRequest }) => ({
    ...claimOffer,
    ...proofRequest,
  })
)

export const getLastSuccessfulBackupTimeStamp = (state: Store) =>
  state.backup.lastSuccessfulBackup

export const getRestoreStatus = (state: Store) => state.restore.status

export const getRestoreFileSize = (state: Store) =>
  state.restore.restoreFile.fileSize

export const getRouteCurrentScreen = (state: Store) => state.route.currentScreen

export const getRestoreFilePath = (state: Store) =>
  state.restore.restoreFile.uri

export const getRestoreFileName = (state: Store) =>
  state.restore.restoreFile.fileName

export const getSalt = (state: Store) => state.backup.passphrase.salt

export const getHistory = (state: Store) => state.history.data
export const getPendingFetchAdditionalDataKey = (state: Store) =>
  state.pushNotification.pendingFetchAdditionalDataKey
export const getProofData = (state: Store, proofRequestId: string) =>
  state.proof[proofRequestId].proofData

export const getPrepareBackupStatus = (state: Store) =>
  state.backup.prepareBackupStatus


<|start_filename|>app/connection/connection.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import {
  View,
  ScrollView,
  Image,
  TouchableHighlight,
  StyleSheet,
} from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { Icon } from 'react-native-elements'
import { Badge, InfoSectionList, CustomView } from '../components'
import ConnectionStatus from './connection-status'
import ConnectionInfo from './connection-info'
import { homeRoute, connectionRoute } from '../common/route-constants'
import { veniceBlue } from '../common/styles/constant'

const styles = StyleSheet.create({
  left: {
    width: 24,
    height: 24,
    marginLeft: 15,
  },
  right: {
    width: 22,
    height: 22,
    marginRight: 15,
  },
  title: {
    width: 160,
  },
})

const headerLeft = (
  <Image
    style={[styles.left]}
    source={require('../images/icon_Chat.png')}
    resizeMode="contain"
  />
)

const headerTitle = (
  <Image
    style={[styles.title]}
    source={require('../images/SovrinSecuredConnection.png')}
    resizeMode="contain"
  />
)
//Note: This page is not in use. [ND 23/08/2018]
export class ConnectionHome extends PureComponent<void, void> {
  static navigationOptions = ({ navigation }) => ({
    headerLeft: headerLeft,
    headerTitle: headerTitle,
    headerRight: (
      <CustomView>
        <TouchableHighlight
          onPress={() => navigation.navigate(homeRoute)}
          testID={'connection-header-close'}
          underlayColor={veniceBlue}
        >
          <Image
            testID="connection-header-close-image"
            accessible={true}
            accessibilityLabel={'connection-header-close-image'}
            style={[styles.right]}
            source={require('../images/icon_close.png')}
            onPress={() => navigation.navigate(homeRoute)}
          />
        </TouchableHighlight>
      </CustomView>
    ),
    headerStyle: {
      backgroundColor: veniceBlue,
      height: 50,
    },
  })

  render() {
    return (
      <ScrollView>
        <ConnectionStatus />
        <InfoSectionList>
          <ConnectionInfo />
        </InfoSectionList>
      </ScrollView>
    )
  }
}

export default createStackNavigator({
  [connectionRoute]: {
    screen: ConnectionHome,
  },
})


<|start_filename|>app/components/icon.js<|end_filename|>
// @flow
import React from 'react'
import { StyleSheet, Image, TouchableWithoutFeedback, View } from 'react-native'
import { CustomView } from './layout/custom-view'
import type { GenericObject } from '../common/type-common'
import { white } from '../common/styles'

const empty = []

// TODO:KS Change GenericObject to actual props of icon
const Icon = (props: GenericObject) => {
  const {
    src,
    small,
    medium,
    mediumLarge,
    large,
    extraLarge,
    xxLarge,
    iconStyle = empty,
    testID,
    resizeMode = 'contain',
    halo,
    round,
    haloStyle = empty,
    onPress,
    onLongPress,
    backgroundRoundWhite,
  } = props
  const size = small
    ? 'small'
    : medium
      ? 'medium'
      : extraLarge
        ? 'extraLarge'
        : mediumLarge ? 'mediumLarge' : xxLarge ? 'xxLarge' : 'large'
  const roundImageStyle =
    halo || round
      ? // $FlowFixMe flow does not support dynamic object key
        styles[`${size}RoundIcon`]
      : null
  let filteredProps = {}
  if (typeof props.testID !== 'undefined') {
    filteredProps.testID = testID
    filteredProps.accessible = true
    filteredProps.accessibilityLabel = testID
  }
  const backgroundRoundWhiteImage = backgroundRoundWhite
    ? // $FlowFixMe flow does not support dynamic object key
      [styles.backgroundWhite, styles[`${size}RoundIcon`]]
    : {}
  const iconImage = (
    <View style={backgroundRoundWhiteImage}>
      <Image
        source={src}
        style={[styles[size], roundImageStyle, ...iconStyle]}
        resizeMode={resizeMode}
        {...filteredProps}
      />
    </View>
  )

  let haloView
  if (halo) {
    // $FlowFixMe flow does not support dynamic object lookup
    const haloSizeStyle = styles[`${size}Halo`]
    haloView = (
      <CustomView center style={[haloSizeStyle, haloStyle]}>
        {iconImage}
      </CustomView>
    )
  }

  return (
    <CustomView clearBg {...props}>
      {halo ? haloView : iconImage}
    </CustomView>
  )
}

export default Icon

export const size = {
  small: 20,
  medium: 30,
  mediumLarge: 40,
  large: 50,
  extraLarge: 80,
  xxLarge: 90,
}

const styles = StyleSheet.create({
  small: {
    width: size.small,
    height: size.small,
  },
  medium: {
    width: size.medium,
    height: size.medium,
  },
  mediumLarge: {
    width: size.mediumLarge,
    height: size.mediumLarge,
  },
  large: {
    width: size.large,
    height: size.large,
  },
  extraLarge: {
    width: size.extraLarge,
    height: size.extraLarge,
  },
  xxLarge: {
    width: size.xxLarge,
    height: size.xxLarge,
  },
  smallRoundIcon: {
    borderRadius: size.small / 2,
  },
  mediumRoundIcon: {
    borderRadius: size.medium / 2,
  },
  largeRoundIcon: {
    borderRadius: size.large / 2,
  },
  mediumLargeRoundIcon: {
    borderRadius: size.mediumLarge / 2,
  },
  extraLargeRoundIcon: {
    borderRadius: size.extraLarge / 2,
  },
  extraLargeHalo: {
    // we are assuming that halo will be at least 20pt larger than image
    borderRadius: (size.extraLarge + 20) / 2,
    width: size.extraLarge + 20,
    height: size.extraLarge + 20,
    backgroundColor: 'rgba(0,0,0,0.07)',
  },
  backgroundWhite: {
    backgroundColor: white,
  },
})


<|start_filename|>app/invitation/__tests__/invitation-store.spec.js<|end_filename|>
// @flow
import React from 'react'
import renderer from 'react-test-renderer'
import { put, call, select } from 'redux-saga/effects'
import { expectSaga } from 'redux-saga-test-plan'
import * as matchers from 'redux-saga-test-plan/matchers'
import invitationReducer, {
  invitationReceived,
  sendInvitationResponse,
  invitationSuccess,
  invitationRejected,
  invitationFail,
  sendResponse,
} from '../invitation-store'
import { initialTestAction } from '../../common/type-common'
import type { InvitationStore } from '../type-invitation'
import { ResponseType } from '../../components/request/type-request'
import { saveNewConnection } from '../../store/connections-store'
import {
  createConnectionWithInvite,
  acceptInvitationVcx,
  serializeConnection,
} from '../../bridge/react-native-cxs/RNCxs'
import {
  ERROR_ALREADY_EXIST,
  ERROR_INVITATION_RESPONSE_PARSE_CODE,
  ERROR_INVITATION_RESPONSE_PARSE,
} from '../../api/api-constants'
import {
  getTestInvitationPayload,
  successConnectionData,
  pairwiseConnection,
  myPairWiseConnectionDetails,
  vcxSerializedConnection,
} from '../../../__mocks__/static-data'
import { connectRegisterCreateAgentDone } from '../../store/user/user-store'
import { VCX_INIT_SUCCESS } from '../../store/type-config-store'
import { safeGet, safeSet } from '../../services/storage'

// TODO:KS These should be moved to a separate file that handles
// all of the static data of whole app, so that if we change
// one type of data, we will immediately know which other part of app it breaks
const agencyDid = '5qiK8KZQ86XjcnLmy5S2Tn'
const agencyVerificationKey = '<KEY>'
const poolConfig = 'sandboxPool'
const agencyUrl = 'https://test-agency.com'
const pushToken = '<PASSWORD>lq92'
const identifier = '3akhf906816kahfadhfas85'
const verificationKey = '<KEY>'

describe('Invitation Store', () => {
  let initialState
  let afterOneInvitationState
  let propsGenerator
  let firstInvitation

  function fail() {
    // we can use this function if we specifically want to fail a test
    expect(1).toBe(2)
  }

  beforeEach(() => {
    initialState = invitationReducer(undefined, initialTestAction())
    propsGenerator = getTestInvitationPayload()
    firstInvitation = propsGenerator.next().value
    if (firstInvitation) {
      afterOneInvitationState = invitationReducer(
        initialState,
        invitationReceived(firstInvitation)
      )
    } else {
      fail()
    }
  })

  it('one invitation is received', () => {
    expect(afterOneInvitationState).toMatchSnapshot()
  })

  it('multiple invitations are received', () => {
    const nextInvitation = propsGenerator.next().value
    if (nextInvitation) {
      const nextState = invitationReducer(
        afterOneInvitationState,
        invitationReceived(nextInvitation)
      )
      expect(nextState).toMatchSnapshot()
    } else {
      fail()
    }
  })

  it('invitation response is sent', () => {
    if (firstInvitation) {
      const data = {
        senderDID: firstInvitation.payload.senderDID,
        response: ResponseType.accepted,
      }
      const state = invitationReducer(
        afterOneInvitationState,
        sendInvitationResponse(data)
      )
      expect(state).toMatchSnapshot()
    }
  })

  it('invitation response is sent successfully', () => {
    if (firstInvitation) {
      const state = invitationReducer(
        afterOneInvitationState,
        invitationSuccess(firstInvitation.payload.senderDID)
      )
      expect(state).toMatchSnapshot()
    }
  })

  it('invitation response sending failed', () => {
    if (firstInvitation) {
      const error = {
        code: 'TEST-INVITATION-FAIL',
        message: 'Invitation sending failed from test',
      }
      const state = invitationReducer(
        afterOneInvitationState,
        invitationFail(error, firstInvitation.payload.senderDID)
      )
      expect(state).toMatchSnapshot()
    }
  })

  it('invitation is rejected', () => {
    if (firstInvitation) {
      const state = invitationReducer(
        afterOneInvitationState,
        invitationRejected(firstInvitation.payload.senderDID)
      )
      expect(state).toMatchSnapshot()
    }
  })

  it('should reset invitation store, if RESET action is raised', () => {
    expect(
      invitationReducer(afterOneInvitationState, { type: 'RESET' })
    ).toMatchSnapshot()
  })

  it('saga:sendResponseVcx', () => {
    if (firstInvitation) {
      const { payload } = firstInvitation
      const { senderDID, senderVerificationKey } = payload
      const data = {
        senderDID,
        response: ResponseType.accepted,
      }
      const vcxInitSuccessWithInvitationState = {
        config: {
          vcxInitializationState: VCX_INIT_SUCCESS,
        },
        invitation: {
          [senderDID]: {
            payload,
          },
        },
        connections: {},
      }
      const connectionHandle = 1

      return expectSaga(sendResponse, sendInvitationResponse(data))
        .withState(vcxInitSuccessWithInvitationState)
        .provide([
          [
            matchers.call.fn(createConnectionWithInvite, payload),
            connectionHandle,
          ],
          [
            matchers.call.fn(acceptInvitationVcx, connectionHandle),
            myPairWiseConnectionDetails,
          ],
          [
            matchers.call.fn(serializeConnection, connectionHandle),
            vcxSerializedConnection,
          ],
        ])
        .put(invitationSuccess(senderDID))
        .put(
          saveNewConnection({
            newConnection: {
              ...successConnectionData.newConnection,
              vcxSerializedConnection,
            },
          })
        )
        .run()
    }
  })
})


<|start_filename|>app/wallet/__tests__/wallet-tabs.spec.js<|end_filename|>
//  @flow

import React from 'react'
import renderer from 'react-test-renderer'
import { createTabNavigator } from 'react-navigation'
import { walletRoute } from '../../common'
import { getNavigation } from '../../../__mocks__/static-data'
import WalletTabs from '../wallet-tabs'

describe('<WalletTabs />', () => {
  let navigation = {
    ...getNavigation(),
  }
  function setup() {
    const component = renderer.create(<WalletTabs navigation={navigation} />)
    const instance = component.getInstance()

    return { component, instance }
  }
  it('should render properly and match the snapshot', () => {
    const { component } = setup()
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/eula/type-eula.js<|end_filename|>
// @flow
import type { CustomError } from '../common/type-common'
import { Platform } from 'react-native'

const isAndroid = Platform.OS === 'android'
export const EULA_ACCEPT = 'EULA_ACCEPT'
export const ANDROID_EULA_URL = 'https://www.connect.me/google.html'
export const IOS_EULA_URL = 'https://www.connect.me/ios_eula.html'
export const EULA_URL = isAndroid ? ANDROID_EULA_URL : IOS_EULA_URL
export const localEulaSource = isAndroid
  ? 'file:///android_asset/external/connectme/eula_android.html'
  : './eula_ios.html'
export const STORAGE_KEY_EULA_ACCEPTANCE = 'STORAGE_KEY_EULA_ACCEPTANCE'
export const HYDRATE_EULA_ACCEPT = 'HYDRATE_EULA_ACCEPT'

export type EulaStore = {
  isEulaAccept: boolean,
}

export type EulaActions = EulaAccept | HydrateEulaAcceptAction

export type EulaAccept = {
  type: typeof EULA_ACCEPT,
  isEulaAccept: boolean,
}

export type HydrateEulaAcceptAction = {
  type: typeof HYDRATE_EULA_ACCEPT,
  isEulaAccept: boolean,
}

export type EulaScreenState = {
  error: null | CustomError,
}


<|start_filename|>app/proof-request/__tests__/proof-request-modal.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import ProofModal from '../proof-modal'
import { PROOF_STATUS } from '../type-proof-request'
import { getStore } from '../../../__mocks__/static-data'

describe('<ProofModal />', () => {
  const title = 'Home Address'
  const name = '<NAME>'
  const logoUrl = 'http://testissuer.com/logoUrl.png'
  const store = getStore()
  let onContinue

  beforeEach(() => {
    onContinue = jest.fn()
  })

  it('should match snapshot when sending proof', () => {
    const proofStatus = PROOF_STATUS.SENDING_PROOF

    const wrapper = renderer
      .create(
        <Provider store={store}>
          <ProofModal
            proofStatus={proofStatus}
            title={title}
            name={name}
            onContinue={onContinue}
            logoUrl={logoUrl}
          />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })

  it('should match snapshot when proof sent success', () => {
    const proofStatus = PROOF_STATUS.SEND_PROOF_SUCCESS
    const wrapper = renderer
      .create(
        <Provider store={store}>
          <ProofModal
            proofStatus={proofStatus}
            title={title}
            name={name}
            onContinue={onContinue}
            logoUrl={logoUrl}
          />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })

  it('should match snapshot when proof sent fail', () => {
    const proofStatus = PROOF_STATUS.SEND_PROOF_FAIL
    const wrapper = renderer
      .create(
        <Provider store={store}>
          <ProofModal
            proofStatus={proofStatus}
            title={title}
            name={name}
            onContinue={onContinue}
            logoUrl={logoUrl}
          />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>app/lock/lock-enter-pin-code.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { createStackNavigator } from 'react-navigation'
import { safeGet, safeSet } from '../services/storage'
import LockEnter from './lock-enter'
import {
  lockEnterPinRoute,
  lockPinSetupRoute,
  homeRoute,
  lockSelectionRoute,
} from '../common'
import type { ReactNavigation } from '../common/type-common'
import type { Store } from '../store/type-store'
import type { LockEnterPinProps, LockEnterPinState } from './type-lock'
import { clearPendingRedirect } from './lock-store'
import {
  ENTER_PASS_CODE_MESSAGE,
  ENTER_YOUR_PASS_CODE_MESSAGE,
} from '../common/message-constants'
import { color } from '../common/styles'
import { UNLOCKING_APP_WAIT_MESSAGE } from '../common/message-constants'
import { unlockApp } from './lock-store'
import { CustomText, CustomHeader } from '../components'
import { Keyboard, Platform } from 'react-native'

export class LockEnterPin extends PureComponent<
  LockEnterPinProps,
  LockEnterPinState
> {
  state = {
    authenticationSuccess: false,
    isKeyboardHidden: false,
    showCustomKeyboard: false,
  }

  keyboardListener = null
  keyboardShowListener = null

  static navigationOptions = ({ navigation }) => ({
    header:
      navigation.state.params &&
      navigation.state.params.fromScreen === 'recovery' ? (
        <CustomHeader flatHeader backgroundColor={color.bg.tertiary.color} />
      ) : (
        <CustomHeader
          flatHeader
          backgroundColor={color.bg.tertiary.color}
          centerComponent={
            <CustomText bg="tertiary" tertiary transparentBg semiBold>
              App Security
            </CustomText>
          }
        />
      ),
  })

  componentDidMount() {
    this.keyboardListener = Keyboard.addListener(
      'keyboardDidHide',
      this.keyboardHideState
    )
    this.keyboardShowListener = Keyboard.addListener(
      'keyboardDidShow',
      this.keyboardShowState
    )
  }

  keyboardShowState = (event: any) => {
    if (event && event.endCoordinates.height < 100 && Platform.OS === 'ios') {
      this.setState({
        showCustomKeyboard: true,
      })
    } else {
      this.setState({
        showCustomKeyboard: false,
      })
    }
  }

  keyboardHideState = () => {
    this.setState({
      isKeyboardHidden: true,
    })

    if (
      this.state.authenticationSuccess &&
      this.props.currentScreen === lockEnterPinRoute
    ) {
      // if we reach at this screen from settings page
      // then user is trying to enable/disable touch id
      if (this.props.existingPin) {
        this.props.navigation.push(lockPinSetupRoute, {
          existingPin: true,
        })
      }
    }
  }

  componentWillReceiveProps(nextProps: LockEnterPinProps) {
    if (
      this.props.isFetchingInvitation !== nextProps.isFetchingInvitation &&
      nextProps.isFetchingInvitation === false &&
      nextProps.pendingRedirection
    ) {
      if (this.state.authenticationSuccess && this.state.isKeyboardHidden) {
        // passing the nextProps in to the redirect function
        // the prop is being changed (pendingRedirection) from object to null
        // CLEAR_PENDING_REDIRECT clearing the pendingRedirection property to null
        // so, the previous props are being sent for the redirection
        this.redirect(nextProps)
      }
    }

    // we are removing the keyboard listener every time we navigate out of this screen.
    if (nextProps.navigation.isFocused()) {
      if (!this.keyboardListener) {
        this.keyboardListener = Keyboard.addListener(
          'keyboardDidHide',
          this.keyboardHideState
        )
      }
      if (!this.keyboardShowListener) {
        this.keyboardShowListener = Keyboard.addListener(
          'keyboardDidShow',
          this.keyboardShowState
        )
      }
    } else if (
      this.props.currentScreen === lockEnterPinRoute &&
      nextProps.currentScreen !== lockEnterPinRoute
    ) {
      this.keyboardListener && this.keyboardListener.remove()
      this.keyboardShowListener && this.keyboardShowListener.remove()
    }
  }

  // passing the props in to the function
  redirect = (props: LockEnterPinProps) => {
    props.unlockApp()
    if (props.pendingRedirection) {
      props.pendingRedirection.map(pendingRedirection => {
        props.navigation.navigate(
          pendingRedirection.routeName,
          pendingRedirection.params
        )
      })
      props.clearPendingRedirect()
    } else if (props.isAppLocked === true) {
      // * if app is unlocked and invitation is fetched , with out this condition we are redirecting user to home screen from invitation screen.
      // * this condition will avoid redirecting user to home screen if app is already unlocked
      setTimeout(() => {
        props.navigation.navigate(homeRoute)
      }, 0)
    }
  }

  onSuccess = () => {
    if (!this.state.authenticationSuccess) {
      this.setState({ authenticationSuccess: true })
      // if we reach at this screen from settings page
      // then user is trying to enable/disable touch id
      if (
        !this.props.existingPin &&
        this.props.isFetchingInvitation === false
      ) {
        // user is trying to unlock the app
        // check if user has some pending action, so redirect to those
        this.redirect(this.props)
      }
    }
  }

  redirectToSetupPasscode = () => {
    this.props.navigation.navigate(lockSelectionRoute)
  }

  render() {
    const { isFetchingInvitation, navigation, inRecovery } = this.props
    let fromRecovery = false
    if (navigation.state) {
      fromRecovery =
        (navigation.state.params &&
        navigation.state.params.fromScreen === 'recovery'
          ? true
          : false) || inRecovery === 'true'
    }
    let message = this.props.existingPin
      ? ENTER_YOUR_PASS_CODE_MESSAGE
      : ENTER_PASS_CODE_MESSAGE

    if (isFetchingInvitation && this.state.authenticationSuccess) {
      message = UNLOCKING_APP_WAIT_MESSAGE
    }

    return (
      <LockEnter
        fromRecovery={fromRecovery}
        onSuccess={this.onSuccess}
        message={message}
        setupNewPassCode={this.redirectToSetupPasscode}
        enableCustomKeyboard={this.state.showCustomKeyboard}
      />
    )
  }
}

const mapStateToProps = (state: Store, { navigation }: ReactNavigation) => ({
  pendingRedirection: state.lock.pendingRedirection,
  isFetchingInvitation: Object.keys(state.smsPendingInvitation).some(
    smsToken =>
      state.smsPendingInvitation[smsToken] &&
      state.smsPendingInvitation[smsToken].isFetching === true
  ),
  existingPin: navigation.state
    ? navigation.state.params ? navigation.state.params.existingPin : false
    : false,
  isAppLocked: state.lock.isAppLocked,
  inRecovery: state.lock.inRecovery,
  currentScreen: state.route.currentScreen,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      clearPendingRedirect,
      unlockApp,
    },
    dispatch
  )

export default createStackNavigator({
  [lockEnterPinRoute]: {
    screen: connect(mapStateToProps, mapDispatchToProps)(LockEnterPin),
  },
})


<|start_filename|>app/bridge/react-native-cxs/__tests__/rncxs.spec.js<|end_filename|>
// @flow
import { NativeModules } from 'react-native'
import { getHandleBySerializedConnection } from '../RNCxs'
import { vcxConnectionSerialized } from '../../../../__mocks__/data/vcx-mock-data'

describe('RNCxs', () => {
  function setup() {
    const connectionHandle = 1
    const mockGetHandleBySerializedConnection =
      NativeModules.RNIndy.deserializeConnection

    return { connectionHandle, mockGetHandleBySerializedConnection }
  }

  it('fn:deserializeConnection, two calls for two different string', async () => {
    const { connectionHandle, mockGetHandleBySerializedConnection } = setup()
    const vcxConnectionHandle = await getHandleBySerializedConnection(
      vcxConnectionSerialized
    )
    expect(vcxConnectionHandle).toBe(connectionHandle)

    await getHandleBySerializedConnection('{someOtherSerializedState}')
    expect(
      mockGetHandleBySerializedConnection.mock.calls.length
    ).toBeGreaterThanOrEqual(2)

    mockGetHandleBySerializedConnection.mockReset()
    mockGetHandleBySerializedConnection.mockRestore()
  })

  it('fn:deserializeConnection, one call for same string, multiple calls', async () => {
    const serializedConnection = '{serializedConnectionForThisTestOnly}'
    const { connectionHandle, mockGetHandleBySerializedConnection } = setup()
    await getHandleBySerializedConnection(serializedConnection)
    await getHandleBySerializedConnection(serializedConnection)
    expect(mockGetHandleBySerializedConnection.mock.calls.length).toBe(1)

    mockGetHandleBySerializedConnection.mockReset()
    mockGetHandleBySerializedConnection.mockRestore()
  })
})


<|start_filename|>app/store/type-store.js<|end_filename|>
// @flow
import type { LockStore } from '../lock/type-lock'
import type { SMSPendingInvitationStore } from '../sms-pending-invitation/type-sms-pending-invitation'
import type { AuthenticationStore } from '../authentication/type-authentication'
import type { ClaimOfferStore } from '../claim-offer/type-claim-offer'
import type { ProofRequestStore } from '../proof-request/type-proof-request'
import type { InvitationStore } from '../invitation/type-invitation'
import type { ConnectionStore } from './type-connection-store'
import type { ConfigStore } from './type-config-store'
import type { ClaimStore } from '../claim/type-claim'
import type { ProofStore } from '../proof/type-proof'
import type { UserStore } from './user/type-user-store'
import type { ConnectionHistoryStore } from '../connection-history/type-connection-history'
import type { DeepLinkStore } from '../deep-link/type-deep-link'
import type { WalletStore } from '../wallet/type-wallet'
import type { EulaStore } from '../eula/type-eula'
import type { BackupStore } from '../backup/type-backup'
import type { RestoreStore } from '../restore/type-restore'
import type { LedgerStore } from './ledger/type-ledger-store'
import type { OfflineStore } from '../offline/type-offline'

export type PushNotificationStore = {
  isAllowed: boolean,
  notification: ?{
    [string]: any,
  },
  pushToken: ?string,
  pendingFetchAdditionalDataKey?: ?{
    [string]: boolean,
  },
}

export type RouteStore = {
  currentScreen: string,
  timeStamp: number,
}

export type Store = {
  config: ConfigStore,
  connections: ConnectionStore,
  deepLink: DeepLinkStore,
  authentication: AuthenticationStore,
  pushNotification: PushNotificationStore,
  route: RouteStore,
  user: UserStore,
  lock: LockStore,
  smsPendingInvitation: SMSPendingInvitationStore,
  claimOffer: ClaimOfferStore,
  proofRequest: ProofRequestStore,
  invitation: InvitationStore,
  claim: ClaimStore,
  proof: ProofStore,
  history: ConnectionHistoryStore,
  wallet: WalletStore,
  eula: EulaStore,
  backup: BackupStore,
  restore: RestoreStore,
  ledger: LedgerStore,
  offline: OfflineStore,
}

export type { AuthenticationStore } from '../authentication/type-authentication'


<|start_filename|>app/invitation/invitation.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, StatusBar } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { captureError } from '../services/error/error-handler'
import {
  Request,
  Container,
  CustomModal,
  Loader,
  CustomText,
  CustomView,
} from '../components'
import { homeRoute } from '../common'
import { OFFSET_1X } from '../common/styles'
import { ResponseType } from '../components/request/type-request'
import { sendInvitationResponse, invitationRejected } from './invitation-store'
import type { Store } from '../store/type-store'
import type { ResponseTypes } from '../components/request/type-request'
import type { InvitationProps, InvitationState } from './type-invitation'
import type { ReactNavigation } from '../common/type-common'
import { smsPendingInvitationSeen } from '../sms-pending-invitation/sms-pending-invitation-store'
import { SMSPendingInvitationStatus } from '../sms-pending-invitation/type-sms-pending-invitation'
import { NavigationActions } from 'react-navigation'
import { barStyleDark, color } from '../common/styles/constant'

export class Invitation extends PureComponent<
  InvitationProps,
  InvitationState
> {
  state = {
    loading: false,
  }

  isLoading = (state: boolean) => this.setState({ loading: state })

  navigate = () => {
    this.props.navigation.navigate(homeRoute)
  }

  onSuccess = () => {
    setTimeout(() => {
      this.navigate()
    }, 500)
  }

  onAction = (response: ResponseTypes) => {
    const { invitation } = this.props
    if (invitation) {
      const { payload } = invitation
      if (payload) {
        if (response === ResponseType.accepted) {
          this.props.sendInvitationResponse({
            response,
            senderDID: payload.senderDID,
          })
        } else if (response === ResponseType.rejected) {
          this.props.invitationRejected(payload.senderDID)
          this.navigate()
        }
      } else {
        this.onSuccess()
      }
    }
  }

  componentWillReceiveProps(nextProps: InvitationProps) {
    // If invitation itself not generated then don't check payload
    if (nextProps.invitation && this.props.invitation) {
      if (
        this.props.invitation !== undefined &&
        nextProps.invitation.payload !== this.props.invitation.payload
      ) {
        // a new invitation was received
        this.isLoading(false)
      } else {
        if (nextProps.invitation.isFetching === false) {
          if (nextProps.invitation.error) {
            // TODO:KS we got error from API response, what to do now
            if (nextProps.invitation.error != this.props.invitation.error) {
              // TODO: captureError should only accept Error object or only json
              // as of now it would fail for JSON objects, as we are using
              // captureException of Sentry which is supposed to take only Error object
              // captureError(nextProps.invitation.error, this.props.showErrorAlerts)
              this.isLoading(false)
            }
          } else {
            // api response was successful, but now we have to check
            // if user accepted or declined the request
            if (nextProps.invitation.status === ResponseType.accepted) {
              this.isLoading(false)
              this.onSuccess()
            }
          }
        } else {
          // TODO:KS show loading indicator, API request was sent
          this.isLoading(true)
        }
      }
    }
  }

  componentDidMount() {
    if (this.props.isSmsInvitationNotSeen) {
      this.props.smsPendingInvitationSeen(this.props.smsToken)
    }
  }

  render() {
    const { invitation, showErrorAlerts, navigation } = this.props

    if (invitation) {
      let { payload } = invitation
      let senderName = ''
      let title = 'Hi'
      let message = 'You have received a connection request'
      let senderLogoUrl = undefined
      if (payload) {
        senderName = payload.senderName
        title = `Hi ${payload.targetName}`
        message = `${senderName} wants to connect with you.`
        senderLogoUrl = payload.senderLogoUrl
        return (
          <Container>
            <StatusBar
              barStyle={barStyleDark}
              animated={true}
              backgroundColor={color.bg.fifth.color}
            />
            <Request
              title={title}
              message={message}
              senderLogoUrl={senderLogoUrl}
              onAction={this.onAction}
              testID={'invitation'}
              navigation={navigation}
              showErrorAlerts={showErrorAlerts}
              invitationError={invitation.error}
              senderName={senderName}
            />
            {this.state.loading && (
              <CustomModal
                testID={'invitation'}
                isVisible={this.state.loading}
                fullScreen
              >
                <CustomView center style={[{ height: '90%' }]}>
                  <CustomText
                    h5
                    center
                    tertiary
                    bg="tertiary"
                    transparentBg
                    style={[{ marginBottom: OFFSET_1X / 2 }]}
                    bold
                  >
                    Connecting...
                  </CustomText>
                  <Loader />
                </CustomView>
              </CustomModal>
            )}
          </Container>
        )
      }
    }
    return <Container />
  }
}

const mapStateToProps = (state: Store, { navigation }: ReactNavigation) => {
  const senderDID = navigation.state ? navigation.state.params.senderDID : ''
  const smsToken = navigation.state ? navigation.state.params.token : null
  const isSmsInvitationNotSeen =
    smsToken &&
    state.smsPendingInvitation[smsToken] &&
    state.smsPendingInvitation[smsToken].status !==
      SMSPendingInvitationStatus.SEEN
  return {
    invitation: state.invitation[senderDID],
    showErrorAlerts: state.config.showErrorAlerts,
    smsToken,
    isSmsInvitationNotSeen,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    { sendInvitationResponse, invitationRejected, smsPendingInvitationSeen },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(Invitation)


<|start_filename|>app/eula/__test__/eula.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import { EulaScreen } from '../eula'
import { getNavigation, getStore } from '../../../__mocks__/static-data'

describe('Eula screen', () => {
  const navigation = getNavigation()
  const store = getStore()

  it('should render properly and snapshot should match', () => {
    const eula = {
      isEulaAccept: false,
    }
    const tree = renderer
      .create(
        <Provider store={store}>
          <EulaScreen eula={eula} navigation={navigation} />
        </Provider>
      )
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/store/connections-store.js<|end_filename|>
// @flow
import {
  put,
  takeLatest,
  takeEvery,
  call,
  select,
  all,
} from 'redux-saga/effects'
import { secureSet, secureDelete, getHydrationItem } from '../services/storage'
import { CONNECTIONS } from '../common'
import {
  getAgencyUrl,
  getAgencyVerificationKey,
  getUserOneTimeInfo,
  getPoolConfig,
  getAllConnection,
  getThemes,
  getConnection as getConnectionBySenderDid,
} from './store-selector'
import { color } from '../common/styles/constant'
import { bubbleSize } from '../common/styles'
import type { CustomError, GenericObject } from '../common/type-common'
import type {
  ConnectionStore,
  Connection,
  Connections,
  ConnectionThemes,
} from './type-connection-store'
import {
  NEW_CONNECTION,
  DELETE_CONNECTION_SUCCESS,
  DELETE_CONNECTION_FAILURE,
  DELETE_CONNECTION,
  STORAGE_KEY_THEMES,
  HYDRATE_CONNECTION_THEMES,
} from './type-connection-store'
import type {
  DeleteConnectionSuccessEventAction,
  DeleteConnectionFailureEventAction,
  DeleteConnectionEventAction,
} from './type-connection-store'
import {
  deleteConnection,
  getHandleBySerializedConnection,
} from '../bridge/react-native-cxs/RNCxs'
import { RESET } from '../common/type-common'
import type { UserOneTimeInfo } from './user/type-user-store'
import { promptBackupBanner } from '../backup/backup-store'
import { HYDRATED } from './type-config-store'
import { captureError } from '../services/error/error-handler'

const UPDATE_CONNECTION_THEME = 'UPDATE_CONNECTION_THEME'
export const NEW_CONNECTION_SUCCESS = 'NEW_CONNECTION_SUCCESS'
export const UPDATE_STATUS_BAR_THEME = 'UPDATE_STATUS_BAR_THEME'
const NEW_CONNECTION_FAIL = 'NEW_CONNECTION_FAIL'
const HYDRATE_CONNECTIONS = 'HYDRATE_CONNECTIONS'

const initialState: ConnectionStore = {
  data: {},
  isFetching: false,
  isPristine: true,
  connectionThemes: {
    default: {
      primary: `rgba(${color.actions.button.primary.rgba})`,
      secondary: `rgba(${color.actions.button.secondary.rgba})`,
    },
  },
  claimMap: null,
  error: {
    code: '',
    message: '',
  },
  hydrated: false,
}

// TODO:KS As of now we have added flow to this file and only checking imports
// but we need to fix all any types. I will do that once claims are done

export const connectionMapper = ({
  logoUrl,
  size = bubbleSize.XL,
  senderName = 'Unknown',
  ...otherArgs
}: GenericObject) => ({
  logoUrl,
  size,
  senderName,
  ...otherArgs,
})

export const updateConnectionTheme = (
  logoUrl: string,
  primaryColor: string,
  secondaryColor: string
) => ({
  type: UPDATE_CONNECTION_THEME,
  logoUrl,
  primaryColor,
  secondaryColor,
})

export const saveNewConnection = (connection: GenericObject) => ({
  type: NEW_CONNECTION,
  connection,
})

export const saveNewConnectionSuccess = (connection: GenericObject) => ({
  type: NEW_CONNECTION_SUCCESS,
  connection,
})

//TODO refactor create a new store for ui
export const updateStatusBarTheme = (statusColor?: string) => ({
  type: UPDATE_STATUS_BAR_THEME,
  color: statusColor || color.bg.tertiary.color,
})

export const saveNewConnectionFailed = (error: CustomError) => ({
  type: NEW_CONNECTION_FAIL,
  error,
})

export const deleteConnectionAction = (
  senderDID: string
): DeleteConnectionEventAction => ({
  type: DELETE_CONNECTION,
  senderDID,
})

export function* deleteConnectionOccurredSaga(
  action: DeleteConnectionEventAction
): Generator<*, *, *> {
  const connections: GenericObject = yield select(getAllConnection)

  const [connection]: Array<Connection> = yield select(
    getConnectionBySenderDid,
    action.senderDID
  )
  const { [connection.myPairwiseDid]: deleted, ...rest } = connections

  const connectionHandle = yield call(
    getHandleBySerializedConnection,
    connection.vcxSerializedConnection
  )

  try {
    yield call(secureSet, CONNECTIONS, JSON.stringify(rest))
    yield put(deleteConnectionSuccess(rest))
    yield call(deleteConnection, connectionHandle)
  } catch (e) {
    captureError(e)
    yield put(deleteConnectionFailure(connection, e))
  }
}

export function* watchDeleteConnectionOccurred(): any {
  yield takeLatest(DELETE_CONNECTION, deleteConnectionOccurredSaga)
}

export function* loadNewConnectionSaga(
  action: GenericObject
): Generator<*, *, *> {
  const {
    identifier,
    logoUrl,
    senderDID,
    senderEndpoint,
    senderName,
    myPairwiseDid,
    myPairwiseVerKey,
    myPairwiseAgentDid,
    myPairwiseAgentVerKey,
    myPairwisePeerVerKey,
    vcxSerializedConnection,
  }: Connection = action.connection.newConnection

  try {
    const connection = {
      identifier,
      logoUrl,
      senderDID,
      senderEndpoint,
      senderName,
      myPairwiseDid,
      myPairwiseVerKey,
      myPairwiseAgentDid,
      myPairwiseAgentVerKey,
      myPairwisePeerVerKey,
      vcxSerializedConnection,
    }

    yield put(promptBackupBanner(true))
    yield put(saveNewConnectionSuccess(connection))
    yield* persistConnections()
  } catch (e) {
    yield put(saveNewConnectionFailed(e))
  }
}

export function* watchNewConnection(): any {
  yield takeEvery(NEW_CONNECTION, loadNewConnectionSaga)
}

export function* persistConnections(): Generator<*, *, *> {
  try {
    const connections = yield select(getAllConnection)
    yield call(secureSet, CONNECTIONS, JSON.stringify(connections))
  } catch (e) {
    captureError(e)
    console.log(`hydrateConnectionSaga: ${e}`)
  }
}

export const hydrateConnections = (connections: Connections) => ({
  type: HYDRATE_CONNECTIONS,
  connections,
})

export function* hydrateConnectionSaga(): Generator<*, *, *> {
  try {
    const connections = yield call(getHydrationItem, CONNECTIONS)
    if (connections) {
      yield put(hydrateConnections(JSON.parse(connections)))
    }
  } catch (e) {
    // to capture secure get
    captureError(e)
    console.log(`hydrateConnectionSaga: ${e}`)
  }
}

export const getConnections = (connectionsData: ?Connections) =>
  connectionsData ? Object.values(connectionsData) : []

export const getConnection = (
  remoteConnectionId: string,
  connections: Connections
) =>
  Object.values(connections).filter(function(c: any) {
    return c.remoteConnectionId === remoteConnectionId
  })

export const getConnectionLogo = (logoUrl: ?string) =>
  logoUrl ? { uri: logoUrl } : require('../images/logo_sovrin.png')

export const deleteConnectionSuccess = (
  filteredConnections: Connections
): DeleteConnectionSuccessEventAction => ({
  type: DELETE_CONNECTION_SUCCESS,
  filteredConnections,
})

export const deleteConnectionFailure = (
  connection: Connection,
  error: CustomError
): DeleteConnectionFailureEventAction => ({
  type: DELETE_CONNECTION_FAILURE,
  connection,
  error,
})

export const hydrateConnectionThemes = (themes: ConnectionThemes) => ({
  type: HYDRATE_CONNECTION_THEMES,
  themes,
})

export function* persistThemes(): Generator<*, *, *> {
  const themes = yield select(getThemes)
  try {
    yield call(secureSet, STORAGE_KEY_THEMES, JSON.stringify(themes))
  } catch (e) {
    // capture error for secure set
    captureError(e)
    console.error(`persistThemes: ${e}`)
  }
}

export function* hydrateThemes(): Generator<*, *, *> {
  try {
    const themes = yield call(getHydrationItem, STORAGE_KEY_THEMES)
    if (themes) {
      yield put(hydrateConnectionThemes(JSON.parse(themes)))
    }
  } catch (e) {
    // capture error for secure get
    captureError(e)
    console.error(`hydrateThemes: ${e}`)
  }
}

export function* removePersistedThemes(): Generator<*, *, *> {
  try {
    yield call(secureDelete, STORAGE_KEY_THEMES)
  } catch (e) {
    // capture error for secure delete
    captureError(e)
    console.error(`removePersistedThemes: ${e}`)
  }
}

export function* watchUpdateConnectionTheme(): any {
  yield takeLatest(UPDATE_CONNECTION_THEME, persistThemes)
}

export function* watchConnection(): any {
  yield all([
    watchDeleteConnectionOccurred(),
    watchNewConnection(),
    watchUpdateConnectionTheme(),
  ])
}

export default function connections(
  state: ConnectionStore = initialState,
  action: any
) {
  switch (action.type) {
    case UPDATE_CONNECTION_THEME:
      return {
        ...state,
        connectionThemes: {
          ...state.connectionThemes,
          [action.logoUrl]: {
            primary: action.primaryColor,
            secondary: action.secondaryColor,
          },
        },
      }
    case HYDRATE_CONNECTION_THEMES:
      return {
        ...state,
        connectionThemes: {
          ...state.connectionThemes,
          ...action.themes,
        },
      }
    case NEW_CONNECTION:
      return {
        ...state,
        isFetching: true,
        isPristine: false,
        error: initialState.error,
      }
    case NEW_CONNECTION_SUCCESS:
      const { connection, connection: { identifier } } = action
      return {
        ...state,
        isFetching: false,
        data: {
          ...state.data,
          [identifier]: connectionMapper(connection),
        },
      }
    case NEW_CONNECTION_FAIL:
      return {
        ...state,
        isFetching: false,
        error: action.error,
      }
    case DELETE_CONNECTION_SUCCESS:
      const filteredData = { ...action.filteredConnections }
      return {
        ...state,
        data: filteredData,
      }
    case UPDATE_STATUS_BAR_THEME:
      return {
        ...state,
        statusBarTheme: action.color,
      }
    case HYDRATE_CONNECTIONS:
      return {
        ...state,
        data: action.connections,
      }
    case HYDRATED:
      return {
        ...state,
        hydrated: true,
      }
    case RESET:
      return initialState
    default:
      return state
  }
}


<|start_filename|>app/common/styles/index.js<|end_filename|>
// @flow
export * from './constant'
export * from './tab-constants'


<|start_filename|>app/backup/type-backup.js<|end_filename|>
// @flow
import type { ReactNavigation } from '../common/type-common'
import type { CustomError } from '../common/type-common'
import type { IsValid } from '../components/input-control/type-input-control'

export type ReactNavigationBackup = {
  navigation: {
    navigate: (route: string, params?: any) => void,
    goBack: (route?: ?string) => void,
    state: {
      params: {
        recoveryPassphrase?: string,
        initialRoute: string,
      },
    },
  },
}

export type GenerateRecoveryPhraseProps = {
  generateRecoveryPhrase: () => void,
  recoveryPassphrase: Passphrase,
  recoveryStatus: $Keys<typeof BACKUP_STORE_STATUS>,
} & ReactNavigationBackup

export type GenerateRecoveryPhraseState = {
  chatBubbleDimensions: ChatBubbleDimensions,
}

export type ChatBubbleDimensions = {
  width: number,
  height: number,
  x: number,
  y: number,
}

export type PassphraseTextProps = {
  recoveryPassphrase: Passphrase,
  chatBubbleDimensions: ChatBubbleDimensions,
}

export type PassphraseErrorProps = {
  chatBubbleDimensions: ChatBubbleDimensions,
}

export type VerifyRecoveryPhraseProps = {
  recoveryPassphrase: Passphrase,
} & ReactNavigationBackup

export type VerifyRecoveryPhraseState = {
  error: boolean,
}

export type ExportBackupFileProps = {
  backupPath: string,
  backupStatus: string,
  exportBackup: () => void,
} & ReactNavigationBackup

export type BackupErrorProps = {
  updateStatusBarTheme: string => void,
  generateBackupFile: () => void,
} & ReactNavigationBackup

export type ExportBackupFileState = {
  submitButtonText: string,
}

export type BackupCompleteProps = {} & ReactNavigationBackup

export type BackupCompleteState = {
  submitButtonText: string,
  recoveryPassphrase: string,
}

export const PREPARE_BACK_IDLE = 'PREPARE_BACKUP_IDLE'
export const PREPARE_BACKUP_LOADING = 'PREPARE_BACKUP_LOADING'
export const PREPARE_BACKUP_SUCCESS = 'PREPARE_BACKUP_SUCCESS'
export const PREPARE_BACKUP_FAILURE = 'PREPARE_BACKUP_FAILURE'

export const BACKUP_STORE_STATUS = {
  IDLE: 'IDLE',
  GENERATE_PHRASE_LOADING: 'GENERATE_PHRASE_LOADING',
  GENERATE_PHRASE_SUCCESS: 'GENERATE_PHRASE_SUCCESS',
  GENERATE_PHRASE_FAILURE: 'GENERATE_PHRASE_FAILURE',
  GENERATE_BACKUP_FILE_LOADING: 'GENERATE_BACKUP_FILE_LOADING',
  GENERATE_BACKUP_FILE_SUCCESS: 'GENERATE_BACKUP_FILE_SUCCESS',
  GENERATE_BACKUP_FILE_FAILURE: 'GENERATE_BACKUP_FILE_FAILURE',
  PREPARE_BACKUP_LOADING,
  PREPARE_BACKUP_SUCCESS,
  PREPARE_BACKUP_FAILURE,
  PREPARE_BACK_IDLE,
  EXPORT_BACKUP_LOADING: 'EXPORT_BACKUP_LOADING',
  EXPORT_BACKUP_SUCCESS: 'EXPORT_BACKUP_SUCCESS',
  EXPORT_BACKUP_FAILURE: 'EXPORT_BACKUP_FAILURE',
  EXPORT_BACKUP_NO_SHARE: 'EXPORT_BACKUP_NO_SHARE',
  BACKUP_COMPLETE: 'BACKUP_COMPLETE',
}

export type Passphrase = {
  phrase: string,
  salt: string,
  hash: string,
}

export type PrepareBackupStatus =
  | typeof PREPARE_BACK_IDLE
  | typeof PREPARE_BACKUP_LOADING
  | typeof PREPARE_BACKUP_SUCCESS
  | typeof PREPARE_BACKUP_FAILURE

export type BackupStore = {
  passphrase: Passphrase,
  backupWalletPath: string,
  showBanner: boolean,
  lastSuccessfulBackup: string,
  // TODO: fix flow type
  error: any,
  status: string,
  prepareBackupStatus: PrepareBackupStatus,
}

export type StoreError = { error: ?CustomError }
export type BackupStoreStatus = { status: $Keys<typeof BACKUP_STORE_STATUS> }

export const ERROR_EXPORT_BACKUP = {
  code: 'WB-001',
  message: 'Error while exporting backup file',
}

export const ERROR_GENERATE_BACKUP_FILE = {
  code: 'WB-002',
  message: 'Error while generating backup file',
}

export const ERROR_GENERATE_RECOVERY_PHRASE = {
  code: 'WB-003',
  message: 'Error while generating recovery phrase',
}

export const ERROR_HYDRATING_BACKUP = {
  code: 'WB-004',
  message: 'Error hydrating backup',
}

export const START_BACKUP = 'START_BACKUP'
export const GENERATE_BACKUP_FILE_LOADING = 'GENERATE_BACKUP_FILE_LOADING'
export const GENERATE_BACKUP_FILE_SUCCESS = 'GENERATE_BACKUP_FILE_SUCCESS'
export const GENERATE_BACKUP_FILE_FAILURE = 'GENERATE_BACKUP_FILE_FAILURE'
export const BACKUP_WALLET_FAIL = 'BACKUP_WALLET_FAIL'
export const GENERATE_RECOVERY_PHRASE_LOADING =
  'GENERATE_RECOVERY_PHRASE_LOADING'
export const GENERATE_RECOVERY_PHRASE_SUCCESS =
  'GENERATE_RECOVERY_PHRASE_SUCCESS'
export const GENERATE_RECOVERY_PHRASE_FAILURE =
  'GENERATE_RECOVERY_PHRASE_FAILURE'
export const EXPORT_BACKUP_LOADING = 'EXPORT_BACKUP_LOADING'
export const EXPORT_BACKUP_SUCCESS = 'EXPORT_BACKUP_SUCCESS'
export const EXPORT_BACKUP_FAILURE = 'EXPORT_BACKUP_FAILURE'
export const EXPORT_BACKUP_NO_SHARE = 'EXPORT_BACKUP_NO_SHARE'
export const BACKUP_COMPLETE = 'BACKUP_COMPLETE'
export const HYDRATE_BACKUP = 'HYDRATE_BACKUP'
export const HYDRATE_BACKUP_FAILURE = 'HYDRATE_BACKUP_FAILURE'
export const PROMPT_WALLET_BACKUP_BANNER = 'PROMPT_WALLET_BACKUP_BANNER'
export const WALLET_FILE_NAME = 'ConnectMe'

export type BackupStartAction = {
  type: typeof START_BACKUP,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  error: CustomError,
}

export type GenerateBackupFileLoadingAction = {
  type: typeof GENERATE_BACKUP_FILE_LOADING,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type GenerateBackupFileSuccessAction = {
  type: typeof GENERATE_BACKUP_FILE_SUCCESS,
  backupWalletPath: string,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type GenerateBackupFileFailureAction = {
  type: typeof GENERATE_BACKUP_FILE_FAILURE,
  error: CustomError,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type BackupWalletFailAction = {
  type: typeof BACKUP_WALLET_FAIL,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  error: CustomError,
}

export type GenerateRecoveryPhraseLoadingAction = {
  type: typeof GENERATE_RECOVERY_PHRASE_LOADING,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type GenerateRecoveryPhraseSuccessAction = {
  type: typeof GENERATE_RECOVERY_PHRASE_SUCCESS,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  passphrase: <PASSWORD>,
  error: CustomError,
}

export type GenerateRecoveryPhraseFailureAction = {
  type: typeof GENERATE_RECOVERY_PHRASE_FAILURE,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  error: CustomError,
}

export type ExportBackupLoadingAction = {
  type: typeof EXPORT_BACKUP_LOADING,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  backupWalletPath: string,
}

export type PrepareBackupLoadingAction = {
  type: typeof PREPARE_BACKUP_LOADING,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type ExportBackupNoShareAction = {
  type: typeof EXPORT_BACKUP_NO_SHARE,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type ExportBackupSuccessAction = {
  type: typeof EXPORT_BACKUP_SUCCESS,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  lastSuccessfulBackup: string,
}

export type ExportBackupFailureAction = {
  type: typeof EXPORT_BACKUP_FAILURE,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  error: CustomError,
}

export type BackupCompleteAction = {
  type: typeof BACKUP_COMPLETE,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type HydrateBackupAction = {
  type: typeof HYDRATE_BACKUP,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
  lastSuccessfulBackup: string,
}

export type HydrateBackupFailAction = {
  type: typeof HYDRATE_BACKUP_FAILURE,
  error: CustomError,
}

export type PromptBackupBannerAction = {
  type: typeof PROMPT_WALLET_BACKUP_BANNER,
  showBanner: boolean,
}

export type PrepareBackupSuccessAction = {
  type: typeof PREPARE_BACKUP_SUCCESS,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type PrepareBackupFailureAction = {
  type: typeof PREPARE_BACKUP_FAILURE,
  status: $Keys<typeof BACKUP_STORE_STATUS>,
}

export type BackupStoreAction =
  | BackupStartAction
  | GenerateBackupFileLoadingAction
  | GenerateBackupFileSuccessAction
  | BackupWalletFailAction
  | GenerateRecoveryPhraseLoadingAction
  | GenerateRecoveryPhraseSuccessAction
  | GenerateBackupFileFailureAction
  | PrepareBackupLoadingAction
  | ExportBackupLoadingAction
  | ExportBackupSuccessAction
  | ExportBackupFailureAction
  | ExportBackupNoShareAction
  | BackupCompleteAction
  | HydrateBackupAction
  | HydrateBackupFailAction
  | PrepareBackupSuccessAction
  | PrepareBackupFailureAction


<|start_filename|>app/switch-environment/switch-environment.js<|end_filename|>
//@flow
import React, { PureComponent } from 'react'
import { TouchableHighlight, Image, StyleSheet, TextInput } from 'react-native'
import { Container, CustomView, CustomText, CustomButton } from '../components'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import type { Store } from '../store/type-store'
import { FooterActions } from '../components'
import {
  color,
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_6X,
  OFFSET_7X,
} from '../common/styles'
import { switchEnvironmentRoute, lockSelectionRoute } from '../common'
import { changeEnvironment } from '../store/config-store'
import { disableDevMode } from '../lock/lock-store'
import type {
  SwitchEnvironmentState,
  SwitchEnvironmentProps,
} from './type-switch-environment'
import { baseUrls } from '../store/config-store'
import { SERVER_ENVIRONMENT } from '../store/type-config-store'

const styles = StyleSheet.create({
  TextInput: {
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    marginHorizontal: OFFSET_1X,
    marginBottom: OFFSET_2X,
  },
  label: {
    marginHorizontal: OFFSET_1X,
  },
})

class SwitchEnvironment extends PureComponent<
  SwitchEnvironmentProps,
  SwitchEnvironmentState
> {
  state = {
    agencyDID: '',
    agencyVerificationKey: '',
    agencyUrl: '',
    poolConfig: '',
  }

  onSave = () => {
    const {
      agencyDID,
      agencyVerificationKey,
      agencyUrl,
      poolConfig,
    } = this.state

    this.props.changeEnvironment(
      agencyUrl,
      agencyDID,
      agencyVerificationKey,
      poolConfig
    )
    this.props.navigation.goBack()
  }

  onCancel = () => {
    this.props.navigation.goBack()
  }

  componentDidMount() {
    const {
      agencyDID,
      agencyUrl,
      agencyVerificationKey,
      disableDevMode,
      poolConfig,
    } = this.props
    disableDevMode()
    this.setState({ agencyDID, agencyUrl, agencyVerificationKey, poolConfig })
  }

  onSwitchTap = (environment: string) => {
    this.setState(baseUrls[environment])
  }

  render() {
    const testID = 'switch-environment'
    return (
      <Container>
        <Container>
          <CustomView row style={[style.buttonGroup]}>
            <CustomButton
              primary
              title="DEV"
              testID={`${testID}-dev`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.DEVELOPMENT)}
            />
            <CustomButton
              primary
              title="SANDBOX"
              testID={`${testID}-sandbox`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.SANDBOX)}
            />
            <CustomButton
              primary
              title="STAGING"
              testID={`${testID}-staging`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.STAGING)}
            />
            <CustomButton
              primary
              title="DEMO"
              testID={`${testID}-demo`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.DEMO)}
            />
          </CustomView>
          <CustomView row style={[style.buttonGroup]}>
            <CustomButton
              primary
              title="QATest1"
              testID={`${testID}-QATest1`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.QATEST1)}
            />
            <CustomButton
              primary
              title="QATest2"
              testID={`${testID}-QATest2`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.QATEST2)}
            />
            <CustomButton
              primary
              title="DEV-RC"
              testID={`${testID}-DEV-RC`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.DEVRC)}
            />
            <CustomButton
              primary
              title="QA-RC"
              testID={`${testID}-QA-RC`}
              onPress={() => this.onSwitchTap(SERVER_ENVIRONMENT.QARC)}
            />
          </CustomView>
          <CustomText
            h7
            uppercase
            bold
            bg="tertiary"
            transparentBg
            style={styles.label}
          >
            {'Agency URL'}
          </CustomText>
          <TextInput
            style={styles.TextInput}
            onChangeText={agencyUrl => this.setState({ agencyUrl })}
            value={this.state.agencyUrl}
            testID="text-input-agencyUrl"
          />
          <CustomText
            h7
            uppercase
            bold
            bg="tertiary"
            transparentBg
            style={styles.label}
          >
            {'Agency DID'}
          </CustomText>
          <TextInput
            style={styles.TextInput}
            onChangeText={agencyDID => this.setState({ agencyDID })}
            value={this.state.agencyDID}
            testID="text-input-agencyDID"
          />
          <CustomText
            h7
            uppercase
            bold
            bg="tertiary"
            transparentBg
            style={styles.label}
          >
            {'Agency VerKey'}
          </CustomText>
          <TextInput
            style={styles.TextInput}
            onChangeText={agencyVerificationKey =>
              this.setState({ agencyVerificationKey })
            }
            value={this.state.agencyVerificationKey}
            testID="text-input-agencyVerificationKey"
          />
          <CustomText
            h7
            uppercase
            bold
            bg="tertiary"
            transparentBg
            style={styles.label}
          >
            {'Pool Config'}
          </CustomText>
          <TextInput
            style={styles.TextInput}
            onChangeText={poolConfig => this.setState({ poolConfig })}
            value={this.state.poolConfig}
            testID="text-input-poolConfig"
          />
        </Container>
        <FooterActions
          onAccept={this.onSave}
          onDecline={this.onCancel}
          denyTitle="Cancel"
          acceptTitle="Save"
          testID={`${testID}-footer`}
        />
      </Container>
    )
  }
}

const mapStateToProps = ({ config }: Store) => {
  return {
    agencyUrl: config.agencyUrl,
    agencyDID: config.agencyDID,
    agencyVerificationKey: config.agencyVerificationKey,
    poolConfig: config.poolConfig,
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      changeEnvironment,
      disableDevMode,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(SwitchEnvironment)

const style = StyleSheet.create({
  buttonGroup: {
    marginTop: 20,
    marginLeft: 10,
    marginRight: 10,
    justifyContent: 'space-between',
  },
})


<|start_filename|>app/components/request/request-detail.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Container, CustomText, CustomView } from '../../components'
import RequestDetailText from './request-detail-text'
import RequestDetailAvatars from './request-detail-avatars'
import type { RequestDetailProps } from './type-request'

export default class RequestDetail extends PureComponent<
  RequestDetailProps,
  void
> {
  render() {
    const { testID } = this.props
    return (
      <Container useNativeDriver hCenter testID={`${testID}-text-container`}>
        <Container bottom testID={`${testID}-text-message-container`}>
          <RequestDetailText
            title={this.props.title}
            message={this.props.message}
            testID={testID}
          />
        </Container>
        <Container testID={`${testID}-text-container-avatars`}>
          <RequestDetailAvatars senderLogoUrl={this.props.senderLogoUrl} />
        </Container>
      </Container>
    )
  }
}


<|start_filename|>app/privacy-tnc/privacy-tnc-screen.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Image, WebView, View } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { createStackNavigator } from 'react-navigation'
import {
  Container,
  CustomText,
  CustomView,
  Icon,
  CustomHeader,
} from '../components'
import {
  color,
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_4X,
  OFFSET_6X,
  OFFSET_7X,
} from '../common/styles'
import { tertiaryHeaderStyles } from '../components/layout/header-styles'
import type { PrivacyTNCProps, PrivacyTNCState } from './type-privacy-tnc'
import {
  TermsAndConditionsTitle,
  TermsAndConditionUrl,
  PrivacyPolicyTitle,
  PrivacyPolicyUrl,
  localPrivacyPolicySource,
} from '../common/privacyTNC-constants'
import { LoaderGif } from '../components/loader-gif/loader-gif'
import type { CustomError } from '../common/type-common'
import { localEulaSource } from '../eula/type-eula'

const styles = StyleSheet.create({
  headerLeft: {
    width: OFFSET_2X,
  },
})

export class PrivacyTNC extends PureComponent<
  PrivacyTNCProps,
  PrivacyTNCState
> {
  static INFO_TYPE = {
    PRIVACY: { url: PrivacyPolicyUrl, title: PrivacyPolicyTitle },
    TNC: { url: TermsAndConditionUrl, title: TermsAndConditionsTitle },
  }

  static navigationOptions = ({ navigation }) => ({
    header: (
      <CustomHeader
        flatHeader
        backgroundColor={color.bg.tertiary.color}
        leftComponent={
          <Icon
            small
            testID={'back-arrow'}
            iconStyle={[styles.headerLeft]}
            src={require('../images/icon_backArrow.png')}
            resizeMode="contain"
            onPress={() => navigation.goBack()}
          />
        }
        centerComponent={
          <CustomText bg="tertiary" tertiary transparentBg semiBold>
            {navigation.state.params.title}
          </CustomText>
        }
      />
    ),
    swipeEnabled: false,
  })

  state = {
    error: null,
  }

  onError = (error: CustomError) => {
    this.setState({ error })
  }

  render() {
    let webViewUri = this.props.navigation.state.params.url
    const isTNC = webViewUri === PrivacyTNC.INFO_TYPE.TNC.url

    if (this.state.error) {
      webViewUri = isTNC ? localEulaSource : localPrivacyPolicySource
    }

    return (
      <WebView
        source={{ uri: webViewUri }}
        startInLoadingState={true}
        renderLoading={() => LoaderGif}
        onError={this.onError}
        renderError={() => <View />}
      />
    )
  }
}

export default PrivacyTNC


<|start_filename|>app/restore/__tests__/restore-store.spec.js<|end_filename|>
// @flow

import { RestoreStatus, ERROR_RESTORE_FILE } from '../type-restore'
import { getStore } from '../../../__mocks__/static-data'
import restoreReducer, {
  saveFileToAppDirectory,
  submitPassphrase,
  restoreStatus,
  errorRestore,
} from '../restore-store'

describe('store: backup-store: ', () => {
  let initialState
  beforeEach(() => {
    initialState = {
      status: RestoreStatus.none,
      error: null,
      passphrase: '',
      restoreFile: {
        fileName: '',
        fileSize: 0,
        type: '',
        uri: '',
      },
    }
  })
  const { restoreFile } = getStore().getState().restore
  const dataStore = getStore().getState()
  const passphrase = '<PASSWORD>'
  const salt = '<PASSWORD>'
  it('action: SAVE_FILE_TO_APP_DIRECTORY', () => {
    expect(
      restoreReducer(initialState, saveFileToAppDirectory(restoreFile))
    ).toMatchSnapshot()
  })
  it('action: RESTORE_SUBMIT_PASSPHRASE', () => {
    expect(
      restoreReducer(initialState, submitPassphrase(passphrase))
    ).toMatchSnapshot()
  })
  it('action: RESTORE_STATUS', () => {
    expect(
      restoreReducer(initialState, restoreStatus(RestoreStatus.success))
    ).toMatchSnapshot()
  })
  it('action: ERROR_RESTORE', () => {
    expect(
      restoreReducer(initialState, errorRestore(ERROR_RESTORE_FILE))
    ).toMatchSnapshot()
  })
})


<|start_filename|>connectMeUITest/src/appModules/LibIndy.java<|end_filename|>
package appModules;


import org.bitcoinj.core.Base58;
import org.hyperledger.indy.sdk.signus.Signus;
import org.hyperledger.indy.sdk.signus.SignusJSONParameters;
import org.hyperledger.indy.sdk.signus.SignusResults.CreateAndStoreMyDidResult;
import org.hyperledger.indy.sdk.wallet.Wallet;

import utility.InMemWalletType;
import utility.InitHelper;
import utility.StorageUtils;


public class LibIndy {
	
	public static final String TRUSTEE_SEED = "000000000000000000000000Trustee1";
	public static final String MY1_SEED = "00000000000000000000000000000My1";
	private Wallet wallet;
	private String walletName = "signusWallet";
//	protected HashSet<Pool> openedPools = new HashSet<>();
	private static Boolean isWalletRegistered = false;
	private byte[] msg;
	public static String v1;
	public static String signature1;
	public static String did2;
	public static String signature2;

	
	public String[] createMyDid() throws Exception {
		InitHelper.init();
		StorageUtils.cleanupStorage();
		if (!isWalletRegistered){
			Wallet.registerWalletType("inmem", new InMemWalletType()).get();
		}
		isWalletRegistered = true;
		Wallet.createWallet("default", walletName, "default", null, null).get();
		this.wallet = Wallet.openWallet(walletName, null, null).get();
		SignusJSONParameters.CreateAndStoreMyDidJSONParameter didJson =
		new SignusJSONParameters.CreateAndStoreMyDidJSONParameter(null, null, null, null);
		CreateAndStoreMyDidResult result = Signus.createAndStoreMyDid(this.wallet, didJson.toJson()).get();
		String verKey=result.getVerkey();
		String did=result.getDid();
		 
	   byte[] msg1 = "{\"requesterName\":\"Ankur\"}".getBytes();
		//Signature2=Base58.encode(Signus.sign(this.wallet, result.getDid(), msg1).get());
		//System.out.println(DID2);
		this.wallet.closeWallet().get();
		Wallet.deleteWallet(walletName, null).get();
        String[] Result={ verKey,did};
        return Result;
		
	}
	
	public void signWithSeed(String seed ) throws Exception {
		InitHelper.init();
		seed="agencyea000000000000000000000000";
		StorageUtils.cleanupStorage();
		if (!isWalletRegistered){
			Wallet.registerWalletType("inmem", new InMemWalletType()).get();
		}
		isWalletRegistered = true;
		Wallet.createWallet("default", walletName, "default", null, null).get();
		this.wallet = Wallet.openWallet(walletName, null, null).get();
		SignusJSONParameters.CreateAndStoreMyDidJSONParameter didJson =
		new SignusJSONParameters.CreateAndStoreMyDidJSONParameter(null, seed, null, null);
     	CreateAndStoreMyDidResult result = Signus.createAndStoreMyDid(this.wallet, didJson.toJson()).get();
		//String s1 = "{\"verKey\":\""+V1+"\",\"targetHostDID\":\"MbVrbbVfvu7duSJWG6XxwR\",\"phoneNumber\":\"8327364896\",\"pairwiseDID\":\""+DID+"\"}";
       // msg=s1.getBytes();
     	byte[] signature = Signus.sign(this.wallet, result.getDid(), msg).get();
	    signature1=Base58.encode(signature);
	    this.wallet.closeWallet().get();
		Wallet.deleteWallet(walletName, null).get();

}
	
}


<|start_filename|>app/proof-request/__tests__/proof-request-store.spec.js<|end_filename|>
// @flow
import { put, call, select } from 'redux-saga/effects'
import { delay } from 'redux-saga'
import proofRequestStore, {
  proofRequestReceived,
  ignoreProofRequest,
  rejectProofRequest,
  acceptProofRequest,
  proofRequestShown,
  sendProof,
  sendProofSuccess,
  sendProofFail,
  proofAccepted,
  convertMissingAttributeListToObject,
  missingAttributesFound,
  proofRequestAutoFill,
  proofRequestShowStart,
} from '../proof-request-store'
import { INITIAL_TEST_ACTION } from '../../common/type-common'
import {
  getProofRequestPairwiseDid,
  getUserPairwiseDid,
  getAgencyUrl,
  getProof,
  getUserOneTimeInfo,
  getAgencyVerificationKey,
  getRemotePairwiseDidAndName,
  getPoolConfig,
} from '../../store/store-selector'

import { MESSAGE_TYPE } from '../../api/api-constants'
import {
  proofRequest,
  proofRequestId as uid,
  poolConfig,
  missingAttributes,
  missingAttributes1,
  fulfilledRequestedAttributes,
} from '../../../__mocks__/static-data'

describe('proof request store', () => {
  const initialAction = { type: 'INITIAL_TEST_ACTION' }
  let initialState = {}
  let newState

  it('should correctly calculate initial state', () => {
    initialState = proofRequestStore(undefined, initialAction)
    expect(initialState).toMatchSnapshot()
  })

  it('proof request is received', () => {
    newState = proofRequestStore(
      initialState,
      proofRequestReceived(proofRequest.payload, proofRequest.payloadInfo)
    )
    expect(newState).toMatchSnapshot()
  })

  it('proof request is shown', () => {
    newState = proofRequestStore(newState, proofRequestShown(uid))
    expect(newState).toMatchSnapshot()
  })

  it('proof request is ignored', () => {
    newState = proofRequestStore(newState, ignoreProofRequest(uid))
    expect(newState).toMatchSnapshot()
  })

  it('proof request is rejected', () => {
    newState = proofRequestStore(newState, rejectProofRequest(uid))
    expect(newState).toMatchSnapshot()
  })

  it('proof request is accepted', () => {
    newState = proofRequestStore(newState, acceptProofRequest(uid))
    expect(newState).toMatchSnapshot()
  })

  it('proof request is ignored', () => {
    newState = proofRequestStore(newState, ignoreProofRequest(uid))
    expect(newState).toMatchSnapshot()
  })

  it('sending proof', () => {
    newState = proofRequestStore(newState, sendProof(uid))
    expect(newState).toMatchSnapshot()
  })

  it('sending proof success', () => {
    newState = proofRequestStore(newState, sendProofSuccess(uid))
    expect(newState).toMatchSnapshot()
  })

  it('sending proof failed', () => {
    newState = proofRequestStore(
      newState,
      sendProofFail(uid, {
        code: 'OCS-002',
        message: 'No pairwise connection found',
      })
    )
    expect(newState).toMatchSnapshot()
  })

  it('ACTION: MISSING_ATTRIBUTES_FOUND', () => {
    expect(
      proofRequestStore(
        newState,
        missingAttributesFound(missingAttributes, uid)
      )
    ).toMatchSnapshot()
  })

  it('ACTION: PROOF_REQUEST_AUTO_FILL', () => {
    expect(
      proofRequestStore(
        newState,
        proofRequestAutoFill(uid, fulfilledRequestedAttributes)
      )
    ).toMatchSnapshot()
  })

  it('should convert missing attributes to self attested attributes', () => {
    expect(
      convertMissingAttributeListToObject(missingAttributes)
    ).toMatchSnapshot()
    expect(
      convertMissingAttributeListToObject(missingAttributes1)
    ).toMatchSnapshot()
  })

  it('should reset proof request store, if RESET action is raised', () => {
    expect(proofRequestStore(newState, { type: 'RESET' })).toMatchSnapshot()
  })

  it('ACTION: PROOF_REQUEST_SHOWN, after missing attributes were found', () => {
    const afterMissingAttributesState = proofRequestStore(
      newState,
      missingAttributesFound(missingAttributes, uid)
    )
    expect(
      proofRequestStore(newState, proofRequestShowStart(uid))
    ).toMatchSnapshot()
  })
})


<|start_filename|>app/wallet/wallet-tab-send-details.js<|end_filename|>
// @flow
import React, { Component } from 'react'
import { StyleSheet, Keyboard, Platform } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { createStackNavigator, NavigationActions } from 'react-navigation'
import { scale } from 'react-native-size-matters'
import {
  Container,
  CustomText,
  CustomView,
  CustomButton,
  CustomHeader,
  Icon,
  Loader,
} from '../components'
import { primaryHeaderStyles } from '../components/layout/header-styles'
import {
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_6X,
  OFFSET_7X,
  color,
  HAIRLINE_WIDTH,
  whiteSmokeSecondary,
} from '../common/styles/constant'
import ControlInput from '../components/input-control/input-control'
import type {
  WalletSendPaymentData,
  WalletTabSendDetailsProps,
  WalletTabSendDetailsState,
} from './type-wallet'
import { formatNumbers } from '../components/text'
import { receiveTabRoute } from '../common'
import { walletAddresses } from '../../__mocks__/static-data'
import {
  SEND_TOKENS_TO_PAYMENT_ADDRESS,
  FOR_SEND_DETAILS_TEST_ID,
  TO_SEND_DETAILS_TEST_ID,
  FONT_SIZE_MAPPING,
} from './wallet-constants'
import { sendTokens } from '../wallet/wallet-store'
import { getWalletAddresses, getTokenAmount } from '../store/store-selector'
import type { Store } from '../store/type-store'
import { STORE_STATUS } from './type-wallet'
import { CREDENTIAL_OFFER_MODAL_STATUS } from '../claim-offer/type-claim-offer'
import Modal from 'react-native-modal'
import PaymentFailureModal from './payment-failure-modal'
import CredentialOfferModal from './credential-offer-modal'

export class WalletTabSendDetails extends Component<
  WalletTabSendDetailsProps,
  WalletTabSendDetailsState
> {
  static navigationOptions = ({ navigation, screenProps }) => ({
    header: (
      <CustomHeader flatHeader backgroundColor={whiteSmokeSecondary}>
        <Icon
          testID={'back-arrow'}
          iconStyle={[styles.headerLeft]}
          src={require('../images/icon_backArrow.png')}
          resizeMode="contain"
          onPress={() => navigation.goBack(null)}
          small
        />

        <CustomText
          style={[{ color: color.bg.seventh.font.sixth }]}
          transparentBg
          h5
        >
          Pay Tokens
        </CustomText>

        <CustomText
          uppercase
          bold
          quinaryText
          transparentBg
          h5
          style={[navigation.state.params.isValid ? {} : styles.disabledText]}
          testID={SEND_TOKENS_TO_PAYMENT_ADDRESS}
          onPress={() => navigation.state.params.onSendTokens()}
        >
          Send
        </CustomText>
      </CustomHeader>
    ),
  })

  state = {
    showPaymentAddress: false,
    isPaymentAddressValid: 'IDLE',
    credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.NONE,
  }

  paymentData: WalletSendPaymentData = {
    paymentTo: '',
    paymentFor: '',
  }

  componentDidUpdate(prevProps: WalletTabSendDetailsProps) {
    if (this.props.tokenSentStatus !== prevProps.tokenSentStatus) {
      if (this.props.tokenSentStatus === STORE_STATUS.SUCCESS) {
        /*
          So, we have one operation to go back to tabs stack, and then another one to change tab to receiveTabRoute.

          Since we're using createTabNavigator inside inside of createStackNavigator
          and are then going to a different createStackNavigator, we use the goBack method and then the navigate method.

          For this to work, we are also passing navigator of tabs via state params and then navigating tabs stack as well.
        */
        this.props.navigation.goBack(null)
        this.props.navigation.state &&
          this.props.navigation.state.params.navigate(receiveTabRoute)
      } else if (this.props.tokenSentStatus === STORE_STATUS.ERROR) {
        this.setState({
          credentialOfferModalStatus:
            CREDENTIAL_OFFER_MODAL_STATUS.TOKEN_SENT_FAIL,
        })
      }
    }
  }

  componentDidMount() {
    this.props.navigation.setParams({
      onSendTokens: this.onSendTokens,
    })
  }

  onTextChange = (text: string, name: string) => {
    this.paymentData[name] = text
    if (this.paymentData['paymentTo'].length) {
      this.setState({
        showPaymentAddress: true,
      })
    } else {
      this.setState({
        showPaymentAddress: false,
      })
    }
  }

  onTokenSentFailedClose = () => {
    this.setState({
      credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.NONE,
    })
  }

  throttledAsyncValidationFunction = () => {
    let status = ''
    if (this.paymentData['paymentTo'].length > 20) {
      status = 'SUCCESS'
      this.props.navigation.setParams({ isValid: true })
    } else if (this.paymentData['paymentTo'].length <= 0) {
      status = 'IDLE'
      this.props.navigation.setParams({ isValid: false })
    } else {
      status = 'ERROR'
      this.props.navigation.setParams({ isValid: false })
    }
    this.setState({
      isPaymentAddressValid: status,
    })
  }

  onShowTransactionFeesModal() {
    this.setState({
      credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.LEDGER_FEES,
    })
  }

  onHideTransactionFeesModal = () => {
    this.setState({
      credentialOfferModalStatus: CREDENTIAL_OFFER_MODAL_STATUS.NONE,
    })
  }

  onStartTransfer = () => {
    this.onHideTransactionFeesModal()
    this.props.sendTokens(this.props.tokenAmount, this.paymentData.paymentTo)
  }

  onSendTokens = () => {
    this.onTokenSentFailedClose()
    if (this.state.isPaymentAddressValid === 'SUCCESS') {
      this.onShowTransactionFeesModal()
    }
  }

  render() {
    const testID = 'wallet-tab-send-details'
    const fontSize = scale(FONT_SIZE_MAPPING(this.props.tokenAmount.length))

    return (
      <Container safeArea fifth onPress={Keyboard.dismiss} testID={testID}>
        <ControlInput
          label="To"
          name="paymentTo"
          placeholder="Enter Payee wallet address"
          validation={this.throttledAsyncValidationFunction}
          onChangeText={this.onTextChange}
          isValid={this.state.isPaymentAddressValid}
          maxLength={100}
          autoCorrect={false}
          autoCapitalize="none"
          autoFocus={true}
        />
        <ControlInput
          label="For"
          name="paymentFor"
          multiline
          maxLength={80}
          placeholder="credential, gift, etc."
          onChangeText={this.onTextChange}
        />
        {this.props.tokenSentStatus === STORE_STATUS.IN_PROGRESS && (
          <CustomView center style={[styles.loaderContainer]}>
            <Loader showMessage={false} />
          </CustomView>
        )}
        <CustomView row center style={[{ width: '100%' }]} horizontalSpace>
          <CustomText
            quinaryText
            formatNumber
            transparentBg
            center
            style={[
              styles.tokenAmountText,
              {
                fontSize,
              },
            ]}
            fullWidth
          >
            {this.props.tokenAmount}
          </CustomText>
        </CustomView>
        <CustomView center>
          <CustomText transparentBg style={[styles.textSovrinTokens]}>
            SOVRIN TOKENS
          </CustomText>
        </CustomView>
        <CustomView center style={[{ marginTop: 36 }]}>
          <CustomView center style={[{ width: '65%' }]}>
            <CustomText transparentBg style={[styles.walletContextText]}>
              You are sending{' '}
              <CustomText transparentBg quinaryText>
                {formatNumbers(this.props.tokenAmount)}
              </CustomText>{' '}
              tokens to this wallet address:
            </CustomText>
          </CustomView>
        </CustomView>
        {this.state.showPaymentAddress ? (
          <CustomView center horizontalSpace>
            <CustomText
              center
              transparentBg
              primary
              style={[
                { marginTop: 10 },
                this.state.isPaymentAddressValid === 'SUCCESS'
                  ? styles.validTextColor
                  : styles.invalidTextColor,
              ]}
            >
              {this.paymentData.paymentTo}
            </CustomText>
          </CustomView>
        ) : (
          <CustomView center>
            <CustomText
              center
              transparentBg
              quinaryText
              style={[styles.walletAddressText]}
            >
              Enter wallet address above
            </CustomText>
          </CustomView>
        )}

        <CredentialOfferModal
          connectionName={this.paymentData.paymentTo}
          credentialOfferModalStatus={this.state.credentialOfferModalStatus}
          testID={`${testID}-payment-failure-modal`}
          onClose={this.onTokenSentFailedClose}
          onRetry={this.onSendTokens}
          onYes={this.onStartTransfer}
          onNo={this.onHideTransactionFeesModal}
          transferAmount={this.props.tokenAmount}
        />
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    marginHorizontal: OFFSET_3X,
  },
  innerContainer: {
    ...Platform.select({
      ios: {
        borderBottomColor: color.bg.fifth.font.tertiary,
        borderBottomWidth: HAIRLINE_WIDTH,
      },
      android: {
        borderBottomColor: color.bg.fifth.font.secondary,
        borderBottomWidth: 1,
      },
    }),
    padding: OFFSET_2X,
  },
  message: {
    marginBottom: OFFSET_1X / 2,
  },
  headerLeft: {
    width: OFFSET_2X,
  },
  title: {
    marginTop: OFFSET_6X,
    marginBottom: OFFSET_7X,
  },
  titleText: {
    lineHeight: 28,
    letterSpacing: 0.5,
    paddingHorizontal: OFFSET_1X,
  },
  invalidTextColor: {
    color: color.bg.tenth.font.color,
  },
  validTextColor: {
    color: color.bg.eighth.color,
  },
  walletAddressText: {
    fontSize: 14,
    flexWrap: 'wrap',
    lineHeight: 16,
    marginTop: 11,
    marginBottom: 15,
  },
  walletContextText: {
    textAlign: 'center',
    fontSize: 14,
    lineHeight: 18,
    color: color.bg.seventh.font.sixth,
    letterSpacing: -0.35,
  },
  textSovrinTokens: {
    fontSize: 18,
    color: color.bg.seventh.font.seventh,
  },
  tokenAmountText: {
    marginTop: 19,
  },
  disabledText: {
    color: color.bg.eighth.disabled,
  },
  loaderContainer: {
    height: 40,
  },
})

const mapStateToProps = (state: Store) => ({
  tokenAmount: getTokenAmount(state),
  tokenSentStatus: state.wallet.payment.status,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators({ sendTokens }, dispatch)

export default createStackNavigator({
  WalletTabSendDetails: {
    screen: connect(mapStateToProps, mapDispatchToProps)(WalletTabSendDetails),
  },
})


<|start_filename|>app/components/touch-id/touch-id.js<|end_filename|>
// @flow
import RNTouchId from 'react-native-touch-id'

export default RNTouchId

export const TouchId = {
  // TODO: Fix type of promise return value from here
  authenticate(message: string, callback: () => void): Promise<any> {
    return new Promise((resolve, reject) => {
      RNTouchId.authenticate(message)
        .then(resolve)
        .catch(error => {
          if (error.name === 'LAErrorSystemCancel') {
            setTimeout(callback, 1000)
          }
          reject(error)
        })
    })
  },
  isSupported(): Promise<any> {
    return new Promise((resolve, reject) => {
      RNTouchId.isSupported()
        .then(resolve)
        .catch(error => {
          reject(error)
        })
    })
  },
}


<|start_filename|>app/components/loader/loader.js<|end_filename|>
// @flow

import React, { Component } from 'react'
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native'
import LoadingIndicator from './loading-indicator'
import type { LoaderProps, LoaderState } from './type-loader'
import { DARK } from './type-loader'
import { color, font, OFFSET_2X } from '../../common/styles'
import { Container, CustomText } from '..'

const LOADING_MESSAGES = ['Please wait…', 'Hold on…', 'Loading…', 'Working…']

const LONG_LOADING_MESSAGES = [
  'Taking longer than usual',
  'Still working',
  'Sorry for the wait',
  'Ok, this is taking longer than normal',
  'Really sorry about this',
  'Thanks for being patient',
  'Taking longer than usual',
]

export default class Loader extends Component<LoaderProps, LoaderState> {
  timers: Array<number>
  interval: any

  static defaultProps = {
    interval: 15000,
    timeout: 90000,
    delay: 0,
    type: DARK,
    showMessage: true,
    size: 30,
  }

  constructor(props: LoaderProps) {
    super(props)

    const { delay, interval, timeout, message } = props
    this.timers = []
    this.interval = interval

    this.timers.push(
      this.createTimer(
        'show',
        () => {
          // if a specific message isn't provided, then start using the random messages
          if (!message) {
            this.startInterval(interval)
          }

          return true
        },
        delay
      )
    )

    // This block will only run once the timeout value has been given and reached. Default is 90 seconds
    if (timeout) {
      this.timers.push(
        this.createTimer(
          'message',
          () => {
            this.clearTimers()

            return this.getRandomMessages(LONG_LOADING_MESSAGES)
          },
          timeout + delay
        )
      )
    }

    this.state = {
      message: message || this.getRandomMessages(LOADING_MESSAGES),
      show: delay === 0,
    }
  }

  // To prevent leaking timers
  componentWillUnmount() {
    this.clearTimers()
  }

  getRandomMessages(arr: Array<string>) {
    return arr[Math.floor(Math.random() * arr.length)]
  }

  startInterval(time: number) {
    const interval = setInterval(() => {
      this.setState({
        message: this.getRandomMessages(LOADING_MESSAGES),
      })
    }, time)

    this.interval = interval
  }

  clearTimers() {
    this.timers.forEach(id => {
      clearTimeout(id)
    })
    if (this.interval) {
      clearInterval(this.interval)
    }
  }

  createTimer(key: string, value: () => mixed, timeout: number = 0) {
    return setTimeout(() => {
      this.setState({
        [key]: value(),
      })
    }, timeout)
  }

  render() {
    const { type, showMessage, size } = this.props
    const { show, message } = this.state
    const textColor =
      type === DARK ? color.textColor.charcoal : color.actions.font.primary

    if (show) {
      return (
        <Container center style={[styles.loading]}>
          <LoadingIndicator type={type} size={size} />
          {showMessage && (
            <CustomText
              center
              transparentBg
              style={[{ color: textColor }, styles.loadingText]}
            >
              {message}
            </CustomText>
          )}
        </Container>
      )
    }

    return null
  }
}

const styles = StyleSheet.create({
  loading: {
    padding: OFFSET_2X,
  },
  loadingText: {
    fontSize: font.size.M,
    fontWeight: '500',
    lineHeight: 21,
    letterSpacing: -0.42,
    marginTop: OFFSET_2X,
  },
})


<|start_filename|>app/components/banner/banner-danger.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { CustomView, Icon, CustomText } from '../index'
import {
  IMAGE_WIDTH,
  IMAGE_HEIGHT,
  BACKUP_BANNER_TEST_ID,
  BANNER_HEIGHT,
} from './banner-constants'
import { color, dangerBannerHeight } from '../../common/styles'
import type { DangerBannerProps } from './type-banner'

export default class DangerBanner extends PureComponent<
  DangerBannerProps,
  void
> {
  render() {
    return (
      <CustomView
        row
        vCenter
        horizontalSpace
        verticalSpace
        style={[styles.bannerContainer, this.props.style || {}]}
        onPress={this.props.onPress}
        testID={this.props.testID}
      >
        <Icon
          iconStyle={[styles.labelImage, { tintColor: 'white' }]}
          src={require('../../images/Alert.png')}
        />
        <CustomView horizontalSpace>
          <CustomText bold transparentBg h5>
            {this.props.bannerTitle}
          </CustomText>
          <CustomText transparentBg h6>
            {this.props.bannerSubtext}
          </CustomText>
        </CustomView>
      </CustomView>
    )
  }
}

const styles = StyleSheet.create({
  bannerContainer: {
    backgroundColor: color.actions.dangerous,
  },
  labelImage: {
    width: IMAGE_WIDTH,
    height: IMAGE_HEIGHT,
  },
})


<|start_filename|>app/proof-request/__tests__/proof-request.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Provider } from 'react-redux'
import {
  ProofRequest,
  enablePrimaryAction,
  getPrimaryActionText,
} from '../proof-request'
import {
  PROOF_REQUEST_STATUS,
  PROOF_STATUS,
  PRIMARY_ACTION_SEND,
  PRIMARY_ACTION_GENERATE_PROOF,
} from '../type-proof-request'
import { color } from '../../common/styles'
import {
  getStore,
  claimMap,
  originalProofRequestData,
  proofRequestData,
  senderDid1,
  senderName1,
  senderLogoUrl1,
  uid,
  getNavigation,
} from '../../../__mocks__/static-data'

describe('<ProofRequest />', () => {
  const store = getStore()
  let wrapper
  let proofRequestShown
  let acceptProofRequest
  let rejectProofRequest
  let ignoreProofRequest
  let getProof
  let updateAttributeClaim
  let tree
  let navigation
  let componentInstance
  let userSelfAttestedAttributes
  let proofRequestShowStart
  const isValid = true
  let proofStatus = PROOF_STATUS.NONE

  beforeEach(() => {
    proofRequestShown = jest.fn()
    acceptProofRequest = jest.fn()
    rejectProofRequest = jest.fn()
    ignoreProofRequest = jest.fn()
    userSelfAttestedAttributes = jest.fn()
    getProof = jest.fn()
    updateAttributeClaim = jest.fn()
    navigation = getNavigation({ uid })
    proofRequestShowStart = jest.fn()

    wrapper = renderer.create(
      <Provider store={store}>
        <ProofRequest
          data={proofRequestData}
          proofStatus={proofStatus}
          originalProofRequestData={originalProofRequestData}
          remotePairwiseDID={senderDid1}
          name={senderName1}
          proofRequestShown={proofRequestShown}
          acceptProofRequest={acceptProofRequest}
          ignoreProofRequest={ignoreProofRequest}
          rejectProofRequest={rejectProofRequest}
          getProof={getProof}
          updateAttributeClaim={updateAttributeClaim}
          navigation={navigation}
          uid={navigation.state.params.uid || ''}
          isValid={isValid}
          logoUrl={senderLogoUrl1}
          claimMap={claimMap}
          missingAttributes={{}}
          userSelfAttestedAttributes={userSelfAttestedAttributes}
          userAvatarSource={undefined}
          proofRequestShowStart={proofRequestShowStart}
        />
      </Provider>
    )
    tree = wrapper.toJSON()
    componentInstance = wrapper.root.findByType(ProofRequest).instance
  })

  it('should call proofRequestShown on componentDidMount', () => {
    expect(tree).toMatchSnapshot()
    expect(proofRequestShown).toHaveBeenCalledWith(uid)
  })

  it('should call getProof if offer is accepted after generate proof is done', () => {
    // generate proof
    componentInstance.onSend()
    // accept
    componentInstance.onSend()
    expect(getProof).toHaveBeenCalledWith(uid)
    expect(tree).toMatchSnapshot()
  })

  it('should call proofRequestIgnored if close button is pressed', () => {
    componentInstance.onIgnore()
    expect(ignoreProofRequest).toHaveBeenCalledWith(uid)
    expect(navigation.goBack).toHaveBeenCalled()
    expect(tree).toMatchSnapshot()
  })

  it('should call proofRequestRejected if ignore button is pressed', () => {
    componentInstance.onReject()
    expect(rejectProofRequest).toHaveBeenCalledWith(uid)
    expect(navigation.goBack).toHaveBeenCalled()
    expect(tree).toMatchSnapshot()
  })

  it('should go back on close action', () => {
    componentInstance.close()
    expect(navigation.goBack).toHaveBeenCalled()
    expect(tree).toMatchSnapshot()
  })
})

describe('fn: enablePrimaryAction & getPrimaryActionText', () => {
  describe('No Missing Attributes', () => {
    const missingAttributes = {}
    const generateProofClicked = false
    const allMissingAttributesFilled = false

    it('all requested attributes filled, no error', () => {
      const requestedAttributes = [{ label: 'Address 1', data: 'data' }]
      const error = null
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(true)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_SEND)
    })

    it('all requested attributes filled, error', () => {
      const requestedAttributes = [{ label: 'Address 1', data: 'data' }]
      const generateProofClicked = true
      const error = {
        code: 'TEST',
        message: 'message',
      }
      const allMissingAttributesFilled = false
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(false)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_SEND)
    })

    it('some requested attributes are filled, no error', () => {
      const requestedAttributes = [
        { label: 'Address 1' },
        { label: 'Address 2', data: 'address' },
      ]
      const error = null
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(false)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_SEND)
    })

    it('some requested attributes are filled, error', () => {
      const requestedAttributes = [
        { label: 'Address 1' },
        { label: 'Address 2', data: 'address' },
      ]
      const error = {
        code: 'TEST',
        message: 'message',
      }
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(false)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_SEND)
    })
  })

  describe('Missing Attributes', () => {
    const missingAttributes = {
      'address 1': { name: 'Address 1', data: '', key: 'attr1' },
      'address 2': { name: 'Address 2', data: '', key: 'attr2' },
    }

    it('not all missing attributes filled, generate not clicked, no requested attributes filled', () => {
      const requestedAttributes = [
        { label: 'address 1' },
        { label: 'address 2' },
      ]
      const generateProofClicked = false
      const error = null
      const allMissingAttributesFilled = false
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(false)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_GENERATE_PROOF)
    })

    it('all missing attributes filled, generate not clicked, no requested attributes', () => {
      const requestedAttributes = [
        { label: 'address 1' },
        { label: 'address 2' },
      ]
      const generateProofClicked = false
      const error = null
      const allMissingAttributesFilled = true
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(true)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_GENERATE_PROOF)
    })

    it('all missing attributes filled, generate clicked, no requested attributes filled', () => {
      const requestedAttributes = [
        { label: 'address 1' },
        { label: 'address 2' },
      ]
      const generateProofClicked = true
      const error = null
      const allMissingAttributesFilled = true
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(false)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_SEND)
    })

    it('all missing attributes filled, generate clicked, some requested attributes filled', () => {
      const requestedAttributes = [
        { label: 'address 1', data: 'address value' },
        { label: 'address 2' },
      ]
      const generateProofClicked = true
      const error = null
      const allMissingAttributesFilled = true
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(false)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_SEND)
    })

    it('all missing attributes filled, generate clicked, all requested attributes filled', () => {
      const requestedAttributes = [
        { label: 'address 1', data: 'address value' },
        { label: 'address 2', data: 'address 2 value' },
      ]
      const generateProofClicked = true
      const error = null
      const allMissingAttributesFilled = true
      expect(
        enablePrimaryAction(
          missingAttributes,
          generateProofClicked,
          allMissingAttributesFilled,
          error,
          requestedAttributes
        )
      ).toBe(true)
      expect(
        getPrimaryActionText(missingAttributes, generateProofClicked)
      ).toBe(PRIMARY_ACTION_SEND)
    })
  })
})


<|start_filename|>__mocks__/setup.js<|end_filename|>
import React from 'react'
import { NativeModules } from 'react-native'
import fetch from './fetch-mock'
import mockCamera from './camera-mock'
import mockModal from './modal-mock'
import mockView from './view-mock'

// mock Math.random for <Loader />
const mockMath = Object.create(global.Math)
mockMath.random = () => 0.1
global.Math = mockMath

// mock this module to allow react-navigation to mock Linking
jest.mock('Linking', () => ({
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
  openURL: jest.fn(() => Promise.resolve()),
  canOpenURL: jest.fn(() => Promise.resolve()),
  getInitialURL: jest.fn(() => Promise.resolve()),
}))

jest.mock('react-navigation', () => ({
  createStackNavigator: jest.fn(() => mockView),
  createTabNavigator: jest.fn(() => mockView),
  TabBarTop: jest.fn(),
  isFocused: true,
  withNavigationFocus: jest.fn(() => mockView),
  NavigationActions: {
    reset() {
      return arguments
    },
    navigate() {
      return arguments
    },
  },
}))

jest.mock('react-native-firebase', () => ({
  notifications: jest.fn(() => ({
    onNotificationDisplayed: jest.fn(() => Promise.resolve()),
    onNotification: jest.fn(() => Promise.resolve()),
    onNotificationOpened: jest.fn(() => Promise.resolve()),
    getInitialNotification: jest.fn(() => Promise.resolve()),
  })),
  messaging: jest.fn(() => ({
    requestPermission: jest.fn(() => Promise.resolve()),
    onTokenRefresh: jest.fn(() => Promise.resolve()),
    getToken: jest.fn(() => Promise.resolve()),
  })),
}))

jest.mock('PixelRatio', () => ({
  get: jest.fn(() => 3), //PixelRatio.get() === 3 then iPhone 6 plus
  roundToNearestPixel: jest.fn(num => num),
}))

jest.mock('react-native-sensitive-info', () => {
  // todo: need to handle empty key-chain case
  const secureStorage = {
    ConnectMeKeyChain: {
      identifier: '26u37qFNUk3QwCUQ9ctest',
      phone: '6428900484',
      seed: 'S1StqtsAL4zkFZxmW57sL75zmufmVFQ3',
      pushComMethod: 'dehVox1KRqM:APA91bFWrJea1avml_ELw2MaH60abydtest',
    },
  }
  return {
    setItem: jest.fn((key, value, st) =>
      Promise.resolve((secureStorage['ConnectMeKeyChain'][key] = value))
    ),
    getItem: jest.fn(key =>
      Promise.resolve(secureStorage['ConnectMeKeyChain'][key])
    ),
    deleteItem: jest.fn(key =>
      Promise.resolve(delete secureStorage['ConnectMeKeyChain'][key])
    ),
  }
})

jest.mock('react-native-animatable', () => ({
  View: 'Animatable.View',
}))

jest.mock('react-native-camera', () => mockCamera)

jest.mock('Dimensions', () => ({
  get: jest.fn(() => ({
    width: 320,
    height: 540,
  })),
}))

jest.mock('react-native-touch-id', () => {
  return {
    authenticate: jest.fn(message => Promise.resolve()),
    isSupported: jest.fn(_ => Promise.resolve()),
  }
})

// jest.mock('react-native-sentry', () => ({
//   Sentry: {
//     install() {},
//     config() {
//       return { install() {} }
//     },
//     captureException(error) {},
//   },
//   SentryLog: {
//     Debug: 1,
//   },
// }))

jest.mock('AlertIOS', () => ({
  alert() {},
}))

global.fetch = fetch

jest.mock('Modal', () => mockModal)

jest.mock('react-native-modal', () => mockModal)

jest.mock('react-native-fetch-blob', () => ({
  fetch: jest.fn((type, url) => Promise.resolve()),
  fs: {
    dirs: {
      DocumentDir: '/var/application/DocumentDir',
    },
    exists: jest.fn(path => Promise.resolve(true)),
    unlink: jest.fn(path => Promise.resolve(true)),
    cp: jest.fn((source, destination) => Promise.resolve(destination)),
  },
}))

jest.mock('WebView', () => 'WebView')

jest.mock('InteractionManager', () => ({
  runAfterInteractions(fn) {
    fn()
  },
  createInteractionHandle: jest.fn(),
  clearInteractionHandle: jest.fn(),
}))

jest.mock('TextInput', () => 'TextInput')

jest.mock('moment', () =>
  jest.fn(date => ({
    format(format) {
      if (format === 'MM/DD/YYYY') {
        return '01/10/2018'
      }

      if (format === 'MMMM YYYY') {
        return 'January 2018'
      }

      return '2018-01-10T04:32:43+05:30'
    },
  }))
)

jest.mock('react-native-branch', () => {
  return {
    ADD_TO_CART_EVENT: 'Add to Cart',
    ADD_TO_WISHLIST_EVENT: 'Add to Wishlist',
    PURCHASE_INITIATED_EVENT: 'Purchase Started',
    PURCHASED_EVENT: 'Purchased',
    REGISTER_VIEW_EVENT: 'View',
    SHARE_COMPLETED_EVENT: 'Share Completed',
    SHARE_INITIATED_EVENT: 'Share Started',

    STANDARD_EVENT_ADD_TO_CART: 'ADD_TO_CART',
    STANDARD_EVENT_ADD_TO_WISHLIST: 'ADD_TO_WISHLIST',
    STANDARD_EVENT_VIEW_CART: 'VIEW_CART',
    STANDARD_EVENT_INITIATE_PURCHASE: 'INITIATE_PURCHASE',
    STANDARD_EVENT_ADD_PAYMENT_INFO: 'ADD_PAYMENT_INFO',
    STANDARD_EVENT_PURCHASE: 'PURCHASE',
    STANDARD_EVENT_SPEND_CREDITS: 'SPEND_CREDITS',

    STANDARD_EVENT_SEARCH: 'SEARCH',
    STANDARD_EVENT_VIEW_ITEM: 'VIEW_ITEM',
    STANDARD_EVENT_VIEW_ITEMS: 'VIEW_ITEMS',
    STANDARD_EVENT_RATE: 'RATE',
    STANDARD_EVENT_SHARE: 'SHARE',

    STANDARD_EVENT_COMPLETE_REGISTRATION: 'COMPLETE_REGISTRATION',
    STANDARD_EVENT_COMPLETE_TUTORIAL: 'COMPLETE_TUTORIAL',
    STANDARD_EVENT_ACHIEVE_LEVEL: 'ACHIEVE_LEVEL',
    STANDARD_EVENT_UNLOCK_ACHIEVEMENT: 'UNLOCK_ACHIEVEMENT',

    // don't need any type checks for mocks, because they are not used
    // for type checking in code
    subscribe(cb: any) {},
  }
})

jest.mock('react-native-splash-screen', () => ({
  hide: jest.fn(),
}))

jest.mock('react-native-unique-id', () =>
  jest.fn(() => Promise.resolve('uniqueDeviceId'))
)

jest.mock('react-native-image-crop-picker', () => ({
  openPicker: jest.fn(() =>
    Promise.resolve({ path: '/var/application/DocumentDir/user-avatar.jpeg' })
  ),
}))

// Add mock for RNIndy on NativeModules
// we don't want to mock NativeModules the way we are doing for all above
// because then we would have to mock everything else as well of NativeModules
// a lot of other modules depend on it, so we are adding RNIndy
// which is what we need to mock
NativeModules.RNIndy = {
  deserializeConnection: jest.fn(_ => Promise.resolve(1)),
  setWalletItem: jest.fn(_ => Promise.resolve(1)),
  deleteWalletItem: jest.fn(_ => Promise.resolve(1)),
  updateWalletItem: jest.fn(_ => Promise.resolve(1)),
  createWalletKey: jest.fn(_ => Promise.resolve('walletKey')),
}

jest.mock('react-native-version-number', () => ({
  appVersion: '1.0',
  buildVersion: '500',
}))


<|start_filename|>app/components/claim-proof-header/claim-proof-header.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Platform, View, Dimensions } from 'react-native'
import {
  CustomView,
  CustomText,
  Icon,
  ImageColorPicker,
  CustomSafeAreaView,
} from '../../components'
import {
  color,
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  isiPhone5,
  font,
  white,
} from '../../common/styles'
import empty from '../../common/empty'
import type {
  ClaimProofHeaderProps,
  ClaimProofHeaderNotchProps,
} from './type-claim-proof-header'
import { scale } from 'react-native-size-matters'
var { height, width } = Dimensions.get('screen')

export class ClaimProofHeaderNotch extends PureComponent<
  ClaimProofHeaderNotchProps,
  void
> {
  render() {
    const {
      containerStyle = empty,
      titleStyle = [],
    }: ClaimProofHeaderNotchProps = this.props
    return (
      <View style={styles.headerNotchContainer}>
        <View style={[styles.trapezoid, containerStyle]}>
          <CustomText h7 center style={[styles.sovrinText, titleStyle]}>
            SOVRIN TOKENS
          </CustomText>
        </View>
        <View style={[containerStyle, styles.triangle]} />
      </View>
    )
  }
}
export default class ClaimProofHeader extends PureComponent<
  ClaimProofHeaderProps,
  void
> {
  render() {
    const {
      message,
      title,
      logoUrl,
      testID,
      containerStyle = empty,
      textContainerStyle = [],
      messageStyle = [],
      titleStyle = [],
      payTokenValue,
    }: ClaimProofHeaderProps = this.props
    return (
      <CustomSafeAreaView>
        <CustomView
          fifth
          style={[styles.header, containerStyle, { marginBottom: -OFFSET_1X }]}
        >
          {this.props.children}
          <CustomView fifth center style={[styles.message, textContainerStyle]}>
            {message && (
              <CustomText h5 center demiBold bg="fifth" style={[messageStyle]}>
                {message}
              </CustomText>
            )}
            {title && (
              <CustomText
                h4
                heavy
                bg="fifth"
                style={[styles.title, titleStyle]}
              >
                {title}
              </CustomText>
            )}
            {payTokenValue && (
              <CustomView row horizontalSpace left>
                <CustomText
                  h4
                  uppercase
                  bg="fifth"
                  style={[styles.prefix, titleStyle]}
                >
                  pay
                </CustomText>
                <CustomText
                  style={[
                    styles.title,
                    titleStyle,
                    styles.payTokenText,
                    {
                      fontSize: tokenAmountSize(
                        payTokenValue ? payTokenValue.length : 0
                      ),
                    },
                  ]}
                  bg="fifth"
                  formatNumber
                >
                  {payTokenValue}
                </CustomText>
                <Icon
                  src={require('../../images/sovrinToken.png')}
                  small
                  iconStyle={[{ marginTop: OFFSET_3X / 2 }]}
                />
              </CustomView>
            )}
          </CustomView>
        </CustomView>
        {payTokenValue && (
          <ClaimProofHeaderNotch
            containerStyle={containerStyle}
            titleStyle={titleStyle}
          />
        )}
      </CustomSafeAreaView>
    )
  }
}

const styles = StyleSheet.create({
  header: {
    paddingTop: (Platform.OS === 'ios' ? OFFSET_1X : 0) + 20,
    shadowColor: color.bg.secondary.color,
    shadowOffset: { width: 0, height: 20 },
    shadowOpacity: 0.2,
    shadowRadius: 10,
    zIndex: 4,
  },
  message: {
    marginTop: OFFSET_1X / 2,
    paddingBottom: OFFSET_1X,
    marginHorizontal: OFFSET_1X,
  },
  title: {
    marginTop: OFFSET_1X / 2,
  },
  prefix: {
    fontSize: font.size.PREFIX,
    marginTop: OFFSET_3X / 2,
  },
  sovrinText: {
    marginBottom: -OFFSET_1X,
  },
  headerNotchContainer: {
    zIndex: 5,
    backgroundColor: white,
  },
  trapezoid: {
    width: '100%',
    height: 0,
    borderBottomWidth: 20,
    borderLeftWidth: 0,
    borderLeftColor: 'transparent',
    borderRightWidth: 0,
    borderRightColor: 'transparent',
    borderStyle: 'solid',
    borderBottomLeftRadius: 10,
    borderBottomRightRadius: 10,
  },
  triangle: {
    width: '95%',
    height: 0,
    alignSelf: 'center',
    backgroundColor: 'transparent',
    borderStyle: 'solid',
    borderLeftWidth: width / 2.1,
    borderRightWidth: width / 2.1,
    borderBottomWidth: 20,
    borderLeftColor: 'transparent',
    borderRightColor: 'transparent',
    transform: [{ rotate: '180deg' }],
  },
  payTokenText: {
    marginTop: OFFSET_1X / 2,
  },
})

const tokenAmountSize = (tokenAmountLength: number): number => {
  // this resizing logic is different than wallet tabs header
  switch (true) {
    case tokenAmountLength < 13:
      return scale(40)
    case tokenAmountLength < 16:
      return scale(35)
    case tokenAmountLength < 20:
      return scale(28)
    default:
      return scale(20)
  }
}


<|start_filename|>app/store/index.js<|end_filename|>
// @flow
import { createStore, combineReducers, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import { all } from 'redux-saga/effects'
import logger from 'redux-logger'
import user, { watchUserStore } from './user/user-store'
import pushNotification, {
  watchPushNotification,
} from '../push-notification/push-notification-store'
import connections, { watchConnection } from './connections-store'
import config, { watchConfig, watchGetMessagesSaga } from './config-store'
import authentication, {
  watchAuthentication,
} from '../authentication/authentication-store'
import deepLink from '../deep-link/deep-link-store'
import route from './route-store'
import lock, {
  watchLock,
  watchPressEventInLockSelectionScreen,
  watchEnableTouchId,
  watchDisableTouchId,
} from '../lock/lock-store'
import smsPendingInvitation, {
  watchSmsPendingInvitationSaga,
} from '../sms-pending-invitation/sms-pending-invitation-store'
import claimOffer, { watchClaimOffer } from '../claim-offer/claim-offer-store'
import proofRequest, {
  watchProofRequestAccepted,
  watchPersistProofRequests,
  watchProofRequestReceived,
} from '../proof-request/proof-request-store'
import invitation, { watchInvitation } from '../invitation/invitation-store'
import claim, { watchClaim } from '../claim/claim-store'
import proof, { watchProof } from '../proof/proof-store'
import history, {
  watchConnectionHistory,
} from '../connection-history/connection-history-store'
import historyRecorder from '../connection-history/history-middleware'
import wallet, { watchWalletStore } from '../wallet/wallet-store'
import eula, { watchEula } from '../eula/eula-store'
import restore, { watchRestore } from '../restore/restore-store'
import backup, { watchBackup } from '../backup/backup-store'
import offline, { watchOffline } from '../offline/offline-store'
import { hydrate } from './hydration-store'
import {
  watchLedgerStore,
  ledgerStoreReducer as ledger,
} from './ledger/ledger-store'

const sagaMiddleware = createSagaMiddleware()

const appReducer = combineReducers({
  config,
  connections,
  deepLink,
  authentication,
  pushNotification,
  route,
  smsPendingInvitation,
  user,
  lock,
  claimOffer,
  proofRequest,
  invitation,
  claim,
  proof,
  history,
  wallet,
  eula,
  restore,
  backup,
  ledger,
  offline,
})

let middlewares = [historyRecorder]

if (process.env.NODE_ENV !== 'test' && __DEV__) {
  // skip logger middleware if we are running tests
  middlewares.push(logger)
}

middlewares.push(sagaMiddleware)

const store = createStore(appReducer, applyMiddleware(...middlewares))

// $FlowFixMe Don't know how to fix polymorphic type coercion
sagaMiddleware.run(function*() {
  return yield all([
    watchConnection(),
    watchConfig(),
    watchAuthentication(),
    watchLock(),
    watchSmsPendingInvitationSaga(),
    watchClaimOffer(),
    watchPushNotification(),
    watchInvitation(),
    watchClaim(),
    watchPressEventInLockSelectionScreen(),
    watchEnableTouchId(),
    watchDisableTouchId(),
    watchProof(),
    watchProofRequestAccepted(),
    watchConnectionHistory(),
    watchUserStore(),
    watchWalletStore(),
    watchBackup(),
    watchEula(),
    watchRestore(),
    hydrate(),
    watchGetMessagesSaga(),
    watchPersistProofRequests(),
    watchProofRequestReceived(),
    watchLedgerStore(),
    watchOffline(),
  ])
})

export default store


<|start_filename|>app/components/layout/custom-safeAreaView.js<|end_filename|>
// @flow
import React from 'react'
import { SafeAreaView, StyleSheet } from 'react-native'
import style from './layout-style'
import type { GenericObject } from '../../common/type-common'

// TODO:KS Change prop type from GenericObject to actual props
//Use this component to adjust the content within
//IphoneX spacing guidelines
export const CustomSafeAreaView = (props: GenericObject) => {
  const { primary, secondary, tertiary, quaternary, fifth } = props
  const passedStyle = props.style || []
  const styles = StyleSheet.flatten([
    primary ? style.primaryBg : null,
    secondary ? style.secondaryBg : null,
    tertiary ? style.tertiaryBg : null,
    quaternary ? style.quaternaryBg : null,
    fifth ? style.fifthBg : null,
    ...passedStyle,
  ])
  return <SafeAreaView style={styles}>{props.children}</SafeAreaView>
}


<|start_filename|>app/type-app.js<|end_filename|>
// @flow

export type AppState = {
  statusBarTheme: string,
}


<|start_filename|>app/wallet/credential-offer-modal.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, Platform } from 'react-native'
import {
  CustomView,
  Icon,
  CustomText,
  CustomButton,
  Container,
  CustomModal,
} from '../components'
import {
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_6X,
  OFFSET_7X,
  color,
  HAIRLINE_WIDTH,
  whiteSmoke,
  isiPhone5,
} from '../common/styles/constant'
import Modal from 'react-native-modal'
import PaymentFailureModal from './payment-failure-modal'
import {
  CLAIM_REQUEST_STATUS,
  CREDENTIAL_OFFER_MODAL_STATUS,
} from '../claim-offer/type-claim-offer'
import type {
  CredentialOfferModalProps,
  CredentialOfferModalState,
  ClaimRequestStatusModalProps,
  ClaimRequestStatus,
} from '../claim-offer/type-claim-offer'
import { ClaimRequestStatusModal } from '../claim-offer/claim-request-modal'
import { LedgerFeesModal } from '../components/ledger-fees-modal/ledger-fees-modal'

export default class CredentialOfferModal extends PureComponent<
  CredentialOfferModalProps,
  CredentialOfferModalState
> {
  onContinue = () => {
    this.props.onClose()
  }

  render() {
    const {
      testID,
      onClose,
      claimRequestStatus,
      onRetry,
      claimOfferData,
      isValid,
      logoUrl,
      payTokenValue,
      credentialOfferModalStatus,
      transferAmount,
      connectionName,
    } = this.props
    return (
      <Modal
        backdropColor={whiteSmoke}
        isVisible={
          credentialOfferModalStatus !== CREDENTIAL_OFFER_MODAL_STATUS.NONE
        }
        animationIn="zoomIn"
        animationOut="zoomOut"
        animationOutTiming={100}
        useNativeDriver={true}
        hideModalContentWhileAnimating={true}
        onBackButtonPress={this.props.onClose}
        onBackdropPress={this.props.onClose}
        onModalHide={this.props.onModalHide}
        testID={'credential-offer-modal'}
        style={[
          claimRequestStatus ===
            CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST ||
          claimRequestStatus === CLAIM_REQUEST_STATUS.SENDING_CLAIM_REQUEST ||
          claimRequestStatus === CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_SUCCESS
            ? {
                padding: 0,
                margin: 0,
              }
            : {},
        ]}
      >
        {isValid &&
          credentialOfferModalStatus ===
            CREDENTIAL_OFFER_MODAL_STATUS.INSUFFICIENT_BALANCE &&
          payTokenValue && (
            <CustomView center fifth shadow style={[styles.container]}>
              <CustomView
                spaceBetween
                style={[styles.innerContainer]}
                center
                verticalSpace
              >
                <CustomView center verticalSpace>
                  <Icon src={require('../images/alertInfo.png')} />
                </CustomView>
                <CustomText
                  transparentBg
                  style={[styles.fontBlack]}
                  center
                  demiBold
                >
                  You do not have enough tokens to purchase this credential
                </CustomText>
              </CustomView>
              <CustomButton
                fifth
                onPress={this.props.onClose}
                title={'Continue'}
                textStyle={{ fontWeight: 'bold', color: '#85BF43' }}
              />
            </CustomView>
          )}

        {isValid &&
          credentialOfferModalStatus ===
            CREDENTIAL_OFFER_MODAL_STATUS.CREDENTIAL_REQUEST_FAIL && (
            <CustomView center fifth shadow style={[styles.container]}>
              <CustomView
                spaceBetween
                style={[styles.innerContainer]}
                center
                verticalSpace
              >
                <CustomView center verticalSpace>
                  <Icon src={require('../images/alertInfo.png')} />
                </CustomView>
                <CustomText
                  transparentBg
                  style={[styles.fontBlack]}
                  center
                  demiBold
                >
                  Error accepting credential. Please try again.
                </CustomText>
              </CustomView>
              <CustomButton
                fifth
                onPress={this.props.onClose}
                title={'OK'}
                textStyle={{ fontWeight: 'bold' }}
              />
            </CustomView>
          )}

        {claimRequestStatus &&
          claimOfferData &&
          isValid &&
          credentialOfferModalStatus ===
            CREDENTIAL_OFFER_MODAL_STATUS.CREDENTIAL_REQUEST_STATUS && (
            <ClaimRequestStatusModal
              claimRequestStatus={claimRequestStatus}
              payload={claimOfferData}
              onContinue={this.props.onClose}
              senderLogoUrl={logoUrl}
              payTokenValue={payTokenValue}
              message1={payTokenValue ? 'You paid' : 'You accepted'}
              message3={payTokenValue ? '' : 'from'}
              message6={
                payTokenValue ? 'They will issue it to you shortly.' : ''
              }
              isPending={
                claimRequestStatus ===
                  CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST ||
                claimRequestStatus ===
                  CLAIM_REQUEST_STATUS.SENDING_CLAIM_REQUEST
              }
              onModalHide={this.props.onModalHide}
            />
          )}

        {credentialOfferModalStatus ===
          CREDENTIAL_OFFER_MODAL_STATUS.SEND_PAID_CREDENTIAL_REQUEST_FAIL ||
        credentialOfferModalStatus ===
          CREDENTIAL_OFFER_MODAL_STATUS.TOKEN_SENT_FAIL ? (
          <PaymentFailureModal
            connectionName={
              connectionName ||
              (claimOfferData != null && claimOfferData.issuer != null
                ? claimOfferData.issuer.name
                : '')
            }
            testID={`${testID}-payment-failure-modal`}
            onClose={this.props.onClose}
            onRetry={this.props.onRetry}
          />
        ) : null}

        {(payTokenValue || transferAmount) &&
        credentialOfferModalStatus ===
          CREDENTIAL_OFFER_MODAL_STATUS.LEDGER_FEES ? (
          <LedgerFeesModal
            onNo={this.props.onNo}
            onYes={this.props.onYes}
            transferAmount={transferAmount}
            renderFeesText={this.props.renderFeesText}
          />
        ) : null}
      </Modal>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    marginHorizontal: OFFSET_3X,
  },
  innerContainer: {
    ...Platform.select({
      ios: {
        borderBottomColor: color.bg.fifth.font.tertiary,
        borderBottomWidth: HAIRLINE_WIDTH,
      },
      android: {
        borderBottomColor: color.bg.fifth.font.secondary,
        borderBottomWidth: 1,
      },
    }),
    padding: OFFSET_2X,
  },
  message: {
    marginBottom: OFFSET_1X / 2,
  },
  fontBlack: {
    color: '#777777',
  },
})


<|start_filename|>app/lock/lock-authorization.js<|end_filename|>
// @flow
/**
 * Intend to verify user actions
 * we will ask authorize user for some actions in app
 * either by asking for TouchId or asking user to enter pin code
 * we will ask for authorization while accepting invitation
 * accepting claim offer, sharing proof for now
 */
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import LockEnter from './lock-enter'
import type { LockAuthorizationProps } from './type-lock'
import { Icon } from '../components'
import { CustomView, CustomHeader } from '../components'
import { OFFSET_2X, color } from '../common/styles'
import { tertiaryHeaderStyles } from '../components/layout/header-styles'
import { lockAuthorizationHomeRoute } from '../common'
import { createStackNavigator } from 'react-navigation'
import type { ReactNavigation } from '../common/type-common'

const styles = StyleSheet.create({
  headerLeft: {
    width: OFFSET_2X,
  },
})

export class LockAuthorization extends PureComponent<
  LockAuthorizationProps,
  void
> {
  static navigationOptions = ({ navigation }: ReactNavigation) => ({
    header: (
      <CustomHeader flatHeader backgroundColor={color.bg.tertiary.color}>
        <CustomView>
          <Icon
            small
            testID={'back-arrow'}
            iconStyle={[styles.headerLeft]}
            src={require('../images/icon_backArrow.png')}
            resizeMode="contain"
            onPress={() => {
              navigation.goBack(null)
              if (navigation.state && navigation.state.params.onAvoid) {
                navigation.state.params.onAvoid()
              }
            }}
          />
        </CustomView>
      </CustomHeader>
    ),
  })

  onSuccess = () => {
    this.props.navigation.goBack(null)
    setTimeout(() => {
      this.props.navigation.state &&
        this.props.navigation.state.params.onSuccess()
    })
  }

  onClose = () => {
    this.props.navigation.goBack(null)
    setTimeout(() => {
      this.props.navigation.state &&
        this.props.navigation.state.params.onAvoid()
    })
  }

  render() {
    return <LockEnter onSuccess={this.onSuccess} />
  }
}

export default createStackNavigator({
  [lockAuthorizationHomeRoute]: {
    screen: LockAuthorization,
  },
})


<|start_filename|>app/connection-history/connection-history-store.js<|end_filename|>
// $FlowFixMe
import {
  all,
  takeLatest,
  takeEvery,
  put,
  call,
  select,
  take,
} from 'redux-saga/effects'
import merge from 'lodash.merge'
import { CONNECTIONS } from '../common'
import {
  LOAD_HISTORY,
  LOAD_HISTORY_SUCCESS,
  LOAD_HISTORY_FAIL,
  RECORD_HISTORY_EVENT,
  DELETE_HISTORY_EVENT,
  ERROR_LOADING_HISTORY,
  HISTORY_EVENT_OCCURRED,
  EventTypeToEventStatusMap,
  HISTORY_EVENT_STATUS,
  HISTORY_EVENT_TYPE,
  HISTORY_EVENT_STORAGE_KEY,
  ERROR_HISTORY_EVENT_OCCURRED,
} from './type-connection-history'
import type {
  HistoryEventType,
  HistoryEventStatus,
  ConnectionHistoryEvent,
  ConnectionHistoryData,
  ConnectionHistoryAction,
  ConnectionHistoryStore,
  HistoryEventOccurredAction,
  HistoryEventOccurredEventType,
  DeleteHistoryEventAction,
} from './type-connection-history'
import type { Connection } from '../store/type-connection-store'
import type {
  CustomError,
  GenericObject,
  GenericStringObject,
} from '../common/type-common'
import type { InvitationPayload } from '../invitation/type-invitation'
import { uuid } from '../services/uuid'
import { INVITATION_RECEIVED } from '../invitation/type-invitation'
import moment from 'moment'
import type { NewConnectionAction } from '../store/type-connection-store'
import { NEW_CONNECTION_SUCCESS } from '../store/connections-store'
import type {
  SendClaimRequestSuccessAction,
  ClaimOfferPayload,
  ClaimOfferReceivedAction,
} from '../claim-offer/type-claim-offer'
import type { ClaimStorageSuccessAction } from '../claim/type-claim'
import type { Proof } from '../proof/type-proof'
import { SEND_CLAIM_REQUEST_SUCCESS } from '../claim-offer/type-claim-offer'
import type {
  ProofRequestReceivedAction,
  SendProofSuccessAction,
  ProofRequestPayload,
} from '../proof-request/type-proof-request'
import {
  PROOF_REQUEST_RECEIVED,
  SEND_PROOF_SUCCESS,
} from '../proof-request/type-proof-request'
import { secureSet, getHydrationItem } from '../services/storage'
import {
  getProofRequest,
  getProof,
  getClaimOffer,
  getPendingHistoryEvent,
  getHistory,
  getPendingHistory,
  getHistoryEvent,
  getClaimReceivedHistory,
} from '../store/store-selector'
import { CLAIM_STORAGE_SUCCESS } from '../claim/type-claim'
import type { UserOneTimeInfo } from '../store/user/type-user-store'
import { RESET } from '../common/type-common'
import { CLAIM_OFFER_RECEIVED } from '../claim-offer/type-claim-offer'
import { captureError } from '../services/error/error-handler'

const initialState = {
  error: null,
  isLoading: false,
  data: null,
}

export const loadHistory = () => ({
  type: LOAD_HISTORY,
})

export const loadHistorySuccess = (data: ConnectionHistoryData) => ({
  type: LOAD_HISTORY_SUCCESS,
  data,
})

export const loadHistoryFail = (error: CustomError) => ({
  type: LOAD_HISTORY_FAIL,
  error,
})

export function* loadHistorySaga(): Generator<*, *, *> {
  yield put(loadHistory())
  try {
    const historyEvents = yield call(
      getHydrationItem,
      HISTORY_EVENT_STORAGE_KEY
    )
    if (historyEvents) {
      yield put(loadHistorySuccess(JSON.parse(historyEvents)))
    }
  } catch (e) {
    captureError(e)
    yield put(
      loadHistoryFail({
        ...ERROR_LOADING_HISTORY,
        message: `${ERROR_LOADING_HISTORY.message} ${e.message}`,
      })
    )
  }
}

// receive invitation
export function convertInvitationToHistoryEvent(
  invitation: InvitationPayload
): ConnectionHistoryEvent {
  return {
    action: HISTORY_EVENT_STATUS[INVITATION_RECEIVED],
    data: {},
    id: uuid(),
    name: invitation.senderName,
    status: HISTORY_EVENT_STATUS[INVITATION_RECEIVED],
    timestamp: moment().format(),
    type: HISTORY_EVENT_TYPE.INVITATION,
    remoteDid: invitation.senderDID,
    originalPayload: invitation,
  }
}

// accept invitation
export function convertConnectionSuccessToHistoryEvent(
  action: NewConnectionAction
): ConnectionHistoryEvent {
  const { senderName, senderDID } = action.connection

  return {
    action: HISTORY_EVENT_STATUS[NEW_CONNECTION_SUCCESS],
    data: [
      {
        label: 'Established on',
        data: moment().format(),
      },
    ],
    id: uuid(),
    name: senderName,
    status: HISTORY_EVENT_STATUS[NEW_CONNECTION_SUCCESS],
    timestamp: moment().format(),
    type: HISTORY_EVENT_TYPE.INVITATION,
    remoteDid: senderDID,
    originalPayload: action,
  }
}

// claim request pending
export function convertSendClaimRequestSuccessToHistoryEvent(
  action: SendClaimRequestSuccessAction
): ConnectionHistoryEvent {
  return {
    action: HISTORY_EVENT_STATUS[SEND_CLAIM_REQUEST_SUCCESS],
    data: action.payload.data && action.payload.data.revealedAttributes,
    id: uuid(),
    name: action.payload.data && action.payload.data.name,
    status: HISTORY_EVENT_STATUS[SEND_CLAIM_REQUEST_SUCCESS],
    timestamp: moment().format(),
    type: HISTORY_EVENT_TYPE.CLAIM,
    remoteDid: action.payload.remotePairwiseDID,
    originalPayload: action,
  }
}

// TODO:KS Add claim accepted
//export function convertClaimAcceptedToHistoryEvent(): ConnectionHistoryEvent {}

export function convertClaimStorageSuccessToHistoryEvent(
  action: ClaimStorageSuccessAction,
  claim: ClaimOfferPayload
): ConnectionHistoryEvent {
  return {
    action: HISTORY_EVENT_STATUS[CLAIM_STORAGE_SUCCESS],
    data: claim.data && claim.data.revealedAttributes,
    id: uuid(),
    name: claim.data && claim.data.name,
    status: HISTORY_EVENT_STATUS[CLAIM_STORAGE_SUCCESS],
    timestamp: moment().format(),
    type: HISTORY_EVENT_TYPE.CLAIM,
    remoteDid: claim.remotePairwiseDID,
    originalPayload: action,
  }
}

// TODO:KS Add proof request received
export function convertProofRequestToHistoryEvent(
  action: ProofRequestReceivedAction
): ConnectionHistoryEvent {
  return {
    action: HISTORY_EVENT_STATUS[PROOF_REQUEST_RECEIVED],
    data: action.payload.data.requestedAttributes,
    id: uuid(),
    name: action.payload.data.name,
    status: HISTORY_EVENT_STATUS[PROOF_REQUEST_RECEIVED],
    timestamp: moment().format(),
    type: HISTORY_EVENT_TYPE.PROOF,
    remoteDid: action.payloadInfo.remotePairwiseDID,
    originalPayload: action,
  }
}

// TODO:SC change the action type from any to appropriate type
export function convertClaimOfferToHistoryEvent(
  action: ClaimOfferReceivedAction
): ConnectionHistoryEvent {
  return {
    action: HISTORY_EVENT_STATUS[CLAIM_OFFER_RECEIVED],
    data: action.payload.data.revealedAttributes,
    id: uuid(),
    name: action.payload.data.name,
    status: HISTORY_EVENT_STATUS[CLAIM_OFFER_RECEIVED],
    timestamp: moment().format(),
    type: HISTORY_EVENT_TYPE.CLAIM,
    remoteDid: action.payload.issuer.did,
    originalPayload: action,
  }
}

function mapSentAttributes(
  revealedAttributes: Array<GenericStringObject>,
  selfAttestedAttributes: Array<GenericStringObject>,
  requestedAttributes: Array<Array<Attribute>>
): Array<Attribute> {
  let sentAttributes = []
  if (revealedAttributes) {
    const revealedAttributeKeys = Object.keys(revealedAttributes)
    Object.values(revealedAttributes).forEach((revealedAttribute, index) => {
      sentAttributes.push({
        label: requestedAttributes[revealedAttributeKeys[index]].name,
        key: revealedAttributeKeys[index],
        data: revealedAttribute[1],
        claimUuid: revealedAttribute[0],
      })
    })
  }

  if (selfAttestedAttributes) {
    const selfAttestedAttributesKeys = Object.keys(selfAttestedAttributes)
    Object.values(selfAttestedAttributes).forEach(
      (selfAttestedAttribute, index) => {
        sentAttributes.push({
          label: requestedAttributes[selfAttestedAttributesKeys[index]].name,
          key: selfAttestedAttributesKeys[index],
          data: selfAttestedAttribute,
        })
      }
    )
  }
  return sentAttributes
}

export function convertProofSendToHistoryEvent(
  action: SendProofSuccessAction,
  {
    data: { name },
    originalProofRequestData: { requested_attributes },
    remotePairwiseDID: remoteDid,
  }: ProofRequestPayload,
  { requested_proof: { revealed_attrs, self_attested_attrs } }: Proof
): ConnectionHistoryEvent {
  return {
    action: HISTORY_EVENT_STATUS[SEND_PROOF_SUCCESS],
    data: mapSentAttributes(
      revealed_attrs,
      self_attested_attrs,
      requested_attributes
    ),
    id: uuid(),
    name,
    status: HISTORY_EVENT_STATUS[SEND_PROOF_SUCCESS],
    timestamp: moment().format(),
    type: HISTORY_EVENT_TYPE.PROOF,
    remoteDid,
    originalPayload: action,
  }
}

export const recordHistoryEvent = (historyEvent: ConnectionHistoryEvent) => ({
  type: RECORD_HISTORY_EVENT,
  historyEvent,
})

export const deleteHistoryEvent = (
  historyEvent: ConnectionHistoryEvent
): DeleteHistoryEventAction => ({
  type: DELETE_HISTORY_EVENT,
  historyEvent,
})

export const historyEventOccurred = (event: HistoryEventOccurredEventType) => ({
  type: HISTORY_EVENT_OCCURRED,
  event,
})

export function* historyEventOccurredSaga(
  action: HistoryEventOccurredAction
): Generator<*, *, *> {
  const { event, type } = action
  let historyEvent: ?ConnectionHistoryEvent = null

  try {
    if (event.type === INVITATION_RECEIVED) {
      historyEvent = convertInvitationToHistoryEvent(event.data.payload)
    }

    if (event.type === NEW_CONNECTION_SUCCESS) {
      historyEvent = convertConnectionSuccessToHistoryEvent(event)
    }

    if (event.type === SEND_CLAIM_REQUEST_SUCCESS) {
      historyEvent = convertSendClaimRequestSuccessToHistoryEvent(event)
      const claimOfferReceivedEvent = yield select(
        getHistoryEvent,
        historyEvent.originalPayload.uid,
        historyEvent.remoteDid,
        CLAIM_OFFER_RECEIVED
      )

      const existingEvent = yield select(
        getPendingHistory,
        historyEvent.originalPayload.uid,
        historyEvent.remoteDid,
        SEND_CLAIM_REQUEST_SUCCESS
      )
      if (existingEvent) historyEvent = null
      if (claimOfferReceivedEvent)
        yield put(deleteHistoryEvent(claimOfferReceivedEvent))
    }

    if (event.type === CLAIM_STORAGE_SUCCESS) {
      const claim: ClaimOfferPayload = yield select(
        getClaimOffer,
        event.messageId
      )
      historyEvent = convertClaimStorageSuccessToHistoryEvent(event, claim)
      const existingEvent = yield select(
        getClaimReceivedHistory,
        historyEvent.originalPayload.messageId,
        historyEvent.remoteDid,
        CLAIM_STORAGE_SUCCESS
      )
      if (existingEvent) historyEvent = null
      const pendingHistory = yield select(getPendingHistoryEvent, claim)

      if (pendingHistory) yield put(deleteHistoryEvent(pendingHistory))
    }

    if (event.type === PROOF_REQUEST_RECEIVED) {
      historyEvent = convertProofRequestToHistoryEvent(event)
      const existingEvent = yield select(
        getHistoryEvent,
        historyEvent.originalPayload.payloadInfo.uid,
        historyEvent.remoteDid,
        PROOF_REQUEST_RECEIVED
      )
      if (existingEvent) historyEvent = null
    }

    if (event.type === CLAIM_OFFER_RECEIVED) {
      historyEvent = convertClaimOfferToHistoryEvent(event)
      const existingEvent = yield select(
        getHistoryEvent,
        historyEvent.originalPayload.payloadInfo.uid,
        historyEvent.remoteDid,
        CLAIM_OFFER_RECEIVED
      )
      if (existingEvent) historyEvent = null
    }

    if (event.type === SEND_PROOF_SUCCESS) {
      const proofRequest: ProofRequestPayload = yield select(
        getProofRequest,
        event.uid
      )
      const proof: ProofRequestPayload = yield select(getProof, event.uid)
      historyEvent = convertProofSendToHistoryEvent(event, proofRequest, proof)
      const oldHistoryEvent = yield select(
        getHistoryEvent,
        historyEvent.originalPayload.uid,
        historyEvent.remoteDid,
        PROOF_REQUEST_RECEIVED
      )
      if (oldHistoryEvent) yield put(deleteHistoryEvent(oldHistoryEvent))
    }

    if (historyEvent) {
      yield put(recordHistoryEvent(historyEvent))
    }
  } catch (e) {
    captureError(e)
    yield put(
      loadHistoryFail({
        ...ERROR_HISTORY_EVENT_OCCURRED,
        message: `${ERROR_HISTORY_EVENT_OCCURRED.message} ${e.message}`,
      })
    )
  }
}

export function* watchRecordHistoryEvent(): any {
  yield takeEvery(RECORD_HISTORY_EVENT, persistHistory)
}

export function* persistHistory(action): any {
  // if we get action to record history event
  // that means our history store is updated with data
  // we can now store history data to secure storage

  const historyData: ConnectionHistoryData | null = yield select(getHistory)
  if (historyData) {
    try {
      yield call(
        secureSet,
        HISTORY_EVENT_STORAGE_KEY,
        JSON.stringify(historyData)
      )
    } catch (e) {
      // Need to figure out what happens if storage fails
      captureError(e)
      console.error(`persistHistory: ${e}`)
    }
  }
}

export function* watchHistoryEventOccurred(): any {
  yield takeEvery(HISTORY_EVENT_OCCURRED, historyEventOccurredSaga)
}

export function* watchConnectionHistory(): any {
  yield all([watchHistoryEventOccurred(), watchRecordHistoryEvent()])
}

export default function connectionHistoryReducer(
  state: ConnectionHistoryStore = initialState,
  action: HistoryEventOccurredEventType
) {
  switch (action.type) {
    case LOAD_HISTORY:
      return {
        ...state,
        isLoading: true,
      }

    case LOAD_HISTORY_SUCCESS:
      return {
        ...state,
        data: {
          ...merge(state.data, action.data),
        },
        isLoading: false,
      }

    case LOAD_HISTORY_FAIL:
      return {
        ...state,
        isLoading: false,
        error: action.error,
      }

    case RECORD_HISTORY_EVENT: {
      const { remoteDid } = action.historyEvent
      return {
        ...state,
        data: {
          ...(state.data ? state.data : {}),
          [remoteDid]: [
            ...(state.data && state.data[remoteDid]
              ? state.data[remoteDid]
              : []),
            action.historyEvent,
          ],
        },
      }
    }

    case DELETE_HISTORY_EVENT: {
      const { remoteDid } = action.historyEvent
      const filteredData =
        state.data && state.data[remoteDid]
          ? state.data[remoteDid].filter(item => {
              return item !== action.historyEvent
            })
          : []
      return {
        ...state,
        data: {
          ...(state.data ? state.data : {}),
          [remoteDid]: filteredData,
        },
      }
    }

    case RESET:
      return initialState

    default:
      return state
  }
}


<|start_filename|>app/home/home.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Animated, StyleSheet, Platform, Dimensions } from 'react-native'
import { connect } from 'react-redux'
import firebase from 'react-native-firebase'
import {
  Container,
  CustomView,
  Icon,
  UserAvatar,
  CustomText,
  CustomHeader,
  Loader,
} from '../components'

import { createStackNavigator } from 'react-navigation'
import Bubbles from './bubbles'
import {
  color,
  barStyleDark,
  OFFSET_3X,
  OFFSET_2X,
  isBiggerThanShortDevice,
  isIphoneX,
  isBiggerThanVeryShortDevice,
  whiteSmokeSecondary,
  responsiveHorizontalPadding,
} from '../common/styles'
import { primaryHeaderStyles } from '../components/layout/header-styles'
import { homeRoute, walletRoute } from '../common'
import { getConnections } from '../store/connections-store'
import type { Store } from '../store/type-store'
import type { HomeProps, HomeState } from './type-home'
import {
  FEEDBACK_TEST_ID,
  SOVRINTOKEN_TEST_ID,
  SOVRINTOKEN_AMOUNT_TEST_ID,
} from './home-constants'
import { Apptentive } from 'apptentive-react-native'
import WalletBalance from '../wallet/wallet-balance'
import type { Connection } from '../store/type-connection-store'
import Banner from '../components/banner/banner'
import { NavigationActions } from 'react-navigation'
import { getUnseenMessages } from '../store/store-selector'
import { scale } from 'react-native-size-matters'
import { size } from './../components/icon'

const { width, height } = Dimensions.get('window')

export class DashboardScreen extends PureComponent<HomeProps, HomeState> {
  state = {
    scrollY: new Animated.Value(0),
  }

  static navigationOptions = ({ navigation }) => ({
    header: (
      <CustomHeader
        backgroundColor={whiteSmokeSecondary}
        outerContainerStyles={styles.headerOuterContainer}
        largeHeader
      >
        <WalletBalance
          render={balance => (
            <CustomView
              row
              center
              onPress={() => {
                const navigateAction = NavigationActions.navigate({
                  routeName: walletRoute,
                  key: walletRoute,
                })
                navigation.dispatch(navigateAction)
              }}
              testID={SOVRINTOKEN_AMOUNT_TEST_ID}
            >
              <Icon
                small
                testID={SOVRINTOKEN_TEST_ID}
                src={require('../images/sovrinTokenOrange.png')}
              />
              <CustomText
                h5
                demiBold
                center
                style={[
                  styles.floatTokenAmount,
                  {
                    fontSize: tokenAmountSize(balance ? balance.length : 0),
                  },
                ]}
                transparentBg
                testID={SOVRINTOKEN_AMOUNT_TEST_ID}
                formatNumber
              >
                {balance}
              </CustomText>
            </CustomView>
          )}
        />

        <CustomView horizontalSpace>
          <Icon
            medium
            onPress={() => Apptentive.presentMessageCenter()}
            testID={FEEDBACK_TEST_ID}
            src={require('../images/icon_feedback_grey.png')}
          />
        </CustomView>
      </CustomHeader>
    ),
  })

  componentDidUpdate(prevProps: HomeProps) {
    const noUnSeenMessages =
      Object.keys(prevProps.unSeenMessages).length &&
      !Object.keys(this.props.unSeenMessages).length

    if (noUnSeenMessages) {
      firebase.notifications().setBadge(0)
    }
  }

  render() {
    const bubblesHeight = this.state.scrollY.interpolate({
      inputRange: [0, 5],
      outputRange: [0, -5],
      extrapolate: 'clamp',
    })

    const { connections: { data, hydrated }, unSeenMessages } = this.props
    // type casting from Array<mixed> to any and then to what we need
    // because flow Array<mixed> can't be directly type casted as of now
    const connections: Connection[] = (getConnections(data): any)
    const connectionsCheck = connections && connections.length > 0

    return (
      <Container tertiary>
        <Container tertiary>
          <Banner navigation={this.props.navigation} />
          {connectionsCheck && (
            <Bubbles
              navigation={this.props.navigation}
              height={bubblesHeight}
              connections={connections}
              unSeenMessages={unSeenMessages}
            />
          )}
          {!hydrated ? (
            <Container center>
              <Loader type="dark" delay={1000} />
            </Container>
          ) : null}
          <CustomView style={[styles.userAvatarContainer]}>
            <UserAvatar />
          </CustomView>
        </Container>
      </Container>
    )
  }
}

const mapStateToProps = (state: Store) => {
  // when ever there is change in claimOffer state and proof request state
  // getUnseenMessages selector will return updated data
  // this data is used to update red dots on connection bubbles.
  let unSeenMessages = getUnseenMessages(state)
  return {
    connections: state.connections,
    unSeenMessages,
  }
}
const getHeight = height => {
  if (isIphoneX) {
    return height - 300
  }
  if (isBiggerThanVeryShortDevice && !isBiggerThanShortDevice) {
    return height - 230
  }
  if (isBiggerThanShortDevice) {
    return height - 250
  }
  return height - 224
}
export default createStackNavigator({
  [homeRoute]: {
    screen: connect(mapStateToProps)(DashboardScreen),
  },
})

const tokenAmountSize = (tokenAmountLength: number): number => {
  // this resizing logic is different than wallet tabs header
  switch (true) {
    case tokenAmountLength < 16:
      return scale(26)
    case tokenAmountLength < 20:
      return scale(20)
    default:
      return scale(19)
  }
}

const styles = StyleSheet.create({
  userAvatarContainer: {
    backgroundColor: 'transparent',
    width: size.extraLarge, // width of user avathar icon extraLarge
    position: 'absolute',
    left: (width - size.extraLarge) / 2,
    top: getHeight(height),
  },
  floatTokenAmount: {
    color: color.actions.font.seventh,
    paddingHorizontal: 8,
  },
  headerOuterContainer: {
    paddingHorizontal: responsiveHorizontalPadding,
  },
})


<|start_filename|>app/components/CustomModal.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, Image, StyleSheet, Platform } from 'react-native'
import Modal from 'react-native-modal'
import {
  color,
  HAIRLINE_WIDTH,
  OFFSET_1X,
  OFFSET_3X,
  isiPhone5,
} from '../common/styles'
import { CustomView, CustomButton } from '../components'
import debounce from 'lodash.debounce'
import { noop } from '../common'

type CustomModalProps = {
  onPress?: (event: any) => void,
  children?: any,
  disabled?: boolean,
  buttonText?: string,
  testID: string,
  isVisible: boolean,
  accessibilityLabel?: string,
  backdropOpacity?: number,
  animationIn: string,
  animationOut: string,
  animationOutTiming: number,
  onModalHide?: () => void,
  fullScreen?: boolean,
}

export default class CustomModal extends PureComponent<CustomModalProps, void> {
  static defaultProps = {
    backdropOpacity: 1,
    animationIn: 'zoomIn',
    animationOut: 'zoomOut',
    animationOutTiming: 100,
  }

  onPressDebounce = debounce(
    event => {
      if (this.props.onPress) {
        this.props.onPress(event)
      }
    },
    600,
    { leading: true, trailing: false }
  )

  render() {
    const {
      disabled,
      onPress,
      buttonText,
      testID,
      isVisible,
      accessibilityLabel = 'Continue to see your new connection',
      backdropOpacity,
      animationIn,
      animationOut,
      animationOutTiming,
      fullScreen,
      onModalHide = noop,
    } = this.props
    return (
      <Modal
        backdropColor={color.bg.tertiary.color}
        backdropOpacity={backdropOpacity}
        isVisible={isVisible}
        animationIn={animationIn}
        animationOut={animationOut}
        animationOutTiming={animationOutTiming}
        onModalHide={onModalHide}
        useNativeDriver={true}
        hideModalContentWhileAnimating={true}
      >
        {fullScreen ? (
          <CustomView fifth>
            <CustomView>{this.props.children}</CustomView>
          </CustomView>
        ) : (
          <CustomView fifth shadow style={[styles.container]}>
            <CustomView style={[styles.innerContainer]}>
              {this.props.children}
            </CustomView>
            {onPress && (
              <CustomButton
                fifth
                disabled={disabled}
                disabledStyle={[styles.disabledStyle]}
                onPress={this.onPressDebounce}
                title={buttonText}
                testID={`${testID}-success-continue`}
                textStyle={{ fontWeight: 'bold' }}
              />
            )}
          </CustomView>
        )}
      </Modal>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    marginHorizontal: isiPhone5 ? OFFSET_1X : OFFSET_3X,
  },
  innerContainer: {
    ...Platform.select({
      ios: {
        borderBottomColor: color.bg.fifth.font.tertiary,
        borderBottomWidth: HAIRLINE_WIDTH,
      },
      android: {
        borderBottomColor: color.bg.fifth.font.secondary,
        borderBottomWidth: 1,
      },
    }),
    paddingVertical: OFFSET_1X,
  },
  disabledStyle: {
    backgroundColor: 'transparent',
  },
})


<|start_filename|>__mocks__/fetch-mock.js<|end_filename|>
import { Headers, Response, Request } from 'node-fetch'

const fetch = jest.fn(() => {})
fetch.Headers = Headers
fetch.Request = Request
fetch.Response = Response

fetch.mockResponse = (body, init) =>
  fetch.mockImplementation(
    () =>
      new Promise((resolve, reject) =>
        process.nextTick(() => resolve(new Response(body, init)))
      )
  )

fetch.mockResponseOnce = (body, init) =>
  fetch.mockImplementationOnce(
    () =>
      new Promise((resolve, reject) =>
        process.nextTick(() => resolve(new Response(body, init)))
      )
  )

fetch.mockResponses = (...responses) =>
  responses.map(([body, init]) =>
    fetch.mockImplementationOnce(
      () =>
        new Promise((resolve, reject) =>
          process.nextTick(() => resolve(new Response(body, init)))
        )
    )
  )

export default fetch


<|start_filename|>app/restore/type-restore.js<|end_filename|>
// @flow
import type { ReactNavigation, CustomError } from '../common/type-common'
import type { Store } from '../store/type-store'

export const SAVE_FILE_TO_APP_DIRECTORY: 'SAVE_FILE_TO_APP_DIRECTORY' =
  'SAVE_FILE_TO_APP_DIRECTORY'
export const RESTORE_STATUS: 'RESTORE_STATUS' = 'RESTORE_STATUS'
export const ERROR_RESTORE: 'ERROR_RESTORE' = 'ERROR_RESTORE'
export const RESTORE_SUBMIT_PASSPHRASE: 'RESTORE_SUBMIT_PASSPHRASE' =
  'RESTORE_SUBMIT_PASSPHRASE'
export const RESTORE_RESET: 'RESTORE_RESET' = 'RESTORE_RESET'

export const RestoreStatus = {
  ZIP_FILE_SELECTED: 'ZIP_FILE_SELECTED',
  fileSaved: 'FILE_SAVED_TO_APP_DIRECTORY',
  FILE_SAVE_ERROR: 'FILE_SAVE_ERROR',
  DECRYPTION_START: 'DECRYPTION_START',
  FILE_DECRYPT_SUCCESS: 'FILE_DECRYPT_SUCCESS',
  RESTORE_DATA_STORE_START: 'RESTORE_DATA_STORE_START',
  RESTORE_DATA_STORE_SUCCESS: 'RESTORE_DATA_STORE_SUCCESS',
  success: 'RESTORE_SUCCESS',
  failedStatus: 'RESTORE_FAILED',
  none: 'none',
}

export const initialState = {
  status: RestoreStatus.none,
  error: null,
  restoreFile: {
    fileName: '',
    fileSize: 0,
    type: '',
    uri: '',
  },
}

export type SaveToAppDirectory = {
  fileName: string,
  fileSize: number,
  type: string,
  uri: string,
}

export type RestoreSubmitPassphrase = {
  type: typeof RESTORE_SUBMIT_PASSPHRASE,
  passphrase: string,
}

export type ResetRestoreAction = {
  type: typeof RESTORE_RESET,
}

export type SaveFiletoAppDirectoryAction = {
  type: typeof SAVE_FILE_TO_APP_DIRECTORY,
  data: SaveToAppDirectory,
}

export type ErrorRestoreAction = {
  type: typeof ERROR_RESTORE,
  error: ?CustomError,
}

export type RestoreStatusAction = {
  type: typeof RESTORE_STATUS,
  status: string,
}

export type RestoreSubmitPassphraseAction = {
  type: typeof RESTORE_SUBMIT_PASSPHRASE,
  passphrase: string,
}

export type RestoreActions =
  | SaveFiletoAppDirectoryAction
  | ErrorRestoreAction
  | RestoreStatusAction
  | RestoreSubmitPassphraseAction
  | ResetRestoreAction

export type RestoreStore = {
  restoreFile: SaveToAppDirectory,
} & StoreError &
  RestoreStoreStatus

export type StoreError = { error: ?CustomError }
export type RestoreStoreStatus = { status: $Keys<typeof RestoreStatus> }

export type RestoreProps = {
  updateStatusBarTheme: string => void,
  saveFileToAppDirectory: SaveToAppDirectory => void,
  restore: RestoreStoreType,
  route: string,
} & ReactNavigation

export type RestorePassphraseProps = {
  submitPassphrase: string => void,
  restore: RestoreStoreType,
} & ReactNavigation

export type RestoreStoreType = {
  status: $Keys<typeof RestoreStatus>,
  error: ?CustomError,
  restoreFile: {
    fileName: string,
    fileSize: number,
    type: string,
    uri: string,
  },
}

export type RestoreWaitScreenProps = {
  restore: RestoreStoreType,
  route: string,
} & ReactNavigation

export const ERROR_RESTORE_FILE = {
  code: 'WR-001',
  message: 'Error while restoring',
}

export const FILE_SAVE_ERROR_MESSAGE = (message: string) => ({
  code: 'WR-002',
  message: `Error while saving file to app directory:${message}`,
})

export const DECRYPT_FAILED_MESSAGE = (message: string) => ({
  code: 'WR-003',
  message: `Error while decryption:${message}`,
})

export const RESTORE_BACK_BUTTON_TEST_ID = 'restore-back-button'
export const RESTORE_CLOSE_BUTTON_TEST_ID = 'restore-close-button'
export const RESTORE_DATA_FAILED_MESSAGE = (message: string) => ({
  code: 'WR-004',
  message: `Error while restoring data store:${message}`,
})


<|start_filename|>app/components/input-control/__tests__/input-control.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import ControlInput from '../input-control'

describe('<WalletTabSendDetails />', () => {
  let onChangeText = jest.fn()
  let validation = jest.fn()
  function setup() {
    const component = renderer.create(
      <ControlInput
        onChangeText={onChangeText}
        placeholder="test"
        label="To"
        name="paymentTo"
        multiline={false}
        validation={validation}
        isValid={'IDLE'}
      />
    )
    const instance = component.root.findByType(ControlInput).instance
    return { component, instance }
  }
  it('should render properly and match the snapshot', () => {
    const { component } = setup()
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})


<|start_filename|>app/components/banner/banner-offline.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { CustomView, Icon, CustomText } from '../index'
import {
  IMAGE_WIDTH,
  IMAGE_HEIGHT,
  BACKUP_BANNER_TEST_ID,
  BANNER_HEIGHT,
} from './banner-constants'
import { color, dangerBannerHeight } from '../../common/styles'
import type { OfflineBannerProps } from './type-banner'

export class OfflineBanner extends PureComponent<OfflineBannerProps, void> {
  render() {
    return (
      <CustomView
        row
        vCenter
        horizontalSpace
        verticalSpace
        style={[styles.bannerContainer, this.props.style || {}]}
        onPress={this.props.onPress}
        testID={this.props.testID}
      >
        <CustomView horizontalSpace>
          <CustomText bold transparentBg center errorText h5>
            {this.props.bannerTitle}
          </CustomText>
        </CustomView>
      </CustomView>
    )
  }
}

const styles = StyleSheet.create({
  bannerContainer: {
    backgroundColor: color.palePink,
  },
})


<|start_filename|>app/components/pin-code/pin-code-box.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { TextInput, StyleSheet, Platform, Keyboard, Text } from 'react-native'
import { PIN_SETUP_STATE } from '../../lock/type-lock'
import PinCodeDigit from './pin-code-digit'
import { CustomView, Keyboard as CustomKeyboard } from '../../components'
import type {
  PinCodeBoxProps,
  PinCodeBoxState,
  TextInputRef,
} from './type-pin-code-box'
import { color } from '../../common/styles/constant'

const keyboard = Platform.OS === 'ios' ? 'number-pad' : 'numeric'

const isDigit = text => {
  if (isNaN(parseInt(text))) {
    return false
  }

  return true
}

export default class PinCodeBox extends PureComponent<
  PinCodeBoxProps,
  PinCodeBoxState
> {
  state = {
    pin: '',
  }

  keyboardDidHideListener = null

  customKeyboardRef = null

  inputBox: ?TextInputRef = null

  pinCodeArray = [1, 2, 3, 4, 5, 6]

  maxLength = 6

  maxValue = '999999'

  componentDidMount = () => {
    this.keyboardDidHideListener = Keyboard.addListener(
      'keyboardDidHide',
      this.hideKeyboard
    )
  }

  componentWillUnMount = () => {
    this.keyboardDidHideListener && this.keyboardDidHideListener.remove()
  }

  onPinChange = (pin: string) => {
    if (pin === '' || isDigit(pin.substr(pin.length - 1))) {
      this.setState({ pin }, this.onPinSet)
    }
  }

  clear = () => {
    // parent can call this to clear entered input
    // either in case pin was wrong, or we want them to enter it again
    this.inputBox && this.inputBox.clear()
    this.customKeyboardRef && this.customKeyboardRef.clear()
    this.setState({ pin: '' })
  }

  hideKeyboard = () => {
    this.inputBox && this.inputBox.blur()
  }

  showKeyboard = () => {
    this.inputBox && this.inputBox.focus()
  }

  onPinSet = () => {
    // need to call this method after user value is set in state
    // here we can check if we got 6 digits, if yes, that means
    // we can say pin input is complete and let parent component
    // handle what to do after pin input is complete
    // while setting pin, parent can clear it and ask for pin again
    // while entering pin to unlock, parent can match pin in keychain
    if (this.state.pin.length === 6) {
      this.props.onPinComplete(this.state.pin)
    }
  }
  saveCustomKeyboardRef: Function = (ref: CustomKeyboard) =>
    (this.customKeyboardRef = ref)
  customKeyboard = () => {
    if (this.props.enableCustomKeyboard) {
      return (
        <CustomKeyboard
          maxLength={this.maxLength}
          onPress={this.onPinChange}
          color={color.bg.seventh.font.fifth}
          customKeyboard
          showDecimal
          ref={this.saveCustomKeyboardRef}
          maxValue={this.maxValue}
        />
      )
    }
    return null
  }

  render() {
    return (
      <CustomView>
        <CustomView onPress={this.showKeyboard} row>
          {this.pinCodeArray.map((keycode, index) => {
            return (
              <PinCodeDigit
                onPress={this.showKeyboard}
                key={index}
                entered={this.state.pin[index] !== undefined}
                testID={`pin-code-digit-${index}`}
              />
            )
          })}
        </CustomView>
        {this.customKeyboard()}
        <TextInput
          autoCorrect={false}
          autoFocus={true}
          blurOnSubmit={false}
          enablesReturnKeyAutomatically={false}
          keyboardType={keyboard}
          keyboardAppearance="dark"
          maxLength={this.maxLength}
          onChangeText={this.onPinChange}
          ref={inputBox => {
            this.inputBox = inputBox
          }}
          style={styles.input}
          testID="pin-code-input-box"
          accessible={true}
          accessibilityLabel={`pin-code-input-box`}
          value={this.state.pin}
        />
      </CustomView>
    )
  }
}

const styles = StyleSheet.create({
  input: {
    position: 'absolute',
    right: -999,
    height: 0,
    width: 0,
  },
})


<|start_filename|>app/store/type-config-store.js<|end_filename|>
// @flow
import type { CustomError } from '../common/type-common'
import {
  splashScreenRoute,
  lockSelectionRoute,
  switchEnvironmentRoute,
  eulaRoute,
  restoreRoute,
} from '../common/route-constants'

export const SERVER_ENVIRONMENT = {
  DEMO: 'DEMO',
  SANDBOX: 'SANDBOX',
  STAGING: 'STAGING',
  DEVELOPMENT: 'DEVELOPMENT',
  QATEST1: 'QATEST1',
  QATEST2: 'QATEST2',
  DEVRC: 'DEVRC',
  QARC: 'QARC',
}

export const __uniqueId = '__uniqueId'

export type ServerEnvironment = $Keys<typeof SERVER_ENVIRONMENT>

export const APP_INSTALLED = 'APP_INSTALLED'
export type AppInstalledSuccessAction = {
  type: typeof APP_INSTALLED,
}

export const HYDRATED = 'HYDRATED'
export type HydratedAction = {
  type: typeof HYDRATED,
}

export const INITIALIZED = 'INITIALIZED'
export type InitializedAction = {
  type: typeof INITIALIZED,
}
export const ALREADY_INSTALLED_RESULT = 'ALREADY_INSTALLED_RESULT'
export type AlreadyInstalledAction = {
  type: typeof ALREADY_INSTALLED_RESULT,
  isAlreadyInstalled: boolean,
}

export const SERVER_ENVIRONMENT_CHANGED = 'SERVER_ENVIRONMENT_CHANGED'
export type ServerEnvironmentChangedAction = {
  type: typeof SERVER_ENVIRONMENT_CHANGED,
  serverEnvironment: ServerEnvironment,
}

export const SWITCH_ENVIRONMENT = 'SWITCH_ENVIRONMENT'
export type ChangeEnvironment = {
  agencyUrl: string,
  poolConfig: string,
  agencyDID: string,
  agencyVerificationKey: string,
}

export type SwitchEnvironmentAction = {
  type: typeof SWITCH_ENVIRONMENT,
} & ChangeEnvironment

export const SWITCH_ERROR_ALERTS = 'SWITCH_ERROR_ALERTS'
export type SwitchErrorAlertsAction = {
  type: typeof SWITCH_ERROR_ALERTS,
}

export const TOGGLE_ERROR_ALERTS = 'TOGGLE_ERROR_ALERTS'
export type ToggleErrorAlertsAction = {
  type: typeof TOGGLE_ERROR_ALERTS,
  isShowErrorAlert: boolean,
}

export const SAVE_SWITCH_ENVIRONMENT_DETAIL_FAIL =
  'SAVE_SWITCH_ENVIRONMENT_DETAIL_FAIL'
export type SaveSwitchEnvironmentDetailFailAction = {
  type: typeof SAVE_SWITCH_ENVIRONMENT_DETAIL_FAIL,
  error: CustomError,
}

export const HYDRATE_SWITCH_ENVIRONMENT_DETAIL_FAIL =
  'HYDRATE_SWITCH_ENVIRONMENT_DETAIL_FAIL'

export type HydrateSwitchEnvironmentDetailFailAction = {
  type: typeof HYDRATE_SWITCH_ENVIRONMENT_DETAIL_FAIL,
  error: CustomError,
}

export const CHANGE_ENVIRONMENT_VIA_URL = 'CHANGE_ENVIRONMENT_VIA_URL'
export type ChangeEnvironmentUrlAction = {
  type: typeof CHANGE_ENVIRONMENT_VIA_URL,
  url: string,
}

export const VCX_INIT_NOT_STARTED = 'VCX_INIT_NOT_STARTED'

export const VCX_INIT_START = 'VCX_INIT_START'
export type VcxInitStartAction = {
  type: typeof VCX_INIT_START,
}

export const VCX_INIT_SUCCESS = 'VCX_INIT_SUCCESS'
export type VcxInitSuccessAction = {
  type: typeof VCX_INIT_SUCCESS,
}

export const VCX_INIT_FAIL = 'VCX_INIT_FAIL'
export type VcxInitFailAction = {
  type: typeof VCX_INIT_FAIL,
  error: CustomError,
}

export const USE_VCX = 'USE_VCX'
export type UseVcxAction = {
  type: typeof USE_VCX,
}

export type ConfigAction =
  | HydratedAction
  | InitializedAction
  | AppInstalledSuccessAction
  | AlreadyInstalledAction
  | ServerEnvironmentChangedAction
  | SwitchErrorAlertsAction
  | ToggleErrorAlertsAction
  | SwitchEnvironmentAction
  | SaveSwitchEnvironmentDetailFailAction
  | HydrateSwitchEnvironmentDetailFailAction
  | ChangeEnvironmentUrlAction
  | VcxInitStartAction
  | VcxInitFailAction
  | VcxInitSuccessAction
  | UseVcxAction

export type VcxInitializationState =
  | typeof VCX_INIT_NOT_STARTED
  | typeof VCX_INIT_START
  | typeof VCX_INIT_SUCCESS
  | typeof VCX_INIT_FAIL

export type AgencyPoolConfig = {
  agencyUrl: string,
  agencyDID: string,
  agencyVerificationKey: string,
  poolConfig: string,
}

export type ConfigStore = {
  isAlreadyInstalled: boolean,
  isHydrated: boolean,
  showErrorAlerts: boolean,
  vcxInitializationState: VcxInitializationState,
  vcxInitializationError: null | CustomError,
  isInitialized: boolean,
} & AgencyPoolConfig

export const STORAGE_KEY_SWITCHED_ENVIRONMENT_DETAIL =
  'STORAGE_KEY_SWITCHED_ENVIRONMENT_DETAIL'

export const ERROR_SAVE_SWITCH_ENVIRONMENT = {
  code: 'CS-000',
  message: 'Failed to store switched environment details: ',
}

export const ERROR_HYDRATE_SWITCH_ENVIRONMENT = {
  code: 'CS-001',
  message: 'Failed to hydrate switched environment details: ',
}

export const schemaDownloadedEnvironmentDetails = {
  type: 'object',
  properties: {
    agencyUrl: {
      type: 'string',
    },
    agencyDID: {
      type: 'string',
    },
    agencyVerificationKey: {
      type: 'string',
    },
    poolConfig: {
      type: 'string',
    },
  },
  required: ['agencyDID', 'agencyUrl', 'agencyVerificationKey', 'poolConfig'],
}

export const MESSAGE_FAIL_ENVIRONMENT_SWITCH_TITLE =
  'Failed to switch environment'

export const ERROR_NO_WALLET_NAME = 'Wallet name not found'

export const MESSAGE_FAIL_ENVIRONMENT_SWITCH_INVALID_DATA = (url: string) =>
  `Data returned by ${url} is not valid as per our requirements.`

export const MESSAGE_FAIL_ENVIRONMENT_SWITCH_ERROR = (message: string) =>
  `Failed to switch environment due to following error. ${message}`

export const MESSAGE_SUCCESS_ENVIRONMENT_SWITCH_TITLE = 'Success'

export const MESSAGE_SUCCESS_ENVIRONMENT_SWITCH_DESCRIPTION =
  'Environment switched successfully.'

export const ERROR_VCX_INIT_FAIL = (message: string) => ({
  code: `CS-002`,
  message: `Failed to init vcx: ${message}`,
})

export const ERROR_VCX_PROVISION_FAIL = (message: string) => ({
  code: `CS-003`,
  message: `Failed to provision vcx: ${message}`,
})

export const UNSAFE_SCREENS_TO_DOWNLOAD_SMS = [
  splashScreenRoute,
  lockSelectionRoute,
  switchEnvironmentRoute,
  eulaRoute,
  restoreRoute,
]

export type DownloadedMessage = {
  statusCode: string,
  payload?: ?any,
  senderDID: string,
  uid: string,
  type: string,
  refMsgId?: ?string,
  deliveryDetails: Array<any>,
  decryptedPayload?: string,
}
export type DownloadedConnectionMessages = {
  pairwiseDID: string,
  msgs: Array<DownloadedMessage>,
}
export type DownloadedConnectionsWithMessages = Array<
  DownloadedConnectionMessages
>
export type AcknowledgeServerData = Array<{
  pairwiseDID: string,
  uids: Array<string>,
}>

export const MESSAGE_RESPONSE_CODE = {
  MESSAGE_CREATED: 'MS-101',
  MESSAGE_SENT: 'MS-102',
  MESSAGE_PENDING: 'MS-103',
  MESSAGE_ACCEPTED: 'MS-104',
  MESSAGE_REJECTED: 'MS-105',
  MESSAGE_ANSWERED: 'MS-106',
}

export type MessageClaimOfferDetails = {|
  claim_id: string,
  claim_name: string,
  cred_def_id: string,
  credential_attrs: {
    [string]: string,
  },
  from_did: string,
  libindy_offer: string,
  msg_ref_id: ?string,
  msg_type: string,
  schema_seq_no: number,
  to_did: string,
  version: string,
|}

export type SerializedClaimOfferData = {
  agent_did: null,
  agent_vk: null,
  cred_id: null,
  credential: null,
  credential_name: null,
  credential_offer: ?MessageClaimOfferDetails,
  credential_request: null,
  msg_uid: null,
  my_did: null,
  my_vk: null,
  payment_info: ?MessagePaymentDetails,
  payment_txn: null,
  source_id: string,
  state: number,
  their_did: null,
  their_vk: null,
}

export type MessagePaymentDetails = {|
  payment_addr: string,
  payment_required: string,
  price: number,
|}

export type ParsedDecryptedPayloadMessage = Array<
  MessageClaimOfferDetails | MessagePaymentDetails
>
export type ParsedDecryptedPayload = {
  '@msg': string,
  '@type': {
    fmt: string,
    name: string,
    ver: string,
  },
}

export const ACKNOWLEDGE_MESSAGES_FAIL = 'ACKNOWLEDGE_MESSAGES_FAIL'
export const GET_MESSAGES_FAIL = 'GET_MESSAGES_FAIL'
export const ACKNOWLEDGE_MESSAGES = 'ACKNOWLEDGE_MESSAGES'
export const GET_MESSAGES_SUCCESS = 'GET_MESSAGES_SUCCESS'
export const GET_MESSAGES_LOADING = 'GET_MESSAGES_LOADING'
export const GET_UN_ACKNOWLEDGED_MESSAGES = 'GET_UN_ACKNOWLEDGED_MESSAGES'

export type GetUnacknowledgedMessagesAction = {
  type: typeof GET_UN_ACKNOWLEDGED_MESSAGES,
}
export type GetMessagesLoadingAction = {
  type: typeof GET_MESSAGES_LOADING,
}

export type GetMessagesSuccessAction = {
  type: typeof GET_MESSAGES_SUCCESS,
}

export type AcknowledgeMessagesAction = {
  type: typeof ACKNOWLEDGE_MESSAGES,
}

export type GetMessagesFailAction = {
  type: typeof GET_MESSAGES_FAIL,
}

export type AcknowledgeMessagesFailAction = {
  type: typeof ACKNOWLEDGE_MESSAGES_FAIL,
  error: string,
}


<|start_filename|>connectMeUITest/src/funcModules/ClaimOfferModules.java<|end_filename|>
package funcModules;

import appModules.AppUtlis;
import appModules.LibIndy;
import appModules.RestApi;
import io.appium.java_client.AppiumDriver;
import pageObjects.ClaimOfferPage;
import pageObjects.ConnectionDetailPage;

public class ClaimOfferModules {
	
	AppUtlis appUtlisObj=new AppUtlis();
	RestApi  restApiObj=new RestApi();
	
	
	
	public void SendClaimOffer(AppiumDriver driver) throws Exception
	{
		//appUtlisObj.sendClaimofferRestApi();
		ClaimOfferPage.Accept_Button(driver).click();

    }
	
}




<|start_filename|>app/claim-offer/claim-request-modal.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, StyleSheet, Image, Platform } from 'react-native'
import { Button } from 'react-native-elements'
import Modal from 'react-native-modal'
import {
  CustomModal,
  CustomView,
  AvatarsPair,
  CustomText,
  Loader,
  Container,
  CustomButton,
} from '../components'
import {
  OFFSET_3X,
  OFFSET_4X,
  OFFSET_6X,
  OFFSET_7X,
  HAIRLINE_WIDTH,
  whiteSmoke,
  isiPhone5,
  white,
} from '../common/styles/constant'
import { color, font, OFFSET_1X, OFFSET_2X } from '../common/styles'
import {
  CLAIM_REQUEST_STATUS,
  ACCEPTING_TEXT,
  PAYING_TEXT,
} from './type-claim-offer'
import type { GenericObject } from '../common/type-common'
import type {
  ClaimRequestStatusModalProps,
  ClaimRequestStatusModalState,
  ClaimRequestStatus,
} from './type-claim-offer'
import { formatNumbers } from '../components/text'

const ClaimRequestModalText = (props: { children: string, bold?: boolean }) => (
  <CustomText
    h5
    center
    tertiary
    bg="tertiary"
    transparentBg
    style={[styles.message]}
    testID={`claim-request-message`}
    bold={props.bold}
  >
    {props.children}
  </CustomText>
)

export class ClaimRequestStatusModal extends PureComponent<
  ClaimRequestStatusModalProps,
  ClaimRequestStatusModalState
> {
  // modalText: string
  state = {
    modalText: '',
  }

  // only states for which claim request modal will be visible
  visibleStates = [
    CLAIM_REQUEST_STATUS.SENDING_CLAIM_REQUEST,
    CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST,
  ]

  successStates = [
    CLAIM_REQUEST_STATUS.CLAIM_REQUEST_SUCCESS,
    CLAIM_REQUEST_STATUS.PAID_CREDENTIAL_REQUEST_SUCCESS,
    CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_SUCCESS,
  ]

  onContinue = () => {
    setTimeout(() => {
      this.props.onContinue()
    }, 1)
  }

  componentDidMount() {
    if (
      this.props.claimRequestStatus ===
      CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST
    ) {
      this.setState({
        modalText: PAYING_TEXT,
      })
    } else if (
      this.props.claimRequestStatus ===
        CLAIM_REQUEST_STATUS.SENDING_CLAIM_REQUEST &&
      this.state.modalText !== ACCEPTING_TEXT
    ) {
      this.setState({
        modalText: ACCEPTING_TEXT,
      })
    } else {
    }
  }

  componentDidUpdate(
    prevProps: ClaimRequestStatusModalProps,
    prevState: ClaimRequestStatusModalState
  ) {
    if (
      prevProps.claimRequestStatus !== this.props.claimRequestStatus &&
      this.visibleStates.indexOf(this.props.claimRequestStatus) < 0
    ) {
      this.props.onModalHide && this.props.onModalHide()
    }
  }

  render() {
    const {
      claimRequestStatus,
      payload: { issuer, data },
      senderLogoUrl,
      isPending = false,
      message1,
      message3,
      message5,
      message6, //message6 is for payTokenValue related usage
      payTokenValue,
      fromConnectionHistory = false,
    }: ClaimRequestStatusModalProps = this.props
    let message2 = data.name
    let message4 = issuer.name
    if (isPending || payTokenValue) {
      message2 = issuer.name
      message4 = `"${data.name}"`
    }

    if (payTokenValue) {
      message2 = `for ${data.name}`
      message4 = ''
    }

    const isSendingPaidCredentialRequest =
      claimRequestStatus ===
      CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST
    const isSendingCredentialRequest =
      claimRequestStatus === CLAIM_REQUEST_STATUS.SENDING_CLAIM_REQUEST
    const isSending =
      isSendingPaidCredentialRequest || isSendingCredentialRequest
    const avatarRight = senderLogoUrl
      ? { uri: senderLogoUrl }
      : require('../images/logo_sovrin.png')
    const { middleImage, middleImageStyle } =
      isPending || isSending
        ? payTokenValue || isSending
          ? {
              middleImage: require('../images/connectArrowsRight.png'),
              middleImageStyle: styles.connectedArrowRight,
            }
          : {
              middleImage: require('../images/connectArrows.png'),
              middleImageStyle: styles.connectedArrow,
            }
        : {
            middleImage: require('../images/checkMark.png'),
            middleImageStyle: null,
          }
    const conditionalMessage =
      message6 !== undefined ? (payTokenValue ? message6 : null) : message5

    const modalProps =
      isPending && !isSending
        ? {
            onPress: this.onContinue,
            buttonText: 'Continue',
          }
        : {
            fullScreen: true,
          }
    return (
      <Container center={!(isPending && !fromConnectionHistory)}>
        {isPending && !fromConnectionHistory ? (
          <Container center fifth>
            <CustomView center style={[styles.loaderHeading]}>
              <CustomText
                h5
                center
                tertiary
                bg="tertiary"
                transparentBg
                style={[{ marginBottom: OFFSET_1X / 2 }]}
                bold
              >
                {isPending && fromConnectionHistory
                  ? message2
                  : this.state.modalText}
              </CustomText>
              {isPending && !fromConnectionHistory && <Loader />}
            </CustomView>
          </Container>
        ) : (
          <CustomView
            center
            shadow
            style={[styles.container, styles.backgroundColor]}
          >
            <CustomView style={[styles.innerContainer]} center verticalSpace>
              {isPending &&
                fromConnectionHistory && (
                  <AvatarsPair
                    middleImage={middleImage}
                    middleImageStyle={middleImageStyle}
                    avatarRight={avatarRight}
                    testID={'claim-request'}
                  />
                )}
              {isPending &&
                !isSending && (
                  <ClaimRequestModalText>{message1}</ClaimRequestModalText>
                )}

              {isPending && payTokenValue && !isSendingPaidCredentialRequest ? (
                <ClaimRequestModalText bold>
                  {`${formatNumbers(payTokenValue)} tokens`}
                </ClaimRequestModalText>
              ) : null}

              <ClaimRequestModalText bold>
                {isPending && fromConnectionHistory
                  ? message2
                  : this.state.modalText}
              </ClaimRequestModalText>

              {isPending && !isSending && message3 ? (
                <ClaimRequestModalText>{message3}</ClaimRequestModalText>
              ) : null}

              {isPending && !isSending && !payTokenValue ? (
                <ClaimRequestModalText bold>{message4}</ClaimRequestModalText>
              ) : null}

              {isPending &&
                conditionalMessage &&
                fromConnectionHistory &&
                !isSending && (
                  <ClaimRequestModalText>
                    {conditionalMessage}
                  </ClaimRequestModalText>
                )}
            </CustomView>
            <CustomButton
              fifth
              onPress={this.onContinue}
              title={'Continue'}
              textStyle={{ fontWeight: 'bold', color: '#85BF43' }}
            />
          </CustomView>
        )}
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  connectedArrow: {
    height: 20,
    width: 80,
    zIndex: -1,
    right: 7,
  },
  connectedArrowRight: {
    height: 20,
    width: 80,
    zIndex: -1,
  },
  message: {
    marginBottom: OFFSET_1X / 2,
  },
  title: {
    marginBottom: OFFSET_1X,
  },
  fullScreen: {
    flex: 1,
  },
  container: {
    marginHorizontal: OFFSET_3X,
  },
  innerContainer: {
    ...Platform.select({
      ios: {
        borderBottomColor: color.bg.fifth.font.tertiary,
        borderBottomWidth: HAIRLINE_WIDTH,
      },
      android: {
        borderBottomColor: color.bg.fifth.font.secondary,
        borderBottomWidth: 1,
      },
    }),
    padding: OFFSET_2X,
  },
  backgroundColor: {
    backgroundColor: white,
  },
  loaderHeading: { height: '84%' },
})


<|start_filename|>connectMeUITest/src/test/java/App2NegativeTest.java<|end_filename|>
 
package test.java;

import io.appium.java_client.AppiumDriver;
import org.testng.annotations.*;
import appModules.AppUtlis;
import appModules.ReadMail;
import funcModules.ConnectionModules;
import funcModules.LockModules;
import utility.*;
@Test
public class App2NegativeTest {

	public  AppiumDriver driver;
	public static String pairwiseDID;
	AppUtlis appUtlisObj=new AppUtlis();
	LockModules lockModlesObj=new LockModules();
	ConnectionModules connectionModulesObj =new ConnectionModules();


	@BeforeClass //testng 
	public void BeforeClass() throws Exception {
	   
		System.out.println(" Before class of second class");


	}
	
	
	  @Test (groups = {"Regression"})
	   public void App0Install() throws Exception {
    	pairwiseDID= appUtlisObj.sendSmsRestApi();
    	Thread.sleep(30000);
    	String InstallConnectMeLink =ReadMail.GetInstallLInk();
    	Thread.sleep(3000);
    	driver = Setup.ConfigureDriver("Safari");
     	connectionModulesObj.InstallApp(driver,InstallConnectMeLink);
		  driver.quit();
      AppUtlis.Success=true;
        

    }
	
	
    @Test (groups = {"Regression"})
	public void App1PinCodeInvalidSetup()throws Exception{
	    appUtlisObj.CheckSkip();
	    Thread.sleep(60000);
		driver = Setup.ConfigureDriver("App");
		lockModlesObj.InvalidPinCodeSetup(driver);
		AppUtlis.Success=true;		

	   }
    
    @Test (groups = {"Regression"})
	public void App2PinCodevalidSetup()throws Exception{
		
		appUtlisObj.CheckSkip();
		lockModlesObj.PinCodeSetup(driver);
		AppUtlis.Success=true;		
	
	   }
	

	
    @Test (groups = {"Regression"})
	public void App3ProvisoningDeny()throws Exception{
		
		appUtlisObj.CheckSkip();
		connectionModulesObj.AppProvisioningRequest("Deny",driver);
		AppUtlis.Success=true;		

		
	}
    
    
    @Test (groups = {"Regression"})
	public void App4EnterInvalidPincode()throws Exception{
    driver.quit();
		driver = Setup.ConfigureDriver("App");
		appUtlisObj.enterPincodeReverse(driver);
		AppUtlis.Success=true;		

		
	}

    @AfterClass
	public void afterClass() {
		 driver.removeApp("com.evernym.connectme.callcenter");
		 driver.quit();
		 System.out.println("Cleaning up Completed");

	}
    
}

<|start_filename|>app/claim-offer/type-claim-offer.js<|end_filename|>
// @flow
import type {
  CustomError,
  ResetAction,
  NotificationPayload,
} from '../common/type-common'
import type {
  AdditionalDataPayload,
  ClaimProofNavigation,
  Attribute,
  NotificationPayloadInfo,
} from '../push-notification/type-push-notification'

export const CLAIM_OFFER_STATUS = {
  IDLE: 'IDLE',
  RECEIVED: 'RECEIVED',
  SHOWN: 'SHOWN',
  ACCEPTED: 'ACCEPTED',
  IGNORED: 'IGNORED',
  REJECTED: 'REJECTED',
}
export const VCX_CLAIM_OFFER_STATE = {
  NONE: 0,
  INITIALIZED: 1,
  UNFULFILLED: 5,
  EXPIRED: 6,
  REVOKED: 7,
  RECEIVED: 3,
  SENT: 2,
  ACCEPTED: 4,
}

export const ACCEPTING_TEXT = 'Accepting...'
export const PAYING_TEXT = 'Paying...'

export const CREDENTIAL_OFFER_MODAL_STATUS = {
  NONE: 'NONE',
  INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',
  LEDGER_FEES: 'LEDGER_FEES',
  CREDENTIAL_REQUEST_STATUS: 'CREDENTIAL_REQUEST_STATUS',
  SEND_PAID_CREDENTIAL_REQUEST_FAIL: 'SEND_PAID_CREDENTIAL_REQUEST_FAIL',
  CREDENTIAL_REQUEST_FAIL: 'CREDENTIAL_REQUEST_FAIL',
  TOKEN_SENT_FAIL: 'TOKEN_SENT_FAIL',
}
export type ClaimOfferStatus = $Keys<typeof CLAIM_OFFER_STATUS>

export const CLAIM_OFFER_RECEIVED = 'CLAIM_OFFER_RECEIVED'
export type ClaimOfferReceivedAction = {
  type: typeof CLAIM_OFFER_RECEIVED,
  payload: AdditionalDataPayload,
  payloadInfo: NotificationPayloadInfo,
}

export const CLAIM_OFFER_FAILED = 'CLAIM_OFFER_FAILED'
export type ClaimOfferFailedAction = {
  type: typeof CLAIM_OFFER_FAILED,
  error: CustomError,
  uid: string,
}

export const CLAIM_OFFER_SHOWN = 'CLAIM_OFFER_SHOWN'
export type ClaimOfferShownAction = {
  type: typeof CLAIM_OFFER_SHOWN,
  uid: string,
}

export const CLAIM_OFFER_ACCEPTED = 'CLAIM_OFFER_ACCEPTED'
export type ClaimOfferAcceptedAction = {
  type: typeof CLAIM_OFFER_ACCEPTED,
  uid: string,
}

export const CLAIM_OFFER_REJECTED = 'CLAIM_OFFER_REJECTED'
export type ClaimOfferRejectedAction = {
  type: typeof CLAIM_OFFER_REJECTED,
  uid: string,
}

export const CLAIM_OFFER_IGNORED = 'CLAIM_OFFER_IGNORED'
export type ClaimOfferIgnoredAction = {
  type: typeof CLAIM_OFFER_IGNORED,
  uid: string,
}

export const SEND_CLAIM_REQUEST = 'SEND_CLAIM_REQUEST'
export type SendClaimRequestAction = {
  type: typeof SEND_CLAIM_REQUEST,
  uid: string,
  payload: ClaimOfferPayload,
}

export const SEND_CLAIM_REQUEST_SUCCESS = 'SEND_CLAIM_REQUEST_SUCCESS'
export type SendClaimRequestSuccessAction = {
  type: typeof SEND_CLAIM_REQUEST_SUCCESS,
  uid: string,
  payload: ClaimOfferPayload,
}

export const SEND_CLAIM_REQUEST_FAIL = 'SEND_CLAIM_REQUEST_FAIL'
export type SendClaimRequestFailAction = {
  type: typeof SEND_CLAIM_REQUEST_FAIL,
  uid: string,
}

export const CLAIM_REQUEST_SUCCESS = 'CLAIM_REQUEST_SUCCESS'
export type ClaimRequestSuccessAction = {
  type: typeof CLAIM_REQUEST_SUCCESS,
  uid: string,
}

export const INSUFFICIENT_BALANCE = 'INSUFFICIENT_BALANCE'
export type InsufficientBalanceAction = {
  type: typeof INSUFFICIENT_BALANCE,
  uid: string,
}

export const SEND_PAID_CREDENTIAL_REQUEST = 'SEND_PAID_CREDENTIAL_REQUEST'
export type SendPaidCredentialRequestAction = {
  type: typeof SEND_PAID_CREDENTIAL_REQUEST,
  uid: string,
  payload: ClaimOfferPayload,
}

export const PAID_CREDENTIAL_REQUEST_SUCCESS = 'PAID_CREDENTIAL_REQUEST_SUCCESS'
export type PaidCredentialRequestSuccessAction = {
  type: typeof PAID_CREDENTIAL_REQUEST_SUCCESS,
  uid: string,
}

export const PAID_CREDENTIAL_REQUEST_FAIL = 'PAID_CREDENTIAL_REQUEST_FAIL'
export type PaidCredentialRequestFailAction = {
  type: typeof PAID_CREDENTIAL_REQUEST_FAIL,
  uid: string,
}

export const CLAIM_REQUEST_FAIL = 'CLAIM_REQUEST_FAIL'
export type ClaimRequestFailAction = {
  type: typeof CLAIM_REQUEST_FAIL,
  uid: string,
}

export const INITIAL_ACTION = 'INITIAL_ACTION'
export type ClaimRequestInitialAction = {
  type: typeof INITIAL_ACTION,
}

export const ADD_SERIALIZED_CLAIM_OFFER = 'ADD_SERIALIZED_CLAIM_OFFER'
export type AddSerializedClaimOfferAction = {
  type: typeof ADD_SERIALIZED_CLAIM_OFFER,
  serializedClaimOffer: string,
  userDID: string,
  messageId: string,
  claimOfferVcxState: number,
}

export const CLAIM_OFFER_SHOW_START = 'CLAIM_OFFER_SHOW_START'
export type ClaimOfferShowStartAction = {
  type: typeof CLAIM_OFFER_SHOW_START,
  uid: string,
}

export const RESET_CLAIM_REQUEST_STATUS = 'RESET_CLAIM_REQUEST_STATUS'
export type ResetClaimRequestStatusAction = {
  type: typeof RESET_CLAIM_REQUEST_STATUS,
  uid: string,
}

export type ClaimOfferAction =
  | ClaimOfferReceivedAction
  | ClaimOfferFailedAction
  | ClaimOfferShownAction
  | ClaimOfferAcceptedAction
  | ClaimOfferRejectedAction
  | SendClaimRequestAction
  | ClaimRequestSuccessAction
  | ClaimRequestFailAction
  | ClaimRequestInitialAction
  | AddSerializedClaimOfferAction
  | HydrateSerializedClaimOffersSuccessAction
  | ResetAction
  | InsufficientBalanceAction
  | SendPaidCredentialRequestAction
  | PaidCredentialRequestSuccessAction
  | PaidCredentialRequestFailAction
  | ClaimOfferShowStartAction
  | ResetClaimRequestStatusAction
  | SendClaimRequestSuccessAction
  | SendClaimRequestFailAction

export type ClaimOfferPayload = AdditionalDataPayload & {
  uid: string,
  senderLogoUrl?: ?string,
  remotePairwiseDID: string,
  status: ClaimOfferStatus,
  claimRequestStatus: ClaimRequestStatus,
  payTokenValue?: ?string,
}

export type SerializedClaimOffer = {
  serialized: string,
  state: number,
  messageId: string,
}

export type SerializedClaimOffersPerDid = {
  +[messageId: string]: SerializedClaimOffer,
}

export type SerializedClaimOffers = {
  +[userDID: string]: SerializedClaimOffersPerDid,
}

export type ClaimOfferStore = {
  +[string]: ClaimOfferPayload,
  // serialized offer are organized by user did so that we can directly
  // take all of offers for a connection and run update_state on all of them
  +vcxSerializedClaimOffers: SerializedClaimOffers,
}

export type ClaimOfferProps = {
  claimOfferShown: (uid: string) => void,
  acceptClaimOffer: (uid: string) => void,
  claimOfferRejected: (uid: string) => void,
  claimOfferIgnored: (uid: string) => void,
  updateStatusBarTheme: (color?: string) => void,
  claimOfferShowStart: (uid: string) => ClaimOfferShowStartAction,
  resetClaimRequestStatus: (uid: string) => ResetClaimRequestStatusAction,
  navigation: ClaimProofNavigation,
  uid: string,
  claimOfferData: ClaimOfferPayload,
  isValid: boolean,
  logoUrl?: string,
  claimThemePrimary: string,
  claimThemeSecondary: string,
}

export type ClaimOfferState = {
  disableAcceptButton: boolean,
  credentialOfferModalStatus: CredentialOfferModalStatus,
}

export type ClaimRequestStatusModalProps = {
  claimRequestStatus: ClaimRequestStatus,
  payload: ClaimOfferPayload,
  onContinue: () => void,
  senderLogoUrl?: string,
  isPending?: boolean,
  message1: string,
  message3: string,
  message5?: string,
  message6?: string,
  buttonDisabled?: boolean,
  payTokenValue?: ?string,
  onModalHide?: () => void,
  fromConnectionHistory?: boolean,
}

export type CredentialOfferModalProps = {
  isValid?: boolean,
  claimRequestStatus?: ClaimRequestStatus,
  onModalHide?: () => void,
  claimOfferData?: ClaimOfferPayload,
  onClose: (event: any) => void,
  logoUrl?: string,
  payTokenValue?: ?string,
  credentialOfferModalStatus: CredentialOfferModalStatus,
  testID: string,
  onRetry: () => void,
  onNo?: () => void,
  onYes?: () => void,
  transferAmount?: string,
  connectionName?: string,
  renderFeesText?: (fees: string, status: string) => any,
}

export type CredentialOfferModalState = {
  isVisible: boolean,
}
export type ClaimRequestStatusModalState = {
  modalText: string,
}

export type ClaimOfferResponse = {
  msgs: [
    {
      statusCode: string,
      edgeAgentPayload: string,
      typ: string,
      statusMsg: string,
      uid: string,
    },
  ],
}

export type ClaimOfferAttributeListProps = {
  list: Array<Attribute>,
}

export const SAVE_CLAIM_OFFERS_SUCCESS = 'SAVE_CLAIM_OFFERS_SUCCESS'
export const SAVE_CLAIM_OFFERS_FAIL = 'SAVE_CLAIM_OFFERS_FAIL'
export const ERROR_SAVE_CLAIM_OFFERS = (message: string) => ({
  code: 'CO-001',
  message: `Error saving serialized claim offers: ${message}`,
})

export const REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS =
  'REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS'
export const REMOVE_SERIALIZED_CLAIM_OFFERS_FAIL =
  'REMOVE_SERIALIZED_CLAIM_OFFERS_FAIL'
export const ERROR_REMOVE_SERIALIZED_CLAIM_OFFERS = (message: string) => ({
  code: 'CO-002',
  message: `Error removing persisted serialized claim offers: ${message}`,
})

export const HYDRATE_CLAIM_OFFERS_SUCCESS = 'HYDRATE_CLAIM_OFFERS_SUCCESS'
export type HydrateSerializedClaimOffersSuccessAction = {
  type: typeof HYDRATE_CLAIM_OFFERS_SUCCESS,
  claimOffers: ClaimOfferStore,
}

export const HYDRATE_CLAIM_OFFERS_FAIL = 'HYDRATE_CLAIM_OFFERS_FAIL'
export const ERROR_HYDRATE_CLAIM_OFFERS = (message: string) => ({
  code: 'CO-003',
  message: `Error hydrating serialized claim offers: ${message}`,
})

export const CLAIM_OFFERS = 'CLAIM_OFFERS'

export const ERROR_NO_SERIALIZED_CLAIM_OFFER = (message: string) => ({
  code: 'CO-004',
  message: `No serialized claim offer found with this message id: ${message}`,
})

export const ERROR_SEND_CLAIM_REQUEST = (message: string) => ({
  code: 'CO-005',
  message: `Error occurred while trying to send/generate claim request: ${message}`,
})

export const CLAIM_REQUEST_STATUS = {
  NONE: 'NONE',
  INSUFFICIENT_BALANCE,
  SENDING_PAID_CREDENTIAL_REQUEST: 'SENDING_PAID_CREDENTIAL_REQUEST',
  SENDING_CLAIM_REQUEST: 'SENDING_CLAIM_REQUEST',
  SEND_CLAIM_REQUEST_SUCCESS,
  SEND_CLAIM_REQUEST_FAIL,
  CLAIM_REQUEST_FAIL,
  CLAIM_REQUEST_SUCCESS,
  PAID_CREDENTIAL_REQUEST_SUCCESS,
  PAID_CREDENTIAL_REQUEST_FAIL,
}

export type ClaimRequestStatus = $Keys<typeof CLAIM_REQUEST_STATUS>

export type CredentialOfferModalStatus = $Keys<
  typeof CREDENTIAL_OFFER_MODAL_STATUS
>


<|start_filename|>app/qr-code/qr-code.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import Camera from 'react-native-camera'
import {
  Alert,
  Platform,
  PermissionsAndroid,
  StatusBar,
  AppState,
} from 'react-native'
import { Container, QRScanner } from '../components'
import { color, barStyleLight, barStyleDark } from '../common/styles/constant'
import { invitationReceived } from '../invitation/invitation-store'
import {
  PENDING_CONNECTION_REQUEST_CODE,
  QR_CODE_SENDER_DID,
  QR_CODE_SENDER_VERIFICATION_KEY,
  QR_CODE_LOGO_URL,
  QR_CODE_REQUEST_ID,
  QR_CODE_SENDER_NAME,
  QR_CODE_TARGET_NAME,
  QR_CODE_SENDER_DETAIL,
  QR_CODE_SENDER_KEY_DELEGATION,
  QR_CODE_DELEGATION_DID,
  QR_CODE_DELEGATION_KEY,
  QR_CODE_DELEGATION_SIGNATURE,
  QR_CODE_SENDER_AGENCY,
  QR_CODE_SENDER_AGENCY_DID,
  QR_CODE_SENDER_AGENCY_KEY,
  QR_CODE_SENDER_AGENCY_ENDPOINT,
} from '../api/api-constants'
import {
  invitationRoute,
  qrCodeScannerTabRoute,
  homeTabRoute,
} from '../common/'
import type { QrCode } from '../components/qr-scanner/type-qr-scanner'
import type { Store } from '../store/type-store'
import type { InvitationPayload } from '../invitation/type-invitation'
import type {
  QRCodeScannerScreenState,
  QRCodeScannerScreenProps,
} from './type-qr-code'
import {
  MESSAGE_NO_CAMERA_PERMISSION,
  MESSAGE_ALLOW_CAMERA_PERMISSION,
  MESSAGE_RESET_CONNECT_ME,
  MESSAGE_RESET_DETAILS,
} from './type-qr-code'
import type { EnvironmentSwitchUrlQrCode } from '../components/qr-scanner/type-qr-scanner'
import { changeEnvironmentUrl } from '../store/config-store'
import { captureError } from '../services/error/error-handler'

export function convertQrCodeToInvitation(qrCode: QrCode) {
  const qrSenderDetail = qrCode[QR_CODE_SENDER_DETAIL]
  const qrSenderAgency = qrCode[QR_CODE_SENDER_AGENCY]
  const senderDetail = {
    name: qrSenderDetail[QR_CODE_SENDER_NAME],
    agentKeyDlgProof: {
      agentDID:
        qrSenderDetail[QR_CODE_SENDER_KEY_DELEGATION][QR_CODE_DELEGATION_DID],
      agentDelegatedKey:
        qrSenderDetail[QR_CODE_SENDER_KEY_DELEGATION][QR_CODE_DELEGATION_KEY],
      signature:
        qrSenderDetail[QR_CODE_SENDER_KEY_DELEGATION][
          QR_CODE_DELEGATION_SIGNATURE
        ],
    },
    DID: qrSenderDetail[QR_CODE_SENDER_DID],
    logoUrl: qrSenderDetail[QR_CODE_LOGO_URL],
    verKey: qrSenderDetail[QR_CODE_SENDER_VERIFICATION_KEY],
  }

  const senderAgencyDetail = {
    DID: qrSenderAgency[QR_CODE_SENDER_AGENCY_DID],
    verKey: qrSenderAgency[QR_CODE_SENDER_AGENCY_KEY],
    endpoint: qrSenderAgency[QR_CODE_SENDER_AGENCY_ENDPOINT],
  }

  return {
    senderEndpoint: senderAgencyDetail.endpoint,
    requestId: qrCode[QR_CODE_REQUEST_ID],
    senderAgentKeyDelegationProof: senderDetail.agentKeyDlgProof,
    senderName: senderDetail.name,
    senderDID: senderDetail.DID,
    senderLogoUrl: senderDetail.logoUrl,
    senderVerificationKey: senderDetail.verKey,
    targetName: qrCode[QR_CODE_TARGET_NAME],
    senderDetail,
    senderAgencyDetail,
  }
}

export class QRCodeScannerScreen extends PureComponent<
  QRCodeScannerScreenProps,
  QRCodeScannerScreenState
> {
  state = {
    appState: AppState.currentState,
    isCameraAuthorized: false,
    isCameraEnabled: false,
  }

  permissionCheckIntervalId = 0
  checkPermission = false

  onRead = (qrCode: QrCode) => {
    if (this.props.currentScreen === qrCodeScannerTabRoute) {
      const invitation = {
        payload: convertQrCodeToInvitation(qrCode),
      }
      this.props.invitationReceived(invitation)
      this.props.navigation.push(invitationRoute, {
        senderDID: invitation.payload.senderDID,
      })
    }
  }

  onAllowSwitchEnvironment = (url: EnvironmentSwitchUrlQrCode) => {
    this.props.changeEnvironmentUrl(url.url)
    this.props.navigation.navigate(homeTabRoute)
  }

  onEnvironmentSwitchUrl = (url: EnvironmentSwitchUrlQrCode) => {
    if (this.props.currentScreen === qrCodeScannerTabRoute) {
      Alert.alert(MESSAGE_RESET_CONNECT_ME, MESSAGE_RESET_DETAILS(url.name), [
        { text: 'Cancel' },
        {
          text: 'Switch',
          onPress: () => this.onAllowSwitchEnvironment(url),
        },
      ])
    }
  }

  onInvitationUrl = (payload: InvitationPayload) => {
    if (this.props.currentScreen === qrCodeScannerTabRoute) {
      this.props.invitationReceived({ payload })
      this.props.navigation.push(invitationRoute, {
        senderDID: payload.senderDID,
      })
    }
  }

  onClose = () => {
    this.props.navigation.navigate(homeTabRoute)
    this.setState({ isCameraEnabled: false })
  }

  allowCameraPermissionAcknowledged = () => {
    this.props.navigation.goBack()
  }

  setHasCameraAccessPermission = () => {
    this.setState({ isCameraAuthorized: true })
  }

  setNoCameraAccessPermission = () => {
    Alert.alert(MESSAGE_NO_CAMERA_PERMISSION, MESSAGE_ALLOW_CAMERA_PERMISSION, [
      { text: 'OK', onPress: this.allowCameraPermissionAcknowledged },
    ])
    this.setState({ isCameraAuthorized: false })
  }

  checkCameraAuthorization = () => {
    if (Platform.OS === 'ios') {
      Camera.checkVideoAuthorizationStatus()
        .then((authorization: boolean) => {
          if (authorization) {
            this.setHasCameraAccessPermission()
          } else {
            this.setNoCameraAccessPermission()
          }
        })
        .catch(this.setNoCameraAccessPermission)
    } else {
      PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
        title: 'App Camera Permission',
        message:
          'App needs access to your camera ' +
          'so you can scan QR codes and form connections.',
      })
        .then(result => {
          if (result === 'granted') {
            this.setHasCameraAccessPermission()
          } else {
            this.setNoCameraAccessPermission()
          }
        })
        .catch(this.setNoCameraAccessPermission)
    }
  }

  componentWillReceiveProps(nextProps: QRCodeScannerScreenProps) {
    if (
      nextProps.currentScreen !== this.props.currentScreen &&
      nextProps.currentScreen === qrCodeScannerTabRoute
    ) {
      // whenever user navigates to this screen, we have to check permission
      // every time, although we should have this logic in componentDidMount
      // but in the router (react navigation) that we are using
      // it caches a component and does not unmount it, and hence
      // componentDidMount is not called every time user comes to this screen
      // so, the option we have now is to use one of other life cycle events
      // such as `cwrp` or `cdu`, we are `cwrp` to check the status every time
      // also, we check status only on the basis of screen switching
      // and only check status if user is redirecting to QrCodeScanScreen
      if (nextProps.navigation.isFocused()) {
        this.setState({ isCameraEnabled: true })
      }

      if (Platform.OS === 'android') {
        this.permissionCheckIntervalId = setInterval(() => {
          PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.CAMERA)
            .then(result => {
              if (result) {
                this.checkCameraAuthorization()
                clearInterval(this.permissionCheckIntervalId)
              } else {
                if (!this.checkPermission) {
                  this.checkCameraAuthorization()
                }
                this.checkPermission = true
              }
            })
            .catch(err => {
              captureError(err)
            })
        }, 1000)
      } else {
        this.checkCameraAuthorization()
      }
    } else {
      this.permissionCheckIntervalId &&
        clearInterval(this.permissionCheckIntervalId)
      this.checkPermission = false
    }
  }

  updateStatusBarTheme() {
    if (this.props.navigation.isFocused()) {
      StatusBar.setBarStyle(barStyleLight, true)
      if (Platform.OS === 'android') {
        StatusBar.setBackgroundColor(color.bg.sixth.color)
      }
    }
  }

  componentDidMount() {
    if (this.props.currentScreen === qrCodeScannerTabRoute) {
      // when this component is mounted first time, `cwrp` will not be called
      // so for the first time mount as well we need to check camera permission
      this.checkCameraAuthorization()
      this.updateStatusBarTheme()
    }
    AppState.addEventListener('change', this._handleAppStateChange)
  }

  componentDidUpdate() {
    if (this.props.currentScreen === qrCodeScannerTabRoute) {
      this.updateStatusBarTheme()
    }
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange)
  }

  _handleAppStateChange = nextAppState => {
    if (
      this.state.appState &&
      this.state.appState.match(/inactive|background/) &&
      nextAppState === 'active'
    ) {
      this.setState({ isCameraEnabled: true })
    } else if (
      this.state.appState &&
      nextAppState.match(/inactive|background/) &&
      this.state.appState === 'active'
    ) {
      this.setState({ isCameraEnabled: false })
    }
    this.setState({ appState: nextAppState })
  }

  render() {
    return (
      //Till the time camera authorization is checked
      //empty black screen will be returned
      //so that it doesn't look odd
      <Container dark collapsable={true}>
        {this.state.isCameraAuthorized &&
        this.state.isCameraEnabled &&
        this.props.currentScreen === qrCodeScannerTabRoute ? (
          <QRScanner
            onRead={this.onRead}
            onClose={this.onClose}
            onEnvironmentSwitchUrl={this.onEnvironmentSwitchUrl}
            onInvitationUrl={this.onInvitationUrl}
          />
        ) : null}
      </Container>
    )
  }
}

const mapStateToProps = (state: Store) => ({
  currentScreen: state.route.currentScreen,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      invitationReceived,
      changeEnvironmentUrl,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(QRCodeScannerScreen)


<|start_filename|>app/lock/lock-enter.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import {
  InteractionManager,
  StyleSheet,
  Platform,
  Dimensions,
  Image,
} from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import {
  Container,
  CustomText,
  PinCodeBox,
  CustomView,
  Icon,
} from '../components'
import {
  color,
  OFFSET_1X,
  OFFSET_2X,
  OFFSET_3X,
  OFFSET_4X,
} from '../common/styles'
import { CHECK_PIN_IDLE, CHECK_PIN_SUCCESS, CHECK_PIN_FAIL } from './type-lock'
import type {
  LockEnterPinProps,
  LockEnterState,
  CheckPinStatus,
  LockEnterProps,
} from './type-lock'
import { checkPinAction, checkPinStatusIdle } from './lock-store'
import { switchErrorAlerts } from '../store/config-store'
import type { Store } from '../store/type-store'
import { ENTER_YOUR_PASS_CODE_MESSAGE } from '../common/message-constants'
import {
  whiteSmokeRGBA,
  whisper,
  isBiggerThanShortDevice,
  grey,
  matterhornSecondary,
} from '../common/styles/constant'

const lockImage = require('../images/lockCombo.png')
const backgroundImg = require('../images/wave1.png')

const styles = StyleSheet.create({
  //TODO : add animations when keyboard popups.
  text: {
    marginTop: OFFSET_4X,
    minHeight: OFFSET_3X,
    marginBottom: OFFSET_4X,
  },
  titleText: {
    lineHeight: 28,
    letterSpacing: 0.5,
  },
})

export const WrongPinText = (
  <CustomText h4 bg="tertiary" tertiary center>
    Wrong passcode! Please try again
  </CustomText>
)

export class LockEnter extends PureComponent<LockEnterProps, LockEnterState> {
  pinCodeBox = null
  clearFailStatus = () => {
    this.props.checkPinStatusIdle()
  }

  clearFailStatusDelayed = () => {
    setTimeout(this.clearFailStatus, 1000)
  }

  onPinComplete = (pin: string) => {
    this.props.checkPinAction(pin)
  }

  componentWillReceiveProps(nextProps: LockEnterProps) {
    if (this.props.checkPinStatus !== nextProps.checkPinStatus) {
      if (nextProps.checkPinStatus === CHECK_PIN_SUCCESS) {
        this.pinCodeBox && this.pinCodeBox.hideKeyboard()
        this.props.onSuccess()
      } else if (nextProps.checkPinStatus === CHECK_PIN_FAIL) {
        this.pinCodeBox && this.pinCodeBox.clear && this.pinCodeBox.clear()
        // set status back to idle so we can come to this else again
        this.clearFailStatusDelayed()
      }
    }
  }

  componentDidMount() {
    if (this.props.checkPinStatus === CHECK_PIN_SUCCESS) {
      this.clearFailStatus()
    }
  }

  render() {
    const {
      checkPinStatus,
      message = ENTER_YOUR_PASS_CODE_MESSAGE,
    } = this.props

    const EnterPinText = (
      <CustomText
        style={[styles.titleText]}
        center
        h4
        bg="tertiary"
        tertiary
        thick
        testID="pass-code-input-text"
      >
        {message}
      </CustomText>
    )

    return (
      <Container>
        {this.props.fromRecovery ? (
          <Container safeArea fifth>
            <Image
              source={backgroundImg}
              style={[stylesRecovery.backgroundImg]}
            />
            <CustomView
              center
              transparentBg
              style={[stylesRecovery.topLockIcon]}
            >
              <CustomView style={[stylesRecovery.blackStrip]} />
              <CustomView style={[stylesRecovery.lockIconWrapper]}>
                <Icon extraLarge halo src={lockImage} />
              </CustomView>
            </CustomView>
            <CustomView center verticalSpace>
              <CustomText
                center
                transparentBg
                style={[stylesRecovery.lockHeading]}
                heavy
                charcoal
              >
                Please enter your current Connect.Me passcode!
              </CustomText>
            </CustomView>
            <CustomView center>
              <PinCodeBox
                ref={pinCodeBox => {
                  this.pinCodeBox = pinCodeBox
                }}
                onPinComplete={this.onPinComplete}
              />
            </CustomView>
            <CustomView center doubleVerticalSpace>
              <CustomText
                transparentBg
                center
                h6
                bold
                style={[stylesRecovery.newPasscodeText]}
                onPress={this.props.setupNewPassCode}
                testID={'set-up-new-passcode-recovery'}
              >
                Or Setup New Passcode
              </CustomText>
            </CustomView>
          </Container>
        ) : (
          <Container tertiary>
            <CustomView
              style={[styles.text]}
              center
              onPress={this.props.switchErrorAlerts}
              testID="pin-code-input-boxes"
            >
              {checkPinStatus === CHECK_PIN_IDLE && EnterPinText}
              {checkPinStatus === CHECK_PIN_SUCCESS && EnterPinText}
              {checkPinStatus === CHECK_PIN_FAIL && WrongPinText}
            </CustomView>
            <CustomView center>
              <PinCodeBox
                ref={pinCodeBox => {
                  this.pinCodeBox = pinCodeBox
                }}
                onPinComplete={this.onPinComplete}
                enableCustomKeyboard={this.props.enableCustomKeyboard}
              />
            </CustomView>
          </Container>
        )}
      </Container>
    )
  }
}

const stylesRecovery = StyleSheet.create({
  backgroundImg: {
    position: 'absolute',
    transform: [{ rotate: '-180deg' }],
    marginTop: '-92%',
    width: '100%',
  },
  topLockIcon: {
    ...Platform.select({
      ios: {
        marginTop: isBiggerThanShortDevice ? '14%' : '3%',
      },
      android: {
        marginTop: isBiggerThanShortDevice ? '12%' : '8%',
      },
    }),
  },
  blackStrip: {
    position: 'absolute',
    height: 8,
    backgroundColor: matterhornSecondary,
    width: '100%',
  },
  lockIconWrapper: {
    backgroundColor: matterhornSecondary,
    borderRadius: 50,
  },
  lockHeading: {
    fontSize: isBiggerThanShortDevice ? 23 : 16,
    width: '80%',
    ...Platform.select({
      ios: {
        marginTop: isBiggerThanShortDevice ? '7%' : '2%',
        marginBottom: '-1%',
      },
      android: {
        marginTop: isBiggerThanShortDevice ? '2%' : 0,
      },
    }),
  },
  newPasscodeText: {
    ...Platform.select({
      ios: {
        marginTop: isBiggerThanShortDevice ? '6.1%' : '1%',
      },
      android: {
        marginTop: isBiggerThanShortDevice ? '2%' : 0,
      },
    }),
    color: color.bg.fifteenth.color,
  },
})

const mapStateToProps = (state: Store) => ({
  checkPinStatus: state.lock.checkPinStatus,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      checkPinAction,
      checkPinStatusIdle,
      switchErrorAlerts,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(LockEnter)


<|start_filename|>app/authentication/authentication-store.js<|end_filename|>
// @flow
import { put, takeLatest, call, all } from 'redux-saga/effects'
import { delay } from 'redux-saga'
import { sendAuthenticationRequest } from '../api/api'
import type { ConfigStore } from '../store/type-config-store'
import type {
  AuthenticationStatus,
  AuthenticationType,
  AuthenticationStore,
  AuthenticationPayload,
  AuthenticationError,
  AuthenticationAction,
  SendUserAuthenticationResponse,
  AuthenticationSuccessData,
  SendUserAuthenticationResponseSuccess,
  SendUserAuthenticationResponseFailure,
  ResetAuthenticationStatus,
  AuthenticationRequestReceived,
} from './type-authentication'
import { RESET } from '../common/type-common'

export const AUTHENTICATION_STATUS: AuthenticationStatus = {
  ACCEPTED: 'accepted',
  REJECTED: 'rejected',
  NONE: 'NONE',
}

export const AUTHENTICATION_TYPE: AuthenticationType = {
  NONE: 'NONE',
  AUTHENTICATION_REQUEST: 'AUTHENTICATION_REQUEST',
}

const initialState: AuthenticationStore = {
  inviter: { image: '' },
  invitee: { image: './images/inviter.jpeg' },
  data: null,
  error: null,
  type: AUTHENTICATION_TYPE.NONE,
  status: AUTHENTICATION_STATUS.NONE,
  isFetching: false,
  isPristine: true,
}

const AUTHENTICATION_REQUEST_RECEIVED = 'AUTHENTICATION_REQUEST_RECEIVED'
const SEND_USER_AUTHENTICATION_RESPONSE = 'SEND_USER_AUTHENTICATION_RESPONSE'
const SEND_USER_AUTHENTICATION_RESPONSE_SUCCESS =
  'SEND_USER_AUTHENTICATION_RESPONSE_SUCCESS'
const SEND_USER_AUTHENTICATION_RESPONSE_FAILURE =
  'SEND_USER_AUTHENTICATION_RESPONSE_FAILURE'
const RESET_AUTHENTICATION_STATUS = 'RESET_AUTHENTICATION_STATUS'

export const sendUserAuthenticationResponse = (
  data: AuthenticationSuccessData,
  config: ConfigStore,
  authenticationType: string
): SendUserAuthenticationResponse => ({
  type: SEND_USER_AUTHENTICATION_RESPONSE,
  data,
  config,
  authenticationType,
})

export const sendUserAuthenticationResponseSuccess = (
  data: AuthenticationSuccessData
): SendUserAuthenticationResponseSuccess => ({
  type: SEND_USER_AUTHENTICATION_RESPONSE_SUCCESS,
  data,
})

export const sendUserAuthenticationResponseFailure = (
  error: AuthenticationError
): SendUserAuthenticationResponseFailure => ({
  type: SEND_USER_AUTHENTICATION_RESPONSE_FAILURE,
  error,
})

export const authenticationRequestReceived = (
  data: AuthenticationPayload
): AuthenticationRequestReceived => ({
  type: AUTHENTICATION_REQUEST_RECEIVED,
  data,
})

export const resetAuthenticationStatus = (): ResetAuthenticationStatus => ({
  type: RESET_AUTHENTICATION_STATUS,
})

export function* watchLoadAuthenticationDetailsRequest(): any {
  yield takeLatest(
    SEND_USER_AUTHENTICATION_RESPONSE,
    handleUserAuthenticationResponse
  )
}

function* handleUserAuthenticationResponse(
  action: SendUserAuthenticationResponse
): Generator<*, *, *> {
  const { authenticationType } = action
  try {
    let authenticationActionResponse = null
    if (authenticationType == AUTHENTICATION_TYPE.AUTHENTICATION_REQUEST) {
      const { remoteConnectionId, dataBody: { challenge } } = action.data
      // TODO: Fix authentication flow
      const signature = ''
      // add signature
      action.data.dataBody.signature = signature

      // TODO: Fix this while fixing authentication flow
      // authenticationActionResponse = yield call(
      //   sendAuthenticationRequest,
      //   action
      // )
      // yield put(sendUserAuthenticationResponseSuccess(action.data))
    }
  } catch (e) {
    yield put(
      sendUserAuthenticationResponseFailure({
        message: e.message,
        authenticationType: action.authenticationType,
      })
    )
  }
}

export function* watchAuthentication(): any {
  yield all([watchLoadAuthenticationDetailsRequest()])
}

export default function authentication(
  state: AuthenticationStore = initialState,
  action: AuthenticationAction
): AuthenticationStore {
  switch (action.type) {
    case SEND_USER_AUTHENTICATION_RESPONSE:
      return {
        ...state,
        isFetching: true,
        isPristine: false,
      }
    case SEND_USER_AUTHENTICATION_RESPONSE_SUCCESS:
      return {
        ...state,
        isFetching: false,
        status: action.data.newStatus,
      }
    case SEND_USER_AUTHENTICATION_RESPONSE_FAILURE:
      return {
        ...state,
        isFetching: false,
        error: action.error,
      }
    case RESET_AUTHENTICATION_STATUS:
      return {
        ...state,
        type: AUTHENTICATION_TYPE.NONE,
        status: AUTHENTICATION_STATUS.NONE,
        error: null,
        data: null,
      }
    case AUTHENTICATION_REQUEST_RECEIVED:
      return {
        ...state,
        type: AUTHENTICATION_TYPE.AUTHENTICATION_REQUEST,
        status: AUTHENTICATION_STATUS.NONE,
        data: action.data,
        error: null,
      }
    case RESET:
      return initialState
    default:
      return state
  }
}


<|start_filename|>app/restore/restore-store.js<|end_filename|>
// @flow
import { decryptWalletFile, copyToPath } from '../bridge/react-native-cxs/RNCxs'
import { unzip } from 'react-native-zip-archive'
import firebase from 'react-native-firebase'
import {
  takeLatest,
  all,
  put,
  call,
  take,
  select,
  fork,
} from 'redux-saga/effects'
import type { CustomError } from '../common/type-common'
import {
  SAVE_FILE_TO_APP_DIRECTORY,
  RESTORE_STATUS,
  ERROR_RESTORE,
  RESTORE_SUBMIT_PASSPHRASE,
  RestoreStatus,
  initialState,
  FILE_SAVE_ERROR_MESSAGE,
  DECRYPT_FAILED_MESSAGE,
  RESTORE_RESET,
  RESTORE_DATA_FAILED_MESSAGE,
} from './type-restore'
import { WALLET_FILE_NAME } from '../backup/type-backup'
import type {
  SaveToAppDirectory,
  RestoreActions,
  SaveFiletoAppDirectoryAction,
  RestoreSubmitPassphrase,
  RestoreStore,
} from './type-restore'
import RNFetchBlob from 'react-native-fetch-blob'
import { getRestoreStatus, getRestoreFileName } from '../store/store-selector'
import { pinHash as generateKey } from '../lock/pin-hash'
import { safeToDownloadSmsInvitation } from '../sms-pending-invitation/sms-pending-invitation-store'
import { Platform } from 'react-native'
import type { Store } from '../store/type-store.js'
import { hydrate, hydrateNonReduxData } from '../store/hydration-store'
import { pushNotificationPermissionAction } from '../push-notification/push-notification-store'
import { safeGet, safeSet } from '../services/storage'
import { PIN_ENABLED_KEY, IN_RECOVERY } from '../lock/type-lock'
import { captureError } from '../services/error/error-handler'

export const saveFileToAppDirectory = (data: SaveToAppDirectory) => ({
  type: SAVE_FILE_TO_APP_DIRECTORY,
  data,
})

export const restoreStatus = (status: string) => ({
  type: RESTORE_STATUS,
  status,
})

export const errorRestore = (error: CustomError) => ({
  type: ERROR_RESTORE,
  error,
})

export const submitPassphrase = (passphrase: string) => ({
  type: RESTORE_SUBMIT_PASSPHRASE,
  passphrase,
})

export const resetRestore = () => ({
  type: RESTORE_RESET,
})

export function* restoreFileDecrypt(
  action: RestoreSubmitPassphrase
): Generator<*, *, *> {
  try {
    const { passphrase } = action
    if ((yield select(getRestoreStatus)) !== 'FILE_SAVED_TO_APP_DIRECTORY') {
      while (true) {
        const { status } = yield take(RESTORE_STATUS)

        if (status === 'FILE_SAVED_TO_APP_DIRECTORY') {
          break
        }
      }
    }

    yield put(restoreStatus(RestoreStatus.DECRYPTION_START))
    const { fs } = RNFetchBlob
    const restoreZipFilePath = `${fs.dirs.DocumentDir}/restore.zip`
    const restoreDirectoryPath = `${fs.dirs.DocumentDir}/restoreDirectory`
    let walletFilePath = `${restoreDirectoryPath}/${WALLET_FILE_NAME}.wallet`
    let restoreSaltPath = `${restoreDirectoryPath}/salt.json`
    yield call(unzip, restoreZipFilePath, restoreDirectoryPath)
    let restoreSalt = ''
    try {
      restoreSalt = yield call(fs.readFile, restoreSaltPath, 'utf8')
    } catch (e) {
      let fileName = yield select(getRestoreFileName)
      let restorePath = `${restoreDirectoryPath}/${fileName.split('.zip')[0]}`

      walletFilePath = `${restorePath}/${WALLET_FILE_NAME}.wallet`
      restoreSaltPath = `${restorePath}/salt.json`

      restoreSalt = yield call(fs.readFile, restoreSaltPath, 'utf8')
    }

    const parsedRestoreSalt = JSON.parse(restoreSalt)
    const hashedPassphrase = yield call(
      generateKey,
      passphrase,
      parsedRestoreSalt.salt
    )

    yield call(decryptWalletFile, walletFilePath, hashedPassphrase)
    yield put(restoreStatus(RestoreStatus.FILE_DECRYPT_SUCCESS))

    // since we have decrypted file successfully, now we restore data from wallet
    // Need to set this here manually, because in normal flow this flag
    // will be set when user sets pin code. However, since user is importing
    // wallet file, we know that user has already enabled pin code
    // so we set this flag manually
    yield call(safeSet, PIN_ENABLED_KEY, 'true')
    yield call(safeSet, IN_RECOVERY, 'true')
    yield* hydrate()
    // hydrate data in secure storage which is not put in store by hydrate saga
    yield fork(hydrateNonReduxData)
    //Push Notification permissions are asked when we do our first connection

    //but in this case if connections are imported from backup then that case is missed
    //since connection is already there

    // so after push token update
    // we need to do requestPermission or else push notifications won't come
    const requestPushNotificationPermission = () => {
      firebase.messaging().requestPermission()
    }
    yield call(requestPushNotificationPermission)
    yield put(pushNotificationPermissionAction(true))
    yield put(restoreStatus(RestoreStatus.RESTORE_DATA_STORE_SUCCESS))
  } catch (e) {
    captureError(e)
    yield put(errorRestore(DECRYPT_FAILED_MESSAGE(e.message)))
  }
}

export function* saveZipFile(
  action: SaveFiletoAppDirectoryAction
): Generator<*, *, *> {
  try {
    yield put(restoreStatus(RestoreStatus.ZIP_FILE_SELECTED))
    const { uri } = action.data
    const { fs } = RNFetchBlob
    let destPath = fs.dirs.DocumentDir + '/restore.zip'
    let tempUri = uri
    //For android emulators the content uri is like "content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fbackup.zip"
    //so it needs to be decoded and split from "/raw:" to get the real path
    //For android device the content uri is of form "Content://com.android.providers.downloads.documents/document/223" which can be used directly
    //For IOS device uri is like "file:///private/var/mobile/Containers/Data/Application/A80FE508-BCED-4950-B9D0-8F1AA1E967B6/tmp/com.evernym.connectme.callcenter-Inbox/backup.zip"
    // which we need to split from /private to get the real path

    //TODO move the copy logic for android to RNLayer
    if (Platform.OS === 'android') {
      copyToPath(tempUri, destPath)
      yield put(restoreStatus(RestoreStatus.fileSaved))
    } else if (Platform.OS === 'ios') {
      tempUri = uri.substr('file://'.length)

      let sourceFileExists =
        tempUri != null ? yield call(fs.exists, tempUri) : false

      if (sourceFileExists) {
        const destFileExists = yield call(fs.exists, destPath)
        if (destFileExists) {
          yield call(fs.unlink, destPath)
        }

        yield call(fs.cp, tempUri, destPath)
      }
      yield put(restoreStatus(RestoreStatus.fileSaved))
    } else {
      yield put(restoreStatus(RestoreStatus.FILE_SAVE_ERROR))
      yield put(
        errorRestore(FILE_SAVE_ERROR_MESSAGE('source file does not exist'))
      )
    }
  } catch (e) {
    captureError(e)
    yield put(restoreStatus(RestoreStatus.FILE_SAVE_ERROR))
    yield put(errorRestore(FILE_SAVE_ERROR_MESSAGE(e.message)))
  }
}

export function* restoreSaga(): any {
  yield takeLatest(SAVE_FILE_TO_APP_DIRECTORY, saveZipFile)
}

export function* watchSubmitPassphrase(): any {
  yield takeLatest(RESTORE_SUBMIT_PASSPHRASE, restoreFileDecrypt)
}

export function* watchRestore(): any {
  yield all([restoreSaga(), watchSubmitPassphrase()])
}

export default function restoreReducer(
  state: RestoreStore = initialState,
  action: RestoreActions
) {
  switch (action.type) {
    case SAVE_FILE_TO_APP_DIRECTORY:
      return {
        ...state,
        status: RestoreStatus.none,
        error: null,
        restoreFile: action.data,
      }
    case RESTORE_SUBMIT_PASSPHRASE:
      return {
        ...state,
        error: null,
        passphrase: action.passphrase,
      }
    case ERROR_RESTORE:
      return {
        ...state,
        error: action.error,
        status: RestoreStatus.failedStatus,
      }
    case RESTORE_STATUS:
      return {
        ...state,
        status: action.status,
        error: null,
      }
    default:
      return state
  }
}


<|start_filename|>flow-typed/npm/react-native-touch-id.js<|end_filename|>
// @flow
declare module 'react-native-touch-id' {
  declare interface TouchIDError {
    name: string;
    message: string;
    details: any;
  }
  declare module.exports: {
    authenticate(reason: string): Promise<boolean | TouchIDError>,
    isSupported(): Promise<boolean | TouchIDError>,
  }
}


<|start_filename|>app/components/__tests__/icon.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { Icon } from '../../components'

describe('<Icon />', () => {
  it('should match snapshot', () => {
    // icon should have only icon props
    // and rest of the props should be passed to CustomView
    const wrapper = renderer
      .create(
        <Icon
          src={require('../../images/cbTest.png')}
          extraLarge
          testID="test-icon-test"
          halo
          resizeMode="cover"
          style={{ fontSize: 15 }}
          center
          iconStyle={[{ width: 90 }]}
        />
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>app/components/loader-gif/loader-gif.js<|end_filename|>
// @flow

import React from 'react'
import { ActivityIndicator } from 'react-native'
import { color } from '../../common/styles'
import { Container } from '../layout'

export const LoaderGif = (
  <Container center>
    <ActivityIndicator size="large" color={color.bg.eighth.color} />
  </Container>
)


<|start_filename|>app/claim-offer/claim-offer-store.js<|end_filename|>
// @flow
import {
  put,
  takeLatest,
  take,
  race,
  call,
  all,
  select,
  takeEvery,
  fork,
} from 'redux-saga/effects'
import { delay } from 'redux-saga'
import { Platform } from 'react-native'
import {
  CLAIM_OFFER_STATUS,
  CLAIM_OFFER_RECEIVED,
  CLAIM_OFFER_SHOWN,
  CLAIM_OFFER_ACCEPTED,
  CLAIM_OFFER_REJECTED,
  SEND_CLAIM_REQUEST,
  CLAIM_REQUEST_SUCCESS,
  CLAIM_REQUEST_FAIL,
  CLAIM_OFFER_IGNORED,
  CLAIM_REQUEST_STATUS,
  ADD_SERIALIZED_CLAIM_OFFER,
  CLAIM_OFFERS,
  SAVE_CLAIM_OFFERS_SUCCESS,
  SAVE_CLAIM_OFFERS_FAIL,
  ERROR_SAVE_CLAIM_OFFERS,
  REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS,
  REMOVE_SERIALIZED_CLAIM_OFFERS_FAIL,
  HYDRATE_CLAIM_OFFERS_SUCCESS,
  HYDRATE_CLAIM_OFFERS_FAIL,
  ERROR_HYDRATE_CLAIM_OFFERS,
  ERROR_NO_SERIALIZED_CLAIM_OFFER,
  ERROR_SEND_CLAIM_REQUEST,
  INSUFFICIENT_BALANCE,
  SEND_PAID_CREDENTIAL_REQUEST,
  PAID_CREDENTIAL_REQUEST_SUCCESS,
  PAID_CREDENTIAL_REQUEST_FAIL,
  CLAIM_OFFER_SHOW_START,
  RESET_CLAIM_REQUEST_STATUS,
  SEND_CLAIM_REQUEST_SUCCESS,
  SEND_CLAIM_REQUEST_FAIL,
} from './type-claim-offer'
import type {
  ClaimOfferStore,
  ClaimOfferAction,
  ClaimOfferShownAction,
  ClaimOfferAcceptedAction,
  ClaimOfferResponse,
  ClaimOfferPayload,
  AddSerializedClaimOfferAction,
  SerializedClaimOffer,
} from './type-claim-offer'
import type {
  AdditionalDataPayload,
  NotificationPayloadInfo,
} from '../push-notification/type-push-notification'
import type { CustomError } from '../common/type-common'
import {
  getAgencyUrl,
  getClaimOffer,
  getUserPairwiseDid,
  getUserOneTimeInfo,
  getAgencyVerificationKey,
  getRemotePairwiseDidAndName,
  getPoolConfig,
  getClaimOffers,
  getConnection,
  getSerializedClaimOffer,
  getWalletBalance,
} from '../store/store-selector'
import type { IndyClaimOffer } from '../bridge/react-native-cxs/type-cxs'
import {
  getHandleBySerializedConnection,
  getClaimHandleBySerializedClaimOffer,
  serializeClaimOffer,
  getClaimOfferState,
  sendClaimRequest as sendClaimRequestApi,
  getLedgerFees,
} from '../bridge/react-native-cxs/RNCxs'
import type { IndyClaimRequest } from '../bridge/react-native-cxs/type-cxs'
import { CLAIM_STORAGE_FAIL, CLAIM_STORAGE_SUCCESS } from '../claim/type-claim'
import { CLAIM_STORAGE_ERROR } from '../services/error/error-code'
import { MESSAGE_TYPE } from '../api/api-constants'
import type { ApiClaimRequest, EdgeClaimRequest } from '../api/type-api'
import type { UserOneTimeInfo } from '../store/user/type-user-store'
import type { Connection } from '../store/type-connection-store'
import { RESET } from '../common/type-common'
import { secureSet, secureDelete, getHydrationItem } from '../services/storage'
import { BigNumber } from 'bignumber.js'
import { refreshWalletBalance } from '../wallet/wallet-store'
import type {
  ClaimStorageSuccessAction,
  ClaimStorageFailAction,
} from '../claim/type-claim'
import type { LedgerFeesData } from '../store/ledger/type-ledger-store'
import moment from 'moment'
import { captureError } from '../services/error/error-handler'

const claimOfferInitialState = {
  vcxSerializedClaimOffers: {},
}

// TODO:PS: data structure for claim offer received should be flat
// It should not have only payload
// Merge payload and payloadInfo
export const claimOfferReceived = (
  payload: AdditionalDataPayload,
  payloadInfo: NotificationPayloadInfo
) => ({
  type: CLAIM_OFFER_RECEIVED,
  payload,
  payloadInfo,
})

// this action is used because we don't want to show claim offer again to user
// we set claim offer status as shown, so another code path doesn't show it
export const claimOfferShown = (uid: string) => ({
  type: CLAIM_OFFER_SHOWN,
  uid,
})

export const claimOfferIgnored = (uid: string) => ({
  type: CLAIM_OFFER_IGNORED,
  uid,
})

export const claimOfferRejected = (uid: string) => ({
  type: CLAIM_OFFER_REJECTED,
  uid,
})

export const sendClaimRequest = (uid: string, payload: ClaimOfferPayload) => ({
  type: SEND_CLAIM_REQUEST,
  uid,
  payload,
})

export const sendClaimRequestSuccess = (
  uid: string,
  payload: ClaimOfferPayload
) => ({
  type: SEND_CLAIM_REQUEST_SUCCESS,
  uid,
  payload,
})

export const sendClaimRequestFail = (uid: string) => ({
  type: SEND_CLAIM_REQUEST_FAIL,
  uid,
})

export const claimRequestSuccess = (uid: string) => ({
  type: CLAIM_REQUEST_SUCCESS,
  uid,
})

export const claimRequestFail = (uid: string, error: CustomError) => ({
  type: CLAIM_REQUEST_FAIL,
  error,
  uid,
})

export const inSufficientBalance = (uid: string) => ({
  type: INSUFFICIENT_BALANCE,
  uid,
})

export const sendPaidCredentialRequest = (
  uid: string,
  payload: ClaimOfferPayload
) => ({
  type: SEND_PAID_CREDENTIAL_REQUEST,
  uid,
  payload,
})

export const paidCredentialRequestSuccess = (uid: string) => ({
  type: PAID_CREDENTIAL_REQUEST_SUCCESS,
  uid,
})

export const paidCredentialRequestFail = (uid: string) => ({
  type: PAID_CREDENTIAL_REQUEST_FAIL,
  uid,
})

export const acceptClaimOffer = (uid: string) => ({
  type: CLAIM_OFFER_ACCEPTED,
  uid,
})

export function convertClaimRequestToEdgeClaimRequest(
  claimRequest: ApiClaimRequest
): EdgeClaimRequest {
  const { blinded_ms, schema_seq_no, issuer_did } = claimRequest

  return {
    blinded_ms,
    issuer_did,
    schema_seq_no,
    msg_type: MESSAGE_TYPE.CLAIM_REQUEST,
    // hard coded version as of now, update once versioning is implemented
    version: '0.1',
    to_did: claimRequest.remoteDid,
    from_did: claimRequest.userPairwiseDid,
    tid: '1',
    mid: '1',
  }
}

export function* claimOfferAccepted(
  action: ClaimOfferAcceptedAction
): Generator<*, *, *> {
  const messageId = action.uid
  const claimOfferPayload: ClaimOfferPayload = yield select(
    getClaimOffer,
    messageId
  )
  const payTokenAmount = new BigNumber(claimOfferPayload.payTokenValue || '0')
  const isPaidCredential = payTokenAmount.isGreaterThan(0)
  const remoteDid = claimOfferPayload.remotePairwiseDID
  const [connection]: Connection[] = yield select(getConnection, remoteDid)
  const vcxSerializedClaimOffer: SerializedClaimOffer | null = yield select(
    getSerializedClaimOffer,
    connection.identifier,
    messageId
  )

  if (!vcxSerializedClaimOffer) {
    captureError(new Error(ERROR_NO_SERIALIZED_CLAIM_OFFER(messageId)))
    yield put(
      claimRequestFail(messageId, ERROR_NO_SERIALIZED_CLAIM_OFFER(messageId))
    )

    return
  }

  try {
    if (isPaidCredential) {
      yield put(sendPaidCredentialRequest(messageId, claimOfferPayload))

      const walletBalance: string = yield select(getWalletBalance)
      const balanceAmount = new BigNumber(walletBalance)
      const getLedgerFeesStartTime = moment()
      const { transfer }: LedgerFeesData = yield call(getLedgerFees)
      const transferFeesAmount = new BigNumber(transfer)

      if (balanceAmount.isLessThan(payTokenAmount.plus(transferFeesAmount))) {
        const afterLedgerFeesCalculationDone = moment()
        // add an artificial delay here because by the time we reach here
        // user would already be seeing `Paying...` status modal
        // and if ledger fees API takes less than 1-2 seconds
        // then user would see UI jumping too quickly from one state to another
        // UX will be bad
        // TODO: this decision can also be effected with the device performance
        // so if we have device with low configuration, then we may not want this
        // Need to add package with device information and test how it behaves
        if (
          getLedgerFeesStartTime
            .add(1.5, 'seconds')
            .isAfter(afterLedgerFeesCalculationDone)
        ) {
          yield call(delay, 600)
        }
        yield put(inSufficientBalance(messageId))
        return
      }
    } else {
      yield put(sendClaimRequest(messageId, claimOfferPayload))
    }
    // since these two api calls are independent, we can call them in parallel
    // but result of both calls are needed before we can move on with other logic
    // so we wait here till both calls are done
    const [connectionHandle, claimHandle] = yield all([
      call(getHandleBySerializedConnection, connection.vcxSerializedConnection),
      call(
        getClaimHandleBySerializedClaimOffer,
        vcxSerializedClaimOffer.serialized
      ),
    ])

    // TODO We don't have any payment handle as of now, so hard code to 0
    const paymentHandle = 0

    try {
      yield call(
        sendClaimRequestApi,
        claimHandle,
        connectionHandle,
        paymentHandle
      )
      yield put(sendClaimRequestSuccess(messageId, claimOfferPayload))
      // if we are able to send claim request successfully,
      // then we can raise an action to show that we have sent claim request
      // so that our history middleware can record this event
      if (isPaidCredential) {
        // it also means payment was successful and we can show success to user in modal
        yield put(paidCredentialRequestSuccess(messageId))
        yield put(refreshWalletBalance())
      }
    } catch (e) {
      captureError(e)
      if (isPaidCredential) {
        yield put(paidCredentialRequestFail(messageId))
      } else {
        yield put(sendClaimRequestFail(messageId))
      }
    }

    // since we have sent claim request, state of claim offer in vcx is changed
    // so we need to update stored serialized claim offer in store
    // update serialized state in background
    yield call(
      saveSerializedClaimOffer,
      claimHandle,
      connection.identifier,
      messageId
    )
    // now the updated claim offer is secure stored now we can update claim request
  } catch (e) {
    captureError(e)
    if (isPaidCredential) {
      yield put(paidCredentialRequestFail(messageId))
    } else {
      yield put(
        claimRequestFail(messageId, ERROR_SEND_CLAIM_REQUEST(e.message))
      )
    }
  }
}

function* claimStorageSuccessSaga(
  action: ClaimStorageSuccessAction
): Generator<*, *, *> {
  const { messageId } = action
  yield put(claimRequestSuccess(messageId))
}

export function* watchClaimStorageSuccess(): any {
  yield takeEvery(CLAIM_STORAGE_SUCCESS, claimStorageSuccessSaga)
}

function* claimStorageFailSaga(
  action: ClaimStorageFailAction
): Generator<*, *, *> {
  const { messageId } = action
  yield put(claimRequestFail(messageId, CLAIM_STORAGE_ERROR()))
}

export function* watchClaimStorageFail(): any {
  yield takeEvery(CLAIM_STORAGE_FAIL, claimStorageFailSaga)
}

export function* saveSerializedClaimOffer(
  claimHandle: number,
  userDID: string,
  messageId: string
): Generator<*, *, *> {
  try {
    const [serializedClaimOffer, claimOfferVcxState]: [
      string,
      number,
    ] = yield all([
      call(serializeClaimOffer, claimHandle),
      call(getClaimOfferState, claimHandle),
    ])
    yield put(
      addSerializedClaimOffer(
        serializedClaimOffer,
        userDID,
        messageId,
        claimOfferVcxState
      )
    )
  } catch (e) {
    captureError(e)
    // TODO:KS need to think about what happens when serialize call from vcx fails
  }
}

function* watchClaimOfferAccepted(): any {
  yield takeEvery(CLAIM_OFFER_ACCEPTED, claimOfferAccepted)
}

export const addSerializedClaimOffer = (
  serializedClaimOffer: string,
  userDID: string,
  messageId: string,
  claimOfferVcxState: number
) => ({
  type: ADD_SERIALIZED_CLAIM_OFFER,
  serializedClaimOffer,
  userDID,
  messageId,
  claimOfferVcxState,
})

export function* watchAddSerializedClaimOffer(): any {
  //save claimOffers as well or rename to save ClaimOfferSaga
  yield takeEvery(
    [
      ADD_SERIALIZED_CLAIM_OFFER,
      CLAIM_OFFER_RECEIVED,
      SEND_CLAIM_REQUEST,
      CLAIM_OFFER_SHOWN,
    ],
    saveClaimOffersSaga
  )
}

export function* saveClaimOffersSaga(
  action: AddSerializedClaimOfferAction
): Generator<*, *, *> {
  try {
    const claimOffers = yield select(getClaimOffers)
    yield call(secureSet, CLAIM_OFFERS, JSON.stringify(claimOffers))
    yield put({
      type: SAVE_CLAIM_OFFERS_SUCCESS,
    })
  } catch (e) {
    // capture error for safe set
    captureError(e)
    yield put({
      type: SAVE_CLAIM_OFFERS_FAIL,
      error: ERROR_SAVE_CLAIM_OFFERS(e.message),
    })
  }
}

export function* removePersistedSerializedClaimOffersSaga(): Generator<
  *,
  *,
  *
> {
  try {
    yield call(secureDelete, CLAIM_OFFERS)
    yield put({
      type: REMOVE_SERIALIZED_CLAIM_OFFERS_SUCCESS,
    })
  } catch (e) {
    // capture error for secure delete
    captureError(e)
    yield put({
      type: REMOVE_SERIALIZED_CLAIM_OFFERS_FAIL,
    })
  }
}

export function* hydrateClaimOffersSaga(): Generator<*, *, *> {
  try {
    const claimOffersJson = yield call(getHydrationItem, CLAIM_OFFERS)
    if (claimOffersJson) {
      const serializedClaimOffers = JSON.parse(claimOffersJson)
      yield put(hydrateClaimOffers(serializedClaimOffers))
    }
  } catch (e) {
    captureError(e)
    yield put({
      type: HYDRATE_CLAIM_OFFERS_FAIL,
      error: ERROR_HYDRATE_CLAIM_OFFERS(e.message),
    })
  }
}

export const hydrateClaimOffers = (claimOffers: ClaimOfferStore) => ({
  type: HYDRATE_CLAIM_OFFERS_SUCCESS,
  claimOffers,
})

export function* watchClaimOffer(): any {
  yield all([
    watchClaimOfferAccepted(),
    watchAddSerializedClaimOffer(),
    watchClaimStorageSuccess(),
    watchClaimStorageFail(),
  ])
}

export const claimOfferShowStart = (uid: string) => ({
  type: CLAIM_OFFER_SHOW_START,
  uid,
})

export const resetClaimRequestStatus = (uid: string) => ({
  type: RESET_CLAIM_REQUEST_STATUS,
  uid,
})

export default function claimOfferReducer(
  state: ClaimOfferStore = claimOfferInitialState,
  action: ClaimOfferAction
) {
  switch (action.type) {
    case CLAIM_OFFER_RECEIVED:
      return {
        ...state,
        [action.payloadInfo.uid]: {
          ...action.payload,
          ...action.payloadInfo,
          status: CLAIM_OFFER_STATUS.RECEIVED,
          claimRequestStatus: CLAIM_REQUEST_STATUS.NONE,
          error: null,
        },
      }
    case CLAIM_OFFER_SHOWN:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: CLAIM_OFFER_STATUS.SHOWN,
        },
      }
    case CLAIM_OFFER_ACCEPTED:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: CLAIM_OFFER_STATUS.ACCEPTED,
        },
      }
    case CLAIM_OFFER_IGNORED:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: CLAIM_OFFER_STATUS.IGNORED,
        },
      }
    case CLAIM_OFFER_REJECTED:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: CLAIM_OFFER_STATUS.REJECTED,
        },
      }
    case SEND_CLAIM_REQUEST:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.SENDING_CLAIM_REQUEST,
        },
      }
    case CLAIM_REQUEST_SUCCESS:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.CLAIM_REQUEST_SUCCESS,
        },
      }
    case CLAIM_REQUEST_FAIL:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.CLAIM_REQUEST_FAIL,
        },
      }
    case INSUFFICIENT_BALANCE:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.INSUFFICIENT_BALANCE,
        },
      }
    case SEND_PAID_CREDENTIAL_REQUEST:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus:
            CLAIM_REQUEST_STATUS.SENDING_PAID_CREDENTIAL_REQUEST,
        },
      }
    case PAID_CREDENTIAL_REQUEST_SUCCESS:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus:
            CLAIM_REQUEST_STATUS.PAID_CREDENTIAL_REQUEST_SUCCESS,
        },
      }
    case PAID_CREDENTIAL_REQUEST_FAIL:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.PAID_CREDENTIAL_REQUEST_FAIL,
        },
      }
    case RESET:
      return claimOfferInitialState
    case ADD_SERIALIZED_CLAIM_OFFER:
      return {
        ...state,
        vcxSerializedClaimOffers: {
          ...state.vcxSerializedClaimOffers,
          [action.userDID]: {
            ...state.vcxSerializedClaimOffers[action.userDID],
            [action.messageId]: {
              serialized: action.serializedClaimOffer,
              state: action.claimOfferVcxState,
              messageId: action.messageId,
            },
          },
        },
      }
    case HYDRATE_CLAIM_OFFERS_SUCCESS:
      return action.claimOffers

    case CLAIM_OFFER_SHOW_START:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          status: CLAIM_OFFER_STATUS.RECEIVED,
          claimRequestStatus: CLAIM_REQUEST_STATUS.NONE,
        },
      }

    case RESET_CLAIM_REQUEST_STATUS:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.NONE,
        },
      }

    case SEND_CLAIM_REQUEST_SUCCESS:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_SUCCESS,
        },
      }

    case SEND_CLAIM_REQUEST_FAIL:
      return {
        ...state,
        [action.uid]: {
          ...state[action.uid],
          claimRequestStatus: CLAIM_REQUEST_STATUS.SEND_CLAIM_REQUEST_FAIL,
        },
      }
    default:
      return state
  }
}


<|start_filename|>app/components/info-section-list.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { Container } from './layout/container'
import { color, MARGIN_BOTTOM } from '../common/styles/constant'
import type { GenericObject } from '../common/type-common'

// TODO:KS Change GenericObject to specific props by combining CustomView props
export class ListItem extends PureComponent<GenericObject, *> {
  render() {
    const { style = [], bottomMargin } = this.props
    const itemStyles = [bottomMargin ? styles.bottomMargin : null, ...style]

    return (
      <Container secondary pad row {...this.props} style={itemStyles}>
        {this.props.children}
      </Container>
    )
  }
}

export class ListItemData extends PureComponent<GenericObject, *> {
  render() {
    return (
      <Container row {...this.props}>
        {this.props.children}
      </Container>
    )
  }
}

export default class InfoSectionList extends PureComponent<GenericObject, *> {
  render() {
    return (
      <Container tertiary {...this.props}>
        {this.props.children}
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  bottomMargin: {
    marginBottom: MARGIN_BOTTOM,
  },
})


<|start_filename|>app/lock/lock-setup-success.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, InteractionManager } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import {
  Container,
  CustomText,
  CustomView,
  CustomButton,
  Icon,
} from '../components'
import { settingsTabRoute, homeTabRoute } from '../common'
import { unlockApp, clearPendingRedirect } from './lock-store'
import type { Store } from '../store/type-store'
import { OFFSET_1X, OFFSET_2X, OFFSET_4X, color } from '../common/styles'
import { UNLOCKING_APP_WAIT_MESSAGE } from '../common/message-constants'
import type { LockSetupSuccessProps, LockSetupSuccessState } from './type-lock'

export class LockSetupSuccess extends PureComponent<
  LockSetupSuccessProps,
  LockSetupSuccessState
> {
  state = {
    interactionsDone: false,
  }
  onClose = () => {
    this.props.unlockApp()
    if (
      this.props.navigation.state &&
      this.props.navigation.state.params &&
      this.props.navigation.state.params.changePin === true
    ) {
      this.props.navigation.navigate(settingsTabRoute)
    } else if (this.props.pendingRedirection) {
      // if there is a redirection pending, then redirect and clear it
      this.props.pendingRedirection.map(pendingRedirection => {
        this.props.navigation.navigate(
          pendingRedirection.routeName,
          pendingRedirection.params
        )
      })
      this.props.clearPendingRedirect()
    } else {
      this.props.navigation.navigate(homeTabRoute)
    }
  }

  componentDidMount() {
    InteractionManager.runAfterInteractions(() => {
      this.setState({ interactionsDone: true })
    })
  }

  render() {
    const { isFetchingInvitation } = this.props
    let message =
      this.props.navigation.state &&
      this.props.navigation.state.params &&
      this.props.navigation.state.params.changePin === true
        ? 'Your connect.me app is secured.'
        : 'Your connect.me app is now secured'

    if (isFetchingInvitation === true) {
      message = UNLOCKING_APP_WAIT_MESSAGE
    }

    return (
      <Container tertiary>
        <Container clearBg center style={[style.successContainer]}>
          <Icon
            extraLarge
            resizeMode="cover"
            src={require('../images/lock.png')}
            testID="lock-success-lock-logo"
          />
          <CustomText
            h4
            bg="tertiary"
            tertiary
            thick
            center
            style={[style.successMessage]}
          >
            {message}
          </CustomText>
          <CustomText
            h6
            bg="tertiary"
            tertiary
            thick
            center
            style={[style.successMessage]}
          >
            {this.props.navigation.state &&
            this.props.navigation.state.params &&
            this.props.navigation.state.params.changePin
              ? "From now on you'll need to use your passcode to unlock this app."
              : ' '}
          </CustomText>
        </Container>
        <CustomView>
          <CustomButton
            primary
            raised
            medium
            disabled={isFetchingInvitation}
            testID="close-button"
            fontWeight="600"
            title="Close"
            onPress={this.onClose}
          />
        </CustomView>
      </Container>
    )
  }
}

const mapStateToProps = (state: Store, props) => ({
  pendingRedirection: state.lock.pendingRedirection,
  pendingRedirectionParams: state.lock.pendingRedirectionParams || {},
  isFetchingInvitation: Object.keys(state.smsPendingInvitation).some(
    smsToken =>
      state.smsPendingInvitation[smsToken] &&
      state.smsPendingInvitation[smsToken].isFetching === true
  ),
  changePin:
    props.navigation.state.params !== undefined
      ? props.navigation.state.params.changePin
      : false,
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      clearPendingRedirect,
      unlockApp,
    },
    dispatch
  )

export default connect(mapStateToProps, mapDispatchToProps)(LockSetupSuccess)

const style = StyleSheet.create({
  successContainer: {
    paddingHorizontal: OFFSET_2X,
  },
  successMessage: {
    paddingVertical: OFFSET_4X,
  },
  successInfo: {
    paddingHorizontal: OFFSET_1X,
  },
})


<|start_filename|>android/app/src/main/java/me/connect/BridgeUtils.java<|end_filename|>
package me.connect;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import com.facebook.react.bridge.Promise;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import android.content.ContextWrapper;

/**
 * Created by abdussami on 23/05/18.
 */

public class BridgeUtils {
    private static  String TAG ="BRIDGEUTILS::";
    public static void resolveIfValid(Promise promise, Object result) {
        // Add more conditions here if you want to check if the result is valid
        //e.g Like if result is null return false
        //e.g If result is empty string return false
        if (result != null) {
            promise.resolve(result);
        } else {
            promise.reject("NULL VALUE", "Null value was received as result from wrapper");
        }

    }


    public static void writeCACert(Context context) {
        Log.d(TAG, "writeCACert() called with: context = [" + context + "]");
        ContextWrapper cw = new ContextWrapper(context);
        File cert_file = new File(cw.getFilesDir().toString() + "/cacert.pem");
        if (!cert_file.exists()) {
            try {
                FileWriter fw = new FileWriter(cert_file);
                fw.write(generateCaCertContents());
                fw.flush();
                fw.close();
            } catch (IOException e) {
                Log.e(TAG, "writeCACert: ",e );
            }
        }
    }

    static String generateCaCertContents() {
        File folder = new File("/system/etc/security/cacerts");
        File[] listOfFiles = folder.listFiles();
        StringBuilder sb = new StringBuilder(99999);
        try {
            for (File certFile : listOfFiles) {
                if (certFile.isFile()) {

                    sb.append(System.lineSeparator());
                    sb.append("-----BEGIN CERTIFICATE-----");
                    sb.append(System.lineSeparator()).append(
                            getBetweenStrings(getFileContents(certFile),
                            "-----BEGIN CERTIFICATE-----",
                            "-----END CERTIFICATE-----"));
                    sb.append("-----END CERTIFICATE-----");
                    sb.append(System.lineSeparator());
                    sb.append(System.lineSeparator());
                }
            }
           return sb.toString();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return "";
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
     static String getFileContents( File file ) throws IOException {
        StringBuffer text = new StringBuffer(99999);
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }
    private static String getBetweenStrings(
            String text,
            String textFrom,
            String textTo) {

        String result = "";

        // Cut the beginning of the text to not occasionally meet a
        // 'textTo' value in it:
        result =
                text.substring(
                        text.indexOf(textFrom) + textFrom.length(),
                        text.length());

        // Cut the excessive ending of the text:
        result =
                result.substring(
                        0,
                        result.indexOf(textTo));

        return result;
    }
}


<|start_filename|>app/invitation/type-invitation.js<|end_filename|>
// @flow
import type {
  ResponseTypes,
  RequestDetailTextPropsText,
  RequestDetailAvatarProps,
} from '../components/request/type-request'
import type {
  CustomError,
  ReactNavigation,
  InitialTestAction,
  ResetAction,
} from '../common/type-common'
import type {
  InvitationSenderAgencyDetail,
  AgentKeyDelegationProof,
  InvitationSenderDetail,
} from '../sms-pending-invitation/type-sms-pending-invitation'

export type InvitationPayload = {
  senderEndpoint: string,
  requestId: string,
  senderAgentKeyDelegationProof: AgentKeyDelegationProof,
  senderName: string,
  senderDID: string,
  senderLogoUrl: string,
  senderVerificationKey: string,
  targetName: string,
  senderDetail: InvitationSenderDetail,
  senderAgencyDetail: InvitationSenderAgencyDetail,
}

export type Invitation = {
  +payload: ?InvitationPayload,
  +status: ResponseTypes,
  +isFetching: boolean,
  +error: ?CustomError,
}

export type InvitationStore = {
  +[string]: Invitation,
}

export const INVITATION_RECEIVED: 'INVITATION_RECEIVED' = 'INVITATION_RECEIVED'

export type InvitationReceivedActionData = {
  payload: InvitationPayload,
}

export type InvitationReceivedAction = {
  type: typeof INVITATION_RECEIVED,
  data: InvitationReceivedActionData,
}

export const INVITATION_RESPONSE_SEND: 'INVITATION_RESPONSE_SEND' =
  'INVITATION_RESPONSE_SEND'

export type InvitationResponseSendData = {
  response: ResponseTypes,
  senderDID: string,
}

export type InvitationResponseSendAction = {
  type: typeof INVITATION_RESPONSE_SEND,
  data: InvitationResponseSendData,
}

export const INVITATION_RESPONSE_SUCCESS: 'INVITATION_RESPONSE_SUCCESS' =
  'INVITATION_RESPONSE_SUCCESS'

export type InvitationSuccessAction = {
  type: typeof INVITATION_RESPONSE_SUCCESS,
  senderDID: string,
}

export const INVITATION_RESPONSE_FAIL: 'INVITATION_RESPONSE_FAIL' =
  'INVITATION_RESPONSE_FAIL'

export type InvitationFailAction = {
  type: typeof INVITATION_RESPONSE_FAIL,
  error: CustomError,
  senderDID: string,
}

export const INVITATION_REJECTED: 'INVITATION_REJECTED' = 'INVITATION_REJECTED'

export type InvitationRejectedAction = {
  type: typeof INVITATION_REJECTED,
  senderDID: string,
}

export type InvitationAction =
  | InvitationReceivedAction
  | InvitationResponseSendAction
  | InvitationFailAction
  | InvitationSuccessAction
  | InvitationRejectedAction
  | InitialTestAction
  | ResetAction

export type InvitationProps = {
  invitation: ?Invitation,
  sendInvitationResponse: (data: InvitationResponseSendData) => void,
  invitationRejected: (senderDID: string) => void,
  smsPendingInvitationSeen: (smsToken: ?string) => void,
  showErrorAlerts: boolean,
  smsToken: ?string,
  isSmsInvitationNotSeen: boolean,
} & ReactNavigation

export type InvitationState = {
  loading: boolean,
}

export const ERROR_INVITATION_VCX_INIT = {
  code: 'INVITATION-001',
  message: 'Could not initialize vcx while creating a connection',
}

export const ERROR_INVITATION_CONNECT = (message: string) => ({
  code: 'INVITATION-002',
  message: `Error while establishing a connection ${message}`,
})


<|start_filename|>app/wallet/__tests__/wallet-balance.spec.js<|end_filename|>
// @flow

import React from 'react'
import { Provider } from 'react-redux'
import { View, Text } from 'react-native'
import renderer from 'react-test-renderer'
import WalletBalance from '../wallet-balance'
import { getStore } from '../../../__mocks__/static-data'

describe('<WalletBalance />', () => {
  it('should render WalletBalance', () => {
    const wrapper = renderer
      .create(
        <Provider store={getStore()}>
          <WalletBalance
            render={balance => (
              <View>
                <Text>{balance}</Text>
              </View>
            )}
          />
        </Provider>
      )
      .toJSON()
    expect(wrapper).toMatchSnapshot()
  })
})


<|start_filename|>flow-typed/npm/reactotron.js<|end_filename|>
// declare module console extends console {
//   tron: {
//     overlay: (T) => T
//   }
// }


<|start_filename|>app/common/message-constants.js<|end_filename|>
// @flow
// for overall app message string, it can be error, success, warning etc.

export const TOUCH_ID_MESSAGE = 'Please confirm with Biometrics'
export const TOUCH_ID_NOT_AVAILABLE =
  'Biometrics is not supported on this device'

export const DEVICE_ENROLLMENT_ERROR = [
  'Enrollment Error',
  'Identifier or Seed or Push-notification token not present!',
]

export const PUSH_NOTIFICATION_PERMISSION_ERROR = [
  'Permission Error',
  'Push Notification permission needed! Please enable it from Settings.',
]

export const DUPLICATE_CONNECTION_ERROR = [
  'Attention!',
  'Duplicate Connection invitation!',
]

export const UNLOCKING_APP_WAIT_MESSAGE = 'Loading please wait...'

export const ENTER_PASS_CODE_MESSAGE = 'Enter passcode'

export const ENTER_YOUR_PASS_CODE_MESSAGE = 'Enter your passcode'

export const FIRST_BACKUP_TITLE = 'Set up data recovery now!'

export const FIRST_BACKUP_SUBTEXT = '2 easy steps, takes 3 minutes.'

export const SUBSEQUENT_BACKUP_TITLE =
  'You have new data that is not backed up.'

export const SUBSEQUENT_BACKUP_SUBTEXT =
  "Create another backup so you don't lose anything."

export const PASSPHRASE_GENERATION_ERROR =
  'Uh oh... Looks like something went wrong.'


<|start_filename|>app/components/custom-list/custom-list.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { StyleSheet, FlatList } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import {
  Container,
  CustomView,
  CustomText,
  Separator,
  Icon,
  CustomSafeAreaView,
} from '../index'
import { OFFSET_1X, OFFSET_3X } from '../../common/styles'
import { getUserAvatarSource } from '../../store/store-selector'
import type { CustomListProps, Item } from './type-custom-list'
import type { Store } from '../../store/type-store'

export class CustomList extends PureComponent<CustomListProps, void> {
  keyExtractor = ({ label }: Item, index: number) => `${label}${index}`

  renderListType1Item = ({ item, index }: { item: Item, index: number }) => {
    // if item is an array then take first element of item
    // as we only need single item
    if (Array.isArray(item)) {
      item = item[0]
    }
    if (this.props.type === 'center') {
      return (
        <CustomView fifth row horizontalSpace doubleVerticalSpace>
          <CustomView fifth right style={[styles.itemLabel]}>
            <CustomText
              h7
              uppercase
              semiBold
              bg="tertiary"
              transparentBg
              style={[styles.labelText]}
              testID={`custom-list-label-${index}`}
            >
              {item.label}
            </CustomText>
          </CustomView>
          <CustomView fifth left style={[styles.itemValue]}>
            <CustomText
              h6
              demiBold
              bg="tertiary"
              transparentBg
              testID={`custom-list-data-${index}`}
            >
              {item.data}
            </CustomText>
          </CustomView>
        </CustomView>
      )
    } else {
      const logoUrl = item.data
        ? item.claimUuid &&
          this.props.claimMap &&
          this.props.claimMap[item.claimUuid] &&
          this.props.claimMap[item.claimUuid].logoUrl
          ? { uri: this.props.claimMap[item.claimUuid].logoUrl }
          : this.props.avatarSource || require('../../images/UserAvatar.png')
        : null

      return (
        <Container fifth style={[styles.list]} row>
          <Container fifth verticalSpace>
            <CustomView fifth>
              <CustomText
                h7
                uppercase
                semiBold
                bg="tertiary"
                transparentBg
                style={[styles.list2LabelText]}
                testID={`custom-list-label-${index}`}
              >
                {item.label}
              </CustomText>
            </CustomView>
            <CustomView fifth>
              <CustomText
                h6
                demiBold
                bg="tertiary"
                transparentBg
                testID={`custom-list-data-${index}`}
              >
                {item.data}
              </CustomText>
            </CustomView>
          </Container>
          <Icon center medium round resizeMode="cover" src={logoUrl} />
        </Container>
      )
    }
  }

  render() {
    const items: Item[] = this.props.items
    return (
      //TODO : fix other customSafeAreaView , use prop
      <Container safeArea fifth>
        <FlatList
          data={items}
          keyExtractor={this.keyExtractor}
          ItemSeparatorComponent={Separator}
          ListFooterComponent={Separator}
          renderItem={this.renderListType1Item}
        />
      </Container>
    )
  }
}

const mapStateToProps = (state: Store) => ({
  avatarSource: getUserAvatarSource(state.user.avatarName),
})

export default connect(mapStateToProps)(CustomList)

const styles = StyleSheet.create({
  list: {
    paddingHorizontal: OFFSET_3X / 2,
  },
  itemLabel: {
    flex: 4,
    paddingRight: OFFSET_3X / 2,
  },
  labelText: {
    lineHeight: 19,
  },
  itemValue: {
    flex: 6,
  },
  list2LabelText: {
    paddingVertical: 2,
  },
})


<|start_filename|>app/components/backup-restore-passphrase/type-backup-restore-passphrase.js<|end_filename|>
// @flow
import type { CustomError } from '../../common/type-common'

export type BackupRestorePassphraseProps = {
  testID: string,
  filename?: string,
  placeholder: string,
  errorState?: boolean,
  onSubmit: () => any,
}


<|start_filename|>app/components/qr-scanner/__tests__/qr-scanner.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import { SCAN_STATUS } from '../type-qr-scanner'
import QRScanner from '../qr-scanner'
import {
  qrData,
  validQrCodeEnvironmentSwitchUrl,
  validInvitationUrlQrCode,
  smsDownloadedPayload,
} from '../../../../__mocks__/static-data'
import * as api from '../../../api/api'
import { convertSmsPayloadToInvitation } from '../../../sms-pending-invitation/sms-pending-invitation-store'

describe('<QRScanner />', () => {
  const getProps = () => ({
    onClose: jest.fn(),
    onRead: jest.fn(),
    onEnvironmentSwitchUrl: jest.fn(),
    onInvitationUrl: jest.fn(),
  })

  function setup() {
    const props = getProps()
    const wrapper = renderer.create(<QRScanner {...props} />)
    const instance = wrapper.getInstance()
    return {
      ...props,
      instance,
      wrapper,
    }
  }

  it('should match snapshot', () => {
    const { wrapper } = setup()
    expect(wrapper.toJSON()).toMatchSnapshot()
  })

  it('should call onRead once QR code read is successful', () => {
    jest.useFakeTimers()
    const { onRead, instance } = setup()

    const qrReadEvent = {
      data: JSON.stringify(qrData),
    }

    instance.onRead(qrReadEvent)
    expect(onRead).toHaveBeenCalledWith(expect.objectContaining(qrData))
    expect(instance.state.scanStatus).toBe(SCAN_STATUS.SUCCESS)
  })

  it('should set state to fail if QR code is not correct', () => {
    jest.useFakeTimers()

    const { instance } = setup()

    instance.onRead({ data: '' })
    expect(instance.state.scanStatus).toBe(SCAN_STATUS.FAIL)

    jest.runAllTimers()

    expect(instance.state.scanStatus).toBe(SCAN_STATUS.SCANNING)
  })

  it('should call onEnvironmentSwitchUrl if it reads correct environment switcher url', () => {
    jest.useFakeTimers()
    const { onEnvironmentSwitchUrl, instance } = setup()

    instance.onRead({ data: validQrCodeEnvironmentSwitchUrl })
    expect(onEnvironmentSwitchUrl).toHaveBeenCalledWith({
      name: 'dev',
      url: validQrCodeEnvironmentSwitchUrl,
    })
    expect(instance.state.scanStatus).toBe(SCAN_STATUS.SUCCESS)
  })

  it('should send a request to download invitation if url is scanned', async () => {
    jest.useFakeTimers()
    const invitationDetailRequestSpy = jest.spyOn(
      api,
      'invitationDetailsRequest'
    )

    invitationDetailRequestSpy.mockImplementation(() =>
      Promise.resolve(smsDownloadedPayload)
    )

    const { onInvitationUrl, instance } = setup()

    const pendingQrProcessing = instance.onRead({
      data: validInvitationUrlQrCode,
    })
    expect(instance.state.scanStatus).toBe(SCAN_STATUS.DOWNLOADING_INVITATION)
    // process API call
    await pendingQrProcessing

    expect(onInvitationUrl).toHaveBeenCalledWith(
      convertSmsPayloadToInvitation(smsDownloadedPayload)
    )
    expect(instance.state.scanStatus).toBe(SCAN_STATUS.SUCCESS)

    invitationDetailRequestSpy.mockReset()
    invitationDetailRequestSpy.mockRestore()

    jest.runAllTimers()

    expect(instance.state.scanStatus).toBe(SCAN_STATUS.SCANNING)
  })
})


<|start_filename|>app/components/qr-scanner/qr-scanner-validator.js<|end_filename|>
// @flow
import schemaValidator from '../../services/schema-validator'
import {
  QR_CODE_SENDER_DID,
  QR_CODE_SENDER_VERIFICATION_KEY,
  QR_CODE_LOGO_URL,
  QR_CODE_REQUEST_ID,
  QR_CODE_SENDER_KEY_DELEGATION,
  QR_CODE_SENDER_NAME,
  QR_CODE_TARGET_NAME,
  QR_CODE_SENDER_DETAIL,
  QR_CODE_DELEGATION_DID,
  QR_CODE_DELEGATION_KEY,
  QR_CODE_DELEGATION_SIGNATURE,
  QR_CODE_SENDER_AGENCY,
  QR_CODE_SENDER_AGENCY_DID,
  QR_CODE_SENDER_AGENCY_KEY,
  QR_CODE_SENDER_AGENCY_ENDPOINT,
} from '../../api/api-constants'
import type { QrCode } from './type-qr-scanner'

const qrSchema = {
  type: 'object',
  properties: {
    [QR_CODE_REQUEST_ID]: { type: 'string' },
    [QR_CODE_SENDER_DETAIL]: {
      type: 'object',
      properties: {
        [QR_CODE_SENDER_DID]: { type: 'string' },
        [QR_CODE_SENDER_NAME]: { type: 'string' },
        [QR_CODE_LOGO_URL]: { type: 'string' },
        [QR_CODE_SENDER_VERIFICATION_KEY]: { type: 'string' },
        [QR_CODE_SENDER_KEY_DELEGATION]: {
          type: 'object',
          properties: {
            [QR_CODE_DELEGATION_DID]: { type: 'string' },
            [QR_CODE_DELEGATION_KEY]: { type: 'string' },
            [QR_CODE_DELEGATION_SIGNATURE]: { type: 'string' },
          },
          required: [
            QR_CODE_DELEGATION_DID,
            QR_CODE_DELEGATION_KEY,
            QR_CODE_DELEGATION_SIGNATURE,
          ],
        },
      },
      required: [
        QR_CODE_SENDER_DID,
        QR_CODE_SENDER_NAME,
        QR_CODE_LOGO_URL,
        QR_CODE_SENDER_VERIFICATION_KEY,
        QR_CODE_SENDER_KEY_DELEGATION,
      ],
    },
    [QR_CODE_SENDER_AGENCY]: {
      type: 'object',
      properties: {
        [QR_CODE_SENDER_AGENCY_DID]: { type: 'string' },
        [QR_CODE_SENDER_AGENCY_KEY]: { type: 'string' },
        [QR_CODE_SENDER_AGENCY_ENDPOINT]: { type: 'string' },
      },
      required: [
        QR_CODE_SENDER_AGENCY_DID,
        QR_CODE_SENDER_AGENCY_KEY,
        QR_CODE_SENDER_AGENCY_ENDPOINT,
      ],
    },
    [QR_CODE_TARGET_NAME]: { type: 'string' },
  },
  required: [
    QR_CODE_REQUEST_ID,
    QR_CODE_SENDER_DETAIL,
    QR_CODE_SENDER_AGENCY,
    QR_CODE_TARGET_NAME,
  ],
}

// this is the number that is max allowed by 200 X 200 qr code
// if we are getting more than that, then there is an issue from
// qr code generation site or someone is trying to break the app
const qrCodeAllowedLength = 1200

// If we need to use QR scanner somewhere else in app as well
// remove this method and create an equivalent in another
// component as well, for now this is good here
export function isValidQrCode(qr: string): QrCode | boolean {
  // check the length of qr data so that we don't get memory issues
  // while parsing the json
  if (qr.length >= qrCodeAllowedLength) {
    return false
  }

  let qrData: QrCode
  try {
    qrData = (JSON.parse(qr): QrCode)
  } catch (e) {
    // qr code is not a valid json, we still return false
    return false
  }

  // check if qr code schema is valid
  if (!schemaValidator.validate(qrSchema, qrData)) {
    return false
  }

  // since all checks are passed
  // qr code data is valid, send the parsed data back
  return qrData
}


<|start_filename|>app/backup/__tests__/backup-error.spec.js<|end_filename|>
// @flow
import 'react-native'
import React from 'react'
import renderer from 'react-test-renderer'
import { BackupErrorScreen } from '../backup-error'
import { getNavigation, getStore } from '../../../__mocks__/static-data'

describe('Restore screen', () => {
  function getProps() {
    return {
      store: getStore(),
      navigation: {
        navigate: jest.fn(),
        goBack: jest.fn(),
        state: {
          params: {
            recoveryPassphrase: '',
            initialRoute: '',
          },
        },
      },
      generateBackupFile: jest.fn(),
      updateStatusBarTheme: jest.fn(),
    }
  }

  function setup() {
    const props = getProps()
    return { props }
  }

  it('should render properly and match the snapshot', () => {
    const { props } = setup()
    const tree = renderer.create(<BackupErrorScreen {...props} />).toJSON()
    expect(tree).toMatchSnapshot()
  })

  //TODO add snapshot for error screen
})


<|start_filename|>app/invitation/wait-for-invitation.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { View, Image, StyleSheet } from 'react-native'
import { Container, CustomView, CustomText, Loader } from '../components'
import { OFFSET_3X, OFFSET_4X } from '../common/styles'

export default class WaitForInvitation extends PureComponent<void, void> {
  render() {
    return (
      <Container center style={[styles.expiredTokenContainer]}>
        <Loader />
      </Container>
    )
  }
}

const styles = StyleSheet.create({
  expiredTokenContainer: {
    paddingTop: OFFSET_3X,
  },
  textContainer: {
    paddingTop: OFFSET_3X,
  },
  sorryText: {
    paddingVertical: OFFSET_4X,
  },
})


<|start_filename|>app/deep-link/__test__/deep-link.spec.js<|end_filename|>
// @flow
import React from 'react'
import renderer from 'react-test-renderer'
import { DeepLink } from '../index'

describe('<DeepLink />', () => {
  function getProps() {
    return {
      deepLinkError: jest.fn(),
      deepLinkEmpty: jest.fn(),
      deepLinkData: jest.fn(),
      tokens: {},
    }
  }

  function setup() {
    const props = getProps()
    const component = renderer.create(<DeepLink {...props} />)
    const instance: DeepLink = component.root.instance

    return { props, component, instance }
  }

  it('should raise error if bundle throws error', () => {
    const { instance, props } = setup()
    const bundle = {
      error: 'Some deep link error',
      params: null,
    }

    instance.onDeepLinkData(bundle)
    expect(props.deepLinkError).toHaveBeenCalledWith(bundle.error)
    // this below line ensures that we are not calling deepLinkData
    // with some hard coded token and prevents us to accidentally
    // committing changes that will break functionality
    expect(props.deepLinkData).not.toHaveBeenCalled()
  })
})


<|start_filename|>app/bridge/react-native-cxs/__tests__/vcx-transformers.spec.js<|end_filename|>
// @flow

import {
  convertAgencyConfigToVcxProvision,
  convertVcxProvisionResultToUserOneTimeInfo,
  convertCxsInitToVcxInit,
  convertInvitationToVcxConnectionCreate,
  convertVcxCredentialOfferToCxsClaimOffer,
  convertVcxLedgerFeesToLedgerFees,
} from '../vcx-transformers'
import {
  vcxProvisionResult,
  agencyUrl,
  agencyDID,
  agencyVerificationKey,
  poolConfig,
  userOneTimeInfo,
  getTestInvitationPayload,
  vcxClaimOffer,
} from '../../../../__mocks__/static-data'
import type { InvitationPayload } from '../../../invitation/type-invitation'

const agencyPoolConfig = {
  agencyUrl,
  agencyDID,
  agencyVerificationKey,
  poolConfig,
}

const initWithGenesisPathConfig = {
  ...userOneTimeInfo,
  ...agencyPoolConfig,
  genesis_path: 'genesis_path',
}

const walletPoolName = {
  walletName: 'walletName',
  poolName: 'poolName',
}

describe('transformer:VCX', () => {
  it('convertAgencyConfigToVcxProvision', async () => {
    const vcxProvisionConfig = await convertAgencyConfigToVcxProvision(
      agencyPoolConfig,
      walletPoolName
    )
    expect(vcxProvisionConfig).toMatchSnapshot()
  })

  it('convertVcxProvisionResultToUserOneTimeInfo', () => {
    expect(
      convertVcxProvisionResultToUserOneTimeInfo(vcxProvisionResult)
    ).toMatchSnapshot()
  })

  it('convertCxsInitToVcxInit', async () => {
    const vcxInitConfig = await convertCxsInitToVcxInit(
      initWithGenesisPathConfig,
      walletPoolName
    )
    expect(vcxInitConfig).toMatchSnapshot()
  })

  it('convertInvitationToVcxConnectionCreate', () => {
    const gen = getTestInvitationPayload()
    const invitation = gen.next().value
    if (invitation) {
      expect(
        convertInvitationToVcxConnectionCreate(invitation.payload)
      ).toMatchSnapshot()
    }
  })

  it('convertVcxCredentialOfferToCxsClaimOffer', () => {
    expect(
      convertVcxCredentialOfferToCxsClaimOffer(vcxClaimOffer)
    ).toMatchSnapshot()
  })

  it('convertVcxLedgerFeesToLedgerFees, return correct fees', () => {
    const correctLedgerFees = {
      '10001': '100',
    }
    expect(
      convertVcxLedgerFeesToLedgerFees(JSON.stringify(correctLedgerFees))
    ).toEqual({
      transfer: '0.000001',
    })
  })

  it('convertVcxLedgerFeesToLedgerFees, 0 fees for incorrect ledger fees', () => {
    const incorrectLedgerFees = {
      '10001': '0',
    }
    expect(
      convertVcxLedgerFeesToLedgerFees(JSON.stringify(incorrectLedgerFees))
    ).toEqual({
      transfer: '0',
    })
    const noLedgerFeesForTransfer = {
      '1001': '0',
    }
    expect(
      convertVcxLedgerFeesToLedgerFees(JSON.stringify(noLedgerFeesForTransfer))
    ).toEqual({
      transfer: '0',
    })
    const noLedgerFeesAsNumberForTransfer = {
      '1001': '1a',
    }
    expect(
      convertVcxLedgerFeesToLedgerFees(
        JSON.stringify(noLedgerFeesAsNumberForTransfer)
      )
    ).toEqual({
      transfer: '0',
    })
  })
})


<|start_filename|>app/components/banner/banner.js<|end_filename|>
// @flow

/*
  This component relies on the `showBanner` value in the wallet store.
  That decides whether or not it will render anything.
  If you want to trigger it to render then you need to call the method `promptBackupBanner` from the /wallet-store and pass it a truthy boolean.
  Right now it's being turned on from the connection saga & then turned off once a backup successful.
*/
import React, { PureComponent } from 'react'
import { StyleSheet } from 'react-native'
import { connect } from 'react-redux'
import type { Store } from '../../store/type-store'
import { CustomView, CustomText, Icon } from '../../components'
import { color } from '../../common/styles'
import BackupWallet from '../../settings/backup-wallet'
import Offline from '../../offline/offline'
import {
  IMAGE_WIDTH,
  IMAGE_HEIGHT,
  BACKUP_BANNER_TEST_ID,
  BANNER_HEIGHT,
} from './banner-constants'
import type { BannerProps } from './type-banner'
import DangerBanner from './banner-danger'
import { OfflineBanner } from './banner-offline'
import {
  getOfflineStatus,
  getBackupShowBanner,
  getLastSuccessfulBackupTimeStamp,
} from '../../store/store-selector'
import {
  LAST_SUCCESSFUL_BACKUP,
  FIRST_BACKUP_SUBTEXT,
  FIRST_BACKUP_TITLE,
  SUBSEQUENT_BACKUP_SUBTEXT,
  SUBSEQUENT_BACKUP_TITLE,
} from '../../common'

class Banner extends PureComponent<BannerProps, void> {
  render() {
    const {
      offline,
      showBanner,
      navigation,
      lastSuccessfulBackupTimeStamp,
    } = this.props
    let title = FIRST_BACKUP_TITLE
    let subtext = FIRST_BACKUP_SUBTEXT
    if (lastSuccessfulBackupTimeStamp !== '') {
      title = SUBSEQUENT_BACKUP_TITLE
      subtext = SUBSEQUENT_BACKUP_SUBTEXT
    }

    if (offline) {
      return (
        <CustomView>
          <Offline
            navigation={navigation}
            render={status => (
              <OfflineBanner
                testID={BACKUP_BANNER_TEST_ID}
                bannerTitle="You are not connected to the internet"
              />
            )}
          />
        </CustomView>
      )
    }

    if (showBanner && !offline) {
      return (
        <CustomView>
          <BackupWallet
            navigation={navigation}
            render={(status, backupWallet) => (
              <DangerBanner
                onPress={backupWallet}
                testID={BACKUP_BANNER_TEST_ID}
                bannerTitle={title}
                bannerSubtext={subtext}
              />
            )}
          />
        </CustomView>
      )
    }

    return null
  }
}

const mapStateToProps = (state: Store) => {
  return {
    offline: getOfflineStatus(state),
    showBanner: getBackupShowBanner(state),
    lastSuccessfulBackupTimeStamp: getLastSuccessfulBackupTimeStamp(state),
  }
}

export default connect(mapStateToProps)(Banner)


<|start_filename|>app/components/qr-scanner/__tests__/qr-validator.spec.js<|end_filename|>
// @flow
import { isValidQrCode } from '../qr-scanner-validator'

describe('QR Scanner validator', () => {
  it('should return false if schema is not valid at top level', () => {
    const invalidQrSchemas = [
      { n: '' },
      { p: '' },
      { n: '', a: '' },
      { n: '', a: '' },
      { p: '', '1': '' },
      // invalid as per length
      {
        n: '',
        p: 'a'.repeat(1300),
      },
      // invalid at second level
      { p: JSON.stringify({ lu: '' }), n: '', sD: '', sVk: '' },
      { p: JSON.stringify({ lu: '', rid: '' }), n: '', sD: '', sVk: '' },
      {
        p: JSON.stringify({ lu: '', rid: '', sakdp: '' }),
        n: '',
        sD: '',
        sVk: '',
      },
      {
        p: JSON.stringify({ lu: '', rid: '', sakdp: '', sn: '' }),
        n: '',
        sD: '',
        sVk: '',
      },
      {
        p: JSON.stringify({ lu: '', rid: '', sakdp: '', sn: '', ts: '' }),
        n: '',
        sD: '',
        sVk: '',
      },
    ]

    invalidQrSchemas.map(schema =>
      expect(isValidQrCode(JSON.stringify(schema))).toBe(false)
    )
  })

  it('should return data for valid schema', () => {
    const validSchema = {
      id: 'yta2odh',
      s: {
        n: 'ent-name',
        dp: {
          d: 'N2Uyi6SVsHZq1VWXuA3EMg',
          k: 'CTfF2sZ5q4oPcBvTP75pgx3WGzYiLST<KEY>i',
          s:
            '/FxHMzX8JaH461k1SI5PfyxF5KwBAe6VlaYBNLI2aSZU3APsiWBfvSC+mxBYJ/zAhX9IUeTEX67fj+FCXZZ2Cg==',
        },
        d: 'F2axeahCaZfbUYUcKefc3j',
        l: 'ent-logo-url',
        v: '74xeXSEac5QTWzQmh84JqzjuXc8yvXLzWKeiqyUnYokx',
      },
      sa: {
        d: 'BDSmVkzxRYGE4HKyMKxd1H',
        v: '6yUatReYWNSUfEtC2ABgRXmmLaxCyQqsjLwv2BomxsxD',
        e: '172.16.58.3:80/agency/msg',
      },
      t: 'there',
    }

    expect(isValidQrCode(JSON.stringify(validSchema))).toMatchSnapshot()
  })
})


<|start_filename|>app/components/image-color-picker/image-color-picker.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { WebView, Platform } from 'react-native'
import RNFetchBlob from 'react-native-fetch-blob'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import ImageResizer from 'react-native-image-resizer'

import { updateConnectionTheme } from '../../store/connections-store'
import type { ImagePickerProps, ImagePickerStates } from './type-color-picker'
import { color, greyRGB } from '../../common/styles/constant'
import { captureError } from '../../services/error/error-handler'
import { canvasHtml } from './canvas-html'
import { getColor } from '../../bridge/react-native-cxs/RNCxs'

const LIGHT_COLOR_LUMINANCE_FACTOR = 200

export function isAllowedColor(color: Array<*>): boolean {
  if (color.length < 3) {
    return false
  }

  const [R, G, B] = color

  // As per luminance https://en.wikipedia.org/wiki/Relative_luminance
  const luminance =
    0.2126 * parseInt(R, 10) +
    0.7152 * parseInt(G, 10) +
    0.0722 * parseInt(B, 10)

  // any luminance below this factor is considered dark color
  return luminance < LIGHT_COLOR_LUMINANCE_FACTOR
}

const imageType = {
  jpg: 'JPEG',
  jpeg: 'JPEG',
  png: 'PNG',
  webp: 'WEBP',
}

export function getImageType(imageUrl: string) {
  const parts = imageUrl.split('.')
  const imageExtension = parts[parts.length - 1].toLowerCase()

  return imageType[imageExtension] || imageType.jpg
}

export class ImageColorPicker extends PureComponent<
  ImagePickerProps,
  ImagePickerStates
> {
  state = {
    imageBlob: '',
  }

  getImage = async (imageUrl: string) => {
    try {
      const localCopy = await RNFetchBlob.config({ fileCache: true }).fetch(
        'GET',
        imageUrl
      )
      const type = getImageType(imageUrl)
      const resizedImage = await ImageResizer.createResizedImage(
        localCopy.path(),
        20,
        20,
        type,
        80
      )
      // if we are on Android, then we have a faster native solution
      // to get color from image, so we will use native for Android
      if (Platform.OS === 'android') {
        const rgb = await getColor(resizedImage.path)
        this.updateTheme([rgb])

        return
      }

      const base64EncodedImage = await RNFetchBlob.fs.readFile(
        resizedImage.path,
        'base64'
      )
      this.setState({ imageBlob: base64EncodedImage })
    } catch (e) {
      captureError(e)
    }
  }

  onBridgeMessage = (message: any) => {
    let messageData = JSON.parse(message.nativeEvent.data)
    if (
      messageData.message === 'rgbValues' &&
      this.state.imageBlob &&
      messageData.payload[0]
    ) {
      this.updateTheme(messageData.payload)
    }
  }

  updateTheme = (payload: Array<Array<string>>) => {
    const firstBestColor = Object.values(payload[0])
    const secondBestColor = payload.length > 1 ? Object.values(payload[1]) : []

    let imageColor = greyRGB.split(', ').map(rgb => parseInt(rgb, 10))
    // add alpha value to rgba
    imageColor.push(1)

    if (isAllowedColor(firstBestColor)) {
      imageColor = firstBestColor
    } else if (isAllowedColor(secondBestColor)) {
      imageColor = secondBestColor
    } else {
      const thirdBestColor =
        payload.length > 2 ? Object.values(payload[2]) : imageColor
      if (isAllowedColor(thirdBestColor)) {
        imageColor = thirdBestColor
      }
    }

    const primaryColor = `rgba(${imageColor.join(',')})`
    const secondaryColor = `rgba(${imageColor.splice(0, 3).join(',')},${
      color.actions.button.secondary.shade
    })`

    this.props.updateConnectionTheme(
      this.props.imageUrl,
      primaryColor,
      secondaryColor
    )
  }

  componentDidMount() {
    this.getImage(this.props.imageUrl)
  }

  render() {
    let { imageType = 'jpeg' } = this.props

    if (!this.state.imageBlob) {
      return null
    }

    return (
      <WebView
        source={{ html: canvasHtml(this.state.imageBlob, imageType) }}
        javaScriptEnabled={true}
        onMessage={this.onBridgeMessage}
      />
    )
  }
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      updateConnectionTheme,
    },
    dispatch
  )

export default connect(null, mapDispatchToProps)(ImageColorPicker)


<|start_filename|>app/components/pin-code/__tests__/pin-code-box.spec.js<|end_filename|>
// @flow
import React from 'react'
import 'react-native'
import renderer from 'react-test-renderer'
import PinCodeBox from '../pin-code-box'
import type { PinCodeBoxProps } from '../type-pin-code-box'

describe('<PinCodeBox />', () => {
  let onPinComplete, wrapper, component

  beforeEach(() => {
    onPinComplete = jest.fn()
    component = renderer.create(<PinCodeBox onPinComplete={onPinComplete} />)
    wrapper = component.toJSON()
  })

  it('should match snapshot', () => {
    expect(wrapper).toMatchSnapshot()
  })

  it('should show two sovrin symbol if two digits are entered', () => {
    const pinBox = component.getInstance()
    // set state to enter two digits
    pinBox.setState({ pin: '12' })
    const expectedTree = component.toJSON()
    expect(expectedTree).toMatchSnapshot()
  })
})


<|start_filename|>e2e/qr-code.spec.js<|end_filename|>
describe('QR Code', () => {
  it('Scan new connection QR Code', async () => {
    // enter Pin Code screen
    // user should redirect to dashboard screen
    // test footer tabs is preset
    // tap on + icon
    // user should redirect to QR Scanner Screen
    // scan connection invitation qr code
    // test Invitation screen shows up
    // verify inviter and invitee avatar is present
    // test Accept button is tap-able
    // verify Continue popup shows up
    // tap on continue
    // verify user is redirected to Dashboard screen
    // verify new Connection is present
    // tap on new Connection bubble
    // verify Connection History popup shows up
    // verify new Connection "Connected" entry is present
    // test delete connection, close popup, and connection logo all are present
    // tap on close button
    // user should come back to dashboard screen
    // test camera should open
    // tap on home icon in footer
    // user should back to dashboard screen
  })

  it('Switch environment', async () => {
    // tap on + icon
    // user should redirect to QR Scanner Screen
    // scan qr code
    // user should see switching environment native alert
    // tap on switch
    // user should redirect back to dashboard screen
  })
})


<|start_filename|>connectMeUITest/src/test/java/App2PositiveTest.java<|end_filename|>

package test.java;

import io.appium.java_client.AppiumDriver;
import org.testng.annotations.*;
import appModules.AppUtlis;
import funcModules.AuthRequestModules;
import funcModules.ConnectionModules;
import funcModules.LockModules;
import pageObjects.ChooseLockPage;
import pageObjects.HomePage;
import utility.*;
@Test
public class App2PositiveTest {

	private AppiumDriver driver;

    static String  ConnectMeLink;
	AppUtlis AppUtlisObj=new AppUtlis();
	LockModules LockModlesObj=new LockModules();
	ConnectionModules ConnectionModulesObj =new ConnectionModules();
	AuthRequestModules AuthRequestModulesObj=new AuthRequestModules();


	@BeforeClass //testng 
	public void BeforeClass() throws Exception {

    	Thread.sleep(20000);
		driver = Setup.ConfigureDriver("App");


	}

	
    @Test (groups = { "Smoke","Regression"})
    public void App1PincodeSetup() throws Exception {
		AppUtlisObj.CheckSkip();
		ChooseLockPage.PinCodeLock_Button(driver).click();
		LockModlesObj.PinCodeSetup(driver);
		AppUtlis.Success=true;		

	}
    @Test (groups = { "Smoke","Regression"})
	public void App2Provisioning() throws Exception {
		
		AppUtlisObj.CheckSkip();
		Thread.sleep(2000);
		ConnectionModulesObj.AppProvisioningRequest("Accept",driver);
		AppUtlis.Success=true;

	}
    @Test (groups = { "Smoke","Regression"})
	public void App3AuthRequestTest() throws Exception {
	
		AppUtlisObj.CheckSkip();
		AuthRequestModulesObj.AuthRequest(driver,"Demo");
		AppUtlis.Success=true;
		
	}
    @Test (groups = { "Smoke","Regression"})
	public void App4PincodeCheck() throws Exception {

		driver.quit();
		driver = Setup.ConfigureDriver("App");
	    AppUtlisObj.enterPincode(driver);
		AppUtlis.Success=true;

	}
	
	
    @AfterClass
	public void afterClass() {
    	
		 driver.removeApp("com.evernym.connectme.callcenter");
		 driver.quit();
		 System.out.println("Cleaning up Completed");

	}
}

<|start_filename|>connectMeUITest/src/utility/PoolUtils.java<|end_filename|>
package utility;

import org.apache.commons.io.FileUtils;
import org.hyperledger.indy.sdk.IndyException;
import org.hyperledger.indy.sdk.pool.Pool;
import org.hyperledger.indy.sdk.pool.PoolJSONParameters;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

public class PoolUtils {

    public static final String DEFAULT_POOL_NAME = "default_pool";


    public static File createGenesisTxnFile(String filename) throws IOException {
        return createGenesisTxnFile(filename, 4);
    }

    public static File createGenesisTxnFile(String filename, int nodesCnt) throws IOException {
        String path = EnvironmentUtils.getTmpPath(filename);
        String testPoolIp = EnvironmentUtils.getTestPoolIP();

        String[] defaultTxns = new String[]{
                String.format("{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"%s\",\"client_port\":9702,\"node_ip\":\"%s\",\"node_port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\",\"identifier\":\"Th7MpTaRZVRYnPiabds81Y\",\"txnId\":\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}", testPoolIp, testPoolIp),
                String.format("{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"%s\",\"client_port\":9704,\"node_ip\":\"%s\",\"node_port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\",\"identifier\":\"EbP4aYNeTHL6q385GuVpRV\",\"txnId\":\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}", testPoolIp, testPoolIp),
                String.format("{\"data\":{\"alias\":\"Node3\",\"client_ip\":\"%s\",\"client_port\":9706,\"node_ip\":\"%s\",\"node_port\":9705,\"services\":[\"VALIDATOR\"]},\"dest\":\"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya\",\"identifier\":\"4cU41vWW82ArfxJxHkzXPG\",\"txnId\":\"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4\",\"type\":\"0\"}", testPoolIp, testPoolIp),
                String.format("{\"data\":{\"alias\":\"Node4\",\"client_ip\":\"%s\",\"client_port\":9708,\"node_ip\":\"%s\",\"node_port\":9707,\"services\":[\"VALIDATOR\"]},\"dest\":\"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA\",\"identifier\":\"TWwCRQRZ2ZHMJFn9TzLp7W\",\"txnId\":\"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008\",\"type\":\"0\"}", testPoolIp, testPoolIp)
        };

        File file = new File(path);

        FileUtils.forceMkdirParent(file);

        FileWriter fw = new FileWriter(file);
        for (int i = 0; i < nodesCnt; i++) {
            fw.write(defaultTxns[i]);
            fw.write("\n");
        }

        fw.close();

        return file;
    }

    public static String createPoolLedgerConfig() throws InterruptedException, ExecutionException, IndyException, IOException {
        return createPoolLedgerConfig(4);
    }

    public static String createPoolLedgerConfig(int nodesCnt) throws InterruptedException, ExecutionException, IndyException, IOException {
        createPoolLedgerConfig(DEFAULT_POOL_NAME, nodesCnt);
        return DEFAULT_POOL_NAME;
    }

    public static void createPoolLedgerConfig(String poolName, int nodesCnt) throws IOException, InterruptedException, java.util.concurrent.ExecutionException, IndyException {
        File genesisTxnFile = createGenesisTxnFile("temp.txn", nodesCnt);
        PoolJSONParameters.CreatePoolLedgerConfigJSONParameter createPoolLedgerConfigJSONParameter
                = new PoolJSONParameters.CreatePoolLedgerConfigJSONParameter(genesisTxnFile.getAbsolutePath());
        Pool.createPoolLedgerConfig(poolName, createPoolLedgerConfigJSONParameter.toJson()).get();
    }

    public static Pool createAndOpenPoolLedger() throws IndyException, InterruptedException, ExecutionException, IOException {
        String poolName = PoolUtils.createPoolLedgerConfig();

        PoolJSONParameters.OpenPoolLedgerJSONParameter config = new PoolJSONParameters.OpenPoolLedgerJSONParameter(true, null, null);
        return Pool.openPoolLedger(poolName, config.toJson()).get();
    }
}


<|start_filename|>app/wallet/wallet-tabs.js<|end_filename|>
// @flow
import React, { PureComponent } from 'react'
import { Dimensions } from 'react-native'
import { TabBarTop, createTabNavigator } from 'react-navigation'
import { CustomView } from '../components'
import {
  RECEIVE_TAB,
  SEND_TAB,
  HISTORY_TAB,
  RECEIVE_TAB_TEST_ID,
  SEND_TAB_TEST_ID,
  HISTORY_TAB_TEST_ID,
} from './wallet-constants'
import { color, font } from '../common/styles/constant'
import { receiveTabRoute, sendTabRoute, historyTabRoute } from '../common'
import WalletSendAmount from './wallet-send-amount'
import styles from './styles'
import WalletTabReceive from './wallet-tab-receive'
import WalletTabHistory from './wallet-tab-history'
import type { WalletTabsProps } from './type-wallet'

const { width } = Dimensions.get('window')

export default class WalletTabs extends PureComponent<WalletTabsProps, void> {
  render() {
    const outerNavigation = {
      navigation: this.props.navigation,
    }
    return <Tabs screenProps={outerNavigation} />
  }
}

const Tabs = createTabNavigator(
  {
    [receiveTabRoute]: {
      screen: WalletTabReceive,
      navigationOptions: {
        tabBarLabel: RECEIVE_TAB,
        tabBarTestIDProps: {
          testID: RECEIVE_TAB_TEST_ID,
          accessible: true,
          accessibleLabel: RECEIVE_TAB_TEST_ID,
          accessibilityLabel: RECEIVE_TAB_TEST_ID,
        },
      },
    },
    [sendTabRoute]: {
      screen: WalletSendAmount,
      navigationOptions: {
        tabBarLabel: SEND_TAB,
        tabBarTestIDProps: {
          testID: SEND_TAB_TEST_ID,
          accessible: true,
          accessibleLabel: SEND_TAB_TEST_ID,
          accessibilityLabel: SEND_TAB_TEST_ID,
        },
      },
    },
    // [historyTabRoute]: {
    //   screen: WalletTabHistory,
    //   navigationOptions: {
    //     tabBarLabel: HISTORY_TAB,
    //     tabBarTestIDProps: {
    //       testID: HISTORY_TAB_TEST_ID,
    //       accessible: true,
    //       accessibleLabel: HISTORY_TAB_TEST_ID,
    //       accessibilityLabel: HISTORY_TAB_TEST_ID,
    //     },
    //   },
    // },
  },
  {
    animationEnabled: true,
    backBehavior: 'none',
    swipeEnabled: true,
    lazy: true,
    initialRouteName: receiveTabRoute,
    order: [receiveTabRoute, sendTabRoute],
    initialLayout: {
      height: 52,
      width,
    },
    tabBarComponent: TabBarTop,
    tabBarPosition: 'top',
    tabBarOptions: {
      allowFontScaling: false,
      activeTintColor: color.actions.font.seventh,
      inactiveTintColor: color.bg.tertiary.font.primary,
      indicatorStyle: {
        backgroundColor: color.actions.font.seventh,
        height: 3,
      },
      style: {
        backgroundColor: color.bg.tertiary.color,
        borderBottomWidth: 1,
        borderBottomColor: color.border.primary,
      },
      labelStyle: {
        fontSize: font.size.S,
        fontFamily: font.family,
        fontWeight: 'bold',
      },
    },
  }
)


<|start_filename|>app/components/user-avatar/type-user-avatar.js<|end_filename|>
// @flow
import * as React from 'react'
import type { Image as RNImagePickerImage } from 'react-native-image-crop-picker'
import type { GenericObject, ImageSource } from '../../common/type-common'

export type UserAvatarProps = {
  userCanChange?: boolean,
  selectUserAvatar: () => void,
  avatarName?: ?ImageSource,
  testID?: string,
  children?: (avatarSource: ImageSource | number) => React.Element<*>,
}


<|start_filename|>app/backup/verify-phrase.js<|end_filename|>
// @flow

import React, { Component } from 'react'
import { Dimensions, Keyboard } from 'react-native'
import { createStackNavigator } from 'react-navigation'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { CustomView, Icon, CustomHeader } from '../components'
import { verifyRecoveryPhraseRoute, exportBackupFileRoute } from '../common'
import { color } from '../common/styles/constant'
import styles from './styles'
import type {
  VerifyRecoveryPhraseProps,
  VerifyRecoveryPhraseState,
} from './type-backup'
import {
  VERIFY_BACK_TEST_ID,
  VERIFY_CLOSE_TEST_ID,
  VERIFY_CONTAINER_TEST_ID,
  VERIFY_INPUT_PLACEHOLDER,
} from './backup-constants'
import { PASSPHRASE_SALT_STORAGE_KEY } from '../common/secure-storage-constants'
import { pinHash as generateKey } from '../lock/pin-hash'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import VerifyPhrase from '../components/backup-restore-passphrase/backup-restore-passphrase'
import { getBackupPassphrase } from '../store/store-selector'
import type { Store } from '../store/type-store'

const transparentBands = require('../images/transparentBands2.png')
const backImage = require('../images/icon_backArrow_white.png')
const closeImage = require('../images/iconClose.png')

export class VerifyRecoveryPhrase extends Component<
  VerifyRecoveryPhraseProps,
  VerifyRecoveryPhraseState
> {
  state = {
    error: false,
  }

  static navigationOptions = ({ navigation: { goBack, navigate, state } }) => ({
    header: (
      <CustomHeader
        backgroundColor={color.bg.twelfth.color}
        largeHeader
        flatHeader
      >
        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => goBack(null)}
            testID={VERIFY_BACK_TEST_ID}
            iconStyle={[styles.headerBackIcon]}
            src={backImage}
          />
        </CustomView>

        <CustomView style={[styles.headerSpacer]}>
          <Icon
            medium
            onPress={() => navigate(state.params.initialRoute)}
            testID={VERIFY_CLOSE_TEST_ID}
            iconStyle={[styles.headerIcon]}
            src={closeImage}
          />
        </CustomView>
      </CustomHeader>
    ),
    gesturesEnabled: false,
  })

  verifyRecoveryPhrase = async (event: any) => {
    const { recoveryPassphrase } = this.props
    const { initialRoute } = this.props.navigation.state.params

    // IMPORTANT: Because of the way that event.nativeEvent works, the nativeEvent property
    // of event will be null if you invoke event.nativeEvent after the await calls below
    const passphraseFromUser = event.nativeEvent.text.trim()
    //////////////////////////////////////////////////////////////////////////////////////////////

    const hashedPassphrase: string | null = await generateKey(
      passphraseFromUser,
      this.props.recoveryPassphrase.salt
    )

    if (recoveryPassphrase.hash === hashedPassphrase) {
      this.props.navigation.navigate(exportBackupFileRoute, {
        initialRoute,
      })
      this.setState({ error: false })
    } else {
      this.setState({ error: true })
    }

    Keyboard.dismiss()
  }

  componentWillUnmount = () => {
    this.setState({ error: false })
  }

  render() {
    // TODO: Add error UI when that is designed
    return (
      <VerifyPhrase
        testID={VERIFY_CONTAINER_TEST_ID}
        placeholder={VERIFY_INPUT_PLACEHOLDER}
        onSubmit={this.verifyRecoveryPhrase}
        errorState={this.state.error}
      />
    )
  }
}

const mapStateToProps = (state: Store) => {
  return {
    recoveryPassphrase: getBackupPassphrase(state),
  }
}

const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch)

export default createStackNavigator({
  [verifyRecoveryPhraseRoute]: {
    screen: connect(mapStateToProps, mapDispatchToProps)(VerifyRecoveryPhrase),
  },
})
