Skip to content

Commit

Permalink
Merge pull request #343 from alephium/post-beta
Browse files Browse the repository at this point in the history
Post beta fixes
  • Loading branch information
nop33 authored Oct 20, 2023
2 parents 2be3609 + ae7ba07 commit b074ac3
Show file tree
Hide file tree
Showing 16 changed files with 120 additions and 54 deletions.
27 changes: 24 additions & 3 deletions src/components/AddressBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@ import styled, { useTheme } from 'styled-components/native'

import { fastestSpringConfiguration } from '~/animations/reanimated/reanimatedAnimations'
import AddressBadge from '~/components/AddressBadge'
import AppText from '~/components/AppText'
import AssetAmountWithLogo from '~/components/AssetAmountWithLogo'
import Checkmark from '~/components/Checkmark'
import { useAppSelector } from '~/hooks/redux'
import { makeSelectAddressesKnownFungibleTokens, makeSelectAddressesNFTs } from '~/store/addressesSlice'
import { BORDER_RADIUS, VERTICAL_GAP } from '~/style/globalStyle'
import {
makeSelectAddressesKnownFungibleTokens,
makeSelectAddressesNFTs,
selectAddressByHash
} from '~/store/addressesSlice'
import { BORDER_RADIUS, DEFAULT_MARGIN, VERTICAL_GAP } from '~/style/globalStyle'
import { AddressHash } from '~/types/addresses'
import { ImpactStyle, vibrate } from '~/utils/haptics'

