Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CP-9314: Set up dynamic app switch #2016

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions packages/core-mobile/AppSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useState, useCallback, useMemo } from 'react'
import { Alert, View, PanResponder } from 'react-native'
import OldApp from 'ContextApp'
import NewApp from 'new/ContextApp'
import { commonStorage } from 'utils/mmkv'
import { StorageKey } from 'resources/Constants'
import DeviceInfoService from 'services/deviceInfo/DeviceInfoService'
import DevDebuggingConfig from 'utils/debugging/DevDebuggingConfig'

const bundleId = DeviceInfoService.getBundleId()
const isInternalBuild =
bundleId === 'org.avalabs.avaxwallet.internal' ||
bundleId === 'com.avaxwallet.internal'

export const AppSwitcher = (): React.JSX.Element => {
const [isNewApp, setIsNewApp] = useState(
commonStorage.getBoolean(StorageKey.K2_ALPINE)
)

const switchApp = useCallback(() => {
const newValue = !isNewApp
commonStorage.set(StorageKey.K2_ALPINE, newValue)
setIsNewApp(newValue)
}, [isNewApp, setIsNewApp])

const panResponder = useMemo(
() =>
PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
if (gestureState.numberActiveTouches === 2) {
Alert.alert('Switch App Experience?', '', [
{
text: 'Cancel',
style: 'cancel'
},
{ text: 'OK', onPress: switchApp }
])
}

return true
}
}),
[switchApp]
)

// only allow switching to new app on internal builds
if (!isInternalBuild) return <OldApp />

return (
<View style={{ flex: 1 }} {...panResponder.panHandlers}>
{DevDebuggingConfig.K2_ALPINE || isNewApp ? <NewApp /> : <OldApp />}
</View>
)
}
32 changes: 2 additions & 30 deletions packages/core-mobile/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,15 @@
import React, { useState } from 'react'
import {
KeyboardAvoidingView,
LogBox,
Platform,
SafeAreaView,
UIManager
} from 'react-native'
import { KeyboardAvoidingView, Platform, SafeAreaView } from 'react-native'
import RootScreenStack from 'navigation/RootScreenStack'
import { NavigationContainer } from '@react-navigation/native'
import { useApplicationContext } from 'contexts/ApplicationContext'
import useDevDebugging from 'utils/debugging/DevDebugging'
import 'utils/debugging/wdyr'
import { navigationRef } from 'utils/Navigation'
import SentryService from 'services/sentry/SentryService'
import DataDogService from 'services/datadog/DataDogService'
import Logger, { LogLevel } from 'utils/Logger'

Logger.setLevel(__DEV__ ? LogLevel.TRACE : LogLevel.ERROR)

LogBox.ignoreLogs([
'Require cycle:',
"Can't perform",
'new',
'Non-serializable'
])

SentryService.init()

Platform.OS === 'android' &&
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(false)
import Logger from 'utils/Logger'

