Skip to content

Commit

Permalink
fixup! feat(suite-native): Mobile Trade: Token picker modal visual stub
Browse files Browse the repository at this point in the history
  • Loading branch information
jbazant committed Feb 6, 2025
1 parent 52aae26 commit a984a79
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ReactNode } from 'react';

import { RequireAllOrNone } from 'type-fest';

import { Box, HStack, IconButton, Text } from '@suite-native/atoms';
import { IconName } from '@suite-native/icons';

export type SheetHeaderTitleProps = {
children: ReactNode;
} & RequireAllOrNone<{
onLeftButtonPress: () => void;
leftButtonIcon: IconName;
}>;

export const SheetHeaderTitle = ({
onLeftButtonPress,
leftButtonIcon,
children,
}: SheetHeaderTitleProps) => (
<HStack alignItems="center" justifyContent="space-between">
{leftButtonIcon && (
<Box flex={1}>
<IconButton
iconName={leftButtonIcon}
onPress={onLeftButtonPress}
colorScheme="tertiaryElevation0"
size="medium"
accessibilityRole="button"
accessibilityLabel="Close"
/>
</Box>
)}
<Box flex={3}>
<Text variant="highlight" textAlign="center" ellipsizeMode="tail" numberOfLines={1}>
{children}
</Text>
</Box>
{leftButtonIcon && <Box flex={1} />}
</HStack>
);
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@ import { Text, VStack } from '@suite-native/atoms';
import { Translation } from '@suite-native/intl';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';

import { SHEET_HEADER_HEIGHT } from './TradeableAssetsSheetHeader';
import { PICKER_BUTTON_HEIGHT } from '../PickerCloseButton';

