Skip to content

Commit e16208e

Browse files
authored
fix: Improve Perps Chart panning navigation (MetaMask#19345)
## **Description** It was reported that on low-end Android devices, that there was a performance jitteriness with the PerpsChart. This PR aims to address those issues by adding custom configurations for Android, and tweaking the sensitivity of the pan gesture handlers. Additionally, this PR addresses a few other chart related bugs: 1. Yaxis values not showing up for Pers with very small values (like PUMP) 2. Xaxis values not being localized to user's timezone 3. "More" should be selected when a period within the more menu is selected 4. Adds skeleton loader 5. Fix for current price line showing the price of the last visible candle, rather than the current candle price This PR also introduces the `OHLClegend` component which displays the OHLC data for each candle when longpressing/dragging over the candles. When switching candles in this mode, haptics should be executed. You can double tap the chart to exit out of this mode. You can also pull down to refresh the chart to it's default period/zoom of 3min/45 candles. ## **Changelog** CHANGELOG entry: Adds configurations and fixes for candlestick chart UX ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Candlestick chart navigationPerps Scenario: user wants to navigate the chart Given they are on the perps details view When user pans, they navigate the time series When user pinches, they zoom in and out of the time series When a user long presses and drags, they enter into OHLC candle mode, where they see the values of each candle ``` ## **Screenshots/Recordings** High End Android - Samsung Galaxy S23 Ultra https://github.com/user-attachments/assets/d465c9e1-3fc8-462b-a130-14e80f93d299 Low end Android - Pixel 3a https://github.com/user-attachments/assets/02d0a827-17dc-40ed-aca0-633edb42c453 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
1 parent 720d954 commit e16208e

7 files changed

Lines changed: 1110 additions & 517 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Theme } from '../../../../../util/theme/models';
2+
import { StyleSheet } from 'react-native';
3+
4+
export const styleSheet = (params: { theme: Theme }) => {
5+
const { theme } = params;
6+
7+
return StyleSheet.create({
8+
container: {
9+
flexDirection: 'row',
10+
alignItems: 'center',
11+
justifyContent: 'center',
12+
width: '100%',
13+
paddingVertical: 12,
14+
paddingHorizontal: 16,
15+
gap: 4,
16+
},
17+
periodButton: {
18+
paddingHorizontal: 12,
19+
paddingVertical: 6,
20+
borderRadius: 8,
21+
marginHorizontal: 2,
22+
alignItems: 'center',
23+
justifyContent: 'center',
24+
},
25+
periodButtonSelected: {
26+
backgroundColor: theme.colors.background.muted,
27+
},
28+
periodButtonUnselected: {
29+
backgroundColor: theme.colors.background.default,
30+
},
31+
periodButtonPressed: {
32+
opacity: 0.7,
33+
},
34+
periodText: {
35+
fontSize: 14,
36+
fontWeight: '400',
37+
},
38+
periodTextSelected: {
39+
color: theme.colors.text.default,
40+
},
41+
periodTextUnselected: {
42+
color: theme.colors.text.muted,
43+
},
44+
moreButton: {
45+
paddingHorizontal: 12,
46+
paddingVertical: 6,
47+
borderRadius: 8,
48+
marginHorizontal: 2,
49+
alignItems: 'center',
50+
justifyContent: 'center',
51+
},
52+
moreButtonSelected: {
53+
backgroundColor: theme.colors.background.muted,
54+
},
55+
moreButtonUnselected: {
56+
backgroundColor: theme.colors.background.default,
57+
},
58+
moreButtonPressed: {
59+
opacity: 0.7,
60+
},
61+
moreText: {
62+
fontSize: 14,
63+
fontWeight: '400',
64+
},
65+
moreTextSelected: {
66+
color: theme.colors.text.default,
67+
},
68+
moreTextUnselected: {
69+
color: theme.colors.text.muted,
70+
},
71+
});
72+
};

app/components/UI/Perps/components/PerpsCandlePeriodSelector/PerpsCandlePeriodSelector.tsx

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
import React from 'react';
22
import { Pressable } from 'react-native';
3-
import { useTailwind } from '@metamask/design-system-twrnc-preset';
4-
import {
5-
Box,
6-
Text,
7-
TextVariant,
8-
BoxFlexDirection,
9-
BoxAlignItems,
10-
BoxJustifyContent,
11-
} from '@metamask/design-system-react-native';
3+
import { Box, Text, TextVariant } from '@metamask/design-system-react-native';
4+
import { useStyles } from '../../../../../component-library/hooks';
125
import { strings } from '../../../../../../locales/i18n';
136
import { CandlePeriod } from '../../constants/chartConfig';
147
import { getPerpsCandlePeriodSelector } from '../../../../../../e2e/selectors/Perps/Perps.selectors';
8+
import { styleSheet } from './PerpsCandlePeriodSelector.styles';
159