function App(): JSX.Element {
const { configure } = useDevDebugging()
const isProduction = process.env.NODE_ENV === 'production'
if (!isProduction) {
configure()
}

const context = useApplicationContext()
const [backgroundStyle] = useState(context.appBackgroundStyle)

Expand Down
17 changes: 5 additions & 12 deletions packages/core-mobile/app/ContextApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import Toast from 'react-native-toast-notifications'
import JailMonkey from 'jail-monkey'
import { RootSiblingParent } from 'react-native-root-siblings'
import { K2ThemeProvider } from '@avalabs/k2-mobile'
import { K2AlpineThemeProvider } from '@avalabs/k2-alpine'
import JailbrokenWarning from 'screens/onboarding/JailbrokenWarning'
import { PosthogContextProvider } from 'contexts/PosthogContext'
import { StatusBar, View } from 'react-native'
Expand All @@ -23,10 +22,6 @@ import SentryService from 'services/sentry/SentryService'
import CoreSplash from 'assets/icons/core_splash.svg'
import { useMigrateFromAsyncStorage } from 'hooks/useMigrateFromAsyncStorage'

if (__DEV__) {
require('../ReactotronConfig')
}

function setToast(toast: Toast): void {
global.toast = toast
}
Expand All @@ -38,13 +33,11 @@ const ContextProviders: FC<PropsWithChildren> = ({ children }) => (
<EncryptedStoreProvider>
<ReactQueryProvider>
<PosthogContextProvider>
<K2AlpineThemeProvider colorScheme={'dark'}>
<K2ThemeProvider>
<ApplicationContextProvider>
<DeeplinkContextProvider>{children}</DeeplinkContextProvider>
</ApplicationContextProvider>
</K2ThemeProvider>
</K2AlpineThemeProvider>
<K2ThemeProvider>
<ApplicationContextProvider>
<DeeplinkContextProvider>{children}</DeeplinkContextProvider>
</ApplicationContextProvider>
</K2ThemeProvider>
</PosthogContextProvider>
</ReactQueryProvider>
</EncryptedStoreProvider>
Expand Down
5 changes: 3 additions & 2 deletions packages/core-mobile/app/contexts/PosthogContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from 'store/posthog/slice'
import AnalyticsService from 'services/analytics/AnalyticsService'
import { commonStorage } from 'utils/mmkv'
import { StorageKey } from 'resources/Constants'

export const PosthogContext = createContext<PosthogContextState>(
{} as PosthogContextState
Expand Down Expand Up @@ -62,8 +63,8 @@ export const PosthogContextProvider = ({

const { timeoutPassed } = useAppBackgroundTracker({
timeoutMs: 30 * 60 * 1000,
getTime: () => commonStorage.getString('POSTHOG_SUSPENDED'),
setTime: time => commonStorage.set('POSTHOG_SUSPENDED', time)
getTime: () => commonStorage.getString(StorageKey.POSTHOG_SUSPENDED),
setTime: time => commonStorage.set(StorageKey.POSTHOG_SUSPENDED, time)
})

const [analyticsConsent, setAnalyticsConsent] = useState<
Expand Down
8 changes: 8 additions & 0 deletions packages/core-mobile/app/new/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ExpoRoot } from 'expo-router'
import React from 'react'

export const App = () => {
const ctx = require.context('./routes')

return <ExpoRoot context={ctx} />
}
77 changes: 77 additions & 0 deletions packages/core-mobile/app/new/ContextApp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Context wrapper for App
**/
import React, { FC, PropsWithChildren, useEffect, useState } from 'react'
import * as Sentry from '@sentry/react-native'
import Toast from 'react-native-toast-notifications'
import JailMonkey from 'jail-monkey'
import { RootSiblingParent } from 'react-native-root-siblings'
import JailbrokenWarning from 'screens/onboarding/JailbrokenWarning'
import { PosthogContextProvider } from 'contexts/PosthogContext'
import { StatusBar } from 'react-native'
import { EncryptedStoreProvider } from 'contexts/EncryptedStoreProvider'
import { TopLevelErrorFallback } from 'components/TopLevelErrorFallback'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { ReactQueryProvider } from 'contexts/ReactQueryProvider'
import SentryService from 'services/sentry/SentryService'
import { App } from './App'

function setToast(toast: Toast): void {
global.toast = toast
}

/**
* Aggregate all the top-level context providers for better readability.
*/
// TODO: add DeeplinkContextProvider
const ContextProviders: FC<PropsWithChildren> = ({ children }) => (
<EncryptedStoreProvider>
<ReactQueryProvider>
<PosthogContextProvider>{children}</PosthogContextProvider>
</ReactQueryProvider>
</EncryptedStoreProvider>
)

const ContextApp = (): JSX.Element => {
// TODO: convert TopLevelErrorFallback to new design
return (
<Sentry.ErrorBoundary fallback={<TopLevelErrorFallback />}>
<StatusBar barStyle={'light-content'} backgroundColor="black" />
<ContextProviders>
<JailBrokenCheck>
<GestureHandlerRootView style={{ flex: 1 }}>
<RootSiblingParent>
<App />
</RootSiblingParent>
</GestureHandlerRootView>
</JailBrokenCheck>
<Toast
ref={ref => {
ref && setToast(ref)
}}
offsetTop={30}
normalColor={'00FFFFFF'}
/>
</ContextProviders>
</Sentry.ErrorBoundary>
)
}

const JailBrokenCheck: FC<PropsWithChildren> = ({ children }) => {
const [showJailBroken, setShowJailBroken] = useState(false)

useEffect(() => {
if (!__DEV__ && JailMonkey.isJailBroken()) {
setShowJailBroken(true)
}
}, [])

if (showJailBroken) {
// TODO: convert JailbrokenWarning to new design
return <JailbrokenWarning onOK={() => setShowJailBroken(false)} />
}

return <>{children}</>
}

export default SentryService.isAvailable ? Sentry.wrap(ContextApp) : ContextApp
7 changes: 6 additions & 1 deletion packages/core-mobile/app/resources/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,12 @@ export enum COLORS_NIGHT {
blueLight = '#6AC0FF'
}

export const SECURE_ACCESS_SET = 'secureAccessSet'
export enum StorageKey {
SECURE_ACCESS_SET = 'secureAccessSet',
POSTHOG_SUSPENDED = 'POSTHOG_SUSPENDED',
HAS_MIGRATED_FROM_ASYNC_STORAGE = 'hasMigratedFromAsyncStorage',
K2_ALPINE = 'k2Alpine'
}

export const CORE_UNIVERSAL_LINK_HOSTS = ['core.app', 'test.core.app']

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { View } from 'react-native'
import { useApplicationContext } from 'contexts/ApplicationContext'
import AvaListItem from 'components/AvaListItem'
import BiometricsSDK from 'utils/BiometricsSDK'
import { SECURE_ACCESS_SET } from 'resources/Constants'
import { StorageKey } from 'resources/Constants'
import Switch from 'components/Switch'
import { useDispatch, useSelector } from 'react-redux'
import {
Expand Down Expand Up @@ -42,7 +42,7 @@ function SecurityPrivacy({
})
.catch(Logger.error)

const type = commonStorage.getString(SECURE_ACCESS_SET)
const type = commonStorage.getString(StorageKey.SECURE_ACCESS_SET)
if (type) {
setIsBiometricSwitchEnabled(type === 'BIO')
} else {
Expand All @@ -55,7 +55,7 @@ function SecurityPrivacy({
if (value) {
onTurnOnBiometrics()
} else {
commonStorage.set(SECURE_ACCESS_SET, 'PIN')
commonStorage.set(StorageKey.SECURE_ACCESS_SET, 'PIN')
}
}

Expand Down
Loading
Loading