-
Notifications
You must be signed in to change notification settings - Fork 634
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support typing into native inputs in swap (#6100)
* Remove unused TODO as build quote params should always rely on the corresponding input output amounts even if native values are updated * Support input native changes in swap inputs controller animated reaction * Temp cleanup on SwapInputAsset to pull out SwapInputAmountCaret and SwapInputNativeAmount * Temp cleanup on SwapOutputAsset to pull out SwapOutputAmountCaret and SwapOutputNativeAmount * Placeholder: generic SwapInputValuesCaret that still need to be hooked up with native inputs * Add caret animatedStyle to SwapInputValuesCaret * Use SwapInputValuesCaret component in SwapInputAsset and SwapOutputAsset * Remove old input and output caret styles from useSwapTextStyles * Cleanup of unused imports in swaps types * Add assetToSellCaretStyle and assetToBuyCaretStyle to caret component * Remove now unused assetToSell/BuyCaretStyles from useAnimatedSwapStyles * Update native input in SwapInputAsset to be typeable * Define size style for native caret in SwapInputValuesCaret * Update swap number pad Remove formatting that isn't a decimal or number on inputs. Previously, we were removing only commas, but now that we support native inputs, we want to remove the native currency symbols. Prevent updating of the native inputs if their is no corresponding price for the input / output asset. * Create separate SwapNativeInput component * Remove unused caret styles from SwapInputAsset and SwapOutputAsset * Add param to ignore alignment for native currency formatting and add handler for basic currency formatting * Update width on nativeCaret * Add support for changes to native output value * Fix missing checks for inputNativeValue and outputNativeValue * Split native currency symbol from value in native input component * Disable caret when correponding asset does not have price for native input * Update formatting for input amount if input method is native inputs * Disable pointer events when no price on native inputs * Distinguish between placeholder values vs typed inputs for native input values * Update checks for color for zero value in swap text styles * Disable focus and pointer events on native output if output based quotes disabled * Support showing explainer if output quotes disabled and user tries to update output native amount * Ignore native input changes if native currency decimals exceeded * Update add decimal in swap number pad to also handle scenarios where there are no native currency decimals * Update South Korea and Japan currencies as they do not use decimals * Fix numbers test after JPY decimal changes * Update numbers test value which should get rounded up * Fix: check for native placeholder value while checking native input decimal places
- Loading branch information
Showing
14 changed files
with
419 additions
and
230 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/__swaps__/screens/Swap/components/SwapInputValuesCaret.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { Box, useColorMode } from '@/design-system'; | ||
import React from 'react'; | ||
import { StyleSheet } from 'react-native'; | ||
import Animated, { Easing, SharedValue, useAnimatedStyle, withRepeat, withSequence, withTiming } from 'react-native-reanimated'; | ||
import { SLIDER_COLLAPSED_HEIGHT, SLIDER_HEIGHT, caretConfig } from '@/__swaps__/screens/Swap/constants'; | ||
import { equalWorklet } from '@/__swaps__/safe-math/SafeMath'; | ||
import { NavigationSteps } from '@/__swaps__/screens/Swap/hooks/useSwapNavigation'; | ||
import { useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider'; | ||
import { inputKeys } from '@/__swaps__/types/swap'; | ||
import { getColorValueForThemeWorklet } from '@/__swaps__/utils/swaps'; | ||
|
||
export function SwapInputValuesCaret({ inputCaretType, disabled }: { inputCaretType: inputKeys; disabled?: SharedValue<boolean> }) { | ||
const { isDarkMode } = useColorMode(); | ||
const { | ||
configProgress, | ||
focusedInput, | ||
inputProgress, | ||
internalSelectedInputAsset, | ||
internalSelectedOutputAsset, | ||
isQuoteStale, | ||
outputProgress, | ||
SwapInputController, | ||
sliderPressProgress, | ||
} = useSwapContext(); | ||
|
||
const inputMethod = SwapInputController.inputMethod; | ||
const inputValues = SwapInputController.inputValues; | ||
|
||
const caretStyle = useAnimatedStyle(() => { | ||
const shouldShow = | ||
!disabled?.value && | ||
configProgress.value === NavigationSteps.INPUT_ELEMENT_FOCUSED && | ||
focusedInput.value === inputCaretType && | ||
inputProgress.value === 0 && | ||
outputProgress.value === 0 && | ||
(inputMethod.value !== 'slider' || | ||
(inputMethod.value === 'slider' && equalWorklet(inputValues.value.inputAmount, 0)) || | ||
(sliderPressProgress.value === SLIDER_COLLAPSED_HEIGHT / SLIDER_HEIGHT && isQuoteStale.value === 0)); | ||
|
||
const opacity = shouldShow | ||
? withRepeat( | ||
withSequence( | ||
withTiming(1, { duration: 0 }), | ||
withTiming(1, { duration: 400, easing: Easing.bezier(0.87, 0, 0.13, 1) }), | ||
withTiming(0, caretConfig), | ||
withTiming(1, caretConfig) | ||
), | ||
-1, | ||
true | ||
) | ||
: withTiming(0, caretConfig); | ||
|
||
const isZero = | ||
(inputMethod.value !== 'slider' && inputValues.value[inputCaretType] === 0) || | ||
(inputMethod.value === 'slider' && equalWorklet(inputValues.value.inputAmount, 0)); | ||
|
||
return { | ||
display: shouldShow ? 'flex' : 'none', | ||
opacity, | ||
position: isZero ? 'absolute' : 'relative', | ||
}; | ||
}); | ||
|
||
const assetCaretStyle = useAnimatedStyle(() => { | ||
const selectedAsset = | ||
inputCaretType === 'inputAmount' || inputCaretType === 'inputNativeValue' ? internalSelectedInputAsset : internalSelectedOutputAsset; | ||
return { | ||
backgroundColor: getColorValueForThemeWorklet(selectedAsset.value?.highContrastColor, isDarkMode, true), | ||
}; | ||
}); | ||
|
||
const caretSizeStyle = | ||
inputCaretType === 'inputNativeValue' || inputCaretType === 'outputNativeValue' ? styles.nativeCaret : styles.inputCaret; | ||
|
||
return ( | ||
<Animated.View style={[styles.caretContainer, caretStyle]}> | ||
<Box as={Animated.View} borderRadius={1} style={[caretSizeStyle, assetCaretStyle]} /> | ||
</Animated.View> | ||
); | ||
} | ||
|
||
export const styles = StyleSheet.create({ | ||
nativeCaret: { | ||
height: 19, | ||
width: 1.5, | ||
}, | ||
inputCaret: { | ||
height: 32, | ||
width: 2, | ||
}, | ||
caretContainer: { | ||
flexGrow: 100, | ||
flexShrink: 0, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { AnimatedText, Box } from '@/design-system'; | ||
import React from 'react'; | ||
import { StyleSheet } from 'react-native'; | ||
import Animated, { runOnJS, useAnimatedStyle, useDerivedValue } from 'react-native-reanimated'; | ||
|
||
import { SwapInputValuesCaret } from '@/__swaps__/screens/Swap/components/SwapInputValuesCaret'; | ||
import { GestureHandlerButton } from '@/__swaps__/screens/Swap/components/GestureHandlerButton'; | ||
import { useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider'; | ||
import { equalWorklet } from '@/__swaps__/safe-math/SafeMath'; | ||
|
||
export function SwapNativeInput({ | ||
nativeInputType, | ||
handleTapWhileDisabled, | ||
}: { | ||
nativeInputType: 'inputNativeValue' | 'outputNativeValue'; | ||
handleTapWhileDisabled?: () => void; | ||
}) { | ||
const { | ||
focusedInput, | ||
internalSelectedInputAsset, | ||
internalSelectedOutputAsset, | ||
outputQuotesAreDisabled, | ||
SwapTextStyles, | ||
SwapInputController, | ||
} = useSwapContext(); | ||
|
||
const formattedNativeInput = | ||
nativeInputType === 'inputNativeValue' ? SwapInputController.formattedInputNativeValue : SwapInputController.formattedOutputNativeValue; | ||
|
||
const textStyle = nativeInputType === 'inputNativeValue' ? SwapTextStyles.inputNativeValueStyle : SwapTextStyles.outputNativeValueStyle; | ||
|
||
const nativeCurrencySymbol = formattedNativeInput.value.slice(0, 1); | ||
const formattedNativeValue = useDerivedValue(() => { | ||
return formattedNativeInput.value.slice(1); | ||
}); | ||
|
||
const disabled = useDerivedValue(() => { | ||
if (nativeInputType === 'outputNativeValue' && outputQuotesAreDisabled.value) return true; | ||
|
||
// disable caret and pointer events for native inputs when corresponding asset is missing price | ||
const asset = nativeInputType === 'inputNativeValue' ? internalSelectedInputAsset : internalSelectedOutputAsset; | ||
const assetPrice = asset.value?.nativePrice || asset.value?.price?.value || 0; | ||
return !assetPrice || equalWorklet(assetPrice, 0); | ||
}); | ||
|
||
const pointerEventsStyle = useAnimatedStyle(() => { | ||
return { | ||
pointerEvents: disabled.value ? 'none' : 'box-only', | ||
}; | ||
}); | ||
|
||
return ( | ||
<GestureHandlerButton | ||
disableButtonPressWrapper | ||
onPressStartWorklet={() => { | ||
'worklet'; | ||
if (outputQuotesAreDisabled.value && handleTapWhileDisabled && nativeInputType === 'outputNativeValue') { | ||
runOnJS(handleTapWhileDisabled)(); | ||
} else { | ||
focusedInput.value = nativeInputType; | ||
} | ||
}} | ||
> | ||
<Box as={Animated.View} style={[styles.nativeRowContainer, pointerEventsStyle]}> | ||
<AnimatedText numberOfLines={1} size="17pt" style={textStyle} weight="heavy"> | ||
{nativeCurrencySymbol} | ||
</AnimatedText> | ||
<Box as={Animated.View} style={styles.nativeContainer}> | ||
<AnimatedText numberOfLines={1} size="17pt" style={textStyle} weight="heavy"> | ||
{formattedNativeValue} | ||
</AnimatedText> | ||
<SwapInputValuesCaret inputCaretType={nativeInputType} disabled={disabled} /> | ||
</Box> | ||
</Box> | ||
</GestureHandlerButton> | ||
); | ||
} | ||
|
||
export const styles = StyleSheet.create({ | ||
nativeContainer: { alignItems: 'center', flexDirection: 'row', height: 17, pointerEvents: 'box-only' }, | ||
nativeRowContainer: { alignItems: 'center', flexDirection: 'row' }, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.