Skip to content

Commit

Permalink
Merge pull request #983 from tonwhales/release/v2.3.8
Browse files Browse the repository at this point in the history
Release/v2.3.8
  • Loading branch information
vzhovnitsky authored Jul 19, 2024
2 parents 0225321 + 0c63d13 commit 28bec9c
Show file tree
Hide file tree
Showing 108 changed files with 2,348 additions and 971 deletions.
2 changes: 1 addition & 1 deletion VERSION_CODE
Original file line number Diff line number Diff line change
@@ -1 +1 @@
201
202
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
buildToolsVersion = "33.0.0"
minSdkVersion = 24
compileSdkVersion = 34
targetSdkVersion = 33
targetSdkVersion = 34
kotlinVersion = "1.8.10"
ndkVersion = "24.0.8215888"
}
Expand Down
38 changes: 33 additions & 5 deletions app/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ import { LedgerDeviceSelectionFragment } from './fragments/ledger/LedgerDeviceSe
import { LedgerSelectAccountFragment } from './fragments/ledger/LedgerSelectAccountFragment';
import { LedgerAppFragment } from './fragments/ledger/LedgerAppFragment';
import { LedgerSignTransferFragment } from './fragments/ledger/LedgerSignTransferFragment';
import { AppStartAuthFragment } from './fragments/AppStartAuthFragment';
import { AppAuthFragment } from './fragments/AppAuthFragment';
import { BackupIntroFragment } from './fragments/onboarding/BackupIntroFragment';
import { ProductsFragment } from './fragments/wallet/ProductsFragment';
import { PendingTxPreviewFragment } from './fragments/wallet/PendingTxPreviewFragment';
Expand All @@ -94,6 +94,9 @@ import { SearchEngineFragment } from './fragments/SearchEngineFragment';
import { ProductsListFragment } from './fragments/wallet/ProductsListFragment';
import { SortedHintsWatcher } from './components/SortedHintsWatcher';
import { PendingTxsWatcher } from './components/PendingTxsWatcher';
import { TonconnectWatcher } from './components/TonconnectWatcher';
import { SessionWatcher } from './components/SessionWatcher';
import { MandatoryAuthSetupFragment } from './fragments/secure/MandatoryAuthSetupFragment';

const Stack = createNativeStackNavigator();
Stack.Navigator.displayName = 'MainStack';
Expand Down Expand Up @@ -178,6 +181,30 @@ function lockedModalScreen(name: string, component: React.ComponentType<any>, sa
);
}

function fullScreenModal(name: string, component: React.ComponentType<any>, safeArea: EdgeInsets) {
const theme = useTheme();
return (
<Stack.Screen
key={`fullScreenModal-${name}`}
name={name}
component={component}
options={{
presentation: 'fullScreenModal',
headerShown: false,
gestureEnabled: false,
contentStyle: Platform.select({
ios: {
borderTopEndRadius: 20, borderTopStartRadius: 20,
paddingBottom: safeArea.bottom + 16,
backgroundColor: theme.elevation
},
android: { backgroundColor: theme.backgroundPrimary }
})
}}
/>
);
}

