Skip to content

Commit

Permalink
[SWAPS V2]: Add token search logic and ability to select assets (#5547)
Browse files Browse the repository at this point in the history
* initial useSwapAssets work

* remove unused chainid ref

* comment out favorites until I can match the types

* add token search and user asset search

* replace a bunch of dummy values with actual color values / balances

* some cleanup

* undo type change and fix lint

* some cleanup

* fix some bugs

* some more optimizations

* touches

* add display prop to animated styles

* more prop splitting

* replaced stuff with reanimated stuff

* this is fucked

* moving over some reanimated stuff

* swap action button colors working

* more progress on reanimated conversion

* ya

* fix token flipping

* fix https://github.com/rainbow-me/browser-extension/pull/1453/files

* fix empty acitivity list

* search + asset lists working

* fix swapbackground linear not using reanimated values

* limit buy sections to first 5 assets

* perf improvements

* fix padding on output asset coin row

* fix lint
  • Loading branch information
walmat authored Apr 3, 2024
1 parent e148fa5 commit dc91f7e
Show file tree
Hide file tree
Showing 70 changed files with 3,360 additions and 894 deletions.
15 changes: 12 additions & 3 deletions src/__swaps__/components/animations/AnimatedSpinner.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import React from 'react';
import Animated, { Easing, useAnimatedReaction, useAnimatedStyle, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated';
import Animated, {
Easing,
SharedValue,
useAnimatedReaction,
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
} from 'react-native-reanimated';
import { useForegroundColor } from '@/design-system';
import styled from '@/styled-thing';
import { ImgixImage } from '@/components/images';
Expand Down Expand Up @@ -27,14 +35,15 @@ const StyledSpinner = styled(ImgixImage).attrs(({ color, size, src }: { color: s
width: ({ size }: { size?: number }) => size,
});

// TODO: We should also accept a regular boolean as a state variable
export const AnimatedSpinner = ({
isLoading,
color,
scaleInFrom = 0,
size = 28,
src = Spinner,
}: {
isLoading: boolean;
isLoading: SharedValue<boolean>;
color?: string;
scaleInFrom?: number;
size?: number;
Expand All @@ -46,7 +55,7 @@ export const AnimatedSpinner = ({
const spinnerScale = useSharedValue(0);

useAnimatedReaction(
() => isLoading,
() => isLoading.value,
(isLoadingCurrent, isLoadingPrevious) => {
if (isLoadingCurrent !== isLoadingPrevious) {
if (isLoadingCurrent) {
Expand Down
20 changes: 10 additions & 10 deletions src/__swaps__/screens/Swap/Swap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { SwapInputAsset } from './components/controls/SwapInputAsset';
import { SwapOutputAsset } from './components/controls/SwapOutputAsset';
import { SwapNavbar } from './components/SwapNavbar';
import { SwapAmountInputs } from './components/controls/SwapAmountInputs';
import { safeAreaInsetValues } from '@/utils';
import { navbarHeight } from '@/components/navbar/Navbar';

/** README
* This prototype is largely driven by Reanimated and Gesture Handler, which
Expand Down Expand Up @@ -56,15 +58,14 @@ export function SwapScreen() {
return (
<SheetGestureBlocker>
<Box as={Page} style={styles.rootViewBackground} testID="swap-screen" width="full">
<SwapBackground>
<Box alignItems="center" height="full" paddingTop={{ custom: 29 }} width="full">
<SwapInputAsset />
<FlipButton />
<SwapOutputAsset />
<ExchangeRateBubble />
<SwapAmountInputs />
</Box>
</SwapBackground>
<SwapBackground />
<Box alignItems="center" height="full" paddingTop={{ custom: safeAreaInsetValues.top + (navbarHeight - 12) + 29 }} width="full">
<SwapInputAsset />
<FlipButton />
<SwapOutputAsset />
<ExchangeRateBubble />
<SwapAmountInputs />
</Box>
<SwapNavbar />
</Box>
</SheetGestureBlocker>
Expand All @@ -73,7 +74,6 @@ export function SwapScreen() {

export const styles = StyleSheet.create({
rootViewBackground: {
backgroundColor: 'transparent',
borderRadius: IS_ANDROID ? 20 : ScreenCornerRadius,
flex: 1,
overflow: 'hidden',
Expand Down
22 changes: 13 additions & 9 deletions src/__swaps__/screens/Swap/components/BalanceBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
/* eslint-disable no-nested-ternary */
import React from 'react';
import { Bleed, Box, Text, useColorMode } from '@/design-system';
import { AnimatedText, Bleed, Box, useColorMode } from '@/design-system';
import { TextColor } from '@/design-system/color/palettes';
import { TextWeight } from '@/design-system/components/Text/Text';
import { LIGHT_SEPARATOR_COLOR, SEPARATOR_COLOR, THICK_BORDER_WIDTH } from '../constants';
import { DerivedValue, useAnimatedStyle } from 'react-native-reanimated';

export const BalanceBadge = ({ color, label, weight }: { color?: TextColor; label: string; weight?: TextWeight }) => {
export const BalanceBadge = ({ color, label, weight }: { color?: TextColor; label: DerivedValue<string>; weight?: TextWeight }) => {
const { isDarkMode } = useColorMode();

const labelTextStyle = useAnimatedStyle(() => {
return {
opacity: label.value === 'No Balance' ? (isDarkMode ? 0.6 : 0.75) : undefined,
};
});

return (
<Bleed vertical={{ custom: 5.5 }}>
<Box
Expand All @@ -21,17 +28,14 @@ export const BalanceBadge = ({ color, label, weight }: { color?: TextColor; labe
borderWidth: THICK_BORDER_WIDTH,
}}
>
<Text
<AnimatedText
align="center"
color={color || 'labelQuaternary'}
size="13pt"
style={{
opacity: label === 'No Balance' ? (isDarkMode ? 0.6 : 0.75) : undefined,
}}
text={label}
style={labelTextStyle}
weight={weight || 'bold'}
>
{label}
</Text>
/>
</Box>
</Bleed>
);
Expand Down
56 changes: 48 additions & 8 deletions src/__swaps__/screens/Swap/components/CoinRow.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,53 @@
import React, { useMemo } from 'react';
import { Address } from 'viem';
import { ButtonPressAnimation } from '@/components/animations';
import { Box, HitSlop, Inline, Stack, Text } from '@/design-system';
import { TextColor } from '@/design-system/color/palettes';
import { Network } from '@/networks/types';
import { useTheme } from '@/theme';
import { SwapCoinIcon } from './SwapCoinIcon';
import { CoinRowButton } from './CoinRowButton';
import { BalancePill } from './BalancePill';
import { ChainId } from '../types/chains';
import { ethereumUtils } from '@/utils';
import { toggleFavorite, useFavorites } from '@/resources/favorites';
import { ETH_ADDRESS } from '@/references';

export const CoinRow = ({
address,
mainnetAddress,
chainId,
balance,
isTrending,
name,
nativeBalance,
color,
iconUrl,
onPress,
output,
symbol,
}: {
address: Address | 'eth';
address: string;
mainnetAddress: string;
chainId: ChainId;
balance: string;
isTrending?: boolean;
name: string;
nativeBalance: string;
color: string | undefined;
iconUrl: string | undefined;
onPress?: () => void;
output?: boolean;
symbol: string;
}) => {
const theme = useTheme();
const { favoritesMetadata } = useFavorites();

const favorites = Object.values(favoritesMetadata);

const isFavorite = (address: string) => {
return favorites.find(fav =>
fav.address === ETH_ADDRESS ? '0x0000000000000000000000000000000000000000' === address : fav.address === address
);
};

const percentChange = useMemo(() => {
if (isTrending) {
Expand All @@ -43,18 +62,34 @@ export const CoinRow = ({
}, [isTrending]);

return (
<ButtonPressAnimation onPress={onPress} scaleTo={0.95}>
<ButtonPressAnimation disallowInterruption onPress={onPress} scaleTo={0.95}>
<HitSlop vertical="10px">
<Box alignItems="center" flexDirection="row" justifyContent="space-between" width="full">
<Box
alignItems="center"
paddingVertical={'10px'}
paddingHorizontal={'20px'}
flexDirection="row"
justifyContent="space-between"
width="full"
>
<Inline alignVertical="center" space="10px">
<SwapCoinIcon address={address} large network={Network.mainnet} symbol={symbol} theme={theme} />
<SwapCoinIcon
iconUrl={iconUrl}
address={address}
mainnetAddress={mainnetAddress}
large
network={ethereumUtils.getNetworkFromChainId(chainId)}
symbol={symbol}
theme={theme}
color={color}
/>
<Stack space="10px">
<Text color="label" size="17pt" weight="semibold">
{name}
</Text>
<Inline alignVertical="center" space={{ custom: 5 }}>
<Text color="labelTertiary" size="13pt" weight="semibold">
{output ? symbol : `${balance} ${symbol}`}
{output ? symbol : `${balance}`}
</Text>
{isTrending && percentChange && (
<Inline alignVertical="center" space={{ custom: 1 }}>
Expand All @@ -72,7 +107,12 @@ export const CoinRow = ({
{output ? (
<Inline space="8px">
<CoinRowButton icon="􀅳" outline size="icon 14px" />
<CoinRowButton icon="􀋃" weight="black" />
<CoinRowButton
color={isFavorite(address) ? '#FFCB0F' : undefined}
onPress={() => toggleFavorite(address)}
icon="􀋃"
weight="black"
/>
</Inline>
) : (
<BalancePill balance={nativeBalance} />
Expand Down
18 changes: 13 additions & 5 deletions src/__swaps__/screens/Swap/components/CoinRowButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import { LIGHT_SEPARATOR_COLOR, SEPARATOR_COLOR, THICK_BORDER_WIDTH } from '../c
import { opacity } from '../utils/swaps';

export const CoinRowButton = ({
color,
icon,
onPress,
outline,
size,
weight,
}: {
color?: string;
icon: string;
onPress?: () => void;
outline?: boolean;
Expand All @@ -26,23 +28,29 @@ export const CoinRowButton = ({
const separatorTertiary = useForegroundColor('separatorTertiary');

return (
<ButtonPressAnimation onPress={onPress} scaleTo={0.8}>
<ButtonPressAnimation disallowInterruption onPress={onPress} scaleTo={0.8}>
<Box
alignItems="center"
borderRadius={14}
height={{ custom: 28 }}
justifyContent="center"
style={{
backgroundColor: outline ? 'transparent' : isDarkMode ? fillQuaternary : opacity(fillTertiary, 0.04),
borderColor: outline ? (isDarkMode ? SEPARATOR_COLOR : LIGHT_SEPARATOR_COLOR) : separatorTertiary,
backgroundColor: outline
? 'transparent'
: color
? opacity(color, 0.25)
: isDarkMode
? fillQuaternary
: opacity(fillTertiary, 0.04),
borderColor: outline ? (isDarkMode ? SEPARATOR_COLOR : LIGHT_SEPARATOR_COLOR) : color ? opacity(color, 0.1) : separatorTertiary,
borderWidth: THICK_BORDER_WIDTH,
}}
width={{ custom: 28 }}
>
<TextIcon
color="labelQuaternary"
color={color ? { custom: color } : 'labelQuaternary'}
containerSize={28}
opacity={isDarkMode ? 0.6 : 0.75}
opacity={isDarkMode ? 1 : 0.75}
size={size || 'icon 12px'}
weight={weight || 'heavy'}
>
Expand Down
43 changes: 34 additions & 9 deletions src/__swaps__/screens/Swap/components/ExchangeRateBubble.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import React from 'react';
import { Box, Inline, Text, TextIcon, useColorMode, useForegroundColor } from '@/design-system';
import { AnimatedText, Box, Inline, TextIcon, useColorMode, useForegroundColor } from '@/design-system';
import { LIGHT_SEPARATOR_COLOR, SEPARATOR_COLOR, THICK_BORDER_WIDTH } from '../constants';
import { opacity } from '../utils/swaps';
import { ButtonPressAnimation } from '@/components/animations';
import Animated from 'react-native-reanimated';
import Animated, { useDerivedValue } from 'react-native-reanimated';
import { useSwapContext } from '../providers/swap-provider';

export const ExchangeRateBubble = () => {
const { isDarkMode } = useColorMode();
const { AnimatedSwapStyles } = useSwapContext();
const { AnimatedSwapStyles, SwapInputController } = useSwapContext();

const fillTertiary = useForegroundColor('fillTertiary');

const assetToSellLabel = useDerivedValue(() => {
if (!SwapInputController?.assetToSell.value) return '';
return `1 ${SwapInputController?.assetToSell.value?.symbol}`;
});

const assetToBuyLabel = useDerivedValue(() => {
if (!SwapInputController.assetToBuy.value) return '';
return `1,624.04 ${SwapInputController.assetToBuy.value?.symbol}`;
});

// TODO: Do proper exchange rate calculation once we receive the quote

// TODO: This doesn't work when assets change, figure out why...
if (!assetToSellLabel.value || !assetToBuyLabel.value) return null;

return (
<ButtonPressAnimation scaleTo={0.925} style={{ marginTop: 4 }}>
<Box
Expand All @@ -31,9 +46,14 @@ export const ExchangeRateBubble = () => {
style={{ borderColor: isDarkMode ? SEPARATOR_COLOR : LIGHT_SEPARATOR_COLOR, borderWidth: THICK_BORDER_WIDTH }}
>
<Inline alignHorizontal="center" alignVertical="center" space="6px" wrap={false}>
<Text align="center" color="labelQuaternary" size="13pt" style={{ opacity: isDarkMode ? 0.6 : 0.75 }} weight="heavy">
1 ETH
</Text>
<AnimatedText
align="center"
color="labelQuaternary"
size="13pt"
style={{ opacity: isDarkMode ? 0.6 : 0.75 }}
weight="heavy"
text={assetToSellLabel}
/>
<Box
borderRadius={10}
height={{ custom: 20 }}
Expand All @@ -45,9 +65,14 @@ export const ExchangeRateBubble = () => {
􀄭
</TextIcon>
</Box>
<Text align="center" color="labelQuaternary" size="13pt" style={{ opacity: isDarkMode ? 0.6 : 0.75 }} weight="heavy">
1,624.04 USDC
</Text>
<AnimatedText
align="center"
color="labelQuaternary"
size="13pt"
style={{ opacity: isDarkMode ? 0.6 : 0.75 }}
weight="heavy"
text={assetToBuyLabel}
/>
</Inline>
</Box>
</Box>
Expand Down
Loading

0 comments on commit dc91f7e

Please sign in to comment.