Skip to content

Commit

Permalink
Add ability to refresh tokens in case of uncaught balance changes (#447)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChewingGlass authored Sep 6, 2023
1 parent d8d5e48 commit 05e9c58
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 5 deletions.
6 changes: 3 additions & 3 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -861,17 +861,17 @@ SPEC CHECKSUMS:
FBLazyVector: f1897022b53abf1469d6ad692ee2c69f57d967f3
FBReactNativeSpec: 627fd07f1b9d498c9fa572e76d7f1a6b1ee9a444
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
glog: 791fe035093b84822da7f0870421a25839ca7870
helium-react-native-sdk: 32c0a7e3abc733a7f3d291013b2db31475fc6980
hermes-engine: 0784cadad14b011580615c496f77e0ae112eed75
hermes-engine: 7a53ccac09146018a08239c5425625fdb79a6162
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
MapboxCommon: fdf7fd31c90b7b607cd9c63e37797f023c01d860
MapboxCoreMaps: 24270c7c6b8cb71819fc2f3c549db9620ee4d019
MapboxMaps: cb76511b98d3b95c74b0771ed105bc69f30ace6b
MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6
MultiplatformBleAdapter: 5a6a897b006764392f9cef785e4360f54fb9477d
OneSignalXCFramework: 81ceac017a290f23793443323090cfbe888f74ea
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCT-Folly: 85766c3226c7ec638f05ad7cb3cf6a268d6c4241
RCTRequired: bd6045fbd511da5efe6db89eecb21e4e36bd7cbf
RCTTypeSafety: c06d9f906faa69dd1c88223204c3a24767725fd8
React: b9ea33557ef1372af247f95d110fbdea114ed3b2
Expand Down
26 changes: 26 additions & 0 deletions src/features/account/AccountManageTokenListScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ import { usePublicKey } from '@hooks/usePublicKey'
import CheckBox from '@react-native-community/checkbox'
import { useNavigation } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
import { useAccountStorage } from '@storage/AccountStorageProvider'
import { useVisibleTokens } from '@storage/TokensProvider'
import { useColors, useHitSlop } from '@theme/themeHooks'
import { useBalance } from '@utils/Balance'
import { humanReadable } from '@utils/solanaUtils'
import BN from 'bn.js'
import React, { memo, useCallback, useMemo } from 'react'
import { useAsyncCallback } from 'react-async-hook'
import { RefreshControl } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import { Edge } from 'react-native-safe-area-context'
import { useSolana } from '../../solana/SolanaProvider'
import { syncTokenAccounts } from '../../store/slices/balancesSlice'
import { useAppDispatch } from '../../store/store'
import { HomeNavigationProp } from '../home/homeTypes'
import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
import { getSortValue } from './AccountTokenList'
Expand Down Expand Up @@ -120,7 +126,18 @@ const AccountManageTokenListScreen: React.FC = () => {
return getSortValue(b) - getSortValue(a)
})
}, [tokenAccounts])
const dispatch = useAppDispatch()
const { anchorProvider, cluster } = useSolana()
const { currentAccount } = useAccountStorage()
const colors = useColors()

const { loading: refetchingTokens, execute: refetchTokens } =
useAsyncCallback(async () => {
if (!anchorProvider || !currentAccount || !cluster) return
await dispatch(
syncTokenAccounts({ cluster, acct: currentAccount, anchorProvider }),
)
})
const renderItem = useCallback(
// eslint-disable-next-line react/no-unused-prop-types
({ index, item: token }: { index: number; item: string }) => {
Expand Down Expand Up @@ -163,6 +180,15 @@ const AccountManageTokenListScreen: React.FC = () => {
</Box>

<FlatList
refreshControl={
<RefreshControl
enabled
refreshing={refetchingTokens}
onRefresh={refetchTokens}
title=""
tintColor={colors.primaryText}
/>
}
data={mints}
renderItem={renderItem}
keyExtractor={keyExtractor}
Expand Down
64 changes: 62 additions & 2 deletions src/features/account/AccountTokenList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,24 @@ import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { BottomSheetFlatList } from '@gorhom/bottom-sheet'
import { BottomSheetFlatListProps } from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheetScrollable/types'
import { useAccountFetchCache } from '@helium/account-fetch-cache-hooks'
import { DC_MINT, HNT_MINT, IOT_MINT, MOBILE_MINT } from '@helium/spl-utils'
import { useNavigation } from '@react-navigation/native'
import { getAssociatedTokenAddressSync } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
import { useVisibleTokens, DEFAULT_TOKENS } from '@storage/TokensProvider'
import { useAccountStorage } from '@storage/AccountStorageProvider'
import { DEFAULT_TOKENS, useVisibleTokens } from '@storage/TokensProvider'
import { useColors } from '@theme/themeHooks'
import { useBalance } from '@utils/Balance'
import { times } from 'lodash'
import React, { useCallback, useMemo } from 'react'
import React, { useCallback, useEffect, useMemo } from 'react'
import { useAsyncCallback } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { AppState, RefreshControl } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSolana } from '../../solana/SolanaProvider'
import { syncTokenAccounts } from '../../store/slices/balancesSlice'
import { useAppDispatch } from '../../store/store'
import { HomeNavigationProp } from '../home/homeTypes'
import TokenListItem, { TokenSkeleton } from './TokenListItem'

Expand All @@ -33,6 +42,46 @@ const AccountTokenList = ({ onLayout }: Props) => {
const navigation = useNavigation<HomeNavigationProp>()
const { t } = useTranslation()
const { visibleTokens } = useVisibleTokens()
const { currentAccount } = useAccountStorage()
const dispatch = useAppDispatch()
const { anchorProvider, cluster } = useSolana()
const colors = useColors()
const cache = useAccountFetchCache()

const { loading: refetchingTokens, execute: refetchTokens } =
useAsyncCallback(async () => {
if (!anchorProvider || !currentAccount || !cluster) return
await dispatch(
syncTokenAccounts({ cluster, acct: currentAccount, anchorProvider }),
)
await Promise.all(
[...visibleTokens].map((mintStr) => {
// Trigger a refetch on all visible token accounts
return cache.search(
getAssociatedTokenAddressSync(
new PublicKey(mintStr),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
new PublicKey(currentAccount!.solanaAddress!),
),
undefined,
false,
true,
)
}),
)
})

// Trigger refresh when the app comes into the foreground from the background
useEffect(() => {
const listener = AppState.addEventListener('change', (state) => {
if (state === 'active') {
refetchTokens()
}
})
return () => {
listener.remove()
}
}, [refetchTokens])

const onManageTokenList = useCallback(() => {
navigation.navigate('AccountManageTokenListScreen')
Expand Down Expand Up @@ -107,6 +156,17 @@ const AccountTokenList = ({ onLayout }: Props) => {
onLayout={onLayout}
data={mints}
numColumns={2}
refreshControl={
<RefreshControl
enabled
refreshing={refetchingTokens}
onRefresh={refetchTokens}
title=""
tintColor={colors.primaryText}
/>
}
refreshing={refetchingTokens}
onRefresh={refetchTokens}
columnWrapperStyle={{
flexDirection: 'column',
}}
Expand Down

0 comments on commit 05e9c58

Please sign in to comment.