Skip to content

Commit

Permalink
CP-4107 Use Flash or Flat list depending on feature flag (#524)
Browse files Browse the repository at this point in the history
* Fix ZeroStateNoWatchlistFavorites design

* Remove unnecessary SafeAreaProvider

* Select Flash or Flat list depending on feature flag

* Fix merge conflicts

* Remove unused style
  • Loading branch information
neven-s authored Dec 10, 2022
1 parent 82d0c94 commit ef24b41
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 65 deletions.
99 changes: 99 additions & 0 deletions app/components/AvaFlashList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { FlashList } from '@shopify/flash-list'
import React from 'react'
import {
ContentStyle,
ListRenderItem as FlashListRenderItem
} from '@shopify/flash-list/dist/FlashListProps'
import { usePosthogContext } from 'contexts/PosthogContext'
import {
FlatList,
ListRenderItem as FlatListRenderItem,
Platform,
RefreshControlProps
} from 'react-native'

interface AvaFlashListProps<TItem> {
data: ReadonlyArray<TItem> | null | undefined
flashRenderItem: FlashListRenderItem<TItem> | null | undefined
flatRenderItem: FlatListRenderItem<TItem> | null | undefined
ItemSeparatorComponent?: React.ComponentType<unknown> | null | undefined
ListEmptyComponent?:
| React.ComponentType<unknown>
| React.ReactElement
| null
| undefined
refreshing?: boolean | null | undefined
onRefresh?: (() => void) | null | undefined
keyExtractor?: ((item: TItem, index: number) => string) | undefined
extraData?: unknown
contentContainerStyle?: ContentStyle
onEndReached?: (() => void) | null | undefined
onEndReachedThreshold?: number | null | undefined
refreshControl?: React.ReactElement<RefreshControlProps> | undefined
getItemType?: (
item: TItem,
index: number,
extraData?: unknown
) => string | number | undefined
estimatedItemSize?: number | undefined
}

/**
* This component just selects between Flash and Flat list depending on feature flag
*/
const AvaFlashList = <T,>({
data,
flashRenderItem,
flatRenderItem,
ItemSeparatorComponent,
ListEmptyComponent,
refreshing,
onRefresh,
keyExtractor,
extraData,
contentContainerStyle,
onEndReached,
onEndReachedThreshold,
refreshControl,
getItemType,
estimatedItemSize
}: AvaFlashListProps<T>) => {
const { useFlatListAndroid } = usePosthogContext()

return useFlatListAndroid && Platform.OS === 'android' ? (
<FlatList
data={data}
renderItem={flatRenderItem}
ItemSeparatorComponent={ItemSeparatorComponent}
ListEmptyComponent={ListEmptyComponent}
refreshing={refreshing}
onRefresh={onRefresh}
refreshControl={refreshControl}
contentContainerStyle={contentContainerStyle}
keyExtractor={keyExtractor}
indicatorStyle="white"
onEndReached={onEndReached}
extraData={extraData}
/>
) : (
<FlashList
data={data}
renderItem={flashRenderItem}
ItemSeparatorComponent={ItemSeparatorComponent}
ListEmptyComponent={ListEmptyComponent}
refreshing={refreshing}
onRefresh={onRefresh}
refreshControl={refreshControl}
contentContainerStyle={contentContainerStyle}
keyExtractor={keyExtractor}
indicatorStyle="white"
getItemType={getItemType}
onEndReached={onEndReached}
onEndReachedThreshold={onEndReachedThreshold}
estimatedItemSize={estimatedItemSize}
extraData={extraData}
/>
)
}

export default AvaFlashList
23 changes: 17 additions & 6 deletions app/components/ZeroState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,27 @@ function ZeroStateNoTransactions() {
return <ZeroStateBase title={title} message={message} />
}

function ZeroStateNoWatchlistFavorites() {
function ZeroStateNoWatchlistFavorites({
exploreAllTokens
}: {
exploreAllTokens?: () => void
}) {
const title = 'No Favorites'
const message = 'Click the star icon on any token to mark it as a favorite.'

return (
<ZeroStateBase
title={title}
message={message}
image={<StarSVG size={60} />}
/>
<View>
<ZeroStateBase
title={title}
message={message}
image={<StarSVG size={60} />}
button={
<AvaButton.SecondaryLarge onPress={exploreAllTokens}>
Explore all tokens
</AvaButton.SecondaryLarge>
}
/>
</View>
)
}

Expand Down
15 changes: 11 additions & 4 deletions app/contexts/PosthogContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export interface PosthogContextState {
sendNftBlockediOS: boolean
sendNftBlockedAndroid: boolean
sentrySampleRate: number
useFlatListAndroid: boolean
}

const DefaultFeatureFlagConfig = {
Expand All @@ -83,7 +84,8 @@ const DefaultFeatureFlagConfig = {
[FeatureGates.SEND]: true,
[FeatureGates.SEND_NFT_IOS]: true,
[FeatureGates.SEND_NFT_ANDROID]: true,
[FeatureVars.SENTRY_SAMPLE_RATE]: '10' // 10% of events/errors
[FeatureVars.SENTRY_SAMPLE_RATE]: '10', // 10% of events/errors
[FeatureGates.USE_FLATLIST_ANDROID]: false
}

const ONE_MINUTE = 60 * 1000
Expand Down Expand Up @@ -116,6 +118,8 @@ const processFlags = (flags: FeatureFlags) => {
const sentrySampleRate =
parseInt((flags[FeatureVars.SENTRY_SAMPLE_RATE] as string) ?? '0') / 100

const useFlatListAndroid = !!flags[FeatureGates.USE_FLATLIST_ANDROID]

return {
swapBlocked,
bridgeBlocked,
Expand All @@ -125,7 +129,8 @@ const processFlags = (flags: FeatureFlags) => {
sendNftBlockediOS,
sendNftBlockedAndroid,
eventsBlocked,
sentrySampleRate
sentrySampleRate,
useFlatListAndroid
}
}

Expand Down Expand Up @@ -159,7 +164,8 @@ export const PosthogContextProvider = ({
sendNftBlockediOS,
sendNftBlockedAndroid,
eventsBlocked,
sentrySampleRate
sentrySampleRate,
useFlatListAndroid
} = useMemo(() => processFlags(flags), [flags])

useEffect(
Expand Down Expand Up @@ -284,7 +290,8 @@ export const PosthogContextProvider = ({
sendBlocked,
sendNftBlockediOS,
sendNftBlockedAndroid,
sentrySampleRate
sentrySampleRate,
useFlatListAndroid
}}>
{children}
</PosthogContext.Provider>
Expand Down
3 changes: 2 additions & 1 deletion app/contexts/PosthogContext/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export enum FeatureGates {
BRIDGE_ETH = 'bridge-feature-eth',
SEND = 'send-feature',
SEND_NFT_IOS = 'send-nft-ios-feature',
SEND_NFT_ANDROID = 'send-nft-android-feature'
SEND_NFT_ANDROID = 'send-nft-android-feature',
USE_FLATLIST_ANDROID = 'use-flatlist-android'
}

export enum FeatureVars {
Expand Down
26 changes: 20 additions & 6 deletions app/screens/shared/ActivityList/Transactions.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import React, { useMemo } from 'react'
import { Animated, View, StyleSheet } from 'react-native'
import { FlashList, ListRenderItemInfo } from '@shopify/flash-list'
import {
Animated,
View,
StyleSheet,
ListRenderItemInfo as FlatListRenderItemInfo
} from 'react-native'
import { ListRenderItemInfo as FlashListRenderItemInfo } from '@shopify/flash-list'
import AvaText from 'components/AvaText'
import ActivityListItem from 'screens/activity/ActivityListItem'
import {
Expand All @@ -20,6 +25,7 @@ import ZeroState from 'components/ZeroState'
import { BridgeTransaction } from '@avalabs/bridge-sdk'
import { UI, useIsUIDisabled } from 'hooks/useIsUIDisabled'
import { RefreshControl } from 'components/RefreshControl'
import AvaFlashList from 'components/AvaFlashList'

const yesterday = endOfYesterday()
const today = endOfToday()
Expand Down Expand Up @@ -125,7 +131,15 @@ const Transactions = ({
)
}

const renderTransaction = ({ item }: ListRenderItemInfo<Item>) => {
const flatRenderItem = ({ item }: FlatListRenderItemInfo<Item>) => {
return renderListItem(item)
}

const flashRenderItem = ({ item }: FlashListRenderItemInfo<Item>) => {
return renderListItem(item)
}

function renderListItem(item: Item) {
// render section header
if (typeof item === 'string') {
return renderSectionHeader(item)
Expand Down Expand Up @@ -173,10 +187,10 @@ const Transactions = ({

const renderTransactions = () => {
return (
<FlashList
indicatorStyle="white"
<AvaFlashList
data={combinedData}
renderItem={renderTransaction}
flashRenderItem={flashRenderItem}
flatRenderItem={flatRenderItem}
keyExtractor={keyExtractor}
contentContainerStyle={styles.contentContainer}
onEndReached={onEndReached}
Expand Down
65 changes: 26 additions & 39 deletions app/screens/watchlist/WatchlistView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { Dispatch, useEffect, useMemo, useState } from 'react'
import { StyleSheet, View } from 'react-native'
import { useApplicationContext } from 'contexts/ApplicationContext'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import Dropdown from 'components/Dropdown'
import AvaText from 'components/AvaText'
import {
Expand All @@ -21,7 +20,6 @@ import watchlistService from 'services/watchlist/WatchlistService'
import { useDispatch } from 'react-redux'
import { WatchListLoader } from 'screens/watchlist/components/WatchListLoader'
import isEmpty from 'lodash.isempty'
import AvaButton from 'components/AvaButton'
import { selectSelectedCurrency } from 'store/settings/currency'
import { ChartData } from 'services/token/types'
import { WatchlistFilter } from './types'
Expand Down Expand Up @@ -169,48 +167,37 @@ const WatchlistView: React.FC<Props> = ({
)

return (
<SafeAreaProvider style={styles.container}>
<>
<View style={styles.filterContainer}>
<Dropdown
alignment={'flex-start'}
width={140}
data={filterPriceOptions}
selectedIndex={selectedPriceFilter}
onItemSelected={setFilterBy}
selectionRenderItem={renderPriceFilterSelection}
<>
<View style={styles.filterContainer}>
<Dropdown
alignment={'flex-start'}
width={140}
data={filterPriceOptions}
selectedIndex={selectedPriceFilter}
onItemSelected={setFilterBy}
selectionRenderItem={renderPriceFilterSelection}
/>
</View>
{showLoader ? (
<WatchListLoader />
) : (
<>
<WatchList
tokens={sortedTokens}
charts={charts}
prices={prices}
filterBy={filterBy}
isShowingFavorites={showFavorites}
isSearching={isSearching}
onExploreAllTokens={() => onTabIndexChanged?.(1)}
/>
</View>
{showLoader ? (
<WatchListLoader />
) : (
<>
<WatchList
tokens={sortedTokens}
charts={charts}
prices={prices}
filterBy={filterBy}
isShowingFavorites={showFavorites}
isSearching={isSearching}
/>
{showFavorites && sortedTokens.length === 0 && (
<AvaButton.SecondaryLarge
onPress={() => onTabIndexChanged?.(1)}
style={{ marginBottom: 128, marginHorizontal: 16 }}>
Explore all tokens
</AvaButton.SecondaryLarge>
)}
</>
)}
</>
</SafeAreaProvider>
</>
)}
</>
)
}

const styles = StyleSheet.create({
container: {
flex: 1
},
filterContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
Expand Down
Loading

0 comments on commit ef24b41

Please sign in to comment.