Expand All @@ -39,6 +44,7 @@ interface AddressBoxProps extends PressableProps {
const AnimatedPressable = Animated.createAnimatedComponent(Pressable)

const AddressBox = ({ addressHash, isSelected, onPress, ...props }: AddressBoxProps) => {
const address = useAppSelector((s) => selectAddressByHash(s, addressHash))
const selectAddressesKnownFungibleTokens = useMemo(makeSelectAddressesKnownFungibleTokens, [])
const knownFungibleTokens = useAppSelector((s) => selectAddressesKnownFungibleTokens(s, addressHash))
const selectAddressesNFTs = useMemo(makeSelectAddressesNFTs, [])
Expand All @@ -59,7 +65,12 @@ const AddressBox = ({ addressHash, isSelected, onPress, ...props }: AddressBoxPr
<AddressBoxStyled {...props} onPress={handlePress} style={[boxAnimatedStyle, props.style]}>
<AddressBoxTop>
<AddressBadgeStyled onPress={handlePress} addressHash={addressHash} textStyle={{ fontSize: 18 }} />
{isSelected && <Checkmark />}
<Group>
<AppText color="tertiary" size={14}>
group {address?.group}
</AppText>
{isSelected && <Checkmark />}
</Group>
</AddressBoxTop>
<AddressBoxBottom>
<AssetsRow>
Expand Down Expand Up @@ -99,6 +110,8 @@ const AddressBoxTop = styled.View`
background-color: ${({ theme }) => theme.bg.highlight};
border-top-right-radius: 6px;
border-top-left-radius: 6px;
gap: ${DEFAULT_MARGIN}px;
align-items: center;
`

const AddressBoxBottom = styled.View`
Expand All @@ -110,10 +123,18 @@ const AddressBoxBottom = styled.View`

const AddressBadgeStyled = styled(AddressBadge)`
max-width: 80%;
flex-shrink: 1;
`

const AssetsRow = styled.View`
flex-direction: row;
flex-wrap: wrap;
gap: 12px;
`

const Group = styled.View`
flex-direction: row;
gap: ${DEFAULT_MARGIN}px;
flex-shrink: 0;
align-items: center;
`
3 changes: 1 addition & 2 deletions src/components/AuthenticationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ You should have received a copy of the GNU Lesser General Public License
along with the library. If not, see <http://www.gnu.org/licenses/>.
*/

import { getHumanReadableError, walletOpenAsyncUnsafe } from '@alephium/sdk'
import { walletOpenAsyncUnsafe } from '@alephium/sdk'
import { useCallback, useEffect, useState } from 'react'
import { Alert } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
Expand Down Expand Up @@ -85,7 +85,6 @@ const AuthenticationModal = ({

if (!error.message?.includes('User canceled')) {
console.error(e)
Alert.alert(getHumanReadableError(e, 'Could not authenticate'))
}

onClose && onClose()
Expand Down
21 changes: 16 additions & 5 deletions src/components/HistoricWorthChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { DEFAULT_MARGIN } from '~/style/globalStyle'
import { Address } from '~/types/addresses'
import { ChartLength, chartLengths, DataPoint, LatestAmountPerAddress } from '~/types/charts'
import { Currency } from '~/types/settings'
import { CHART_DATE_FORMAT } from '~/utils/constants'

interface HistoricWorthChart {
latestWorth: number
Expand Down Expand Up @@ -87,8 +88,10 @@ const HistoricWorthChart = ({ latestWorth, currency, onWorthInBeginningOfChartCh
}, [firstItem?.worth, onWorthInBeginningOfChartChange])

useEffect(() => {
setChartData(isDataAvailable ? trimInitialZeroDataPoints(computeChartDataPoints(alphPriceHistory, addresses)) : [])
}, [addresses, alphPriceHistory, isDataAvailable])
setChartData(
isDataAvailable ? trimInitialZeroDataPoints(computeChartDataPoints(alphPriceHistory, addresses, latestWorth)) : []
)
}, [addresses, alphPriceHistory, isDataAvailable, latestWorth])

const worthHasGoneUp = firstItem?.worth ? firstItem.worth < latestWorth : undefined

Expand All @@ -104,7 +107,7 @@ const HistoricWorthChart = ({ latestWorth, currency, onWorthInBeginningOfChartCh
}))
: undefined

if (!data || data.length < 2 || (data.length === 2 && data[0].x === data[1].x)) return null
if (!data || data.length < 2) return null

return (
<Animated.View style={[style, animatedStyle]}>
Expand Down Expand Up @@ -166,10 +169,14 @@ const getFilteredChartData = (chartData: DataPoint[], startingDate: string) => {

const trimInitialZeroDataPoints = (data: DataPoint[]) => data.slice(data.findIndex((point) => point.worth !== 0))

const computeChartDataPoints = (alphPriceHistory: HistoricalPriceResult[], addresses: Address[]): DataPoint[] => {
const computeChartDataPoints = (
alphPriceHistory: HistoricalPriceResult[],
addresses: Address[],
latestWorth: number
): DataPoint[] => {
const addressesLatestAmount: LatestAmountPerAddress = {}

return alphPriceHistory.map(({ date, price }) => {
const dataPoints = alphPriceHistory.map(({ date, price }) => {
let totalAmountPerDate = BigInt(0)

addresses.forEach(({ hash, balanceHistory }) => {
Expand All @@ -189,6 +196,10 @@ const computeChartDataPoints = (alphPriceHistory: HistoricalPriceResult[], addre
worth: price * parseFloat(toHumanReadableAmount(totalAmountPerDate))
}
})

if (latestWorth !== undefined) dataPoints.push({ date: dayjs().format(CHART_DATE_FORMAT), worth: latestWorth })

return dataPoints
}

const DeltaAndChartLengths = styled(Animated.View)`
Expand Down
24 changes: 13 additions & 11 deletions src/navigation/RootStackNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { CardStyleInterpolators, createStackNavigator } from '@react-navigation/
import { isEnrolledAsync } from 'expo-local-authentication'
import * as SplashScreen from 'expo-splash-screen'
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react'
import { Alert, AppState, AppStateStatus } from 'react-native'
import { AppState, AppStateStatus } from 'react-native'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { Host } from 'react-native-portalize'
import { useTheme } from 'styled-components/native'
Expand Down Expand Up @@ -68,17 +68,20 @@ import { routeChanged } from '~/store/appSlice'
import { appBecameInactive } from '~/store/appSlice'
import { biometricsToggled } from '~/store/settingsSlice'
import { walletUnlocked } from '~/store/wallet/walletSlice'
import { isNavStateRestorable, rootStackNavigationRef } from '~/utils/navigation'
import { resetNavigationState, setNavigationState } from '~/utils/navigation'
import { showToast } from '~/utils/layout'
import { isNavStateRestorable, resetNavigation, restoreNavigation, rootStackNavigationRef } from '~/utils/navigation'

const RootStack = createStackNavigator<RootStackParamList>()

SplashScreen.preventAutoHideAsync()

const RootStackNavigation = () => {
const theme = useTheme()
const mnemonic = useAppSelector((s) => s.wallet.mnemonic)
const dispatch = useAppDispatch()

const isAuthenticated = !!mnemonic

const handleStateChange = (state?: NavigationState) => {
if (state && isNavStateRestorable(state)) dispatch(routeChanged(state))
}
Expand All @@ -105,8 +108,9 @@ const RootStackNavigation = () => {
<AnalyticsProvider>
<WalletConnectContextProvider>
<RootStack.Navigator initialRouteName="LandingScreen">
{/* Sub-navigation with custom header */}
<RootStack.Group screenOptions={{ headerTransparent: true }}>
{/* Sub-navigation with custom header. Showing the header only when authenticated fixes the
reanimated bug while still allowing animated transitions between screens */}
<RootStack.Group screenOptions={{ headerTransparent: true, headerShown: isAuthenticated }}>
<RootStack.Screen
name="SendNavigation"
component={SendNavigation}
Expand Down Expand Up @@ -231,7 +235,7 @@ const AppUnlockHandler = ({ children }: { children: ReactNode }) => {
if (!wallet) {
if (lastNavigationState) {
// When we are at the wallet creation flow we want to reset to the last screen
setNavigationState(lastNavigationState)
restoreNavigation(navigation, lastNavigationState)
SplashScreen.hideAsync()
} else {
navigation.navigate('LandingScreen')
Expand All @@ -243,7 +247,7 @@ const AppUnlockHandler = ({ children }: { children: ReactNode }) => {
addressesStatus === 'uninitialized' ? await deriveWalletStoredAddresses(wallet) : []
dispatch(walletUnlocked({ wallet, addressesToInitialize, contacts: metadata?.contacts ?? [] }))

lastNavigationState ? setNavigationState(lastNavigationState) : resetNavigationState()
lastNavigationState ? restoreNavigation(navigation, lastNavigationState) : resetNavigation(navigation)
SplashScreen.hideAsync()
} else {
navigation.navigate('LoginWithPinScreen')
Expand All @@ -255,9 +259,7 @@ const AppUnlockHandler = ({ children }: { children: ReactNode }) => {
const error = e as { message?: string }

if (error.message?.includes('User canceled')) {
Alert.alert('Authentication required', 'Please authenticate to unlock your wallet.', [
{ text: 'Try again', onPress: unlockApp }
])
showToast('Authentication required. Exit the app and try again.')
} else {
console.error(e)
}
Expand All @@ -268,7 +270,7 @@ const AppUnlockHandler = ({ children }: { children: ReactNode }) => {
const handleAppStateChange = (nextAppState: AppStateStatus) => {
if (nextAppState === 'background' && walletMnemonic && !isCameraOpen) {
loadBiometricsSettings().then((isBioEnabled) =>
navigation.navigate(isBioEnabled ? 'LandingScreen' : 'LoginWithPinScreen')
resetNavigation(navigation, isBioEnabled ? 'LandingScreen' : 'LoginWithPinScreen')
)
dispatch(appBecameInactive())
// The following is needed when the switch between background/active happens so fast that the component didn't
Expand Down
4 changes: 2 additions & 2 deletions src/screens/AddressDiscoveryScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
import { VERTICAL_GAP } from '~/style/globalStyle'
import { AddressHash } from '~/types/addresses'
import { getRandomLabelColor } from '~/utils/colors'
import { resetNavigationState } from '~/utils/navigation'
import { resetNavigation } from '~/utils/navigation'

interface ScreenProps extends StackScreenProps<RootStackParamList, 'AddressDiscoveryScreen'>, ScrollScreenProps {}

Expand All @@ -70,7 +70,7 @@ const AddressDiscoveryScreen = ({ navigation, route: { params }, ...props }: Scr
const stopScan = () => dispatch(addressDiscoveryStopped())

const continueToNextScreen = () =>
isImporting ? resetNavigationState('NewWalletSuccessScreen') : navigation.goBack()
isImporting ? resetNavigation(navigation, 'NewWalletSuccessScreen') : navigation.goBack()

const importAddresses = async () => {
setImportLoading(true)
Expand Down
4 changes: 2 additions & 2 deletions src/screens/BackupMnemonic/VerificationSuccessScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { ScreenSection } from '~/components/layout/Screen'
import ScrollScreen, { ScrollScreenProps } from '~/components/layout/ScrollScreen'
import CenteredInstructions from '~/components/text/CenteredInstructions'
import { BackupMnemonicNavigationParamList } from '~/navigation/BackupMnemonicNavigation'
import { resetNavigationState } from '~/utils/navigation'
import { resetNavigation } from '~/utils/navigation'

interface VerificationSuccessScreenProps
extends StackScreenProps<BackupMnemonicNavigationParamList, 'VerificationSuccessScreen'>,
Expand All @@ -46,7 +46,7 @@ const VerificationSuccessScreen = ({ navigation, ...props }: VerificationSuccess
/>
</ScreenSection>
<ScreenSection>
<Button variant="highlight" title="Return to my wallet" onPress={() => resetNavigationState()} />
<Button variant="highlight" title="Return to my wallet" onPress={() => resetNavigation(navigation.getParent())} />
</ScreenSection>
</ScrollScreen>
)
Expand Down
8 changes: 4 additions & 4 deletions src/screens/LoginWithPinScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ import RootStackParamList from '~/navigation/rootStackRoutes'
import { deriveWalletStoredAddresses, getWalletMetadata } from '~/persistent-storage/wallet'
import { walletUnlocked } from '~/store/wallet/walletSlice'
import { WalletState } from '~/types/wallet'
import { resetNavigationState, setNavigationState } from '~/utils/navigation'
import { resetNavigation, restoreNavigation } from '~/utils/navigation'

interface LoginWithPinScreenProps extends StackScreenProps<RootStackParamList, 'LoginWithPinScreen'>, ScreenProps {}

const LoginWithPinScreen = (props: LoginWithPinScreenProps) => {
const LoginWithPinScreen = ({ navigation, ...props }: LoginWithPinScreenProps) => {
const dispatch = useAppDispatch()
const addressesStatus = useAppSelector((s) => s.addresses.status)
const lastNavigationState = useAppSelector((s) => s.app.lastNavigationState)
Expand All @@ -51,11 +51,11 @@ const LoginWithPinScreen = (props: LoginWithPinScreenProps) => {
const metadata = await getWalletMetadata()

dispatch(walletUnlocked({ wallet, addressesToInitialize, pin, contacts: metadata?.contacts ?? [] }))
lastNavigationState ? setNavigationState(lastNavigationState) : resetNavigationState()
lastNavigationState ? restoreNavigation(navigation, lastNavigationState) : resetNavigation(navigation)

posthog?.capture('Unlocked wallet')
},
[addressesStatus, dispatch, lastNavigationState, posthog]
[addressesStatus, dispatch, lastNavigationState, navigation, posthog]
)

return (
Expand Down
5 changes: 4 additions & 1 deletion src/screens/Settings/SettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
walletConnectToggled
} from '~/store/settingsSlice'
import { VERTICAL_GAP } from '~/style/globalStyle'
import { resetNavigation } from '~/utils/navigation'

interface ScreenProps extends StackScreenProps<RootStackParamList, 'SettingsScreen'>, ScrollScreenProps {}

Expand Down Expand Up @@ -307,7 +308,9 @@ const SettingsScreen = ({ navigation, ...props }: ScreenProps) => {
isOpen={isWalletDeleteModalOpen}
onClose={() => setIsWalletDeleteModalOpen(false)}
maximisedContent={Platform.OS === 'ios'}
Content={(props) => <WalletDeleteModal {...props} />}
Content={(props) => (
<WalletDeleteModal onDelete={() => resetNavigation(navigation, 'LandingScreen')} {...props} />
)}
/>
</Portal>
</>
Expand Down
9 changes: 6 additions & 3 deletions src/screens/Settings/WalletDeleteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ import SpinnerModal from '~/components/SpinnerModal'
import { useAppDispatch, useAppSelector } from '~/hooks/redux'
import { deleteWallet } from '~/persistent-storage/wallet'
import { walletDeleted } from '~/store/wallet/walletActions'
import { resetNavigationState } from '~/utils/navigation'

const WalletDeleteModal = (props: ModalContentProps) => {
interface WalletDeleteModalProps extends ModalContentProps {
onDelete: () => void
}

const WalletDeleteModal = ({ onDelete, ...props }: WalletDeleteModalProps) => {
const dispatch = useAppDispatch()
const posthog = usePostHog()
const walletName = useAppSelector((s) => s.wallet.name)
Expand All @@ -47,7 +50,7 @@ const WalletDeleteModal = (props: ModalContentProps) => {

setIsLoading(false)

resetNavigationState('LandingScreen')
onDelete()

dispatch(walletDeleted())
posthog?.capture('Deleted wallet')
Expand Down
10 changes: 7 additions & 3 deletions src/screens/new-wallet/AddBiometricsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import RootStackParamList from '~/navigation/rootStackRoutes'
import { enableBiometrics } from '~/persistent-storage/wallet'
import { selectAddressIds } from '~/store/addressesSlice'
import { biometricsToggled } from '~/store/settingsSlice'
import { resetNavigationState } from '~/utils/navigation'
import { resetNavigation } from '~/utils/navigation'

interface AddBiometricsScreenProps extends StackScreenProps<RootStackParamList, 'AddBiometricsScreen'>, ScreenProps {}

Expand Down Expand Up @@ -63,7 +63,10 @@ const AddBiometricsScreen = ({ navigation, route: { params }, ...props }: AddBio

posthog?.capture('Activated biometrics from wallet creation flow')

resetNavigationState(skipAddressDiscovery ? 'NewWalletSuccessScreen' : 'ImportWalletAddressDiscoveryScreen')
resetNavigation(
navigation,
skipAddressDiscovery ? 'NewWalletSuccessScreen' : 'ImportWalletAddressDiscoveryScreen'
)
} finally {
setLoading(false)
}
Expand All @@ -72,7 +75,8 @@ const AddBiometricsScreen = ({ navigation, route: { params }, ...props }: AddBio
const handleLaterPress = () => {
posthog?.capture('Skipped biometrics activation from wallet creation flow')

resetNavigationState(
resetNavigation(
navigation,
method === 'import' && !skipAddressDiscovery ? 'ImportWalletAddressDiscoveryScreen' : 'NewWalletSuccessScreen'
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/screens/new-wallet/DecryptScannedMnemonicScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { importAddresses } from '~/store/addresses/addressesStorageUtils'
import { newWalletImportedWithMetadata } from '~/store/wallet/walletActions'
import { WalletImportData } from '~/types/wallet'
import { pbkdf2 } from '~/utils/crypto'
import { resetNavigationState } from '~/utils/navigation'
import { resetNavigation } from '~/utils/navigation'

interface DecryptScannedMnemonicScreenProps
extends StackScreenProps<RootStackParamList, 'DecryptScannedMnemonicScreen'>,
Expand Down Expand Up @@ -102,7 +102,7 @@ const DecryptScannedMnemonicScreen = ({ navigation }: DecryptScannedMnemonicScre

if (contacts.length > 0) await importContacts(contacts)

resetNavigationState(deviceHasBiometricsData ? 'AddBiometricsScreen' : 'NewWalletSuccessScreen')
resetNavigation(navigation, deviceHasBiometricsData ? 'AddBiometricsScreen' : 'NewWalletSuccessScreen')
} catch (e) {
setError('Could not decrypt wallet with the given password.')
} finally {
Expand Down
Loading

0 comments on commit b074ac3

Please sign in to comment.