Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add max swappable amount on balance badge tap #5947

Merged
merged 10 commits into from
Jul 25, 2024
Merged
38 changes: 32 additions & 6 deletions src/__swaps__/screens/Swap/components/SwapInputAsset.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import MaskedView from '@react-native-masked-view/masked-view';
import React from 'react';
import { StatusBar, StyleSheet } from 'react-native';
import Animated, { useDerivedValue } from 'react-native-reanimated';
import Animated, { runOnJS, useDerivedValue, withSpring } from 'react-native-reanimated';
import { ScreenCornerRadius } from 'react-native-screen-corner-radius';

import { AnimatedText, Box, Column, Columns, Stack, useColorMode } from '@/design-system';
Expand All @@ -12,11 +12,14 @@ import { GestureHandlerV1Button } from '@/__swaps__/screens/Swap/components/Gest
import { SwapActionButton } from '@/__swaps__/screens/Swap/components/SwapActionButton';
import { SwapInput } from '@/__swaps__/screens/Swap/components/SwapInput';
import { TokenList } from '@/__swaps__/screens/Swap/components/TokenList/TokenList';
import { BASE_INPUT_WIDTH, INPUT_INNER_WIDTH, INPUT_PADDING, THICK_BORDER_WIDTH } from '@/__swaps__/screens/Swap/constants';
import { BASE_INPUT_WIDTH, INPUT_INNER_WIDTH, INPUT_PADDING, SLIDER_WIDTH, THICK_BORDER_WIDTH } from '@/__swaps__/screens/Swap/constants';

import { useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider';
import { IS_ANDROID, IS_IOS } from '@/env';
import * as i18n from '@/languages';
import { triggerHapticFeedback } from '@/screens/points/constants';
import { SPRING_CONFIGS } from '@/components/animations/animationConfigs';
import { equalWorklet } from '@/__swaps__/safe-math/SafeMath';

import Clipboard from '@react-native-clipboard/clipboard';
import { AnimatedSwapCoinIcon } from './AnimatedSwapCoinIcon';
Expand Down Expand Up @@ -83,8 +86,6 @@ function SwapInputAmount() {
}

function SwapInputIcon() {
const { internalSelectedInputAsset } = useSwapContext();

return (
<Box paddingRight="10px">
<AnimatedSwapCoinIcon assetType={'input'} large />
Expand All @@ -93,7 +94,7 @@ function SwapInputIcon() {
}

function InputAssetBalanceBadge() {
const { internalSelectedInputAsset } = useSwapContext();
const { internalSelectedInputAsset, SwapInputController, sliderXPosition } = useSwapContext();

const label = useDerivedValue(() => {
const asset = internalSelectedInputAsset.value;
Expand All @@ -103,7 +104,32 @@ function InputAssetBalanceBadge() {
return asset ? balance : TOKEN_TO_SWAP_LABEL;
});

return <BalanceBadge label={label} />;
const onSetMaxBalance = () => {
'worklet';

const asset = internalSelectedInputAsset.value;
if (!asset?.maxSwappableAmount || equalWorklet(asset.maxSwappableAmount, 0)) return;

const isAlreadyMax = SwapInputController.percentageToSwap.value === 1;
if (isAlreadyMax) {
runOnJS(triggerHapticFeedback)('impactMedium');
return;
}

SwapInputController.inputMethod.value = 'slider';
SwapInputController.quoteFetchingInterval.stop();
sliderXPosition.value = withSpring(SLIDER_WIDTH, SPRING_CONFIGS.snappySpringConfig, isFinished => {
if (isFinished) {
runOnJS(SwapInputController.onChangedPercentage)(1);
}
});
};

return (
<GestureHandlerV1Button onPressWorklet={onSetMaxBalance}>
<BalanceBadge label={label} />
</GestureHandlerV1Button>
);
}

export function SwapInputAsset() {
Expand Down
34 changes: 30 additions & 4 deletions src/__swaps__/screens/Swap/components/SwapOutputAsset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AnimatedText, Box, Column, Columns, Stack, useColorMode } from '@/desig
import MaskedView from '@react-native-masked-view/masked-view';
import React, { useCallback, useState } from 'react';
import { StatusBar, StyleSheet } from 'react-native';
import Animated, { runOnJS, useAnimatedReaction, useDerivedValue } from 'react-native-reanimated';
import Animated, { runOnJS, useAnimatedReaction, useDerivedValue, withSpring } from 'react-native-reanimated';
import { ScreenCornerRadius } from 'react-native-screen-corner-radius';

import { AnimatedSwapCoinIcon } from '@/__swaps__/screens/Swap/components/AnimatedSwapCoinIcon';
Expand All @@ -12,7 +12,8 @@ import { GestureHandlerV1Button } from '@/__swaps__/screens/Swap/components/Gest
import { SwapActionButton } from '@/__swaps__/screens/Swap/components/SwapActionButton';
import { SwapInput } from '@/__swaps__/screens/Swap/components/SwapInput';
import { TokenList } from '@/__swaps__/screens/Swap/components/TokenList/TokenList';
import { BASE_INPUT_WIDTH, INPUT_INNER_WIDTH, INPUT_PADDING, THICK_BORDER_WIDTH } from '@/__swaps__/screens/Swap/constants';
import { BASE_INPUT_WIDTH, INPUT_INNER_WIDTH, INPUT_PADDING, SLIDER_WIDTH, THICK_BORDER_WIDTH } from '@/__swaps__/screens/Swap/constants';
import { IS_ANDROID, IS_IOS } from '@/env';
import { useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider';
import { ChainId } from '@/__swaps__/types/chains';
import { IS_ANDROID, IS_IOS } from '@/env';
Expand All @@ -21,6 +22,9 @@ import { useNavigation } from '@/navigation';
import Routes from '@/navigation/routesNames';
import { useSwapsStore } from '@/state/swaps/swapsStore';
import { ethereumUtils } from '@/utils';
import { triggerHapticFeedback } from '@/screens/points/constants';
import { SPRING_CONFIGS } from '@/components/animations/animationConfigs';
import { equalWorklet } from '@/__swaps__/safe-math/SafeMath';
import Clipboard from '@react-native-clipboard/clipboard';
import { CopyPasteMenu } from './CopyPasteMenu';

Expand Down Expand Up @@ -131,7 +135,7 @@ function SwapOutputIcon() {
}

function OutputAssetBalanceBadge() {
const { internalSelectedOutputAsset } = useSwapContext();
const { internalSelectedOutputAsset, SwapInputController, sliderXPosition } = useSwapContext();

const label = useDerivedValue(() => {
const asset = internalSelectedOutputAsset.value;
Expand All @@ -141,7 +145,29 @@ function OutputAssetBalanceBadge() {
return asset ? balance : TOKEN_TO_GET_LABEL;
});

return <BalanceBadge label={label} />;
const onSetMaxBalance = () => {
'worklet';

const asset = internalSelectedOutputAsset.value;
if (!asset?.maxSwappableAmount || equalWorklet(asset.maxSwappableAmount, 0)) return;

const currentOutputValue = SwapInputController.inputValues.value.outputAmount;
const isAlreadyMax = equalWorklet(currentOutputValue, asset.maxSwappableAmount);
if (isAlreadyMax) {
runOnJS(triggerHapticFeedback)('impactMedium');
return;
}

SwapInputController.inputMethod.value = 'outputAmount';
SwapInputController.quoteFetchingInterval.stop();
SwapInputController.inputValues.modify(prev => ({ ...prev, outputAmount: asset.maxSwappableAmount }));
};

return (
<GestureHandlerV1Button onPressWorklet={onSetMaxBalance}>
<BalanceBadge label={label} />
</GestureHandlerV1Button>
);
}

export function SwapOutputAsset() {
Expand Down
Loading