1610
// Default candle periods with preset values
1711
const DEFAULT_CANDLE_PERIODS = [
@@ -34,16 +28,15 @@ const PerpsCandlePeriodSelector: React.FC<PerpsCandlePeriodSelectorProps> = ({
3428
onMorePress,
3529
testID,
3630
}) => {
37-
const tw = useTailwind();
31+
const { styles } = useStyles(styleSheet, {});
32+
33+
// Check if the selected period is in the "More" category (not in default periods)
34+
const isMorePeriodSelected = !DEFAULT_CANDLE_PERIODS.some(
35+
(period) => period.value.toLowerCase() === selectedPeriod.toLowerCase(),
36+
);
3837

3938
return (
40-
<Box
41-
flexDirection={BoxFlexDirection.Row}
42-
alignItems={BoxAlignItems.Center}
43-
justifyContent={BoxJustifyContent.Center}
44-
twClassName="w-full py-3 px-4 gap-1"
45-
testID={testID}
46-
>
39+
<Box style={styles.container} testID={testID}>
4740
{/* Candle Period Buttons */}
4841
{DEFAULT_CANDLE_PERIODS.map((period) => {
4942
const isSelected =
@@ -52,14 +45,13 @@ const PerpsCandlePeriodSelector: React.FC<PerpsCandlePeriodSelectorProps> = ({
5245
return (
5346
<Pressable
5447
key={period.value}
55-
style={({ pressed }) =>
56-
tw.style(
57-
'px-3 py-1.5 rounded-lg mx-0.5 items-center justify-center',
58-
isSelected && 'bg-background-muted',
59-
!isSelected && 'bg-background-default',
60-
pressed && 'opacity-70',
61-
)
62-
}
48+
style={({ pressed }) => [
49+
styles.periodButton,
50+
isSelected
51+
? styles.periodButtonSelected
52+
: styles.periodButtonUnselected,
53+
pressed && styles.periodButtonPressed,
54+
]}
6355
onPress={() => onPeriodChange?.(period.value)}
6456
testID={
6557
testID
@@ -72,7 +64,12 @@ const PerpsCandlePeriodSelector: React.FC<PerpsCandlePeriodSelectorProps> = ({
7264
>
7365
<Text
7466
variant={TextVariant.BodySm}
75-
twClassName={isSelected ? 'text-text-default' : 'text-text-muted'}
67+
style={[
68+
styles.periodText,
69+
isSelected
70+
? styles.periodTextSelected
71+
: styles.periodTextUnselected,
72+
]}
7673
>
7774
{period.label}
7875
</Text>
@@ -82,18 +79,27 @@ const PerpsCandlePeriodSelector: React.FC<PerpsCandlePeriodSelectorProps> = ({
8279

8380
{/* More Button */}
8481
<Pressable
85-
style={({ pressed }) =>
86-
tw.style(
87-
'px-3 py-1.5 rounded-lg mx-0.5 items-center justify-center bg-background-default',
88-
pressed && 'opacity-70',
89-
)
90-
}
82+
style={({ pressed }) => [
83+
styles.moreButton,
84+
isMorePeriodSelected
85+
? styles.moreButtonSelected
86+
: styles.moreButtonUnselected,
87+
pressed && styles.moreButtonPressed,
88+
]}
9189
onPress={onMorePress}
9290
testID={
9391
testID ? getPerpsCandlePeriodSelector.moreButton(testID) : undefined
9492
}
9593
>
96-
<Text variant={TextVariant.BodySm} twClassName="text-text-muted">
94+
<Text
95+
variant={TextVariant.BodySm}
96+
style={[
97+
styles.moreText,
98+
isMorePeriodSelected
99+
? styles.moreTextSelected
100+
: styles.moreTextUnselected,
101+
]}
102+
>
97103
{strings('perps.chart.candle_period_selector.show_more')}
98104
</Text>
99105
</Pressable>

0 commit comments

Comments
 (0)