function transparentModalScreen(name: string, component: React.ComponentType<any>, safeArea: EdgeInsets) {
const theme = useTheme();
return (
Expand Down Expand Up @@ -293,6 +320,7 @@ const navigation = (safeArea: EdgeInsets) => [
modalScreen('NewAddressFormat', NewAddressFormatFragment, safeArea),
modalScreen('BounceableFormatAbout', BounceableFormatAboutFragment, safeArea),
modalScreen('SearchEngine', SearchEngineFragment, safeArea),
lockedModalScreen('MandatoryAuthSetup', MandatoryAuthSetupFragment, safeArea),

// Holders
genericScreen('HoldersLanding', HoldersLandingFragment, safeArea, true, 0),
Expand All @@ -305,7 +333,8 @@ const navigation = (safeArea: EdgeInsets) => [
transparentModalScreen('Alert', AlertFragment, safeArea),
transparentModalScreen('ScreenCapture', ScreenCaptureFragment, safeArea),
transparentModalScreen('AccountSelector', AccountSelectorFragment, safeArea),
fullScreen('AppStartAuth', AppStartAuthFragment),
fullScreen('AppStartAuth', AppAuthFragment),
fullScreenModal('AppAuth', AppAuthFragment, safeArea),
genericScreen('DAppWebView', DAppWebViewFragment, safeArea, true, 0),
genericScreen('DAppWebViewLocked', DAppWebViewFragment, safeArea, true, 0, { gestureEnabled: false }),
];
Expand Down Expand Up @@ -409,9 +438,6 @@ export const Navigation = memo(() => {
// Watch blocks
useBlocksWatcher();

// Watch for TonConnect requests
useTonconnectWatcher();

// Watch for holders updates
useHoldersWatcher();

Expand Down Expand Up @@ -441,6 +467,8 @@ export const Navigation = memo(() => {
<HintsPrefetcher />
<SortedHintsWatcher owner={selected} />
<PendingTxsWatcher />
<TonconnectWatcher />
<SessionWatcher navRef={navigationRef} />
<Splash hide={hideSplash} />
</View>
);
Expand Down
8 changes: 7 additions & 1 deletion app/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ import { LogBox } from 'react-native';
import { AddressBookLoader } from './engine/AddressBookContext';
import { ThemeProvider } from './engine/ThemeContext';
import { PriceLoader } from './engine/PriceContext';
import { migrateDontShowComments } from './engine/state/spam';
import { AppBlurContextProvider } from './components/AppBlurContext';

const PERSISTANCE_VERSION = '23';
// set default value for spam comments
migrateDontShowComments();

LogBox.ignoreAllLogs()

Expand Down Expand Up @@ -55,7 +59,9 @@ export const Root = memo(() => {
<PriceLoader>
<AddressBookLoader>
<LedgerTransportProvider>
<Navigation />
<AppBlurContextProvider>
<Navigation />
</AppBlurContextProvider>
</LedgerTransportProvider>
</AddressBookLoader>
</PriceLoader>
Expand Down
6 changes: 0 additions & 6 deletions app/analytics/mixpanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { IS_SANDBOX } from '../engine/state/network';
export enum MixpanelEvent {
Reset = 'reset',
Screen = 'screen',
LinkReceived = 'link_received',
NotificationReceived = 'notification_received',
AppOpen = 'app_open',
AppClose = 'app_close',
Holders = 'holders',
Expand All @@ -17,14 +15,10 @@ export enum MixpanelEvent {
HoldersInfoClose = 'holders_info_close',
HoldersEnrollmentClose = 'holders_entrollment_close',
HoldersClose = 'holders_close',
AppInstall = 'app_install',
AppInstallCancel = 'app_install_cancel',
AppUninstall = 'app_uninstall',
Connect = 'connect',
Transfer = 'transfer',
TransferCancel = 'transfer_cancel',
ProductBannerClick = 'product_banner_click',
BrowserBannerShown = 'browser_banner_shown',
BrowserSearch = 'browser_search',
}

Expand Down
58 changes: 58 additions & 0 deletions app/components/AppBlurContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { BlurView } from "expo-blur";
import { createContext, useContext, useRef, useState } from "react";
import { Platform } from "react-native";
import Animated, { Easing, FadeOut } from "react-native-reanimated";

export const AppBlurContext = createContext<{
blur: boolean,
setBlur: (newState: boolean) => void,
getBlur: () => boolean
setAuthInProgress: (newState: boolean) => void
} | null>(null);

export const AppBlurContextProvider = ({ children }: { children: any }) => {
const [blur, setBlurState] = useState(false);
const blurRef = useRef(blur);
const getBlur = () => blurRef.current;

const authInProgressRef = useRef(false);
const setAuthInProgress = (newState: boolean) => authInProgressRef.current = newState;

const setBlur = (newState: boolean) => {
// On iOS we don't want to show blur when auth is in progress (biometrics prompt is shown AppState is 'inactive')
if (newState && authInProgressRef.current && Platform.OS === 'ios') {
return;
}
blurRef.current = newState;
setBlurState(newState);
}

return (
<AppBlurContext.Provider value={{ blur, setBlur, getBlur, setAuthInProgress }}>
{children}
{blur
? (
<Animated.View
exiting={FadeOut.duration(350).easing(Easing.bezier(0.23, 1, 0.32, 1).factory())}
style={{ position: 'absolute', left: 0, right: 0, bottom: 0, top: 0 }}
>
<BlurView
style={{ position: 'absolute', left: 0, right: 0, bottom: 0, top: 0 }}
intensity={30}
experimentalBlurMethod={'dimezisBlurView'} // android only custom blur view impl
/>
</Animated.View>
)
: null
}
</AppBlurContext.Provider>
);
};

export function useAppBlur() {
let res = useContext(AppBlurContext);
if (!res) {
throw Error('No AppBlur found');
}
return res;
}
7 changes: 3 additions & 4 deletions app/components/CheckBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from "react";
import { Pressable, View, Text, StyleProp, ViewStyle } from "react-native";
import CheckMark from '../../assets/ic_check_mark.svg';
import { useTheme } from '../engine/hooks';
import { Typography } from "./styles";

export const CheckBox = React.memo((
{
Expand Down Expand Up @@ -53,12 +54,10 @@ export const CheckBox = React.memo((
}}>
{isChecked && <CheckMark />}
</View>
<Text style={{
fontWeight: '400',
fontSize: 16,
<Text style={[{
marginLeft: 16,
color: theme.textPrimary
}}>
}, Typography.regular15_20]}>
{text}
</Text>
</View>
Expand Down
2 changes: 1 addition & 1 deletion app/components/ConnectedAppButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const ConnectedAppButton = memo(({
padding: 10
}}>
<WImage
heigh={42}
height={42}
width={42}
src={app?.type === 'app-data' ? app?.image?.preview256 : app?.iconUrl}
blurhash={app?.type === 'app-data' ? app?.image?.blurhash : undefined}
Expand Down
2 changes: 1 addition & 1 deletion app/components/ConnectionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const ConnectionButton = memo((
animatedStyle
]}>
<WImage
heigh={56}
height={56}
width={56}
src={app?.type === 'app-data' ? app?.image?.preview256 : app?.iconUrl}
blurhash={app?.type === 'app-data' ? app?.image?.blurhash : undefined}
Expand Down
1 change: 1 addition & 0 deletions app/components/Contacts/ContactEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export const ContactEdit = memo(({
blurOnSubmit={true}
editable={true}
onFocus={() => onFocus(0)}
cursorColor={theme.accent}
/>
</View>
<View style={{
Expand Down
1 change: 1 addition & 0 deletions app/components/Contacts/ContactField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const ContactField = memo(forwardRef((props: {
props.input.onSubmit(props.index);
}
}}
cursorColor={theme.accent}
/>
)

Expand Down
26 changes: 13 additions & 13 deletions app/components/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ImageSourcePropType, Pressable, Text, View, Image, Platform, StyleProp,
import { Switch } from 'react-native-gesture-handler';
import { useTheme } from '../engine/hooks';
import { memo } from 'react';
import { Typography } from './styles';

export const Item = memo((props: { title?: string, hint?: string, onPress?: () => void, backgroundColor?: string, textColor?: string }) => {
const theme = useTheme();
Expand Down Expand Up @@ -51,13 +52,16 @@ export const ItemSwitch = memo((props: {
onPress={() => {
props.onChange(!props.value);
}}
style={{
flexGrow: 1,
alignItems: 'center', justifyContent: 'space-between',
flexDirection: 'row',
padding: 20,
minHeight: 72
}}
style={[
{
flexGrow: 1,
alignItems: 'center', justifyContent: 'space-between',
flexDirection: 'row',
padding: 20,
minHeight: 72
},
Platform.select({ android: { opacity: props.disabled ? 0.8 : 1 } }),
]}
disabled={props.disabled}
>
<View style={{ flexDirection: 'row', flexShrink: 1, alignItems: 'center' }}>
Expand All @@ -69,12 +73,8 @@ export const ItemSwitch = memo((props: {
)}
<Text
style={[
{
fontSize: 17, lineHeight: 24,
fontWeight: '600',
textAlignVertical: 'center',
flexShrink: 1, color: theme.textPrimary, marginRight: 4,
},
{ textAlignVertical: 'center', flexShrink: 1, color: theme.textPrimary, marginRight: 4 },
Typography.semiBold17_24,
props.titleStyle
]}
>
Expand Down
2 changes: 1 addition & 1 deletion app/components/QRCode/QRCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const QRCode = memo((props: {
src={props.icon?.preview256}
blurhash={props.icon?.blurhash}
width={46}
heigh={46}
height={46}
borderRadius={23}
lockLoading
/>}
Expand Down
61 changes: 61 additions & 0 deletions app/components/SessionWatcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { NavigationContainerRefWithCurrent } from "@react-navigation/native";
import { useEffect, useRef } from "react";
import { AppState, Platform } from "react-native";
import { useLockAppWithAuthState } from "../engine/hooks/settings";
import { getLastAuthTimestamp } from "./secure/AuthWalletKeys";
import { useAppBlur } from "./AppBlurContext";

const appLockTimeout = 1000 * 60 * 15; // 15 minutes

export const SessionWatcher = (({ navRef }: { navRef: NavigationContainerRefWithCurrent<any> }) => {
const [locked,] = useLockAppWithAuthState();
const lastStateRef = useRef<string | null>(null);
const { setBlur } = useAppBlur();
useEffect(() => {
if (!locked) {
setBlur(false);
return;
}

const checkAndNavigate = () => {
const lastAuthAt = getLastAuthTimestamp() ?? 0;

if (lastAuthAt + appLockTimeout < Date.now()) {
navRef.navigate('AppAuth');
} else {
setBlur(false);
}
}

const subscription = AppState.addEventListener('change', (newState) => {

if (Platform.OS === 'ios') { // ios goes to inactive on biometric auth
if (newState === 'background') {
setBlur(true);
} else if (newState === 'inactive') {
setBlur(true);
} else if (newState === 'active' && lastStateRef.current === 'background') {
checkAndNavigate();
} else {
setBlur(false);
}
} else {
if (newState === 'background') {
setBlur(true);
} else if (newState === 'active' && lastStateRef.current === 'background') {
checkAndNavigate();
} else {
setBlur(false);
}
}

// update last state
lastStateRef.current = newState;
});

return () => {
subscription.remove();
};
}, [locked]);
return null;
});
7 changes: 7 additions & 0 deletions app/components/TonconnectWatcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useTonconnectWatcher } from "../engine/tonconnectWatcher";

export const TonconnectWatcher = () => {
// Watch for TonConnect requests
useTonconnectWatcher();
return null;
}
Loading

0 comments on commit 28bec9c

Please sign in to comment.