const emptyComponentStyle = prepareNativeStyle(({ spacings }) => ({
paddingTop: SHEET_HEADER_HEIGHT + spacings.sp12,
paddingBottom: PICKER_BUTTON_HEIGHT + spacings.sp12,
paddingHorizontal: spacings.sp52,
padding: spacings.sp52,
alignContent: 'center',
justifyContent: 'center',
gap: spacings.sp12,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import { Translation } from '@suite-native/intl';

import { TradeAssetsListEmptyComponent } from './TradeAssetsListEmptyComponent';
import { ASSET_ITEM_HEIGHT, TradeableAssetListItem } from './TradeableAssetListItem';
import { SHEET_HEADER_HEIGHT, TradeableAssetsSheetHeader } from './TradeableAssetsSheetHeader';
import { TradeableAssetsSheetHeader } from './TradeableAssetsSheetHeader';
import { TradeableAsset } from '../../../types';
import { PICKER_BUTTON_HEIGHT, PickerCloseButton } from '../PickerCloseButton';

export type TradeableAssetsSheetProps = {
isVisible: boolean;
Expand All @@ -18,8 +17,6 @@ export type TradeableAssetsSheetProps = {
};

type ListInnerItemShape =
// [type, height, key]
| ['spacer', number, string]
// [type, text, key]
| ['sectionHeader', ReactNode, string]
// [type, data, isFavourite]
Expand Down Expand Up @@ -54,16 +51,12 @@ const getMockFiatRate = () => Math.random() * 1000;
const getMockPriceChange = () => Math.random() * 3 - 1;

const getEstimatedListHeight = (itemsCount: number) =>
itemsCount * ASSET_ITEM_HEIGHT +
SHEET_HEADER_HEIGHT +
PICKER_BUTTON_HEIGHT +
2 * SECTION_HEADER_HEIGHT;
itemsCount * ASSET_ITEM_HEIGHT + 2 * SECTION_HEADER_HEIGHT;

const transformToInnerFlatListData = (
favourites: TradeableAsset[],
assetsData: TradeableAsset[],
): ListInnerItemShape[] => [
['spacer', SHEET_HEADER_HEIGHT, 'spacer_top'],
[
'sectionHeader',
<Translation key="favourites" id="moduleTrading.tradeableAssetsSheet.favouritesTitle" />,
Expand Down Expand Up @@ -98,12 +91,10 @@ const transformToInnerFlatListData = (
},
] as ListInnerItemShape,
),
['spacer', PICKER_BUTTON_HEIGHT, 'spacer_bottom'],
];

const keyExtractor = (item: ListInnerItemShape) => {
switch (item[0]) {
case 'spacer':
case 'sectionHeader':
return item[2];

Expand All @@ -120,12 +111,6 @@ const keyExtractor = (item: ListInnerItemShape) => {

const renderItem = (data: ListInnerItemShape, onAssetSelect: (asset: TradeableAsset) => void) => {
switch (data[0]) {
case 'spacer': {
const height = data[1];

return <Box style={{ height }} />;
}

case 'sectionHeader': {
const text = data[1];

Expand Down Expand Up @@ -188,10 +173,8 @@ export const TradeableAssetsSheet = ({
<BottomSheetFlashList<ListInnerItemShape>
isVisible={isVisible}
onClose={onClose}
isCloseDisplayed={false}
ListEmptyComponent={<TradeAssetsListEmptyComponent />}
stickyListHeaderComponent={<TradeableAssetsSheetHeader />}
stickyListFooterComponent={<PickerCloseButton onPress={onClose} />}
handleComponent={() => <TradeableAssetsSheetHeader onClose={onClose} />}
data={data}
keyExtractor={keyExtractor}
estimatedListHeight={estimatedListHeight}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,66 +1,62 @@
import { useMemo, useState } from 'react';
import { useState } from 'react';
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated';

import { LinearGradient } from 'expo-linear-gradient';

import { hexToRgba } from '@suite-common/suite-utils';
import { Text, VStack } from '@suite-native/atoms';
import { BottomSheetGrabber, VStack } from '@suite-native/atoms';
import { Translation } from '@suite-native/intl';
import { useNativeStyles } from '@trezor/styles';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';

import { SheetHeaderTitle } from '../SheetHeaderTitle';
import { TradeableAssetsFilterTabs } from './TradeableAssetsFilterTabs';
import { SearchInputWithCancel } from '../SearchInputWithCancel';

export const SHEET_HEADER_HEIGHT = 140 as const;
type TradeableAssetsSheetHeaderProps = {
onClose: () => void;
};

const HEADER_HEIGHT = 160;
const FOCUS_ANIMATION_DURATION = 300 as const;

const GRADIENT_START = { x: 0.5, y: 0.9 } as const;
const GRADIENT_END = { x: 0.5, y: 1 } as const;
const wrapperStyle = prepareNativeStyle<{}>(({ spacings }) => ({
height: HEADER_HEIGHT,
padding: spacings.sp16,
gap: spacings.sp16,
}));

export const TradeableAssetsSheetHeader = ({ onClose }: TradeableAssetsSheetHeaderProps) => {
const { applyStyle } = useNativeStyles();

export const TradeableAssetsSheetHeader = () => {
const {
utils: {
colors: { backgroundSurfaceElevation0 },
},
} = useNativeStyles();
const [isFilterActive, setIsFilterActive] = useState(false);
const [filterValue, setFilterValue] = useState('');

const gradientColors = useMemo<[string, string]>(
() => [backgroundSurfaceElevation0, hexToRgba(backgroundSurfaceElevation0, 0.1)],
[backgroundSurfaceElevation0],
);

return (
<LinearGradient colors={gradientColors} start={GRADIENT_START} end={GRADIENT_END}>
<VStack spacing="sp16" padding="sp16">
<Animated.View layout={LinearTransition.duration(FOCUS_ANIMATION_DURATION)}>
{!isFilterActive && (
<Animated.View
entering={FadeIn.duration(FOCUS_ANIMATION_DURATION)}
exiting={FadeOut.duration(FOCUS_ANIMATION_DURATION)}
>
<Text variant="highlight" textAlign="center">
<Translation id="moduleTrading.tradeableAssetsSheet.title" />
</Text>
</Animated.View>
)}
</Animated.View>
<Animated.View layout={LinearTransition.duration(FOCUS_ANIMATION_DURATION)}>
<SearchInputWithCancel
onChange={setFilterValue}
onFocus={() => setIsFilterActive(true)}
onBlur={() => setIsFilterActive(false)}
value={filterValue}
/>
</Animated.View>
<Animated.View layout={LinearTransition.duration(FOCUS_ANIMATION_DURATION)}>
<TradeableAssetsFilterTabs
visible={isFilterActive}
animationDuration={FOCUS_ANIMATION_DURATION}
/>
</Animated.View>
</VStack>
</LinearGradient>
<VStack style={applyStyle(wrapperStyle)}>
<BottomSheetGrabber />
<Animated.View layout={LinearTransition.duration(FOCUS_ANIMATION_DURATION)}>
{!isFilterActive && (
<Animated.View
entering={FadeIn.duration(FOCUS_ANIMATION_DURATION)}
exiting={FadeOut.duration(FOCUS_ANIMATION_DURATION)}
>
<SheetHeaderTitle leftButtonIcon="x" onLeftButtonPress={onClose}>
<Translation id="moduleTrading.tradeableAssetsSheet.title" />
</SheetHeaderTitle>
</Animated.View>
)}
</Animated.View>
<Animated.View layout={LinearTransition.duration(FOCUS_ANIMATION_DURATION)}>
<SearchInputWithCancel
onChange={setFilterValue}
onFocus={() => setIsFilterActive(true)}
onBlur={() => setIsFilterActive(false)}
value={filterValue}
/>
</Animated.View>
<Animated.View layout={LinearTransition.duration(FOCUS_ANIMATION_DURATION)}>
<TradeableAssetsFilterTabs
visible={isFilterActive}
animationDuration={FOCUS_ANIMATION_DURATION}
/>
</Animated.View>
</VStack>
);
};

0 comments on commit a984a79

Please sign in to comment.