Skip to content

Commit bb2cb1d

Browse files
authored
Merge pull request #5454 from EdgeApp/william/wallet-search-performance
Wallet search performance
2 parents 131ff77 + 89e8021 commit bb2cb1d

File tree

7 files changed

+136
-208
lines changed

7 files changed

+136
-208
lines changed

src/__tests__/components/TransactionListTop.test.tsx

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,7 @@ describe('TransactionListTop', () => {
6666
ENV.ENABLE_VISA_PROGRAM = false
6767
const renderer = TestRenderer.create(
6868
<FakeProviders initialState={fakeState}>
69-
<TransactionListTop
70-
isEmpty={false}
71-
navigation={fakeCompositeNavigation}
72-
searching={false}
73-
tokenId={null}
74-
wallet={fakeWallet}
75-
onSearchingChange={() => undefined}
76-
onSearchTextChange={() => undefined}
77-
isLightAccount={false}
78-
/>
69+
<TransactionListTop isEmpty={false} navigation={fakeCompositeNavigation} searching={false} tokenId={null} wallet={fakeWallet} isLightAccount={false} />
7970
</FakeProviders>
8071
)
8172

@@ -87,16 +78,7 @@ describe('TransactionListTop', () => {
8778
ENV.ENABLE_VISA_PROGRAM = true
8879
const renderer = TestRenderer.create(
8980
<FakeProviders initialState={fakeState}>
90-
<TransactionListTop
91-
isEmpty={false}
92-
navigation={fakeCompositeNavigation}
93-
searching={false}
94-
tokenId={null}
95-
wallet={fakeWallet}
96-
onSearchingChange={() => undefined}
97-
onSearchTextChange={() => undefined}
98-
isLightAccount={false}
99-
/>
81+
<TransactionListTop isEmpty={false} navigation={fakeCompositeNavigation} searching={false} tokenId={null} wallet={fakeWallet} isLightAccount={false} />
10082
</FakeProviders>
10183
)
10284

src/components/Main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ import { SweepPrivateKeyCompletionScene as SweepPrivateKeyCompletionSceneCompone
126126
import { SweepPrivateKeyProcessingScene as SweepPrivateKeyProcessingSceneComponent } from './scenes/SweepPrivateKeyProcessingScene'
127127
import { SweepPrivateKeySelectCryptoScene as SweepPrivateKeySelectCryptoSceneComponent } from './scenes/SweepPrivateKeySelectCryptoScene'
128128
import { TransactionDetailsScene as TransactionDetailsSceneComponent } from './scenes/TransactionDetailsScene'
129-
import { TransactionList as TransactionListComponent } from './scenes/TransactionListScene2'
129+
import { TransactionList as TransactionListComponent } from './scenes/TransactionListScene'
130130
import { TransactionsExportScene as TransactionsExportSceneComponent } from './scenes/TransactionsExportScene'
131131
import { UpgradeUsernameScene as UpgradeUsernameSceneComponent } from './scenes/UpgradeUsernameScreen'
132132
import { WalletDetails as WalletDetailsComponent } from './scenes/WalletDetailsScene'

src/components/charts/SwipeChart.tsx

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { CursorProps, GradientProps, SlideAreaChart, ToolTipProps, ToolTipTextRenderersInput, YAxisProps } from '@connectedcars/react-native-slide-charts'
22
import { asArray, asEither, asNumber, asObject, asString, asTuple } from 'cleaners'
33
import * as React from 'react'
4-
import { LayoutChangeEvent, Platform, View } from 'react-native'
4+
import { Dimensions, LayoutChangeEvent, Platform, View } from 'react-native'
55
import { cacheStyles } from 'react-native-patina'
66
import Animated, { Easing, SharedValue, useAnimatedProps, useAnimatedStyle, useSharedValue, withDelay, withRepeat, withTiming } from 'react-native-reanimated'
77
import Svg, { Circle, CircleProps, LinearGradient, Stop } from 'react-native-svg'
@@ -14,7 +14,6 @@ import { formatFiatString } from '../../hooks/useFiatText'
1414
import { useHandler } from '../../hooks/useHandler'
1515
import { formatDate } from '../../locales/intl'
1616
import { lstrings } from '../../locales/strings'
17-
import { fixSides, mapSides, sidesToMargin } from '../../util/sides'
1817
import { MinimalButton } from '../buttons/MinimalButton'
1918
import { FillLoader } from '../progress-indicators/FillLoader'
2019
import { showWarning } from '../services/AirshipInstance'
@@ -30,12 +29,6 @@ interface Props {
3029
assetId: string
3130
currencyCode: string
3231
fiatCurrencyCode: string
33-
/**
34-
* Typically we don't want to add custom margins to break consistent design,
35-
* but for this particular component, we sometimes want to adjust how the line
36-
* chart itself, minus the timeframe buttons, is laid out.
37-
*/
38-
marginRem?: number[] | number
3932
}
4033
interface ChartDataPoint {
4134
x: Date
@@ -137,9 +130,7 @@ const reduceChartData = (chartData: ChartDataPoint[], timespan: Timespan): Chart
137130
const SwipeChartComponent = (params: Props) => {
138131
const theme = useTheme()
139132
const styles = getStyles(theme)
140-
const { assetId, marginRem, currencyCode, fiatCurrencyCode } = params
141-
142-
const customMargin = sidesToMargin(mapSides(fixSides(marginRem, 0), theme.rem))
133+
const { assetId, currencyCode, fiatCurrencyCode } = params
143134

144135
// #region Chart setup
145136

@@ -156,9 +147,6 @@ const SwipeChartComponent = (params: Props) => {
156147
const [queryFromTimeOffset, setQueryFromTimeOffset] = React.useState(UNIX_SECONDS_MONTH_OFFSET)
157148
const [isLoading, setIsLoading] = React.useState(false)
158149

159-
const chartWidth = React.useRef(0)
160-
const chartHeight = React.useRef(0)
161-
162150
const fiatSymbol = React.useMemo(() => getFiatSymbol(fiatCurrencyCode), [fiatCurrencyCode])
163151

164152
// Min/Max Price Calcs
@@ -167,9 +155,7 @@ const SwipeChartComponent = (params: Props) => {
167155
const maxPrice = Math.max(...prices)
168156

169157
const sMinPriceLabelX = useSharedValue(0)
170-
const sMinPriceLabelY = useSharedValue(0)
171158
const sMaxPriceLabelX = useSharedValue(0)
172-
const sMaxPriceLabelY = useSharedValue(0)
173159

174160
const sMinPriceString = useSharedValue(``)
175161
const sMaxPriceString = useSharedValue(``)
@@ -179,6 +165,14 @@ const SwipeChartComponent = (params: Props) => {
179165
const minPriceDataPoint = React.useMemo(() => chartData.find(point => point.y === minPrice), [chartData, minPrice])
180166
const maxPriceDataPoint = React.useMemo(() => chartData.find(point => point.y === maxPrice), [chartData, maxPrice])
181167

168+
// The chart component defaults to the phone width.
169+
// To fit the chart into its parent view,
170+
// we measure the parent and pass that width in.
171+
// The chart will freeze the whole app if the width is too narrow,
172+
// so start with the window width:
173+
const [chartWidth, setChartWidth] = React.useState(Dimensions.get('window').width)
174+
const chartHeight = theme.rem(CHART_HEIGHT_REM)
175+
182176
// Fetch/cache chart data, set shared animation transition values
183177
useAsyncEffect(
184178
async () => {
@@ -303,14 +297,15 @@ const SwipeChartComponent = (params: Props) => {
303297

304298
// A delayed fadein for the max/min labels, to ensure the labels don't get
305299
// rendered before the price line. Also hidden when gesture is active
300+
const minPriceLabelY = Platform.OS === 'ios' ? chartHeight - theme.rem(2.5) : chartHeight - theme.rem(2.75)
306301
const aMinLabelStyle = useAnimatedStyle(() => ({
307302
left: sMinPriceLabelX.value,
308-
top: sMinPriceLabelY.value,
303+
top: minPriceLabelY,
309304
opacity: sMinMaxOpacity.value * (1 - sCursorOpacity.value)
310305
}))
311306
const aMaxLabelStyle = useAnimatedStyle(() => ({
312307
left: sMaxPriceLabelX.value,
313-
top: sMaxPriceLabelY.value,
308+
top: 0,
314309
opacity: sMinMaxOpacity.value * (1 - sCursorOpacity.value)
315310
}))
316311

@@ -356,6 +351,10 @@ const SwipeChartComponent = (params: Props) => {
356351

357352
// #region Handlers
358353

354+
const handleLayout = useHandler((event: LayoutChangeEvent) => {
355+
setChartWidth(event.nativeEvent.layout.width)
356+
})
357+
359358
const handleGradient = useHandler((props: GradientProps) => {
360359
return (
361360
<LinearGradient x1="50%" y1="0%" x2="50%" y2="100%" {...props}>
@@ -365,16 +364,6 @@ const SwipeChartComponent = (params: Props) => {
365364
)
366365
})
367366

368-
/**
369-
* Handle the layout event on the chart, set the min price label Y value.
370-
*/
371-
const handleSetChartDimensions = useHandler((event: LayoutChangeEvent) => {
372-
const { width, height } = event.nativeEvent.layout
373-
chartWidth.current = width
374-
chartHeight.current = height
375-
sMinPriceLabelY.value = Platform.OS === 'ios' ? chartHeight.current - theme.rem(2.5) : chartHeight.current - theme.rem(2.75)
376-
})
377-
378367
/**
379368
* Handle the tap and hold gesture event on the chart.
380369
*
@@ -436,7 +425,7 @@ const SwipeChartComponent = (params: Props) => {
436425
const setMinMaxLabelsX = (xSharedVal: SharedValue<number>, priceDatapoint?: ChartDataPoint) => (layoutChangeEvent: LayoutChangeEvent) => {
437426
if (layoutChangeEvent != null && layoutChangeEvent.nativeEvent != null && minPriceDataPoint != null && chartData != null && priceDatapoint != null) {
438427
const xIndex = chartData.indexOf(priceDatapoint)
439-
const xPosition = (chartWidth.current / (chartData.length - 1)) * xIndex
428+
const xPosition = (chartWidth / (chartData.length - 1)) * xIndex
440429
const labelWidth = layoutChangeEvent.nativeEvent.layout.width
441430
const isRightJustified = xPosition > chartData.length / 2
442431

@@ -536,7 +525,7 @@ const SwipeChartComponent = (params: Props) => {
536525

537526
// Main Render
538527
return (
539-
<View style={styles.container}>
528+
<View style={styles.container} onLayout={handleLayout}>
540529
{/* Timespan control bar */}
541530
<View style={styles.controlBar}>
542531
{renderTimespanButton(lstrings.coin_rank_hour, 'hour', handleSetTimespanH)}
@@ -548,22 +537,24 @@ const SwipeChartComponent = (params: Props) => {
548537

549538
{/* Chart */}
550539
{chartData.length === 0 || isLoading ? (
551-
<View style={styles.loader} onLayout={handleSetChartDimensions}>
540+
<View style={styles.loader}>
552541
<FillLoader />
553542
</View>
554543
) : (
555544
<View>
556545
<SlideAreaChart
557546
data={chartData}
558547
animated
559-
height={theme.rem(11)}
548+
height={theme.rem(CHART_HEIGHT_REM)}
549+
width={chartWidth}
560550
chartLineColor={theme.iconTappable}
561551
chartLineWidth={1.5}
562552
renderFillGradient={handleGradient}
553+
// Create space for our min label:
563554
paddingBottom={theme.rem(1.5)}
564-
// Price line has weird uneven margins when unadjusted
565-
paddingRight={theme.rem(2)}
566-
paddingLeft={theme.rem(-0.5)}
555+
// The default padding is 8, which we don't want:
556+
paddingRight={0}
557+
paddingLeft={0}
567558
yRange={chartYRange}
568559
xScale="linear"
569560
yAxisProps={Y_AXIS_PROPS}
@@ -577,7 +568,7 @@ const SwipeChartComponent = (params: Props) => {
577568
toolTipProps={tooltipProps}
578569
// #endregion ToolTip
579570

580-
style={[styles.baseChart, customMargin]}
571+
style={styles.baseChart}
581572
/>
582573

583574
{/* Min/Max price labels */}
@@ -613,6 +604,8 @@ const SwipeChartComponent = (params: Props) => {
613604
// #endregion Components
614605
}
615606

607+
const CHART_HEIGHT_REM = 11
608+
616609
const getStyles = cacheStyles((theme: Theme) => {
617610
return {
618611
baseChart: {
@@ -625,7 +618,10 @@ const getStyles = cacheStyles((theme: Theme) => {
625618
position: 'absolute'
626619
},
627620
container: {
628-
margin: theme.rem(0.5)
621+
margin: theme.rem(0.5),
622+
// The chart starts off at the phone width,
623+
// so hide the extra until we can adjust the layout:
624+
overflow: 'hidden'
629625
},
630626
controlBar: {
631627
justifyContent: 'center',
@@ -637,7 +633,7 @@ const getStyles = cacheStyles((theme: Theme) => {
637633
},
638634
loader: {
639635
marginTop: theme.rem(0),
640-
height: theme.rem(11)
636+
height: theme.rem(CHART_HEIGHT_REM)
641637
},
642638
label: {
643639
color: theme.primaryText,

src/components/scenes/TransactionListScene2.tsx renamed to src/components/scenes/TransactionListScene.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface TransactionListParams {
3030
walletName: string
3131
tokenId: EdgeTokenId
3232
countryCode?: string
33+
searchText?: string
3334
}
3435

3536
type ListItem = EdgeTransaction | string | null
@@ -39,6 +40,7 @@ interface Props extends WalletsTabSceneProps<'transactionList'> {
3940

4041
function TransactionListComponent(props: Props) {
4142
const { navigation, route, wallet } = props
43+
const { searchText: initSearchText } = route.params
4244
const theme = useTheme()
4345
const styles = getStyles(theme)
4446
const dispatch = useDispatch()
@@ -48,8 +50,8 @@ function TransactionListComponent(props: Props) {
4850

4951
// State:
5052
const flashListRef = React.useRef<Animated.FlatList<ListItem> | null>(null)
51-
const [isSearching, setIsSearching] = React.useState(false)
52-
const [searchText, setSearchText] = React.useState('')
53+
const [isSearching, setIsSearching] = React.useState(initSearchText != null)
54+
const [searchText, setSearchText] = React.useState(initSearchText ?? '')
5355
const [footerHeight, setFooterHeight] = React.useState<number | undefined>()
5456

5557
// Watchers:

0 commit comments

Comments
 (0)